Skip to content

Deploy RRGraphBuilder in place of rr_node_indices in routing resource graph builder functions #1747

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 8 commits into from
Jun 1, 2021
32 changes: 25 additions & 7 deletions vpr/src/device/rr_spatial_lookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,33 @@ void RRSpatialLookup::add_node(RRNodeId node,
t_rr_type type,
int ptc,
e_side side) {
VTR_ASSERT(node); /* Must have a valid node id to be added */
VTR_ASSERT_SAFE(3 == rr_node_indices_[type].ndims());

resize_nodes(x, y, type, side);

if (size_t(ptc) >= rr_node_indices_[type][x][y][side].size()) {
/* Deposit invalid ids to newly allocated elements while original elements are untouched */
rr_node_indices_[type][x][y][side].resize(ptc + 1, int(size_t(RRNodeId::INVALID())));
}

/* Resize on demand finished; Register the node */
rr_node_indices_[type][x][y][side][ptc] = int(size_t(node));
}

void RRSpatialLookup::mirror_nodes(const vtr::Point<int>& src_coord,
const vtr::Point<int>& des_coord,
t_rr_type type,
e_side side) {
VTR_ASSERT(SOURCE == type || SINK == type);
resize_nodes(des_coord.x(), des_coord.y(), type, side);
rr_node_indices_[type][des_coord.x()][des_coord.y()][side] = rr_node_indices_[type][src_coord.x()][src_coord.y()][side];
}

void RRSpatialLookup::resize_nodes(int x,
int y,
t_rr_type type,
e_side side) {
/* Expand the fast look-up if the new node is out-of-range
* This may seldom happen because the rr_graph building function
* should ensure the fast look-up well organized
Expand All @@ -97,11 +122,4 @@ void RRSpatialLookup::add_node(RRNodeId node,
std::max(rr_node_indices_[type].dim_size(1), size_t(y) + 1),
std::max(rr_node_indices_[type].dim_size(2), size_t(side) + 1)});
}

if (size_t(ptc) >= rr_node_indices_[type][x][y][side].size()) {
rr_node_indices_[type][x][y][side].resize(ptc + 1);
}

/* Resize on demand finished; Register the node */
rr_node_indices_[type][x][y][side][ptc] = int(size_t(node));
}
55 changes: 52 additions & 3 deletions vpr/src/device/rr_spatial_lookup.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef RR_SPATIAL_LOOKUP_H
#define RR_SPATIAL_LOOKUP_H

#include "vtr_geometry.h"
#include "vpr_types.h"

/********************************************************************
Expand Down Expand Up @@ -29,7 +30,8 @@ class RRSpatialLookup {

/* -- Accessors -- */
public:
/* Returns the index of the specified routing resource node.
/**
* Returns the index of the specified routing resource node.
* - (x, y) are the grid location within the FPGA
* - rr_type specifies the type of resource,
* - ptc gives a unique number of resources of that type (e.g. CHANX) at that (x,y).
Expand Down Expand Up @@ -63,7 +65,8 @@ class RRSpatialLookup {

/* -- Mutators -- */
public:
/* Register a node in the fast look-up
/**
* Register a node in the fast look-up
* - You must have a valid node id to register the node in the lookup
* - (x, y) are the coordinate of the node to be indexable in the fast look-up
* - type is the type of a node
Expand All @@ -89,7 +92,53 @@ class RRSpatialLookup {
int ptc,
e_side side);

/* TODO: Add an API remove_node() to unregister a node from the look-up */
/**
* Mirror the last dimension of a look-up, i.e., a list of nodes, from a source coordinate to
* a destination coordinate.
* This function is mostly need by SOURCE and SINK nodes which are indexable in multiple locations.
* Considering a bounding box (x, y)->(x + width, y + height) of a multi-height and multi-width grid,
* SOURCE and SINK nodes are indexable in any location inside the boundry.
*
* An example of usage:
*
* // Create a empty lookup
* RRSpatialLookup rr_lookup;
* // Adding other nodes ...
* // Copy the nodes whose types are SOURCE at (1, 1) to (1, 2)
* rr_lookup.mirror_nodes(vtr::Point<int>(1, 1),
* vtr::Point<int>(1, 2),
* SOURCE,
* TOP);
*
* Note: currently this function only accepts SOURCE/SINK nodes. May unlock for the other types
* depending on needs
*
* TODO: Consider to make a high-level API to duplicate the nodes for large blocks.
* Then this API can become a private one
* For example,
* expand_nodes(source_coordinate, bounding_box_coordinate, type, side);
* Alternatively, we can rework the ``find_node()`` API so that we always search the lowest (x,y)
* corner when dealing with large blocks. But this may require the data structure to be dependent
* on DeviceGrid information (it needs to identify if a grid has height > 1 as well as width > 1)
*/
void mirror_nodes(const vtr::Point<int>& src_coord,
const vtr::Point<int>& des_coord,
t_rr_type type,
e_side side);

/**
* Resize the given 3 dimensions (x, y, side) of the RRSpatialLookup data structure for the given type
* This function will keep any existing data
*
* Strongly recommend to use when the sizes of dimensions are deterministic
*
* TODO: should have a reserve function but vtd::ndmatrix does not have such API
* as a result, resize can be an internal one while reserve function is a public mutator
*/
void resize_nodes(int x,
int y,
t_rr_type type,
e_side side);

/* -- Internal data storage -- */
private:
Expand Down
25 changes: 25 additions & 0 deletions vpr/src/route/rr_edge.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#ifndef RR_EDGE_H
#define RR_EDGE_H

struct t_rr_edge_info {
t_rr_edge_info(int from, int to, short type) noexcept
: from_node(from)
, to_node(to)
, switch_type(type) {}

int from_node = OPEN;
int to_node = OPEN;
short switch_type = OPEN;

friend bool operator<(const t_rr_edge_info& lhs, const t_rr_edge_info& rhs) {
return std::tie(lhs.from_node, lhs.to_node, lhs.switch_type) < std::tie(rhs.from_node, rhs.to_node, rhs.switch_type);
}

friend bool operator==(const t_rr_edge_info& lhs, const t_rr_edge_info& rhs) {
return std::tie(lhs.from_node, lhs.to_node, lhs.switch_type) == std::tie(rhs.from_node, rhs.to_node, rhs.switch_type);
}
};

typedef std::vector<t_rr_edge_info> t_rr_edge_info_set;

#endif /* RR_EDGE */
2 changes: 1 addition & 1 deletion vpr/src/route/rr_graph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,7 @@ static void build_rr_graph(const t_graph_type graph_type,
/* Alloc node lookups, count nodes, alloc rr nodes */
int num_rr_nodes = 0;

alloc_and_load_rr_node_indices(device_ctx.rr_node_indices,
alloc_and_load_rr_node_indices(device_ctx.rr_graph_builder,
max_chan_width, grid,
&num_rr_nodes, chan_details_x, chan_details_y);

Expand Down
91 changes: 32 additions & 59 deletions vpr/src/route/rr_graph2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,10 @@ static void load_chan_rr_indices(const int max_chan_width,
const int num_chans,
const t_rr_type type,
const t_chan_details& chan_details,
t_rr_node_indices& indices,
RRGraphBuilder& rr_graph_builder,
int* index);

static void load_block_rr_indices(RRGraphBuilder& rr_graph_builder,
t_rr_node_indices& indices,
const DeviceGrid& grid,
int* index);

Expand Down Expand Up @@ -928,44 +927,41 @@ static void load_chan_rr_indices(const int max_chan_width,
const int num_chans,
const t_rr_type type,
const t_chan_details& chan_details,
t_rr_node_indices& indices,
RRGraphBuilder& rr_graph_builder,
int* index) {
VTR_ASSERT(indices[type].dim_size(0) == size_t(num_chans));
VTR_ASSERT(indices[type].dim_size(1) == size_t(chan_len));
VTR_ASSERT(indices[type].dim_size(2) == NUM_SIDES);
for (int chan = 0; chan < num_chans - 1; ++chan) {
for (int seg = 1; seg < chan_len - 1; ++seg) {
/* Alloc the track inode lookup list */
//Since channels have no side, we just use the first side
indices[type][chan][seg][0].resize(max_chan_width, OPEN);
}
}

for (int chan = 0; chan < num_chans - 1; ++chan) {
for (int seg = 1; seg < chan_len - 1; ++seg) {
/* Assign an inode to the starts of tracks */
int x = (type == CHANX ? seg : chan);
int y = (type == CHANX ? chan : seg);
const t_chan_seg_details* seg_details = chan_details[x][y].data();

for (unsigned track = 0; track < indices[type][chan][seg][0].size(); ++track) {
for (int track = 0; track < max_chan_width; ++track) {
/* TODO: May let the length() == 0 case go through, to model muxes */
if (seg_details[track].length() <= 0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We likely should let the .length = 0 case go through eventually, to model muxes. Could comment that now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem. Added this as a TODO item. I will check details about the t_chan_details data structure and see what we can do.

continue;

int start = get_seg_start(seg_details, track, chan, seg);

/* TODO: Now we still use the (y, x) convention here for CHANX. Should rework later */
int node_x = chan;
int node_y = start;
if (CHANX == type) {
std::swap(node_x, node_y);
}

/* If the start of the wire doesn't have a inode,
* assign one to it. */
int inode = indices[type][chan][start][0][track];
if (OPEN == inode) {
inode = *index;
RRNodeId inode = rr_graph_builder.node_lookup().find_node(node_x, node_y, type, track, SIDES[0]);
if (!inode) {
inode = RRNodeId(*index);
++(*index);

indices[type][chan][start][0][track] = inode;
rr_graph_builder.node_lookup().add_node(inode, chan, start, type, track, SIDES[0]);
}

/* Assign inode of start of wire to current position */
indices[type][chan][seg][0][track] = inode;
rr_graph_builder.node_lookup().add_node(inode, chan, seg, type, track, SIDES[0]);
}
}
}
Expand All @@ -975,7 +971,6 @@ static void load_chan_rr_indices(const int max_chan_width,
* TODO: these building functions should only talk to a RRGraphBuilder object
*/
static void load_block_rr_indices(RRGraphBuilder& rr_graph_builder,
t_rr_node_indices& indices,
const DeviceGrid& grid,
int* index) {
//Walk through the grid assigning indices to SOURCE/SINK IPIN/OPIN
Expand All @@ -991,16 +986,12 @@ static void load_block_rr_indices(RRGraphBuilder& rr_graph_builder,
auto class_type = type->class_inf[iclass].type;
if (class_type == DRIVER) {
rr_graph_builder.node_lookup().add_node(RRNodeId(*index), x, y, SOURCE, iclass, SIDES[0]);
rr_graph_builder.node_lookup().add_node(RRNodeId::INVALID(), x, y, SINK, iclass, SIDES[0]);
} else {
VTR_ASSERT(class_type == RECEIVER);
rr_graph_builder.node_lookup().add_node(RRNodeId(*index), x, y, SINK, iclass, SIDES[0]);
rr_graph_builder.node_lookup().add_node(RRNodeId::INVALID(), x, y, SOURCE, iclass, SIDES[0]);
}
++(*index);
}
VTR_ASSERT(indices[SOURCE][x][y][0].size() == type->class_inf.size());
VTR_ASSERT(indices[SINK][x][y][0].size() == type->class_inf.size());

/* Limited sides for grids
* The wanted side depends on the location of the grid.
Expand Down Expand Up @@ -1068,18 +1059,13 @@ static void load_block_rr_indices(RRGraphBuilder& rr_graph_builder,
auto class_type = type->class_inf[iclass].type;

if (class_type == DRIVER) {
indices[OPIN][x_tile][y_tile][side].push_back(*index);
indices[IPIN][x_tile][y_tile][side].push_back(OPEN);
rr_graph_builder.node_lookup().add_node(RRNodeId(*index), x_tile, y_tile, OPIN, ipin, side);
assigned_to_rr_node = true;
} else {
VTR_ASSERT(class_type == RECEIVER);
indices[OPIN][x_tile][y_tile][side].push_back(OPEN);
indices[IPIN][x_tile][y_tile][side].push_back(*index);
rr_graph_builder.node_lookup().add_node(RRNodeId(*index), x_tile, y_tile, IPIN, ipin, side);
assigned_to_rr_node = true;
}
} else {
indices[IPIN][x_tile][y_tile][side].push_back(OPEN);
indices[OPIN][x_tile][y_tile][side].push_back(OPEN);
}
}
}
Expand All @@ -1099,25 +1085,6 @@ static void load_block_rr_indices(RRGraphBuilder& rr_graph_builder,
++(*index);
}
}

//Sanity check
for (int width_offset = 0; width_offset < type->width; ++width_offset) {
int x_tile = x + width_offset;
for (int height_offset = 0; height_offset < type->height; ++height_offset) {
int y_tile = y + height_offset;
for (e_side side : SIDES) {
//Note that the fast look-up stores all the indices for the pins on each side
//It has a fixed size (either 0 or the number of pins)
//Case 0 pins: the side is skipped as no pins are located on it
//Case number of pins: there are pins on this side
//and data query can be applied any pin id on this side
VTR_ASSERT((indices[IPIN][x_tile][y_tile][side].size() == size_t(type->num_pins))
|| (0 == indices[IPIN][x_tile][y_tile][side].size()));
VTR_ASSERT((indices[OPIN][x_tile][y_tile][side].size() == size_t(type->num_pins))
|| (0 == indices[OPIN][x_tile][y_tile][side].size()));
}
}
}
}
}
}
Expand All @@ -1132,8 +1099,14 @@ static void load_block_rr_indices(RRGraphBuilder& rr_graph_builder,
int root_x = x - width_offset;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could the whole double-for loop comtaining these calls be moved into RRGraphBuilder as a high-level API? Call it something like dupLargeBlkLookups(). Then mirror_nodes could be removed or made a (private if possible) helper function.

Right now the comment for mirror_node describes a good chunk of the body of this for loop, despite the for loop being in the caller. I think that's a sign we really want a higher-level API.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. This is what I thought:

  • We can create a high-level API like expand_nodes() which will copy the vector from a source coordinate to all the coordinates in a bounding box.

I will keep thinking about what high-level API we need. I am positive for moving the for-loops into API.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good. Let's land this and keep iterating on the higher-level api.

int root_y = y - height_offset;

indices[SOURCE][x][y][0] = indices[SOURCE][root_x][root_y][0];
indices[SINK][x][y][0] = indices[SINK][root_x][root_y][0];
rr_graph_builder.node_lookup().mirror_nodes(vtr::Point<int>(root_x, root_y),
vtr::Point<int>(x, y),
SOURCE,
SIDES[0]);
rr_graph_builder.node_lookup().mirror_nodes(vtr::Point<int>(root_x, root_y),
vtr::Point<int>(x, y),
SINK,
SIDES[0]);
}
}
}
Expand All @@ -1149,7 +1122,7 @@ static void load_block_rr_indices(RRGraphBuilder& rr_graph_builder,
* This will block us when putting the RRGraphBuilder object as an input arguement
* of this function
*/
void alloc_and_load_rr_node_indices(t_rr_node_indices& indices,
void alloc_and_load_rr_node_indices(RRGraphBuilder& rr_graph_builder,
const int max_chan_width,
const DeviceGrid& grid,
int* index,
Expand All @@ -1162,20 +1135,20 @@ void alloc_and_load_rr_node_indices(t_rr_node_indices& indices,
/* Alloc the lookup table */
for (t_rr_type rr_type : RR_TYPES) {
if (rr_type == CHANX) {
indices[rr_type].resize({grid.height(), grid.width(), NUM_SIDES});
rr_graph_builder.node_lookup().resize_nodes(grid.height(), grid.width(), rr_type, NUM_SIDES);
} else {
indices[rr_type].resize({grid.width(), grid.height(), NUM_SIDES});
rr_graph_builder.node_lookup().resize_nodes(grid.width(), grid.height(), rr_type, NUM_SIDES);
}
}

/* Assign indices for block nodes */
load_block_rr_indices(g_vpr_ctx.mutable_device().rr_graph_builder, indices, grid, index);
load_block_rr_indices(rr_graph_builder, grid, index);

/* Load the data for x and y channels */
load_chan_rr_indices(max_chan_width, grid.width(), grid.height(),
CHANX, chan_details_x, indices, index);
CHANX, chan_details_x, rr_graph_builder, index);
load_chan_rr_indices(max_chan_width, grid.height(), grid.width(),
CHANY, chan_details_y, indices, index);
CHANY, chan_details_y, rr_graph_builder, index);
}

bool verify_rr_node_indices(const DeviceGrid& grid, const t_rr_node_indices& rr_node_indices, const t_rr_graph_storage& rr_nodes) {
Expand Down
Loading