From 7b956b61d0aa47c49815232e48117ad1a8d387b9 Mon Sep 17 00:00:00 2001 From: Duck Deux Date: Thu, 15 Aug 2024 08:49:20 -0700 Subject: [PATCH] Add flat version of sync_netlists_to_routing --- libs/libarchfpga/src/physical_types.h | 3 + .../src/io/rr_graph_uxsdcxx_serializer.h | 2 +- utils/fasm/src/main.cpp | 16 +- utils/fasm/test/test_fasm.cpp | 23 +- vpr/src/base/atom_lookup.cpp | 53 +- vpr/src/base/atom_lookup.h | 21 +- vpr/src/base/read_netlist.cpp | 4 +- vpr/src/base/vpr_api.cpp | 29 +- vpr/src/base/vpr_context.h | 3 + vpr/src/draw/search_bar.cpp | 5 +- vpr/src/pack/pack.cpp | 2 +- vpr/src/pack/post_routing_pb_pin_fixup.cpp | 52 +- vpr/src/pack/post_routing_pb_pin_fixup.h | 22 +- .../pack/sync_netlists_to_routing_flat.cpp | 469 ++++++++++++++++++ vpr/src/pack/sync_netlists_to_routing_flat.h | 18 + vpr/src/route/annotate_routing.cpp | 44 +- vpr/src/route/annotate_routing.h | 16 +- vpr/src/route/route_common.cpp | 2 + vpr/src/route/route_utils.h | 13 + vpr/src/util/vpr_utils.cpp | 2 +- 20 files changed, 649 insertions(+), 150 deletions(-) create mode 100644 vpr/src/pack/sync_netlists_to_routing_flat.cpp create mode 100644 vpr/src/pack/sync_netlists_to_routing_flat.h diff --git a/libs/libarchfpga/src/physical_types.h b/libs/libarchfpga/src/physical_types.h index d34c4382f75..3742795ed40 100644 --- a/libs/libarchfpga/src/physical_types.h +++ b/libs/libarchfpga/src/physical_types.h @@ -1689,6 +1689,9 @@ constexpr std::array SWITCH_T */ constexpr const char* VPR_DELAYLESS_SWITCH_NAME = "__vpr_delayless_switch__"; +/* An intracluster switch automatically added to the RRG by the flat router. */ +constexpr const char* VPR_INTERNAL_SWITCH_NAME = "__vpr_intra_cluster_switch__"; + enum class BufferSize { AUTO, ABSOLUTE diff --git a/libs/librrgraph/src/io/rr_graph_uxsdcxx_serializer.h b/libs/librrgraph/src/io/rr_graph_uxsdcxx_serializer.h index 6c820aeb192..f13a1c7b686 100644 --- a/libs/librrgraph/src/io/rr_graph_uxsdcxx_serializer.h +++ b/libs/librrgraph/src/io/rr_graph_uxsdcxx_serializer.h @@ -526,7 +526,7 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { bool found_arch_name = false; std::string string_name = std::string(name); // The string name has the format of "Internal Switch/delay". So, I have to use compare to specify the portion I want to be compared. - bool is_internal_sw = string_name.compare(0, 15, "Internal Switch") == 0; + bool is_internal_sw = string_name.compare(0, strlen(VPR_INTERNAL_SWITCH_NAME), VPR_INTERNAL_SWITCH_NAME) == 0; for (const auto& arch_sw_inf: arch_switch_inf_) { if (string_name == arch_sw_inf.name || is_internal_sw) { found_arch_name = true; diff --git a/utils/fasm/src/main.cpp b/utils/fasm/src/main.cpp index d0e9c8040c9..2fbee0a79c2 100644 --- a/utils/fasm/src/main.cpp +++ b/utils/fasm/src/main.cpp @@ -23,6 +23,7 @@ using namespace std; #include "fasm.h" #include "post_routing_pb_pin_fixup.h" +#include "sync_netlists_to_routing_flat.h" /* * Exit codes to signal success/failure to scripts @@ -87,25 +88,14 @@ int main(int argc, const char **argv) { bool is_flat = vpr_setup.RouterOpts.flat_routing; if (flow_succeeded) { if(is_flat) { - sync_netlists_to_routing((const Netlist<>&) g_vpr_ctx.atom().nlist, - g_vpr_ctx.device(), - g_vpr_ctx.mutable_atom(), - g_vpr_ctx.atom().lookup, - g_vpr_ctx.mutable_clustering(), - g_vpr_ctx.placement(), - g_vpr_ctx.routing(), - vpr_setup.PackerOpts.pack_verbosity > 2, - is_flat); + sync_netlists_to_routing_flat(); } else { sync_netlists_to_routing((const Netlist<>&) g_vpr_ctx.clustering().clb_nlist, g_vpr_ctx.device(), g_vpr_ctx.mutable_atom(), - g_vpr_ctx.atom().lookup, g_vpr_ctx.mutable_clustering(), g_vpr_ctx.placement(), - g_vpr_ctx.routing(), - vpr_setup.PackerOpts.pack_verbosity > 2, - is_flat); + vpr_setup.PackerOpts.pack_verbosity > 2); } } diff --git a/utils/fasm/test/test_fasm.cpp b/utils/fasm/test/test_fasm.cpp index 387d77fb3b5..2b750e76652 100644 --- a/utils/fasm/test/test_fasm.cpp +++ b/utils/fasm/test/test_fasm.cpp @@ -9,13 +9,15 @@ #include "fasm_utils.h" #include "arch_util.h" #include "rr_graph_writer.h" -#include "post_routing_pb_pin_fixup.h" #include #include #include #include #include +#include "post_routing_pb_pin_fixup.h" +#include "sync_netlists_to_routing_flat.h" + static constexpr const char kArchFile[] = "test_fasm_arch.xml"; static constexpr const char kRrGraphFile[] = "test_fasm_rrgraph.xml"; @@ -328,15 +330,16 @@ TEST_CASE("fasm_integration_test", "[fasm]") { /* Sync netlist to the actual routing (necessary if there are block ports with equivalent pins) */ if (flow_succeeded) { - sync_netlists_to_routing((const Netlist<>&) g_vpr_ctx.clustering().clb_nlist, - g_vpr_ctx.device(), - g_vpr_ctx.mutable_atom(), - g_vpr_ctx.atom().lookup, - g_vpr_ctx.mutable_clustering(), - g_vpr_ctx.placement(), - g_vpr_ctx.routing(), - vpr_setup.PackerOpts.pack_verbosity > 2, - is_flat); + if (is_flat) { + sync_netlists_to_routing_flat(); + } else { + sync_netlists_to_routing((const Netlist<>&) g_vpr_ctx.clustering().clb_nlist, + g_vpr_ctx.device(), + g_vpr_ctx.mutable_atom(), + g_vpr_ctx.mutable_clustering(), + g_vpr_ctx.placement(), + vpr_setup.PackerOpts.pack_verbosity > 2); + } } std::stringstream fasm_string; diff --git a/vpr/src/base/atom_lookup.cpp b/vpr/src/base/atom_lookup.cpp index 8b3a45c0098..f771b8af154 100644 --- a/vpr/src/base/atom_lookup.cpp +++ b/vpr/src/base/atom_lookup.cpp @@ -1,5 +1,7 @@ +#include "clustered_netlist_fwd.h" #include "vtr_assert.h" #include "vtr_log.h" +#include "vtr_optional.h" #include "atom_lookup.h" /* @@ -85,36 +87,51 @@ void AtomLookup::set_atom_clb(const AtomBlockId blk_id, const ClusterBlockId clb * Nets */ AtomNetId AtomLookup::atom_net(const ClusterNetId clb_net_index) const { - auto iter = atom_net_to_clb_net_.find(clb_net_index); - if (iter == atom_net_to_clb_net_.inverse_end()) { + auto iter = clb_net_to_atom_net_.find(clb_net_index); + if (iter == clb_net_to_atom_net_.end()) { //Not found return AtomNetId::INVALID(); } return iter->second; } -ClusterNetId AtomLookup::clb_net(const AtomNetId net_id) const { - auto iter = atom_net_to_clb_net_.find(net_id); - if (iter == atom_net_to_clb_net_.end()) { +vtr::optional&> AtomLookup::clb_nets(const AtomNetId atom_net) const { + auto iter = atom_net_to_clb_nets_.find(atom_net); + if (iter == atom_net_to_clb_nets_.end()) { //Not found - return ClusterNetId::INVALID(); + return vtr::nullopt; } return iter->second; } -void AtomLookup::set_atom_clb_net(const AtomNetId net_id, const ClusterNetId clb_net_index) { - VTR_ASSERT(net_id); - //If either are invalid remove any mapping - if (!net_id && clb_net_index != ClusterNetId::INVALID()) { - //Remove - atom_net_to_clb_net_.erase(clb_net_index); - } else if (net_id && clb_net_index == ClusterNetId::INVALID()) { - //Remove - atom_net_to_clb_net_.erase(net_id); - } else if (net_id && clb_net_index != ClusterNetId::INVALID()) { - //Store - atom_net_to_clb_net_.update(net_id, clb_net_index); +void AtomLookup::add_atom_clb_net(const AtomNetId atom_net, const ClusterNetId clb_net) { + VTR_ASSERT(atom_net && clb_net); + + /* Use the default behavior of [] operator */ + atom_net_to_clb_nets_[atom_net].push_back(clb_net); + clb_net_to_atom_net_[clb_net] = atom_net; +} + +void AtomLookup::remove_clb_net(const ClusterNetId clb_net){ + if(!clb_net_to_atom_net_.count(clb_net)) + return; + + auto atom_net = clb_net_to_atom_net_[clb_net]; + auto& all_clb_nets = atom_net_to_clb_nets_[atom_net]; + /* This is o(n), but an AtomNetId rarely has >5 ClusterNetIds */ + all_clb_nets.erase(std::remove(all_clb_nets.begin(), all_clb_nets.end(), clb_net), all_clb_nets.end()); +} + +/* Remove mapping for given atom net */ +void AtomLookup::remove_atom_net(const AtomNetId atom_net) { + if(!atom_net_to_clb_nets_.count(atom_net)) + return; + + auto cluster_nets = atom_net_to_clb_nets_[atom_net]; + for(auto c: cluster_nets){ + clb_net_to_atom_net_.erase(c); } + atom_net_to_clb_nets_.erase(atom_net); } /* diff --git a/vpr/src/base/atom_lookup.h b/vpr/src/base/atom_lookup.h index c87807056f8..fdf17cddd46 100644 --- a/vpr/src/base/atom_lookup.h +++ b/vpr/src/base/atom_lookup.h @@ -13,6 +13,8 @@ #include "vpr_types.h" #include "tatum/TimingGraphFwd.hpp" +#include "vtr_optional.h" + /** * @brief The AtomLookup class describes the mapping between components in the AtomNetlist * and other netlists/entities (i.e. atom block <-> t_pb, atom block <-> clb) @@ -76,17 +78,21 @@ class AtomLookup { */ ///@brief Returns the atom net id associated with the clb_net_index - AtomNetId atom_net(const ClusterNetId clb_net_index) const; + AtomNetId atom_net(const ClusterNetId cluster_net_id) const; - ///@brief Returns the clb net index associated with net_id - ClusterNetId clb_net(const AtomNetId net_id) const; + ///@brief Returns the clb net indices associated with atom_net_id + vtr::optional&> clb_nets(const AtomNetId atom_net_id) const; /** * @brief Sets the bidirectional mapping between an atom net and a clb net - * - * If either net_id or clb_net_index are not valid any existing mapping is removed */ - void set_atom_clb_net(const AtomNetId net_id, const ClusterNetId clb_net_index); + void add_atom_clb_net(const AtomNetId atom_net, const ClusterNetId clb_net); + + /** Remove given clb net from the mapping */ + void remove_clb_net(const ClusterNetId clb_net); + + /** Remove given atom net from the mapping */ + void remove_atom_net(const AtomNetId atom_net); /* * Timing Nodes @@ -112,7 +118,8 @@ class AtomLookup { vtr::vector_map atom_to_clb_; - vtr::bimap atom_net_to_clb_net_; + vtr::linear_map> atom_net_to_clb_nets_; + vtr::linear_map clb_net_to_atom_net_; vtr::linear_map atom_pin_tnode_external_; vtr::linear_map atom_pin_tnode_internal_; diff --git a/vpr/src/base/read_netlist.cpp b/vpr/src/base/read_netlist.cpp index 6aee712a04b..4f2d5f6da06 100644 --- a/vpr/src/base/read_netlist.cpp +++ b/vpr/src/base/read_netlist.cpp @@ -218,14 +218,14 @@ ClusteredNetlist read_netlist(const char* net_file, /* load mapping between external nets and all nets */ for (auto net_id : atom_ctx.nlist.nets()) { - atom_ctx.lookup.set_atom_clb_net(net_id, ClusterNetId::INVALID()); + atom_ctx.lookup.remove_atom_net(net_id); } //Save the mapping between clb and atom nets for (auto clb_net_id : clb_nlist.nets()) { AtomNetId net_id = atom_ctx.nlist.find_net(clb_nlist.net_name(clb_net_id)); VTR_ASSERT(net_id); - atom_ctx.lookup.set_atom_clb_net(net_id, clb_net_id); + atom_ctx.lookup.add_atom_clb_net(net_id, clb_net_id); } // Mark ignored and global atom nets diff --git a/vpr/src/base/vpr_api.cpp b/vpr/src/base/vpr_api.cpp index 9b45cf46b9e..8f7df673b68 100644 --- a/vpr/src/base/vpr_api.cpp +++ b/vpr/src/base/vpr_api.cpp @@ -86,7 +86,7 @@ #include "arch_util.h" #include "post_routing_pb_pin_fixup.h" - +#include "sync_netlists_to_routing_flat.h" #include "load_flat_place.h" @@ -1477,27 +1477,26 @@ bool vpr_analysis_flow(const Netlist<>& net_list, * - Turn on verbose output when users require verbose output * for packer (default verbosity is set to 2 for compact logs) */ - if (!is_flat) { - if (route_status.success()) { + if (route_status.success()) { + if (is_flat) { + sync_netlists_to_routing_flat(); + } else { sync_netlists_to_routing(net_list, g_vpr_ctx.device(), g_vpr_ctx.mutable_atom(), - g_vpr_ctx.atom().lookup, g_vpr_ctx.mutable_clustering(), g_vpr_ctx.placement(), - g_vpr_ctx.routing(), - vpr_setup.PackerOpts.pack_verbosity > 2, - is_flat); - - std::string post_routing_packing_output_file_name = vpr_setup.PackerOpts.output_file + ".post_routing"; - write_packing_results_to_xml(vpr_setup.PackerOpts.global_clocks, - Arch.architecture_id, - post_routing_packing_output_file_name.c_str()); - } else { - VTR_LOG_WARN("Synchronization between packing and routing results is not applied due to illegal circuit implementation\n"); + vpr_setup.PackerOpts.pack_verbosity > 2); } - VTR_LOG("\n"); + + std::string post_routing_packing_output_file_name = vpr_setup.PackerOpts.output_file + ".post_routing"; + write_packing_results_to_xml(vpr_setup.PackerOpts.global_clocks, + Arch.architecture_id, + post_routing_packing_output_file_name.c_str()); + } else { + VTR_LOG_WARN("Synchronization between packing and routing results is not applied due to illegal circuit implementation\n"); } + VTR_LOG("\n"); vpr_analysis(net_list, vpr_setup, diff --git a/vpr/src/base/vpr_context.h b/vpr/src/base/vpr_context.h index d684527f2cd..f9b90d0b60b 100644 --- a/vpr/src/base/vpr_context.h +++ b/vpr/src/base/vpr_context.h @@ -466,6 +466,9 @@ struct RoutingContext : public Context { * @brief User specified routing constraints */ UserRouteConstraints constraints; + + /** Is flat routing enabled? */ + bool is_flat; }; /** diff --git a/vpr/src/draw/search_bar.cpp b/vpr/src/draw/search_bar.cpp index c0aeef85f84..b557b27d5ca 100644 --- a/vpr/src/draw/search_bar.cpp +++ b/vpr/src/draw/search_bar.cpp @@ -167,8 +167,9 @@ void search_and_highlight(GtkWidget* /*widget*/, ezgl::application* app) { warning_dialog_box("Invalid Net Name"); return; //name not exist } - ClusterNetId clb_net_id = atom_ctx.lookup.clb_net(atom_net_id); - highlight_nets(clb_net_id); + for(auto clb_net_id: atom_ctx.lookup.clb_nets(atom_net_id).value()){ + highlight_nets(clb_net_id); + } } else diff --git a/vpr/src/pack/pack.cpp b/vpr/src/pack/pack.cpp index 6da6e3ffbf7..566ca03e3ae 100644 --- a/vpr/src/pack/pack.cpp +++ b/vpr/src/pack/pack.cpp @@ -232,7 +232,7 @@ bool try_pack(t_packer_opts* packer_opts, g_vpr_ctx.mutable_atom().lookup.set_atom_pb(blk, nullptr); } for (auto net : g_vpr_ctx.atom().nlist.nets()) { - g_vpr_ctx.mutable_atom().lookup.set_atom_clb_net(net, ClusterNetId::INVALID()); + g_vpr_ctx.mutable_atom().lookup.remove_atom_net(net); } g_vpr_ctx.mutable_floorplanning().cluster_constraints.clear(); //attraction_groups.reset_attraction_groups(); diff --git a/vpr/src/pack/post_routing_pb_pin_fixup.cpp b/vpr/src/pack/post_routing_pb_pin_fixup.cpp index e8c2c34a126..78084d56df3 100644 --- a/vpr/src/pack/post_routing_pb_pin_fixup.cpp +++ b/vpr/src/pack/post_routing_pb_pin_fixup.cpp @@ -48,15 +48,13 @@ static std::vector find_physical_tile_pin_side(t_physical_tile_type_ptr * - if the net id does not match, we update the clustering context *******************************************************************/ static void update_cluster_pin_with_post_routing_results(const Netlist<>& net_list, - const AtomContext& atom_ctx, const DeviceContext& device_ctx, ClusteringContext& clustering_ctx, - const vtr::vector& rr_node_nets, + const vtr::vector& rr_node_nets, const t_pl_loc& grid_coord, const ClusterBlockId& blk_id, size_t& num_mismatches, - const bool& verbose, - bool is_flat) { + const bool& verbose) { const int sub_tile_z = grid_coord.sub_tile; const int coord_x = grid_coord.x; const int coord_y = grid_coord.y; @@ -210,15 +208,7 @@ static void update_cluster_pin_with_post_routing_results(const Netlist<>& net_li continue; } - ClusterNetId cluster_equivalent_net_id = ClusterNetId::INVALID(); - if (is_flat) { - cluster_equivalent_net_id = atom_ctx.lookup.clb_net(convert_to_atom_net_id(routing_net_id)); - if (routing_net_id != ParentNetId::INVALID()) { - VTR_ASSERT(cluster_equivalent_net_id != ClusterNetId::INVALID()); - } - } else { - cluster_equivalent_net_id = convert_to_cluster_net_id(routing_net_id); - } + ClusterNetId cluster_equivalent_net_id = convert_to_cluster_net_id(routing_net_id); /* If the net from the routing results matches the net from the packing results, * nothing to be changed. Move on to the next net. @@ -1029,29 +1019,12 @@ static void update_cluster_routing_traces_with_post_routing_results(AtomContext& pb->pb_route = new_pb_routes; } -/******************************************************************** - * Top-level function to synchronize a packed netlist to routing results - * The problem comes from a mismatch between the packing and routing results - * When there are equivalent input/output for any grids, router will try - * to swap the net mapping among these pins so as to achieve best - * routing optimization. - * However, it will cause the packing results out-of-date as the net mapping - * of each grid remain untouched once packing is done. - * This function aims to fix the mess after routing so that the net mapping - * can be synchronized - * - * Note: - * - This function SHOULD be run ONLY when routing is finished!!! - *******************************************************************/ void sync_netlists_to_routing(const Netlist<>& net_list, const DeviceContext& device_ctx, AtomContext& atom_ctx, - const AtomLookup& atom_look_up, ClusteringContext& clustering_ctx, const PlacementContext& placement_ctx, - const RoutingContext& routing_ctx, - const bool& verbose, - bool is_flat) { + const bool& verbose) { vtr::ScopedStartFinishTimer timer("Synchronize the packed netlist to routing optimization"); /* Reset the database for post-routing clb net mapping */ @@ -1059,11 +1032,9 @@ void sync_netlists_to_routing(const Netlist<>& net_list, clustering_ctx.pre_routing_net_pin_mapping.clear(); /* Create net-to-rr_node mapping */ - vtr::vector rr_node_nets = annotate_rr_node_nets(net_list, + vtr::vector rr_node_nets = annotate_rr_node_nets(clustering_ctx, device_ctx, - routing_ctx, - verbose, - is_flat); + verbose); IntraLbPbPinLookup intra_lb_pb_pin_lookup(device_ctx.logical_block_types); @@ -1076,25 +1047,18 @@ void sync_netlists_to_routing(const Netlist<>& net_list, /* Update the core logic (center blocks of the FPGA) */ for (const ParentBlockId& blk_id : net_list.blocks()) { /* We know the entrance to grid info and mapping results, do the fix-up for this block */ - ClusterBlockId clb_blk_id; - if (is_flat) { - clb_blk_id = atom_look_up.atom_clb(convert_to_atom_block_id(blk_id)); - } else { - clb_blk_id = convert_to_cluster_block_id(blk_id); - } + ClusterBlockId clb_blk_id = convert_to_cluster_block_id(blk_id); VTR_ASSERT(clb_blk_id != ClusterBlockId::INVALID()); if (seen_block_ids.insert(clb_blk_id).second) { update_cluster_pin_with_post_routing_results(net_list, - atom_ctx, device_ctx, clustering_ctx, rr_node_nets, placement_ctx.block_locs()[clb_blk_id].loc, clb_blk_id, num_mismatches, - verbose, - is_flat); + verbose); update_cluster_routing_traces_with_post_routing_results(atom_ctx, intra_lb_pb_pin_lookup, diff --git a/vpr/src/pack/post_routing_pb_pin_fixup.h b/vpr/src/pack/post_routing_pb_pin_fixup.h index 3ad16c38d0c..2459da04487 100644 --- a/vpr/src/pack/post_routing_pb_pin_fixup.h +++ b/vpr/src/pack/post_routing_pb_pin_fixup.h @@ -9,14 +9,28 @@ /******************************************************************** * Function declaration *******************************************************************/ + +/******************************************************************** + * Top-level function to synchronize a packed netlist to routing results + * The problem comes from a mismatch between the packing and routing results + * When there are equivalent input/output for any grids, the router will try + * to swap the net mapping among these pins so as to achieve best + * routing optimization. + * However, it will cause the packing results out-of-date as the net mapping + * of each grid remain untouched once packing is done. + * This function aims to fix the mess after routing so that the net mapping + * can be synchronized + * + * Note: + * - This function SHOULD be run ONLY when routing is finished. + * - This function only handles the two-stage routing results. + * See \see sync_netlists_to_routing_flat() for the flat routing case. + *******************************************************************/ void sync_netlists_to_routing(const Netlist<>& net_list, const DeviceContext& device_ctx, AtomContext& atom_ctx, - const AtomLookup& atom_lookup, ClusteringContext& clustering_ctx, const PlacementContext& placement_ctx, - const RoutingContext& routing_ctx, - const bool& verbose, - bool is_flat); + const bool& verbose); #endif diff --git a/vpr/src/pack/sync_netlists_to_routing_flat.cpp b/vpr/src/pack/sync_netlists_to_routing_flat.cpp new file mode 100644 index 00000000000..01ab9d7866c --- /dev/null +++ b/vpr/src/pack/sync_netlists_to_routing_flat.cpp @@ -0,0 +1,469 @@ +/** +* @file sync_netlists_to_routing_flat.cpp +* +* @brief Implementation for \see sync_netlists_to_routing_flat(). +*/ + +#include "clustered_netlist_fwd.h" +#include "clustered_netlist_utils.h" +#include "logic_types.h" +#include "netlist_fwd.h" +#include "physical_types.h" +#include "vtr_time.h" +#include "vtr_assert.h" +#include "vtr_log.h" + +#include "annotate_routing.h" +#include "globals.h" +#include "vpr_error.h" +#include "vpr_utils.h" +#include "rr_graph2.h" + +#include "sync_netlists_to_routing_flat.h" + +/* Static function decls (file-scope) */ + +/** Get intra-cluster connections from a given RouteTree. Output pairs to \p out_connections . */ +static void get_intra_cluster_connections(const RouteTree& tree, std::vector>& out_connections); + +/** Rudimentary intra-cluster router between two pb_graph pins. + * This is needed because the flat router compresses the RRG reducing singular paths into nodes. + * We need to unpack it to get valid packing results, which is the purpose of this simple BFS router. + * Outputs the path to the pb_routes field of \p out_pb . */ +static void route_intra_cluster_conn(const t_pb_graph_pin* source_pin, const t_pb_graph_pin* sink_pin, AtomNetId net_id, t_pb* out_pb); + +/** Rebuild the pb.pb_routes struct for each cluster block from flat routing results. + * The pb_routes struct holds all intra-cluster routing. */ +static void sync_pb_routes_to_routing(void); + +/** Rebuild ClusteredNetlist from flat routing results, since some nets can move in/out of a block after routing. */ +static void sync_clustered_netlist_to_routing(void); + +/** Rebuild atom_lookup.atom_pin_pb_graph_pin and pb.atom_pin_bit_index from flat routing results. + * These contain mappings between the AtomNetlist and the physical pins, which are invalidated after flat routing due to changed pin rotations. + * (i.e. the primitive has equivalent input pins and flat routing used a different pin) */ +static void fixup_atom_pb_graph_pin_mapping(void); + + +/* Function definitions */ + +/** Is the clock net found in the routing results? + * (If not, clock_modeling is probably ideal and we should preserve clock routing while rebuilding.) */ +inline bool is_clock_net_routed(void){ + auto& atom_ctx = g_vpr_ctx.atom(); + auto& route_ctx = g_vpr_ctx.routing(); + + for(auto net_id: atom_ctx.nlist.nets()){ + auto& tree = route_ctx.route_trees[net_id]; + if(!tree) + continue; + if(route_ctx.is_clock_net[net_id]) /* Clock net has routing */ + return true; + } + + return false; +} + +/** Get the ClusterBlockId for a given RRNodeId. */ +inline ClusterBlockId get_cluster_block_from_rr_node(RRNodeId inode){ + auto& device_ctx = g_vpr_ctx.device(); + auto& place_ctx = g_vpr_ctx.placement(); + auto& rr_graph = device_ctx.rr_graph; + + auto physical_tile = device_ctx.grid.get_physical_type({ + rr_graph.node_xlow(inode), + rr_graph.node_ylow(inode), + rr_graph.node_layer(inode) + }); + + int source_pin = rr_graph.node_pin_num(inode); + + auto [_, subtile] = get_sub_tile_from_pin_physical_num(physical_tile, source_pin); + + ClusterBlockId clb = place_ctx.grid_blocks().block_at_location({ + rr_graph.node_xlow(inode), + rr_graph.node_ylow(inode), + subtile, + rr_graph.node_layer(inode) + }); + + return clb; +} + +static void get_intra_cluster_connections(const RouteTree& tree, std::vector>& out_connections){ + auto& rr_graph = g_vpr_ctx.device().rr_graph; + + for(auto& node: tree.all_nodes()){ + const auto& parent = node.parent(); + if(!parent) /* Root */ + continue; + + /* Find the case where both nodes are IPIN/OPINs and on the same block */ + auto type = rr_graph.node_type(node.inode); + auto parent_type = rr_graph.node_type(parent->inode); + + if((type == IPIN || type == OPIN) && (parent_type == IPIN || parent_type == OPIN)){ + auto clb = get_cluster_block_from_rr_node(node.inode); + auto parent_clb = get_cluster_block_from_rr_node(parent->inode); + if(clb == parent_clb) + out_connections.push_back({parent->inode, node.inode}); + } + } +} + +static void route_intra_cluster_conn(const t_pb_graph_pin* source_pin, const t_pb_graph_pin* sink_pin, AtomNetId net_id, t_pb* out_pb){ + std::unordered_set visited; + std::deque queue; + std::unordered_map prev; + + auto& out_pb_routes = out_pb->pb_route; + + queue.push_back(source_pin); + prev[source_pin] = NULL; + + while(!queue.empty()){ + const t_pb_graph_pin* cur_pin = queue.front(); + queue.pop_front(); + if(visited.count(cur_pin)) + continue; + visited.insert(cur_pin); + + /* Backtrack and return */ + if(cur_pin == sink_pin){ + break; + } + + for(auto& edge: cur_pin->output_edges){ + VTR_ASSERT(edge->num_output_pins == 1); + queue.push_back(edge->output_pins[0]); + prev[edge->output_pins[0]] = cur_pin; + } + } + + VTR_ASSERT_MSG(visited.count(sink_pin), "Couldn't find sink pin"); + + /* Collect path: we need to build pb_routes from source to sink */ + std::vector path; + const t_pb_graph_pin* cur_pin = sink_pin; + while(cur_pin != source_pin){ + path.push_back(cur_pin); + cur_pin = prev[cur_pin]; + } + path.push_back(source_pin); + + /* Output the path into out_pb, starting from source. This is where the pb_route is updated */ + int prev_pin_id = -1; + for(auto it = path.rbegin(); it != path.rend(); ++it){ + cur_pin = *it; + int cur_pin_id = cur_pin->pin_count_in_cluster; + t_pb_route* cur_pb_route; + + if(out_pb_routes.count(cur_pin_id)) + cur_pb_route = &out_pb_routes[cur_pin_id]; + else { + t_pb_route pb_route = { + net_id, + -1, + {}, + cur_pin + }; + out_pb_routes.insert(std::make_pair<>(cur_pin_id, pb_route)); + cur_pb_route = &out_pb_routes[cur_pin_id]; + } + + if(prev_pin_id != -1){ + t_pb_route& prev_pb_route = out_pb_routes[prev_pin_id]; + prev_pb_route.sink_pb_pin_ids.push_back(cur_pin_id); + cur_pb_route->driver_pb_pin_id = prev_pb_route.pb_graph_pin->pin_count_in_cluster; + } + + prev_pin_id = cur_pin_id; + } +} + +static void sync_pb_routes_to_routing(void){ + auto& device_ctx = g_vpr_ctx.device(); + auto& atom_ctx = g_vpr_ctx.atom(); + auto& cluster_ctx = g_vpr_ctx.mutable_clustering(); + auto& place_ctx = g_vpr_ctx.placement(); + auto& route_ctx = g_vpr_ctx.routing(); + auto& rr_graph = device_ctx.rr_graph; + + /* Was the clock net routed? */ + bool clock_net_is_routed = is_clock_net_routed(); + + /* Clear out existing pb_routes: they were made by the intra cluster router and are invalid now */ + for (ClusterBlockId clb_blk_id : cluster_ctx.clb_nlist.blocks()) { + /* If we don't have routing for the clock net, don't erase entries associated with a clock net. + * Otherwise we won't have data to rebuild them */ + std::vector pins_to_erase; + auto& pb_routes = cluster_ctx.clb_nlist.block_pb(clb_blk_id)->pb_route; + for(auto& [pin, pb_route]: pb_routes){ + if(clock_net_is_routed || !route_ctx.is_clock_net[pb_route.atom_net_id]) + pins_to_erase.push_back(pin); + } + + for(int pin: pins_to_erase){ + pb_routes.erase(pin); + } + } + + /* Go through each route tree and rebuild the pb_routes */ + for(ParentNetId net_id: atom_ctx.nlist.nets()){ + auto& tree = route_ctx.route_trees[net_id]; + if(!tree) + continue; /* No routing at this ParentNetId */ + + /* Get all intrablock connections */ + std::vector> conns_to_restore; /* (source, sink) */ + get_intra_cluster_connections(tree.value(), conns_to_restore); + + /* Restore the connections */ + for(auto [source_inode, sink_inode]: conns_to_restore){ + auto physical_tile = device_ctx.grid.get_physical_type({ + rr_graph.node_xlow(source_inode), + rr_graph.node_ylow(source_inode), + rr_graph.node_layer(source_inode) + }); + int source_pin = rr_graph.node_pin_num(source_inode); + int sink_pin = rr_graph.node_pin_num(sink_inode); + + auto [_, subtile] = get_sub_tile_from_pin_physical_num(physical_tile, source_pin); + + ClusterBlockId clb = place_ctx.grid_blocks().block_at_location({ + rr_graph.node_xlow(source_inode), + rr_graph.node_ylow(source_inode), + subtile, + rr_graph.node_layer(source_inode) + }); + + /* Look up pb graph pins from pb type if pin is not on tile, look up from block otherwise */ + const t_pb_graph_pin* source_pb_graph_pin, *sink_pb_graph_pin; + if(is_pin_on_tile(physical_tile, sink_pin)){ + sink_pb_graph_pin = get_pb_graph_node_pin_from_block_pin(clb, sink_pin); + }else{ + sink_pb_graph_pin = get_pb_pin_from_pin_physical_num(physical_tile, sink_pin); + } + if(is_pin_on_tile(physical_tile, source_pin)){ + source_pb_graph_pin = get_pb_graph_node_pin_from_block_pin(clb, source_pin); + }else{ + source_pb_graph_pin = get_pb_pin_from_pin_physical_num(physical_tile, source_pin); + } + + t_pb* pb = cluster_ctx.clb_nlist.block_pb(clb); + + /* Route between the pins */ + route_intra_cluster_conn(source_pb_graph_pin, sink_pb_graph_pin, convert_to_atom_net_id(net_id), pb); + } + } +} + +/** Rebuild the ClusterNetId <-> AtomNetId lookup after compressing the ClusterNetlist. + * Needs the old ClusterNetIds in atom_ctx.lookup. Won't work after calling compress() twice, + * since we won't have access to the old IDs in the IdRemapper anywhere. */ +inline void rebuild_atom_nets_lookup(ClusteredNetlist::IdRemapper& remapped){ + auto& atom_ctx = g_vpr_ctx.mutable_atom(); + auto& atom_lookup = atom_ctx.lookup; + + for(auto parent_net_id: atom_ctx.nlist.nets()){ + auto atom_net_id = convert_to_atom_net_id(parent_net_id); + auto old_clb_nets_opt = atom_lookup.clb_nets(atom_net_id); + if(!old_clb_nets_opt) + continue; + std::vector old_clb_nets = old_clb_nets_opt.value(); + atom_lookup.remove_atom_net(atom_net_id); + for(auto old_clb_net: old_clb_nets){ + ClusterNetId new_clb_net = remapped.new_net_id(old_clb_net); + atom_lookup.add_atom_clb_net(atom_net_id, new_clb_net); + } + } +} + +/** Regenerate clustered netlist nets from routing results */ +static void sync_clustered_netlist_to_routing(void){ + auto& cluster_ctx = g_vpr_ctx.mutable_clustering(); + auto& place_ctx = g_vpr_ctx.mutable_placement(); + auto& route_ctx = g_vpr_ctx.routing(); + auto& clb_netlist = cluster_ctx.clb_nlist; + auto& device_ctx = g_vpr_ctx.device(); + auto& rr_graph = device_ctx.rr_graph; + auto& atom_ctx = g_vpr_ctx.mutable_atom(); + auto& atom_lookup = atom_ctx.lookup; + + bool clock_net_is_routed = is_clock_net_routed(); + + /* 1. Remove all nets, pins and ports from the clustered netlist. + * If the clock net is not routed, don't remove entries for the clock net + * otherwise we won't have data to rebuild them. */ + std::vector nets_to_remove; + std::vector pins_to_remove; + std::vector ports_to_remove; + + for(auto net_id: clb_netlist.nets()){ + auto atom_net_id = atom_lookup.atom_net(net_id); + if(!clock_net_is_routed && route_ctx.is_clock_net[atom_net_id]) + continue; + + nets_to_remove.push_back(net_id); + } + for(auto pin_id: clb_netlist.pins()){ + ClusterNetId clb_net_id = clb_netlist.pin_net(pin_id); + auto atom_net_id = atom_lookup.atom_net(clb_net_id); + if(!clock_net_is_routed && atom_net_id && route_ctx.is_clock_net[atom_net_id]) + continue; + + pins_to_remove.push_back(pin_id); + } + for(auto port_id: clb_netlist.ports()){ + ClusterNetId clb_net_id = clb_netlist.port_net(port_id, 0); + auto atom_net_id = atom_lookup.atom_net(clb_net_id); + if(!clock_net_is_routed && atom_net_id && route_ctx.is_clock_net[atom_net_id]) + continue; + + ports_to_remove.push_back(port_id); + } + + /* ClusteredNetlist's iterators rely on internal lookups, so we mark for removal + * while iterating, then remove in bulk */ + for(auto net_id: nets_to_remove){ + clb_netlist.remove_net(net_id); + atom_lookup.remove_clb_net(net_id); + } + for(auto pin_id: pins_to_remove){ + clb_netlist.remove_pin(pin_id); + } + for(auto port_id: ports_to_remove){ + clb_netlist.remove_port(port_id); + } + + /* 2. Reset all internal lookups for netlist */ + auto remapped = clb_netlist.compress(); + rebuild_atom_nets_lookup(remapped); + + /* 3. Walk each routing in the atom netlist. If a node is on the tile, add a ClusterPinId for it. + * Add the associated net and port too if they don't exist */ + for(auto parent_net_id: atom_ctx.nlist.nets()){ + auto& tree = route_ctx.route_trees[parent_net_id]; + AtomNetId atom_net_id = convert_to_atom_net_id(parent_net_id); + + ClusterNetId clb_net_id; + int clb_nets_so_far = 0; + for(auto& rt_node: tree->all_nodes()){ + auto node_type = rr_graph.node_type(rt_node.inode); + if(node_type != IPIN && node_type != OPIN) + continue; + + auto physical_tile = device_ctx.grid.get_physical_type({ + rr_graph.node_xlow(rt_node.inode), + rr_graph.node_ylow(rt_node.inode), + rr_graph.node_layer(rt_node.inode) + }); + + int pin_index = rr_graph.node_pin_num(rt_node.inode); + + auto [_, subtile] = get_sub_tile_from_pin_physical_num(physical_tile, pin_index); + + ClusterBlockId clb = place_ctx.grid_blocks().block_at_location({ + rr_graph.node_xlow(rt_node.inode), + rr_graph.node_ylow(rt_node.inode), + subtile, + rr_graph.node_layer(rt_node.inode) + }); + + if(!is_pin_on_tile(physical_tile, pin_index)) + continue; + + /* OPIN on the tile: create a new clb_net_id and add all ports & pins into here + * Due to how the route tree is traversed, all nodes until the next OPIN on the tile will + * be under this OPIN, so this is valid (we don't need to get the branch explicitly) */ + if(node_type == OPIN){ + std::string net_name; + if(clb_nets_so_far == 0) + net_name = atom_ctx.nlist.net_name(parent_net_id); + else + net_name = atom_ctx.nlist.net_name(parent_net_id) + "_" + std::to_string(clb_nets_so_far); + clb_net_id = clb_netlist.create_net(net_name); + atom_lookup.add_atom_clb_net(atom_net_id, clb_net_id); + clb_nets_so_far++; + } + + t_pb_graph_pin* pb_graph_pin = get_pb_graph_node_pin_from_block_pin(clb, pin_index); + + ClusterPortId port_id = clb_netlist.find_port(clb, pb_graph_pin->port->name); + if(!port_id){ + PortType port_type; + if(pb_graph_pin->port->is_clock) + port_type = PortType::CLOCK; + else if(pb_graph_pin->port->type == IN_PORT) + port_type = PortType::INPUT; + else if(pb_graph_pin->port->type == OUT_PORT) + port_type = PortType::OUTPUT; + else + VTR_ASSERT_MSG(false, "Unsupported port type"); + port_id = clb_netlist.create_port(clb, pb_graph_pin->port->name, pb_graph_pin->port->num_pins, port_type); + } + PinType pin_type = node_type == OPIN ? PinType::DRIVER : PinType::SINK; + + ClusterPinId new_pin = clb_netlist.create_pin(port_id, pb_graph_pin->pin_number, clb_net_id, pin_type, pb_graph_pin->pin_count_in_cluster); + clb_netlist.set_pin_net(new_pin, pin_type, clb_net_id); + } + } + /* 4. Rebuild internal cluster netlist lookups */ + remapped = clb_netlist.compress(); + rebuild_atom_nets_lookup(remapped); + /* 5. Rebuild place_ctx.physical_pins lookup + * TODO: maybe we don't need this fn and pin_index is enough? */ + auto& blk_loc_registry = place_ctx.mutable_blk_loc_registry(); + auto& physical_pins = place_ctx.mutable_physical_pins(); + physical_pins.clear(); + for(auto clb: clb_netlist.blocks()){ + blk_loc_registry.place_sync_external_block_connections(clb); + } +} + +static void fixup_atom_pb_graph_pin_mapping(void){ + auto& cluster_ctx = g_vpr_ctx.clustering(); + auto& atom_ctx = g_vpr_ctx.mutable_atom(); + + for(ClusterBlockId clb: cluster_ctx.clb_nlist.blocks()){ + /* Collect all innermost pb routes */ + std::vector sink_pb_route_ids; + t_pb* clb_pb = cluster_ctx.clb_nlist.block_pb(clb); + for(auto [pb_route_id, pb_route]: clb_pb->pb_route){ + if(pb_route.sink_pb_pin_ids.empty()) + sink_pb_route_ids.push_back(pb_route_id); + } + + for(int sink_pb_route_id: sink_pb_route_ids){ + t_pb_route& pb_route = clb_pb->pb_route.at(sink_pb_route_id); + + const t_pb_graph_pin* atom_pbg_pin = pb_route.pb_graph_pin; + t_pb* atom_pb = clb_pb->find_mutable_pb(atom_pbg_pin->parent_node); + AtomBlockId atb = atom_ctx.lookup.pb_atom(atom_pb); + if(!atb) + continue; + + /* Find atom port from pbg pin's model port */ + AtomPortId atom_port = atom_ctx.nlist.find_atom_port(atb, atom_pbg_pin->port->model_port); + for(AtomPinId atom_pin: atom_ctx.nlist.port_pins(atom_port)){ + /* Match net IDs from pb_route and atom netlist and connect in lookup */ + if(pb_route.atom_net_id == atom_ctx.nlist.pin_net(atom_pin)){ + atom_ctx.lookup.set_atom_pin_pb_graph_pin(atom_pin, atom_pbg_pin); + atom_pb->set_atom_pin_bit_index(atom_pbg_pin, atom_ctx.nlist.pin_port_bit(atom_pin)); + } + } + } + } +} + +/** + * Regenerate intra-cluster routing in the packer ctx from flat routing results. + * This function SHOULD be run ONLY when routing is finished!!! + */ +void sync_netlists_to_routing_flat(void) { + vtr::ScopedStartFinishTimer timer("Synchronize the packed netlist to routing optimization"); + + sync_clustered_netlist_to_routing(); + sync_pb_routes_to_routing(); + fixup_atom_pb_graph_pin_mapping(); +} diff --git a/vpr/src/pack/sync_netlists_to_routing_flat.h b/vpr/src/pack/sync_netlists_to_routing_flat.h new file mode 100644 index 00000000000..9403eb1c2a9 --- /dev/null +++ b/vpr/src/pack/sync_netlists_to_routing_flat.h @@ -0,0 +1,18 @@ +#include "netlist.h" + + /******************************************************************** + * Top-level function to synchronize packing results to routing results. + * Flat routing invalidates the ClusteredNetlist since nets may be routed + * inside or outside a block and changes virtually all intrablock routing. + * This function: + * - rebuilds ClusteredNetlist + * - rebuilds all pb_routes + * - rebuilds pb graph <-> atom pin mapping in AtomLookup + * taking routing results as the source of truth. + * + * Note: + * - This function SHOULD be run ONLY when routing is finished. + * - This function only handles the flat routing results. + * See \see sync_netlists_to_routing() for the two-stage case. + *******************************************************************/ +void sync_netlists_to_routing_flat(void); diff --git a/vpr/src/route/annotate_routing.cpp b/vpr/src/route/annotate_routing.cpp index f290b7ccbf2..42b798d4d02 100644 --- a/vpr/src/route/annotate_routing.cpp +++ b/vpr/src/route/annotate_routing.cpp @@ -1,46 +1,44 @@ /******************************************************************** * This file includes functions that are used to annotate routing results - * from VPR to OpenFPGA + * from VPR to OpenFPGA. (i.e. create a mapping from RRNodeIds to ClusterNetIds) *******************************************************************/ -/* Headers from vtrutil library */ + +#include "vpr_error.h" #include "vtr_assert.h" #include "vtr_time.h" #include "vtr_log.h" -#include "vpr_error.h" +#include "route_utils.h" #include "rr_graph.h" + #include "annotate_routing.h" -/******************************************************************** - * Create a mapping between each rr_node and its mapped nets - * based on VPR routing results - * - Store the net ids mapped to each routing resource nodes - * - Mapped nodes should have valid net ids (except SOURCE and SINK nodes) - * - Unmapped rr_node will use invalid ids - *******************************************************************/ -vtr::vector annotate_rr_node_nets(const Netlist<>& net_list, +vtr::vector annotate_rr_node_nets(const ClusteringContext& cluster_ctx, const DeviceContext& device_ctx, - const RoutingContext& routing_ctx, - const bool& verbose, - bool is_flat) { + const bool& verbose) { size_t counter = 0; vtr::ScopedStartFinishTimer timer("Annotating rr_node with routed nets"); const auto& rr_graph = device_ctx.rr_graph; - vtr::vector rr_node_nets; - rr_node_nets.resize(rr_graph.num_nodes(), ParentNetId::INVALID()); + auto& netlist = cluster_ctx.clb_nlist; + vtr::vector rr_node_nets; + rr_node_nets.resize(rr_graph.num_nodes(), ClusterNetId::INVALID()); - for (auto net_id : net_list.nets()) { - if (net_list.net_is_ignored(net_id)) { + for (auto net_id : netlist.nets()) { + if (netlist.net_is_ignored(net_id)) { continue; } /* Ignore used in local cluster only, reserved one CLB pin */ - if (net_list.net_sinks(net_id).empty()) { + if (netlist.net_sinks(net_id).empty()) { continue; } - for (auto& rt_node : routing_ctx.route_trees[net_id].value().all_nodes()) { + auto& tree = get_route_tree_from_cluster_net_id(net_id); + if(!tree) + continue; + + for (auto& rt_node : tree->all_nodes()) { const RRNodeId rr_node = rt_node.inode; /* Ignore source and sink nodes, they are the common node multiple starting and ending points */ if ((SOURCE != rr_graph.node_type(rr_node)) @@ -56,14 +54,14 @@ vtr::vector annotate_rr_node_nets(const Netlist<>& net_li && (net_id != rr_node_nets[rr_node])) { VPR_FATAL_ERROR(VPR_ERROR_ANALYSIS, "Detect two nets '%s' and '%s' that are mapped to the same rr_node '%ld'!\n%s\n", - net_list.net_name(net_id).c_str(), - net_list.net_name(rr_node_nets[rr_node]).c_str(), + netlist.net_name(net_id).c_str(), + netlist.net_name(rr_node_nets[rr_node]).c_str(), size_t(rr_node), describe_rr_node(rr_graph, device_ctx.grid, device_ctx.rr_indexed_data, rr_node, - is_flat) + false) .c_str()); } else { rr_node_nets[rr_node] = net_id; diff --git a/vpr/src/route/annotate_routing.h b/vpr/src/route/annotate_routing.h index 97f22f1c3bc..cf548e1e0fe 100644 --- a/vpr/src/route/annotate_routing.h +++ b/vpr/src/route/annotate_routing.h @@ -1,19 +1,17 @@ #ifndef ANNOTATE_ROUTING_H #define ANNOTATE_ROUTING_H -/******************************************************************** - * Include header files that are required by function declaration - *******************************************************************/ #include "vpr_context.h" /******************************************************************** - * Function declaration + * Create a mapping between each rr_node and its mapped nets + * based on VPR routing results. + * - Store the net ids mapped to each routing resource nodes + * - Mapped nodes should have valid net ids (except SOURCE and SINK nodes) + * - Unmapped rr_node will use invalid ids *******************************************************************/ - -vtr::vector annotate_rr_node_nets(const Netlist<>& net_list, +vtr::vector annotate_rr_node_nets(const ClusteringContext& cluster_ctx, const DeviceContext& device_ctx, - const RoutingContext& routing_ctx, - const bool& verbose, - bool is_flat); + const bool& verbose); #endif diff --git a/vpr/src/route/route_common.cpp b/vpr/src/route/route_common.cpp index 480919ae9b6..fe9db221ae9 100644 --- a/vpr/src/route/route_common.cpp +++ b/vpr/src/route/route_common.cpp @@ -272,6 +272,8 @@ void init_route_structs(const Netlist<>& net_list, route_ctx.clb_opins_used_locally = alloc_and_load_clb_opins_used_locally(); route_ctx.net_status.resize(net_list.nets().size()); + route_ctx.is_flat = is_flat; + if (has_choking_point && is_flat) { std::tie(route_ctx.net_terminal_groups, route_ctx.net_terminal_group_num) = load_net_terminal_groups(device_ctx.rr_graph, net_list, diff --git a/vpr/src/route/route_utils.h b/vpr/src/route/route_utils.h index fddad8247dd..9148180a94c 100644 --- a/vpr/src/route/route_utils.h +++ b/vpr/src/route/route_utils.h @@ -70,6 +70,19 @@ void generate_route_timing_reports(const t_router_opts& router_opts, /** Get the maximum number of pins used in the netlist (used to allocate things) */ int get_max_pins_per_net(const Netlist<>& net_list); +/** Get the RouteTree associated with the ClusterNetId. + * Flat routing maps AtomNetIds to RouteTrees instead, so we need to first look up the associated AtomNetId. */ +inline const vtr::optional& get_route_tree_from_cluster_net_id(ClusterNetId net_id){ + auto& route_ctx = g_vpr_ctx.routing(); + if(!route_ctx.is_flat){ + return route_ctx.route_trees[ParentNetId(net_id)]; + }else{ + auto& atom_lookup = g_vpr_ctx.atom().lookup; + AtomNetId atom_id = atom_lookup.atom_net(net_id); + return route_ctx.route_trees[ParentNetId(atom_id)]; + } +} + /** Initialize net_delay based on best-case delay estimates from the router lookahead. */ void init_net_delay_from_lookahead(const RouterLookahead& router_lookahead, const Netlist<>& net_list, diff --git a/vpr/src/util/vpr_utils.cpp b/vpr/src/util/vpr_utils.cpp index 1b216f11a68..3caf87e43ba 100644 --- a/vpr/src/util/vpr_utils.cpp +++ b/vpr/src/util/vpr_utils.cpp @@ -2365,7 +2365,7 @@ t_arch_switch_inf create_internal_arch_sw(float delay) { arch_switch_inf.set_type(SwitchType::MUX); std::ostringstream stream_obj; stream_obj << delay << std::scientific; - arch_switch_inf.name = ("Internal Switch/" + stream_obj.str()); + arch_switch_inf.name = (std::string(VPR_INTERNAL_SWITCH_NAME) + "/" + stream_obj.str()); arch_switch_inf.R = 0.; arch_switch_inf.Cin = 0.; arch_switch_inf.Cout = 0;