Skip to content

Commit 0502b83

Browse files
authored
Now direct connection builder in tileable rr_graph supports any subtile index as the from_pin (#3318)
* [test] add a strong test where clb, dsp and bram in a same tile, to validate the direct connections across subtiles * [test] deploy new test to strong reg test * [test] add new test * [test] add new arch from openfpga * [test] add new blif benchmark for tileable direct connection strong tests * [test] add new example arch to validate tileable direct connections * [test] reorg tasks * [test] deploy new tests to validate supertile with z_offset in direct connection for tileable rr_graph * [test] debug * [test] debug * [core] debug * [core] now search all the sub tiles which contains the ports defined in the direct * [core] syntax * [test] debug * [test] update golden * [test] add missing golden results * [core] add doxygen-style comments to vpr utility function * [core] simplify swap in if condition * [test] add arch file to validate direct connections across subtiles for regular rr_graph generator * [test] add new testcases for strong reg tests about direct connections between subtiles * [core] fixed the bug where IPIN coordinate does not consider pin offset at tile-level (pin location) * [core] should sit with root location for IPIN * [core] debug * [core] debug * [core] debug * [test] update golden * [doc] add examples * [doc] typo * [core] typo * [doc] typo
1 parent d3783bc commit 0502b83

File tree

35 files changed

+8849
-1087
lines changed

35 files changed

+8849
-1087
lines changed
27 KB
Loading

doc/src/arch/reference.rst

Lines changed: 83 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2365,6 +2365,8 @@ Direct Inter-block Connections
23652365
The content within the ``<directlist>`` tag consists of a group of ``<direct>`` tags.
23662366
The ``<direct>`` tag and its contents are described below.
23672367

2368+
.. note:: ``from_pin`` and ``to_pin`` only support big endian! For example, ``clb.out[8:0]``
2369+
23682370
.. arch:tag:: <direct name="string" from_pin="string" to_pin="string" x_offset="int" y_offset="int" z_offset="int" switch_name="string" from_side="{left|right|top|bottom}" to_side="{left|right|top|bottom}"/>
23692371
23702372
:req_param name: is a unique alphanumeric string to name the connection.
@@ -2384,12 +2386,89 @@ The ``<direct>`` tag and its contents are described below.
23842386
The ``from_side`` and ``to_side`` options can usually be left unspecified.
23852387
However they can be used to explicitly control how direct connections to physically equivalent pins (which may appear on multiple sides) are handled.
23862388

2387-
**Example:**
2388-
Consider a carry chain where the ``cout`` of each CLB drives the ``cin`` of the CLB immediately below it, using the delay-less switch one would enter the following:
2389+
**Example: Inter-tile connection**
2390+
Consider a carry chain where the ``cout`` of each CLB drives the ``cin`` of the CLB immediately below it, using the delay-less switch one would enter the following:
23892391

2390-
.. code-block:: xml
2392+
.. code-block:: xml
2393+
2394+
<direct name="adder_carry" from_pin="clb.cout" to_pin="clb.cin" x_offset="0" y_offset="-1" z_offset="0"/>
2395+
2396+
**Example: Inner-tile feedback**
2397+
2398+
Consider a feedback connection where the ``out`` of each CLB drives the ``in`` of the CLB in the same location, using the connection block switch one would enter the following:
2399+
2400+
.. code-block:: xml
2401+
2402+
<direct name="feedback" from_pin="clb.out" to_pin="clb.in" x_offset="0" y_offset="0" z_offset="0" switch_name="cb_mux"/>
2403+
2404+
**Example: Cross-sub-tile connection**
2405+
2406+
In this example, a tile ``cim8_1k`` is defined, under which there are two types of sub-tiles:
2407+
2408+
- ``mult_8``: the first sub-tile
2409+
- ``memory``: the second, and the third sub-tile
2410+
2411+
.. code-block:: xml
2412+
2413+
<tile name="cim8_1k" height="2" area="396000">
2414+
<sub_tile name="mult_8" capacity="1">
2415+
<equivalent_sites>
2416+
<site pb_type="mult_8" pin_mapping="direct"/>
2417+
</equivalent_sites>
2418+
<input name="a" num_pins="8"/>
2419+
<input name="b" num_pins="8"/>
2420+
<output name="out" num_pins="16"/>
2421+
<fc in_type="frac" in_val="0.15" out_type="frac" out_val="0.10">
2422+
<fc_override port_name="out" fc_type="frac" fc_val="0"/>
2423+
</fc>
2424+
<pinlocations pattern="custom">
2425+
<loc side="left"/>
2426+
<loc side="top"/>
2427+
<loc side="right" yoffset="0">mult_8.a[0:2] mult_8.b[0:2] mult_8.out[0:5]</loc>
2428+
<loc side="right" yoffset="1">mult_8.a[3:5] mult_8.b[3:5] mult_8.out[6:10]</loc>
2429+
<loc side="bottom">mult_8.a[6:7] mult_8.b[6:7] mult_8.out[11:15]</loc>
2430+
</pinlocations>
2431+
</sub_tile>
2432+
<sub_tile name="memory" capacity="2">
2433+
<equivalent_sites>
2434+
<site pb_type="memory"/>
2435+
</equivalent_sites>
2436+
<input name="waddr" num_pins="7"/>
2437+
<input name="raddr" num_pins="7"/>
2438+
<input name="data_in" num_pins="8"/>
2439+
<input name="wen" num_pins="1"/>
2440+
<input name="ren" num_pins="1"/>
2441+
<output name="data_out" num_pins="8"/>
2442+
<clock name="clk" num_pins="1"/>
2443+
<fc in_type="frac" in_val="0.15" out_type="frac" out_val="0.10">
2444+
<fc_override port_name="clk" fc_type="frac" fc_val="0"/>
2445+
<fc_override port_name="data_in" fc_type="frac" fc_val="0"/>
2446+
</fc>
2447+
<pinlocations pattern="custom">
2448+
<loc side="left" yoffset="0">memory.clk memory.waddr[0:0] memory.raddr[0:0] memory.data_in[0:0] memory.data_out[0:0]</loc>
2449+
<loc side="left" yoffset="1">memory.waddr[1:1] memory.raddr[1:1] memory.data_in[1:1] memory.data_out[1:1]</loc>
2450+
<loc side="top" yoffset="1">memory.waddr[2:2] memory.raddr[2:2] memory.data_in[2:2] memory.data_out[2:2] memory.waddr[3:3] memory.raddr[3:3] memory.data_in[3:3] memory.data_out[3:3]</loc>
2451+
<loc side="right" yoffset="0">memory.waddr[4:4] memory.raddr[4:4] memory.data_in[4:4] memory.data_out[4:4]</loc>
2452+
<loc side="right" yoffset="1">memory.waddr[5:5] memory.raddr[5:5] memory.data_in[5:5] memory.data_out[5:5]</loc>
2453+
<loc side="bottom" yoffset="0">memory.wen memory.waddr[6:6] memory.raddr[6:6] memory.data_in[6:6] memory.data_out[6:6] memory.ren memory.data_in[7:7] memory.data_out[7:7]</loc>
2454+
</pinlocations>
2455+
</sub_tile>
2456+
</tile>
2457+
2458+
As shown in :numref:`fig_example_subtile_direct_connection`, consider a connection where the ``out`` of a sub tile ``mult_8`` of tile ``cim8_1k`` drives the ``data_in`` of the sub tile ``memory`` of tile ``cim8_1k`` with an offset, using the delayless switch one would enter the following:
2459+
2460+
.. code-block:: xml
2461+
2462+
<direct name="cim_direct0" from_pin="cim8_1k.out[7:0]" to_pin="cim8_1k.data_in[7:0]" x_offset="0" y_offset="0" z_offset="1"/>
2463+
<direct name="cim_direct1" from_pin="cim8_1k.out[15:8]" to_pin="cim8_1k.data_in[7:0]" x_offset="0" y_offset="0" z_offset="2"/>
2464+
2465+
.. _fig_example_subtile_direct_connection:
2466+
2467+
.. figure:: ./example_subtile_direct_connection.png
2468+
:width: 60%
2469+
:alt: Example of direct connections across sub-tiles
23912470

2392-
<direct name="adder_carry" from_pin="clb.cout" to_pin="clb.cin" x_offset="0" y_offset="-1" z_offset="0"/>
2471+
Example of direct connections across sub-tiles
23932472

23942473
.. _custom_switch_blocks:
23952474

vpr/src/route/rr_graph_generation/clb2clb_directs.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ std::vector<t_clb_to_clb_directs> alloc_and_load_clb_to_clb_directs(const std::v
3333
clb_to_clb_directs[i].from_clb_type = physical_tile;
3434

3535
t_physical_tile_port tile_port = find_tile_port_by_name(physical_tile, port_name);
36+
/* Find the sub tile indices */
37+
clb_to_clb_directs[i].from_sub_tiles = find_sub_tile_indices_by_port_name(physical_tile, port_name);
38+
if (clb_to_clb_directs[i].from_sub_tiles.empty()) {
39+
VPR_THROW(VPR_ERROR_ARCH, "Unable to find sub tile under tile '%s' which contains the port %s.\n", tile_name.c_str(), port_name.data());
40+
}
3641

3742
if (start_pin_index == UNDEFINED) {
3843
VTR_ASSERT(start_pin_index == end_pin_index);

vpr/src/route/rr_graph_generation/clb2clb_directs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
*/
1414
struct t_clb_to_clb_directs {
1515
t_physical_tile_type_ptr from_clb_type;
16+
std::vector<int> from_sub_tiles;
1617
int from_clb_pin_start_index;
1718
int from_clb_pin_end_index;
1819
t_physical_tile_type_ptr to_clb_type;

vpr/src/route/rr_graph_generation/rr_graph.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2939,7 +2939,7 @@ static int get_opin_direct_connections(RRGraphBuilder& rr_graph_builder,
29392939
auto [z, relative_opin] = get_capacity_location_from_physical_pin(curr_type, opin);
29402940
VTR_ASSERT(z >= 0 && z < curr_type->capacity);
29412941
const int num_directs = directs.size();
2942-
2942+
29432943
// Iterate through all direct connections
29442944
for (int i = 0; i < num_directs; i++) {
29452945
// Find matching direct clb-to-clb connections with the same type as current grid location
@@ -3012,15 +3012,21 @@ static int get_opin_direct_connections(RRGraphBuilder& rr_graph_builder,
30123012
// Add new ipin edge to list of edges
30133013
std::vector<RRNodeId> inodes;
30143014

3015+
int target_width_offset = device_ctx.grid.get_width_offset({x + directs[i].x_offset, y + directs[i].y_offset, layer});
3016+
int target_height_offset = device_ctx.grid.get_height_offset({x + directs[i].x_offset, y + directs[i].y_offset, layer});
3017+
int final_ipin_x = x + directs[i].x_offset - target_width_offset + target_type->pin_width_offset[ipin];
3018+
int final_ipin_y = y + directs[i].y_offset - target_height_offset + target_type->pin_height_offset[ipin];
3019+
30153020
if (directs[i].to_side != NUM_2D_SIDES) {
30163021
//Explicit side specified, only create if pin exists on that side
3017-
RRNodeId inode = rr_graph_builder.node_lookup().find_node(layer, x + directs[i].x_offset, y + directs[i].y_offset, e_rr_type::IPIN, ipin, directs[i].to_side);
3022+
RRNodeId inode = rr_graph_builder.node_lookup().find_node(layer, final_ipin_x, final_ipin_y,
3023+
e_rr_type::IPIN, ipin, directs[i].to_side);
30183024
if (inode) {
30193025
inodes.push_back(inode);
30203026
}
30213027
} else {
30223028
//No side specified, get all candidates
3023-
inodes = rr_graph_builder.node_lookup().find_nodes_at_all_sides(layer, x + directs[i].x_offset, y + directs[i].y_offset, e_rr_type::IPIN, ipin);
3029+
inodes = rr_graph_builder.node_lookup().find_nodes_at_all_sides(layer, final_ipin_x, final_ipin_y, e_rr_type::IPIN, ipin);
30243030
}
30253031

30263032
if (inodes.size() > 0) {

vpr/src/route/rr_graph_generation/tileable_rr_graph/tileable_rr_graph_gsb.cpp

Lines changed: 67 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1722,74 +1722,81 @@ void build_direct_connections_for_one_gsb(const RRGraphView& rr_graph,
17221722
}
17231723

17241724
/* get every opin in the range */
1725-
for (int opin = min_index; opin <= max_index; ++opin) {
1726-
int offset = opin - min_index;
1725+
for (int relative_opin = min_index; relative_opin <= max_index; ++relative_opin) {
1726+
int offset = relative_opin - min_index;
17271727
//Capacity location determined by pin number relative to pins per capacity instance
1728-
auto [z, relative_opin] = get_capacity_location_from_physical_pin(grid_type, opin);
1729-
VTR_ASSERT(z >= 0 && z < grid_type->capacity);
1730-
1731-
if ((to_grid_coordinate.x() < grids.width() - 1)
1732-
&& (to_grid_coordinate.y() < grids.height() - 1)) {
1733-
int relative_ipin = UNDEFINED;
1734-
if (clb_to_clb_directs[i].to_clb_pin_start_index
1735-
> clb_to_clb_directs[i].to_clb_pin_end_index) {
1736-
if (true == swap) {
1737-
relative_ipin = clb_to_clb_directs[i].to_clb_pin_end_index + offset;
1728+
for (int z : clb_to_clb_directs[i].from_sub_tiles) {
1729+
int opin = get_physical_pin_from_capacity_location(grid_type, relative_opin, z);
1730+
VTR_ASSERT(z >= 0 && z < grid_type->capacity);
1731+
1732+
if ((to_grid_coordinate.x() < grids.width() - 1)
1733+
&& (to_grid_coordinate.y() < grids.height() - 1)) {
1734+
int relative_ipin = UNDEFINED;
1735+
if (clb_to_clb_directs[i].to_clb_pin_start_index
1736+
> clb_to_clb_directs[i].to_clb_pin_end_index) {
1737+
if (swap) {
1738+
relative_ipin = clb_to_clb_directs[i].to_clb_pin_end_index + offset;
1739+
} else {
1740+
relative_ipin = clb_to_clb_directs[i].to_clb_pin_start_index - offset;
1741+
}
17381742
} else {
1739-
relative_ipin = clb_to_clb_directs[i].to_clb_pin_start_index - offset;
1743+
if (swap) {
1744+
relative_ipin = clb_to_clb_directs[i].to_clb_pin_end_index - offset;
1745+
} else {
1746+
relative_ipin = clb_to_clb_directs[i].to_clb_pin_start_index + offset;
1747+
}
17401748
}
1741-
} else {
1742-
if (true == swap) {
1743-
relative_ipin = clb_to_clb_directs[i].to_clb_pin_end_index - offset;
1744-
} else {
1745-
relative_ipin = clb_to_clb_directs[i].to_clb_pin_start_index + offset;
1749+
1750+
/* Get the pin index in the rr_graph */
1751+
t_physical_tile_loc from_tile_loc(from_grid_coordinate.x(), from_grid_coordinate.y(), layer);
1752+
t_physical_tile_loc to_tile_loc(to_grid_coordinate.x(), to_grid_coordinate.y(), layer);
1753+
1754+
/* Find the side of grid pins, the pin location should be unique!
1755+
* Pin location is required by searching a node in rr_graph
1756+
*/
1757+
std::vector<e_side> opin_grid_side = find_grid_pin_sides(grids, layer, from_grid_coordinate.x() + grid_type->pin_width_offset[opin], from_grid_coordinate.y() + grid_type->pin_height_offset[opin], opin);
1758+
if (1 != opin_grid_side.size()) {
1759+
VPR_FATAL_ERROR(VPR_ERROR_ARCH, "[Arch LINE %d] From pin (index=%d) of direct connection '%s' does not exist on any side of the programmable block '%s'.\n", directs[i].line, opin, directs[i].from_pin.c_str());
17461760
}
1747-
}
17481761

1749-
/* Get the pin index in the rr_graph */
1750-
t_physical_tile_loc from_tile_loc(from_grid_coordinate.x(), from_grid_coordinate.y(), layer);
1751-
t_physical_tile_loc to_tile_loc(to_grid_coordinate.x(), to_grid_coordinate.y(), layer);
1762+
/* directs[i].sub_tile_offset is added to from_capacity(z) to get the target_capacity */
1763+
int to_subtile_cap = z + directs[i].sub_tile_offset;
1764+
/* Iterate over all sub_tiles to get the sub_tile which the target_cap belongs to. */
1765+
const t_sub_tile* to_sub_tile = nullptr;
1766+
for (const t_sub_tile& sub_tile : to_grid_type->sub_tiles) {
1767+
if (sub_tile.capacity.is_in_range(to_subtile_cap)) {
1768+
to_sub_tile = &sub_tile;
1769+
break;
1770+
}
1771+
}
1772+
VTR_ASSERT(to_sub_tile != nullptr);
1773+
if (relative_ipin >= to_sub_tile->num_phy_pins) continue;
1774+
// If this block has capacity > 1 then the pins of z position > 0 are offset
1775+
// by the number of pins per capacity instance
1776+
int ipin = get_physical_pin_from_capacity_location(to_grid_type, relative_ipin, to_subtile_cap);
1777+
std::vector<e_side> ipin_grid_side = find_grid_pin_sides(grids, layer, to_grid_coordinate.x() + to_grid_type->pin_width_offset[ipin], to_grid_coordinate.y() + to_grid_type->pin_height_offset[ipin], ipin);
1778+
if (1 != ipin_grid_side.size()) {
1779+
VPR_FATAL_ERROR(VPR_ERROR_ARCH, "[Arch LINE %d] To pin (index=%d) of direct connection '%s' does not exist on any side of the programmable block '%s'.\n", directs[i].line, relative_ipin, directs[i].to_pin.c_str());
1780+
}
17521781

1753-
/* Find the side of grid pins, the pin location should be unique!
1754-
* Pin location is required by searching a node in rr_graph
1755-
*/
1756-
std::vector<e_side> opin_grid_side = find_grid_pin_sides(grids, layer, from_grid_coordinate.x() + grid_type->pin_width_offset[opin], from_grid_coordinate.y() + grid_type->pin_height_offset[opin], opin);
1757-
if (1 != opin_grid_side.size()) {
1758-
VPR_FATAL_ERROR(VPR_ERROR_ARCH, "[Arch LINE %d] From pin (index=%d) of direct connection '%s' does not exist on any side of the programmable block '%s'.\n", directs[i].line, opin, directs[i].from_pin.c_str());
1759-
}
1760-
1761-
/* directs[i].sub_tile_offset is added to from_capacity(z) to get the target_capacity */
1762-
int to_subtile_cap = z + directs[i].sub_tile_offset;
1763-
/* Iterate over all sub_tiles to get the sub_tile which the target_cap belongs to. */
1764-
const t_sub_tile* to_sub_tile = nullptr;
1765-
for (const t_sub_tile& sub_tile : to_grid_type->sub_tiles) {
1766-
if (sub_tile.capacity.is_in_range(to_subtile_cap)) {
1767-
to_sub_tile = &sub_tile;
1768-
break;
1782+
RRNodeId opin_node_id = rr_graph.node_lookup().find_node(layer,
1783+
from_grid_coordinate.x() + grid_type->pin_width_offset[opin],
1784+
from_grid_coordinate.y() + grid_type->pin_height_offset[opin],
1785+
e_rr_type::OPIN, opin, opin_grid_side[0]);
1786+
RRNodeId ipin_node_id = rr_graph.node_lookup().find_node(layer,
1787+
to_grid_coordinate.x() + to_grid_type->pin_width_offset[ipin],
1788+
to_grid_coordinate.y() + to_grid_type->pin_height_offset[ipin],
1789+
e_rr_type::IPIN, ipin, ipin_grid_side[0]);
1790+
1791+
/* add edges to the opin_node */
1792+
if (!opin_node_id) {
1793+
VTR_ASSERT(opin_node_id);
1794+
}
1795+
if (!ipin_node_id) {
1796+
VTR_ASSERT(opin_node_id);
17691797
}
1798+
rr_graph_builder.create_edge_in_cache(opin_node_id, ipin_node_id, RRSwitchId(clb_to_clb_directs[i].switch_index), false);
17701799
}
1771-
VTR_ASSERT(to_sub_tile != nullptr);
1772-
if (relative_ipin >= to_sub_tile->num_phy_pins) continue;
1773-
// If this block has capacity > 1 then the pins of z position > 0 are offset
1774-
// by the number of pins per capacity instance
1775-
int ipin = get_physical_pin_from_capacity_location(to_grid_type, relative_ipin, to_subtile_cap);
1776-
std::vector<e_side> ipin_grid_side = find_grid_pin_sides(grids, layer, to_grid_coordinate.x() + to_grid_type->pin_width_offset[ipin], to_grid_coordinate.y() + to_grid_type->pin_height_offset[ipin], ipin);
1777-
if (1 != ipin_grid_side.size()) {
1778-
VPR_FATAL_ERROR(VPR_ERROR_ARCH, "[Arch LINE %d] To pin (index=%d) of direct connection '%s' does not exist on any side of the programmable block '%s'.\n", directs[i].line, relative_ipin, directs[i].to_pin.c_str());
1779-
}
1780-
1781-
RRNodeId opin_node_id = rr_graph.node_lookup().find_node(layer,
1782-
from_grid_coordinate.x() + grid_type->pin_width_offset[opin],
1783-
from_grid_coordinate.y() + grid_type->pin_height_offset[opin],
1784-
e_rr_type::OPIN, opin, opin_grid_side[0]);
1785-
RRNodeId ipin_node_id = rr_graph.node_lookup().find_node(layer,
1786-
to_grid_coordinate.x() + to_grid_type->pin_width_offset[ipin],
1787-
to_grid_coordinate.y() + to_grid_type->pin_height_offset[ipin],
1788-
e_rr_type::IPIN, ipin, ipin_grid_side[0]);
1789-
1790-
/* add edges to the opin_node */
1791-
VTR_ASSERT(opin_node_id && ipin_node_id);
1792-
rr_graph_builder.create_edge_in_cache(opin_node_id, ipin_node_id, RRSwitchId(clb_to_clb_directs[i].switch_index), false);
17931800
}
17941801
}
17951802
}

0 commit comments

Comments
 (0)