diff --git a/libopenfpga/libopenfpgautil/CMakeLists.txt b/libopenfpga/libopenfpgautil/CMakeLists.txt index 66c3dc471..9cb09e7b4 100644 --- a/libopenfpga/libopenfpgautil/CMakeLists.txt +++ b/libopenfpga/libopenfpgautil/CMakeLists.txt @@ -19,6 +19,7 @@ set_target_properties(libopenfpgautil PROPERTIES PREFIX "") #Avoid extra 'lib' p #Specify link-time dependancies target_link_libraries(libopenfpgautil + libarchfpga libvtrutil) #Create the test executable diff --git a/libopenfpga/libopenfpgautil/src/openfpga_side_manager.cpp b/libopenfpga/libopenfpgautil/src/openfpga_side_manager.cpp new file mode 100644 index 000000000..00ff9912c --- /dev/null +++ b/libopenfpga/libopenfpgautil/src/openfpga_side_manager.cpp @@ -0,0 +1,175 @@ +/******************************************************************** + * Memeber function for class SideManagerManager + *******************************************************************/ +#include "openfpga_side_manager.h" + +/* namespace openfpga begins */ +namespace openfpga { + +/* Constructors */ +SideManager::SideManager(enum e_side side) { + side_ = side; +} + +SideManager::SideManager() { + side_ = NUM_SIDES; +} + +SideManager::SideManager(size_t side) { + set_side(side); +} + +/* Public Accessors */ +enum e_side SideManager::get_side() const { + return side_; +} + +enum e_side SideManager::get_opposite() const { + switch (side_) { + case TOP: + return BOTTOM; + case RIGHT: + return LEFT; + case BOTTOM: + return TOP; + case LEFT: + return RIGHT; + default: + return NUM_SIDES; + } +} + +enum e_side SideManager::get_rotate_clockwise() const { + switch (side_) { + case TOP: + return RIGHT; + case RIGHT: + return BOTTOM; + case BOTTOM: + return LEFT; + case LEFT: + return TOP; + default: + return NUM_SIDES; + } +} + +enum e_side SideManager::get_rotate_counterclockwise() const { + switch (side_) { + case TOP: + return LEFT; + case RIGHT: + return TOP; + case BOTTOM: + return RIGHT; + case LEFT: + return BOTTOM; + default: + return NUM_SIDES; + } +} + +bool SideManager::validate() const { + if (NUM_SIDES == side_) { + return false; + } + return true; +} + +size_t SideManager::to_size_t() const { + switch (side_) { + case TOP: + return 0; + case RIGHT: + return 1; + case BOTTOM: + return 2; + case LEFT: + return 3; + default: + return 4; + } +} + +/* Convert to char* */ +const char* SideManager::c_str() const { + switch (side_) { + case TOP: + return "top"; + case RIGHT: + return "right"; + case BOTTOM: + return "bottom"; + case LEFT: + return "left"; + default: + return "invalid_side"; + } +} + +/* Convert to char* */ +std::string SideManager::to_string() const { + std::string ret; + switch (side_) { + case TOP: + ret.assign("top"); + break; + case RIGHT: + ret.assign("right"); + break; + case BOTTOM: + ret.assign("bottom"); + break; + case LEFT: + ret.assign("left"); + break; + default: + ret.assign("invalid_side"); + break; + } + + return ret; +} + +/* Public Mutators */ +void SideManager::set_side(size_t side) { + switch (side) { + case 0: + side_ = TOP; + return; + case 1: + side_ = RIGHT; + return; + case 2: + side_ = BOTTOM; + return; + case 3: + side_ = LEFT; + return; + default: + side_ = NUM_SIDES; + return; + } +} + +void SideManager::set_side(enum e_side side) { + side_ = side; + return; +} + +void SideManager::set_opposite() { + side_ = get_opposite(); + return; +} + +void SideManager::rotate_clockwise() { + side_ = get_rotate_clockwise(); + return; +} + +void SideManager::rotate_counterclockwise() { + side_ = get_rotate_counterclockwise(); + return; +} + +} /* namespace openfpga ends */ diff --git a/libopenfpga/libopenfpgautil/src/openfpga_side_manager.h b/libopenfpga/libopenfpgautil/src/openfpga_side_manager.h new file mode 100644 index 000000000..4903f7b4b --- /dev/null +++ b/libopenfpga/libopenfpgautil/src/openfpga_side_manager.h @@ -0,0 +1,49 @@ +#ifndef OPENFPGA_SIDE_MANAGER_H +#define OPENFPGA_SIDE_MANAGER_H + +/******************************************************************** + * Include header files that are required by function declaration + *******************************************************************/ +#include +#include + +/* Header files form archfpga library */ +#include "physical_types.h" + +/* namespace openfpga begins */ +namespace openfpga { + +/******************************************************************** + * Define a class for the sides of a physical block in FPGA architecture + * Basically, each block has four sides : + * TOP, RIGHT, BOTTOM, LEFT + * This class aims to provide a easy proctol for manipulating a side + ********************************************************************/ + +class SideManager { + public: /* Constructor */ + SideManager(enum e_side side); + SideManager(); + SideManager(size_t side); + public: /* Accessors */ + enum e_side get_side() const; + enum e_side get_opposite() const; + enum e_side get_rotate_clockwise() const; + enum e_side get_rotate_counterclockwise() const; + bool validate() const; + size_t to_size_t() const; + const char* c_str() const; + std::string to_string() const; + public: /* Mutators */ + void set_side(size_t side); + void set_side(enum e_side side); + void set_opposite(); + void rotate_clockwise(); + void rotate_counterclockwise(); + private: /* internal data */ + enum e_side side_; +}; + +} /* namespace openfpga ends */ + +#endif diff --git a/openfpga/src/annotation/annotate_routing.cpp b/openfpga/src/annotation/annotate_routing.cpp index 2f16a2bff..5e9dc4144 100644 --- a/openfpga/src/annotation/annotate_routing.cpp +++ b/openfpga/src/annotation/annotate_routing.cpp @@ -16,26 +16,33 @@ namespace openfpga { * based on VPR routing results * - Unmapped rr_node will use invalid ids *******************************************************************/ -void annotate_rr_node_nets(const ClusteringContext& vpr_clustering_ctx, - const RoutingContext& vpr_routing_ctx, - VprRoutingAnnotation& vpr_routing_annotation) { +void annotate_rr_node_nets(const DeviceContext& device_ctx, + const ClusteringContext& clustering_ctx, + const RoutingContext& routing_ctx, + VprRoutingAnnotation& vpr_routing_annotation, + const bool& verbose) { size_t counter = 0; VTR_LOG("Annotating rr_node with routed nets..."); + VTR_LOGV(verbose, "\n"); - for (auto net_id : vpr_clustering_ctx.clb_nlist.nets()) { + for (auto net_id : clustering_ctx.clb_nlist.nets()) { /* Ignore nets that are not routed */ - if (true == vpr_clustering_ctx.clb_nlist.net_is_ignored(net_id)) { + if (true == clustering_ctx.clb_nlist.net_is_ignored(net_id)) { continue; } /* Ignore used in local cluster only, reserved one CLB pin */ - if (false == vpr_clustering_ctx.clb_nlist.net_sinks(net_id).size()) { + if (false == clustering_ctx.clb_nlist.net_sinks(net_id).size()) { continue; } - t_trace* tptr = vpr_routing_ctx.trace[net_id].head; + t_trace* tptr = routing_ctx.trace[net_id].head; while (tptr != nullptr) { RRNodeId rr_node = tptr->index; - vpr_routing_annotation.set_rr_node_net(rr_node, net_id); - counter++; + /* Ignore source and sink nodes, they are the common node multiple starting and ending points */ + if ( (SOURCE != device_ctx.rr_graph.node_type(rr_node)) + && (SINK != device_ctx.rr_graph.node_type(rr_node)) ) { + vpr_routing_annotation.set_rr_node_net(rr_node, net_id); + counter++; + } tptr = tptr->next; } } diff --git a/openfpga/src/annotation/annotate_routing.h b/openfpga/src/annotation/annotate_routing.h index e0c571278..9496c6e81 100644 --- a/openfpga/src/annotation/annotate_routing.h +++ b/openfpga/src/annotation/annotate_routing.h @@ -15,9 +15,11 @@ /* begin namespace openfpga */ namespace openfpga { -void annotate_rr_node_nets(const ClusteringContext& vpr_clustering_ctx, - const RoutingContext& vpr_routing_ctx, - VprRoutingAnnotation& vpr_routing_annotation); +void annotate_rr_node_nets(const DeviceContext& device_ctx, + const ClusteringContext& clustering_ctx, + const RoutingContext& routing_ctx, + VprRoutingAnnotation& vpr_routing_annotation, + const bool& verbose); } /* end namespace openfpga */ diff --git a/openfpga/src/annotation/vpr_routing_annotation.cpp b/openfpga/src/annotation/vpr_routing_annotation.cpp index 0eaa4b5c1..1c17450ed 100644 --- a/openfpga/src/annotation/vpr_routing_annotation.cpp +++ b/openfpga/src/annotation/vpr_routing_annotation.cpp @@ -37,7 +37,7 @@ void VprRoutingAnnotation::set_rr_node_net(const RRNodeId& rr_node, VTR_ASSERT(size_t(rr_node) < rr_node_nets_.size()); /* Warn any override attempt */ if (ClusterNetId::INVALID() != rr_node_nets_[rr_node]) { - VTR_LOG_WARN("Override the net '%ld' for node'%ld' with in routing context annotation!\n", + VTR_LOG_WARN("Override the net '%ld' for node '%ld' with in routing context annotation!\n", size_t(net_id), size_t(rr_node)); } diff --git a/openfpga/src/base/openfpga_link_arch.cpp b/openfpga/src/base/openfpga_link_arch.cpp index 186f95f22..dee7662a6 100644 --- a/openfpga/src/base/openfpga_link_arch.cpp +++ b/openfpga/src/base/openfpga_link_arch.cpp @@ -57,8 +57,9 @@ void link_arch(OpenfpgaContext& openfpga_context, */ openfpga_context.mutable_vpr_routing_annotation().init(g_vpr_ctx.device().rr_graph); - annotate_rr_node_nets(g_vpr_ctx.clustering(), g_vpr_ctx.routing(), - openfpga_context.mutable_vpr_routing_annotation()); + annotate_rr_node_nets(g_vpr_ctx.device(), g_vpr_ctx.clustering(), g_vpr_ctx.routing(), + openfpga_context.mutable_vpr_routing_annotation(), + cmd_context.option_enable(cmd, opt_verbose)); } } /* end namespace openfpga */ diff --git a/openfpga/src/base/openfpga_pb_pin_fixup.cpp b/openfpga/src/base/openfpga_pb_pin_fixup.cpp index 4dc5e0b57..1c0beee27 100644 --- a/openfpga/src/base/openfpga_pb_pin_fixup.cpp +++ b/openfpga/src/base/openfpga_pb_pin_fixup.cpp @@ -10,6 +10,9 @@ /* Headers from vpr library */ #include "vpr_utils.h" +/* Headers from openfpgautil library */ +#include "openfpga_side_manager.h" + #include "pb_type_utils.h" #include "openfpga_pb_pin_fixup.h" @@ -56,6 +59,7 @@ void update_cluster_pin_with_post_routing_results(const DeviceContext& device_ct VprClusteringAnnotation& vpr_clustering_annotation, const vtr::Point& grid_coord, const ClusterBlockId& blk_id, + const e_side& border_side, const bool& verbose) { /* Handle each pin */ auto logical_block = clustering_ctx.clb_nlist.block_type(blk_id); @@ -66,6 +70,7 @@ void update_cluster_pin_with_post_routing_results(const DeviceContext& device_ct int physical_pin = get_physical_pin(physical_tile, logical_block, j); auto pin_class = physical_tile->pin_class[physical_pin]; auto class_inf = physical_tile->class_inf[pin_class]; + t_rr_type rr_node_type; if (class_inf.type == DRIVER) { rr_node_type = OPIN; @@ -74,49 +79,74 @@ void update_cluster_pin_with_post_routing_results(const DeviceContext& device_ct rr_node_type = IPIN; } std::vector pin_sides = find_logic_tile_pin_side(physical_tile, physical_pin); - /* As some grid go across columns or rows, we may not have the pin on any side */ + /* As some grid has height/width offset, we may not have the pin on any side */ if (0 == pin_sides.size()) { continue; } - for (const e_side& pin_side : pin_sides) { - /* Find the net mapped to this pin in routing results */ - const RRNodeId& rr_node = device_ctx.rr_graph.find_node(grid_coord.x(), grid_coord.y(), rr_node_type, physical_pin, pin_side); - if (false == device_ctx.rr_graph.valid_node_id(rr_node)) { - continue; - } - /* Get the cluster net id which has been mapped to this net */ - ClusterNetId routing_net_id = vpr_routing_annotation.rr_node_net(rr_node); - - /* Find the net mapped to this pin in clustering results*/ - ClusterNetId cluster_net_id = clustering_ctx.clb_nlist.block_net(blk_id, j); - - /* If matched, we finish here */ - if (routing_net_id == cluster_net_id) { - continue; - } - /* Add to net modification */ - vpr_clustering_annotation.rename_net(blk_id, j, routing_net_id); - - std::string routing_net_name("unmapped"); - if (ClusterNetId::INVALID() != routing_net_id) { - routing_net_name = clustering_ctx.clb_nlist.net_name(routing_net_id); - } - - std::string cluster_net_name("unmapped"); - if (ClusterNetId::INVALID() != cluster_net_id) { - cluster_net_name = clustering_ctx.clb_nlist.net_name(cluster_net_id); - } - - VTR_LOGV(verbose, - "Fixed up net '%s' mapping mismatch at clustered block '%s' pin '%s[%d]' (was net '%s')\n", - routing_net_name.c_str(), - clustering_ctx.clb_nlist.block_pb(blk_id)->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, - cluster_net_name.c_str() - ); + /* For regular grid, we should have pin only one side! + * I/O grids: VPR creates the grid with duplicated pins on every side + * but the expected side (only used side) will be opposite side of the border side! + */ + e_side pin_side = NUM_SIDES; + if (NUM_SIDES == border_side) { + VTR_ASSERT(1 == pin_sides.size()); + pin_side = pin_sides[0]; + } else { + SideManager side_manager(border_side); + VTR_ASSERT(pin_sides.end() != std::find(pin_sides.begin(), pin_sides.end(), side_manager.get_opposite())); + pin_side = side_manager.get_opposite(); } + + /* Find the net mapped to this pin in routing results */ + const RRNodeId& rr_node = device_ctx.rr_graph.find_node(grid_coord.x(), grid_coord.y(), rr_node_type, physical_pin, pin_side); + if (false == device_ctx.rr_graph.valid_node_id(rr_node)) { + continue; + } + /* Get the cluster net id which has been mapped to this net */ + ClusterNetId routing_net_id = vpr_routing_annotation.rr_node_net(rr_node); + + /* Find the net mapped to this pin in clustering results*/ + ClusterNetId cluster_net_id = clustering_ctx.clb_nlist.block_net(blk_id, j); + + /* Ignore those net have never been routed */ + if ( (ClusterNetId::INVALID() != cluster_net_id) + && (true == clustering_ctx.clb_nlist.net_is_ignored(cluster_net_id))) { + continue; + } + + /* Ignore used in local cluster only, reserved one CLB pin */ + if (false == clustering_ctx.clb_nlist.net_sinks(cluster_net_id).size()) { + continue; + } + + /* If matched, we finish here */ + if (routing_net_id == cluster_net_id) { + continue; + } + /* Add to net modification */ + vpr_clustering_annotation.rename_net(blk_id, j, routing_net_id); + + std::string routing_net_name("unmapped"); + if (ClusterNetId::INVALID() != routing_net_id) { + routing_net_name = clustering_ctx.clb_nlist.net_name(routing_net_id); + } + + std::string cluster_net_name("unmapped"); + if (ClusterNetId::INVALID() != cluster_net_id) { + cluster_net_name = clustering_ctx.clb_nlist.net_name(cluster_net_id); + } + + VTR_LOGV(verbose, + "Fixed up net '%s' mapping mismatch at clustered block '%s' pin 'grid[%ld][%ld].%s.%s[%d]' (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, + cluster_net_name.c_str() + ); } } @@ -131,12 +161,15 @@ void update_pb_pin_with_post_routing_results(const DeviceContext& device_ctx, const VprRoutingAnnotation& vpr_routing_annotation, VprClusteringAnnotation& vpr_clustering_annotation, const bool& verbose) { - for (size_t x = 0; x < device_ctx.grid.width(); ++x) { - for (size_t y = 0; y < device_ctx.grid.height(); ++y) { + /* Update the core logic (center blocks of the FPGA) */ + for (size_t x = 1; x < device_ctx.grid.width() - 1; ++x) { + for (size_t y = 1; y < device_ctx.grid.height() - 1; ++y) { /* Bypass the EMPTY tiles */ - if (device_ctx.EMPTY_PHYSICAL_TILE_TYPE == device_ctx.grid[x][y].type) { + if (true == is_empty_type(device_ctx.grid[x][y].type)) { continue; } + /* We must have an regular (non-I/O) type here */ + VTR_ASSERT(false == is_io_type(device_ctx.grid[x][y].type)); /* Get the mapped blocks to this grid */ for (const ClusterBlockId& cluster_blk_id : placement_ctx.grid_blocks[x][y].blocks) { /* Skip invalid ids */ @@ -147,11 +180,59 @@ void update_pb_pin_with_post_routing_results(const DeviceContext& device_ctx, vtr::Point grid_coord(x, y); update_cluster_pin_with_post_routing_results(device_ctx, clustering_ctx, vpr_routing_annotation, vpr_clustering_annotation, - grid_coord, cluster_blk_id, + grid_coord, cluster_blk_id, NUM_SIDES, verbose); } } } + + /* Update the periperal I/O blocks at fours sides of FPGA */ + std::vector io_sides{TOP, RIGHT, BOTTOM, LEFT}; + std::map>> io_coords; + + /* TOP side */ + for (size_t x = 1; x < device_ctx.grid.width() - 1; ++x) { + io_coords[TOP].push_back(vtr::Point(x, device_ctx.grid.height() -1)); + } + + /* RIGHT side */ + for (size_t y = 1; y < device_ctx.grid.height() - 1; ++y) { + io_coords[RIGHT].push_back(vtr::Point(device_ctx.grid.width() -1, y)); + } + + /* BOTTOM side */ + for (size_t x = 1; x < device_ctx.grid.width() - 1; ++x) { + io_coords[BOTTOM].push_back(vtr::Point(x, 0)); + } + + /* LEFT side */ + for (size_t y = 1; y < device_ctx.grid.height() - 1; ++y) { + io_coords[LEFT].push_back(vtr::Point(0, y)); + } + + /* Walk through io grid on by one */ + for (const e_side& io_side : io_sides) { + for (const vtr::Point& io_coord : io_coords[io_side]) { + /* Bypass EMPTY grid */ + if (true == is_empty_type(device_ctx.grid[io_coord.x()][io_coord.y()].type)) { + continue; + } + /* We must have an I/O type here */ + VTR_ASSERT(true == is_io_type(device_ctx.grid[io_coord.x()][io_coord.y()].type)); + /* Get the mapped blocks to this grid */ + for (const ClusterBlockId& cluster_blk_id : placement_ctx.grid_blocks[io_coord.x()][io_coord.y()].blocks) { + /* Skip invalid ids */ + if (ClusterBlockId::INVALID() == cluster_blk_id) { + continue; + } + /* Update on I/O grid */ + update_cluster_pin_with_post_routing_results(device_ctx, clustering_ctx, + vpr_routing_annotation, vpr_clustering_annotation, + io_coord, cluster_blk_id, io_side, + verbose); + } + } + } } /********************************************************************