@@ -107,13 +107,11 @@ static void init_molecule_chain_info(const AtomBlockId blk_id,
107107 const AtomNetlist& atom_nlist);
108108
109109static AtomBlockId get_sink_block (const AtomBlockId block_id,
110- const t_model_ports* model_port,
111- const BitIndex pin_number,
110+ const t_pack_pattern_connections& connections,
112111 const AtomNetlist& atom_nlist);
113112
114113static AtomBlockId get_driving_block (const AtomBlockId block_id,
115- const t_model_ports* model_port,
116- const BitIndex pin_number,
114+ const t_pack_pattern_connections& connections,
117115 const AtomNetlist& atom_nlist);
118116
119117static void print_chain_starting_points (t_pack_patterns* chain_pattern);
@@ -1047,17 +1045,13 @@ static bool try_expand_molecule(t_pack_molecule& molecule,
10471045 // this block is the driver of this connection
10481046 if (block_connection->from_block == pattern_block) {
10491047 // find the block this connection is driving and add it to the queue
1050- auto port_model = block_connection->from_pin ->port ->model_port ;
1051- auto ipin = block_connection->from_pin ->pin_number ;
1052- auto sink_blk_id = get_sink_block (block_id, port_model, ipin, atom_nlist);
1048+ auto sink_blk_id = get_sink_block (block_id, *block_connection, atom_nlist);
10531049 // add this sink block id with its corresponding pattern block to the queue
10541050 pattern_block_queue.push (std::make_pair (block_connection->to_block , sink_blk_id));
10551051 // this block is being driven by this connection
10561052 } else if (block_connection->to_block == pattern_block) {
10571053 // find the block that is driving this connection and it to the queue
1058- auto port_model = block_connection->to_pin ->port ->model_port ;
1059- auto ipin = block_connection->to_pin ->pin_number ;
1060- auto driver_blk_id = get_driving_block (block_id, port_model, ipin, atom_nlist);
1054+ auto driver_blk_id = get_driving_block (block_id, *block_connection, atom_nlist);
10611055 // add this driver block id with its corresponding pattern block to the queue
10621056 pattern_block_queue.push (std::make_pair (block_connection->from_block , driver_blk_id));
10631057 }
@@ -1076,62 +1070,94 @@ static bool try_expand_molecule(t_pack_molecule& molecule,
10761070/* *
10771071 * Find the atom block in the netlist driven by this pin of the input atom block
10781072 * If doesn't exist return AtomBlockId::INVALID()
1079- * Limitation: The block should be driving only one sink block
1073+ * TODO: Limitation — For pack patterns other than chains,
1074+ * the block should be driven by only one block
10801075 * block_id : id of the atom block that is driving the net connected to the sink block
1081- * model_port : the model of the port driving the net
1082- * pin_number : the pin_number of the pin driving the net (pin index within the port)
1076+ * connections : pack pattern connections from the given block
10831077 */
10841078static AtomBlockId get_sink_block (const AtomBlockId block_id,
1085- const t_model_ports* model_port,
1086- const BitIndex pin_number,
1079+ const t_pack_pattern_connections& connections,
10871080 const AtomNetlist& atom_nlist) {
1088- auto port_id = atom_nlist.find_atom_port (block_id, model_port);
1089-
1090- if (port_id) {
1091- auto net_id = atom_nlist.port_net (port_id, pin_number);
1092- if (net_id && atom_nlist.net_sinks (net_id).size () == 1 ) { /* Single fanout assumption */
1093- auto net_sinks = atom_nlist.net_sinks (net_id);
1094- auto sink_pin_id = *(net_sinks.begin ());
1095- return atom_nlist.pin_block (sink_pin_id);
1096- }
1081+ const t_model_ports* from_port_model = connections.from_pin ->port ->model_port ;
1082+ const int from_pin_number = connections.from_pin ->pin_number ;
1083+ auto from_port_id = atom_nlist.find_atom_port (block_id, from_port_model);
1084+
1085+ const t_model_ports* to_port_model = connections.to_pin ->port ->model_port ;
1086+ const int to_pin_number = connections.to_pin ->pin_number ;
1087+ const auto & to_pb_type = connections.to_block ->pb_type ;
1088+
1089+ if (!from_port_id.is_valid ()) {
1090+ return AtomBlockId::INVALID ();
10971091 }
10981092
1099- return AtomBlockId::INVALID ();
1093+ auto net_id = atom_nlist.port_net (from_port_id, from_pin_number);
1094+ if (!net_id.is_valid ()) {
1095+ return AtomBlockId::INVALID ();
1096+ }
1097+
1098+ const auto & net_sinks = atom_nlist.net_sinks (net_id);
1099+ // Iterate through all sink blocks and check whether any of them
1100+ // is compatible with the block specified in the pack pattern.
1101+ bool connected_to_latch = false ;
1102+ AtomBlockId pattern_sink_block_id = AtomBlockId::INVALID ();
1103+ for (const auto & sink_pin_id : net_sinks) {
1104+ auto sink_block_id = atom_nlist.pin_block (sink_pin_id);
1105+ if (atom_nlist.block_model (sink_block_id)->name == std::string (MODEL_LATCH)) {
1106+ connected_to_latch = true ;
1107+ }
1108+ if (primitive_type_feasible (sink_block_id, to_pb_type)) {
1109+ auto to_port_id = atom_nlist.find_atom_port (sink_block_id, to_port_model);
1110+ auto to_pin_id = atom_nlist.find_pin (to_port_id, BitIndex (to_pin_number));
1111+ if (to_pin_id == sink_pin_id) {
1112+ pattern_sink_block_id = sink_block_id;
1113+ }
1114+ }
1115+ }
1116+ // If the number of sinks is greater than 1, and one of the connected blocks is a latch,
1117+ // then we drop the block to avoid a situation where only registers or unregistered output
1118+ // of the block can use the output pin.
1119+ // TODO: This is a conservative assumption, and ideally we need to do analysis of the architecture
1120+ // before to determine which pattern is supported by the architecture.
1121+ if (connected_to_latch && net_sinks.size () > 1 ) {
1122+ pattern_sink_block_id = AtomBlockId::INVALID ();
1123+ }
1124+ return pattern_sink_block_id;
11001125}
11011126
11021127/* *
11031128 * Find the atom block in the netlist driving this pin of the input atom block
11041129 * If doesn't exist return AtomBlockId::INVALID()
11051130 * Limitation: This driving block should be driving only the input block
11061131 * block_id : id of the atom block that is connected to a net driven by the driving block
1107- * model_port : the model of the port driven by the net
1108- * pin_number : the pin_number of the pin driven by the net (pin index within the port)
1132+ * connections : pack pattern connections from the given block
11091133 */
11101134static AtomBlockId get_driving_block (const AtomBlockId block_id,
1111- const t_model_ports* model_port,
1112- const BitIndex pin_number,
1135+ const t_pack_pattern_connections& connections,
11131136 const AtomNetlist& atom_nlist) {
1114- auto port_id = atom_nlist.find_atom_port (block_id, model_port);
1115-
1116- if (port_id) {
1117- auto net_id = atom_nlist.port_net (port_id, pin_number);
1118- if (net_id && atom_nlist.net_sinks (net_id).size () == 1 ) { /* Single fanout assumption */
1137+ auto to_port_model = connections.to_pin ->port ->model_port ;
1138+ auto to_pin_number = connections.to_pin ->pin_number ;
1139+ auto to_port_id = atom_nlist.find_atom_port (block_id, to_port_model);
11191140
1120- auto driver_blk_id = atom_nlist.net_driver_block (net_id);
1141+ if (!to_port_id.is_valid ()) {
1142+ return AtomBlockId::INVALID ();
1143+ }
11211144
1122- if (model_port->is_clock ) {
1123- auto driver_blk_type = atom_nlist.block_type (driver_blk_id);
1145+ auto net_id = atom_nlist.port_net (to_port_id, to_pin_number);
1146+ if (net_id && atom_nlist.net_sinks (net_id).size () == 1 ) { /* Single fanout assumption */
1147+ auto driver_blk_id = atom_nlist.net_driver_block (net_id);
11241148
1125- // TODO: support multi-clock primitives.
1126- // If the driver block is a .input block, this assertion should not
1127- // be triggered as the sink block might have only one input pin, which
1128- // would be a clock pin in case the sink block primitive is a clock generator,
1129- // resulting in a pin_number == 0.
1130- VTR_ASSERT (pin_number == 1 || (pin_number == 0 && driver_blk_type == AtomBlockType::INPAD));
1131- }
1149+ if (to_port_model->is_clock ) {
1150+ auto driver_blk_type = atom_nlist.block_type (driver_blk_id);
11321151
1133- return atom_nlist.net_driver_block (net_id);
1152+ // TODO: support multi-clock primitives.
1153+ // If the driver block is a .input block, this assertion should not
1154+ // be triggered as the sink block might have only one input pin, which
1155+ // would be a clock pin in case the sink block primitive is a clock generator,
1156+ // resulting in a pin_number == 0.
1157+ VTR_ASSERT (to_pin_number == 1 || (to_pin_number == 0 && driver_blk_type == AtomBlockType::INPAD));
11341158 }
1159+
1160+ return driver_blk_id;
11351161 }
11361162
11371163 return AtomBlockId::INVALID ();
0 commit comments