diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/device_coordinator.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/base/device_coordinator.cpp new file mode 100644 index 000000000..0bb8f66ed --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/device_coordinator.cpp @@ -0,0 +1,57 @@ +#include +#include "device_coordinator.h" + +/* Member functions for DeviceCoordinator */ +/* Public constructors */ +/* +DeviceCoordinator::DeviceCoordinator(DeviceCoordinator& coordinator) { + set(coordinator.get_x(), coordinator.get_y()); + return; +} +*/ + +DeviceCoordinator::DeviceCoordinator(size_t x, size_t y) { + set(x, y); + return; +} + +DeviceCoordinator::DeviceCoordinator() { + set(0, 0); + return; +} + +/* Public accessors */ +size_t DeviceCoordinator::get_x() const { + return x_; +} + +size_t DeviceCoordinator::get_y() const { + return y_; +} + +/* Public mutators */ +void DeviceCoordinator::set(size_t x, size_t y) { + set_x(x); + set_y(y); + return; +} + +void DeviceCoordinator::set_x(size_t x) { + x_ = x; + return; +} + +void DeviceCoordinator::set_y(size_t y) { + y_ = y; + return; +} + +void DeviceCoordinator::rotate() { + std::swap(x_, y_); + return; +} + +void DeviceCoordinator::clear() { + set(0, 0); + return; +} diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/device_coordinator.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/device_coordinator.h new file mode 100644 index 000000000..61cb3235d --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/device_coordinator.h @@ -0,0 +1,33 @@ +#ifndef DEVICE_COORDINATOR_H +#define DEVICE_COORDINATOR_H + +/* Coordinator System for FPGA Device + * It is based on a 3-D (x,y,z) coordinator system + * (x,y) is used for all the routing resources, + * z is used for only grid, which have multiple logic blocks + */ +class DeviceCoordinator { + public: /* Contructors */ + /* + DeviceCoordinator(DeviceCoordinator& coordinator); + */ + DeviceCoordinator(size_t x, size_t y); + DeviceCoordinator(); + public: /* Accessors */ + size_t get_x() const; + size_t get_y() const; + public: /* Mutators */ + void set(size_t x, size_t y); + void set_x(size_t x); + void set_y(size_t y); + void rotate(); + void clear(); + private: /* Internal Mutators */ + private: /* internal functions */ + private: /* Internal Data */ + size_t x_; + size_t y_; + size_t z_; +}; + +#endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_backannotate_utils.c b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_backannotate_utils.c index eb66b22d9..3aba9f5a1 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_backannotate_utils.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_backannotate_utils.c @@ -27,6 +27,7 @@ /* Include spice support headers*/ #include "read_xml_spice_util.h" #include "linkedlist.h" +#include "rr_blocks.h" #include "fpga_x2p_types.h" #include "fpga_x2p_globals.h" #include "fpga_x2p_utils.h" @@ -35,6 +36,7 @@ #include "fpga_x2p_pbtypes_utils.h" #include "fpga_x2p_pb_rr_graph.h" #include "fpga_x2p_router.h" +#include "fpga_x2p_unique_routing.h" /* Get initial value of a Latch/FF output*/ int get_ff_output_init_val(t_logical_block* ff_logical_block) { @@ -3127,6 +3129,7 @@ void spice_backannotate_vpr_post_route_info(t_det_routing_arch RoutingArch, /* Build Array for each Switch block and Connection block */ vpr_printf(TIO_MESSAGE_INFO, "Collecting detailed information for each Switch block...\n"); alloc_and_build_switch_blocks_info(RoutingArch, num_rr_nodes, rr_node, rr_node_indices); + device_rr_switch_block = build_device_rr_switch_blocks(RoutingArch, num_rr_nodes, rr_node, rr_node_indices); vpr_printf(TIO_MESSAGE_INFO, "Collecting detailed information for each to Connection block...\n"); alloc_and_build_connection_blocks_info(RoutingArch, num_rr_nodes, rr_node, rr_node_indices); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_globals.c b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_globals.c index b078609c0..cc73027d3 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_globals.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_globals.c @@ -46,3 +46,4 @@ char* fpga_spice_bitstream_routing_log_file_postfix = "_routing_bitstream.log"; char* default_sdc_folder = "SDC/"; DeviceRRChan device_rr_chan; +DeviceRRSwitchBlock device_rr_switch_block; diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_globals.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_globals.h index 2ef8e95f1..8f39a70e9 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_globals.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_globals.h @@ -41,5 +41,6 @@ extern char* fpga_spice_bitstream_logic_block_log_file_postfix; extern char* fpga_spice_bitstream_routing_log_file_postfix; extern DeviceRRChan device_rr_chan; +extern DeviceRRSwitchBlock device_rr_switch_block; #endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_unique_routing.c b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_unique_routing.c index c4da1741e..c7b195563 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_unique_routing.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_unique_routing.c @@ -80,6 +80,13 @@ RRChan build_one_rr_chan(t_rr_type chan_type, size_t chan_x, size_t chan_y, void print_device_rr_chan_stats(DeviceRRChan& device_rr_chan); +static +RRSwitchBlock build_rr_switch_block(int sb_x, int sb_y, + t_det_routing_arch RoutingArch, + int LL_num_rr_nodes, + t_rr_node* LL_rr_node, + t_ivec*** LL_rr_node_indices); + /***** subroutines *****/ void assign_switch_block_mirror(t_sb* src, t_sb* des) { assert ( (NULL != src) && (NULL != des) ); @@ -796,6 +803,288 @@ DeviceRRChan build_device_rr_chan(int LL_num_rr_nodes, t_rr_node* LL_rr_node, return LL_device_rr_chan; } +/* Build arrays for rr_nodes of each Switch Blocks + * A Switch Box subckt consists of following ports: + * 1. Channel Y [x][y] inputs + * 2. Channel X [x+1][y] inputs + * 3. Channel Y [x][y-1] outputs + * 4. Channel X [x][y] outputs + * 5. Grid[x][y+1] Right side outputs pins + * 6. Grid[x+1][y+1] Left side output pins + * 7. Grid[x+1][y+1] Bottom side output pins + * 8. Grid[x+1][y] Top side output pins + * 9. Grid[x+1][y] Left side output pins + * 10. Grid[x][y] Right side output pins + * 11. Grid[x][y] Top side output pins + * 12. Grid[x][y+1] Bottom side output pins + * + * -------------- -------------- + * | | | | + * | Grid | ChanY | Grid | + * | [x][y+1] | [x][y+1] | [x+1][y+1] | + * | | | | + * -------------- -------------- + * ---------- + * ChanX | Switch | ChanX + * [x][y] | Box | [x+1][y] + * | [x][y] | + * ---------- + * -------------- -------------- + * | | | | + * | Grid | ChanY | Grid | + * | [x][y] | [x][y] | [x+1][y] | + * | | | | + * -------------- -------------- + * For channels chanY with INC_DIRECTION on the top side, they should be marked as outputs + * For channels chanY with DEC_DIRECTION on the top side, they should be marked as inputs + * For channels chanY with INC_DIRECTION on the bottom side, they should be marked as inputs + * For channels chanY with DEC_DIRECTION on the bottom side, they should be marked as outputs + * For channels chanX with INC_DIRECTION on the left side, they should be marked as inputs + * For channels chanX with DEC_DIRECTION on the left side, they should be marked as outputs + * For channels chanX with INC_DIRECTION on the right side, they should be marked as outputs + * For channels chanX with DEC_DIRECTION on the right side, they should be marked as inputs + */ +static +RRSwitchBlock build_rr_switch_block(int sb_x, int sb_y, + t_det_routing_arch RoutingArch, + int LL_num_rr_nodes, + t_rr_node* LL_rr_node, + t_ivec*** LL_rr_node_indices) { + /* Create an object to return */ + RRSwitchBlock rr_switch_block; + + /* Check */ + assert((!(0 > sb_x))&&(!(sb_x > (nx + 1)))); + assert((!(0 > sb_y))&&(!(sb_y > (ny + 1)))); + + /* Basic information*/ + rr_switch_block.init_num_sides(4); /* Fixed number of sides */ + + /* Find all rr_nodes of channels */ + /* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */ + for (size_t side = 0; side < rr_switch_block.get_num_sides(); ++side) { + /* Local variables inside this for loop */ + Side side_manager(side); + int ix = 0; + int iy = 0; + int chan_width = 0; + t_rr_node** chan_rr_node = NULL; + int temp_num_opin_rr_nodes[2] = {0,0}; + t_rr_node** temp_opin_rr_node[2] = {NULL, NULL}; + enum e_side opin_grid_side[2] = {NUM_SIDES, NUM_SIDES}; + enum PORTS chan_dir_to_port_dir_mapping[2] = {OUT_PORT, IN_PORT}; /* 0: INC_DIRECTION => ?; 1: DEC_DIRECTION => ? */ + switch (side) { + case 0: /* TOP */ + /* For the bording, we should take special care */ + if (sb_y == ny) { + rr_switch_block.clear_one_side(side_manager.get_side()); + break; + } + /* Routing channels*/ + ix = sb_x; + iy = sb_y + 1; + /* Channel width */ + chan_width = chan_width_y[ix]; + /* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */ + chan_rr_node = get_chan_rr_nodes(&chan_width, CHANY, ix, iy, + LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices); + chan_dir_to_port_dir_mapping[0] = OUT_PORT; + chan_dir_to_port_dir_mapping[1] = IN_PORT; + + /* Include Grid[x][y+1] RIGHT side outputs pins */ + temp_opin_rr_node[0] = get_grid_side_pin_rr_nodes(&temp_num_opin_rr_nodes[0], + OPIN, sb_x, sb_y + 1, 1, + LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices); + /* Include Grid[x+1][y+1] Left side output pins */ + temp_opin_rr_node[1] = get_grid_side_pin_rr_nodes(&temp_num_opin_rr_nodes[1], + OPIN, sb_x + 1, sb_y + 1, 3, + LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices); + + /* Assign grid side of OPIN */ + /* Grid[x][y+1] RIGHT side outputs pins */ + opin_grid_side[0] = RIGHT; + /* Grid[x+1][y+1] left side outputs pins */ + opin_grid_side[1] = LEFT; + break; + case 1: /* RIGHT */ + /* For the bording, we should take special care */ + if (sb_x == nx) { + rr_switch_block.clear_one_side(side_manager.get_side()); + break; + } + /* Routing channels*/ + ix = sb_x + 1; + iy = sb_y; + /* Channel width */ + chan_width = chan_width_x[iy]; + /* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */ + /* Collect rr_nodes for Tracks for top: chany[x][y+1] */ + chan_rr_node = get_chan_rr_nodes(&chan_width, CHANX, ix, iy, + LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices); + chan_dir_to_port_dir_mapping[0] = OUT_PORT; + chan_dir_to_port_dir_mapping[1] = IN_PORT; + + /* include Grid[x+1][y+1] Bottom side output pins */ + temp_opin_rr_node[0] = get_grid_side_pin_rr_nodes(&temp_num_opin_rr_nodes[0], + OPIN, sb_x + 1, sb_y + 1, 2, + LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices); + /* include Grid[x+1][y] Top side output pins */ + temp_opin_rr_node[1] = get_grid_side_pin_rr_nodes(&temp_num_opin_rr_nodes[1], + OPIN, sb_x + 1, sb_y, 0, + LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices); + /* Assign grid side of OPIN */ + /* Grid[x+1][y+1] BOTTOM side outputs pins */ + opin_grid_side[0] = BOTTOM; + /* Grid[x+1][y] TOP side outputs pins */ + opin_grid_side[1] = TOP; + break; + case 2: + /* For the bording, we should take special care */ + if (sb_y == 0) { + rr_switch_block.clear_one_side(side_manager.get_side()); + break; + } + /* Routing channels*/ + ix = sb_x; + iy = sb_y; + /* Channel width */ + chan_width = chan_width_y[ix]; + /* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */ + /* Collect rr_nodes for Tracks for bottom: chany[x][y] */ + chan_rr_node = get_chan_rr_nodes(&chan_width, CHANY, ix, iy, + LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices); + chan_dir_to_port_dir_mapping[0] = IN_PORT; + chan_dir_to_port_dir_mapping[1] = OUT_PORT; + + /* TODO: include Grid[x+1][y] Left side output pins */ + temp_opin_rr_node[0] = get_grid_side_pin_rr_nodes(&temp_num_opin_rr_nodes[0], + OPIN, sb_x + 1, sb_y, 3, + LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices); + /* TODO: include Grid[x][y] Right side output pins */ + temp_opin_rr_node[1] = get_grid_side_pin_rr_nodes(&temp_num_opin_rr_nodes[1], + OPIN, sb_x, sb_y, 1, + LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices); + /* Assign grid side of OPIN */ + /* Grid[x+1][y] LEFT side outputs pins */ + opin_grid_side[0] = LEFT; + /* Grid[x][y] RIGHT side outputs pins */ + opin_grid_side[1] = RIGHT; + break; + case 3: + /* For the bording, we should take special care */ + if (sb_x == 0) { + rr_switch_block.clear_one_side(side_manager.get_side()); + break; + } + /* Routing channels*/ + ix = sb_x; + iy = sb_y; + /* Channel width */ + chan_width = chan_width_x[iy]; + /* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */ + /* Collect rr_nodes for Tracks for left: chanx[x][y] */ + chan_rr_node = get_chan_rr_nodes(&chan_width, CHANX, ix, iy, + LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices); + chan_dir_to_port_dir_mapping[0] = IN_PORT; + chan_dir_to_port_dir_mapping[1] = OUT_PORT; + + /* include Grid[x][y+1] Bottom side outputs pins */ + temp_opin_rr_node[0] = get_grid_side_pin_rr_nodes(&temp_num_opin_rr_nodes[0], + OPIN, sb_x, sb_y + 1, 2, + LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices); + /* include Grid[x][y] Top side output pins */ + temp_opin_rr_node[1] = get_grid_side_pin_rr_nodes(&temp_num_opin_rr_nodes[1], + OPIN, sb_x, sb_y, 0, + LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices); + + /* Grid[x][y+1] BOTTOM side outputs pins */ + opin_grid_side[0] = BOTTOM; + /* Grid[x][y] TOP side outputs pins */ + opin_grid_side[0] = TOP; + break; + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d])Invalid side index!\n", + __FILE__, __LINE__); + exit(1); + } + + /* Fill chan_rr_nodes */ + for (int itrack = 0; itrack < chan_width; ++itrack) { + /* Identify the directionality, record it in rr_node_direction */ + if (INC_DIRECTION == chan_rr_node[itrack]->direction) { + rr_switch_block.add_chan_node(chan_rr_node[itrack], side_manager.get_side(), chan_dir_to_port_dir_mapping[0]); + } else { + assert (DEC_DIRECTION == chan_rr_node[itrack]->direction); + rr_switch_block.add_chan_node(chan_rr_node[itrack], side_manager.get_side(), chan_dir_to_port_dir_mapping[1]); + } + } + + /* Fill opin_rr_nodes */ + /* Copy from temp_opin_rr_node to opin_rr_node */ + for (int inode = 0; inode < temp_num_opin_rr_nodes[0]; ++inode) { + /* Grid[x+1][y+1] Bottom side outputs pins */ + rr_switch_block.add_opin_node(temp_opin_rr_node[0][inode], side_manager.get_side(), opin_grid_side[0]); + } + for (int inode = 0; inode < temp_num_opin_rr_nodes[1]; ++inode) { + /* Grid[x+1][y] TOP side outputs pins */ + rr_switch_block.add_opin_node(temp_opin_rr_node[1][inode], side_manager.get_side(), opin_grid_side[1]); + } + + /* Clean ipin_rr_nodes */ + /* We do not have any IPIN for a Switch Block */ + rr_switch_block.clear_ipin_nodes(side_manager.get_side()); + + /* Free */ + temp_num_opin_rr_nodes[0] = 0; + my_free(temp_opin_rr_node[0]); + temp_num_opin_rr_nodes[1] = 0; + my_free(temp_opin_rr_node[1]); + /* Set them to NULL, avoid double free errors */ + temp_opin_rr_node[0] = NULL; + temp_opin_rr_node[1] = NULL; + opin_grid_side[0] = NUM_SIDES; + opin_grid_side[1] = NUM_SIDES; + } + + return rr_switch_block; +} + + +/* Build a list of Switch blocks, each of which contains a collection of rr_nodes + * We will maintain a list of unique switch blocks, which will be outputted as a Verilog module + * Each switch block in the FPGA fabric will be an instance of these modules. + * We maintain a map from each instance to each module + */ +DeviceRRSwitchBlock build_device_rr_switch_blocks(t_det_routing_arch RoutingArch, + int LL_num_rr_nodes, + t_rr_node* LL_rr_node, + t_ivec*** LL_rr_node_indices) { + /* Create an object */ + DeviceRRSwitchBlock LL_device_rr_switch_block; + + /* Initialize */ + DeviceCoordinator device_coordinator(size_t(nx + 1), size_t(ny + 1)); + LL_device_rr_switch_block.reserve(device_coordinator); + + /* For each switch block, determine the size of array */ + for (int ix = 0; ix < (nx + 1); ++ix) { + for (int iy = 0; iy < (ny + 1); ++iy) { + RRSwitchBlock rr_switch_block = build_rr_switch_block(ix, iy, RoutingArch, + LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices); + DeviceCoordinator sb_coordinator(ix, iy); + LL_device_rr_switch_block.add_rr_switch_block(sb_coordinator, rr_switch_block); + } + } + + /* Report number of unique mirrors */ + vpr_printf(TIO_MESSAGE_INFO, + "Detect %d independent switch blocks from %d switch blocks.\n", + LL_device_rr_switch_block.get_num_unique_mirror(), (nx + 1) * (ny + 1) ); + + return LL_device_rr_switch_block; +} + /* Rotatable will be done in the next step void identify_rotatable_switch_blocks(); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_unique_routing.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_unique_routing.h index bb50cd25e..8a0b9ee88 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_unique_routing.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_unique_routing.h @@ -9,6 +9,16 @@ DeviceRRChan build_device_rr_chan(int LL_num_rr_nodes, t_rr_node* LL_rr_node, t_ivec*** LL_rr_node_indices, int num_segments, t_rr_indexed_data* LL_rr_indexed_data); +/* Build a list of Switch blocks, each of which contains a collection of rr_nodes + * We will maintain a list of unique switch blocks, which will be outputted as a Verilog module + * Each switch block in the FPGA fabric will be an instance of these modules. + * We maintain a map from each instance to each module + */ +DeviceRRSwitchBlock build_device_rr_switch_blocks(t_det_routing_arch RoutingArch, + int LL_num_rr_nodes, + t_rr_node* LL_rr_node, + t_ivec*** LL_rr_node_indices); + /* Rotatable will be done in the next step identify_rotatable_switch_blocks(); identify_rotatable_connection_blocks(); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.cpp index a6b902d9c..832d4caeb 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.cpp @@ -1,10 +1,11 @@ #include +#include #include "rr_blocks.h" /* Member Functions of Class RRChan */ -/* accessors */ +/* Accessors */ t_rr_type RRChan::get_type() const { return type_; } @@ -560,7 +561,133 @@ bool RRSwitchBlock::is_mirror(RRSwitchBlock& cand) const { return true; } -/* Internal functions */ +/* Public mutators */ +/* Allocate the vectors with the given number of sides */ +void RRSwitchBlock::init_num_sides(size_t num_sides) { + /* Initialize the vectors */ + chan_rr_node_direction_.resize(num_sides); + chan_rr_node_.resize(num_sides); + ipin_rr_node_.resize(num_sides); + ipin_rr_node_grid_side_.resize(num_sides); + opin_rr_node_.resize(num_sides); + opin_rr_node_grid_side_.resize(num_sides); + return; +} + +/* Add a node to the chan_rr_node_ list and also assign its direction in chan_rr_node_direction_ */ +void RRSwitchBlock::add_chan_node(t_rr_node* node, enum e_side node_side, enum PORTS node_direction) { + Side side_manager(node_side); + assert(validate_side(node_side)); + /* resize the array if needed, node is placed in the sequence of node->ptc_num */ + if (size_t(node->ptc_num + 1) > chan_rr_node_[side_manager.to_size_t()].size()) { + chan_rr_node_[side_manager.to_size_t()].resize(node->ptc_num + 1); /* resize to the maximum */ + chan_rr_node_direction_[side_manager.to_size_t()].resize(node->ptc_num + 1); /* resize to the maximum */ + } + /* fill the dedicated element in the vector */ + chan_rr_node_[side_manager.to_size_t()][node->ptc_num] = node; + chan_rr_node_direction_[side_manager.to_size_t()][node->ptc_num] = node_direction; + + return; +} + +/* Add a node to the chan_rr_node_ list and also assign its direction in chan_rr_node_direction_ */ +void RRSwitchBlock::add_ipin_node(t_rr_node* node, enum e_side node_side, enum e_side grid_side) { + Side side_manager(node_side); + assert(validate_side(node_side)); + /* push pack the dedicated element in the vector */ + ipin_rr_node_[side_manager.to_size_t()].push_back(node); + ipin_rr_node_grid_side_[side_manager.to_size_t()].push_back(grid_side); + + return; +} + +/* Add a node to the chan_rr_node_ list and also assign its direction in chan_rr_node_direction_ */ +void RRSwitchBlock::add_opin_node(t_rr_node* node, enum e_side node_side, enum e_side grid_side) { + Side side_manager(node_side); + assert(validate_side(node_side)); + /* push pack the dedicated element in the vector */ + opin_rr_node_[side_manager.to_size_t()].push_back(node); + opin_rr_node_grid_side_[side_manager.to_size_t()].push_back(grid_side); + + return; +} + +void RRSwitchBlock::set_num_reserved_conf_bits(size_t num_reserved_conf_bits) { + num_reserved_conf_bits_ = num_reserved_conf_bits; + return; +} + +void RRSwitchBlock::set_num_conf_bits(size_t num_conf_bits) { + num_conf_bits_ = num_conf_bits; + return; +} + +void RRSwitchBlock::clear() { + /* Clean all the vectors */ + assert(validate_num_sides()); + /* Clear the inner vector of each matrix */ + for (size_t side = 0; side < get_num_sides(); ++side) { + chan_rr_node_direction_[side].clear(); + chan_rr_node_[side].clear(); + ipin_rr_node_[side].clear(); + ipin_rr_node_grid_side_[side].clear(); + opin_rr_node_[side].clear(); + opin_rr_node_grid_side_[side].clear(); + } + chan_rr_node_direction_.clear(); + chan_rr_node_.clear(); + ipin_rr_node_.clear(); + ipin_rr_node_grid_side_.clear(); + opin_rr_node_.clear(); + opin_rr_node_grid_side_.clear(); + + set_num_reserved_conf_bits(0); + set_num_conf_bits(0); + + return; +} + +/* Clean the chan_width of a side */ +void RRSwitchBlock::clear_chan_nodes(enum e_side node_side) { + Side side_manager(node_side); + assert(validate_side(node_side)); + + chan_rr_node_[side_manager.to_size_t()].clear(); + chan_rr_node_direction_[side_manager.to_size_t()].clear(); + return; +} + +/* Clean the number of IPINs of a side */ +void RRSwitchBlock::clear_ipin_nodes(enum e_side node_side) { + Side side_manager(node_side); + assert(validate_side(node_side)); + + ipin_rr_node_[side_manager.to_size_t()].clear(); + ipin_rr_node_grid_side_[side_manager.to_size_t()].clear(); + return; +} + +/* Clean the number of OPINs of a side */ +void RRSwitchBlock::clear_opin_nodes(enum e_side node_side) { + Side side_manager(node_side); + assert(validate_side(node_side)); + + opin_rr_node_[side_manager.to_size_t()].clear(); + opin_rr_node_grid_side_[side_manager.to_size_t()].clear(); + return; +} + +/* Clean chan/opin/ipin nodes at one side */ +void RRSwitchBlock::clear_one_side(enum e_side node_side) { + clear_chan_nodes(node_side); + clear_ipin_nodes(node_side); + clear_opin_nodes(node_side); + + return; +} + + +/* Internal functions for validation */ /* check if two rr_nodes have a similar set of drive_rr_nodes * for each drive_rr_node: @@ -665,3 +792,151 @@ bool RRSwitchBlock::validate_track_id(enum e_side side, size_t track_id) const { return false; } + +/* Member Functions of Class RRChan */ +/* Accessors */ + +/* get the max coordinator of the switch block array */ +DeviceCoordinator DeviceRRSwitchBlock::get_switch_block_range() const { + size_t max_y = 0; + /* Get the largest size of sub-arrays */ + for (size_t x = 0; x < rr_switch_block_.size(); ++x) { + max_y = std::max(max_y, rr_switch_block_[x].size()); + } + + DeviceCoordinator coordinator(rr_switch_block_.size(), max_y); + return coordinator; +} + +/* Get a rr switch block in the array with a coordinator */ +RRSwitchBlock DeviceRRSwitchBlock::get_switch_block(DeviceCoordinator coordinator) const { + assert(validate_coordinator(coordinator)); + return rr_switch_block_[coordinator.get_x()][coordinator.get_y()]; +} + +/* Get a rr switch block in the array with a coordinator */ +RRSwitchBlock DeviceRRSwitchBlock::get_switch_block(size_t x, size_t y) const { + DeviceCoordinator coordinator(x, y); + return get_switch_block(coordinator); +} + +/* get the number of unique mirrors of switch blocks */ +size_t DeviceRRSwitchBlock::get_num_unique_mirror() const { + return unique_mirror_.size(); +} + +/* get the number of rotatable mirrors of switch blocks */ +size_t DeviceRRSwitchBlock::get_num_rotatable_mirror() const { + return rotatable_mirror_.size(); +} + +/* Get a rr switch block which a unique mirror */ +RRSwitchBlock DeviceRRSwitchBlock::get_unique_mirror(size_t index) const { + assert (validate_unique_mirror_index(index)); + + return rr_switch_block_[unique_mirror_[index].get_x()][unique_mirror_[index].get_y()]; +} + +/* Get a rr switch block which a unique mirror */ +RRSwitchBlock DeviceRRSwitchBlock::get_rotatable_mirror(size_t index) const { + assert (validate_rotatable_mirror_index(index)); + + return rr_switch_block_[rotatable_mirror_[index].get_x()][rotatable_mirror_[index].get_y()]; +} + +/* Public Mutators */ + +/* Pre-allocate the rr_switch_block array that the device requires */ +void DeviceRRSwitchBlock::reserve(DeviceCoordinator& coordinator) { + rr_switch_block_.reserve(coordinator.get_x()); + for (size_t x = 0; x < coordinator.get_x(); ++x) { + rr_switch_block_[x].reserve(coordinator.get_y()); + } + return; +} + +/* Resize rr_switch_block array is needed*/ +void DeviceRRSwitchBlock::resize_upon_need(DeviceCoordinator& coordinator) { + if (coordinator.get_x() + 1 > rr_switch_block_.capacity()) { + rr_switch_block_.resize(coordinator.get_x()); + } + + if (coordinator.get_y() + 1 > rr_switch_block_[coordinator.get_x()].capacity()) { + rr_switch_block_[coordinator.get_x()].resize(coordinator.get_y()); + } + + return; +} + +/* Add a switch block to the array, which will automatically identify and update the lists of unique mirrors and rotatable mirrors */ +void DeviceRRSwitchBlock::add_rr_switch_block(DeviceCoordinator& coordinator, + RRSwitchBlock& rr_switch_block) { + bool is_unique_mirror = true; + + /* Resize upon needs*/ + resize_upon_need(coordinator); + + /* Add the switch block into array */ + rr_switch_block_[coordinator.get_x()][coordinator.get_y()] = rr_switch_block; + + /* Traverse the unique_mirror list and check it is an mirror of another */ + for (size_t mirror_id = 0; mirror_id < get_num_unique_mirror(); ++mirror_id) { + if (true == get_switch_block(unique_mirror_[mirror_id]).is_mirror(rr_switch_block)) { + /* This is a mirror, raise the flag and we finish */ + is_unique_mirror = false; + break; + } + } + /* Add to list if this is a unique mirror*/ + if (true == is_unique_mirror) { + unique_mirror_.push_back(coordinator); + } + + /* TODO: add rotatable mirror support */ + + return; +} + +/* clean the content */ +void DeviceRRSwitchBlock::clear() { + /* clean rr_switch_block array */ + for (size_t x = 0; x < rr_switch_block_.size(); ++x) { + rr_switch_block_[x].clear(); + } + rr_switch_block_.clear(); + + /* clean unique mirror */ + unique_mirror_.clear(); + + /* clean unique mirror */ + rotatable_mirror_.clear(); + + return; +} + +/* Validate if the (x,y) is the range of this device */ +bool DeviceRRSwitchBlock::validate_coordinator(DeviceCoordinator& coordinator) const { + if (coordinator.get_x() >= rr_switch_block_.capacity()) { + return false; + } + if (coordinator.get_y() >= rr_switch_block_[coordinator.get_x()].capacity()) { + return false; + } + return true; +} + +/* Validate if the index in the range of unique_mirror vector*/ +bool DeviceRRSwitchBlock::validate_unique_mirror_index(size_t index) const { + if (index >= unique_mirror_.size()) { + return false; + } + return true; +} + +/* Validate if the index in the range of unique_mirror vector*/ +bool DeviceRRSwitchBlock::validate_rotatable_mirror_index(size_t index) const { + if (index >= rotatable_mirror_.size()) { + return false; + } + return true; +} diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.h index d5a39568e..bfb6b3c8c 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.h @@ -14,6 +14,7 @@ /* Standard header files required go first */ #include +#include "device_coordinator.h" #include "vpr_types.h" /* RRChan coordinator class */ @@ -134,6 +135,18 @@ class RRSwitchBlock { bool is_node_imply_short_connection(t_rr_node* src_node) const; /* Check if the node imply a short connection inside the SB, which happens to long wires across a FPGA fabric */ bool is_mirror(RRSwitchBlock& cand) const; /* check if the candidate SB is a mirror of the current one */ public: /* Mutators */ + void init_num_sides(size_t num_sides); /* Allocate the vectors with the given number of sides */ + void add_chan_node(t_rr_node* node, enum e_side node_side, enum PORTS node_direction); /* Add a node to the chan_rr_node_ list and also assign its direction in chan_rr_node_direction_ */ + void add_ipin_node(t_rr_node* node, enum e_side node_side, enum e_side grid_side); /* Add a node to the chan_rr_node_ list and also assign its direction in chan_rr_node_direction_ */ + void add_opin_node(t_rr_node* node, enum e_side node_side, enum e_side grid_side); /* Add a node to the chan_rr_node_ list and also assign its direction in chan_rr_node_direction_ */ + void set_num_reserved_conf_bits(size_t num_reserved_conf_bits); + void set_num_conf_bits(size_t num_conf_bits); + void clear(); + void clear_chan_nodes(enum e_side node_side); /* Clean the chan_width of a side */ + void clear_ipin_nodes(enum e_side node_side); /* Clean the number of IPINs of a side */ + void clear_opin_nodes(enum e_side node_side); /* Clean the number of OPINs of a side */ + void clear_one_side(enum e_side node_side); /* Clean chan/opin/ipin nodes at one side */ + private: /* Internal Mutators */ private: /* internal functions */ bool is_node_mirror (RRSwitchBlock& cand, enum e_side node_side, size_t track_id) const; bool validate_num_sides() const; @@ -150,5 +163,38 @@ class RRSwitchBlock { size_t num_conf_bits_; }; +/* Object Device Routing Resource Switch Block + * This includes: + * 1. a collection of RRSwitch blocks, each of which can be used to instance Switch blocks in the top-level netlists + * 2. a collection of unique mirrors of RRSwitchBlocks, which can be used to output Verilog / SPICE modules + * 3. a colleciton of unique rotatable of RRSwitchBlocks, which can be used to output Verilog / SPICE modules + * The rotatable RRSwitchBlocks are more generic mirrors, which allow SwitchBlocks to be wired by rotating the pins, + * further reduce the number of Verilog/SPICE modules outputted. This will lead to rapid layout generation + */ +class DeviceRRSwitchBlock { + public: /* Contructors */ + public: /* Accessors */ + DeviceCoordinator get_switch_block_range() const; /* get the max coordinator of the switch block array */ + RRSwitchBlock get_switch_block(DeviceCoordinator coordinator) const; /* Get a rr switch block in the array with a coordinator */ + RRSwitchBlock get_switch_block(size_t x, size_t y) const; /* Get a rr switch block in the array with a coordinator */ + size_t get_num_unique_mirror() const; /* get the number of unique mirrors of switch blocks */ + size_t get_num_rotatable_mirror() const; /* get the number of rotatable mirrors of switch blocks */ + RRSwitchBlock get_unique_mirror(size_t index) const; /* Get a rr switch block which a unique mirror */ + RRSwitchBlock get_rotatable_mirror(size_t index) const; /* Get a rr switch block which a unique mirror */ + public: /* Mutators */ + void reserve(DeviceCoordinator& coordinator); /* Pre-allocate the rr_switch_block array that the device requires */ + void resize_upon_need(DeviceCoordinator& coordinator); /* Resize the rr_switch_block array if needed */ + void add_rr_switch_block(DeviceCoordinator& coordinator, RRSwitchBlock& rr_switch_block); /* Add a switch block to the array, which will automatically identify and update the lists of unique mirrors and rotatable mirrors */ + void clear(); /* clean the content */ + private: /* Validators */ + bool validate_coordinator(DeviceCoordinator& coordinator) const; /* Validate if the (x,y) is the range of this device */ + bool validate_unique_mirror_index(size_t index) const; /* Validate if the index in the range of unique_mirror vector*/ + bool validate_rotatable_mirror_index(size_t index) const; /* Validate if the index in the range of unique_mirror vector*/ + private: /* Internal Data */ + std::vector< std::vector > rr_switch_block_; + std::vector unique_mirror_; + std::vector rotatable_mirror_; +}; + #endif