From 812686d1694cbe85c03f8e39ec20cef35fede933 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 13 Aug 2024 22:36:37 -0700 Subject: [PATCH] [core] support global net fixup in pb pin fixup --- openfpga/src/base/openfpga_pb_pin_fixup.cpp | 185 +++++++++++++++--- openfpga/src/base/openfpga_pb_pin_fixup.h | 2 +- .../src/base/openfpga_pb_pin_fixup_template.h | 5 +- 3 files changed, 159 insertions(+), 33 deletions(-) diff --git a/openfpga/src/base/openfpga_pb_pin_fixup.cpp b/openfpga/src/base/openfpga_pb_pin_fixup.cpp index 0c731f018..634197be0 100644 --- a/openfpga/src/base/openfpga_pb_pin_fixup.cpp +++ b/openfpga/src/base/openfpga_pb_pin_fixup.cpp @@ -23,6 +23,89 @@ /* begin namespace openfpga */ namespace openfpga { +/******************************************************************** + * For global net which was remapped during routing, no tracking can be found. Packer only keeps an out-of-date record on its pin mapping. Router does not assign it to a new pin. So we have to restore the pin mapping. The strategy is to find the first unused pin in the same port as it was mapped by the packer. + *******************************************************************/ +static int update_cluster_pin_global_net_with_post_routing_results(const ClusteringContext& clustering_ctx, + VprClusteringAnnotation& clustering_annotation, + const ClusterBlockId& blk_id, + t_logical_block_type_ptr logical_block, + size_t& num_fixup, + const bool& verbose) { + /* Reassign global nets to unused pins in the same port where they were mapped + * NO optimization is done here!!! First find first fit + */ + for (int pb_type_pin = 0; pb_type_pin < logical_block->pb_type->num_pins; ++pb_type_pin) { + const t_pb_graph_pin* pb_graph_pin = get_pb_graph_node_pin_from_block_pin(blk_id, pb_type_pin); + + /* Limitation: bypass output pins now + * TODO: This is due to the 'instance' equivalence port + * where outputs may be swapped. This definitely requires re-run of packing + * It can not be solved by swapping routing traces now + */ + if (OUT_PORT == pb_graph_pin->port->type) { + continue; + } + + /* Sanity check to ensure the pb_graph_pin is the top-level */ + VTR_ASSERT(pb_graph_pin->parent_node->is_root()); + + /* Focus on global net only */ + ClusterNetId global_net_id = clustering_ctx.clb_nlist.block_net(blk_id, pb_type_pin); + if (!clustering_ctx.clb_nlist.valid_net_id(global_net_id)) { + continue; + } + if ((clustering_ctx.clb_nlist.valid_net_id(global_net_id)) + && (!clustering_ctx.clb_nlist.net_is_ignored(global_net_id))) { + continue; + } + /* Skip this pin: it is consistent in pre- and post- routing results */ + if (!clustering_annotation.is_net_renamed(blk_id, pb_type_pin)) { + continue; + } + /* This net has been remapped, find the first unused pin in the same port + * Get the offset of the pin index in the port, based on which we can infer the pin index in the context of logical block + */ + size_t cand_pin_start = pb_type_pin - pb_graph_pin->pin_number; + size_t cand_pin_end = cand_pin_start + pb_graph_pin->port->num_pins; + bool found_cand = false; + for (size_t cand_pin = cand_pin_start; cand_pin < cand_pin_end; ++cand_pin) { + ClusterNetId cand_pin_net_id = clustering_ctx.clb_nlist.block_net(blk_id, cand_pin); + const t_pb_graph_pin* cand_pb_graph_pin = get_pb_graph_node_pin_from_block_pin(blk_id, cand_pin); + if (!clustering_annotation.is_net_renamed(blk_id, cand_pin)) { + cand_pin_net_id = clustering_annotation.net(blk_id, cand_pin); + } + if (clustering_ctx.clb_nlist.valid_net_id(cand_pin_net_id)) { + VTR_LOG("Candidate pin '%s' is already mapped to net '%s'\n", + cand_pb_graph_pin->to_string().c_str(), + clustering_ctx.clb_nlist.net_name(cand_pin_net_id).c_str()); + continue; + } + /* Add to net modification */ + clustering_annotation.rename_net(blk_id, cand_pin, global_net_id); + VTR_LOGV(verbose, + "Remap clustered block '%s' global net '%s' to pin '%s'\n", + clustering_ctx.clb_nlist.block_pb(blk_id)->name, + clustering_ctx.clb_nlist.net_name(global_net_id).c_str(), + cand_pb_graph_pin->to_string().c_str()); + found_cand = true; + break; + } + /* Error out if no candidates are found */ + if (!found_cand) { + VTR_LOG_ERROR( + "Failed to find any unused pin in the same port to remap clustered block '%s' global net '%s' (was mapped to pin '%s').\n", + clustering_ctx.clb_nlist.block_pb(blk_id)->name, + clustering_ctx.clb_nlist.net_name(global_net_id).c_str(), + pb_graph_pin->to_string().c_str()); + return CMD_EXEC_FATAL_ERROR; + } + /* Update fixup counter */ + num_fixup++; + } + return CMD_EXEC_SUCCESS; +} + /******************************************************************** * Fix up the pb pin mapping results for a given clustered block * 1. For each input/output pin of a clustered pb, @@ -32,13 +115,15 @@ namespace openfpga { * - if the net id does not match, we update the clustering context * TODO: For global net which was remapped during routing, no tracking can be found. Packer only keeps an out-of-date record on its pin mapping. Router does not assign it to a new pin. So we have to restore the pin mapping. The strategy is to find the first unused pin in the same port as it was mapped by the packer. *******************************************************************/ -static void update_cluster_pin_with_post_routing_results( +static int update_cluster_pin_with_post_routing_results( const DeviceContext& device_ctx, const ClusteringContext& clustering_ctx, const VprRoutingAnnotation& vpr_routing_annotation, VprClusteringAnnotation& vpr_clustering_annotation, const size_t& layer, const vtr::Point& grid_coord, const ClusterBlockId& blk_id, const e_side& border_side, const size_t& z, const bool& perimeter_cb, + size_t& num_fixup, const bool& verbose) { + int status = CMD_EXEC_SUCCESS; /* Handle each pin */ auto logical_block = clustering_ctx.clb_nlist.block_type(blk_id); auto physical_tile = device_ctx.grid.get_physical_type( @@ -76,20 +161,53 @@ static void update_cluster_pin_with_post_routing_results( */ e_side pin_side = NUM_SIDES; if (NUM_SIDES == border_side) { - VTR_ASSERT(1 == pin_sides.size()); + if (1 != pin_sides.size()) { + VTR_LOG_ERROR("For tile '%s', found pin '%s' on %lu sides. Expect only 1. Following info is for debugging:\n", + physical_tile->name, + get_pb_graph_node_pin_from_block_pin(blk_id, physical_pin)->to_string(), + pin_sides.size()); + for (e_side curr_side : pin_sides) { + VTR_LOG_ERROR("\t%s\n", SideManager(curr_side).c_str()); + } + return CMD_EXEC_FATAL_ERROR; + } pin_side = pin_sides[0]; } else if (perimeter_cb) { /* When perimeter connection blcoks are allowed, I/O pins may occur on any * side but the border side */ - VTR_ASSERT(pin_sides.end() == - std::find(pin_sides.begin(), pin_sides.end(), border_side)); - VTR_ASSERT(1 == pin_sides.size()); + if (pin_sides.end() != + std::find(pin_sides.begin(), pin_sides.end(), border_side)) { + VTR_LOG_ERROR("For tile '%s', found pin '%s' on the boundary side '%s', which is not physically possible.\n", + physical_tile->name, + get_pb_graph_node_pin_from_block_pin(blk_id, physical_pin)->to_string(), + SideManager(border_side).c_str()); + return CMD_EXEC_FATAL_ERROR; + } + if (1 != pin_sides.size()) { + VTR_LOG_ERROR("For tile '%s', found pin '%s' on %lu sides. Expect only 1. Following info is for debugging:\n", + physical_tile->name, + get_pb_graph_node_pin_from_block_pin(blk_id, physical_pin)->to_string(), + pin_sides.size()); + for (e_side curr_side : pin_sides) { + VTR_LOG_ERROR("\t%s\n", SideManager(curr_side).c_str()); + } + return CMD_EXEC_FATAL_ERROR; + } pin_side = pin_sides[0]; } else { SideManager side_manager(border_side); - VTR_ASSERT(pin_sides.end() != std::find(pin_sides.begin(), + if (pin_sides.end() == std::find(pin_sides.begin(), pin_sides.end(), - side_manager.get_opposite())); + side_manager.get_opposite())) { + VTR_LOG_ERROR("For boundary tile '%s', expect pin '%s' only on the side '%s' but found on the following sides:\n", + physical_tile->name, + get_pb_graph_node_pin_from_block_pin(blk_id, physical_pin)->to_string(), + SideManager(side_manager.get_opposite()).c_str()); + for (e_side curr_side : pin_sides) { + VTR_LOG_ERROR("\t%s\n", SideManager(curr_side).c_str()); + } + return CMD_EXEC_FATAL_ERROR; + } pin_side = side_manager.get_opposite(); } @@ -124,13 +242,11 @@ static void update_cluster_pin_with_post_routing_results( (true == clustering_ctx.clb_nlist.net_is_ignored(cluster_net_id))) { VTR_LOGV( verbose, - "Bypass net at clustered block '%s' pin 'grid[%ld][%ld].%s.%s[%d]' as " + "Bypass net at clustered block '%s' pin 'grid[%ld][%ld].%s' as " "it is not routed\n", clustering_ctx.clb_nlist.block_pb(blk_id)->name, grid_coord.x(), grid_coord.y(), - clustering_ctx.clb_nlist.block_pb(blk_id)->pb_graph_node->pb_type->name, - get_pb_graph_node_pin_from_block_pin(blk_id, physical_pin)->port->name, - get_pb_graph_node_pin_from_block_pin(blk_id, physical_pin)->pin_number); + get_pb_graph_node_pin_from_block_pin(blk_id, physical_pin)->to_string()); continue; } @@ -139,13 +255,11 @@ static void update_cluster_pin_with_post_routing_results( (0 == clustering_ctx.clb_nlist.net_sinks(cluster_net_id).size())) { VTR_LOGV( verbose, - "Bypass net at clustered block '%s' pin 'grid[%ld][%ld].%s.%s[%d]' as " + "Bypass net at clustered block '%s' pin 'grid[%ld][%ld].%s' as " "it is a local net inside the cluster\n", clustering_ctx.clb_nlist.block_pb(blk_id)->name, grid_coord.x(), grid_coord.y(), - clustering_ctx.clb_nlist.block_pb(blk_id)->pb_graph_node->pb_type->name, - get_pb_graph_node_pin_from_block_pin(blk_id, physical_pin)->port->name, - get_pb_graph_node_pin_from_block_pin(blk_id, physical_pin)->pin_number); + get_pb_graph_node_pin_from_block_pin(blk_id, physical_pin)->to_string().c_str()); continue; } @@ -153,13 +267,11 @@ static void update_cluster_pin_with_post_routing_results( if (routing_net_id == cluster_net_id) { VTR_LOGV( verbose, - "Bypass net at clustered block '%s' pin 'grid[%ld][%ld].%s.%s[%d]' as " + "Bypass net at clustered block '%s' pin 'grid[%ld][%ld].%s' as " "it matches cluster routing\n", clustering_ctx.clb_nlist.block_pb(blk_id)->name, grid_coord.x(), grid_coord.y(), - clustering_ctx.clb_nlist.block_pb(blk_id)->pb_graph_node->pb_type->name, - get_pb_graph_node_pin_from_block_pin(blk_id, physical_pin)->port->name, - get_pb_graph_node_pin_from_block_pin(blk_id, physical_pin)->pin_number); + get_pb_graph_node_pin_from_block_pin(blk_id, physical_pin)->to_string().c_str()); continue; } @@ -179,26 +291,35 @@ static void update_cluster_pin_with_post_routing_results( VTR_LOGV( verbose, "Fixed up net '%s' mapping mismatch at clustered block '%s' pin " - "'grid[%ld][%ld].%s.%s[%d]' (was net '%s')\n", + "'grid[%ld][%ld].%s' (was net '%s')\n", routing_net_name.c_str(), clustering_ctx.clb_nlist.block_pb(blk_id)->name, grid_coord.x(), grid_coord.y(), - clustering_ctx.clb_nlist.block_pb(blk_id)->pb_graph_node->pb_type->name, - get_pb_graph_node_pin_from_block_pin(blk_id, physical_pin)->port->name, - get_pb_graph_node_pin_from_block_pin(blk_id, physical_pin)->pin_number, + get_pb_graph_node_pin_from_block_pin(blk_id, physical_pin)->to_string().c_str(), cluster_net_name.c_str()); + num_fixup++; } + /* 2nd round of fixup: focus on global nets */ + status = update_cluster_pin_global_net_with_post_routing_results(clustering_ctx, + vpr_clustering_annotation, + blk_id, + logical_block, + num_fixup, + verbose); + return status; } /******************************************************************** * Main function to fix up the pb pin mapping results * This function will walk through each grid *******************************************************************/ -void update_pb_pin_with_post_routing_results( +int update_pb_pin_with_post_routing_results( const DeviceContext& device_ctx, const ClusteringContext& clustering_ctx, const PlacementContext& placement_ctx, const VprRoutingAnnotation& vpr_routing_annotation, VprClusteringAnnotation& vpr_clustering_annotation, const bool& perimeter_cb, const bool& verbose) { + int status = CMD_EXEC_SUCCESS; + size_t num_fixup = 0; /* Ensure a clean start: remove all the remapping results from VTR's * post-routing clustering result sync-up */ vpr_clustering_annotation.clear_net_remapping(); @@ -225,11 +346,14 @@ void update_pb_pin_with_post_routing_results( /* We know the entrance to grid info and mapping results, do the fix-up * for this block */ vtr::Point grid_coord(x, y); - update_cluster_pin_with_post_routing_results( + status = update_cluster_pin_with_post_routing_results( device_ctx, clustering_ctx, vpr_routing_annotation, vpr_clustering_annotation, layer, grid_coord, cluster_blk_id, NUM_SIDES, placement_ctx.block_locs[cluster_blk_id].loc.sub_tile, - perimeter_cb, verbose); + perimeter_cb, num_fixup, verbose); + if (status != CMD_EXEC_SUCCESS) { + return CMD_EXEC_FATAL_ERROR; + } } } } @@ -257,14 +381,19 @@ void update_pb_pin_with_post_routing_results( continue; } /* Update on I/O grid */ - update_cluster_pin_with_post_routing_results( + status = update_cluster_pin_with_post_routing_results( device_ctx, clustering_ctx, vpr_routing_annotation, vpr_clustering_annotation, layer, io_coord, cluster_blk_id, io_side, placement_ctx.block_locs[cluster_blk_id].loc.sub_tile, perimeter_cb, - verbose); + num_fixup, verbose); + if (status != CMD_EXEC_SUCCESS) { + return CMD_EXEC_FATAL_ERROR; + } } } } + VTR_LOG("In total %lu fixup have been applied\n", num_fixup); + return status; } } /* end namespace openfpga */ diff --git a/openfpga/src/base/openfpga_pb_pin_fixup.h b/openfpga/src/base/openfpga_pb_pin_fixup.h index de60c721a..11813b60c 100644 --- a/openfpga/src/base/openfpga_pb_pin_fixup.h +++ b/openfpga/src/base/openfpga_pb_pin_fixup.h @@ -14,7 +14,7 @@ /* begin namespace openfpga */ namespace openfpga { -void update_pb_pin_with_post_routing_results( +int update_pb_pin_with_post_routing_results( const DeviceContext& device_ctx, const ClusteringContext& clustering_ctx, const PlacementContext& placement_ctx, const VprRoutingAnnotation& vpr_routing_annotation, diff --git a/openfpga/src/base/openfpga_pb_pin_fixup_template.h b/openfpga/src/base/openfpga_pb_pin_fixup_template.h index 945175bad..50c415727 100644 --- a/openfpga/src/base/openfpga_pb_pin_fixup_template.h +++ b/openfpga/src/base/openfpga_pb_pin_fixup_template.h @@ -38,15 +38,12 @@ int pb_pin_fixup_template(T& openfpga_context, const Command& cmd, CommandOptionId opt_verbose = cmd.option("verbose"); /* Apply fix-up to each grid */ - update_pb_pin_with_post_routing_results( + return update_pb_pin_with_post_routing_results( g_vpr_ctx.device(), g_vpr_ctx.clustering(), g_vpr_ctx.placement(), openfpga_context.vpr_routing_annotation(), openfpga_context.mutable_vpr_clustering_annotation(), g_vpr_ctx.device().arch->perimeter_cb, cmd_context.option_enable(cmd, opt_verbose)); - - /* TODO: should identify the error code from internal function execution */ - return CMD_EXEC_SUCCESS; } } /* end namespace openfpga */