diff --git a/vpr/src/pack/prepack.cpp b/vpr/src/pack/prepack.cpp index 05912f70b12..6f80d5927a5 100644 --- a/vpr/src/pack/prepack.cpp +++ b/vpr/src/pack/prepack.cpp @@ -107,13 +107,11 @@ 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, - 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); @@ -1047,17 +1045,13 @@ 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 } 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)); } @@ -1076,27 +1070,58 @@ 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 + * 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 - * 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; + const auto& to_pb_type = connections.to_block->pb_type; + + if (!from_port_id.is_valid()) { + return AtomBlockId::INVALID(); } - 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); + // 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) { + 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 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; } /** @@ -1104,34 +1129,35 @@ 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); - auto driver_blk_id = atom_nlist.net_driver_block(net_id); + if (!to_port_id.is_valid()) { + return AtomBlockId::INVALID(); + } - if (model_port->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(pin_number == 1 || (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 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)); } + + return driver_blk_id; } return AtomBlockId::INVALID();