Skip to content

Commit 7641911

Browse files
authored
Merge pull request #3212 from verilog-to-routing/sg_parsing
Add Parsing Code For Scatter-Gather Patterns
2 parents ac29169 + bf244ed commit 7641911

File tree

15 files changed

+2139
-125
lines changed

15 files changed

+2139
-125
lines changed

doc/src/arch/reference.rst

Lines changed: 109 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2485,7 +2485,7 @@ The full format is documented below.
24852485
Defined under the ``<switchfuncs>`` XML node, one or more ``<func...>`` entries is used to specify permutation functions that connect different sides of a switch block.
24862486

24872487

2488-
.. arch:tag:: <wireconn num_conns="expr" from_type="string, string, string, ..." to_type="string, string, string, ..." from_switchpoint="int, int, int, ..." to_switchpoint="int, int, int, ..." from_order="{fixed | shuffled}" to_order="{fixed | shuffled}" switch_override="string"/>
2488+
.. arch:tag:: <wireconn num_conns="expr" from_type="string, string, string, ..." to_type="string, string, string, ..." from_switchpoint="int, int, int, ..." to_switchpoint="int, int, int, ..." from_order="{fixed | shuffled}" to_order="{fixed | shuffled}" switch_override="string" side="string"/>
24892489
24902490
:req_param num_conns:
24912491
Specifies how many connections should be created between the from_type/from_switchpoint set and the to_type/to_switchpoint set.
@@ -2592,6 +2592,10 @@ The full format is documented below.
25922592
By using a zero-delay and zero-resistance switch one can also create T and L shaped wire segments.
25932593

25942594
**Default:** If no override is specified, the usual wire_switch that drives the ``to`` wire will be used.
2595+
2596+
:opt_param side:
2597+
Specifies the sides that connections are gathered from or scattered to. Valid sides are right, left, top and bottom and are represented by characters 'r', 'l', 't' and 'b'.
2598+
For example, to select connections from right, left and bottom set this attribute to "rlb". Note that this attribute is used only for :ref:`scatter_gather_patterns` and does not do anything for other usages of this tag.
25952599

25962600
.. arch:tag:: <from type="string" switchpoint="int, int, int, ..."/>
25972601
@@ -2634,6 +2638,110 @@ The full format is documented below.
26342638
The 'to' set is all L4 switchpoint 0's.
26352639
Note that since different switchpoints are selected from different segment types it is not possible to specify this without using ``<from>`` sub-tags.
26362640
2641+
.. _scatter_gather_patterns:
2642+
2643+
Scatter-Gather Patterns
2644+
---------------------
2645+
2646+
The content under the ``<scatter_gather_list>`` tag consists of one or more ``<sg_pattern>`` tags that are used to specify a scatter-gather pattern.
2647+
Scatter-gather patterns can be used to specify multi-level switch patterns, rather than the direct wire-to-wire switch patterns of conventional switch blocks.
2648+
These additional switches, wires and/or muxes will be added to the architecture, augmenting wires created using segment specifications and swiches created using switch box specifications.
2649+
The number of any additional wires or muxes created by scatter-gather specifications will not vary with routing channel width.
2650+
2651+
.. figure:: scatter_gather_images/scattergather_diagram.svg
2652+
2653+
Overview of how scatter-gather patterns work. First, connections from a switchblock location are selected according to the specification.
2654+
These selected connection are then muxed and passed through the scatter-gather node, which is typically a wire segment. The scatter-gather node then fans out or scatters in another switchblock location.
2655+
2656+
.. note:: Scatter-Gather patterns are work in progress and experimental. Currently, VPR does not support this specification and using this tag would not result in any modifications to the RR-Graph.
2657+
2658+
When instantiated, a scatter-gather pattern gathers connections from a switchblock and passes the connection through a multiplexer and the scatter-gather node which is typically a wire segment, then scatters or fans out somewhere else in the device. These patterns can be used to define 3D switchblocks. An example is shown below:
2659+
2660+
.. code-block:: xml
2661+
2662+
<scatter_gather_list>
2663+
<sg_pattern name="name" type="unidir">
2664+
<gather>
2665+
<!-- Gather 30 connections from the 0, 4, 8 or 12 position of L16 wires of all four sides of a switchblock location -->
2666+
<wireconn num_conns="30" from_type="L16" from_switchpoint="0,12,8,4" side="rltb"/>
2667+
<gather/>
2668+
2669+
<scatter>
2670+
<!-- Scatter 30 connections to the starting position of L16 wires of all four sides of a switchblock location -->
2671+
<wireconn num_conns="30" to_type="L16" to_switchpoint="0" side="rtlb"/>
2672+
<scatter/>
2673+
2674+
<sg_link_list>
2675+
<!-- Link going up one layer, using the '3D_SB_MUX' multiplexer to gather connections from the bottom layer and using the 'TSV' node/wire to move up one layer -->
2676+
<sg_link name="L_UP" z_offset="1" x_offset="0" y_offset="0" mux="3D_SB_MUX" seg_type="TSV"/>
2677+
<!-- Same as above but moving one layer down -->
2678+
<sg_link name="L_DOWN" z_offset="-1" mux="3D_SB_MUX" seg_type="TSV"/>
2679+
<sg_link_list/>
2680+
2681+
<!-- Instantiate 10 'L_UP' sg_links per switchblock location everywhere on the device -->
2682+
<sg_location type="EVERYWHERE" num="10" sg_link="L_UP"/>
2683+
<!-- Instantiate 10 'L_DOWN' sg_links per switchblock location everywhere on the device -->
2684+
<sg_location type="EVERYWHERE" num="10" sg_link="L_DOWN"/>
2685+
<sg_pattern/>
2686+
2687+
<sg_pattern name="interposer_conn_sg" type="bidir">
2688+
... <!-- Another scatter-gather pattern specification -->
2689+
<sg_pattern/>
2690+
<scatter_gather_list/>
2691+
2692+
.. arch:tag:: <sg_pattern name="string" type={unidir|bidir}>
2693+
2694+
:req_param name: A unique alphanumeric string
2695+
:req_param type: ``unidir`` or ``bidir``.
2696+
2697+
'unidir': Added connections are unidirectional; all the gather connections are combined in a mux that then drives the scatter-gather node which in turn drives the wires specified in the scatter specification.
2698+
2699+
'bidir': The gather and scatter connections are mirrored; the same scatter pattern is implemented at each end of the scatter-gather pattern. This implies the two muxes driving the scatter-gather node can have their outputs tri-stated.
2700+
2701+
.. arch:tag:: <gather>
2702+
2703+
Contains a <wireconn> tag specifying how the fan-in or gather connections are selected. See ``wireconn`` for the relevant specification.
2704+
This <wireconn> tag supports an additioinal 'side' attribute which selects the sides that connections are gathered from (e.g. any of the top, bottom, left and right).
2705+
2706+
.. arch:tag:: <scatter>
2707+
2708+
Contains a <wireconn> tag specifying how the fan-out or scatter connections are selected. See ``wireconn`` for the relevant specification.
2709+
This <wireconn> tag supports an additioinal 'side' attribute which selects the sides that connections are scattered to (e.g. any of the top, bottom, left and right).
2710+
2711+
.. arch:tag:: <sg_link_list>
2712+
2713+
Contains one or more <sg_link> tags specifying how the pattern of how connections move from the gather location to the scatter location i.e. defines the used mux and scatter-gather node.
2714+
2715+
.. note:: <sg_link> tags are not instantiations of the pattern and would not result in any changes to the device. instead, the <sg_location> tag instantiates the pattern and selects one of the <sg_link> tags to be used for the instantiation.
2716+
2717+
.. arch:tag:: <sg_link name="string" x_offset="int" y_offset="int" z_offset="int" mux="string" seg_type="string">
2718+
2719+
:req_param name: A unique alphanumeric string
2720+
:req_param mux: Name of the multiplexer used to gather connections
2721+
:req_param seg_type: Name of the segment/wire used to move through the device to the scatter location (i.e. the type of the scatter-gather node)
2722+
2723+
:opt_param x_offset: Offset of the scatter relative to the gather in the x-axis
2724+
:opt_param y_offset: Offset of the scatter relative to the gather in the y-axis
2725+
:opt_param z_offset: Offset of the scatter relative to the gather in the z-axis
2726+
2727+
.. note:: One and only one of the offset fields for the sg_link tag should be set. The magnitude of the offset will generally be chosen by the architecture file creator to match the length of the sg_link segment type.
2728+
2729+
.. arch:tag:: <sg_location type="string" num="int" sg_link_name="string">
2730+
2731+
Instantiates the scatter-gather pattern with the specified sg_link.
2732+
2733+
:req_param num: number of scatter-gather instances per matching location (e.g. per switch block)
2734+
:req_param sg_link_name: name of the sg_link used in the instantiation
2735+
:req_param type: Can be one of the following strings:
2736+
2737+
* ``EVERYWHERE`` – at each switch block of the FPGA
2738+
* ``PERIMETER`` – at each perimeter switch block (x-directed and/or y-directed channel segments may terminate here)
2739+
* ``CORNER`` – only at the corner switch blocks (both x and y-directed channels terminate here)
2740+
* ``FRINGE`` – same as PERIMETER but excludes corners
2741+
* ``CORE`` – everywhere but the perimeter
2742+
Sets the location on the FPGA where the connections described by this scatter-gather pattern be instantiated.
2743+
2744+
26372745
.. _arch_metadata:
26382746
26392747
Architecture metadata
171 KB
Loading

doc/src/arch/scatter_gather_images/scattergather_diagram.svg

Lines changed: 4 additions & 0 deletions
Loading

libs/libarchfpga/src/parse_switchblocks.cpp

Lines changed: 72 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -34,19 +34,6 @@ using vtr::t_formula_data;
3434
/**** Function Declarations ****/
3535
/*---- Functions for Parsing Switchblocks from Architecture ----*/
3636

37-
/**
38-
* @brief Parses a wireconn node and returns a `t_wireconn_inf` structure.
39-
*
40-
* Determines whether the wireconn is in inline or multi-node format and dispatches
41-
* to the appropriate parsing subroutine.
42-
*
43-
* @param node XML node representing the wireconn.
44-
* @param loc_data Location data for error reporting.
45-
* @param switches List of architecture switch definitions (used for switch overrides).
46-
* @return A `t_wireconn_inf` structure populated with parsed data.
47-
*/
48-
static t_wireconn_inf parse_wireconn(pugi::xml_node node, const pugiutil::loc_data& loc_data, const std::vector<t_arch_switch_inf>& switches);
49-
5037
//Process the desired order of a wireconn
5138
static void parse_switchpoint_order(const char* order, SwitchPointOrder& switchpoint_order);
5239

@@ -60,11 +47,15 @@ static void parse_switchpoint_order(const char* order, SwitchPointOrder& switchp
6047
* @param node XML node containing inline wireconn attributes.
6148
* @param loc_data Location data for error reporting.
6249
* @param switches List of architecture switch definitions (used for switch overrides).
50+
* @param can_skip_from_or_to Determines if the from or to attributes are optional or mandatory.
51+
* <wireconn> tags for switch blocks require both from and to attributes while those for
52+
* scatter-gather use one or the other.
6353
* @return A `t_wireconn_inf` structure populated with parsed data.
6454
*/
6555
static t_wireconn_inf parse_wireconn_inline(pugi::xml_node node,
6656
const pugiutil::loc_data& loc_data,
67-
const std::vector<t_arch_switch_inf>& switches);
57+
const std::vector<t_arch_switch_inf>& switches,
58+
bool can_skip_from_or_to);
6859

6960
/**
7061
* @brief Parses a multi-node `<wireconn>` definition with `<from>` and `<to>` children.
@@ -137,49 +128,77 @@ void read_sb_wireconns(const std::vector<t_arch_switch_inf>& switches,
137128
}
138129
}
139130

140-
static t_wireconn_inf parse_wireconn(pugi::xml_node node,
141-
const pugiutil::loc_data& loc_data,
142-
const std::vector<t_arch_switch_inf>& switches) {
131+
t_wireconn_inf parse_wireconn(pugi::xml_node node,
132+
const pugiutil::loc_data& loc_data,
133+
const std::vector<t_arch_switch_inf>& switches,
134+
bool can_skip_from_or_to) {
143135

144136
size_t num_children = count_children(node, "from", loc_data, ReqOpt::OPTIONAL);
145137
num_children += count_children(node, "to", loc_data, ReqOpt::OPTIONAL);
146138

139+
t_wireconn_inf wireconn;
147140
if (num_children == 0) {
148-
return parse_wireconn_inline(node, loc_data, switches);
141+
wireconn = parse_wireconn_inline(node, loc_data, switches, can_skip_from_or_to);
149142
} else {
150143
VTR_ASSERT(num_children > 0);
151-
return parse_wireconn_multinode(node, loc_data, switches);
144+
wireconn = parse_wireconn_multinode(node, loc_data, switches);
145+
}
146+
147+
// Parse the optional "side" field of the <wireconn> tag
148+
std::string sides_string = get_attribute(node, "side", loc_data, pugiutil::OPTIONAL).as_string();
149+
150+
if (sides_string.find_first_not_of("rtlbRTLB") != std::string::npos) {
151+
archfpga_throw(loc_data.filename_c_str(), loc_data.line(node), "Unknown side specified: %s\n", sides_string.c_str());
152152
}
153+
for (char side_char : sides_string) {
154+
wireconn.sides.insert(CHAR_SIDE_MAP.at(side_char));
155+
}
156+
157+
return wireconn;
153158
}
154159

155160
static t_wireconn_inf parse_wireconn_inline(pugi::xml_node node,
156161
const pugiutil::loc_data& loc_data,
157-
const std::vector<t_arch_switch_inf>& switches) {
162+
const std::vector<t_arch_switch_inf>& switches,
163+
bool can_skip_from_or_to) {
158164

159165
// Parse an inline wireconn definition, using attributes
160-
expect_only_attributes(node, {"num_conns", "from_type", "to_type", "from_switchpoint", "to_switchpoint", "from_order", "to_order", "switch_override"}, loc_data);
166+
expect_only_attributes(node,
167+
{"num_conns", "from_type", "to_type", "from_switchpoint",
168+
"to_switchpoint", "from_order", "to_order", "switch_override", "side"},
169+
loc_data);
161170

162171
t_wireconn_inf wc;
163172

173+
ReqOpt from_to_required = can_skip_from_or_to ? ReqOpt::OPTIONAL : ReqOpt::REQUIRED;
174+
164175
// get the connection style
165176
const char* char_prop = get_attribute(node, "num_conns", loc_data).value();
166177
parse_num_conns(char_prop, wc);
167178

168179
// get from type
169-
char_prop = get_attribute(node, "from_type", loc_data).value();
170-
parse_comma_separated_wire_types(char_prop, wc.from_switchpoint_set);
180+
char_prop = get_attribute(node, "from_type", loc_data, from_to_required).value();
181+
if (!can_skip_from_or_to) {
182+
parse_comma_separated_wire_types(char_prop, wc.from_switchpoint_set);
183+
}
171184

172185
// get to type
173-
char_prop = get_attribute(node, "to_type", loc_data).value();
174-
parse_comma_separated_wire_types(char_prop, wc.to_switchpoint_set);
186+
char_prop = get_attribute(node, "to_type", loc_data, from_to_required).value();
187+
if (!can_skip_from_or_to) {
188+
parse_comma_separated_wire_types(char_prop, wc.to_switchpoint_set);
189+
}
175190

176191
// get the source wire point
177-
char_prop = get_attribute(node, "from_switchpoint", loc_data).value();
178-
parse_comma_separated_wire_points(char_prop, wc.from_switchpoint_set);
192+
char_prop = get_attribute(node, "from_switchpoint", loc_data, from_to_required).value();
193+
if (!can_skip_from_or_to) {
194+
parse_comma_separated_wire_points(char_prop, wc.from_switchpoint_set);
195+
}
179196

180197
// get the destination wire point
181-
char_prop = get_attribute(node, "to_switchpoint", loc_data).value();
182-
parse_comma_separated_wire_points(char_prop, wc.to_switchpoint_set);
198+
char_prop = get_attribute(node, "to_switchpoint", loc_data, from_to_required).value();
199+
if (!can_skip_from_or_to) {
200+
parse_comma_separated_wire_points(char_prop, wc.to_switchpoint_set);
201+
}
183202

184203
char_prop = get_attribute(node, "from_order", loc_data, ReqOpt::OPTIONAL).value();
185204
parse_switchpoint_order(char_prop, wc.from_switchpoint_order);
@@ -315,66 +334,31 @@ static void parse_num_conns(std::string num_conns, t_wireconn_inf& wireconn) {
315334

316335
//set sides for a specific conn for custom switch block pattern
317336
static void set_switch_func_type(SBSideConnection& conn, const char* func_type) {
318-
if (0 == strcmp(func_type, "lt")) {
319-
conn.set_sides(LEFT, TOP);
320-
} else if (0 == strcmp(func_type, "lr")) {
321-
conn.set_sides(LEFT, RIGHT);
322-
} else if (0 == strcmp(func_type, "lb")) {
323-
conn.set_sides(LEFT, BOTTOM);
324-
} else if (0 == strcmp(func_type, "la")) {
325-
conn.set_sides(LEFT, ABOVE);
326-
} else if (0 == strcmp(func_type, "lu")) {
327-
conn.set_sides(LEFT, UNDER);
328-
} else if (0 == strcmp(func_type, "tl")) {
329-
conn.set_sides(TOP, LEFT);
330-
} else if (0 == strcmp(func_type, "tb")) {
331-
conn.set_sides(TOP, BOTTOM);
332-
} else if (0 == strcmp(func_type, "tr")) {
333-
conn.set_sides(TOP, RIGHT);
334-
} else if (0 == strcmp(func_type, "ta")) {
335-
conn.set_sides(TOP, ABOVE);
336-
} else if (0 == strcmp(func_type, "tu")) {
337-
conn.set_sides(TOP, UNDER);
338-
} else if (0 == strcmp(func_type, "rt")) {
339-
conn.set_sides(RIGHT, TOP);
340-
} else if (0 == strcmp(func_type, "rl")) {
341-
conn.set_sides(RIGHT, LEFT);
342-
} else if (0 == strcmp(func_type, "rb")) {
343-
conn.set_sides(RIGHT, BOTTOM);
344-
} else if (0 == strcmp(func_type, "ra")) {
345-
conn.set_sides(RIGHT, ABOVE);
346-
} else if (0 == strcmp(func_type, "ru")) {
347-
conn.set_sides(RIGHT, UNDER);
348-
} else if (0 == strcmp(func_type, "bl")) {
349-
conn.set_sides(BOTTOM, LEFT);
350-
} else if (0 == strcmp(func_type, "bt")) {
351-
conn.set_sides(BOTTOM, TOP);
352-
} else if (0 == strcmp(func_type, "br")) {
353-
conn.set_sides(BOTTOM, RIGHT);
354-
} else if (0 == strcmp(func_type, "ba")) {
355-
conn.set_sides(BOTTOM, ABOVE);
356-
} else if (0 == strcmp(func_type, "bu")) {
357-
conn.set_sides(BOTTOM, UNDER);
358-
} else if (0 == strcmp(func_type, "al")) {
359-
conn.set_sides(ABOVE, LEFT);
360-
} else if (0 == strcmp(func_type, "at")) {
361-
conn.set_sides(ABOVE, TOP);
362-
} else if (0 == strcmp(func_type, "ar")) {
363-
conn.set_sides(ABOVE, RIGHT);
364-
} else if (0 == strcmp(func_type, "ab")) {
365-
conn.set_sides(ABOVE, BOTTOM);
366-
} else if (0 == strcmp(func_type, "ul")) {
367-
conn.set_sides(UNDER, LEFT);
368-
} else if (0 == strcmp(func_type, "ut")) {
369-
conn.set_sides(UNDER, TOP);
370-
} else if (0 == strcmp(func_type, "ur")) {
371-
conn.set_sides(UNDER, RIGHT);
372-
} else if (0 == strcmp(func_type, "ub")) {
373-
conn.set_sides(UNDER, BOTTOM);
374-
} else {
375-
/* unknown permutation function */
376-
archfpga_throw(__FILE__, __LINE__, "Unknown permutation function specified: %s\n", func_type);
337+
338+
if (std::string(func_type).length() != 2) {
339+
archfpga_throw(__FILE__, __LINE__, "Custom switchblock func type must be 2 characters long: %s\n", func_type);
340+
}
341+
342+
// Only valid sides are right, top, left, bottom, above and under
343+
if (std::string(func_type).find_first_not_of("rtlbauRTLBAU") != std::string::npos) {
344+
archfpga_throw(__FILE__, __LINE__, "Unknown direction specified: %s\n", func_type);
345+
}
346+
347+
e_side from_side = CHAR_SIDE_MAP.at(func_type[0]);
348+
e_side to_side = CHAR_SIDE_MAP.at(func_type[1]);
349+
350+
// Can't go from side to same side
351+
if (to_side == from_side) {
352+
archfpga_throw(__FILE__, __LINE__, "Unknown permutation function specified, cannot go from side to same side: %s\n", func_type);
377353
}
354+
355+
// We don't allow specification of patterns that imply edges going over 2 or more layers
356+
// (this doesn't seem electrically logical), so we disallow going from above/under to above/under.
357+
if ((to_side == ABOVE || to_side == UNDER) && (from_side == ABOVE || from_side == UNDER)) {
358+
archfpga_throw(__FILE__, __LINE__, "Unknown permutation function specified, cannot go from above/under to above/under: %s\n", func_type);
359+
}
360+
361+
conn.set_sides(from_side, to_side);
378362
}
379363

380364
void read_sb_switchfuncs(pugi::xml_node node, t_switchblock_inf& sb, const pugiutil::loc_data& loc_data) {

0 commit comments

Comments
 (0)