From 6e865338107627e90b278252f63c77bfd3ead022 Mon Sep 17 00:00:00 2001 From: Amin Mohaghegh Date: Mon, 21 Apr 2025 15:35:20 -0700 Subject: [PATCH 01/12] [vpr][pack] update prepack get_sink --- vpr/src/pack/prepack.cpp | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/vpr/src/pack/prepack.cpp b/vpr/src/pack/prepack.cpp index 05912f70b12..5a66f296f30 100644 --- a/vpr/src/pack/prepack.cpp +++ b/vpr/src/pack/prepack.cpp @@ -107,8 +107,7 @@ static void init_molecule_chain_info(const AtomBlockId blk_id, const AtomNetlist& atom_nlist); static AtomBlockId get_sink_block(const AtomBlockId block_id, - const t_model_ports* model_port, - const BitIndex pin_number, + const t_pack_pattern_connections& connections, const AtomNetlist& atom_nlist); static AtomBlockId get_driving_block(const AtomBlockId block_id, @@ -1047,9 +1046,7 @@ static bool try_expand_molecule(t_pack_molecule& molecule, // this block is the driver of this connection if (block_connection->from_block == pattern_block) { // find the block this connection is driving and add it to the queue - auto port_model = block_connection->from_pin->port->model_port; - auto ipin = block_connection->from_pin->pin_number; - auto sink_blk_id = get_sink_block(block_id, port_model, ipin, atom_nlist); + auto sink_blk_id = get_sink_block(block_id, *block_connection, atom_nlist); // add this sink block id with its corresponding pattern block to the queue pattern_block_queue.push(std::make_pair(block_connection->to_block, sink_blk_id)); // this block is being driven by this connection @@ -1076,23 +1073,27 @@ static bool try_expand_molecule(t_pack_molecule& molecule, /** * Find the atom block in the netlist driven by this pin of the input atom block * If doesn't exist return AtomBlockId::INVALID() - * Limitation: The block should be driving only one sink block * block_id : id of the atom block that is driving the net connected to the sink block - * model_port : the model of the port driving the net - * pin_number : the pin_number of the pin driving the net (pin index within the port) + * connections : pack pattern connections from the given block */ static AtomBlockId get_sink_block(const AtomBlockId block_id, - const t_model_ports* model_port, - const BitIndex pin_number, + const t_pack_pattern_connections& connections, const AtomNetlist& atom_nlist) { - auto port_id = atom_nlist.find_atom_port(block_id, model_port); - - if (port_id) { - auto net_id = atom_nlist.port_net(port_id, pin_number); - if (net_id && atom_nlist.net_sinks(net_id).size() == 1) { /* Single fanout assumption */ - auto net_sinks = atom_nlist.net_sinks(net_id); - auto sink_pin_id = *(net_sinks.begin()); - return atom_nlist.pin_block(sink_pin_id); + const t_model_ports* from_port_model = connections.from_pin->port->model_port; + const int from_pin_number = connections.from_pin->pin_number; + auto from_port_id = atom_nlist.find_atom_port(block_id, from_port_model); + + const t_model_ports* to_port_model = connections.to_pin->port->model_port; + const int to_pin_number = connections.to_pin->pin_number; + auto to_port_id = atom_nlist.find_atom_port(block_id, to_port_model); + + if (from_port_id && to_port_id) { + auto net_id = atom_nlist.port_net(from_port_id, from_pin_number); + const auto& net_sinks = atom_nlist.net_sinks(net_id); + for (const auto& sink_pin_id : net_sinks) { + if (atom_nlist.pin_port(sink_pin_id) == to_port_id && atom_nlist.pin_port_bit(sink_pin_id) == to_pin_number) { + return atom_nlist.pin_block(sink_pin_id); + } } } From 349783862121fb2aeaba7a56b6e3018e0553caac Mon Sep 17 00:00:00 2001 From: Amin Mohaghegh Date: Mon, 21 Apr 2025 15:58:57 -0700 Subject: [PATCH 02/12] [vpr][pack] update prepack get_driving_block --- vpr/src/pack/prepack.cpp | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/vpr/src/pack/prepack.cpp b/vpr/src/pack/prepack.cpp index 5a66f296f30..ad3805d378e 100644 --- a/vpr/src/pack/prepack.cpp +++ b/vpr/src/pack/prepack.cpp @@ -111,8 +111,7 @@ static AtomBlockId get_sink_block(const AtomBlockId block_id, const AtomNetlist& atom_nlist); static AtomBlockId get_driving_block(const AtomBlockId block_id, - const t_model_ports* model_port, - const BitIndex pin_number, + const t_pack_pattern_connections& connections, const AtomNetlist& atom_nlist); static void print_chain_starting_points(t_pack_patterns* chain_pattern); @@ -1052,9 +1051,7 @@ static bool try_expand_molecule(t_pack_molecule& molecule, // this block is being driven by this connection } else if (block_connection->to_block == pattern_block) { // find the block that is driving this connection and it to the queue - auto port_model = block_connection->to_pin->port->model_port; - auto ipin = block_connection->to_pin->pin_number; - auto driver_blk_id = get_driving_block(block_id, port_model, ipin, atom_nlist); + auto driver_blk_id = get_driving_block(block_id, *block_connection, atom_nlist); // add this driver block id with its corresponding pattern block to the queue pattern_block_queue.push(std::make_pair(block_connection->from_block, driver_blk_id)); } @@ -1091,7 +1088,7 @@ static AtomBlockId get_sink_block(const AtomBlockId block_id, auto net_id = atom_nlist.port_net(from_port_id, from_pin_number); const auto& net_sinks = atom_nlist.net_sinks(net_id); for (const auto& sink_pin_id : net_sinks) { - if (atom_nlist.pin_port(sink_pin_id) == to_port_id && atom_nlist.pin_port_bit(sink_pin_id) == to_pin_number) { + if (atom_nlist.pin_port(sink_pin_id) == to_port_id && static_cast(atom_nlist.pin_port_bit(sink_pin_id)) == to_pin_number) { return atom_nlist.pin_block(sink_pin_id); } } @@ -1105,22 +1102,21 @@ static AtomBlockId get_sink_block(const AtomBlockId block_id, * If doesn't exist return AtomBlockId::INVALID() * Limitation: This driving block should be driving only the input block * block_id : id of the atom block that is connected to a net driven by the driving block - * model_port : the model of the port driven by the net - * pin_number : the pin_number of the pin driven by the net (pin index within the port) + * connections : pack pattern connections from the given block */ static AtomBlockId get_driving_block(const AtomBlockId block_id, - const t_model_ports* model_port, - const BitIndex pin_number, + const t_pack_pattern_connections& connections, const AtomNetlist& atom_nlist) { - auto port_id = atom_nlist.find_atom_port(block_id, model_port); - - if (port_id) { - auto net_id = atom_nlist.port_net(port_id, pin_number); - if (net_id && atom_nlist.net_sinks(net_id).size() == 1) { /* Single fanout assumption */ + auto to_port_model = connections.to_pin->port->model_port; + auto to_pin_number = connections.to_pin->pin_number; + auto to_port_id = atom_nlist.find_atom_port(block_id, to_port_model); + if (to_port_id) { + auto net_id = atom_nlist.port_net(to_port_id, to_pin_number); + if (net_id) { auto driver_blk_id = atom_nlist.net_driver_block(net_id); - if (model_port->is_clock) { + if (to_port_model->is_clock) { auto driver_blk_type = atom_nlist.block_type(driver_blk_id); // TODO: support multi-clock primitives. @@ -1128,10 +1124,10 @@ static AtomBlockId get_driving_block(const AtomBlockId block_id, // be triggered as the sink block might have only one input pin, which // would be a clock pin in case the sink block primitive is a clock generator, // resulting in a pin_number == 0. - VTR_ASSERT(pin_number == 1 || (pin_number == 0 && driver_blk_type == AtomBlockType::INPAD)); + VTR_ASSERT(to_pin_number == 1 || (to_pin_number == 0 && driver_blk_type == AtomBlockType::INPAD)); } - return atom_nlist.net_driver_block(net_id); + return driver_blk_id; } } From 00082923c023c55a118ab8fa1d6e0abbf814d6f5 Mon Sep 17 00:00:00 2001 From: Amin Mohaghegh Date: Tue, 22 Apr 2025 07:11:25 -0700 Subject: [PATCH 03/12] [pack][prepack] fix the bug with finding sink pin id --- vpr/src/pack/prepack.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/vpr/src/pack/prepack.cpp b/vpr/src/pack/prepack.cpp index ad3805d378e..138baa59a86 100644 --- a/vpr/src/pack/prepack.cpp +++ b/vpr/src/pack/prepack.cpp @@ -1082,14 +1082,21 @@ static AtomBlockId get_sink_block(const AtomBlockId block_id, const t_model_ports* to_port_model = connections.to_pin->port->model_port; const int to_pin_number = connections.to_pin->pin_number; - auto to_port_id = atom_nlist.find_atom_port(block_id, to_port_model); + const auto& to_pb_type = connections.to_block->pb_type; - if (from_port_id && to_port_id) { + if (from_port_id) { auto net_id = atom_nlist.port_net(from_port_id, from_pin_number); const auto& net_sinks = atom_nlist.net_sinks(net_id); + // Iterate over all net sinks and find the one corresponding + // to the to_pin specified in the pack pattern connection for (const auto& sink_pin_id : net_sinks) { - if (atom_nlist.pin_port(sink_pin_id) == to_port_id && static_cast(atom_nlist.pin_port_bit(sink_pin_id)) == to_pin_number) { - return atom_nlist.pin_block(sink_pin_id); + auto sink_block_id = atom_nlist.pin_block(sink_pin_id); + if (primitive_type_feasible(sink_block_id, to_pb_type)) { + auto to_port_id = atom_nlist.find_atom_port(sink_block_id, to_port_model); + auto to_pin_id = atom_nlist.find_pin(to_port_id, BitIndex(to_pin_number)); + if (to_pin_id == sink_pin_id) { + return sink_block_id; + } } } } From a777170e8d9edc6fed1fc3b4829cf6343b34c795 Mon Sep 17 00:00:00 2001 From: Amin Mohaghegh Date: Tue, 22 Apr 2025 08:13:44 -0700 Subject: [PATCH 04/12] [vpr][pack] skip if net is not valid --- vpr/src/pack/prepack.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/vpr/src/pack/prepack.cpp b/vpr/src/pack/prepack.cpp index 138baa59a86..335b8210f29 100644 --- a/vpr/src/pack/prepack.cpp +++ b/vpr/src/pack/prepack.cpp @@ -1086,16 +1086,18 @@ static AtomBlockId get_sink_block(const AtomBlockId block_id, if (from_port_id) { auto net_id = atom_nlist.port_net(from_port_id, from_pin_number); - const auto& net_sinks = atom_nlist.net_sinks(net_id); // Iterate over all net sinks and find the one corresponding // to the to_pin specified in the pack pattern connection - for (const auto& sink_pin_id : net_sinks) { - auto sink_block_id = atom_nlist.pin_block(sink_pin_id); - if (primitive_type_feasible(sink_block_id, to_pb_type)) { - auto to_port_id = atom_nlist.find_atom_port(sink_block_id, to_port_model); - auto to_pin_id = atom_nlist.find_pin(to_port_id, BitIndex(to_pin_number)); - if (to_pin_id == sink_pin_id) { - return sink_block_id; + if (net_id.is_valid()) { + const auto& net_sinks = atom_nlist.net_sinks(net_id); + for (const auto& sink_pin_id : net_sinks) { + auto sink_block_id = atom_nlist.pin_block(sink_pin_id); + if (primitive_type_feasible(sink_block_id, to_pb_type)) { + auto to_port_id = atom_nlist.find_atom_port(sink_block_id, to_port_model); + auto to_pin_id = atom_nlist.find_pin(to_port_id, BitIndex(to_pin_number)); + if (to_pin_id == sink_pin_id) { + return sink_block_id; + } } } } From f4c6ee87efb7b15a6af5da100ee5abce2b3afb2c Mon Sep 17 00:00:00 2001 From: Amin Mohaghegh Date: Tue, 22 Apr 2025 09:53:42 -0700 Subject: [PATCH 05/12] [vpr][pack] consider nets with fan-out of more than one only if pack pattern is chain --- vpr/src/pack/prepack.cpp | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/vpr/src/pack/prepack.cpp b/vpr/src/pack/prepack.cpp index 335b8210f29..27ebda4aff3 100644 --- a/vpr/src/pack/prepack.cpp +++ b/vpr/src/pack/prepack.cpp @@ -108,7 +108,8 @@ static void init_molecule_chain_info(const AtomBlockId blk_id, static AtomBlockId get_sink_block(const AtomBlockId block_id, const t_pack_pattern_connections& connections, - const AtomNetlist& atom_nlist); + const AtomNetlist& atom_nlist, + bool is_chain_pattern); static AtomBlockId get_driving_block(const AtomBlockId block_id, const t_pack_pattern_connections& connections, @@ -1045,7 +1046,7 @@ static bool try_expand_molecule(t_pack_molecule& molecule, // this block is the driver of this connection if (block_connection->from_block == pattern_block) { // find the block this connection is driving and add it to the queue - auto sink_blk_id = get_sink_block(block_id, *block_connection, atom_nlist); + auto sink_blk_id = get_sink_block(block_id, *block_connection, atom_nlist, molecule.is_chain()); // add this sink block id with its corresponding pattern block to the queue pattern_block_queue.push(std::make_pair(block_connection->to_block, sink_blk_id)); // this block is being driven by this connection @@ -1075,7 +1076,8 @@ static bool try_expand_molecule(t_pack_molecule& molecule, */ static AtomBlockId get_sink_block(const AtomBlockId block_id, const t_pack_pattern_connections& connections, - const AtomNetlist& atom_nlist) { + const AtomNetlist& atom_nlist, + bool is_chain_pattern) { const t_model_ports* from_port_model = connections.from_pin->port->model_port; const int from_pin_number = connections.from_pin->pin_number; auto from_port_id = atom_nlist.find_atom_port(block_id, from_port_model); @@ -1086,19 +1088,24 @@ static AtomBlockId get_sink_block(const AtomBlockId block_id, if (from_port_id) { auto net_id = atom_nlist.port_net(from_port_id, from_pin_number); - // Iterate over all net sinks and find the one corresponding - // to the to_pin specified in the pack pattern connection if (net_id.is_valid()) { const auto& net_sinks = atom_nlist.net_sinks(net_id); - for (const auto& sink_pin_id : net_sinks) { - auto sink_block_id = atom_nlist.pin_block(sink_pin_id); - if (primitive_type_feasible(sink_block_id, to_pb_type)) { - auto to_port_id = atom_nlist.find_atom_port(sink_block_id, to_port_model); - auto to_pin_id = atom_nlist.find_pin(to_port_id, BitIndex(to_pin_number)); - if (to_pin_id == sink_pin_id) { - return sink_block_id; + if (is_chain_pattern) { + for (const auto& sink_pin_id : net_sinks) { + auto sink_block_id = atom_nlist.pin_block(sink_pin_id); + if (primitive_type_feasible(sink_block_id, to_pb_type)) { + auto to_port_id = atom_nlist.find_atom_port(sink_block_id, to_port_model); + auto to_pin_id = atom_nlist.find_pin(to_port_id, BitIndex(to_pin_number)); + if (to_pin_id == sink_pin_id) { + return sink_block_id; + } } } + } else { + if (net_sinks.size() == 1) { + auto sink_pin_id = *(net_sinks.begin()); + return atom_nlist.pin_block(sink_pin_id); + } } } } @@ -1122,7 +1129,7 @@ static AtomBlockId get_driving_block(const AtomBlockId block_id, if (to_port_id) { auto net_id = atom_nlist.port_net(to_port_id, to_pin_number); - if (net_id) { + if (net_id && atom_nlist.net_sinks(net_id).size() == 1) { /* Single fanout assumption */ auto driver_blk_id = atom_nlist.net_driver_block(net_id); if (to_port_model->is_clock) { From 7a4ff268f0b140bba2b1d0b246ce75d0f9787e54 Mon Sep 17 00:00:00 2001 From: Amin Mohaghegh Date: Tue, 22 Apr 2025 09:59:51 -0700 Subject: [PATCH 06/12] [vpr][pack] add comment --- vpr/src/pack/prepack.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/vpr/src/pack/prepack.cpp b/vpr/src/pack/prepack.cpp index 27ebda4aff3..0bd49edc8dc 100644 --- a/vpr/src/pack/prepack.cpp +++ b/vpr/src/pack/prepack.cpp @@ -1091,6 +1091,9 @@ static AtomBlockId get_sink_block(const AtomBlockId block_id, if (net_id.is_valid()) { const auto& net_sinks = atom_nlist.net_sinks(net_id); if (is_chain_pattern) { + // If the pattern is a chain, allow nets with multiple sinks. + // This enables forming chains where the COUT is connected both to + // the next element in the chain and to the block's output pin. for (const auto& sink_pin_id : net_sinks) { auto sink_block_id = atom_nlist.pin_block(sink_pin_id); if (primitive_type_feasible(sink_block_id, to_pb_type)) { @@ -1102,6 +1105,11 @@ static AtomBlockId get_sink_block(const AtomBlockId block_id, } } } else { + // For non-chain patterns, we conservatively only consider the sink block + // if the net fanout is 1. To clarify, consider a case where the output of a LUT + // is connected to both a register and an unregistered output that feeds another block. + // If the intra-cluster architecture doesn't support having both registered and + // unregistered outputs simultaneously, this could lead to a packing failure. if (net_sinks.size() == 1) { auto sink_pin_id = *(net_sinks.begin()); return atom_nlist.pin_block(sink_pin_id); From 17afb8ce6fa79fc05ac3d64734c081c4146635ed Mon Sep 17 00:00:00 2001 From: Amin Mohaghegh Date: Tue, 22 Apr 2025 10:18:41 -0700 Subject: [PATCH 07/12] make format --- vpr/src/pack/prepack.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vpr/src/pack/prepack.cpp b/vpr/src/pack/prepack.cpp index 0bd49edc8dc..3c52ba79370 100644 --- a/vpr/src/pack/prepack.cpp +++ b/vpr/src/pack/prepack.cpp @@ -1092,7 +1092,7 @@ static AtomBlockId get_sink_block(const AtomBlockId block_id, const auto& net_sinks = atom_nlist.net_sinks(net_id); if (is_chain_pattern) { // If the pattern is a chain, allow nets with multiple sinks. - // This enables forming chains where the COUT is connected both to + // This enables forming chains where the COUT is connected both to // the next element in the chain and to the block's output pin. for (const auto& sink_pin_id : net_sinks) { auto sink_block_id = atom_nlist.pin_block(sink_pin_id); @@ -1105,10 +1105,10 @@ static AtomBlockId get_sink_block(const AtomBlockId block_id, } } } else { - // For non-chain patterns, we conservatively only consider the sink block - // if the net fanout is 1. To clarify, consider a case where the output of a LUT + // For non-chain patterns, we conservatively only consider the sink block + // if the net fanout is 1. To clarify, consider a case where the output of a LUT // is connected to both a register and an unregistered output that feeds another block. - // If the intra-cluster architecture doesn't support having both registered and + // If the intra-cluster architecture doesn't support having both registered and // unregistered outputs simultaneously, this could lead to a packing failure. if (net_sinks.size() == 1) { auto sink_pin_id = *(net_sinks.begin()); From 6fa242206bdae86e698267f70d19dc441ec65717 Mon Sep 17 00:00:00 2001 From: Amin Mohaghegh Date: Tue, 22 Apr 2025 13:01:51 -0700 Subject: [PATCH 08/12] [vpr][pack] remove nested ifs and add comments --- vpr/src/pack/prepack.cpp | 91 ++++++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 41 deletions(-) diff --git a/vpr/src/pack/prepack.cpp b/vpr/src/pack/prepack.cpp index 3c52ba79370..42411023d32 100644 --- a/vpr/src/pack/prepack.cpp +++ b/vpr/src/pack/prepack.cpp @@ -1071,8 +1071,11 @@ static bool try_expand_molecule(t_pack_molecule& molecule, /** * Find the atom block in the netlist driven by this pin of the input atom block * If doesn't exist return AtomBlockId::INVALID() + * TODO: Limitation — For pack patterns other than chains, + * the block should be driven by only one block * block_id : id of the atom block that is driving the net connected to the sink block * connections : pack pattern connections from the given block + * is_chain_pattern : whether the pattern is a chain */ static AtomBlockId get_sink_block(const AtomBlockId block_id, const t_pack_pattern_connections& connections, @@ -1086,36 +1089,40 @@ static AtomBlockId get_sink_block(const AtomBlockId block_id, const int to_pin_number = connections.to_pin->pin_number; const auto& to_pb_type = connections.to_block->pb_type; - if (from_port_id) { - auto net_id = atom_nlist.port_net(from_port_id, from_pin_number); - if (net_id.is_valid()) { - const auto& net_sinks = atom_nlist.net_sinks(net_id); - if (is_chain_pattern) { - // If the pattern is a chain, allow nets with multiple sinks. - // This enables forming chains where the COUT is connected both to - // the next element in the chain and to the block's output pin. - for (const auto& sink_pin_id : net_sinks) { - auto sink_block_id = atom_nlist.pin_block(sink_pin_id); - if (primitive_type_feasible(sink_block_id, to_pb_type)) { - auto to_port_id = atom_nlist.find_atom_port(sink_block_id, to_port_model); - auto to_pin_id = atom_nlist.find_pin(to_port_id, BitIndex(to_pin_number)); - if (to_pin_id == sink_pin_id) { - return sink_block_id; - } - } - } - } else { - // For non-chain patterns, we conservatively only consider the sink block - // if the net fanout is 1. To clarify, consider a case where the output of a LUT - // is connected to both a register and an unregistered output that feeds another block. - // If the intra-cluster architecture doesn't support having both registered and - // unregistered outputs simultaneously, this could lead to a packing failure. - if (net_sinks.size() == 1) { - auto sink_pin_id = *(net_sinks.begin()); - return atom_nlist.pin_block(sink_pin_id); + if (!from_port_id.is_valid()) { + return AtomBlockId::INVALID(); + } + + auto net_id = atom_nlist.port_net(from_port_id, from_pin_number); + if (!net_id.is_valid()) { + return AtomBlockId::INVALID(); + } + + const auto& net_sinks = atom_nlist.net_sinks(net_id); + if (is_chain_pattern) { + // If the pattern is a chain, allow nets with multiple sinks. + // This enables forming chains where the COUT is connected both to + // the next element in the chain and to the block's output pin. + for (const auto& sink_pin_id : net_sinks) { + auto sink_block_id = atom_nlist.pin_block(sink_pin_id); + if (primitive_type_feasible(sink_block_id, to_pb_type)) { + auto to_port_id = atom_nlist.find_atom_port(sink_block_id, to_port_model); + auto to_pin_id = atom_nlist.find_pin(to_port_id, BitIndex(to_pin_number)); + if (to_pin_id == sink_pin_id) { + return sink_block_id; } } } + } else { + // For non-chain patterns, we conservatively only consider the sink block + // if the net fanout is 1. To clarify, consider a case where the output of a LUT + // is connected to both a register and an unregistered output that feeds another block. + // If the intra-cluster architecture doesn't support having both registered and + // unregistered outputs simultaneously, this could lead to a packing failure. + if (net_sinks.size() == 1) { + auto sink_pin_id = *(net_sinks.begin()); + return atom_nlist.pin_block(sink_pin_id); + } } return AtomBlockId::INVALID(); @@ -1135,24 +1142,26 @@ static AtomBlockId get_driving_block(const AtomBlockId block_id, auto to_pin_number = connections.to_pin->pin_number; auto to_port_id = atom_nlist.find_atom_port(block_id, to_port_model); - if (to_port_id) { - auto net_id = atom_nlist.port_net(to_port_id, to_pin_number); - if (net_id && atom_nlist.net_sinks(net_id).size() == 1) { /* Single fanout assumption */ - auto driver_blk_id = atom_nlist.net_driver_block(net_id); + if (!to_port_id.is_valid()) { + return AtomBlockId::INVALID(); + } - if (to_port_model->is_clock) { - auto driver_blk_type = atom_nlist.block_type(driver_blk_id); + auto net_id = atom_nlist.port_net(to_port_id, to_pin_number); + if (net_id && atom_nlist.net_sinks(net_id).size() == 1) { /* Single fanout assumption */ + auto driver_blk_id = atom_nlist.net_driver_block(net_id); - // TODO: support multi-clock primitives. - // If the driver block is a .input block, this assertion should not - // be triggered as the sink block might have only one input pin, which - // would be a clock pin in case the sink block primitive is a clock generator, - // resulting in a pin_number == 0. - VTR_ASSERT(to_pin_number == 1 || (to_pin_number == 0 && driver_blk_type == AtomBlockType::INPAD)); - } + if (to_port_model->is_clock) { + auto driver_blk_type = atom_nlist.block_type(driver_blk_id); - return driver_blk_id; + // TODO: support multi-clock primitives. + // If the driver block is a .input block, this assertion should not + // be triggered as the sink block might have only one input pin, which + // would be a clock pin in case the sink block primitive is a clock generator, + // resulting in a pin_number == 0. + VTR_ASSERT(to_pin_number == 1 || (to_pin_number == 0 && driver_blk_type == AtomBlockType::INPAD)); } + + return driver_blk_id; } return AtomBlockId::INVALID(); From b4587bc86390ae7a663dbf33f07657540b882534 Mon Sep 17 00:00:00 2001 From: Amin Mohaghegh Date: Tue, 22 Apr 2025 17:12:39 -0700 Subject: [PATCH 09/12] [vpr][pack] skip the blocck if it is connected to ff and another block --- vpr/src/pack/prepack.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/vpr/src/pack/prepack.cpp b/vpr/src/pack/prepack.cpp index 42411023d32..78856a4bfed 100644 --- a/vpr/src/pack/prepack.cpp +++ b/vpr/src/pack/prepack.cpp @@ -1103,16 +1103,30 @@ static AtomBlockId get_sink_block(const AtomBlockId block_id, // If the pattern is a chain, allow nets with multiple sinks. // This enables forming chains where the COUT is connected both to // the next element in the chain and to the block's output pin. + bool connected_to_latch = false; + AtomBlockId pattern_sink_block_id = AtomBlockId::INVALID(); for (const auto& sink_pin_id : net_sinks) { auto sink_block_id = atom_nlist.pin_block(sink_pin_id); + if (atom_nlist.block_model(sink_block_id)->name == std::string(MODEL_LATCH)) { + connected_to_latch = true; + } if (primitive_type_feasible(sink_block_id, to_pb_type)) { auto to_port_id = atom_nlist.find_atom_port(sink_block_id, to_port_model); auto to_pin_id = atom_nlist.find_pin(to_port_id, BitIndex(to_pin_number)); if (to_pin_id == sink_pin_id) { - return sink_block_id; + pattern_sink_block_id = sink_block_id; } } } + // If the number of sinks is greater than 1, and one of the connected blocks is a latch, + // then we drop the block to avoid a situation where only registers or unregistered output + // of the block can use the output pin. + // TODO: This is a conservative assumption, and ideally we need to do analysis of the architecture + // before to determine which pattern is supported by the architecture. + if (connected_to_latch && net_sinks.size() > 1) { + return AtomBlockId::INVALID(); + } + return pattern_sink_block_id; } else { // For non-chain patterns, we conservatively only consider the sink block // if the net fanout is 1. To clarify, consider a case where the output of a LUT From 48ba9b0da03d3df0643de1b19a8d9dd061c3c99a Mon Sep 17 00:00:00 2001 From: Amin Mohaghegh Date: Wed, 23 Apr 2025 07:30:40 -0700 Subject: [PATCH 10/12] [vpr][pack] don't separate chain pattern w/ non-chain --- vpr/src/pack/prepack.cpp | 62 ++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 38 deletions(-) diff --git a/vpr/src/pack/prepack.cpp b/vpr/src/pack/prepack.cpp index 78856a4bfed..160d63caa98 100644 --- a/vpr/src/pack/prepack.cpp +++ b/vpr/src/pack/prepack.cpp @@ -1099,47 +1099,33 @@ static AtomBlockId get_sink_block(const AtomBlockId block_id, } const auto& net_sinks = atom_nlist.net_sinks(net_id); - if (is_chain_pattern) { - // If the pattern is a chain, allow nets with multiple sinks. - // This enables forming chains where the COUT is connected both to - // the next element in the chain and to the block's output pin. - bool connected_to_latch = false; - AtomBlockId pattern_sink_block_id = AtomBlockId::INVALID(); - for (const auto& sink_pin_id : net_sinks) { - auto sink_block_id = atom_nlist.pin_block(sink_pin_id); - if (atom_nlist.block_model(sink_block_id)->name == std::string(MODEL_LATCH)) { - connected_to_latch = true; - } - if (primitive_type_feasible(sink_block_id, to_pb_type)) { - auto to_port_id = atom_nlist.find_atom_port(sink_block_id, to_port_model); - auto to_pin_id = atom_nlist.find_pin(to_port_id, BitIndex(to_pin_number)); - if (to_pin_id == sink_pin_id) { - pattern_sink_block_id = sink_block_id; - } - } + // If the pattern is a chain, allow nets with multiple sinks. + // This enables forming chains where the COUT is connected both to + // the next element in the chain and to the block's output pin. + bool connected_to_latch = false; + AtomBlockId pattern_sink_block_id = AtomBlockId::INVALID(); + for (const auto& sink_pin_id : net_sinks) { + auto sink_block_id = atom_nlist.pin_block(sink_pin_id); + if (atom_nlist.block_model(sink_block_id)->name == std::string(MODEL_LATCH)) { + connected_to_latch = true; } - // If the number of sinks is greater than 1, and one of the connected blocks is a latch, - // then we drop the block to avoid a situation where only registers or unregistered output - // of the block can use the output pin. - // TODO: This is a conservative assumption, and ideally we need to do analysis of the architecture - // before to determine which pattern is supported by the architecture. - if (connected_to_latch && net_sinks.size() > 1) { - return AtomBlockId::INVALID(); - } - return pattern_sink_block_id; - } else { - // For non-chain patterns, we conservatively only consider the sink block - // if the net fanout is 1. To clarify, consider a case where the output of a LUT - // is connected to both a register and an unregistered output that feeds another block. - // If the intra-cluster architecture doesn't support having both registered and - // unregistered outputs simultaneously, this could lead to a packing failure. - if (net_sinks.size() == 1) { - auto sink_pin_id = *(net_sinks.begin()); - return atom_nlist.pin_block(sink_pin_id); + if (primitive_type_feasible(sink_block_id, to_pb_type)) { + auto to_port_id = atom_nlist.find_atom_port(sink_block_id, to_port_model); + auto to_pin_id = atom_nlist.find_pin(to_port_id, BitIndex(to_pin_number)); + if (to_pin_id == sink_pin_id) { + pattern_sink_block_id = sink_block_id; + } } } - - return AtomBlockId::INVALID(); + // If the number of sinks is greater than 1, and one of the connected blocks is a latch, + // then we drop the block to avoid a situation where only registers or unregistered output + // of the block can use the output pin. + // TODO: This is a conservative assumption, and ideally we need to do analysis of the architecture + // before to determine which pattern is supported by the architecture. + if (connected_to_latch && net_sinks.size() > 1) { + pattern_sink_block_id = AtomBlockId::INVALID(); + } + return pattern_sink_block_id; } /** From 00d6d9445664ed3072ec57aa240a3f7c38ded7d1 Mon Sep 17 00:00:00 2001 From: Amin Mohaghegh Date: Wed, 23 Apr 2025 07:33:53 -0700 Subject: [PATCH 11/12] [vpr][pack] update comments --- vpr/src/pack/prepack.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/vpr/src/pack/prepack.cpp b/vpr/src/pack/prepack.cpp index 160d63caa98..34457e9845b 100644 --- a/vpr/src/pack/prepack.cpp +++ b/vpr/src/pack/prepack.cpp @@ -1099,9 +1099,8 @@ static AtomBlockId get_sink_block(const AtomBlockId block_id, } const auto& net_sinks = atom_nlist.net_sinks(net_id); - // If the pattern is a chain, allow nets with multiple sinks. - // This enables forming chains where the COUT is connected both to - // the next element in the chain and to the block's output pin. + // Iterate through all sink blocks and check whether any of them + // is compatible with the block specified in the pack pattern. bool connected_to_latch = false; AtomBlockId pattern_sink_block_id = AtomBlockId::INVALID(); for (const auto& sink_pin_id : net_sinks) { From d7549ca723e6ec8953b63fef8d828b5d6616b0b9 Mon Sep 17 00:00:00 2001 From: amin1377 Date: Wed, 23 Apr 2025 15:30:53 +0000 Subject: [PATCH 12/12] [vpr][pack] remove is_chan_patter parameter --- vpr/src/pack/prepack.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/vpr/src/pack/prepack.cpp b/vpr/src/pack/prepack.cpp index 34457e9845b..6f80d5927a5 100644 --- a/vpr/src/pack/prepack.cpp +++ b/vpr/src/pack/prepack.cpp @@ -108,8 +108,7 @@ static void init_molecule_chain_info(const AtomBlockId blk_id, static AtomBlockId get_sink_block(const AtomBlockId block_id, const t_pack_pattern_connections& connections, - const AtomNetlist& atom_nlist, - bool is_chain_pattern); + const AtomNetlist& atom_nlist); static AtomBlockId get_driving_block(const AtomBlockId block_id, const t_pack_pattern_connections& connections, @@ -1046,7 +1045,7 @@ static bool try_expand_molecule(t_pack_molecule& molecule, // this block is the driver of this connection if (block_connection->from_block == pattern_block) { // find the block this connection is driving and add it to the queue - auto sink_blk_id = get_sink_block(block_id, *block_connection, atom_nlist, molecule.is_chain()); + auto sink_blk_id = get_sink_block(block_id, *block_connection, atom_nlist); // add this sink block id with its corresponding pattern block to the queue pattern_block_queue.push(std::make_pair(block_connection->to_block, sink_blk_id)); // this block is being driven by this connection @@ -1075,12 +1074,10 @@ static bool try_expand_molecule(t_pack_molecule& molecule, * the block should be driven by only one block * block_id : id of the atom block that is driving the net connected to the sink block * connections : pack pattern connections from the given block - * is_chain_pattern : whether the pattern is a chain */ static AtomBlockId get_sink_block(const AtomBlockId block_id, const t_pack_pattern_connections& connections, - const AtomNetlist& atom_nlist, - bool is_chain_pattern) { + const AtomNetlist& atom_nlist) { const t_model_ports* from_port_model = connections.from_pin->port->model_port; const int from_pin_number = connections.from_pin->pin_number; auto from_port_id = atom_nlist.find_atom_port(block_id, from_port_model);