Skip to content

Addition of switch_override feature to custom SB #2067

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Sep 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion doc/src/arch/reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2301,7 +2301,7 @@ The full format is documented below.
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.


.. 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}"/>
.. 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"/>

:req_param num_conns:
Specifies how many connections should be created between the from_type/from_switchpoint set and the to_type/to_switchpoint set.
Expand Down Expand Up @@ -2401,6 +2401,14 @@ The full format is documented below.

.. note:: See ``from_switchpoint_order`` for value descritpions.

:opt_param switch_override:

Specifies the name of a switch to be used to override the wire_switch of the segments in the ``to`` set.
Can be used to create switch patterns where different switches are used for different types of connections.
By using a zero-delay and zero-resistance switch one can also create T and L shaped wire segments.

**Default:** If no override is specified, the usual wire_switch that drives the ``to`` wire will be used.

.. arch:tag:: <from type="string" switchpoint="int, int, int, ..."/>

:req_param type:
Expand Down
50 changes: 39 additions & 11 deletions libs/libarchfpga/src/parse_switchblocks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,16 @@ using vtr::t_formula_data;
/*---- Functions for Parsing Switchblocks from Architecture ----*/

//Load an XML wireconn specification into a t_wireconn_inf
t_wireconn_inf parse_wireconn(pugi::xml_node node, const pugiutil::loc_data& loc_data);
t_wireconn_inf parse_wireconn(pugi::xml_node node, const pugiutil::loc_data& loc_data, const t_arch_switch_inf* switches, int num_switches);

//Process the desired order of a wireconn
static void parse_switchpoint_order(const char* order, SwitchPointOrder& switchpoint_order);

//Process a wireconn defined in the inline style (using attributes)
void parse_wireconn_inline(pugi::xml_node node, const pugiutil::loc_data& loc_data, t_wireconn_inf& wc);
void parse_wireconn_inline(pugi::xml_node node, const pugiutil::loc_data& loc_data, t_wireconn_inf& wc, const t_arch_switch_inf* switches, int num_switches);

//Process a wireconn defined in the multinode style (more advanced specification)
void parse_wireconn_multinode(pugi::xml_node node, const pugiutil::loc_data& loc_data, t_wireconn_inf& wc);
void parse_wireconn_multinode(pugi::xml_node node, const pugiutil::loc_data& loc_data, t_wireconn_inf& wc, const t_arch_switch_inf* switches, int num_switches);

//Process a <from> or <to> sub-node of a multinode wireconn
t_wire_switchpoints parse_wireconn_from_to_node(pugi::xml_node node, const pugiutil::loc_data& loc_data);
Expand All @@ -65,6 +65,9 @@ static void parse_comma_separated_wire_points(const char* ch, std::vector<t_wire
/* Parses the number of connections type */
static void parse_num_conns(std::string num_conns, t_wireconn_inf& wireconn);

/* parse switch_override in wireconn */
static void parse_switch_override(const char* switch_override, t_wireconn_inf& wireconn, const t_arch_switch_inf* switches, int num_switches);

/* checks for correctness of a unidir switchblock. */
static void check_unidir_switchblock(const t_switchblock_inf* sb);

Expand All @@ -79,7 +82,7 @@ static void check_wireconn(const t_arch* arch, const t_wireconn_inf& wireconn);
/*---- Functions for Parsing Switchblocks from Architecture ----*/

/* Reads-in the wire connections specified for the switchblock in the xml arch file */
void read_sb_wireconns(const t_arch_switch_inf* /*switches*/, int /*num_switches*/, pugi::xml_node Node, t_switchblock_inf* sb, const pugiutil::loc_data& loc_data) {
void read_sb_wireconns(const t_arch_switch_inf* switches, int num_switches, pugi::xml_node Node, t_switchblock_inf* sb, const pugiutil::loc_data& loc_data) {
/* Make sure that Node is a switchblock */
check_node(Node, "switchblock", loc_data);

Expand All @@ -94,33 +97,33 @@ void read_sb_wireconns(const t_arch_switch_inf* /*switches*/, int /*num_switches
SubElem = get_first_child(Node, "wireconn", loc_data);
}
for (int i = 0; i < num_wireconns; i++) {
t_wireconn_inf wc = parse_wireconn(SubElem, loc_data);
t_wireconn_inf wc = parse_wireconn(SubElem, loc_data, switches, num_switches); // need to pass in switch info for switch override
sb->wireconns.push_back(wc);
SubElem = SubElem.next_sibling(SubElem.name());
}

return;
}

t_wireconn_inf parse_wireconn(pugi::xml_node node, const pugiutil::loc_data& loc_data) {
t_wireconn_inf parse_wireconn(pugi::xml_node node, const pugiutil::loc_data& loc_data, const t_arch_switch_inf* switches, int num_switches) {
t_wireconn_inf wc;

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

if (num_children == 0) {
parse_wireconn_inline(node, loc_data, wc);
parse_wireconn_inline(node, loc_data, wc, switches, num_switches);
} else {
VTR_ASSERT(num_children > 0);
parse_wireconn_multinode(node, loc_data, wc);
parse_wireconn_multinode(node, loc_data, wc, switches, num_switches);
}

return wc;
}

void parse_wireconn_inline(pugi::xml_node node, const pugiutil::loc_data& loc_data, t_wireconn_inf& wc) {
void parse_wireconn_inline(pugi::xml_node node, const pugiutil::loc_data& loc_data, t_wireconn_inf& wc, const t_arch_switch_inf* switches, int num_switches) {
//Parse an inline wireconn definition, using attributes
expect_only_attributes(node, {"num_conns", "from_type", "to_type", "from_switchpoint", "to_switchpoint", "from_order", "to_order"}, loc_data);
expect_only_attributes(node, {"num_conns", "from_type", "to_type", "from_switchpoint", "to_switchpoint", "from_order", "to_order", "switch_override"}, loc_data);

/* get the connection style */
const char* char_prop = get_attribute(node, "num_conns", loc_data).value();
Expand All @@ -147,9 +150,13 @@ void parse_wireconn_inline(pugi::xml_node node, const pugiutil::loc_data& loc_da

char_prop = get_attribute(node, "to_order", loc_data, ReqOpt::OPTIONAL).value();
parse_switchpoint_order(char_prop, wc.to_switchpoint_order);

// parse switch overrides if they exist:
char_prop = get_attribute(node, "switch_override", loc_data, ReqOpt::OPTIONAL).value();
parse_switch_override(char_prop, wc, switches, num_switches);
}

void parse_wireconn_multinode(pugi::xml_node node, const pugiutil::loc_data& loc_data, t_wireconn_inf& wc) {
void parse_wireconn_multinode(pugi::xml_node node, const pugiutil::loc_data& loc_data, t_wireconn_inf& wc, const t_arch_switch_inf* switches, int num_switches) {
expect_only_children(node, {"from", "to"}, loc_data);

/* get the connection style */
Expand All @@ -162,6 +169,9 @@ void parse_wireconn_multinode(pugi::xml_node node, const pugiutil::loc_data& loc
char_prop = get_attribute(node, "to_order", loc_data, ReqOpt::OPTIONAL).value();
parse_switchpoint_order(char_prop, wc.to_switchpoint_order);

char_prop = get_attribute(node, "switch_override", loc_data, ReqOpt::OPTIONAL).value();
parse_switch_override(char_prop, wc, switches, num_switches);

size_t num_from_children = count_children(node, "from", loc_data);
size_t num_to_children = count_children(node, "to", loc_data);

Expand Down Expand Up @@ -331,6 +341,24 @@ void read_sb_switchfuncs(pugi::xml_node Node, t_switchblock_inf* sb, const pugiu
return;
}

static void parse_switch_override(const char* switch_override, t_wireconn_inf& wireconn, const t_arch_switch_inf* switches, int num_switches) {
// sentinel value to use default driving switch for the receiving wire type
if (switch_override == std::string("")) {
wireconn.switch_override_indx = DEFAULT_SWITCH; //Default
return;
}

// iterate through the valid switch names in the arch looking for the requested switch_override
for (int i = 0; i < num_switches; i++) {
if (0 == strcmp(switch_override, switches[i].name)) {
wireconn.switch_override_indx = i;
return;
}
}
// if we haven't found a switch that matched, then throw an error
archfpga_throw(__FILE__, __LINE__, "Unknown switch_override specified in wireconn of custom switch blocks: \"%s\"\n", switch_override);
}

/* checks for correctness of switch block read-in from the XML architecture file */
void check_switchblock(const t_switchblock_inf* sb, const t_arch* arch) {
/* get directionality */
Expand Down
2 changes: 2 additions & 0 deletions libs/libarchfpga/src/physical_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -1688,6 +1688,8 @@ struct t_wireconn_inf {
std::vector<t_wire_switchpoints> to_switchpoint_set; //The set of segment/wirepoints representing the 'to' set (union of all t_wire_switchpoints in vector)
SwitchPointOrder from_switchpoint_order = SwitchPointOrder::FIXED; //The desired from_switchpoint_set ordering
SwitchPointOrder to_switchpoint_order = SwitchPointOrder::FIXED; //The desired to_switchpoint_set ordering
int switch_override_indx = DEFAULT_SWITCH; // index in switch array of the switch used to override wire_switch of the 'to' set.
// DEFAULT_SWITCH is a sentinel value (i.e. the usual driving switch from a wire for the receiving wire will be used)

std::string num_conns_formula; /* Specifies how many connections should be made for this wireconn.
*
Expand Down
8 changes: 7 additions & 1 deletion vpr/src/route/build_switchblocks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -983,7 +983,13 @@ static void compute_wireconn_connections(
t_switchblock_edge sb_edge;
sb_edge.from_wire = from_wire;
sb_edge.to_wire = to_wire;
sb_edge.switch_ind = to_chan_details[to_x][to_y][to_wire].arch_wire_switch();

// if the switch override has been set, use that. Otherwise use default
if (wireconn_ptr->switch_override_indx != DEFAULT_SWITCH) {
sb_edge.switch_ind = wireconn_ptr->switch_override_indx;
} else {
sb_edge.switch_ind = to_chan_details[to_x][to_y][to_wire].arch_wire_switch();
}
VTR_LOGV(verbose, " make_conn: %d -> %d switch=%d\n", sb_edge.from_wire, sb_edge.to_wire, sb_edge.switch_ind);

/* and now, finally, add this switchblock connection to the switchblock connections map */
Expand Down
Loading