diff --git a/libs/libclkarchopenfpga/src/base/clock_network.cpp b/libs/libclkarchopenfpga/src/base/clock_network.cpp index ecfdd48c6..9c493c9f7 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.cpp +++ b/libs/libclkarchopenfpga/src/base/clock_network.cpp @@ -389,6 +389,46 @@ std::vector ClockNetwork::tree_flatten_taps( return flatten_taps; } +std::vector ClockNetwork::flatten_internal_driver_port(const ClockInternalDriverId& int_driver_id) const { + std::vector flatten_taps; + for (const std::string& tap_name : internal_driver_port(int_driver_id)) { + StringToken tokenizer(tap_name); + std::vector pin_tokens = tokenizer.split("."); + if (pin_tokens.size() != 2) { + VTR_LOG_ERROR("Invalid pin name '%s'. Expect .\n", + tap_name.c_str()); + exit(1); + } + PortParser tile_parser(pin_tokens[0]); + BasicPort tile_info = tile_parser.port(); + PortParser pin_parser(pin_tokens[1]); + BasicPort pin_info = pin_parser.port(); + if (!tile_info.is_valid()) { + VTR_LOG_ERROR("Invalid pin name '%s' whose subtile index is not valid\n", + tap_name.c_str()); + exit(1); + } + if (!pin_info.is_valid()) { + VTR_LOG_ERROR("Invalid pin name '%s' whose pin index is not valid\n", + tap_name.c_str()); + exit(1); + } + for (size_t& tile_idx : tile_info.pins()) { + std::string flatten_tile_str = + tile_info.get_name() + "[" + std::to_string(tile_idx) + "]"; + for (size_t& pin_idx : pin_info.pins()) { + if (pin_idx != size_t(clk_pin_id)) { + continue; + } + std::string flatten_pin_str = + pin_info.get_name() + "[" + std::to_string(pin_idx) + "]"; + flatten_taps.push_back(flatten_tile_str + "." + flatten_pin_str); + } + } + } + return flatten_taps; +} + ClockTreeId ClockNetwork::find_tree(const std::string& name) const { auto result = tree_name2id_map_.find(name); if (result == tree_name2id_map_.end()) { diff --git a/libs/libclkarchopenfpga/src/base/clock_network.h b/libs/libclkarchopenfpga/src/base/clock_network.h index 836781ee6..6a972cb46 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.h +++ b/libs/libclkarchopenfpga/src/base/clock_network.h @@ -125,6 +125,7 @@ class ClockNetwork { const ClockSpineId& spine_id, const ClockSwitchPointId& switch_point_id) const; std::string internal_driver_port(const ClockInternalDriverId& int_driver_id) const; + std::vector flatten_internal_driver_port(const ClockInternalDriverId& int_driver_id) const; /* Return the original list of tap pins that is in storage; useful for parsers */ diff --git a/openfpga/src/annotation/append_clock_rr_graph.cpp b/openfpga/src/annotation/append_clock_rr_graph.cpp index ac48b5cef..3263c838b 100644 --- a/openfpga/src/annotation/append_clock_rr_graph.cpp +++ b/openfpga/src/annotation/append_clock_rr_graph.cpp @@ -545,7 +545,7 @@ static void add_rr_graph_block_clock_edges( clk_ntwk.default_tap_switch(), false); edge_count++; } - VTR_LOGV(verbose, "\tWill add %lu edges to other IPIN\n", + VTR_LOGV(verbose, "\tWill add %lu edges to IPINs\n", edge_count - curr_edge_count); } } @@ -557,6 +557,147 @@ static void add_rr_graph_block_clock_edges( num_edges_to_create += edge_count; } +/******************************************************************** + * Try to find an OPIN of a grid which satisfy the requirement of clock pins + * that has been defined in clock network. If the OPIN does exist in a + * routing resource graph, add it to the node list + *******************************************************************/ +static void try_find_and_add_clock_opin2track_node( + std::vector& opin_nodes, const DeviceGrid& grids, + const RRGraphView& rr_graph_view, const size_t& layer, + const vtr::Point& grid_coord, const e_side& pin_side, + const ClockNetwork& clk_ntwk, + const ClockInternalDriverId& int_driver_id) { + t_physical_tile_type_ptr grid_type = grids.get_physical_type( + t_physical_tile_loc(grid_coord.x(), grid_coord.y(), layer)); + for (std::string tap_pin_name : + clk_ntwk.flatten_internal_driver_port(int_driver_id)) { + /* tap pin name could be 'io[5:5].a2f[0]' */ + int grid_pin_idx = find_physical_tile_pin_index(grid_type, tap_pin_name); + if (grid_pin_idx == grid_type->num_pins) { + continue; + } + RRNodeId opin_node = rr_graph_view.node_lookup().find_node( + layer, grid_coord.x(), grid_coord.y(), OPIN, grid_pin_idx, pin_side); + if (rr_graph_view.valid_node(opin_node)) { + opin_nodes.push_back(opin_node); + } + } +} + +/******************************************************************** + * Find the source OPIN nodes as internal drivers for a clock node + * For example + * clk0_lvl1_chany[1][1] + * ^ + * | + * internal_driver OPIN[0] -->-------+ + * ^ + * | + * internal_driver OPIN[1] + * + * Coordinate system: + * + * +----------+----------+------------+ + * | Grid | CBy | Grid | + * | [x][y+1] | [x][y+1] | [x+1][y+1] | + * +----------+----------+------------+ + * | CBx | SB | CBx | + * | [x][y] | [x][y] | [x+1][y] | + * +----------+----------+------------+ + * | Grid | CBy | Grid | + * | [x][y] | [x][y] | [x+1][y] | + * +----------+----------+------------+ + *******************************************************************/ +static std::vector find_clock_opin2track_node( + const DeviceGrid& grids, const RRGraphView& rr_graph_view, + const size_t& layer, + const vtr::Point& sb_coord, + const ClockNetwork& clk_ntwk, + const std::vector& int_driver_ids +) { + std::vector opin_nodes; + /* Find opins from + * - Grid[x][y+1] on right and bottom sides + * - Grid[x+1][y+1] on left and bottom sides + * - Grid[x][y] on right and top sides + * - Grid[x+1][y] on left and top sides + */ + std::array, 4> grid_coords; + std::array, 2>, 4> grid_sides; + grid_coords[0] = grid_coord(sb_coord.x(), sb_coord.y() + 1); + grid_sides[0] = {RIGHT, BOTTOM}; + grid_coords[1] = grid_coord(sb_coord.x() + 1, sb_coord.y() + 1); + grid_sides[1] = {LEFT, BOTTOM}; + grid_coords[2] = grid_coord(sb_coord.x() + 1, sb_coord.y()); + grid_sides[2] = {RIGHT, TOP}; + grid_coords[3] = grid_coord(sb_coord.x(), sb_coord.y()); + grid_sides[3] = {LEFT, TOP}; + for (size_t igrid = 0; igrid < 4; igrid++) { + vtr::Point grid_coord = grid_coords[igrid]; + for (e_side grid_side : grid_sides[igrid]) { + for (ClockInternalDriverId int_driver_id : int_driver_ids) { + try_find_and_add_clock_opin2track_node(opin_nodes, grids, rr_graph_view, + layer, grid_coord, grid_side, + clk_ntwk, int_driver_id); + } + } + } + return opin_nodes; +} + +/******************************************************************** + * Add edges between OPIN of programmable blocks and clock routing tracks + * Note that such edges only occur at the switching points of spines + * Different from add_rr_graph_block_clock_edges(), we follow the clock spines here + * By expanding on switching points, internal drivers will be added + *******************************************************************/ +static int add_rr_graph_opin2clk_edges(RRGraphBuilder& rr_graph_builder, size_t& num_edges_to_create, + const RRClockSpatialLookup& clk_rr_lookup, const RRGraphView& rr_graph_view, + const DeviceGrid& grids, const size_t& layer, + const ClockNetwork& clk_ntwk, const bool& verbose) { + size_t edge_count = 0; + for (ClockSpineId ispine : clk_ntwk.spines(clk_tree)) { + VTR_LOGV(verbose, "Finding internal drivers on spine '%s'...\n", + clk_ntwk.spine_name(ispine).c_str()); + for (auto ipin : clk_ntwk.pins(clk_tree)) { + for (ClockSwitchPointId switch_point_id : + clk_ntwk.spine_switch_points(ispine)) { + if (clk_ntwk.spine_switch_point_internal_drivers(ispine, switch_point_id).empty()) { + continue; /* We only focus on switching points containing internal drivers */ + } + size_t curr_edge_count = edge_count; + /* Get the rr node of destination spine */ + ClockSpineId des_spine = + clk_ntwk.spine_switch_point_tap(ispine, switch_point_id); + vtr::Point des_coord = clk_ntwk.spine_start_point(des_spine); + Direction des_spine_direction = clk_ntwk.spine_direction(des_spine); + ClockLevelId des_spine_level = clk_ntwk.spine_level(des_spine); + RRNodeId des_node = + clk_rr_lookup.find_node(des_coord.x(), des_coord.y(), clk_tree, + des_spine_level, ipin, des_spine_direction); + /* Walk through each qualified OPIN, build edges */ + vtr::Point src_coord = + clk_ntwk.spine_switch_point(ispine, switch_point_id); + std::vector int_driver_ids = clk_ntwk.spine_switch_point_internal_drivers(ispine, switch_point_id); + for (RRNodId src_node : find_clock_opin2track_node(grids, rr_graph_view, layer, src_coord, clk_ntwk, int_driver_ids)) { + /* Create edges */ + VTR_ASSERT(rr_graph_view.valid_node(des_node)); + rr_graph_builder.create_edge(src_node, des_node, + clk_ntwk.default_driver_switch(), false); + edge_count++; + } + VTR_LOGV(verbose, "\tWill add %lu edges to OPINs at (x=%lu, y=%lu)\n", + edge_count - curr_edge_count, des_coord.x(), des_coord.y()); + } + } + } + /* Allocate edges */ + rr_graph_builder.build_edges(true); + num_edges_to_create += edge_count; + return CMD_EXEC_SUCCESS; +} + /******************************************************************** * Add edges to interconnect clock nodes * Walk through the routing tracks in each connection block (driver nodes) @@ -614,6 +755,8 @@ static void add_rr_graph_clock_edges( clk_ntwk, chany_coord, CHANY, verbose); } } + /* Add edges between OPIN (internal driver) and clock routing tracks */ + add_rr_graph_opin2clk_edges(rr_graph_builder, num_edges_to_create, rr_graph_view, grids, layer, clk_ntwk, verbose); } /********************************************************************