From 8c9cc003ea240a8d151dada5b191de53d7e9ea60 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 15 Jun 2019 18:11:08 -0600 Subject: [PATCH 01/25] developing routing track rr_node set up in tileable routing architecture --- .../rr_graph/rr_graph_tileable_builder.c | 314 ++++++++++++++++-- 1 file changed, 281 insertions(+), 33 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c index d5cbd8bfc..5c9d8664c 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c @@ -61,6 +61,72 @@ /************************************************************************ * Local function in the file ***********************************************************************/ +/************************************************************************ + * Initialize a rr_node + ************************************************************************/ +static +void tileable_rr_graph_init_rr_node(t_rr_node* cur_rr_node) { + cur_rr_node->xlow = 0; + cur_rr_node->xhigh = 0; + cur_rr_node->ylow = 0; + cur_rr_node->xhigh = 0; + + cur_rr_node->ptc_num = 0; + cur_rr_node->track_ids.clear(); + + cur_rr_node->cost_index = 0; + cur_rr_node->occ = 0; + cur_rr_node->fan_in = 0; + cur_rr_node->num_edges = 0; + cur_rr_node->type = NUM_RR_TYPES; + cur_rr_node->edges = NULL; + cur_rr_node->switches = NULL; + + cur_rr_node->driver_switch = 0; + cur_rr_node->unbuf_switched = 0; + cur_rr_node->buffered = 0; + cur_rr_node->R = 0.; + cur_rr_node->C = 0.; + + cur_rr_node->direction = BI_DIRECTION; /* Give an invalid value, easy to check errors */ + cur_rr_node->drivers = SINGLE; + cur_rr_node->num_wire_drivers = 0; + cur_rr_node->num_opin_drivers = 0; + + cur_rr_node->num_drive_rr_nodes = 0; + cur_rr_node->drive_rr_nodes = NULL; + cur_rr_node->drive_switches = NULL; + + cur_rr_node->vpack_net_num_changed = FALSE; + cur_rr_node->is_parasitic_net = FALSE; + cur_rr_node->is_in_heap = FALSE; + + cur_rr_node->sb_num_drive_rr_nodes = 0; + cur_rr_node->sb_drive_rr_nodes = NULL; + cur_rr_node->sb_drive_switches = NULL; + + cur_rr_node->pb = NULL; + + cur_rr_node->name_mux = NULL; + cur_rr_node->id_path = -1; + + cur_rr_node->prev_node = -1; + cur_rr_node->prev_edge = -1; + cur_rr_node->net_num = -1; + cur_rr_node->vpack_net_num = -1; + + cur_rr_node->prev_node_in_pack = -1; + cur_rr_node->prev_edge_in_pack = -1; + cur_rr_node->net_num_in_pack = -1; + + cur_rr_node->pb_graph_pin = NULL; + cur_rr_node->tnode = NULL; + + cur_rr_node->pack_intrinsic_cost = 0.; + cur_rr_node->z = 0; + + return; +} /************************************************************************ * Generate the number of tracks for each types of routing segments @@ -398,47 +464,222 @@ std::vector estimate_num_rr_nodes_per_type(const DeviceCoordinator& devi * in X-direction and Y-direction channels!!! * So we will load segment details for different channels ***********************************************************************/ - /* For X-direction Channel */ - /* For LEFT side of FPGA */ - ChanNodeDetails left_chanx_details = build_unidir_chan_node_details(chan_width[0], device_size.get_x() - 2, LEFT, segment_infs); - for (size_t iy = 0; iy < device_size.get_y() - 1; ++iy) { - num_rr_nodes_per_type[CHANX] += left_chanx_details.get_num_starting_tracks(); - } - /* For RIGHT side of FPGA */ - ChanNodeDetails right_chanx_details = build_unidir_chan_node_details(chan_width[0], device_size.get_x() - 2, RIGHT, segment_infs); - for (size_t iy = 0; iy < device_size.get_y() - 1; ++iy) { - num_rr_nodes_per_type[CHANX] += right_chanx_details.get_num_starting_tracks(); - } - /* For core of FPGA */ - ChanNodeDetails core_chanx_details = build_unidir_chan_node_details(chan_width[1], device_size.get_x() - 2, NUM_SIDES, segment_infs); - for (size_t ix = 1; ix < grids.size() - 2; ++ix) { - for (size_t iy = 1; iy < grids[ix].size() - 2; ++iy) { - num_rr_nodes_per_type[CHANX] += core_chanx_details.get_num_starting_tracks(); + /* For X-direction Channel: CHANX */ + for (size_t ix = 0; ix < grids.size() - 1; ++ix) { + for (size_t iy = 0; iy < grids[ix].size() - 1; ++iy) { + enum e_side chan_side = NUM_SIDES; + /* For LEFT side of FPGA */ + if (0 == ix) { + chan_side = LEFT; + } + /* For RIGHT side of FPGA */ + if (grids.size() - 2 == ix) { + chan_side = RIGHT; + } + ChanNodeDetails chanx_details = build_unidir_chan_node_details(chan_width[0], device_size.get_x() - 2, chan_side, segment_infs); + num_rr_nodes_per_type[CHANX] += chanx_details.get_num_starting_tracks(); } } - /* For Y-direction Channel */ - /* For TOP side of FPGA */ - ChanNodeDetails top_chany_details = build_unidir_chan_node_details(chan_width[1], device_size.get_y() - 2, TOP, segment_infs); - for (size_t ix = 0; ix < device_size.get_x() - 1; ++ix) { - num_rr_nodes_per_type[CHANY] += top_chany_details.get_num_starting_tracks(); - } - /* For BOTTOM side of FPGA */ - ChanNodeDetails bottom_chany_details = build_unidir_chan_node_details(chan_width[1], device_size.get_y() - 2, BOTTOM, segment_infs); - for (size_t ix = 0; ix < device_size.get_x() - 1; ++ix) { - num_rr_nodes_per_type[CHANY] += bottom_chany_details.get_num_starting_tracks(); - } - /* For core of FPGA */ - ChanNodeDetails core_chany_details = build_unidir_chan_node_details(chan_width[1], device_size.get_y() - 2, NUM_SIDES, segment_infs); - for (size_t ix = 1; ix < grids.size() - 2; ++ix) { - for (size_t iy = 1; iy < grids[ix].size() - 2; ++iy) { - num_rr_nodes_per_type[CHANY] += core_chany_details.get_num_starting_tracks(); + /* For Y-direction Channel: CHANX */ + for (size_t ix = 0; ix < grids.size() - 1; ++ix) { + for (size_t iy = 0; iy < grids[ix].size() - 1; ++iy) { + enum e_side chan_side = NUM_SIDES; + /* For LEFT side of FPGA */ + if (0 == iy) { + chan_side = BOTTOM; + } + /* For RIGHT side of FPGA */ + if (grids[ix].size() - 2 == iy) { + chan_side = TOP; + } + ChanNodeDetails chany_details = build_unidir_chan_node_details(chan_width[1], device_size.get_y() - 2, chan_side, segment_infs); + num_rr_nodes_per_type[CHANY] += chany_details.get_num_starting_tracks(); } } return num_rr_nodes_per_type; } +/************************************************************************ + * Configure rr_nodes for this grid + * coordinators: xlow, ylow, xhigh, yhigh, + * features: capacity, ptc_num (pin_num), + ***********************************************************************/ +static +void load_one_grid_rr_nodes_basic_info(const DeviceCoordinator& grid_coordinator, + const t_grid_tile& cur_grid, enum e_side io_side, + t_rr_graph* rr_graph, size_t* cur_node_id) { + Side io_side_manager(io_side); + /* Walk through the height of each grid, + * get pins and configure the rr_nodes */ + for (int height = 0; height < cur_grid.type->height; ++height) { + /* Walk through sides */ + for (size_t side = 0; side < NUM_SIDES; ++side) { + Side side_manager(side); + /* skip unwanted sides */ + if ( (IO_TYPE == cur_grid.type) + && (side != io_side_manager.to_size_t()) ) { + continue; + } + /* Find OPINs */ + /* Configure pins by pins */ + std::vector opin_list = get_grid_side_pins(cur_grid, DRIVER, side_manager.get_side(), height); + for (size_t pin = 0; pin < opin_list.size(); ++pin) { + /* Configure the rr_node for the OPIN */ + rr_graph->rr_node[*cur_node_id].type = OPIN; + rr_graph->rr_node[*cur_node_id].xlow = grid_coordinator.get_x(); + rr_graph->rr_node[*cur_node_id].xhigh = grid_coordinator.get_x(); + rr_graph->rr_node[*cur_node_id].ylow = grid_coordinator.get_y(); + rr_graph->rr_node[*cur_node_id].yhigh = grid_coordinator.get_y(); + rr_graph->rr_node[*cur_node_id].ptc_num = opin_list[pin]; + rr_graph->rr_node[*cur_node_id].capacity = 1; + rr_graph->rr_node[*cur_node_id].occ = 0; + (*cur_node_id)++; + /* Set a SOURCE rr_node for the OPIN */ + rr_graph->rr_node[*cur_node_id].type = SOURCE; + rr_graph->rr_node[*cur_node_id].xlow = grid_coordinator.get_x(); + rr_graph->rr_node[*cur_node_id].xhigh = grid_coordinator.get_x(); + rr_graph->rr_node[*cur_node_id].ylow = grid_coordinator.get_y(); + rr_graph->rr_node[*cur_node_id].yhigh = grid_coordinator.get_y(); + rr_graph->rr_node[*cur_node_id].ptc_num = opin_list[pin]; + rr_graph->rr_node[*cur_node_id].capacity = 1; + rr_graph->rr_node[*cur_node_id].occ = 0; + /* TODO: should we set pb_graph_pin here? */ + (*cur_node_id)++; + } + /* Find IPINs */ + /* Configure pins by pins */ + std::vector ipin_list = get_grid_side_pins(cur_grid, RECEIVER, side_manager.get_side(), height); + for (size_t pin = 0; pin < ipin_list.size(); ++pin) { + rr_graph->rr_node[*cur_node_id].type = IPIN; + rr_graph->rr_node[*cur_node_id].xlow = grid_coordinator.get_x(); + rr_graph->rr_node[*cur_node_id].xhigh = grid_coordinator.get_x(); + rr_graph->rr_node[*cur_node_id].ylow = grid_coordinator.get_y(); + rr_graph->rr_node[*cur_node_id].yhigh = grid_coordinator.get_y(); + rr_graph->rr_node[*cur_node_id].ptc_num = opin_list[pin]; + rr_graph->rr_node[*cur_node_id].capacity = 1; + rr_graph->rr_node[*cur_node_id].occ = 0; + (*cur_node_id)++; + /* Set a SINK rr_node for the OPIN */ + rr_graph->rr_node[*cur_node_id].type = SINK; + rr_graph->rr_node[*cur_node_id].xlow = grid_coordinator.get_x(); + rr_graph->rr_node[*cur_node_id].xhigh = grid_coordinator.get_x(); + rr_graph->rr_node[*cur_node_id].ylow = grid_coordinator.get_y(); + rr_graph->rr_node[*cur_node_id].yhigh = grid_coordinator.get_y(); + rr_graph->rr_node[*cur_node_id].ptc_num = opin_list[pin]; + rr_graph->rr_node[*cur_node_id].capacity = 1; + rr_graph->rr_node[*cur_node_id].occ = 0; + /* TODO: should we set pb_graph_pin here? */ + (*cur_node_id)++; + } + } + } + + return; +} + +/************************************************************************ + * Initialize the basic information of routing track rr_nodes + * coordinators: xlow, ylow, xhigh, yhigh, + * features: capacity, track_ids, ptc_num, direction + ***********************************************************************/ +static +void load_one_chan_rr_nodes_basic_info(const DeviceCoordinator& chan_coordinator, + t_rr_type chan_type, + const ChanNodeDetails& chan_details, + t_rr_graph* rr_graph, + size_t* cur_node_id) { + + return; +} + +/************************************************************************ + * Initialize the basic information of rr_nodes: + * coordinators: xlow, ylow, xhigh, yhigh, + * features: capacity, track_ids, ptc_num, direction + * grid_info : pb_graph_pin + ***********************************************************************/ +static +void load_rr_nodes_basic_info(t_rr_graph* rr_graph, + std::vector num_rr_nodes_per_type, + const DeviceCoordinator& device_size, + std::vector> grids, + std::vector chan_width, + std::vector segment_infs) { + /* counter */ + size_t cur_node_id = 0; + /* configure by node type */ + /* SOURCE, SINK, OPIN and IPIN */ + /************************************************************************ + * Search the grid and find the number OPINs and IPINs per grid + * Note that the number of SOURCE nodes are the same as OPINs + * and the number of SINK nodes are the same as IPINs + ***********************************************************************/ + for (size_t ix = 0; ix < grids.size(); ++ix) { + for (size_t iy = 0; iy < grids[ix].size(); ++iy) { + /* Skip EMPTY tiles */ + if (EMPTY_TYPE == grids[ix][iy].type) { + continue; + } + DeviceCoordinator grid_coordinator(ix, iy); + enum e_side io_side = NUM_SIDES; + /* If this is the block on borders, we consider IO side */ + if (IO_TYPE == grid[ix][iy].type) { + DeviceCoordinator io_device_size(device_size.get_x() - 1, device_size.get_y() - 1); + io_side = determine_io_grid_pin_side(device_size, grid_coordinator); + } + /* Configure rr_nodes for this grid */ + load_one_grid_rr_nodes_basic_info(grid_coordinator, grid[ix][iy], io_side, + rr_graph, &cur_node_id); + } + } + + /* For X-direction Channel: CHANX */ + for (size_t ix = 0; ix < grids.size() - 1; ++ix) { + for (size_t iy = 0; iy < grids[ix].size() - 1; ++iy) { + DeviceCoordinator chan_coordinator(ix, iy); + enum e_side chan_side = NUM_SIDES; + /* For LEFT side of FPGA */ + if (0 == ix) { + chan_side = LEFT; + } + /* For RIGHT side of FPGA */ + if (grids.size() - 2 == ix) { + chan_side = RIGHT; + } + ChanNodeDetails chanx_details = build_unidir_chan_node_details(chan_width[0], device_size.get_x() - 2, chan_side, segment_infs); + /* Configure CHANX in this channel */ + load_one_chan_rr_nodes_basic_info(chan_coordinator, CHANX, chanx_details, + rr_graph, &cur_node_id); + } + } + + /* For Y-direction Channel: CHANX */ + for (size_t ix = 0; ix < grids.size() - 1; ++ix) { + for (size_t iy = 0; iy < grids[ix].size() - 1; ++iy) { + DeviceCoordinator chan_coordinator(ix, iy); + enum e_side chan_side = NUM_SIDES; + /* For LEFT side of FPGA */ + if (0 == iy) { + chan_side = BOTTOM; + } + /* For RIGHT side of FPGA */ + if (grids[ix].size() - 2 == iy) { + chan_side = TOP; + } + ChanNodeDetails chany_details = build_unidir_chan_node_details(chan_width[1], device_size.get_y() - 2, chan_side, segment_infs); + /* Configure CHANX in this channel */ + load_one_chan_rr_nodes_basic_info(chan_coordinator, CHANY, chany_details, + rr_graph, &cur_node_id); + } + } + + /* Check */ + assert ((int)cur_node_id == rr_graph->num_rr_nodes); + + return; +} /************************************************************************ * Main function of this file @@ -541,8 +782,11 @@ t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types, for (size_t i = 0; i < num_rr_nodes_per_type.size(); ++i) { rr_graph.num_rr_nodes += num_rr_nodes_per_type[i]; } - /* use calloc to initialize everything to be zero */ + /* use calloc and memset to initialize everything to be zero */ rr_graph.rr_node = (t_rr_node*)my_calloc(rr_graph.num_rr_nodes, sizeof(t_rr_node)); + for (int i = 0; i < rr_graph.num_rr_nodes; ++i) { + tileable_rr_graph_init_rr_node(&(rr_graph.rr_node[i])); + } /************************************************************************ * 4. Initialize the basic information of rr_nodes: @@ -550,6 +794,10 @@ t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types, * features: capacity, track_ids, ptc_num, direction * grid_info : pb_graph_pin ***********************************************************************/ + load_rr_nodes_basic_info(&rr_graph, num_rr_nodes_per_type, + device_size, grids, device_chan_width, segment_infs); + + /* build_rr_graph_fast_lookup(&rr_graph); */ /************************************************************************ * 3. Create the connectivity of OPINs From 1af3b5ef5524f38b3d823f7d2b5a3189eac22ab8 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sun, 16 Jun 2019 14:23:19 -0600 Subject: [PATCH 02/25] set chan_rr_nodes in tileable rr_graph builder --- .../SRC/device/rr_graph/chan_node_details.cpp | 12 +- .../SRC/device/rr_graph/chan_node_details.h | 3 +- .../rr_graph/rr_graph_tileable_builder.c | 158 ++++++++++++++---- 3 files changed, 134 insertions(+), 39 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/chan_node_details.cpp b/vpr7_x2p/vpr/SRC/device/rr_graph/chan_node_details.cpp index 2e8c80708..9096fe1ec 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/chan_node_details.cpp +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/chan_node_details.cpp @@ -184,6 +184,12 @@ void ChanNodeDetails::add_track(size_t track_node_id, e_direction track_directio track_end_.push_back(is_end); } +/* Update the node_id of a given track */ +void ChanNodeDetails::set_track_node_id(size_t track_index, size_t track_node_id) { + assert(validate_track_id(track_index)); + track_node_ids_[track_index] = track_node_id; +} + /* Set tracks with a given direction to start */ void ChanNodeDetails::set_tracks_start(e_direction track_direction) { for (size_t inode = 0; inode < get_chan_width(); ++inode) { @@ -205,7 +211,7 @@ void ChanNodeDetails::set_tracks_end(e_direction track_direction) { } /* rotate the track_node_id by an offset */ -void ChanNodeDetails::rotate_track_node_id(size_t offset, bool counter_rotate) { +void ChanNodeDetails::rotate_track_node_id(size_t offset, e_direction track_direction, bool counter_rotate) { /* Rotate the node_ids by groups * A group begins from a track_start and ends before another track_start */ @@ -215,6 +221,10 @@ void ChanNodeDetails::rotate_track_node_id(size_t offset, bool counter_rotate) { if (false == is_track_start(itrack) ) { continue; } + /* Bypass segments do not match track_direction */ + if (track_direction != get_track_direction(itrack) ) { + continue; + } /* Find the group nodes */ std::vector track_group = get_seg_group(itrack); /* Build a vector of the node ids of the tracks */ diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/chan_node_details.h b/vpr7_x2p/vpr/SRC/device/rr_graph/chan_node_details.h index 8b45ba25f..779cb4926 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/chan_node_details.h +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/chan_node_details.h @@ -86,9 +86,10 @@ class ChanNodeDetails { public: /* Mutators */ void reserve(size_t chan_width); /* Reserve the capacitcy of vectors */ void add_track(size_t track_node_id, e_direction track_direction, size_t seg_length, size_t is_start, size_t is_end); + void set_track_node_id(size_t track_index, size_t track_node_id); void set_tracks_start(e_direction track_direction); void set_tracks_end(e_direction track_direction); - void rotate_track_node_id(size_t offset, bool counter_rotate); /* rotate the track_node_id by an offset */ + void rotate_track_node_id(size_t offset, e_direction track_direction, bool counter_rotate); /* rotate the track_node_id by an offset */ void clear(); private: /* validators */ bool validate_chan_width() const; diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c index 5c9d8664c..95963120f 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c @@ -218,29 +218,29 @@ std::vector get_num_tracks_per_seg_type(size_t chan_width, * But still the rr_graph is tileable, which is the first concern! * * Here is a quick example of Length-4 wires in a W=12 routing channel - * +---------------------------------+ - * | Index | Direction | Start Point | - * +---------------------------------+ - * | 0 | --------> | Yes | - * +---------------------------------+ - * | 1 | <-------- | Yes | - * +---------------------------------+ - * | 2 | --------> | No | - * +---------------------------------+ - * | 3 | <-------- | No | - * +---------------------------------+ - * | 4 | --------> | No | - * +---------------------------------+ - * | 5 | <-------- | No | - * +---------------------------------+ - * | 7 | --------> | No | - * +---------------------------------+ - * | 8 | <-------- | No | - * +---------------------------------+ - * | 9 | --------> | Yes | - * +---------------------------------+ - * | 10 | <-------- | Yes | - * +---------------------------------+ + * +---------------------------------------+--------------+ + * | Index | Direction | Starting Point | Ending Point | + * +---------------------------------------+--------------+ + * | 0 | MUX--------> | Yes | No | + * +---------------------------------------+--------------+ + * | 1 | <--------MUX | Yes | No | + * +---------------------------------------+--------------+ + * | 2 | --------> | No | No | + * +---------------------------------------+--------------+ + * | 3 | <-------- | No | No | + * +---------------------------------------+--------------+ + * | 4 | --------> | No | No | + * +---------------------------------------+--------------+ + * | 5 | <-------- | No | No | + * +---------------------------------------+--------------+ + * | 7 | -------->MUX | No | Yes | + * +---------------------------------------+--------------+ + * | 8 | MUX<-------- | No | Yes | + * +---------------------------------------+--------------+ + * | 9 | MUX--------> | Yes | No | + * +---------------------------------------+--------------+ + * | 10 | <--------MUX | Yes | No | + * +---------------------------------------+--------------+ * | 11 | --------> | No | * +---------------------------------+ * | 12 | <-------- | No | @@ -285,16 +285,21 @@ ChanNodeDetails build_unidir_chan_node_details(size_t chan_width, size_t max_seg } for (size_t itrack = 0; itrack < num_tracks[iseg]; ++itrack) { bool seg_start = false; - /* Every length of wire, we set a starting point */ + bool seg_end = false; + /* Every first track of a group of Length-N wires, we set a starting point */ if (0 == itrack % seg_len) { seg_start = true; } + /* Every last track of a group of Length-N wires, we set an ending point */ + if (seg_len - 1 == itrack % seg_len) { + seg_end = true; + } /* Since this is a unidirectional routing architecture, * Add a pair of tracks, 1 INC_DIRECTION track and 1 DEC_DIRECTION track */ - chan_node_details.add_track(cur_track, INC_DIRECTION, seg_len, seg_start, false); + chan_node_details.add_track(cur_track, INC_DIRECTION, seg_len, seg_start, seg_end); cur_track++; - chan_node_details.add_track(cur_track, DEC_DIRECTION, seg_len, seg_start, false); + chan_node_details.add_track(cur_track, DEC_DIRECTION, seg_len, seg_start, seg_end); cur_track++; } } @@ -535,6 +540,7 @@ void load_one_grid_rr_nodes_basic_info(const DeviceCoordinator& grid_coordinator rr_graph->rr_node[*cur_node_id].ptc_num = opin_list[pin]; rr_graph->rr_node[*cur_node_id].capacity = 1; rr_graph->rr_node[*cur_node_id].occ = 0; + /* Update node counter */ (*cur_node_id)++; /* Set a SOURCE rr_node for the OPIN */ rr_graph->rr_node[*cur_node_id].type = SOURCE; @@ -546,6 +552,7 @@ void load_one_grid_rr_nodes_basic_info(const DeviceCoordinator& grid_coordinator rr_graph->rr_node[*cur_node_id].capacity = 1; rr_graph->rr_node[*cur_node_id].occ = 0; /* TODO: should we set pb_graph_pin here? */ + /* Update node counter */ (*cur_node_id)++; } /* Find IPINs */ @@ -560,6 +567,7 @@ void load_one_grid_rr_nodes_basic_info(const DeviceCoordinator& grid_coordinator rr_graph->rr_node[*cur_node_id].ptc_num = opin_list[pin]; rr_graph->rr_node[*cur_node_id].capacity = 1; rr_graph->rr_node[*cur_node_id].occ = 0; + /* Update node counter */ (*cur_node_id)++; /* Set a SINK rr_node for the OPIN */ rr_graph->rr_node[*cur_node_id].type = SINK; @@ -571,6 +579,7 @@ void load_one_grid_rr_nodes_basic_info(const DeviceCoordinator& grid_coordinator rr_graph->rr_node[*cur_node_id].capacity = 1; rr_graph->rr_node[*cur_node_id].occ = 0; /* TODO: should we set pb_graph_pin here? */ + /* Update node counter */ (*cur_node_id)++; } } @@ -587,9 +596,54 @@ void load_one_grid_rr_nodes_basic_info(const DeviceCoordinator& grid_coordinator static void load_one_chan_rr_nodes_basic_info(const DeviceCoordinator& chan_coordinator, t_rr_type chan_type, - const ChanNodeDetails& chan_details, + ChanNodeDetails* chan_details, t_rr_graph* rr_graph, size_t* cur_node_id) { + /* Check each node_id(potential ptc_num) in the channel : + * If this is a starting point, we set a new rr_node with xlow/ylow, ptc_num + * If this is a ending point, we set xhigh/yhigh and track_ids + * For other nodes, we set changes in track_ids + */ + for (size_t itrack = 0; itrack < chan_details->get_chan_width(); ++itrack) { + if (true == chan_details->is_track_start(itrack)) { + /* Use a new chan rr_node */ + rr_graph->rr_node[*cur_node_id].type = chan_type; + rr_graph->rr_node[*cur_node_id].xlow = chan_coordinator.get_x(); + rr_graph->rr_node[*cur_node_id].ylow = chan_coordinator.get_y(); + rr_graph->rr_node[*cur_node_id].direction = chan_details->get_track_direction(itrack); + rr_graph->rr_node[*cur_node_id].ptc_num = itrack; + rr_graph->rr_node[*cur_node_id].track_ids.push_back(itrack); + rr_graph->rr_node[*cur_node_id].capacity = 1; + rr_graph->rr_node[*cur_node_id].occ = 0; + /* Update chan_details with node_id */ + chan_details->set_track_node_id(itrack, *cur_node_id); + /* Update node counter */ + (*cur_node_id)++; + /* Finish here, go to next */ + continue; + } + if (true == chan_details->is_track_end(itrack)) { + /* Get the node_id */ + size_t rr_node_id = chan_details->get_track_node_id(itrack); + /* Do a quick check, make sure we do not mistakenly modify other nodes */ + assert(chan_type == rr_graph->rr_node[rr_node_id].type); + assert(chan_details->get_track_direction(itrack) == rr_graph->rr_node[rr_node_id].type); + /* set xhigh/yhigh and push changes to track_ids */ + rr_graph->rr_node[rr_node_id].xhigh = chan_coordinator.get_x(); + rr_graph->rr_node[rr_node_id].yhigh = chan_coordinator.get_y(); + rr_graph->rr_node[rr_node_id].track_ids.push_back(itrack); + /* Finish here, go to next */ + continue; + } + /* For other nodes, we get the node_id and just update track_ids */ + /* Get the node_id */ + size_t rr_node_id = chan_details->get_track_node_id(itrack); + /* Do a quick check, make sure we do not mistakenly modify other nodes */ + assert(chan_type == rr_graph->rr_node[rr_node_id].type); + assert(chan_details->get_track_direction(itrack) == rr_graph->rr_node[rr_node_id].type); + rr_graph->rr_node[rr_node_id].track_ids.push_back(itrack); + /* Finish here, go to next */ + } return; } @@ -616,8 +670,8 @@ void load_rr_nodes_basic_info(t_rr_graph* rr_graph, * Note that the number of SOURCE nodes are the same as OPINs * and the number of SINK nodes are the same as IPINs ***********************************************************************/ - for (size_t ix = 0; ix < grids.size(); ++ix) { - for (size_t iy = 0; iy < grids[ix].size(); ++iy) { + for (size_t ix = 0; ix < device_size.get_x(); ++ix) { + for (size_t iy = 0; iy < device_size.get_y(); ++iy) { /* Skip EMPTY tiles */ if (EMPTY_TYPE == grids[ix][iy].type) { continue; @@ -636,8 +690,8 @@ void load_rr_nodes_basic_info(t_rr_graph* rr_graph, } /* For X-direction Channel: CHANX */ - for (size_t ix = 0; ix < grids.size() - 1; ++ix) { - for (size_t iy = 0; iy < grids[ix].size() - 1; ++iy) { + for (size_t iy = 0; iy < device_size.get_y() - 1; ++iy) { + for (size_t ix = 0; ix < device_size.get_x() - 1; ++ix) { DeviceCoordinator chan_coordinator(ix, iy); enum e_side chan_side = NUM_SIDES; /* For LEFT side of FPGA */ @@ -645,19 +699,34 @@ void load_rr_nodes_basic_info(t_rr_graph* rr_graph, chan_side = LEFT; } /* For RIGHT side of FPGA */ - if (grids.size() - 2 == ix) { + if (device_size.get_x() - 2 == ix) { chan_side = RIGHT; } ChanNodeDetails chanx_details = build_unidir_chan_node_details(chan_width[0], device_size.get_x() - 2, chan_side, segment_infs); /* Configure CHANX in this channel */ - load_one_chan_rr_nodes_basic_info(chan_coordinator, CHANX, chanx_details, + load_one_chan_rr_nodes_basic_info(chan_coordinator, CHANX, &chanx_details, rr_graph, &cur_node_id); + /* Rotate the chanx_details by an offset of 1*/ + /* For INC_DIRECTION, we use clockwise rotation + * node_id A ----> -----> node_id D + * node_id B ----> / ----> node_id A + * node_id C ----> / ----> node_id B + * node_id D ----> ----> node_id C + */ + chanx_details.rotate_track_node_id(1, INC_DIRECTION, false); + /* For DEC_DIRECTION, we use clockwise rotation + * node_id A <----- <----- node_id B + * node_id B <----- \ <----- node_id C + * node_id C <----- \ <----- node_id D + * node_id D <----- <----- node_id A + */ + chanx_details.rotate_track_node_id(1, DEC_DIRECTION, true); } } /* For Y-direction Channel: CHANX */ - for (size_t ix = 0; ix < grids.size() - 1; ++ix) { - for (size_t iy = 0; iy < grids[ix].size() - 1; ++iy) { + for (size_t ix = 0; ix < device_size.get_x() - 1; ++ix) { + for (size_t iy = 0; iy < device_size.get_y() - 1; ++iy) { DeviceCoordinator chan_coordinator(ix, iy); enum e_side chan_side = NUM_SIDES; /* For LEFT side of FPGA */ @@ -665,13 +734,28 @@ void load_rr_nodes_basic_info(t_rr_graph* rr_graph, chan_side = BOTTOM; } /* For RIGHT side of FPGA */ - if (grids[ix].size() - 2 == iy) { + if (device_size.get_y() - 2 == iy) { chan_side = TOP; } ChanNodeDetails chany_details = build_unidir_chan_node_details(chan_width[1], device_size.get_y() - 2, chan_side, segment_infs); /* Configure CHANX in this channel */ - load_one_chan_rr_nodes_basic_info(chan_coordinator, CHANY, chany_details, + load_one_chan_rr_nodes_basic_info(chan_coordinator, CHANY, &chany_details, rr_graph, &cur_node_id); + /* Rotate the chany_details by an offset of 1*/ + /* For INC_DIRECTION, we use clockwise rotation + * node_id A ----> -----> node_id D + * node_id B ----> / ----> node_id A + * node_id C ----> / ----> node_id B + * node_id D ----> ----> node_id C + */ + chany_details.rotate_track_node_id(1, INC_DIRECTION, false); + /* For DEC_DIRECTION, we use clockwise rotation + * node_id A <----- <----- node_id B + * node_id B <----- \ <----- node_id C + * node_id C <----- \ <----- node_id D + * node_id D <----- <----- node_id A + */ + chany_details.rotate_track_node_id(1, DEC_DIRECTION, true); } } From 0d14fef53e603dfb723a5bf0904e57761262678d Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sun, 16 Jun 2019 23:02:18 -0600 Subject: [PATCH 03/25] bug fixing in setting CHANX and CHANY nodes in tileable rr_graph generator --- .../rr_graph/rr_graph_tileable_builder.c | 63 +++++++++++++++++-- 1 file changed, 59 insertions(+), 4 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c index 95963120f..f0d042337 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c @@ -45,6 +45,8 @@ #include #include #include +#include + #include "vpr_types.h" #include "globals.h" #include "vpr_utils.h" @@ -605,7 +607,9 @@ void load_one_chan_rr_nodes_basic_info(const DeviceCoordinator& chan_coordinator * For other nodes, we set changes in track_ids */ for (size_t itrack = 0; itrack < chan_details->get_chan_width(); ++itrack) { - if (true == chan_details->is_track_start(itrack)) { + /* For INC direction, a starting point requires a new chan rr_node */ + if ( (true == chan_details->is_track_start(itrack)) + && (INC_DIRECTION == chan_details->get_track_direction(itrack)) ) { /* Use a new chan rr_node */ rr_graph->rr_node[*cur_node_id].type = chan_type; rr_graph->rr_node[*cur_node_id].xlow = chan_coordinator.get_x(); @@ -622,12 +626,33 @@ void load_one_chan_rr_nodes_basic_info(const DeviceCoordinator& chan_coordinator /* Finish here, go to next */ continue; } - if (true == chan_details->is_track_end(itrack)) { + /* For DEC direction, an ending point requires a new chan rr_node */ + if ( (true == chan_details->is_track_end(itrack)) + && (DEC_DIRECTION == chan_details->get_track_direction(itrack)) ) { + /* Use a new chan rr_node */ + rr_graph->rr_node[*cur_node_id].type = chan_type; + rr_graph->rr_node[*cur_node_id].xhigh = chan_coordinator.get_x(); + rr_graph->rr_node[*cur_node_id].yhigh = chan_coordinator.get_y(); + rr_graph->rr_node[*cur_node_id].direction = chan_details->get_track_direction(itrack); + rr_graph->rr_node[*cur_node_id].ptc_num = itrack; + rr_graph->rr_node[*cur_node_id].track_ids.push_back(itrack); + rr_graph->rr_node[*cur_node_id].capacity = 1; + rr_graph->rr_node[*cur_node_id].occ = 0; + /* Update chan_details with node_id */ + chan_details->set_track_node_id(itrack, *cur_node_id); + /* Update node counter */ + (*cur_node_id)++; + /* Finish here, go to next */ + continue; + } + /* For INC direction, an ending point requires an update on xhigh and yhigh */ + if ( (true == chan_details->is_track_end(itrack)) + && (INC_DIRECTION == chan_details->get_track_direction(itrack)) ) { /* Get the node_id */ size_t rr_node_id = chan_details->get_track_node_id(itrack); /* Do a quick check, make sure we do not mistakenly modify other nodes */ assert(chan_type == rr_graph->rr_node[rr_node_id].type); - assert(chan_details->get_track_direction(itrack) == rr_graph->rr_node[rr_node_id].type); + assert(chan_details->get_track_direction(itrack) == rr_graph->rr_node[rr_node_id].direction); /* set xhigh/yhigh and push changes to track_ids */ rr_graph->rr_node[rr_node_id].xhigh = chan_coordinator.get_x(); rr_graph->rr_node[rr_node_id].yhigh = chan_coordinator.get_y(); @@ -635,16 +660,46 @@ void load_one_chan_rr_nodes_basic_info(const DeviceCoordinator& chan_coordinator /* Finish here, go to next */ continue; } + /* For DEC direction, an starting point requires an update on xlow and ylow */ + if ( (true == chan_details->is_track_start(itrack)) + && (DEC_DIRECTION == chan_details->get_track_direction(itrack)) ) { + /* Get the node_id */ + size_t rr_node_id = chan_details->get_track_node_id(itrack); + /* Do a quick check, make sure we do not mistakenly modify other nodes */ + assert(chan_type == rr_graph->rr_node[rr_node_id].type); + assert(chan_details->get_track_direction(itrack) == rr_graph->rr_node[rr_node_id].direction); + /* set xhigh/yhigh and push changes to track_ids */ + rr_graph->rr_node[rr_node_id].xlow = chan_coordinator.get_x(); + rr_graph->rr_node[rr_node_id].ylow = chan_coordinator.get_y(); + rr_graph->rr_node[rr_node_id].track_ids.push_back(itrack); + /* Finish here, go to next */ + continue; + } /* For other nodes, we get the node_id and just update track_ids */ /* Get the node_id */ size_t rr_node_id = chan_details->get_track_node_id(itrack); /* Do a quick check, make sure we do not mistakenly modify other nodes */ assert(chan_type == rr_graph->rr_node[rr_node_id].type); - assert(chan_details->get_track_direction(itrack) == rr_graph->rr_node[rr_node_id].type); + assert(chan_details->get_track_direction(itrack) == rr_graph->rr_node[rr_node_id].direction); rr_graph->rr_node[rr_node_id].track_ids.push_back(itrack); /* Finish here, go to next */ } + /* Reverse the track_ids of CHANX and CHANY nodes in DEC_DIRECTION*/ + for (int inode = 0; inode < rr_graph->num_rr_nodes; ++inode) { + /* Bypass condition: only focus on CHANX and CHANY in DEC_DIRECTION */ + if ( (CHANX != rr_graph->rr_node[inode].type) + && (CHANY != rr_graph->rr_node[inode].type) ) { + continue; + } + /* Reach here, we must have a node of CHANX or CHANY */ + if (DEC_DIRECTION != rr_graph->rr_node[inode].direction) { + continue; + } + std::reverse(rr_graph->rr_node[inode].track_ids.begin(), + rr_graph->rr_node[inode].track_ids.end() ); + } + return; } From 51ff150a77e43b7dc8ee8f87ba60ef556c5a1a0c Mon Sep 17 00:00:00 2001 From: tangxifan Date: Mon, 17 Jun 2019 10:16:08 -0600 Subject: [PATCH 04/25] bug fixing in tileable rr_graph generator --- .../rr_graph/rr_graph_tileable_builder.c | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c index f0d042337..b8928468e 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c @@ -624,7 +624,6 @@ void load_one_chan_rr_nodes_basic_info(const DeviceCoordinator& chan_coordinator /* Update node counter */ (*cur_node_id)++; /* Finish here, go to next */ - continue; } /* For DEC direction, an ending point requires a new chan rr_node */ if ( (true == chan_details->is_track_end(itrack)) @@ -643,7 +642,6 @@ void load_one_chan_rr_nodes_basic_info(const DeviceCoordinator& chan_coordinator /* Update node counter */ (*cur_node_id)++; /* Finish here, go to next */ - continue; } /* For INC direction, an ending point requires an update on xhigh and yhigh */ if ( (true == chan_details->is_track_end(itrack)) @@ -658,7 +656,6 @@ void load_one_chan_rr_nodes_basic_info(const DeviceCoordinator& chan_coordinator rr_graph->rr_node[rr_node_id].yhigh = chan_coordinator.get_y(); rr_graph->rr_node[rr_node_id].track_ids.push_back(itrack); /* Finish here, go to next */ - continue; } /* For DEC direction, an starting point requires an update on xlow and ylow */ if ( (true == chan_details->is_track_start(itrack)) @@ -673,16 +670,18 @@ void load_one_chan_rr_nodes_basic_info(const DeviceCoordinator& chan_coordinator rr_graph->rr_node[rr_node_id].ylow = chan_coordinator.get_y(); rr_graph->rr_node[rr_node_id].track_ids.push_back(itrack); /* Finish here, go to next */ - continue; } /* For other nodes, we get the node_id and just update track_ids */ - /* Get the node_id */ - size_t rr_node_id = chan_details->get_track_node_id(itrack); - /* Do a quick check, make sure we do not mistakenly modify other nodes */ - assert(chan_type == rr_graph->rr_node[rr_node_id].type); - assert(chan_details->get_track_direction(itrack) == rr_graph->rr_node[rr_node_id].direction); - rr_graph->rr_node[rr_node_id].track_ids.push_back(itrack); - /* Finish here, go to next */ + if ( (false == chan_details->is_track_start(itrack)) + && (false == chan_details->is_track_end(itrack)) ) { + /* Get the node_id */ + size_t rr_node_id = chan_details->get_track_node_id(itrack); + /* Do a quick check, make sure we do not mistakenly modify other nodes */ + assert(chan_type == rr_graph->rr_node[rr_node_id].type); + assert(chan_details->get_track_direction(itrack) == rr_graph->rr_node[rr_node_id].direction); + rr_graph->rr_node[rr_node_id].track_ids.push_back(itrack); + /* Finish here, go to next */ + } } /* Reverse the track_ids of CHANX and CHANY nodes in DEC_DIRECTION*/ @@ -711,7 +710,6 @@ void load_one_chan_rr_nodes_basic_info(const DeviceCoordinator& chan_coordinator ***********************************************************************/ static void load_rr_nodes_basic_info(t_rr_graph* rr_graph, - std::vector num_rr_nodes_per_type, const DeviceCoordinator& device_size, std::vector> grids, std::vector chan_width, @@ -933,8 +931,7 @@ t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types, * features: capacity, track_ids, ptc_num, direction * grid_info : pb_graph_pin ***********************************************************************/ - load_rr_nodes_basic_info(&rr_graph, num_rr_nodes_per_type, - device_size, grids, device_chan_width, segment_infs); + load_rr_nodes_basic_info(&rr_graph, device_size, grids, device_chan_width, segment_infs); /* build_rr_graph_fast_lookup(&rr_graph); */ From f4191315dac3952b7c91bbfa79b712360c75132b Mon Sep 17 00:00:00 2001 From: tangxifan Date: Mon, 17 Jun 2019 18:01:45 -0600 Subject: [PATCH 05/25] use rr_gsb to build edges of rr_graph --- .../SRC/device/rr_graph/chan_node_details.cpp | 13 +- .../SRC/device/rr_graph/chan_node_details.h | 4 +- .../rr_graph/rr_graph_tileable_builder.c | 641 ++++++++++++++++-- .../rr_graph/rr_graph_tileable_builder.h | 20 +- 4 files changed, 595 insertions(+), 83 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/chan_node_details.cpp b/vpr7_x2p/vpr/SRC/device/rr_graph/chan_node_details.cpp index 9096fe1ec..a717cd36a 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/chan_node_details.cpp +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/chan_node_details.cpp @@ -49,6 +49,7 @@ ChanNodeDetails::ChanNodeDetails(const ChanNodeDetails& src) { for (size_t itrack = 0; itrack < chan_width; ++itrack) { track_node_ids_.push_back(src.get_track_node_id(itrack)); track_direction_.push_back(src.get_track_direction(itrack)); + seg_ids_.push_back(src.get_track_segment_id(itrack)); seg_length_.push_back(src.get_track_segment_length(itrack)); track_start_.push_back(src.is_track_start(itrack)); track_end_.push_back(src.is_track_end(itrack)); @@ -82,6 +83,11 @@ size_t ChanNodeDetails::get_track_segment_length(size_t track_id) const { return seg_length_[track_id]; } +size_t ChanNodeDetails::get_track_segment_id(size_t track_id) const { + assert(validate_track_id(track_id)); + return seg_ids_[track_id]; +} + bool ChanNodeDetails::is_track_start(size_t track_id) const { assert(validate_track_id(track_id)); return track_start_[track_id]; @@ -171,14 +177,16 @@ void ChanNodeDetails::reserve(size_t chan_width) { track_node_ids_.reserve(chan_width); track_direction_.reserve(chan_width); seg_length_.reserve(chan_width); + seg_ids_.reserve(chan_width); track_start_.reserve(chan_width); track_end_.reserve(chan_width); } /* Add a track to the channel */ -void ChanNodeDetails::add_track(size_t track_node_id, e_direction track_direction, size_t seg_length, size_t is_start, size_t is_end) { +void ChanNodeDetails::add_track(size_t track_node_id, e_direction track_direction, size_t seg_id, size_t seg_length, size_t is_start, size_t is_end) { track_node_ids_.push_back(track_node_id); track_direction_.push_back(track_direction); + seg_ids_.push_back(seg_id); seg_length_.push_back(seg_length); track_start_.push_back(is_start); track_end_.push_back(is_end); @@ -246,6 +254,7 @@ void ChanNodeDetails::rotate_track_node_id(size_t offset, e_direction track_dire void ChanNodeDetails::clear() { track_node_ids_.clear(); track_direction_.clear(); + seg_ids_.clear(); seg_length_.clear(); track_start_.clear(); track_end_.clear(); @@ -257,6 +266,7 @@ void ChanNodeDetails::clear() { bool ChanNodeDetails::validate_chan_width() const { size_t chan_width = track_node_ids_.size(); if ( (chan_width == track_direction_.size()) + &&(chan_width == seg_ids_.size()) &&(chan_width == seg_length_.size()) &&(chan_width == track_start_.size()) &&(chan_width == track_end_.size()) ) { @@ -268,6 +278,7 @@ bool ChanNodeDetails::validate_chan_width() const { bool ChanNodeDetails::validate_track_id(size_t track_id) const { if ( (track_id < track_node_ids_.size()) && (track_id < track_direction_.size()) + && (track_id < seg_ids_.size()) && (track_id < seg_length_.size()) && (track_id < track_start_.size()) && (track_id < track_end_.size()) ) { diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/chan_node_details.h b/vpr7_x2p/vpr/SRC/device/rr_graph/chan_node_details.h index 779cb4926..1b75cf8eb 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/chan_node_details.h +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/chan_node_details.h @@ -77,6 +77,7 @@ class ChanNodeDetails { size_t get_track_node_id(size_t track_id) const; e_direction get_track_direction(size_t track_id) const; size_t get_track_segment_length(size_t track_id) const; + size_t get_track_segment_id(size_t track_id) const; bool is_track_start(size_t track_id) const; bool is_track_end(size_t track_id) const; std::vector get_seg_group(size_t track_id) const; @@ -85,7 +86,7 @@ class ChanNodeDetails { size_t get_num_ending_tracks() const; public: /* Mutators */ void reserve(size_t chan_width); /* Reserve the capacitcy of vectors */ - void add_track(size_t track_node_id, e_direction track_direction, size_t seg_length, size_t is_start, size_t is_end); + void add_track(size_t track_node_id, e_direction track_direction, size_t seg_id, size_t seg_length, size_t is_start, size_t is_end); void set_track_node_id(size_t track_index, size_t track_node_id); void set_tracks_start(e_direction track_direction); void set_tracks_end(e_direction track_direction); @@ -97,6 +98,7 @@ class ChanNodeDetails { private: /* Internal data */ std::vector track_node_ids_; /* indices of each track */ std::vector track_direction_; /* direction of each track */ + std::vector seg_ids_; /* id of segment of each track */ std::vector seg_length_; /* Length of each segment */ std::vector track_start_; /* flag to identify if this is the starting point of the track */ std::vector track_end_; /* flag to identify if this is the ending point of the track */ diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c index b8928468e..8300e17ea 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c @@ -56,7 +56,10 @@ #include "route_common.h" #include "fpga_x2p_types.h" #include "rr_graph_tileable_builder.h" +#include "fpga_x2p_backannotate_utils.h" +#include "my_free_fwd.h" +#include "rr_blocks.h" #include "chan_node_details.h" #include "device_coordinator.h" @@ -299,9 +302,9 @@ ChanNodeDetails build_unidir_chan_node_details(size_t chan_width, size_t max_seg /* Since this is a unidirectional routing architecture, * Add a pair of tracks, 1 INC_DIRECTION track and 1 DEC_DIRECTION track */ - chan_node_details.add_track(cur_track, INC_DIRECTION, seg_len, seg_start, seg_end); + chan_node_details.add_track(cur_track, INC_DIRECTION, iseg, seg_len, seg_start, seg_end); cur_track++; - chan_node_details.add_track(cur_track, DEC_DIRECTION, seg_len, seg_start, seg_end); + chan_node_details.add_track(cur_track, DEC_DIRECTION, iseg, seg_len, seg_start, seg_end); cur_track++; } } @@ -472,8 +475,8 @@ std::vector estimate_num_rr_nodes_per_type(const DeviceCoordinator& devi * So we will load segment details for different channels ***********************************************************************/ /* For X-direction Channel: CHANX */ - for (size_t ix = 0; ix < grids.size() - 1; ++ix) { - for (size_t iy = 0; iy < grids[ix].size() - 1; ++iy) { + for (size_t iy = 0; iy < device_size.get_y() - 1; ++iy) { + for (size_t ix = 1; ix < device_size.get_x() - 1; ++ix) { enum e_side chan_side = NUM_SIDES; /* For LEFT side of FPGA */ if (0 == ix) { @@ -489,8 +492,8 @@ std::vector estimate_num_rr_nodes_per_type(const DeviceCoordinator& devi } /* For Y-direction Channel: CHANX */ - for (size_t ix = 0; ix < grids.size() - 1; ++ix) { - for (size_t iy = 0; iy < grids[ix].size() - 1; ++iy) { + for (size_t ix = 0; ix < device_size.get_x() - 1; ++ix) { + for (size_t iy = 1; iy < device_size.get_y() - 1; ++iy) { enum e_side chan_side = NUM_SIDES; /* For LEFT side of FPGA */ if (0 == iy) { @@ -508,6 +511,22 @@ std::vector estimate_num_rr_nodes_per_type(const DeviceCoordinator& devi return num_rr_nodes_per_type; } +/************************************************************************ + * Configure one rr_node to the fast-look up of a rr_graph + ***********************************************************************/ +static +void load_one_node_to_rr_graph_fast_lookup(t_rr_graph* rr_graph, int node_index, + t_rr_type node_type, int x, int y, int ptc_num) { + /* check the size of ivec (nelem), + * if the ptc_num exceeds the size limit, we realloc the ivec */ + if (ptc_num > rr_graph->rr_node_indices[node_type][x][y].nelem - 1) { + rr_graph->rr_node_indices[node_type][x][y].list = (int*) my_realloc(rr_graph->rr_node_indices[node_type][x][y].list, sizeof(int) * ptc_num); + } + /* fill the lookup table */ + rr_graph->rr_node_indices[node_type][x][y].list[ptc_num] = node_index; + return; +} + /************************************************************************ * Configure rr_nodes for this grid * coordinators: xlow, ylow, xhigh, yhigh, @@ -542,18 +561,12 @@ void load_one_grid_rr_nodes_basic_info(const DeviceCoordinator& grid_coordinator rr_graph->rr_node[*cur_node_id].ptc_num = opin_list[pin]; rr_graph->rr_node[*cur_node_id].capacity = 1; rr_graph->rr_node[*cur_node_id].occ = 0; - /* Update node counter */ - (*cur_node_id)++; - /* Set a SOURCE rr_node for the OPIN */ - rr_graph->rr_node[*cur_node_id].type = SOURCE; - rr_graph->rr_node[*cur_node_id].xlow = grid_coordinator.get_x(); - rr_graph->rr_node[*cur_node_id].xhigh = grid_coordinator.get_x(); - rr_graph->rr_node[*cur_node_id].ylow = grid_coordinator.get_y(); - rr_graph->rr_node[*cur_node_id].yhigh = grid_coordinator.get_y(); - rr_graph->rr_node[*cur_node_id].ptc_num = opin_list[pin]; - rr_graph->rr_node[*cur_node_id].capacity = 1; - rr_graph->rr_node[*cur_node_id].occ = 0; - /* TODO: should we set pb_graph_pin here? */ + /* fill fast look-up table */ + load_one_node_to_rr_graph_fast_lookup(rr_graph, *cur_node_id, + rr_graph->rr_node[*cur_node_id].type, + rr_graph->rr_node[*cur_node_id].xlow, + rr_graph->rr_node[*cur_node_id].ylow, + rr_graph->rr_node[*cur_node_id].ptc_num); /* Update node counter */ (*cur_node_id)++; } @@ -569,18 +582,39 @@ void load_one_grid_rr_nodes_basic_info(const DeviceCoordinator& grid_coordinator rr_graph->rr_node[*cur_node_id].ptc_num = opin_list[pin]; rr_graph->rr_node[*cur_node_id].capacity = 1; rr_graph->rr_node[*cur_node_id].occ = 0; + /* fill fast look-up table */ + load_one_node_to_rr_graph_fast_lookup(rr_graph, *cur_node_id, + rr_graph->rr_node[*cur_node_id].type, + rr_graph->rr_node[*cur_node_id].xlow, + rr_graph->rr_node[*cur_node_id].ylow, + rr_graph->rr_node[*cur_node_id].ptc_num); /* Update node counter */ (*cur_node_id)++; + } + /* Set a SOURCE or a SINK rr_node for each class */ + for (int iclass = 0; iclass < cur_grid.type->num_class; ++iclass) { /* Set a SINK rr_node for the OPIN */ - rr_graph->rr_node[*cur_node_id].type = SINK; + if ( DRIVER == cur_grid.type->class_inf[iclass].type) { + rr_graph->rr_node[*cur_node_id].type = SOURCE; + } + if ( RECEIVER == cur_grid.type->class_inf[iclass].type) { + rr_graph->rr_node[*cur_node_id].type = SINK; + } rr_graph->rr_node[*cur_node_id].xlow = grid_coordinator.get_x(); rr_graph->rr_node[*cur_node_id].xhigh = grid_coordinator.get_x(); rr_graph->rr_node[*cur_node_id].ylow = grid_coordinator.get_y(); rr_graph->rr_node[*cur_node_id].yhigh = grid_coordinator.get_y(); - rr_graph->rr_node[*cur_node_id].ptc_num = opin_list[pin]; - rr_graph->rr_node[*cur_node_id].capacity = 1; + rr_graph->rr_node[*cur_node_id].ptc_num = iclass; + /* FIXME: need to confirm if the capacity should be the number of pins in this class*/ + rr_graph->rr_node[*cur_node_id].capacity = cur_grid.type->class_inf[iclass].num_pins; rr_graph->rr_node[*cur_node_id].occ = 0; /* TODO: should we set pb_graph_pin here? */ + /* fill fast look-up table */ + load_one_node_to_rr_graph_fast_lookup(rr_graph, *cur_node_id, + rr_graph->rr_node[*cur_node_id].type, + rr_graph->rr_node[*cur_node_id].xlow, + rr_graph->rr_node[*cur_node_id].ylow, + rr_graph->rr_node[*cur_node_id].ptc_num); /* Update node counter */ (*cur_node_id)++; } @@ -682,21 +716,25 @@ void load_one_chan_rr_nodes_basic_info(const DeviceCoordinator& chan_coordinator rr_graph->rr_node[rr_node_id].track_ids.push_back(itrack); /* Finish here, go to next */ } - } - - /* Reverse the track_ids of CHANX and CHANY nodes in DEC_DIRECTION*/ - for (int inode = 0; inode < rr_graph->num_rr_nodes; ++inode) { - /* Bypass condition: only focus on CHANX and CHANY in DEC_DIRECTION */ - if ( (CHANX != rr_graph->rr_node[inode].type) - && (CHANY != rr_graph->rr_node[inode].type) ) { - continue; + /* fill fast look-up table */ + /* Get node_id */ + int track_node_id = chan_details->get_track_node_id(itrack); + /* CHANX requires a reverted (x,y) in the fast look-up table */ + if (CHANX == chan_type) { + load_one_node_to_rr_graph_fast_lookup(rr_graph, track_node_id, + chan_type, + chan_coordinator.get_y(), + chan_coordinator.get_x(), + itrack); } - /* Reach here, we must have a node of CHANX or CHANY */ - if (DEC_DIRECTION != rr_graph->rr_node[inode].direction) { - continue; + /* CHANY follows a regular (x,y) in the fast look-up table */ + if (CHANY == chan_type) { + load_one_node_to_rr_graph_fast_lookup(rr_graph, track_node_id, + chan_type, + chan_coordinator.get_x(), + chan_coordinator.get_y(), + itrack); } - std::reverse(rr_graph->rr_node[inode].track_ids.begin(), - rr_graph->rr_node[inode].track_ids.end() ); } return; @@ -744,7 +782,7 @@ void load_rr_nodes_basic_info(t_rr_graph* rr_graph, /* For X-direction Channel: CHANX */ for (size_t iy = 0; iy < device_size.get_y() - 1; ++iy) { - for (size_t ix = 0; ix < device_size.get_x() - 1; ++ix) { + for (size_t ix = 1; ix < device_size.get_x() - 1; ++ix) { DeviceCoordinator chan_coordinator(ix, iy); enum e_side chan_side = NUM_SIDES; /* For LEFT side of FPGA */ @@ -779,7 +817,7 @@ void load_rr_nodes_basic_info(t_rr_graph* rr_graph, /* For Y-direction Channel: CHANX */ for (size_t ix = 0; ix < device_size.get_x() - 1; ++ix) { - for (size_t iy = 0; iy < device_size.get_y() - 1; ++iy) { + for (size_t iy = 1; iy < device_size.get_y() - 1; ++iy) { DeviceCoordinator chan_coordinator(ix, iy); enum e_side chan_side = NUM_SIDES; /* For LEFT side of FPGA */ @@ -815,6 +853,478 @@ void load_rr_nodes_basic_info(t_rr_graph* rr_graph, /* Check */ assert ((int)cur_node_id == rr_graph->num_rr_nodes); + /* Reverse the track_ids of CHANX and CHANY nodes in DEC_DIRECTION*/ + for (int inode = 0; inode < rr_graph->num_rr_nodes; ++inode) { + /* Bypass condition: only focus on CHANX and CHANY in DEC_DIRECTION */ + if ( (CHANX != rr_graph->rr_node[inode].type) + && (CHANY != rr_graph->rr_node[inode].type) ) { + continue; + } + /* Reach here, we must have a node of CHANX or CHANY */ + if (DEC_DIRECTION != rr_graph->rr_node[inode].direction) { + continue; + } + std::reverse(rr_graph->rr_node[inode].track_ids.begin(), + rr_graph->rr_node[inode].track_ids.end() ); + } + + + + return; +} + +/************************************************************************ + * Build a fast look-up for the rr_nodes + * it is a 4-dimension array to categorize rr_nodes in terms of + * types, coordinators and ptc_num (feature number) + * The results will be stored in rr_node_indices[type][x][y] + ***********************************************************************/ +static +void alloc_rr_graph_fast_lookup(const DeviceCoordinator& device_size, + t_rr_graph* rr_graph) { + /* Allocates and loads all the structures needed for fast lookups of the * + * index of an rr_node. rr_node_indices is a matrix containing the index * + * of the *first* rr_node at a given (i,j) location. */ + + /* Alloc the lookup table */ + rr_graph->rr_node_indices = (t_ivec ***) my_malloc(sizeof(t_ivec **) * NUM_RR_TYPES); + + /* For OPINs, IPINs, SOURCE, SINKs, CHANX and CHANY */ + for (int type = 0; type < NUM_RR_TYPES; ++type) { + /* Skip SOURCE and OPIN, they will share with SOURCE and SINK + * SOURCE and SINK have unique ptc values so their data can be shared. + * IPIN and OPIN have unique ptc values so their data can be shared. + */ + if ((SOURCE == type) || (OPIN == type) ) { + continue; + } + rr_graph->rr_node_indices[type] = (t_ivec **) my_malloc(sizeof(t_ivec *) * device_size.get_x()); + for (size_t i = 0; i < device_size.get_x(); ++i) { + rr_graph->rr_node_indices[type][i] = (t_ivec *) my_malloc(sizeof(t_ivec) * device_size.get_y()); + for (size_t j = 0; j < device_size.get_y(); ++j) { + rr_graph->rr_node_indices[type][i][j].nelem = 0; + rr_graph->rr_node_indices[type][i][j].list = NULL; + } + } + } + + /* SOURCE and SINK have unique ptc values so their data can be shared. + * IPIN and OPIN have unique ptc values so their data can be shared. */ + rr_graph->rr_node_indices[SOURCE] = rr_graph->rr_node_indices[SINK]; + rr_graph->rr_node_indices[OPIN] = rr_graph->rr_node_indices[IPIN]; + + return; +} + +/* Build a RRChan Object with the given channel type and coorindators */ +static +RRChan build_one_tileable_rr_chan(const DeviceCoordinator& chan_coordinator, + t_rr_type chan_type, + const t_rr_graph* rr_graph, + const ChanNodeDetails& chan_details) { + int chan_width = 0; + t_rr_node** chan_rr_nodes = NULL; + + /* Create a rr_chan object and check if it is unique in the graph */ + RRChan rr_chan; + /* Fill the information */ + rr_chan.set_type(chan_type); + + /* Collect rr_nodes for this channel */ + chan_rr_nodes = get_chan_rr_nodes(&chan_width, chan_type, chan_coordinator.get_x(), chan_coordinator.get_y(), + rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->rr_node_indices); + + /* Reserve */ + /* rr_chan.reserve_node(size_t(chan_width)); */ + + /* Fill the rr_chan */ + for (size_t itrack = 0; itrack < size_t(chan_width); ++itrack) { + size_t iseg = chan_details.get_track_segment_id(itrack); + rr_chan.add_node(chan_rr_nodes[itrack], iseg); + } + + /* Free rr_nodes */ + my_free(chan_rr_nodes); + + return rr_chan; +} + +/*********************************************************************** + * Build a General Switch Block (GSB) + * which includes: + * [I] 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 + * + * -------------- -------------- + * | | CBY | | + * | Grid | ChanY | Grid | + * | [x][y+1] | [x][y+1] | [x+1][y+1] | + * | | | | + * -------------- -------------- + * ---------- + * ChanX & CBX | 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 + * + * [II] A X-direction Connection Block [x][y] + * The connection block shares the same routing channel[x][y] with the Switch Block + * We just need to fill the ipin nodes at TOP and BOTTOM sides + * as well as properly fill the ipin_grid_side information + * [III] A Y-direction Connection Block [x][y+1] + * The connection block shares the same routing channel[x][y+1] with the Switch Block + * We just need to fill the ipin nodes at LEFT and RIGHT sides + * as well as properly fill the ipin_grid_side information + ***********************************************************************/ +static +RRGSB build_one_tileable_rr_gsb(const DeviceCoordinator& device_range, + std::vector device_chan_width, + std::vector segment_inf, + const DeviceCoordinator& gsb_coordinator, + t_rr_graph* rr_graph) { + /* Create an object to return */ + RRGSB rr_gsb; + + /* Check */ + assert(gsb_coordinator.get_x() <= device_range.get_x()); + assert(gsb_coordinator.get_y() <= device_range.get_y()); + + /* Coordinator initialization */ + rr_gsb.set_coordinator(gsb_coordinator.get_x(), gsb_coordinator.get_y()); + + /* Basic information*/ + rr_gsb.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_gsb.get_num_sides(); ++side) { + /* Local variables inside this for loop */ + Side side_manager(side); + DeviceCoordinator coordinator = rr_gsb.get_side_block_coordinator(side_manager.get_side()); + RRChan rr_chan; + 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 => ? */ + /* Build a segment details, where we need the segment ids for building rr_chan + * We do not care starting and ending points here, so set chan_side as NUM_SIDES + */ + ChanNodeDetails chanx_details = build_unidir_chan_node_details(device_chan_width[0], device_range.get_x() - 1, + NUM_SIDES, segment_inf); + ChanNodeDetails chany_details = build_unidir_chan_node_details(device_chan_width[1], device_range.get_y() - 1, + NUM_SIDES, segment_inf); + + switch (side) { + case TOP: /* TOP = 0 */ + /* For the bording, we should take special care */ + if (gsb_coordinator.get_y() == device_range.get_y()) { + rr_gsb.clear_one_side(side_manager.get_side()); + break; + } + /* Routing channels*/ + /* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */ + /* Create a rr_chan object and check if it is unique in the graph */ + rr_chan = build_one_tileable_rr_chan(coordinator, CHANY, rr_graph, chany_details); + chan_dir_to_port_dir_mapping[0] = OUT_PORT; /* INC_DIRECTION => OUT_PORT */ + chan_dir_to_port_dir_mapping[1] = IN_PORT; /* DEC_DIRECTION => IN_PORT */ + + /* Build the Switch block: opin and opin_grid_side */ + /* 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, gsb_coordinator.get_x(), gsb_coordinator.get_y() + 1, 1, + rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->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, gsb_coordinator.get_x() + 1, gsb_coordinator.get_y() + 1, 3, + rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->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 RIGHT: /* RIGHT = 1 */ + /* For the bording, we should take special care */ + if (gsb_coordinator.get_x() == device_range.get_x()) { + rr_gsb.clear_one_side(side_manager.get_side()); + break; + } + /* Routing channels*/ + /* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */ + /* Collect rr_nodes for Tracks for top: chany[x][y+1] */ + /* Create a rr_chan object and check if it is unique in the graph */ + rr_chan = build_one_tileable_rr_chan(coordinator, CHANX, rr_graph, chanx_details); + chan_dir_to_port_dir_mapping[0] = OUT_PORT; /* INC_DIRECTION => OUT_PORT */ + chan_dir_to_port_dir_mapping[1] = IN_PORT; /* DEC_DIRECTION => IN_PORT */ + + /* Build the Switch block: opin and opin_grid_side */ + /* 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, gsb_coordinator.get_x() + 1, gsb_coordinator.get_y() + 1, 2, + rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->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, gsb_coordinator.get_x() + 1, gsb_coordinator.get_y(), 0, + rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->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 BOTTOM: /* BOTTOM = 2*/ + /* For the bording, we should take special care */ + if (gsb_coordinator.get_y() == 0) { + rr_gsb.clear_one_side(side_manager.get_side()); + break; + } + /* Routing channels*/ + /* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */ + /* Collect rr_nodes for Tracks for bottom: chany[x][y] */ + /* Create a rr_chan object and check if it is unique in the graph */ + rr_chan = build_one_tileable_rr_chan(coordinator, CHANY, rr_graph, chany_details); + chan_dir_to_port_dir_mapping[0] = IN_PORT; /* INC_DIRECTION => IN_PORT */ + chan_dir_to_port_dir_mapping[1] = OUT_PORT; /* DEC_DIRECTION => OUT_PORT */ + + /* Build the Switch block: opin and opin_grid_side */ + /* 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, gsb_coordinator.get_x() + 1, gsb_coordinator.get_y(), 3, + rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->rr_node_indices); + /* 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, gsb_coordinator.get_x(), gsb_coordinator.get_y(), 1, + rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->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 LEFT: /* LEFT = 3 */ + /* For the bording, we should take special care */ + if (gsb_coordinator.get_x() == 0) { + rr_gsb.clear_one_side(side_manager.get_side()); + break; + } + /* Routing channels*/ + /* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */ + /* Collect rr_nodes for Tracks for left: chanx[x][y] */ + /* Create a rr_chan object and check if it is unique in the graph */ + rr_chan = build_one_tileable_rr_chan(coordinator, CHANX, rr_graph, chanx_details); + chan_dir_to_port_dir_mapping[0] = IN_PORT; /* INC_DIRECTION => IN_PORT */ + chan_dir_to_port_dir_mapping[1] = OUT_PORT; /* DEC_DIRECTION => OUT_PORT */ + + /* Build the Switch block: opin and opin_grid_side */ + /* 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, gsb_coordinator.get_x(), gsb_coordinator.get_y() + 1, 2, + rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->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, gsb_coordinator.get_x(), gsb_coordinator.get_y(), 0, + rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->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[1] = TOP; + break; + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d])Invalid side index!\n", + __FILE__, __LINE__); + exit(1); + } + + /* Organize a vector of port direction */ + if (0 < rr_chan.get_chan_width()) { + std::vector rr_chan_dir; + rr_chan_dir.resize(rr_chan.get_chan_width()); + for (size_t itrack = 0; itrack < rr_chan.get_chan_width(); ++itrack) { + /* Identify the directionality, record it in rr_node_direction */ + if (INC_DIRECTION == rr_chan.get_node(itrack)->direction) { + rr_chan_dir[itrack] = chan_dir_to_port_dir_mapping[0]; + } else { + assert (DEC_DIRECTION == rr_chan.get_node(itrack)->direction); + rr_chan_dir[itrack] = chan_dir_to_port_dir_mapping[1]; + } + } + /* Fill chan_rr_nodes */ + rr_gsb.add_chan_node(side_manager.get_side(), rr_chan, rr_chan_dir); + } + + /* 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_gsb.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_gsb.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_gsb.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; + } + + /* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */ + for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { + /* Local variables inside this for loop */ + Side side_manager(side); + size_t ix; + size_t iy; + enum e_side chan_side; + int num_temp_ipin_rr_nodes = 0; + t_rr_node** temp_ipin_rr_node = NULL; + enum e_side ipin_rr_node_grid_side; + + switch (side) { + case TOP: /* TOP = 0 */ + /* For the bording, we should take special care */ + /* Check if left side chan width is 0 or not */ + chan_side = LEFT; + /* Build the connection block: ipin and ipin_grid_side */ + /* BOTTOM side INPUT Pins of Grid[x][y+1] */ + ix = rr_gsb.get_sb_x(); + iy = rr_gsb.get_sb_y() + 1; + ipin_rr_node_grid_side = BOTTOM; + break; + case RIGHT: /* RIGHT = 1 */ + /* For the bording, we should take special care */ + /* Check if TOP side chan width is 0 or not */ + chan_side = TOP; + /* Build the connection block: ipin and ipin_grid_side */ + /* LEFT side INPUT Pins of Grid[x+1][y+1] */ + ix = rr_gsb.get_sb_x() + 1; + iy = rr_gsb.get_sb_y() + 1; + ipin_rr_node_grid_side = LEFT; + break; + case BOTTOM: /* BOTTOM = 2*/ + /* For the bording, we should take special care */ + /* Check if left side chan width is 0 or not */ + chan_side = LEFT; + /* Build the connection block: ipin and ipin_grid_side */ + /* TOP side INPUT Pins of Grid[x][y] */ + ix = rr_gsb.get_sb_x(); + iy = rr_gsb.get_sb_y(); + ipin_rr_node_grid_side = TOP; + break; + case LEFT: /* LEFT = 3 */ + /* For the bording, we should take special care */ + /* Check if left side chan width is 0 or not */ + chan_side = TOP; + /* Build the connection block: ipin and ipin_grid_side */ + /* RIGHT side INPUT Pins of Grid[x][y+1] */ + ix = rr_gsb.get_sb_x(); + iy = rr_gsb.get_sb_y() + 1; + ipin_rr_node_grid_side = RIGHT; + break; + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d])Invalid side index!\n", + __FILE__, __LINE__); + exit(1); + } + + /* If there is no channel at this side, we skip ipin_node annotation */ + if (0 == rr_gsb.get_chan_width(chan_side)) { + continue; + } + /* Collect IPIN rr_nodes*/ + temp_ipin_rr_node = get_grid_side_pin_rr_nodes(&(num_temp_ipin_rr_nodes), + IPIN, ix, iy, ipin_rr_node_grid_side, + rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->rr_node_indices); + /* Fill the ipin nodes of RRGSB */ + for (int inode = 0; inode < num_temp_ipin_rr_nodes; ++inode) { + rr_gsb.add_ipin_node(temp_ipin_rr_node[inode], side_manager.get_side(), ipin_rr_node_grid_side); + } + /* Free */ + num_temp_ipin_rr_nodes = 0; + my_free(temp_ipin_rr_node); + } + + return rr_gsb; + +} + +/************************************************************************ + * Build the edges of each rr_node tile by tile: + * We classify rr_nodes into a general switch block (GSB) data structure + * where we create edges to each rr_nodes in the GSB with respect to + * Fc_in and Fc_out, switch block patterns + * For each GSB: + * 1. create edges between SOURCE and OPINs + * 2. create edges between IPINs and SINKs + * 3. create edges between CHANX | CHANY and IPINs (connections inside connection blocks) + * 4. create edges between OPINs, CHANX and CHANY (connections inside switch blocks) + * 5. create edges between OPINs and IPINs (direct-connections) + ***********************************************************************/ +static +void build_rr_graph_edges(t_rr_graph* rr_graph, + const DeviceCoordinator& device_size, + std::vector device_chan_width, + std::vector segment_inf, + int** Fc_in, int** Fc_out, + enum e_switch_block_type sb_type, int Fs, + int num_directs, t_clb_to_clb_directs* clb_to_clb_directs, + int num_switches, int delayless_switch) { + DeviceCoordinator device_range(device_size.get_x() - 1, device_size.get_y() - 1); + /* Go Switch Block by Switch Block */ + for (size_t ix = 0; ix < device_size.get_x(); ++ix) { + for (size_t iy = 0; iy < device_size.get_y(); ++iy) { + DeviceCoordinator gsb_coordinator(ix, iy); + /* Create a GSB object */ + RRGSB rr_gsb = build_one_tileable_rr_gsb(device_range, device_chan_width, segment_inf, gsb_coordinator, rr_graph); + /* 1. create edges between SOURCE and OPINs */ + /* 2. create edges between IPINs and SINKs */ + /* 3. create edges between CHANX | CHANY and IPINs (connections inside connection blocks) */ + /* 4. create edges between OPINs, CHANX and CHANY (connections inside switch blocks) */ + /* 5. create edges between OPINs and IPINs (direct-connections) */ + + /* Finish this GSB, go to the next*/ + } + } + return; } @@ -858,18 +1368,14 @@ void load_rr_nodes_basic_info(t_rr_graph* rr_graph, * b. RC tree ***********************************************************************/ t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types, - INP t_type_ptr types, INP int L_nx, INP int L_ny, - INP struct s_grid_tile **L_grid, INP int chan_width, - INP struct s_chan_width_dist *chan_capacity_inf, - INP enum e_switch_block_type sb_type, INP int Fs, INP int num_seg_types, - INP int num_switches, INP t_segment_inf * segment_inf, - INP int global_route_switch, INP int delayless_switch, - INP t_timing_inf timing_inf, INP int wire_to_ipin_switch, - INP enum e_base_cost_type base_cost_type, INP t_direct_inf *directs, - INP int num_directs, INP boolean ignore_Fc_0, OUTP int *Warnings, - /*Xifan TANG: Switch Segment Pattern Support*/ - INP int num_swseg_pattern, INP t_swseg_pattern_inf* swseg_patterns, - INP boolean opin_to_cb_fast_edges, INP boolean opin_logic_eq_edges) { + INP t_type_ptr types, INP int L_nx, INP int L_ny, + INP struct s_grid_tile **L_grid, INP int chan_width, + INP enum e_switch_block_type sb_type, INP int Fs, INP int num_seg_types, + INP int num_switches, INP t_segment_inf * segment_inf, + INP int delayless_switch, + INP t_timing_inf timing_inf, INP int wire_to_ipin_switch, + INP enum e_base_cost_type base_cost_type, INP t_direct_inf *directs, + INP int num_directs, INP boolean ignore_Fc_0, OUTP int *Warnings) { /* Create an empty graph */ t_rr_graph rr_graph; rr_graph.rr_node_indices = NULL; @@ -931,9 +1437,8 @@ t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types, * features: capacity, track_ids, ptc_num, direction * grid_info : pb_graph_pin ***********************************************************************/ - load_rr_nodes_basic_info(&rr_graph, device_size, grids, device_chan_width, segment_infs); - - /* build_rr_graph_fast_lookup(&rr_graph); */ + alloc_rr_graph_fast_lookup(device_size, &rr_graph); + load_rr_nodes_basic_info(&rr_graph, device_size, grids, device_chan_width, segment_infs); /************************************************************************ * 3. Create the connectivity of OPINs @@ -960,37 +1465,35 @@ t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types, TRUE, UNI_DIRECTIONAL, &Fc_clipped, ignore_Fc_0); /************************************************************************ - * 6. Allocate rr_graph, fill the node information - * For each node, fill - * a. basic information: coordinator(xlow, xhigh, ylow, yhigh), ptc_num - * b. edges (both incoming and outcoming) - * c. handle direct-connections + * 5. Build the connections tile by tile: + * We classify rr_nodes into a general switch block (GSB) data structure + * where we create edges to each rr_nodes in the GSB with respect to + * Fc_in and Fc_out, switch block patterns + * In addition, we will also handle direct-connections: + * Add edges that bridge OPINs and IPINs to the rr_graph ***********************************************************************/ - /* Alloc node lookups, count nodes, alloc rr nodes */ - /* - rr_graph.num_rr_nodes = 0; - rr_graph.rr_node_indices = alloc_and_load_rr_node_indices(nodes_per_chan, L_nx, L_ny, - &(rr_graph.num_rr_nodes), seg_details); - rr_graph.rr_node = (t_rr_node *) my_malloc(sizeof(t_rr_node) * rr_graph.num_rr_nodes); - memset(rr_node, 0, sizeof(t_rr_node) * rr_graph.num_rr_nodes); - boolean* L_rr_edge_done = (boolean *) my_malloc(sizeof(boolean) * rr_graph.num_rr_nodes); - memset(L_rr_edge_done, 0, sizeof(boolean) * rr_graph.num_rr_nodes); - */ - - /* handle direct-connections */ + /* Create data structure of direct-connections */ t_clb_to_clb_directs* clb_to_clb_directs = NULL; if (num_directs > 0) { clb_to_clb_directs = alloc_and_load_clb_to_clb_directs(directs, num_directs); } + build_rr_graph_edges(&rr_graph, device_size, device_chan_width, segment_infs, + Fc_in, Fc_out, sb_type, Fs, + num_directs, clb_to_clb_directs, num_switches, delayless_switch); + /************************************************************************ - * 8. Allocate external data structures + * 7. Allocate external data structures * a. cost_index * b. RC tree ***********************************************************************/ rr_graph_externals(timing_inf, segment_inf, num_seg_types, chan_width, wire_to_ipin_switch, base_cost_type); + /************************************************************************ + * 8. Sanitizer for the rr_graph, check connectivities of rr_nodes + ***********************************************************************/ + return rr_graph; } diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.h b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.h index fdb704454..7f6e913cb 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.h +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.h @@ -2,17 +2,13 @@ #define RR_GRAPH_TILEABLE_BUILDER_H t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types, - INP t_type_ptr types, INP int L_nx, INP int L_ny, - INP struct s_grid_tile **L_grid, INP int chan_width, - INP struct s_chan_width_dist *chan_capacity_inf, - INP enum e_switch_block_type sb_type, INP int Fs, INP int num_seg_types, - INP int num_switches, INP t_segment_inf * segment_inf, - INP int global_route_switch, INP int delayless_switch, - INP t_timing_inf timing_inf, INP int wire_to_ipin_switch, - INP enum e_base_cost_type base_cost_type, INP t_direct_inf *directs, - INP int num_directs, INP boolean ignore_Fc_0, OUTP int *Warnings, - /*Xifan TANG: Switch Segment Pattern Support*/ - INP int num_swseg_pattern, INP t_swseg_pattern_inf* swseg_patterns, - INP boolean opin_to_cb_fast_edges, INP boolean opin_logic_eq_edges); + INP t_type_ptr types, INP int L_nx, INP int L_ny, + INP struct s_grid_tile **L_grid, INP int chan_width, + INP enum e_switch_block_type sb_type, INP int Fs, INP int num_seg_types, + INP int num_switches, INP t_segment_inf * segment_inf, + INP int delayless_switch, + INP t_timing_inf timing_inf, INP int wire_to_ipin_switch, + INP enum e_base_cost_type base_cost_type, INP t_direct_inf *directs, + INP int num_directs, INP boolean ignore_Fc_0, OUTP int *Warnings); #endif From 352c97302b2fb4f8ef19f403eaad238462160da8 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Mon, 17 Jun 2019 22:10:30 -0600 Subject: [PATCH 06/25] start building object GSB graph --- .../rr_graph/{gsb_graph.c => gsb_graph.cpp} | 2 +- vpr7_x2p/vpr/SRC/device/rr_graph/gsb_graph.h | 15 +- .../rr_graph/rr_graph_tileable_builder.c | 131 +++++++++++++++--- .../rr_graph/rr_graph_tileable_builder.h | 19 +-- 4 files changed, 137 insertions(+), 30 deletions(-) rename vpr7_x2p/vpr/SRC/device/rr_graph/{gsb_graph.c => gsb_graph.cpp} (98%) diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/gsb_graph.c b/vpr7_x2p/vpr/SRC/device/rr_graph/gsb_graph.cpp similarity index 98% rename from vpr7_x2p/vpr/SRC/device/rr_graph/gsb_graph.c rename to vpr7_x2p/vpr/SRC/device/rr_graph/gsb_graph.cpp index 40159d05e..b7fd40cb8 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/gsb_graph.c +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/gsb_graph.cpp @@ -23,7 +23,7 @@ ***********************************************************************/ /************************************************************************ - * Filename: rr_graph_gsb.c + * Filename: rr_graph_gsb.cpp * Created by: Xifan Tang * Change history: * +-------------------------------------+ diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/gsb_graph.h b/vpr7_x2p/vpr/SRC/device/rr_graph/gsb_graph.h index 0ada48d32..b0c1ed1d3 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/gsb_graph.h +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/gsb_graph.h @@ -42,11 +42,11 @@ * 2. A Y-direction Connection block locates at the top side of the switch block * * +---------------------------------+ - * | Y-direction CB | + * IPIN_NODES | Y-direction CB | IPIN_NODES * | [x][y + 1] | * +---------------------------------+ * - * TOP SIDE + * IPIN_NODES TOP SIDE * +-------------+ +---------------------------------+ * | | | OPIN_NODE CHAN_NODES OPIN_NODES | * | | | | @@ -61,7 +61,7 @@ * | | | | * | | | OPIN_NODE CHAN_NODES OPIN_NODES | * +-------------+ +---------------------------------+ - * BOTTOM SIDE + * IPIN_NODES BOTTOM SIDE * ***********************************************************************/ @@ -92,6 +92,7 @@ /* Define open nodes */ #define OPEN_NODE_ID RRNodeId(-1) #define OPEN_EDGE_ID RREdgeId(-1) +#define OPEN_SEGMENT_ID RRSegmentId(-1) /*********************************************************************** * This data structure focuses on modeling the internal pin-to-pin connections. @@ -142,6 +143,9 @@ class GSBGraph { /* Aggregates */ node_range nodes() const; edge_range edges() const; + public: /* Coordinator generation */ + public: /* Accessors */ + public: /* Mutators */ private: /* Internal Data */ /* Coordinator of this GSB */ DeviceCoordinator coordinator_; @@ -152,6 +156,7 @@ class GSBGraph { vtr::vector node_sides_; vtr::vector node_directions_; vtr::vector node_grid_sides_; + vtr::vector node_segment_ids_; vtr::vector> node_in_edges; vtr::vector> node_out_edges; @@ -160,6 +165,10 @@ class GSBGraph { vtr::vector edge_ids_; vtr::vector edge_src_nodes_; /* each element is a node_id */ vtr::vector edge_sink_nodes_; /* each element is a node_id */ + + /* fast look-up [node_side][node_type][node_id] */ + typedef std::vector< std::vector< std::vector > > NodeLookup; + mutable NodeLookup node_lookup_; }; #endif diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c index 8300e17ea..42ea4946a 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c @@ -1287,6 +1287,95 @@ RRGSB build_one_tileable_rr_gsb(const DeviceCoordinator& device_range, } +/************************************************************************ + * Add a edge connecting two rr_nodes + * For src rr_node, update the edge list and update switch_id, + * For des rr_node, update the fan_in + ***********************************************************************/ +static +void add_one_edge_for_two_rr_nodes(t_rr_graph* rr_graph, + int src_rr_node_id, + int des_rr_node_id, + short switch_id) { + /* Check */ + assert ( (-1 < src_rr_node_id) && (src_rr_node_id < rr_graph->num_rr_nodes) ); + assert ( (-1 < des_rr_node_id) && (des_rr_node_id < rr_graph->num_rr_nodes) ); + + t_rr_node* src_rr_node = &(rr_graph->rr_node[src_rr_node_id]); + t_rr_node* des_rr_node = &(rr_graph->rr_node[des_rr_node_id]); + + /* Allocate edge and switch to src_rr_node */ + src_rr_node->num_edges++; + if (NULL == src_rr_node->edges) { + /* calloc */ + src_rr_node->edges = (int*) my_calloc( src_rr_node->num_edges, sizeof(int) ); + src_rr_node->switches = (short*) my_calloc( src_rr_node->num_edges, sizeof(short) ); + } else { + /* realloc */ + src_rr_node->edges = (int*) my_realloc(src_rr_node->edges, + src_rr_node->num_edges * sizeof(int)); + src_rr_node->switches = (short*) my_realloc(src_rr_node->switches, + src_rr_node->num_edges * sizeof(short)); + } + /* Fill edge and switch info */ + src_rr_node->edges[src_rr_node->num_edges - 1] = des_rr_node_id; + src_rr_node->switches[src_rr_node->num_edges - 1] = switch_id; + + /* Update the des_rr_node */ + des_rr_node->fan_in++; + + return; +} + +/************************************************************************ + * Create edges for each rr_node of a General Switch Blocks (GSB): + * 1. create edges between SOURCE and OPINs + * 2. create edges between IPINs and SINKs + * 3. create edges between CHANX | CHANY and IPINs (connections inside connection blocks) + * 4. create edges between OPINs, CHANX and CHANY (connections inside switch blocks) + * 5. create edges between OPINs and IPINs (direct-connections) + ***********************************************************************/ +static +void build_edges_for_one_tileable_rr_gsb(t_rr_graph* rr_graph, RRGSB* rr_gsb, + int** Fc_in, int** Fc_out, + enum e_switch_block_type sb_type, int Fs, + int num_directs, t_clb_to_clb_directs* clb_to_clb_directs, + int num_switches, int delayless_switch) { + /* Check rr_gsb */ + assert (NULL != rr_gsb); + + /* Walk through each sides */ + for (size_t side = 0; side < rr_gsb->get_num_sides(); ++side) { + Side side_manager(side); + enum e_side gsb_side = side_manager.get_side(); + /* Find OPINs */ + for (size_t inode = 0; inode < rr_gsb->get_num_opin_nodes(gsb_side); ++inode) { + t_rr_node* opin_node = rr_gsb->get_opin_node(gsb_side, inode); + /* 1. create edges between SOURCE and OPINs */ + int src_node_id = get_rr_node_index(opin_node->xlow, opin_node->ylow, + SOURCE, opin_node->ptc_num, + rr_graph->rr_node_indices); + /* add edges to the src_node */ + add_one_edge_for_two_rr_nodes(rr_graph, src_node_id, opin_node - rr_graph->rr_node, + delayless_switch); + } + /* Find IPINs */ + for (size_t inode = 0; inode < rr_gsb->get_num_ipin_nodes(gsb_side); ++inode) { + t_rr_node* ipin_node = rr_gsb->get_ipin_node(gsb_side, inode); + /* 1. create edges between SOURCE and OPINs */ + int sink_node_id = get_rr_node_index(ipin_node->xlow, ipin_node->ylow, + SINK, ipin_node->ptc_num, + rr_graph->rr_node_indices); + /* add edges to the src_node */ + add_one_edge_for_two_rr_nodes(rr_graph, ipin_node - rr_graph->rr_node, sink_node_id, + delayless_switch); + } + } + + + return; +} + /************************************************************************ * Build the edges of each rr_node tile by tile: * We classify rr_nodes into a general switch block (GSB) data structure @@ -1315,12 +1404,11 @@ void build_rr_graph_edges(t_rr_graph* rr_graph, DeviceCoordinator gsb_coordinator(ix, iy); /* Create a GSB object */ RRGSB rr_gsb = build_one_tileable_rr_gsb(device_range, device_chan_width, segment_inf, gsb_coordinator, rr_graph); - /* 1. create edges between SOURCE and OPINs */ - /* 2. create edges between IPINs and SINKs */ - /* 3. create edges between CHANX | CHANY and IPINs (connections inside connection blocks) */ - /* 4. create edges between OPINs, CHANX and CHANY (connections inside switch blocks) */ - /* 5. create edges between OPINs and IPINs (direct-connections) */ - + /* Build edges for a GSB */ + build_edges_for_one_tileable_rr_gsb(rr_graph, &rr_gsb, Fc_in, Fc_out, + sb_type, Fs, + num_directs, clb_to_clb_directs, + num_switches, delayless_switch); /* Finish this GSB, go to the next*/ } } @@ -1367,15 +1455,18 @@ void build_rr_graph_edges(t_rr_graph* rr_graph, * a. cost_index * b. RC tree ***********************************************************************/ -t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types, - INP t_type_ptr types, INP int L_nx, INP int L_ny, - INP struct s_grid_tile **L_grid, INP int chan_width, - INP enum e_switch_block_type sb_type, INP int Fs, INP int num_seg_types, - INP int num_switches, INP t_segment_inf * segment_inf, - INP int delayless_switch, - INP t_timing_inf timing_inf, INP int wire_to_ipin_switch, - INP enum e_base_cost_type base_cost_type, INP t_direct_inf *directs, - INP int num_directs, INP boolean ignore_Fc_0, OUTP int *Warnings) { +void build_tileable_unidir_rr_graph(INP int L_num_types, + INP t_type_ptr types, INP int L_nx, INP int L_ny, + INP struct s_grid_tile **L_grid, INP int chan_width, + INP enum e_switch_block_type sb_type, INP int Fs, + INP int num_seg_types, + INP int num_switches, INP t_segment_inf * segment_inf, + INP int delayless_switch, + INP t_timing_inf timing_inf, INP int wire_to_ipin_switch, + INP enum e_base_cost_type base_cost_type, + INP t_direct_inf *directs, + INP int num_directs, INP boolean ignore_Fc_0, + OUTP int *Warnings) { /* Create an empty graph */ t_rr_graph rr_graph; rr_graph.rr_node_indices = NULL; @@ -1478,6 +1569,7 @@ t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types, clb_to_clb_directs = alloc_and_load_clb_to_clb_directs(directs, num_directs); } + /* Create edges for a tileable rr_graph */ build_rr_graph_edges(&rr_graph, device_size, device_chan_width, segment_infs, Fc_in, Fc_out, sb_type, Fs, num_directs, clb_to_clb_directs, num_switches, delayless_switch); @@ -1494,9 +1586,14 @@ t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types, * 8. Sanitizer for the rr_graph, check connectivities of rr_nodes ***********************************************************************/ - return rr_graph; -} + /* We set global variables for rr_nodes here, + */ + num_rr_nodes = rr_graph.num_rr_nodes; + rr_node = rr_graph.rr_node; + rr_node_indices = rr_graph.rr_node_indices; + return; +} /************************************************************************ * End of file : rr_graph_tileable_builder.c diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.h b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.h index 7f6e913cb..04694f492 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.h +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.h @@ -1,14 +1,15 @@ #ifndef RR_GRAPH_TILEABLE_BUILDER_H #define RR_GRAPH_TILEABLE_BUILDER_H -t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types, - INP t_type_ptr types, INP int L_nx, INP int L_ny, - INP struct s_grid_tile **L_grid, INP int chan_width, - INP enum e_switch_block_type sb_type, INP int Fs, INP int num_seg_types, - INP int num_switches, INP t_segment_inf * segment_inf, - INP int delayless_switch, - INP t_timing_inf timing_inf, INP int wire_to_ipin_switch, - INP enum e_base_cost_type base_cost_type, INP t_direct_inf *directs, - INP int num_directs, INP boolean ignore_Fc_0, OUTP int *Warnings); +void build_tileable_unidir_rr_graph(INP int L_num_types, + INP t_type_ptr types, INP int L_nx, INP int L_ny, + INP struct s_grid_tile **L_grid, INP int chan_width, + INP enum e_switch_block_type sb_type, INP int Fs, + INP int num_seg_types, + INP int num_switches, INP t_segment_inf * segment_inf, + INP int delayless_switch, + INP t_timing_inf timing_inf, INP int wire_to_ipin_switch, + INP enum e_base_cost_type base_cost_type, INP t_direct_inf *directs, + INP int num_directs, INP boolean ignore_Fc_0, OUTP int *Warnings); #endif From 9ca1b42f4c57acd560fd73ef33f77dbb6baea760 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 18 Jun 2019 16:52:42 -0600 Subject: [PATCH 07/25] developing switch block pattern for tileable routing architecture --- .../rr_graph/rr_graph_tileable_builder.c | 188 ++++++++++++++++-- vpr7_x2p/vpr/SRC/route/rr_graph.c | 27 +-- vpr7_x2p/vpr/SRC/route/rr_graph.h | 22 ++ 3 files changed, 193 insertions(+), 44 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c index 42ea4946a..4aaffddc1 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c @@ -47,12 +47,16 @@ #include #include +#include "vtr_ndmatrix.h" + #include "vpr_types.h" #include "globals.h" #include "vpr_utils.h" #include "rr_graph_util.h" +#include "ReadOptions.h" #include "rr_graph.h" #include "rr_graph2.h" +#include "rr_graph_sbox.h" #include "route_common.h" #include "fpga_x2p_types.h" #include "rr_graph_tileable_builder.h" @@ -892,9 +896,9 @@ void alloc_rr_graph_fast_lookup(const DeviceCoordinator& device_size, /* For OPINs, IPINs, SOURCE, SINKs, CHANX and CHANY */ for (int type = 0; type < NUM_RR_TYPES; ++type) { /* Skip SOURCE and OPIN, they will share with SOURCE and SINK - * SOURCE and SINK have unique ptc values so their data can be shared. - * IPIN and OPIN have unique ptc values so their data can be shared. - */ + * SOURCE and SINK have unique ptc values so their data can be shared. + * IPIN and OPIN have unique ptc values so their data can be shared. + */ if ((SOURCE == type) || (OPIN == type) ) { continue; } @@ -1337,8 +1341,9 @@ void add_one_edge_for_two_rr_nodes(t_rr_graph* rr_graph, ***********************************************************************/ static void build_edges_for_one_tileable_rr_gsb(t_rr_graph* rr_graph, RRGSB* rr_gsb, - int** Fc_in, int** Fc_out, - enum e_switch_block_type sb_type, int Fs, + std::vector < std::vector< std::vector > > track2ipin_lookup, + std::vector < std::vector< std::vector > > opin2track_map, + std::vector < std::vector< std::vector > > sb_conn, int num_directs, t_clb_to_clb_directs* clb_to_clb_directs, int num_switches, int delayless_switch) { /* Check rr_gsb */ @@ -1362,15 +1367,18 @@ void build_edges_for_one_tileable_rr_gsb(t_rr_graph* rr_graph, RRGSB* rr_gsb, /* Find IPINs */ for (size_t inode = 0; inode < rr_gsb->get_num_ipin_nodes(gsb_side); ++inode) { t_rr_node* ipin_node = rr_gsb->get_ipin_node(gsb_side, inode); - /* 1. create edges between SOURCE and OPINs */ + /* 2. create edges between IPINs and SINKs */ int sink_node_id = get_rr_node_index(ipin_node->xlow, ipin_node->ylow, SINK, ipin_node->ptc_num, rr_graph->rr_node_indices); - /* add edges to the src_node */ + /* add edges to connect the IPIN node to SINK nodes */ add_one_edge_for_two_rr_nodes(rr_graph, ipin_node - rr_graph->rr_node, sink_node_id, delayless_switch); } } + + /* 3. create edges between CHANX | CHANY and IPINs (connections inside connection blocks) */ + /* For TOP and BOTTOM */ return; @@ -1393,8 +1401,9 @@ void build_rr_graph_edges(t_rr_graph* rr_graph, const DeviceCoordinator& device_size, std::vector device_chan_width, std::vector segment_inf, - int** Fc_in, int** Fc_out, - enum e_switch_block_type sb_type, int Fs, + int L_num_types, t_type_ptr types, + struct s_ivec**** track_to_ipin_lookup, int***** opin_to_track_map, + vtr::NdMatrix,3> switch_block_conn, int num_directs, t_clb_to_clb_directs* clb_to_clb_directs, int num_switches, int delayless_switch) { DeviceCoordinator device_range(device_size.get_x() - 1, device_size.get_y() - 1); @@ -1404,9 +1413,15 @@ void build_rr_graph_edges(t_rr_graph* rr_graph, DeviceCoordinator gsb_coordinator(ix, iy); /* Create a GSB object */ RRGSB rr_gsb = build_one_tileable_rr_gsb(device_range, device_chan_width, segment_inf, gsb_coordinator, rr_graph); + /* adapt the track_to_ipin_lookup for the GSB nodes */ + std::vector < std::vector< std::vector > > track2ipin_lookup; /* [0..gsb_side][0..num_tracks][0..Fc] */ + /* adapt the opin_to_track_map for the GSB nodes */ + std::vector < std::vector< std::vector > > opin2track_map; /* [0..gsb_side][0..num_opin_node][0..Fc] */ + /* adapt the switch_block_conn for the GSB nodes */ + std::vector < std::vector< std::vector > > sb_conn; /* [0..gsb_side][0..chan_width][0..Fc] */ /* Build edges for a GSB */ - build_edges_for_one_tileable_rr_gsb(rr_graph, &rr_gsb, Fc_in, Fc_out, - sb_type, Fs, + build_edges_for_one_tileable_rr_gsb(rr_graph, &rr_gsb, + track2ipin_lookup, opin2track_map, sb_conn, num_directs, clb_to_clb_directs, num_switches, delayless_switch); /* Finish this GSB, go to the next*/ @@ -1416,6 +1431,76 @@ void build_rr_graph_edges(t_rr_graph* rr_graph, return; } +/************************************************************************ + * Build internal connection pattern for a switch block + * This function is adapt to fit the tileable routing context from + * rr_graph_sbox.c : alloc_and_load_switch_block_conn + * Switch box: * + * TOP (CHANY) * + * | | | | | | * + * +-----------+ * + * --| |-- * + * --| |-- * + * LEFT --| |-- RIGHT * + * (CHANX)--| |--(CHANX) * + * --| |-- * + * --| |-- * + * +-----------+ * + * | | | | | | * + * BOTTOM (CHANY) + * + * [0..3][0..3][0..nodes_per_chan-1]. Structure below is indexed as: * + * [from_side][to_side][from_track]. That yields an integer vector (ivec) * + * of the tracks to which from_track connects in the proper to_location. * + * For simple switch boxes this is overkill, but it will allow complicated * + * switch boxes with Fs > 3, etc. without trouble. + ***********************************************************************/ +static +vtr::NdMatrix,3> alloc_and_load_tileable_switch_block_conn(size_t chan_width, + enum e_switch_block_type switch_block_type, + int Fs) { + + /* Currently Fs must be 3 since each track maps once to each other side */ + VTR_ASSERT(3 == Fs); + + vtr::NdMatrix,3> switch_block_conn({4, 4, chan_width}); + + for (e_side from_side : {TOP, RIGHT, BOTTOM, LEFT}) { + for (e_side to_side : {TOP, RIGHT, BOTTOM, LEFT}) { + for (size_t from_track = 0; from_track < chan_width; from_track++) { + if (from_side != to_side) { + switch_block_conn[from_side][to_side][from_track].resize(1); + + switch_block_conn[from_side][to_side][from_track][0] = get_simple_switch_block_track(from_side, to_side, + from_track, switch_block_type, + chan_width); + } else { /* from_side == to_side -> no connection. */ + switch_block_conn[from_side][to_side][from_track].clear(); + } + } + } + } + + if (getEchoEnabled()) { + FILE *out = fopen("switch_block_conn.echo", "w"); + for (int l = 0; l < 4; ++l) { + for (int k = 0; k < 4; ++k) { + fprintf(out, "Side %d to %d\n", l, k); + for (size_t j = 0; j < chan_width; ++j) { + fprintf(out, "%zu: ", j); + for (unsigned i = 0; i < switch_block_conn[l][k][j].size(); ++i) { + fprintf(out, "%d ", switch_block_conn[l][k][j][i]); + } + fprintf(out, "\n"); + } + fprintf(out, "\n"); + } + } + fclose(out); + } + return switch_block_conn; +} + /************************************************************************ * Main function of this file * Builder for a detailed uni-directional tileable rr_graph @@ -1484,7 +1569,7 @@ void build_tileable_unidir_rr_graph(INP int L_num_types, for (int ix = 0; ix < (L_nx + 2); ++ix) { grids[ix].resize(L_ny + 2); for (int iy = 0; ix < (L_ny + 2); ++iy) { - grid[ix][iy] = L_grid[ix][iy]; + grids[ix][iy] = L_grid[ix][iy]; } } /* Create a vector of channel width, we support X-direction and Y-direction has different W */ @@ -1532,9 +1617,13 @@ void build_tileable_unidir_rr_graph(INP int L_num_types, load_rr_nodes_basic_info(&rr_graph, device_size, grids, device_chan_width, segment_infs); /************************************************************************ - * 3. Create the connectivity of OPINs - * a. Evenly assign connections to OPINs to routing tracks - * b. the connection pattern should be same across the fabric + * 3.1 Create the connectivity of OPINs + * a. Evenly assign connections to OPINs to routing tracks + * b. the connection pattern should be same across the fabric + * + * 3.2 Create the connectivity of IPINs + * a. Evenly assign connections from routing tracks to IPINs + * b. the connection pattern should be same across the fabric ***********************************************************************/ int **Fc_in = NULL; /* [0..num_types-1][0..num_pins-1] */ boolean Fc_clipped; @@ -1545,18 +1634,42 @@ void build_tileable_unidir_rr_graph(INP int L_num_types, *Warnings |= RR_GRAPH_WARN_FC_CLIPPED; } - /************************************************************************ - * 4. Create the connectivity of IPINs - * a. Evenly assign connections from routing tracks to IPINs - * b. the connection pattern should be same across the fabric - ***********************************************************************/ int **Fc_out = NULL; /* [0..num_types-1][0..num_pins-1] */ Fc_clipped = FALSE; Fc_out = alloc_and_load_actual_fc(L_num_types, types, chan_width, TRUE, UNI_DIRECTIONAL, &Fc_clipped, ignore_Fc_0); + if (Fc_clipped) { + *Warnings |= RR_GRAPH_WARN_FC_CLIPPED; + } + + /* START IPINP MAP */ + /* Create ipin map lookups */ + int***** ipin_to_track_map = (int*****) my_calloc(L_num_types, sizeof(int****)); + struct s_ivec**** track_to_ipin_lookup = (struct s_ivec****) my_calloc(L_num_types, sizeof(struct s_ivec***)); + boolean* perturb_ipins = alloc_and_load_perturb_ipins(chan_width, L_num_types, Fc_in, Fc_out, UNI_DIRECTIONAL); + for (int i = 0; i < L_num_types; ++i) { + ipin_to_track_map[i] = alloc_and_load_pin_to_track_map(RECEIVER, chan_width, Fc_in[i], &types[i], + perturb_ipins[i], UNI_DIRECTIONAL); + track_to_ipin_lookup[i] = alloc_and_load_track_to_pin_lookup(ipin_to_track_map[i], Fc_in[i], + types[i].height, types[i].num_pins, chan_width); + } + /* END IPINP MAP */ + + /* START OPINP MAP */ + /* Create opin map lookups */ + int***** opin_to_track_map = (int*****) my_calloc(L_num_types, sizeof(int****)); + for (int i = 0; i < L_num_types; ++i) { + opin_to_track_map[i] = alloc_and_load_pin_to_track_map(DRIVER, chan_width, Fc_out[i], &types[i], FALSE, UNI_DIRECTIONAL); + } + /************************************************************************ - * 5. Build the connections tile by tile: + * 4. Build switch block connection matrix + ***********************************************************************/ + vtr::NdMatrix,3> switch_block_conn = alloc_and_load_tileable_switch_block_conn(chan_width, sb_type, Fs); + + /************************************************************************ + * 6. Build the connections tile by tile: * We classify rr_nodes into a general switch block (GSB) data structure * where we create edges to each rr_nodes in the GSB with respect to * Fc_in and Fc_out, switch block patterns @@ -1571,7 +1684,7 @@ void build_tileable_unidir_rr_graph(INP int L_num_types, /* Create edges for a tileable rr_graph */ build_rr_graph_edges(&rr_graph, device_size, device_chan_width, segment_infs, - Fc_in, Fc_out, sb_type, Fs, + L_num_types, types, track_to_ipin_lookup, opin_to_track_map, switch_block_conn, num_directs, clb_to_clb_directs, num_switches, delayless_switch); /************************************************************************ @@ -1592,6 +1705,37 @@ void build_tileable_unidir_rr_graph(INP int L_num_types, rr_node = rr_graph.rr_node; rr_node_indices = rr_graph.rr_node_indices; + /************************************************************************ + * 9. Free all temp stucts + ***********************************************************************/ + + /* Free all temp structs */ + if (Fc_in) { + free_matrix(Fc_in,0, L_num_types, 0, sizeof(int)); + Fc_in = NULL; + } + if (Fc_out) { + free_matrix(Fc_out,0, L_num_types, 0, sizeof(int)); + Fc_out = NULL; + } + if (perturb_ipins) { + free(perturb_ipins); + perturb_ipins = NULL; + } + if (opin_to_track_map) { + for (int i = 0; i < L_num_types; ++i) { + free_matrix4(opin_to_track_map[i], 0, types[i].num_pins - 1, 0, + types[i].height - 1, 0, 3, 0, sizeof(int)); + } + free(opin_to_track_map); + } + + free_type_pin_to_track_map(ipin_to_track_map, types); + free_type_track_to_ipin_map(track_to_ipin_lookup, types, chan_width); + if(clb_to_clb_directs != NULL) { + free(clb_to_clb_directs); + } + return; } diff --git a/vpr7_x2p/vpr/SRC/route/rr_graph.c b/vpr7_x2p/vpr/SRC/route/rr_graph.c index 800a23441..51c4a5035 100755 --- a/vpr7_x2p/vpr/SRC/route/rr_graph.c +++ b/vpr7_x2p/vpr/SRC/route/rr_graph.c @@ -69,14 +69,6 @@ static t_chunk rr_mem_ch = {NULL, 0, NULL}; /* Status of current chunk being dished out by calls to my_chunk_malloc. */ /********************* Subroutines local to this module. *******************/ -static int ****alloc_and_load_pin_to_track_map(INP enum e_pin_type pin_type, - INP int nodes_per_chan, INP int *Fc, INP t_type_ptr Type, - INP boolean perturb_switch_pattern, - INP enum e_directionality directionality); - -static struct s_ivec ***alloc_and_load_track_to_pin_lookup( - INP int ****pin_to_track_map, INP int *Fc, INP int height, - INP int num_pins, INP int nodes_per_chan); static void build_bidir_rr_opins(INP int i, INP int j, INOUTP t_rr_node * L_rr_node, INP t_ivec *** L_rr_node_indices, @@ -124,10 +116,6 @@ static void check_all_tracks_reach_pins(t_type_ptr type, int ****tracks_connected_to_pin, int nodes_per_chan, int Fc, enum e_pin_type ipin_or_opin); -static boolean *alloc_and_load_perturb_ipins(INP int nodes_per_chan, - INP int L_num_types, INP int **Fc_in, INP int **Fc_out, - INP enum e_directionality directionality); - static void build_rr_sinks_sources(INP int i, INP int j, INP t_rr_node * L_rr_node, INP t_ivec *** L_rr_node_indices, INP int delayless_switch, INP struct s_grid_tile **L_grid); @@ -188,11 +176,6 @@ static void print_distribution(FILE * fptr, t_mux_size_distribution * distr_struct); #endif -static void free_type_pin_to_track_map(int***** ipin_to_track_map, - t_type_ptr types); - -static void free_type_track_to_ipin_map(struct s_ivec**** track_to_pin_map, - t_type_ptr types, int nodes_per_chan); static t_seg_details *alloc_and_load_global_route_seg_details( INP int nodes_per_chan, INP int global_route_switch); @@ -543,7 +526,7 @@ void rr_graph_externals(t_timing_inf timing_inf, alloc_and_load_rr_clb_source(rr_node_indices); } -static boolean * +boolean * alloc_and_load_perturb_ipins(INP int nodes_per_chan, INP int L_num_types, INP int **Fc_in, INP int **Fc_out, INP enum e_directionality directionality) { int i; @@ -675,7 +658,7 @@ alloc_and_load_actual_fc(INP int L_num_types, INP t_type_ptr types, } /* frees the track to ipin mapping for each physical grid type */ -static void free_type_track_to_ipin_map(struct s_ivec**** track_to_pin_map, +void free_type_track_to_ipin_map(struct s_ivec**** track_to_pin_map, t_type_ptr types, int nodes_per_chan) { int i, itrack, ioff, iside; for (i = 0; i < num_types; i++) { @@ -698,7 +681,7 @@ static void free_type_track_to_ipin_map(struct s_ivec**** track_to_pin_map, } /* frees the ipin to track mapping for each physical grid type */ -static void free_type_pin_to_track_map(int***** ipin_to_track_map, +void free_type_pin_to_track_map(int***** ipin_to_track_map, t_type_ptr types) { int i; for (i = 0; i < num_types; i++) { @@ -1532,7 +1515,7 @@ void alloc_and_load_edges_and_switches(INP t_rr_node * L_rr_node, INP int inode, assert(i == num_edges); } -static int **** +int **** alloc_and_load_pin_to_track_map(INP enum e_pin_type pin_type, INP int nodes_per_chan, INP int *Fc, INP t_type_ptr Type, INP boolean perturb_switch_pattern, @@ -1873,7 +1856,7 @@ static void check_all_tracks_reach_pins(t_type_ptr type, /* Allocates and loads the track to ipin lookup for each physical grid type. This * is the same information as the ipin_to_track map but accessed in a different way. */ -static struct s_ivec *** +struct s_ivec *** alloc_and_load_track_to_pin_lookup(INP int ****pin_to_track_map, INP int *Fc, INP int height, INP int num_pins, INP int nodes_per_chan) { int ipin, iside, itrack, iconn, ioff, pin_counter; diff --git a/vpr7_x2p/vpr/SRC/route/rr_graph.h b/vpr7_x2p/vpr/SRC/route/rr_graph.h index 5251bf8b5..c8cb18aa3 100755 --- a/vpr7_x2p/vpr/SRC/route/rr_graph.h +++ b/vpr7_x2p/vpr/SRC/route/rr_graph.h @@ -63,5 +63,27 @@ void rr_graph_externals(t_timing_inf timing_inf, t_segment_inf * segment_inf, int num_seg_types, int nodes_per_chan, int wire_to_ipin_switch, enum e_base_cost_type base_cost_type); +/* Xifan Tang: Functions shared by tileable rr_graph generator */ + +int ****alloc_and_load_pin_to_track_map(INP enum e_pin_type pin_type, + INP int nodes_per_chan, INP int *Fc, INP t_type_ptr Type, + INP boolean perturb_switch_pattern, + INP enum e_directionality directionality); + +struct s_ivec ***alloc_and_load_track_to_pin_lookup( + INP int ****pin_to_track_map, INP int *Fc, INP int height, + INP int num_pins, INP int nodes_per_chan); + +boolean * +alloc_and_load_perturb_ipins(INP int nodes_per_chan, INP int L_num_types, + INP int **Fc_in, INP int **Fc_out, INP enum e_directionality directionality); + +void free_type_pin_to_track_map(int***** ipin_to_track_map, + t_type_ptr types); + +void free_type_track_to_ipin_map(struct s_ivec**** track_to_pin_map, + t_type_ptr types, int nodes_per_chan); + + #endif From ba153585645838ec457e54d6510f91e6c37d3e8e Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 18 Jun 2019 18:06:21 -0600 Subject: [PATCH 08/25] developing ipin2track mapping for tiles --- .../rr_graph/rr_graph_tileable_builder.c | 137 +++++------- .../rr_graph/rr_graph_tileable_sbox.cpp | 211 ++++++++++++++++++ .../device/rr_graph/rr_graph_tileable_sbox.h | 12 + 3 files changed, 279 insertions(+), 81 deletions(-) create mode 100755 vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_sbox.cpp create mode 100755 vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_sbox.h diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c index 4aaffddc1..54cea15ea 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c @@ -56,7 +56,7 @@ #include "ReadOptions.h" #include "rr_graph.h" #include "rr_graph2.h" -#include "rr_graph_sbox.h" +#include "rr_graph_tileable_sbox.h" #include "route_common.h" #include "fpga_x2p_types.h" #include "rr_graph_tileable_builder.h" @@ -1384,6 +1384,52 @@ void build_edges_for_one_tileable_rr_gsb(t_rr_graph* rr_graph, RRGSB* rr_gsb, return; } +/************************************************************************ + * Convert the track_to_ipin_look[0..nodes_per_chan-1][0..height][0..3][pin_numbers] + * to the existing routing resources in the General Switch Block (GSB) + * The resulting matrix will be oragnized in + * track2ipin_lookup[gsb_side][0..chan_width-1][ipin_indices] + ***********************************************************************/ +static +std::vector < std::vector< std::vector > > build_gsb_track_to_ipin_lookup(const RRGSB& rr_gsb, + std::vector< std::vector > grids, + int** Fc_in, + int***** ipin_to_track_map) { + std::vector < std::vector< std::vector > > track2ipin_lookup; /* [0..gsb_side][0..num_tracks][0..Fc-1] */ + /* Resize the matrix */ + track2ipin_lookup.resize(rr_gsb.get_num_sides()); + + /* Walk through each side */ + for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { + Side side_manager(side); + enum e_side gsb_side = side_manager.get_side(); + /* Get channel width and resize the matrix */ + size_t chan_width = rr_gsb.get_chan_width(gsb_side); + track2ipin_lookup[side].resize(chan_width); + /* Find the ipin nodes */ + for (size_t inode = 0; inode < rr_gsb.get_num_ipin_nodes(gsb_side); ++inode) { + t_rr_node* ipin_node = rr_gsb.get_ipin_node(gsb_side, inode); + /* For each IPIN, we find the type_descriptor, offset and pin_side on the grid */ + int grid_type_id = grids[ipin_node->xlow][ipin_node->ylow].type->index; + int offset = grid[ipin_node->xlow][ipin_node->ylow].offset; + enum e_side pin_side = rr_gsb.get_ipin_node_grid_side(gsb_side, inode); + /* Now, we fill the return matrix */ + /* Bypass empty array */ + if (NULL == ipin_to_track_map[grid_type_id][ipin_node->ptc_num][offset][0]) { + continue; + } + /* Get each track_id */ + for (int iconn = 0; iconn < Fc_in[grid_type_id][ipin_node->ptc_num]; ++iconn) { + int track_id = ipin_to_track_map[grid_type_id][ipin_node->ptc_num][offset][pin_side][iconn]; + track2ipin_lookup[gsb_side][track_id].push_back(inode); + } + } + } + + return track2ipin_lookup; +} + + /************************************************************************ * Build the edges of each rr_node tile by tile: * We classify rr_nodes into a general switch block (GSB) data structure @@ -1399,10 +1445,12 @@ void build_edges_for_one_tileable_rr_gsb(t_rr_graph* rr_graph, RRGSB* rr_gsb, static void build_rr_graph_edges(t_rr_graph* rr_graph, const DeviceCoordinator& device_size, + std::vector< std::vector > grids, std::vector device_chan_width, std::vector segment_inf, int L_num_types, t_type_ptr types, - struct s_ivec**** track_to_ipin_lookup, int***** opin_to_track_map, + int** Fc_in, int** Fc_out, + int***** ipin_to_track_map, int***** opin_to_track_map, vtr::NdMatrix,3> switch_block_conn, int num_directs, t_clb_to_clb_directs* clb_to_clb_directs, int num_switches, int delayless_switch) { @@ -1414,11 +1462,12 @@ void build_rr_graph_edges(t_rr_graph* rr_graph, /* Create a GSB object */ RRGSB rr_gsb = build_one_tileable_rr_gsb(device_range, device_chan_width, segment_inf, gsb_coordinator, rr_graph); /* adapt the track_to_ipin_lookup for the GSB nodes */ - std::vector < std::vector< std::vector > > track2ipin_lookup; /* [0..gsb_side][0..num_tracks][0..Fc] */ + std::vector < std::vector< std::vector > > track2ipin_lookup; /* [0..gsb_side][0..num_tracks][0..Fc-1] */ + track2ipin_lookup = build_gsb_track_to_ipin_lookup(rr_gsb, grids, Fc_in, ipin_to_track_map); /* adapt the opin_to_track_map for the GSB nodes */ - std::vector < std::vector< std::vector > > opin2track_map; /* [0..gsb_side][0..num_opin_node][0..Fc] */ + std::vector < std::vector< std::vector > > opin2track_map; /* [0..gsb_side][0..num_opin_node][0..Fc-1] */ /* adapt the switch_block_conn for the GSB nodes */ - std::vector < std::vector< std::vector > > sb_conn; /* [0..gsb_side][0..chan_width][0..Fc] */ + std::vector < std::vector< std::vector > > sb_conn; /* [0..from_gsb_side][0..to_gsb_side][0..chan_width-1] */ /* Build edges for a GSB */ build_edges_for_one_tileable_rr_gsb(rr_graph, &rr_gsb, track2ipin_lookup, opin2track_map, sb_conn, @@ -1431,76 +1480,6 @@ void build_rr_graph_edges(t_rr_graph* rr_graph, return; } -/************************************************************************ - * Build internal connection pattern for a switch block - * This function is adapt to fit the tileable routing context from - * rr_graph_sbox.c : alloc_and_load_switch_block_conn - * Switch box: * - * TOP (CHANY) * - * | | | | | | * - * +-----------+ * - * --| |-- * - * --| |-- * - * LEFT --| |-- RIGHT * - * (CHANX)--| |--(CHANX) * - * --| |-- * - * --| |-- * - * +-----------+ * - * | | | | | | * - * BOTTOM (CHANY) - * - * [0..3][0..3][0..nodes_per_chan-1]. Structure below is indexed as: * - * [from_side][to_side][from_track]. That yields an integer vector (ivec) * - * of the tracks to which from_track connects in the proper to_location. * - * For simple switch boxes this is overkill, but it will allow complicated * - * switch boxes with Fs > 3, etc. without trouble. - ***********************************************************************/ -static -vtr::NdMatrix,3> alloc_and_load_tileable_switch_block_conn(size_t chan_width, - enum e_switch_block_type switch_block_type, - int Fs) { - - /* Currently Fs must be 3 since each track maps once to each other side */ - VTR_ASSERT(3 == Fs); - - vtr::NdMatrix,3> switch_block_conn({4, 4, chan_width}); - - for (e_side from_side : {TOP, RIGHT, BOTTOM, LEFT}) { - for (e_side to_side : {TOP, RIGHT, BOTTOM, LEFT}) { - for (size_t from_track = 0; from_track < chan_width; from_track++) { - if (from_side != to_side) { - switch_block_conn[from_side][to_side][from_track].resize(1); - - switch_block_conn[from_side][to_side][from_track][0] = get_simple_switch_block_track(from_side, to_side, - from_track, switch_block_type, - chan_width); - } else { /* from_side == to_side -> no connection. */ - switch_block_conn[from_side][to_side][from_track].clear(); - } - } - } - } - - if (getEchoEnabled()) { - FILE *out = fopen("switch_block_conn.echo", "w"); - for (int l = 0; l < 4; ++l) { - for (int k = 0; k < 4; ++k) { - fprintf(out, "Side %d to %d\n", l, k); - for (size_t j = 0; j < chan_width; ++j) { - fprintf(out, "%zu: ", j); - for (unsigned i = 0; i < switch_block_conn[l][k][j].size(); ++i) { - fprintf(out, "%d ", switch_block_conn[l][k][j][i]); - } - fprintf(out, "\n"); - } - fprintf(out, "\n"); - } - } - fclose(out); - } - return switch_block_conn; -} - /************************************************************************ * Main function of this file * Builder for a detailed uni-directional tileable rr_graph @@ -1646,13 +1625,10 @@ void build_tileable_unidir_rr_graph(INP int L_num_types, /* START IPINP MAP */ /* Create ipin map lookups */ int***** ipin_to_track_map = (int*****) my_calloc(L_num_types, sizeof(int****)); - struct s_ivec**** track_to_ipin_lookup = (struct s_ivec****) my_calloc(L_num_types, sizeof(struct s_ivec***)); boolean* perturb_ipins = alloc_and_load_perturb_ipins(chan_width, L_num_types, Fc_in, Fc_out, UNI_DIRECTIONAL); for (int i = 0; i < L_num_types; ++i) { ipin_to_track_map[i] = alloc_and_load_pin_to_track_map(RECEIVER, chan_width, Fc_in[i], &types[i], perturb_ipins[i], UNI_DIRECTIONAL); - track_to_ipin_lookup[i] = alloc_and_load_track_to_pin_lookup(ipin_to_track_map[i], Fc_in[i], - types[i].height, types[i].num_pins, chan_width); } /* END IPINP MAP */ @@ -1683,8 +1659,8 @@ void build_tileable_unidir_rr_graph(INP int L_num_types, } /* Create edges for a tileable rr_graph */ - build_rr_graph_edges(&rr_graph, device_size, device_chan_width, segment_infs, - L_num_types, types, track_to_ipin_lookup, opin_to_track_map, switch_block_conn, + build_rr_graph_edges(&rr_graph, device_size, grids, device_chan_width, segment_infs, + L_num_types, types, Fc_in, Fc_out, ipin_to_track_map, opin_to_track_map, switch_block_conn, num_directs, clb_to_clb_directs, num_switches, delayless_switch); /************************************************************************ @@ -1731,7 +1707,6 @@ void build_tileable_unidir_rr_graph(INP int L_num_types, } free_type_pin_to_track_map(ipin_to_track_map, types); - free_type_track_to_ipin_map(track_to_ipin_lookup, types, chan_width); if(clb_to_clb_directs != NULL) { free(clb_to_clb_directs); } diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_sbox.cpp b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_sbox.cpp new file mode 100755 index 000000000..f30ceed2d --- /dev/null +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_sbox.cpp @@ -0,0 +1,211 @@ +#include "vtr_assert.h" + +#include "vtr_util.h" +#include "vtr_memory.h" + +#include "vpr_types.h" +#include "rr_graph_tileable_sbox.h" +#include "rr_graph_util.h" +#include "ReadOptions.h" + +static +int get_tileable_simple_switch_block_track(const enum e_side from_side, + const enum e_side to_side, const int from_track, + const enum e_switch_block_type switch_block_type, const int nodes_per_chan); + +/************************************************************************ + * Build internal connection pattern for a switch block + * This function is adapt to fit the tileable routing context from + * rr_graph_sbox.c : alloc_and_load_switch_block_conn + * Switch box: * + * TOP (CHANY) * + * | | | | | | * + * +-----------+ * + * --| |-- * + * --| |-- * + * LEFT --| |-- RIGHT * + * (CHANX)--| |--(CHANX) * + * --| |-- * + * --| |-- * + * +-----------+ * + * | | | | | | * + * BOTTOM (CHANY) * + * + * [0..3][0..3][0..nodes_per_chan-1]. Structure below is indexed as: * + * [from_side][to_side][from_track]. That yields an integer vector (ivec) * + * of the tracks to which from_track connects in the proper to_location. * + * For simple switch boxes this is overkill, but it will allow complicated * + * switch boxes with Fs > 3, etc. without trouble. * + ***********************************************************************/ + +/* Allocates and loads the switch_block_conn data structure. This structure * + * lists which tracks connect to which at each switch block. This is for + * bidir. */ +vtr::NdMatrix,3> alloc_and_load_tileable_switch_block_conn(const size_t nodes_per_chan, + const e_switch_block_type switch_block_type, + const int Fs) { + + /* Currently Fs must be 3 since each track maps once to each other side */ + VTR_ASSERT(3 == Fs); + + vtr::NdMatrix,3> switch_block_conn({4, 4, nodes_per_chan}); + + for (e_side from_side : {TOP, RIGHT, BOTTOM, LEFT}) { + for (e_side to_side : {TOP, RIGHT, BOTTOM, LEFT}) { + for (size_t from_track = 0; from_track < nodes_per_chan; from_track++) { + if (from_side != to_side) { + switch_block_conn[from_side][to_side][from_track].resize(1); + + switch_block_conn[from_side][to_side][from_track][0] = get_tileable_simple_switch_block_track(from_side, to_side, + from_track, switch_block_type, nodes_per_chan); + } else { /* from_side == to_side -> no connection. */ + switch_block_conn[from_side][to_side][from_track].clear(); + } + } + } + } + + if (getEchoEnabled()) { + FILE *out = vtr::fopen("switch_block_conn.echo", "w"); + for (int l = 0; l < 4; ++l) { + for (int k = 0; k < 4; ++k) { + fprintf(out, "Side %d to %d\n", l, k); + for (size_t j = 0; j < nodes_per_chan; ++j) { + fprintf(out, "%zu: ", j); + for (unsigned i = 0; i < switch_block_conn[l][k][j].size(); ++i) { + fprintf(out, "%d ", switch_block_conn[l][k][j][i]); + } + fprintf(out, "\n"); + } + fprintf(out, "\n"); + } + } + fclose(out); + } + return switch_block_conn; +} + +#define SBOX_ERROR -1 + +/* This routine permutes the track number to connect for topologies + * SUBSET, UNIVERSAL, and WILTON. I added FULL (for fully flexible topology) + * but the returned value is simply a dummy, since we don't need to permute + * what connections to make for FULL (connect to EVERYTHING) */ +static +int get_tileable_simple_switch_block_track(const enum e_side from_side, + const enum e_side to_side, const int from_track, + const enum e_switch_block_type switch_block_type, const int nodes_per_chan) { + + /* This routine returns the track number to which the from_track should * + * connect. It supports three simple, Fs = 3, switch blocks. */ + + int to_track = SBOX_ERROR; /* Can check to see if it's not set later. */ + + if (switch_block_type == SUBSET) { /* NB: Global routing uses SUBSET too */ + to_track = from_track; + } + + /* See S. Wilton Phd thesis, U of T, 1996 p. 103 for details on following. */ + + else if (switch_block_type == WILTON) { + + if (from_side == LEFT) { + + if (to_side == RIGHT) { /* CHANX to CHANX */ + to_track = from_track; + } else if (to_side == TOP) { /* from CHANX to CHANY */ + to_track = (nodes_per_chan - (from_track % nodes_per_chan)) % nodes_per_chan; + } else if (to_side == BOTTOM) { + to_track = (nodes_per_chan + from_track - 1) % nodes_per_chan; + } + } + + else if (from_side == RIGHT) { + if (to_side == LEFT) { /* CHANX to CHANX */ + to_track = from_track; + } else if (to_side == TOP) { /* from CHANX to CHANY */ + to_track = (nodes_per_chan + from_track - 1) % nodes_per_chan; + } else if (to_side == BOTTOM) { + to_track = (2 * nodes_per_chan - 2 - from_track) % nodes_per_chan; + } + } + + else if (from_side == BOTTOM) { + if (to_side == TOP) { /* CHANY to CHANY */ + to_track = from_track; + } else if (to_side == LEFT) { /* from CHANY to CHANX */ + to_track = (from_track + 1) % nodes_per_chan; + } else if (to_side == RIGHT) { + to_track = (2 * nodes_per_chan - 2 - from_track) % nodes_per_chan; + } + } + + else if (from_side == TOP) { + if (to_side == BOTTOM) { /* CHANY to CHANY */ + to_track = from_track; + } else if (to_side == LEFT) { /* from CHANY to CHANX */ + to_track = (nodes_per_chan - (from_track % nodes_per_chan)) % nodes_per_chan; + } else if (to_side == RIGHT) { + to_track = (from_track + 1) % nodes_per_chan; + } + } + + /* Force to_track to UN_SET if it falls outside the min/max channel width range */ + if (to_track < 0 || to_track >= nodes_per_chan) { + to_track = -1; + } + } + /* End switch_block_type == WILTON case. */ + else if (switch_block_type == UNIVERSAL) { + + if (from_side == LEFT) { + + if (to_side == RIGHT) { /* CHANX to CHANX */ + to_track = from_track; + } else if (to_side == TOP) { /* from CHANX to CHANY */ + to_track = nodes_per_chan - 1 - from_track; + } else if (to_side == BOTTOM) { + to_track = from_track; + } + } + + else if (from_side == RIGHT) { + if (to_side == LEFT) { /* CHANX to CHANX */ + to_track = from_track; + } else if (to_side == TOP) { /* from CHANX to CHANY */ + to_track = from_track; + } else if (to_side == BOTTOM) { + to_track = nodes_per_chan - 1 - from_track; + } + } + + else if (from_side == BOTTOM) { + if (to_side == TOP) { /* CHANY to CHANY */ + to_track = from_track; + } else if (to_side == LEFT) { /* from CHANY to CHANX */ + to_track = from_track; + } else if (to_side == RIGHT) { + to_track = nodes_per_chan - 1 - from_track; + } + } + + else if (from_side == TOP) { + if (to_side == BOTTOM) { /* CHANY to CHANY */ + to_track = from_track; + } else if (to_side == LEFT) { /* from CHANY to CHANX */ + to_track = nodes_per_chan - 1 - from_track; + } else if (to_side == RIGHT) { + to_track = from_track; + } + } + } + + /* End switch_block_type == UNIVERSAL case. */ + /* UDSD Modification by WMF Begin */ + if (switch_block_type == FULL) { /* Just a placeholder. No meaning in reality */ + to_track = from_track; + } + /* UDSD Modification by WMF End */ + + return (to_track); +} diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_sbox.h b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_sbox.h new file mode 100755 index 000000000..93f3ea5ea --- /dev/null +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_sbox.h @@ -0,0 +1,12 @@ +#ifndef RR_GRAPH_TILEABLE_SBOX_H +#define RR_GRAPH_TILEABLE_SBOX_H + +#include + +#include "vtr_ndmatrix.h" + +vtr::NdMatrix,3> alloc_and_load_tileable_switch_block_conn(size_t nodes_per_chan, + enum e_switch_block_type switch_block_type, int Fs); + +#endif + From 2f15d2d13cb064b05fbf17006ef1bf9e5ba000e2 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 19 Jun 2019 21:30:16 -0600 Subject: [PATCH 09/25] keep developing tileable rr_graph, track2ipin and opin2track to go --- .../rr_graph/rr_graph_tileable_builder.c | 371 ++++++++-- .../rr_graph/rr_graph_tileable_builder.h | 2 +- .../rr_graph/rr_graph_tileable_sbox.cpp | 644 ++++++++++++------ .../device/rr_graph/rr_graph_tileable_sbox.h | 12 +- .../vpr/SRC/fpga_x2p/base/fpga_x2p_types.h | 6 + vpr7_x2p/vpr/SRC/route/route_common.h | 5 +- 6 files changed, 771 insertions(+), 269 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c index 54cea15ea..58010142e 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c @@ -56,7 +56,6 @@ #include "ReadOptions.h" #include "rr_graph.h" #include "rr_graph2.h" -#include "rr_graph_tileable_sbox.h" #include "route_common.h" #include "fpga_x2p_types.h" #include "rr_graph_tileable_builder.h" @@ -66,6 +65,13 @@ #include "rr_blocks.h" #include "chan_node_details.h" #include "device_coordinator.h" +#include "rr_graph_tileable_sbox.h" + +/************************************************************************ + * Local data stuctures in the file + ***********************************************************************/ +typedef std::vector>> t_track2pin_map; +typedef std::vector>> t_pin2track_map; /************************************************************************ * Local function in the file @@ -538,8 +544,11 @@ void load_one_node_to_rr_graph_fast_lookup(t_rr_graph* rr_graph, int node_index, ***********************************************************************/ static void load_one_grid_rr_nodes_basic_info(const DeviceCoordinator& grid_coordinator, - const t_grid_tile& cur_grid, enum e_side io_side, - t_rr_graph* rr_graph, size_t* cur_node_id) { + const t_grid_tile& cur_grid, + enum e_side io_side, + t_rr_graph* rr_graph, + size_t* cur_node_id, + int wire_to_ipin_switch, int delayless_switch) { Side io_side_manager(io_side); /* Walk through the height of each grid, * get pins and configure the rr_nodes */ @@ -565,6 +574,10 @@ void load_one_grid_rr_nodes_basic_info(const DeviceCoordinator& grid_coordinator rr_graph->rr_node[*cur_node_id].ptc_num = opin_list[pin]; rr_graph->rr_node[*cur_node_id].capacity = 1; rr_graph->rr_node[*cur_node_id].occ = 0; + /* cost index is a FIXED value for OPIN */ + rr_graph->rr_node[*cur_node_id].cost_index = OPIN_COST_INDEX; + /* Switch info */ + rr_graph->rr_node[*cur_node_id].driver_switch = delayless_switch; /* fill fast look-up table */ load_one_node_to_rr_graph_fast_lookup(rr_graph, *cur_node_id, rr_graph->rr_node[*cur_node_id].type, @@ -586,6 +599,10 @@ void load_one_grid_rr_nodes_basic_info(const DeviceCoordinator& grid_coordinator rr_graph->rr_node[*cur_node_id].ptc_num = opin_list[pin]; rr_graph->rr_node[*cur_node_id].capacity = 1; rr_graph->rr_node[*cur_node_id].occ = 0; + /* cost index is a FIXED value for IPIN */ + rr_graph->rr_node[*cur_node_id].cost_index = IPIN_COST_INDEX; + /* Switch info */ + rr_graph->rr_node[*cur_node_id].driver_switch = wire_to_ipin_switch; /* fill fast look-up table */ load_one_node_to_rr_graph_fast_lookup(rr_graph, *cur_node_id, rr_graph->rr_node[*cur_node_id].type, @@ -612,6 +629,15 @@ void load_one_grid_rr_nodes_basic_info(const DeviceCoordinator& grid_coordinator /* FIXME: need to confirm if the capacity should be the number of pins in this class*/ rr_graph->rr_node[*cur_node_id].capacity = cur_grid.type->class_inf[iclass].num_pins; rr_graph->rr_node[*cur_node_id].occ = 0; + /* cost index is a FIXED value for SOURCE and SINK */ + if (SOURCE == rr_graph->rr_node[*cur_node_id].type) { + rr_graph->rr_node[*cur_node_id].cost_index = SOURCE_COST_INDEX; + } + if (SINK == rr_graph->rr_node[*cur_node_id].type) { + rr_graph->rr_node[*cur_node_id].cost_index = SINK_COST_INDEX; + } + /* Switch info */ + rr_graph->rr_node[*cur_node_id].driver_switch = delayless_switch; /* TODO: should we set pb_graph_pin here? */ /* fill fast look-up table */ load_one_node_to_rr_graph_fast_lookup(rr_graph, *cur_node_id, @@ -635,8 +661,10 @@ void load_one_grid_rr_nodes_basic_info(const DeviceCoordinator& grid_coordinator ***********************************************************************/ static void load_one_chan_rr_nodes_basic_info(const DeviceCoordinator& chan_coordinator, - t_rr_type chan_type, + const t_rr_type chan_type, ChanNodeDetails* chan_details, + const std::vector segment_infs, + const int cost_index_offset, t_rr_graph* rr_graph, size_t* cur_node_id) { /* Check each node_id(potential ptc_num) in the channel : @@ -657,8 +685,13 @@ void load_one_chan_rr_nodes_basic_info(const DeviceCoordinator& chan_coordinator rr_graph->rr_node[*cur_node_id].track_ids.push_back(itrack); rr_graph->rr_node[*cur_node_id].capacity = 1; rr_graph->rr_node[*cur_node_id].occ = 0; + /* assign switch id */ + size_t seg_id = chan_details->get_track_segment_id(itrack); + rr_graph->rr_node[*cur_node_id].driver_switch = segment_infs[seg_id].opin_switch; /* Update chan_details with node_id */ chan_details->set_track_node_id(itrack, *cur_node_id); + /* cost index depends on the segment index */ + rr_graph->rr_node[*cur_node_id].cost_index = cost_index_offset + seg_id; /* Update node counter */ (*cur_node_id)++; /* Finish here, go to next */ @@ -677,6 +710,11 @@ void load_one_chan_rr_nodes_basic_info(const DeviceCoordinator& chan_coordinator rr_graph->rr_node[*cur_node_id].occ = 0; /* Update chan_details with node_id */ chan_details->set_track_node_id(itrack, *cur_node_id); + /* assign switch id */ + size_t seg_id = chan_details->get_track_segment_id(itrack); + rr_graph->rr_node[*cur_node_id].driver_switch = segment_infs[seg_id].opin_switch; + /* cost index depends on the segment index */ + rr_graph->rr_node[*cur_node_id].cost_index = cost_index_offset + seg_id; /* Update node counter */ (*cur_node_id)++; /* Finish here, go to next */ @@ -755,7 +793,8 @@ void load_rr_nodes_basic_info(t_rr_graph* rr_graph, const DeviceCoordinator& device_size, std::vector> grids, std::vector chan_width, - std::vector segment_infs) { + std::vector segment_infs, + int wire_to_ipin_switch, int delayless_switch) { /* counter */ size_t cur_node_id = 0; /* configure by node type */ @@ -780,7 +819,8 @@ void load_rr_nodes_basic_info(t_rr_graph* rr_graph, } /* Configure rr_nodes for this grid */ load_one_grid_rr_nodes_basic_info(grid_coordinator, grid[ix][iy], io_side, - rr_graph, &cur_node_id); + rr_graph, &cur_node_id, + wire_to_ipin_switch, delayless_switch); } } @@ -799,7 +839,10 @@ void load_rr_nodes_basic_info(t_rr_graph* rr_graph, } ChanNodeDetails chanx_details = build_unidir_chan_node_details(chan_width[0], device_size.get_x() - 2, chan_side, segment_infs); /* Configure CHANX in this channel */ - load_one_chan_rr_nodes_basic_info(chan_coordinator, CHANX, &chanx_details, + load_one_chan_rr_nodes_basic_info(chan_coordinator, CHANX, + &chanx_details, + segment_infs, + CHANX_COST_INDEX_START, rr_graph, &cur_node_id); /* Rotate the chanx_details by an offset of 1*/ /* For INC_DIRECTION, we use clockwise rotation @@ -834,7 +877,10 @@ void load_rr_nodes_basic_info(t_rr_graph* rr_graph, } ChanNodeDetails chany_details = build_unidir_chan_node_details(chan_width[1], device_size.get_y() - 2, chan_side, segment_infs); /* Configure CHANX in this channel */ - load_one_chan_rr_nodes_basic_info(chan_coordinator, CHANY, &chany_details, + load_one_chan_rr_nodes_basic_info(chan_coordinator, CHANY, + &chany_details, + segment_infs, + CHANX_COST_INDEX_START + segment_infs.size(), rr_graph, &cur_node_id); /* Rotate the chany_details by an offset of 1*/ /* For INC_DIRECTION, we use clockwise rotation @@ -1341,11 +1387,9 @@ void add_one_edge_for_two_rr_nodes(t_rr_graph* rr_graph, ***********************************************************************/ static void build_edges_for_one_tileable_rr_gsb(t_rr_graph* rr_graph, RRGSB* rr_gsb, - std::vector < std::vector< std::vector > > track2ipin_lookup, - std::vector < std::vector< std::vector > > opin2track_map, - std::vector < std::vector< std::vector > > sb_conn, - int num_directs, t_clb_to_clb_directs* clb_to_clb_directs, - int num_switches, int delayless_switch) { + t_track2pin_map track2ipin_map, + t_pin2track_map opin2track_map, + t_track2track_map track2track_map) { /* Check rr_gsb */ assert (NULL != rr_gsb); @@ -1353,6 +1397,7 @@ void build_edges_for_one_tileable_rr_gsb(t_rr_graph* rr_graph, RRGSB* rr_gsb, for (size_t side = 0; side < rr_gsb->get_num_sides(); ++side) { Side side_manager(side); enum e_side gsb_side = side_manager.get_side(); + /* Find OPINs */ for (size_t inode = 0; inode < rr_gsb->get_num_opin_nodes(gsb_side); ++inode) { t_rr_node* opin_node = rr_gsb->get_opin_node(gsb_side, inode); @@ -1362,42 +1407,69 @@ void build_edges_for_one_tileable_rr_gsb(t_rr_graph* rr_graph, RRGSB* rr_gsb, rr_graph->rr_node_indices); /* add edges to the src_node */ add_one_edge_for_two_rr_nodes(rr_graph, src_node_id, opin_node - rr_graph->rr_node, - delayless_switch); + opin_node->driver_switch); + /* 2. create edges between OPINs and CHANX|CHANY, using opin2track_map */ + int num_edges = opin2track_map[side_manager.to_size_t()][inode].size(); + for (int iedge = 0; iedge < num_edges; ++iedge) { + int track_node_id = opin2track_map[side_manager.to_size_t()][inode][iedge]; + /* add edges to the chan_node */ + add_one_edge_for_two_rr_nodes(rr_graph, opin_node - rr_graph->rr_node, track_node_id, + rr_graph->rr_node[track_node_id].driver_switch); + } } + /* Find IPINs */ for (size_t inode = 0; inode < rr_gsb->get_num_ipin_nodes(gsb_side); ++inode) { t_rr_node* ipin_node = rr_gsb->get_ipin_node(gsb_side, inode); - /* 2. create edges between IPINs and SINKs */ + /* 3. create edges between IPINs and SINKs */ int sink_node_id = get_rr_node_index(ipin_node->xlow, ipin_node->ylow, SINK, ipin_node->ptc_num, rr_graph->rr_node_indices); /* add edges to connect the IPIN node to SINK nodes */ add_one_edge_for_two_rr_nodes(rr_graph, ipin_node - rr_graph->rr_node, sink_node_id, - delayless_switch); + rr_graph->rr_node[sink_node_id].driver_switch); + } + /* Find CHANX or CHANY */ + for (size_t inode = 0; inode < rr_gsb->get_chan_width(gsb_side); ++inode) { + t_rr_node* chan_node = rr_gsb->get_chan_node(gsb_side, inode); + /* 4. create edges between CHANX|CHANY and IPINs, using ipin2track_map */ + int num_edges = track2ipin_map[side_manager.to_size_t()][inode].size(); + for (int iedge = 0; iedge < num_edges; ++iedge) { + int ipin_node_id = track2ipin_map[side_manager.to_size_t()][inode][iedge]; + /* add edges to the chan_node */ + add_one_edge_for_two_rr_nodes(rr_graph, chan_node - rr_graph->rr_node, ipin_node_id, + rr_graph->rr_node[ipin_node_id].driver_switch); + } + /* 5. create edges between CHANX|CHANY and CHANX|CHANY, using track2track_map */ + num_edges = track2track_map[side_manager.to_size_t()][inode].size(); + for (int iedge = 0; iedge < num_edges; ++iedge) { + int track_node_id = track2track_map[side_manager.to_size_t()][inode][iedge]; + /* add edges to the chan_node */ + add_one_edge_for_two_rr_nodes(rr_graph, chan_node - rr_graph->rr_node, track_node_id, + rr_graph->rr_node[track_node_id].driver_switch); + } } } - /* 3. create edges between CHANX | CHANY and IPINs (connections inside connection blocks) */ - /* For TOP and BOTTOM */ - - return; } /************************************************************************ - * Convert the track_to_ipin_look[0..nodes_per_chan-1][0..height][0..3][pin_numbers] + * Convert the pin_to_track_map[0..nodes_per_chan-1][0..height][0..3][pin_numbers] * to the existing routing resources in the General Switch Block (GSB) * The resulting matrix will be oragnized in - * track2ipin_lookup[gsb_side][0..chan_width-1][ipin_indices] + * pin2track_map[gsb_side][0..chan_width-1][ipin_indices] ***********************************************************************/ static -std::vector < std::vector< std::vector > > build_gsb_track_to_ipin_lookup(const RRGSB& rr_gsb, - std::vector< std::vector > grids, - int** Fc_in, - int***** ipin_to_track_map) { - std::vector < std::vector< std::vector > > track2ipin_lookup; /* [0..gsb_side][0..num_tracks][0..Fc-1] */ +t_pin2track_map build_gsb_pin_to_track_map(const RRGSB& rr_gsb, + std::vector< std::vector > grids, + int** Fc, + bool is_Fc_out, + int***** pin_to_track_map) { + /* [0..gsb_side][0..num_tracks][0..Fc-1] */ + t_pin2track_map pin2track_map; /* Resize the matrix */ - track2ipin_lookup.resize(rr_gsb.get_num_sides()); + pin2track_map.resize(rr_gsb.get_num_sides()); /* Walk through each side */ for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { @@ -1405,28 +1477,151 @@ std::vector < std::vector< std::vector > > build_gsb_track_to_ipin_lookup(c enum e_side gsb_side = side_manager.get_side(); /* Get channel width and resize the matrix */ size_t chan_width = rr_gsb.get_chan_width(gsb_side); - track2ipin_lookup[side].resize(chan_width); - /* Find the ipin nodes */ - for (size_t inode = 0; inode < rr_gsb.get_num_ipin_nodes(gsb_side); ++inode) { - t_rr_node* ipin_node = rr_gsb.get_ipin_node(gsb_side, inode); + pin2track_map[side].resize(chan_width); + /* Find the ipin/opin nodes */ + size_t num_pin_nodes; + if (true == is_Fc_out) { /* Fc_out, we consider OPINs */ + num_pin_nodes = rr_gsb.get_num_opin_nodes(gsb_side); + } else { /* Fc_in, we consider IPINs */ + num_pin_nodes = rr_gsb.get_num_ipin_nodes(gsb_side); + } + for (size_t inode = 0; inode < num_pin_nodes; ++inode) { + t_rr_node* pin_node; + if (true == is_Fc_out) { /* Fc_out, we consider OPINs */ + pin_node = rr_gsb.get_opin_node(gsb_side, inode); + } else { /* Fc_in, we consider IPINs */ + pin_node = rr_gsb.get_ipin_node(gsb_side, inode); + } /* For each IPIN, we find the type_descriptor, offset and pin_side on the grid */ - int grid_type_id = grids[ipin_node->xlow][ipin_node->ylow].type->index; - int offset = grid[ipin_node->xlow][ipin_node->ylow].offset; - enum e_side pin_side = rr_gsb.get_ipin_node_grid_side(gsb_side, inode); + int grid_type_id = grids[pin_node->xlow][pin_node->ylow].type->index; + int offset = grid[pin_node->xlow][pin_node->ylow].offset; + enum e_side pin_side; + if (true == is_Fc_out) { /* Fc_out, we consider OPINs */ + pin_side = rr_gsb.get_opin_node_grid_side(gsb_side, inode); + } else { /* Fc_in, we consider IPINs */ + pin_side = rr_gsb.get_ipin_node_grid_side(gsb_side, inode); + } /* Now, we fill the return matrix */ /* Bypass empty array */ - if (NULL == ipin_to_track_map[grid_type_id][ipin_node->ptc_num][offset][0]) { + if (NULL == pin_to_track_map[grid_type_id][pin_node->ptc_num][offset][0]) { continue; } /* Get each track_id */ - for (int iconn = 0; iconn < Fc_in[grid_type_id][ipin_node->ptc_num]; ++iconn) { - int track_id = ipin_to_track_map[grid_type_id][ipin_node->ptc_num][offset][pin_side][iconn]; - track2ipin_lookup[gsb_side][track_id].push_back(inode); + for (int iconn = 0; iconn < Fc[grid_type_id][pin_node->ptc_num]; ++iconn) { + int track_id = pin_to_track_map[grid_type_id][pin_node->ptc_num][offset][pin_side][iconn]; + pin2track_map[gsb_side][track_id].push_back(inode); } } } - return track2ipin_lookup; + return pin2track_map; +} + +/************************************************************************ + * Build the track_to_ipin_map[gsb_side][0..chan_width-1][ipin_indices] + * based on the existing routing resources in the General Switch Block (GSB) + * This function supports both X-directional and Y-directional tracks + * The mapping is done in the following steps: + * 1. build a list of routing tracks which are allowed for connections + * We will check the Connection Block (CB) population of each routing track. + * By comparing current chan_y - ylow, we can determine if a CB connection + * is required for each routing track + * 2. Divide the routing tracks by segment types, so that we can balance + * the connections between IPINs and different types of routing tracks. + * 3. Scale the Fc of each pin to the actual number of routing tracks + * actual_Fc = (int) Fc * num_tracks / chan_width + * 4. Build ipin_to_track_map[gsb_side][0..num_ipin_nodes-1][track_indices] + * For each IPIN, we ensure at least one connection to the tracks. + * Then, we assign IPINs to tracks evenly while satisfying the actual_Fc + * 5. Convert the ipin_to_track_map to track_to_ipin_map + ***********************************************************************/ + +/************************************************************************ + * Build the opin_to_track_map[gsb_side][0..num_opin_nodes-1][track_indices] + * based on the existing routing resources in the General Switch Block (GSB) + * This function supports both X-directional and Y-directional tracks + * The mapping is done in the following steps: + * 1. Build a list of routing tracks whose starting points locate at this GSB + * (xlow - gsb_x == 0) + * 2. Divide the routing tracks by segment types, so that we can balance + * the connections between OPINs and different types of routing tracks. + * 3. Scale the Fc of each pin to the actual number of routing tracks + * actual_Fc = (int) Fc * num_tracks / chan_width + ***********************************************************************/ + +/************************************************************************ + * Add all direct clb-pin-to-clb-pin edges to given opin + ***********************************************************************/ +static +void build_direct_connections_for_one_gsb(t_rr_graph* rr_graph, + const DeviceCoordinator& device_size, + const DeviceCoordinator& from_grid_coordinator, + const t_grid_tile& from_grid, + const int delayless_switch, + const int num_directs, + const t_direct_inf *directs, + const t_clb_to_clb_directs *clb_to_clb_directs) { + t_type_ptr grid_type = from_grid.type; + + /* Iterate through all direct connections */ + for (int i = 0; i < num_directs; ++i) { + /* Bypass unmatched direct clb-to-clb connections */ + if (grid_type != clb_to_clb_directs[i].from_clb_type) { + continue; + } + bool swap; + int max_index, min_index; + /* Compute index of opin with regards to given pins */ + if ( clb_to_clb_directs[i].from_clb_pin_start_index + > clb_to_clb_directs[i].from_clb_pin_end_index) { + swap = true; + max_index = clb_to_clb_directs[i].from_clb_pin_start_index; + min_index = clb_to_clb_directs[i].from_clb_pin_end_index; + } else { + swap = false; + min_index = clb_to_clb_directs[i].from_clb_pin_start_index; + max_index = clb_to_clb_directs[i].from_clb_pin_end_index; + } + /* get every opin in the range */ + for (int opin = min_index; opin <= max_index; ++opin) { + int offset = opin - min_index; + /* This opin is specified to connect directly to an ipin, now compute which ipin to connect to */ + DeviceCoordinator to_grid_coordinator(from_grid_coordinator.get_x() + directs[i].x_offset, + from_grid_coordinator.get_y() + directs[i].y_offset); + if ( (to_grid_coordinator.get_x() < device_size.get_x() - 1) + && (to_grid_coordinator.get_y() < device_size.get_y() - 1) ) { + int ipin = OPEN; + if ( clb_to_clb_directs[i].to_clb_pin_start_index + > clb_to_clb_directs[i].to_clb_pin_end_index) { + if (true == swap) { + ipin = clb_to_clb_directs[i].to_clb_pin_end_index + offset; + } else { + ipin = clb_to_clb_directs[i].to_clb_pin_start_index - offset; + } + } else { + if(true == swap) { + ipin = clb_to_clb_directs[i].to_clb_pin_end_index - offset; + } else { + ipin = clb_to_clb_directs[i].to_clb_pin_start_index + offset; + } + } + /* Get the pin index in the rr_graph */ + int from_grid_ofs = from_grid.offset; + int to_grid_ofs = grid[to_grid_coordinator.get_x()][to_grid_coordinator.get_y()].offset; + int opin_node_id = get_rr_node_index(from_grid_coordinator.get_x(), + from_grid_coordinator.get_y() - from_grid_ofs, + OPIN, opin, rr_graph->rr_node_indices); + int ipin_node_id = get_rr_node_index(to_grid_coordinator.get_x(), + to_grid_coordinator.get_y() - to_grid_ofs, + IPIN, ipin, rr_graph->rr_node_indices); + /* add edges to the opin_node */ + add_one_edge_for_two_rr_nodes(rr_graph, opin_node_id, ipin_node_id, + delayless_switch); + } + } + } + + return; } @@ -1448,31 +1643,36 @@ void build_rr_graph_edges(t_rr_graph* rr_graph, std::vector< std::vector > grids, std::vector device_chan_width, std::vector segment_inf, - int L_num_types, t_type_ptr types, int** Fc_in, int** Fc_out, int***** ipin_to_track_map, int***** opin_to_track_map, - vtr::NdMatrix,3> switch_block_conn, - int num_directs, t_clb_to_clb_directs* clb_to_clb_directs, - int num_switches, int delayless_switch) { + enum e_switch_block_type sb_type, int Fs) { + DeviceCoordinator device_range(device_size.get_x() - 1, device_size.get_y() - 1); + /* Go Switch Block by Switch Block */ for (size_t ix = 0; ix < device_size.get_x(); ++ix) { for (size_t iy = 0; iy < device_size.get_y(); ++iy) { + DeviceCoordinator gsb_coordinator(ix, iy); /* Create a GSB object */ RRGSB rr_gsb = build_one_tileable_rr_gsb(device_range, device_chan_width, segment_inf, gsb_coordinator, rr_graph); + /* adapt the track_to_ipin_lookup for the GSB nodes */ - std::vector < std::vector< std::vector > > track2ipin_lookup; /* [0..gsb_side][0..num_tracks][0..Fc-1] */ - track2ipin_lookup = build_gsb_track_to_ipin_lookup(rr_gsb, grids, Fc_in, ipin_to_track_map); + t_pin2track_map ipin2track_map; /* [0..track_gsb_side][0..num_tracks][ipin_indices] */ + ipin2track_map = build_gsb_pin_to_track_map(rr_gsb, grids, Fc_in, false, ipin_to_track_map); + /* adapt the opin_to_track_map for the GSB nodes */ - std::vector < std::vector< std::vector > > opin2track_map; /* [0..gsb_side][0..num_opin_node][0..Fc-1] */ + t_pin2track_map opin2track_map; /* [0..gsb_side][0..num_opin_node][track_indices] */ + opin2track_map = build_gsb_pin_to_track_map(rr_gsb, grids, Fc_out, true, opin_to_track_map); + /* adapt the switch_block_conn for the GSB nodes */ - std::vector < std::vector< std::vector > > sb_conn; /* [0..from_gsb_side][0..to_gsb_side][0..chan_width-1] */ + t_track2track_map sb_conn; /* [0..from_gsb_side][0..chan_width-1][track_indices] */ + sb_conn = build_gsb_track_to_track_map(rr_graph, rr_gsb, sb_type, Fs, segment_inf); + /* Build edges for a GSB */ build_edges_for_one_tileable_rr_gsb(rr_graph, &rr_gsb, - track2ipin_lookup, opin2track_map, sb_conn, - num_directs, clb_to_clb_directs, - num_switches, delayless_switch); + ipin2track_map, opin2track_map, + sb_conn); /* Finish this GSB, go to the next*/ } } @@ -1480,6 +1680,39 @@ void build_rr_graph_edges(t_rr_graph* rr_graph, return; } +/************************************************************************ + * Build direct edges for Grids * + ***********************************************************************/ +static +void build_rr_graph_direct_connections(t_rr_graph* rr_graph, + const DeviceCoordinator& device_size, + std::vector< std::vector > grids, + const int delayless_switch, + const int num_directs, + const t_direct_inf *directs, + const t_clb_to_clb_directs *clb_to_clb_directs) { + for (size_t ix = 0; ix < device_size.get_x(); ++ix) { + for (size_t iy = 0; iy < device_size.get_y(); ++iy) { + /* Skip EMPTY tiles */ + if (EMPTY_TYPE == grids[ix][iy].type) { + continue; + } + /* Skip height>1 tiles (mostly heterogeneous blocks) */ + if (0 < grids[ix][iy].offset) { + continue; + } + DeviceCoordinator from_grid_coordinator(ix, iy); + build_direct_connections_for_one_gsb(rr_graph, device_size, + from_grid_coordinator, + grids[ix][iy], + delayless_switch, + num_directs, directs, clb_to_clb_directs); + } + } + + return; +} + /************************************************************************ * Main function of this file * Builder for a detailed uni-directional tileable rr_graph @@ -1524,7 +1757,7 @@ void build_tileable_unidir_rr_graph(INP int L_num_types, INP struct s_grid_tile **L_grid, INP int chan_width, INP enum e_switch_block_type sb_type, INP int Fs, INP int num_seg_types, - INP int num_switches, INP t_segment_inf * segment_inf, + INP t_segment_inf * segment_inf, INP int delayless_switch, INP t_timing_inf timing_inf, INP int wire_to_ipin_switch, INP enum e_base_cost_type base_cost_type, @@ -1593,14 +1826,15 @@ void build_tileable_unidir_rr_graph(INP int L_num_types, * grid_info : pb_graph_pin ***********************************************************************/ alloc_rr_graph_fast_lookup(device_size, &rr_graph); - load_rr_nodes_basic_info(&rr_graph, device_size, grids, device_chan_width, segment_infs); + load_rr_nodes_basic_info(&rr_graph, device_size, grids, device_chan_width, segment_infs, + wire_to_ipin_switch, delayless_switch); /************************************************************************ - * 3.1 Create the connectivity of OPINs + * 5.1 Create the connectivity of OPINs * a. Evenly assign connections to OPINs to routing tracks * b. the connection pattern should be same across the fabric * - * 3.2 Create the connectivity of IPINs + * 5.2 Create the connectivity of IPINs * a. Evenly assign connections from routing tracks to IPINs * b. the connection pattern should be same across the fabric ***********************************************************************/ @@ -1639,11 +1873,6 @@ void build_tileable_unidir_rr_graph(INP int L_num_types, opin_to_track_map[i] = alloc_and_load_pin_to_track_map(DRIVER, chan_width, Fc_out[i], &types[i], FALSE, UNI_DIRECTIONAL); } - /************************************************************************ - * 4. Build switch block connection matrix - ***********************************************************************/ - vtr::NdMatrix,3> switch_block_conn = alloc_and_load_tileable_switch_block_conn(chan_width, sb_type, Fs); - /************************************************************************ * 6. Build the connections tile by tile: * We classify rr_nodes into a general switch block (GSB) data structure @@ -1652,19 +1881,25 @@ void build_tileable_unidir_rr_graph(INP int L_num_types, * In addition, we will also handle direct-connections: * Add edges that bridge OPINs and IPINs to the rr_graph ***********************************************************************/ + + /* Create edges for a tileable rr_graph */ + build_rr_graph_edges(&rr_graph, device_size, grids, device_chan_width, segment_infs, + Fc_in, Fc_out, ipin_to_track_map, opin_to_track_map, + sb_type, Fs); + + /************************************************************************ + * 7. Build direction connection lists + ***********************************************************************/ /* Create data structure of direct-connections */ t_clb_to_clb_directs* clb_to_clb_directs = NULL; if (num_directs > 0) { clb_to_clb_directs = alloc_and_load_clb_to_clb_directs(directs, num_directs); } - - /* Create edges for a tileable rr_graph */ - build_rr_graph_edges(&rr_graph, device_size, grids, device_chan_width, segment_infs, - L_num_types, types, Fc_in, Fc_out, ipin_to_track_map, opin_to_track_map, switch_block_conn, - num_directs, clb_to_clb_directs, num_switches, delayless_switch); + build_rr_graph_direct_connections(&rr_graph, device_size, grids, delayless_switch, + num_directs, directs, clb_to_clb_directs); /************************************************************************ - * 7. Allocate external data structures + * 8. Allocate external data structures * a. cost_index * b. RC tree ***********************************************************************/ @@ -1672,7 +1907,7 @@ void build_tileable_unidir_rr_graph(INP int L_num_types, wire_to_ipin_switch, base_cost_type); /************************************************************************ - * 8. Sanitizer for the rr_graph, check connectivities of rr_nodes + * 9. Sanitizer for the rr_graph, check connectivities of rr_nodes ***********************************************************************/ /* We set global variables for rr_nodes here, @@ -1682,7 +1917,7 @@ void build_tileable_unidir_rr_graph(INP int L_num_types, rr_node_indices = rr_graph.rr_node_indices; /************************************************************************ - * 9. Free all temp stucts + * 10. Free all temp stucts ***********************************************************************/ /* Free all temp structs */ diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.h b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.h index 04694f492..26e1f9cc7 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.h +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.h @@ -6,7 +6,7 @@ void build_tileable_unidir_rr_graph(INP int L_num_types, INP struct s_grid_tile **L_grid, INP int chan_width, INP enum e_switch_block_type sb_type, INP int Fs, INP int num_seg_types, - INP int num_switches, INP t_segment_inf * segment_inf, + INP t_segment_inf * segment_inf, INP int delayless_switch, INP t_timing_inf timing_inf, INP int wire_to_ipin_switch, INP enum e_base_cost_type base_cost_type, INP t_direct_inf *directs, diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_sbox.cpp b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_sbox.cpp index f30ceed2d..df894c81a 100755 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_sbox.cpp +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_sbox.cpp @@ -1,211 +1,461 @@ -#include "vtr_assert.h" +/********************************************************** + * MIT License + * + * Copyright (c) 2018 LNIS - The University of Utah + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + ***********************************************************************/ -#include "vtr_util.h" -#include "vtr_memory.h" +/************************************************************************ + * Filename: rr_graph_tileable_sbox.cpp + * Created by: Xifan Tang + * Change history: + * +-------------------------------------+ + * | Date | Author | Notes + * +-------------------------------------+ + * | 2019/06/19 | Xifan Tang | Created + * +-------------------------------------+ + ***********************************************************************/ +/************************************************************************ + * This file contains a builder for track-to-track connections inside a + * tileable General Switch Block (GSB). + ***********************************************************************/ + +#include +#include + +#include #include "vpr_types.h" #include "rr_graph_tileable_sbox.h" -#include "rr_graph_util.h" -#include "ReadOptions.h" - -static -int get_tileable_simple_switch_block_track(const enum e_side from_side, - const enum e_side to_side, const int from_track, - const enum e_switch_block_type switch_block_type, const int nodes_per_chan); /************************************************************************ - * Build internal connection pattern for a switch block - * This function is adapt to fit the tileable routing context from - * rr_graph_sbox.c : alloc_and_load_switch_block_conn - * Switch box: * - * TOP (CHANY) * - * | | | | | | * - * +-----------+ * - * --| |-- * - * --| |-- * - * LEFT --| |-- RIGHT * - * (CHANX)--| |--(CHANX) * - * --| |-- * - * --| |-- * - * +-----------+ * - * | | | | | | * - * BOTTOM (CHANY) * - * - * [0..3][0..3][0..nodes_per_chan-1]. Structure below is indexed as: * - * [from_side][to_side][from_track]. That yields an integer vector (ivec) * - * of the tracks to which from_track connects in the proper to_location. * - * For simple switch boxes this is overkill, but it will allow complicated * - * switch boxes with Fs > 3, etc. without trouble. * + * Internal data structures ***********************************************************************/ +typedef std::vector> t_track_group; -/* Allocates and loads the switch_block_conn data structure. This structure * - * lists which tracks connect to which at each switch block. This is for - * bidir. */ -vtr::NdMatrix,3> alloc_and_load_tileable_switch_block_conn(const size_t nodes_per_chan, - const e_switch_block_type switch_block_type, - const int Fs) { +/************************************************************************ + * A enumeration to list the status of a track inside a GSB + * 1. start; 2. end; 3. passing + * This is used to group tracks which ease the building of + * track-to-track mapping matrix + ***********************************************************************/ +enum e_track_status { + TRACK_START, + TRACK_END, + TRACK_PASS, + NUM_TRACK_STATUS /* just a place holder to get the number of status */ +}; - /* Currently Fs must be 3 since each track maps once to each other side */ - VTR_ASSERT(3 == Fs); - - vtr::NdMatrix,3> switch_block_conn({4, 4, nodes_per_chan}); - - for (e_side from_side : {TOP, RIGHT, BOTTOM, LEFT}) { - for (e_side to_side : {TOP, RIGHT, BOTTOM, LEFT}) { - for (size_t from_track = 0; from_track < nodes_per_chan; from_track++) { - if (from_side != to_side) { - switch_block_conn[from_side][to_side][from_track].resize(1); - - switch_block_conn[from_side][to_side][from_track][0] = get_tileable_simple_switch_block_track(from_side, to_side, - from_track, switch_block_type, nodes_per_chan); - } else { /* from_side == to_side -> no connection. */ - switch_block_conn[from_side][to_side][from_track].clear(); - } - } - } - } - - if (getEchoEnabled()) { - FILE *out = vtr::fopen("switch_block_conn.echo", "w"); - for (int l = 0; l < 4; ++l) { - for (int k = 0; k < 4; ++k) { - fprintf(out, "Side %d to %d\n", l, k); - for (size_t j = 0; j < nodes_per_chan; ++j) { - fprintf(out, "%zu: ", j); - for (unsigned i = 0; i < switch_block_conn[l][k][j].size(); ++i) { - fprintf(out, "%d ", switch_block_conn[l][k][j][i]); - } - fprintf(out, "\n"); - } - fprintf(out, "\n"); - } - } - fclose(out); - } - return switch_block_conn; -} - -#define SBOX_ERROR -1 - -/* This routine permutes the track number to connect for topologies - * SUBSET, UNIVERSAL, and WILTON. I added FULL (for fully flexible topology) - * but the returned value is simply a dummy, since we don't need to permute - * what connections to make for FULL (connect to EVERYTHING) */ +/************************************************************************ + * Check if a track starts from this GSB or not + * (xlow, ylow) should be same as the GSB side coordinator + * + * Check if a track ends at this GSB or not + * (xhigh, yhigh) should be same as the GSB side coordinator + ***********************************************************************/ static -int get_tileable_simple_switch_block_track(const enum e_side from_side, - const enum e_side to_side, const int from_track, - const enum e_switch_block_type switch_block_type, const int nodes_per_chan) { +enum e_track_status determine_track_status_of_gsb(const RRGSB& rr_gsb, + const enum e_side gsb_side, + const size_t track_id) { + enum e_track_status track_status = TRACK_PASS; + /* Get the rr_node */ + t_rr_node* track_node = rr_gsb.get_chan_node(gsb_side, track_id); + /* Get the coordinators */ + DeviceCoordinator side_coordinator = rr_gsb.get_side_block_coordinator(gsb_side); - /* This routine returns the track number to which the from_track should * - * connect. It supports three simple, Fs = 3, switch blocks. */ - - int to_track = SBOX_ERROR; /* Can check to see if it's not set later. */ - - if (switch_block_type == SUBSET) { /* NB: Global routing uses SUBSET too */ - to_track = from_track; + /* INC_DIRECTION start_track: (xlow, ylow) should be same as the GSB side coordinator */ + if ( ((size_t)track_node->xlow == side_coordinator.get_x()) + && ((size_t)track_node->ylow == side_coordinator.get_y()) + && (OUT_PORT == rr_gsb.get_chan_node_direction(gsb_side, track_id)) ) { + /* Double check: start track should be an OUTPUT PORT of the GSB */ + track_status = TRACK_START; + } + /* INC_DIRECTION end_track: (xhigh, yhigh) should be same as the GSB side coordinator */ + if ( ((size_t)track_node->xhigh == side_coordinator.get_x()) + && ((size_t)track_node->yhigh == side_coordinator.get_y()) + && (IN_PORT == rr_gsb.get_chan_node_direction(gsb_side, track_id)) ) { + /* Double check: end track should be an INPUT PORT of the GSB */ + track_status = TRACK_END; } - /* See S. Wilton Phd thesis, U of T, 1996 p. 103 for details on following. */ - - else if (switch_block_type == WILTON) { - - if (from_side == LEFT) { - - if (to_side == RIGHT) { /* CHANX to CHANX */ - to_track = from_track; - } else if (to_side == TOP) { /* from CHANX to CHANY */ - to_track = (nodes_per_chan - (from_track % nodes_per_chan)) % nodes_per_chan; - } else if (to_side == BOTTOM) { - to_track = (nodes_per_chan + from_track - 1) % nodes_per_chan; - } - } - - else if (from_side == RIGHT) { - if (to_side == LEFT) { /* CHANX to CHANX */ - to_track = from_track; - } else if (to_side == TOP) { /* from CHANX to CHANY */ - to_track = (nodes_per_chan + from_track - 1) % nodes_per_chan; - } else if (to_side == BOTTOM) { - to_track = (2 * nodes_per_chan - 2 - from_track) % nodes_per_chan; - } - } - - else if (from_side == BOTTOM) { - if (to_side == TOP) { /* CHANY to CHANY */ - to_track = from_track; - } else if (to_side == LEFT) { /* from CHANY to CHANX */ - to_track = (from_track + 1) % nodes_per_chan; - } else if (to_side == RIGHT) { - to_track = (2 * nodes_per_chan - 2 - from_track) % nodes_per_chan; - } - } - - else if (from_side == TOP) { - if (to_side == BOTTOM) { /* CHANY to CHANY */ - to_track = from_track; - } else if (to_side == LEFT) { /* from CHANY to CHANX */ - to_track = (nodes_per_chan - (from_track % nodes_per_chan)) % nodes_per_chan; - } else if (to_side == RIGHT) { - to_track = (from_track + 1) % nodes_per_chan; - } - } - - /* Force to_track to UN_SET if it falls outside the min/max channel width range */ - if (to_track < 0 || to_track >= nodes_per_chan) { - to_track = -1; - } - } - /* End switch_block_type == WILTON case. */ - else if (switch_block_type == UNIVERSAL) { - - if (from_side == LEFT) { - - if (to_side == RIGHT) { /* CHANX to CHANX */ - to_track = from_track; - } else if (to_side == TOP) { /* from CHANX to CHANY */ - to_track = nodes_per_chan - 1 - from_track; - } else if (to_side == BOTTOM) { - to_track = from_track; - } - } - - else if (from_side == RIGHT) { - if (to_side == LEFT) { /* CHANX to CHANX */ - to_track = from_track; - } else if (to_side == TOP) { /* from CHANX to CHANY */ - to_track = from_track; - } else if (to_side == BOTTOM) { - to_track = nodes_per_chan - 1 - from_track; - } - } - - else if (from_side == BOTTOM) { - if (to_side == TOP) { /* CHANY to CHANY */ - to_track = from_track; - } else if (to_side == LEFT) { /* from CHANY to CHANX */ - to_track = from_track; - } else if (to_side == RIGHT) { - to_track = nodes_per_chan - 1 - from_track; - } - } - - else if (from_side == TOP) { - if (to_side == BOTTOM) { /* CHANY to CHANY */ - to_track = from_track; - } else if (to_side == LEFT) { /* from CHANY to CHANX */ - to_track = nodes_per_chan - 1 - from_track; - } else if (to_side == RIGHT) { - to_track = from_track; - } - } - } - - /* End switch_block_type == UNIVERSAL case. */ - /* UDSD Modification by WMF Begin */ - if (switch_block_type == FULL) { /* Just a placeholder. No meaning in reality */ - to_track = from_track; - } - /* UDSD Modification by WMF End */ - - return (to_track); + return track_status; } + +/************************************************************************ + * Check if the GSB is in the Switch Block (SB) population list of the segment + * SB population of a L3 wire: 1 0 0 1 + * + * +----+ +----+ +----+ +----+ + * | SB |--->| SB |--->| SB |--->| SB | + * +----+ +----+ +----+ +----+ + * Engage SB connection Yes No No Yes + * + * We will find the offset between gsb_side_coordinator and (xlow,ylow) of the track + * Use the offset to check if the tracks should engage in this GSB connection + ***********************************************************************/ +static +bool is_gsb_in_track_sb_population(const RRGSB& rr_gsb, + const enum e_side gsb_side, + const int track_id, + const std::vector segment_inf) { + /* Get the rr_node */ + t_rr_node* track_node = rr_gsb.get_chan_node(gsb_side, track_id); + /* Get the coordinators */ + DeviceCoordinator side_coordinator = rr_gsb.get_side_block_coordinator(gsb_side); + + /* Get the offset */ + size_t offset = (side_coordinator.get_x() - track_node->xlow) + + (side_coordinator.get_y() - track_node->ylow); + + /* Get segment id */ + size_t seg_id = rr_gsb.get_chan_node_segment(gsb_side, track_id); + /* validate offset */ + assert (offset < (size_t)segment_inf[seg_id].sb_len); + + /* Get the SB population */ + bool in_sb_population = false; + if (TRUE == segment_inf[seg_id].sb[offset]) { + in_sb_population = true; + } + return in_sb_population; +} + +/************************************************************************ + * Create a list of track_id based on the to_track and num_to_tracks + * We consider the following list [to_track, to_track + Fs/3 - 1] + * if the [to_track + Fs/3 - 1] exceeds the num_to_tracks, we start over from 0! +***********************************************************************/ +static +std::vector get_to_track_list(const int Fs, const int to_track, const int num_to_tracks) { + std::vector to_tracks; + for (int i = 0; i < Fs; i = i + 3) { + /* TODO: currently, for Fs > 3, I always search the next from_track until Fs is satisfied + * The optimal track selection should be done in a more scientific way!!! + */ + size_t to_track_i = to_track + i; + /* make sure the track id is still in range */ + if ( to_track_i > (size_t)num_to_tracks) { + to_track_i = to_track_i % num_to_tracks; + } + /* from track must be connected */ + to_tracks.push_back(to_track_i); + } + return to_tracks; +} + +/************************************************************************ + * This function aims to return the track indices that drive the from_track + * in a Switch Block + * The track_ids to return will depend on different topologies of SB + * SUBSET, UNIVERSAL, and WILTON. + ***********************************************************************/ +static +std::vector get_switch_block_to_track_id(const enum e_switch_block_type switch_block_type, + const int Fs, + const enum e_side from_side, + const int from_track, + const enum e_side to_side, + const int num_to_tracks) { + + /* This routine returns the track number to which the from_track should + * connect. It supports any Fs % 3 == 0, switch blocks. + */ + std::vector to_tracks; + + /* TODO: currently, for Fs > 3, I always search the next from_track until Fs is satisfied + * The optimal track selection should be done in a more scientific way!!! + */ + + assert (0 == Fs % 3); + + switch (switch_block_type) { + case SUBSET: /* NB: Global routing uses SUBSET too */ + to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); + /* Finish, we return */ + return to_tracks; + case UNIVERSAL: + if ( (from_side == LEFT) + || (from_side == RIGHT) ) { + /* For the prev_side, to_track is from_track + * For the next_side, to_track is num_to_tracks - 1 - from_track + * For the opposite_side, to_track is always from_track + */ + Side side_manager(from_side); + if ( (to_side == side_manager.get_opposite()) + || (to_side == side_manager.get_rotate_counterclockwise()) ) { + to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); + } else if (to_side == side_manager.get_rotate_clockwise()) { + to_tracks = get_to_track_list(Fs, num_to_tracks - 1 - from_track, num_to_tracks); + } + } + + if ( (from_side == TOP) + || (from_side == BOTTOM) ) { + /* For the next_side, to_track is from_track + * For the prev_side, to_track is num_to_tracks - 1 - from_track + * For the opposite_side, to_track is always from_track + */ + Side side_manager(from_side); + if ( (to_side == side_manager.get_opposite()) + || (to_side == side_manager.get_rotate_clockwise()) ) { + to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); + } else if (to_side == side_manager.get_rotate_counterclockwise()) { + to_tracks = get_to_track_list(Fs, num_to_tracks - 1 - from_track, num_to_tracks); + } + } + /* Finish, we return */ + return to_tracks; + /* End switch_block_type == UNIVERSAL case. */ + case WILTON: + /* See S. Wilton Phd thesis, U of T, 1996 p. 103 for details on following. */ + if (from_side == LEFT) { + if (to_side == RIGHT) { /* CHANX to CHANX */ + to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); + } else if (to_side == TOP) { /* from CHANX to CHANY */ + to_tracks = get_to_track_list(Fs, (num_to_tracks - (from_track % num_to_tracks)) % num_to_tracks, num_to_tracks); + } else if (to_side == BOTTOM) { + to_tracks = get_to_track_list(Fs, (num_to_tracks + from_track - 1) % num_to_tracks, num_to_tracks); + } + } else if (from_side == RIGHT) { + if (to_side == LEFT) { /* CHANX to CHANX */ + to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); + } else if (to_side == TOP) { /* from CHANX to CHANY */ + to_tracks = get_to_track_list(Fs, (num_to_tracks + from_track - 1) % num_to_tracks, num_to_tracks); + } else if (to_side == BOTTOM) { + to_tracks = get_to_track_list(Fs, (num_to_tracks - 2 - from_track) % num_to_tracks, num_to_tracks); + } + } else if (from_side == BOTTOM) { + if (to_side == TOP) { /* CHANY to CHANY */ + to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); + } else if (to_side == LEFT) { /* from CHANY to CHANX */ + to_tracks = get_to_track_list(Fs, (from_track + 1) % num_to_tracks, num_to_tracks); + } else if (to_side == RIGHT) { + to_tracks = get_to_track_list(Fs, (2 * num_to_tracks - 2 - from_track) % num_to_tracks, num_to_tracks); + } + } else if (from_side == TOP) { + if (to_side == BOTTOM) { /* CHANY to CHANY */ + to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); + } else if (to_side == LEFT) { /* from CHANY to CHANX */ + to_tracks = get_to_track_list(Fs, (num_to_tracks - (from_track % num_to_tracks)) % num_to_tracks, num_to_tracks); + } else if (to_side == RIGHT) { + to_tracks = get_to_track_list(Fs, (from_track + 1) % num_to_tracks, num_to_tracks); + } + } + /* Finish, we return */ + return to_tracks; + /* End switch_block_type == WILTON case. */ + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d]) Invalid switch block pattern !\n", + __FILE__, __LINE__); + exit(1); + } + + return to_tracks; +} + + +/************************************************************************ + * Build the track_to_track_map[from_side][0..chan_width-1][to_side][track_indices] + * For a group of from_track nodes and to_track nodes + * For each side of from_tracks, we call a routine to get the list of to_tracks + * Then, we fill the track2track_map + ***********************************************************************/ +static +void build_gsb_one_group_track_to_track_map(const t_rr_graph* rr_graph, + const RRGSB& rr_gsb, + const enum e_switch_block_type sb_type, + const int Fs, + const t_track_group from_tracks, /* [0..gsb_side][track_indices] */ + const t_track_group to_tracks, /* [0..gsb_side][track_indices] */ + t_track2track_map* track2track_map) { + for (size_t side = 0; side < from_tracks.size(); ++side) { + Side side_manager(side); + enum e_side gsb_side = side_manager.get_side(); + /* Find the other sides where the start tracks will locate */ + std::vector to_track_sides; + /* 0. opposite side */ + to_track_sides.push_back(side_manager.get_opposite()); + /* 1. prev side */ + /* Previous side definition: TOP => LEFT; RIGHT=>TOP; BOTTOM=>RIGHT; LEFT=>BOTTOM */ + to_track_sides.push_back(side_manager.get_rotate_counterclockwise()); + /* 2. next side */ + /* Next side definition: TOP => RIGHT; RIGHT=>BOTTOM; BOTTOM=>LEFT; LEFT=>TOP */ + to_track_sides.push_back(side_manager.get_rotate_clockwise()); + + for (size_t inode = 0; inode < from_tracks[side].size(); ++inode) { + for (size_t to_side_id = 0; to_side_id < to_track_sides.size(); ++to_side_id) { + enum e_side to_side = to_track_sides[to_side_id]; + Side to_side_manager(to_side); + size_t to_side_index = to_side_manager.to_size_t(); + /* Bypass those to_sides have no nodes */ + if (0 == to_tracks[to_side_index].size()) { + continue; + } + /* Get other track_ids depending on the switch block pattern */ + /* Find the track ids that will start at the other sides */ + std::vector to_track_ids = get_switch_block_to_track_id(sb_type, Fs, gsb_side, inode, + to_side, + to_tracks[to_side_index].size()); + /* Update the track2track_map: */ + for (size_t to_track_id = 0; to_track_id < to_track_ids.size(); ++to_track_id) { + size_t from_side_index = side_manager.to_size_t(); + size_t from_track_index = from_tracks[side][inode]; + size_t to_track_index = to_tracks[to_side_index][to_track_ids[to_track_id]]; + t_rr_node* to_track_node = rr_gsb.get_chan_node(to_side, to_track_index); + (*track2track_map)[from_side_index][from_track_index].push_back(to_track_node - rr_graph->rr_node); + } + } + } + } + + return; +} + +/************************************************************************ + * Build the track_to_track_map[from_side][0..chan_width-1][to_side][track_indices] + * based on the existing routing resources in the General Switch Block (GSB) + * The track_indices is the indices of tracks that the node at from_side and [0..chan_width-1] will drive + * IMPORTANT: the track_indices are the indicies in the GSB context, but not the rr_graph!!! + * We separate the connections into two groups: + * Group 1: the routing tracks start from this GSB + * We will apply switch block patterns (SUBSET, UNIVERSAL, WILTON) + * Group 2: the routing tracks do not start from this GSB (bypassing wires) + * We will apply switch block patterns (SUBSET, UNIVERSAL, WILTON) + * but we will check the Switch Block (SB) population of these + * routing segments, and determine which requires connections + * + * CHANY CHANY CHANY CHANY + * [0] [1] [2] [3] + * start yes no yes no + * end +-------------------------+ start Group 1 Group 2 + * no CHANX[0] | TOP | CHANX[0] yes TOP/BOTTOM TOP/BOTTOM + * | | CHANY[0,2] CHANY[1,3] + * yes CHANX[1] | | CHANX[1] no + * | LEFT RIGHT | + * no CHANX[2] | | CHANX[2] yes + * | | + * yes CHANX[3] | BOTTOM | CHANX[3] no + * +-------------------------+ + * CHANY CHANY CHANY CHANY + * [0] [1] [2] [3] + * start yes no yes no + * + * The mapping is done in the following steps: (For each side of the GSB) + * 1. Build a list of tracks that will start from this side + * if a track starts, its xlow/ylow is the same as the x,y of this gsb + * 2. Build a list of tracks on the other sides belonging to Group 1. + * Take the example of RIGHT side, we will collect + * a. tracks that will end at the LEFT side + * b. tracks that will start at the TOP side + * c. tracks that will start at the BOTTOM side + * 3. Apply switch block patterns to Group 1 (SUBSET, UNIVERSAL, WILTON) + * 4. Build a list of tracks on the other sides belonging to Group 1. + * Take the example of RIGHT side, we will collect + * a. tracks that will bypass at the TOP side + * b. tracks that will bypass at the BOTTOM side + * 5. Apply switch block patterns to Group 2 (SUBSET, UNIVERSAL, WILTON) + ***********************************************************************/ +t_track2track_map build_gsb_track_to_track_map(const t_rr_graph* rr_graph, + const RRGSB& rr_gsb, + const enum e_switch_block_type sb_type, + const int Fs, + const std::vector segment_inf) { + t_track2track_map track2track_map; /* [0..gsb_side][0..chan_width][track_indices] */ + + /* Categorize tracks into 3 groups: + * (1) tracks will start here + * (2) tracks will end here + * (2) tracks will just pass through the SB */ + t_track_group start_tracks; /* [0..gsb_side][track_indices] */ + t_track_group end_tracks; /* [0..gsb_side][track_indices] */ + t_track_group pass_tracks; /* [0..gsb_side][track_indices] */ + + /* resize to the number of sides */ + start_tracks.resize(rr_gsb.get_num_sides()); + end_tracks.resize(rr_gsb.get_num_sides()); + pass_tracks.resize(rr_gsb.get_num_sides()); + + /* Walk through each side */ + for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { + Side side_manager(side); + enum e_side gsb_side = side_manager.get_side(); + /* Build a list of tracks that will start from this side */ + for (size_t inode = 0; inode < rr_gsb.get_chan_width(gsb_side); ++inode) { + /* check if this track will start from here */ + enum e_track_status track_status = determine_track_status_of_gsb(rr_gsb, gsb_side, inode); + switch (track_status) { + case TRACK_START: + /* update starting track list */ + start_tracks[gsb_side].push_back(inode); + break; + case TRACK_END: + /* Update end track list */ + end_tracks[gsb_side].push_back(inode); + break; + case TRACK_PASS: + /* We need to check Switch block population of this track + * The track node will not be considered if there supposed to be no SB at this position + */ + if (true == is_gsb_in_track_sb_population(rr_gsb, gsb_side, inode, segment_inf)) { + /* Update passing track list */ + pass_tracks[gsb_side].push_back(inode); + } + break; + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d]) Invalid track status!\n", + __FILE__, __LINE__); + exit(1); + } + } + } + + /* Allocate track2track map */ + track2track_map.resize(rr_gsb.get_num_sides()); + for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { + Side side_manager(side); + enum e_side gsb_side = side_manager.get_side(); + /* allocate track2track_map[gsb_side] */ + track2track_map[side].resize(rr_gsb.get_chan_width(gsb_side)); + for (size_t inode = 0; inode < rr_gsb.get_chan_width(gsb_side); ++inode) { + /* allocate track2track_map[gsb_side][inode] */ + track2track_map[side][inode].clear(); + } + } + + /* For Group 1: we build connections between end_tracks and start_tracks*/ + build_gsb_one_group_track_to_track_map(rr_graph, rr_gsb, + sb_type, Fs, + end_tracks, start_tracks, + &track2track_map); + + /* For Group 2: we build connections between end_tracks and start_tracks*/ + /* Currently, I use the same Switch Block pattern for the passing tracks and end tracks, + * TODO: This can be improved with different patterns! + */ + build_gsb_one_group_track_to_track_map(rr_graph, rr_gsb, + sb_type, Fs, + pass_tracks, start_tracks, + &track2track_map); + + return track2track_map; +} + diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_sbox.h b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_sbox.h index 93f3ea5ea..3079cbea8 100755 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_sbox.h +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_sbox.h @@ -5,8 +5,16 @@ #include "vtr_ndmatrix.h" -vtr::NdMatrix,3> alloc_and_load_tileable_switch_block_conn(size_t nodes_per_chan, - enum e_switch_block_type switch_block_type, int Fs); +#include "rr_blocks.h" +#include "fpga_x2p_types.h" + +typedef std::vector>> t_track2track_map; + +t_track2track_map build_gsb_track_to_track_map(const t_rr_graph* rr_graph, + const RRGSB& rr_gsb, + const enum e_switch_block_type sb_type, + const int Fs, + const std::vector segment_inf); #endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_types.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_types.h index 6a53c32c9..796707d78 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_types.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_types.h @@ -1,3 +1,8 @@ +#ifndef FPGA_X2P_TYPES_H +#define FPGA_X2P_TYPES_H + +#include "route_common.h" + /* Define the basic data structures used for FPGA-SPICE */ /* Default ID of switch used in rr_node */ @@ -135,3 +140,4 @@ struct fpga_spice_phy_pb { int num_iopads; }; +#endif diff --git a/vpr7_x2p/vpr/SRC/route/route_common.h b/vpr7_x2p/vpr/SRC/route/route_common.h index f3be76474..272791041 100755 --- a/vpr7_x2p/vpr/SRC/route/route_common.h +++ b/vpr7_x2p/vpr/SRC/route/route_common.h @@ -1,3 +1,6 @@ +#ifndef ROUTE_COMMON_H +#define ROUTE_COMMON_H + /************ Defines and types shared by all route files ********************/ typedef struct s_heap t_heap; @@ -118,4 +121,4 @@ void auto_detect_and_reserve_locally_used_opins(float pres_fac, boolean rip_up_l void free_chunk_memory_trace(void); - +#endif From baab9c4a21e856d8202aca4c57a561fbb112f4aa Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 20 Jun 2019 18:17:07 -0600 Subject: [PATCH 10/25] basically finished the coding of tileable rr_graph generator. testing to go --- .../rr_graph/rr_graph_tileable_builder.c | 818 +--------- .../rr_graph/rr_graph_tileable_builder.h | 32 +- .../device/rr_graph/rr_graph_tileable_gsb.cpp | 1346 +++++++++++++++++ .../device/rr_graph/rr_graph_tileable_gsb.h | 62 + .../rr_graph/rr_graph_tileable_sbox.cpp | 461 ------ .../device/rr_graph/rr_graph_tileable_sbox.h | 20 - vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.cpp | 59 + vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.h | 5 + vpr7_x2p/vpr/SRC/route/check_rr_graph.c | 15 +- vpr7_x2p/vpr/SRC/route/check_rr_graph.h | 30 +- vpr7_x2p/vpr/SRC/route/rr_graph.c | 10 +- vpr7_x2p/vpr/SRC/route/rr_graph.h | 6 +- .../vpr/SRC/route/rr_graph_indexed_data.c | 6 +- .../vpr/SRC/route/rr_graph_indexed_data.h | 2 +- vpr7_x2p/vpr/SRC/util/vpr_utils.c | 4 +- vpr7_x2p/vpr/SRC/util/vpr_utils.h | 2 +- 16 files changed, 1596 insertions(+), 1282 deletions(-) create mode 100755 vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.cpp create mode 100755 vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.h delete mode 100755 vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_sbox.cpp delete mode 100755 vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_sbox.h diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c index 58010142e..e8d4a0365 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c @@ -56,26 +56,24 @@ #include "ReadOptions.h" #include "rr_graph.h" #include "rr_graph2.h" +#include "check_rr_graph.h" #include "route_common.h" #include "fpga_x2p_types.h" #include "rr_graph_tileable_builder.h" -#include "fpga_x2p_backannotate_utils.h" -#include "my_free_fwd.h" #include "rr_blocks.h" #include "chan_node_details.h" #include "device_coordinator.h" -#include "rr_graph_tileable_sbox.h" +#include "rr_graph_tileable_gsb.h" /************************************************************************ * Local data stuctures in the file ***********************************************************************/ -typedef std::vector>> t_track2pin_map; -typedef std::vector>> t_pin2track_map; /************************************************************************ * Local function in the file ***********************************************************************/ + /************************************************************************ * Initialize a rr_node ************************************************************************/ @@ -153,9 +151,9 @@ void tileable_rr_graph_init_rr_node(t_rr_node* cur_rr_node) { * In this way, we can assign the number of tracks with repect to frequency ***********************************************************************/ static -std::vector get_num_tracks_per_seg_type(size_t chan_width, - std::vector segment_inf, - bool use_full_seg_groups) { +std::vector get_num_tracks_per_seg_type(const size_t chan_width, + const std::vector segment_inf, + const bool use_full_seg_groups) { std::vector result; std::vector demand; /* Make sure a clean start */ @@ -269,26 +267,26 @@ std::vector get_num_tracks_per_seg_type(size_t chan_width, * in X-direction and Y-direction channels!!! * So we will load segment details for different channels ***********************************************************************/ -static -ChanNodeDetails build_unidir_chan_node_details(size_t chan_width, size_t max_seg_length, - enum e_side device_side, - std::vector segment_inf) { +ChanNodeDetails build_unidir_chan_node_details(const size_t chan_width, const size_t max_seg_length, + const enum e_side device_side, + const std::vector segment_inf) { ChanNodeDetails chan_node_details; + size_t actual_chan_width = chan_width; /* Correct the chan_width: it should be an even number */ - if (0 != chan_width % 2) { - chan_width++; /* increment it to be even */ + if (0 != actual_chan_width % 2) { + actual_chan_width++; /* increment it to be even */ } - assert (0 == chan_width % 2); + assert (0 == actual_chan_width % 2); /* Reserve channel width */ chan_node_details.reserve(chan_width); /* Return if zero width is forced */ - if (0 == chan_width) { + if (0 == actual_chan_width) { return chan_node_details; } /* Find the number of segments required by each group */ - std::vector num_tracks = get_num_tracks_per_seg_type(chan_width/2, segment_inf, TRUE); + std::vector num_tracks = get_num_tracks_per_seg_type(actual_chan_width/2, segment_inf, TRUE); /* Add node to ChanNodeDetails */ size_t cur_track = 0; @@ -319,7 +317,7 @@ ChanNodeDetails build_unidir_chan_node_details(size_t chan_width, size_t max_seg } } /* Check if all the tracks have been satisified */ - assert (cur_track == chan_width); + assert (cur_track == actual_chan_width); /* If this is on the border of a device, segments should start */ switch (device_side) { @@ -375,7 +373,10 @@ enum e_side determine_io_grid_pin_side(const DeviceCoordinator& device_size, * For others, we consider all the sides ***********************************************************************/ static -std::vector get_grid_side_pins(const t_grid_tile& cur_grid, enum e_pin_type pin_type, enum e_side pin_side, int pin_height) { +std::vector get_grid_side_pins(const t_grid_tile& cur_grid, + const enum e_pin_type pin_type, + const enum e_side pin_side, + const int pin_height) { std::vector pin_list; /* Make sure a clear start */ pin_list.clear(); @@ -395,7 +396,7 @@ std::vector get_grid_side_pins(const t_grid_tile& cur_grid, enum e_pin_type * For others, we consider all the sides ***********************************************************************/ static -size_t get_grid_num_pins(const t_grid_tile& cur_grid, enum e_pin_type pin_type, enum e_side io_side) { +size_t get_grid_num_pins(const t_grid_tile& cur_grid, const enum e_pin_type pin_type, const enum e_side io_side) { size_t num_pins = 0; Side io_side_manager(io_side); /* For IO_TYPE sides */ @@ -422,9 +423,9 @@ size_t get_grid_num_pins(const t_grid_tile& cur_grid, enum e_pin_type pin_type, ***********************************************************************/ static std::vector estimate_num_rr_nodes_per_type(const DeviceCoordinator& device_size, - std::vector> grids, - std::vector chan_width, - std::vector segment_infs) { + const std::vector> grids, + const std::vector chan_width, + const std::vector segment_infs) { std::vector num_rr_nodes_per_type; /* reserve the vector: * we have the follow type: @@ -525,8 +526,10 @@ std::vector estimate_num_rr_nodes_per_type(const DeviceCoordinator& devi * Configure one rr_node to the fast-look up of a rr_graph ***********************************************************************/ static -void load_one_node_to_rr_graph_fast_lookup(t_rr_graph* rr_graph, int node_index, - t_rr_type node_type, int x, int y, int ptc_num) { +void load_one_node_to_rr_graph_fast_lookup(t_rr_graph* rr_graph, const int node_index, + const t_rr_type node_type, + const int x, const int y, + const int ptc_num) { /* check the size of ivec (nelem), * if the ptc_num exceeds the size limit, we realloc the ivec */ if (ptc_num > rr_graph->rr_node_indices[node_type][x][y].nelem - 1) { @@ -545,10 +548,10 @@ void load_one_node_to_rr_graph_fast_lookup(t_rr_graph* rr_graph, int node_index, static void load_one_grid_rr_nodes_basic_info(const DeviceCoordinator& grid_coordinator, const t_grid_tile& cur_grid, - enum e_side io_side, + const enum e_side io_side, t_rr_graph* rr_graph, size_t* cur_node_id, - int wire_to_ipin_switch, int delayless_switch) { + const int wire_to_ipin_switch, const int delayless_switch) { Side io_side_manager(io_side); /* Walk through the height of each grid, * get pins and configure the rr_nodes */ @@ -791,10 +794,10 @@ void load_one_chan_rr_nodes_basic_info(const DeviceCoordinator& chan_coordinator static void load_rr_nodes_basic_info(t_rr_graph* rr_graph, const DeviceCoordinator& device_size, - std::vector> grids, - std::vector chan_width, - std::vector segment_infs, - int wire_to_ipin_switch, int delayless_switch) { + const std::vector> grids, + const std::vector chan_width, + const std::vector segment_infs, + const int wire_to_ipin_switch, const int delayless_switch) { /* counter */ size_t cur_node_id = 0; /* configure by node type */ @@ -966,665 +969,6 @@ void alloc_rr_graph_fast_lookup(const DeviceCoordinator& device_size, return; } -/* Build a RRChan Object with the given channel type and coorindators */ -static -RRChan build_one_tileable_rr_chan(const DeviceCoordinator& chan_coordinator, - t_rr_type chan_type, - const t_rr_graph* rr_graph, - const ChanNodeDetails& chan_details) { - int chan_width = 0; - t_rr_node** chan_rr_nodes = NULL; - - /* Create a rr_chan object and check if it is unique in the graph */ - RRChan rr_chan; - /* Fill the information */ - rr_chan.set_type(chan_type); - - /* Collect rr_nodes for this channel */ - chan_rr_nodes = get_chan_rr_nodes(&chan_width, chan_type, chan_coordinator.get_x(), chan_coordinator.get_y(), - rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->rr_node_indices); - - /* Reserve */ - /* rr_chan.reserve_node(size_t(chan_width)); */ - - /* Fill the rr_chan */ - for (size_t itrack = 0; itrack < size_t(chan_width); ++itrack) { - size_t iseg = chan_details.get_track_segment_id(itrack); - rr_chan.add_node(chan_rr_nodes[itrack], iseg); - } - - /* Free rr_nodes */ - my_free(chan_rr_nodes); - - return rr_chan; -} - -/*********************************************************************** - * Build a General Switch Block (GSB) - * which includes: - * [I] 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 - * - * -------------- -------------- - * | | CBY | | - * | Grid | ChanY | Grid | - * | [x][y+1] | [x][y+1] | [x+1][y+1] | - * | | | | - * -------------- -------------- - * ---------- - * ChanX & CBX | 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 - * - * [II] A X-direction Connection Block [x][y] - * The connection block shares the same routing channel[x][y] with the Switch Block - * We just need to fill the ipin nodes at TOP and BOTTOM sides - * as well as properly fill the ipin_grid_side information - * [III] A Y-direction Connection Block [x][y+1] - * The connection block shares the same routing channel[x][y+1] with the Switch Block - * We just need to fill the ipin nodes at LEFT and RIGHT sides - * as well as properly fill the ipin_grid_side information - ***********************************************************************/ -static -RRGSB build_one_tileable_rr_gsb(const DeviceCoordinator& device_range, - std::vector device_chan_width, - std::vector segment_inf, - const DeviceCoordinator& gsb_coordinator, - t_rr_graph* rr_graph) { - /* Create an object to return */ - RRGSB rr_gsb; - - /* Check */ - assert(gsb_coordinator.get_x() <= device_range.get_x()); - assert(gsb_coordinator.get_y() <= device_range.get_y()); - - /* Coordinator initialization */ - rr_gsb.set_coordinator(gsb_coordinator.get_x(), gsb_coordinator.get_y()); - - /* Basic information*/ - rr_gsb.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_gsb.get_num_sides(); ++side) { - /* Local variables inside this for loop */ - Side side_manager(side); - DeviceCoordinator coordinator = rr_gsb.get_side_block_coordinator(side_manager.get_side()); - RRChan rr_chan; - 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 => ? */ - /* Build a segment details, where we need the segment ids for building rr_chan - * We do not care starting and ending points here, so set chan_side as NUM_SIDES - */ - ChanNodeDetails chanx_details = build_unidir_chan_node_details(device_chan_width[0], device_range.get_x() - 1, - NUM_SIDES, segment_inf); - ChanNodeDetails chany_details = build_unidir_chan_node_details(device_chan_width[1], device_range.get_y() - 1, - NUM_SIDES, segment_inf); - - switch (side) { - case TOP: /* TOP = 0 */ - /* For the bording, we should take special care */ - if (gsb_coordinator.get_y() == device_range.get_y()) { - rr_gsb.clear_one_side(side_manager.get_side()); - break; - } - /* Routing channels*/ - /* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */ - /* Create a rr_chan object and check if it is unique in the graph */ - rr_chan = build_one_tileable_rr_chan(coordinator, CHANY, rr_graph, chany_details); - chan_dir_to_port_dir_mapping[0] = OUT_PORT; /* INC_DIRECTION => OUT_PORT */ - chan_dir_to_port_dir_mapping[1] = IN_PORT; /* DEC_DIRECTION => IN_PORT */ - - /* Build the Switch block: opin and opin_grid_side */ - /* 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, gsb_coordinator.get_x(), gsb_coordinator.get_y() + 1, 1, - rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->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, gsb_coordinator.get_x() + 1, gsb_coordinator.get_y() + 1, 3, - rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->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 RIGHT: /* RIGHT = 1 */ - /* For the bording, we should take special care */ - if (gsb_coordinator.get_x() == device_range.get_x()) { - rr_gsb.clear_one_side(side_manager.get_side()); - break; - } - /* Routing channels*/ - /* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */ - /* Collect rr_nodes for Tracks for top: chany[x][y+1] */ - /* Create a rr_chan object and check if it is unique in the graph */ - rr_chan = build_one_tileable_rr_chan(coordinator, CHANX, rr_graph, chanx_details); - chan_dir_to_port_dir_mapping[0] = OUT_PORT; /* INC_DIRECTION => OUT_PORT */ - chan_dir_to_port_dir_mapping[1] = IN_PORT; /* DEC_DIRECTION => IN_PORT */ - - /* Build the Switch block: opin and opin_grid_side */ - /* 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, gsb_coordinator.get_x() + 1, gsb_coordinator.get_y() + 1, 2, - rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->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, gsb_coordinator.get_x() + 1, gsb_coordinator.get_y(), 0, - rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->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 BOTTOM: /* BOTTOM = 2*/ - /* For the bording, we should take special care */ - if (gsb_coordinator.get_y() == 0) { - rr_gsb.clear_one_side(side_manager.get_side()); - break; - } - /* Routing channels*/ - /* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */ - /* Collect rr_nodes for Tracks for bottom: chany[x][y] */ - /* Create a rr_chan object and check if it is unique in the graph */ - rr_chan = build_one_tileable_rr_chan(coordinator, CHANY, rr_graph, chany_details); - chan_dir_to_port_dir_mapping[0] = IN_PORT; /* INC_DIRECTION => IN_PORT */ - chan_dir_to_port_dir_mapping[1] = OUT_PORT; /* DEC_DIRECTION => OUT_PORT */ - - /* Build the Switch block: opin and opin_grid_side */ - /* 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, gsb_coordinator.get_x() + 1, gsb_coordinator.get_y(), 3, - rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->rr_node_indices); - /* 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, gsb_coordinator.get_x(), gsb_coordinator.get_y(), 1, - rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->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 LEFT: /* LEFT = 3 */ - /* For the bording, we should take special care */ - if (gsb_coordinator.get_x() == 0) { - rr_gsb.clear_one_side(side_manager.get_side()); - break; - } - /* Routing channels*/ - /* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */ - /* Collect rr_nodes for Tracks for left: chanx[x][y] */ - /* Create a rr_chan object and check if it is unique in the graph */ - rr_chan = build_one_tileable_rr_chan(coordinator, CHANX, rr_graph, chanx_details); - chan_dir_to_port_dir_mapping[0] = IN_PORT; /* INC_DIRECTION => IN_PORT */ - chan_dir_to_port_dir_mapping[1] = OUT_PORT; /* DEC_DIRECTION => OUT_PORT */ - - /* Build the Switch block: opin and opin_grid_side */ - /* 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, gsb_coordinator.get_x(), gsb_coordinator.get_y() + 1, 2, - rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->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, gsb_coordinator.get_x(), gsb_coordinator.get_y(), 0, - rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->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[1] = TOP; - break; - default: - vpr_printf(TIO_MESSAGE_ERROR, - "(File:%s, [LINE%d])Invalid side index!\n", - __FILE__, __LINE__); - exit(1); - } - - /* Organize a vector of port direction */ - if (0 < rr_chan.get_chan_width()) { - std::vector rr_chan_dir; - rr_chan_dir.resize(rr_chan.get_chan_width()); - for (size_t itrack = 0; itrack < rr_chan.get_chan_width(); ++itrack) { - /* Identify the directionality, record it in rr_node_direction */ - if (INC_DIRECTION == rr_chan.get_node(itrack)->direction) { - rr_chan_dir[itrack] = chan_dir_to_port_dir_mapping[0]; - } else { - assert (DEC_DIRECTION == rr_chan.get_node(itrack)->direction); - rr_chan_dir[itrack] = chan_dir_to_port_dir_mapping[1]; - } - } - /* Fill chan_rr_nodes */ - rr_gsb.add_chan_node(side_manager.get_side(), rr_chan, rr_chan_dir); - } - - /* 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_gsb.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_gsb.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_gsb.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; - } - - /* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */ - for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { - /* Local variables inside this for loop */ - Side side_manager(side); - size_t ix; - size_t iy; - enum e_side chan_side; - int num_temp_ipin_rr_nodes = 0; - t_rr_node** temp_ipin_rr_node = NULL; - enum e_side ipin_rr_node_grid_side; - - switch (side) { - case TOP: /* TOP = 0 */ - /* For the bording, we should take special care */ - /* Check if left side chan width is 0 or not */ - chan_side = LEFT; - /* Build the connection block: ipin and ipin_grid_side */ - /* BOTTOM side INPUT Pins of Grid[x][y+1] */ - ix = rr_gsb.get_sb_x(); - iy = rr_gsb.get_sb_y() + 1; - ipin_rr_node_grid_side = BOTTOM; - break; - case RIGHT: /* RIGHT = 1 */ - /* For the bording, we should take special care */ - /* Check if TOP side chan width is 0 or not */ - chan_side = TOP; - /* Build the connection block: ipin and ipin_grid_side */ - /* LEFT side INPUT Pins of Grid[x+1][y+1] */ - ix = rr_gsb.get_sb_x() + 1; - iy = rr_gsb.get_sb_y() + 1; - ipin_rr_node_grid_side = LEFT; - break; - case BOTTOM: /* BOTTOM = 2*/ - /* For the bording, we should take special care */ - /* Check if left side chan width is 0 or not */ - chan_side = LEFT; - /* Build the connection block: ipin and ipin_grid_side */ - /* TOP side INPUT Pins of Grid[x][y] */ - ix = rr_gsb.get_sb_x(); - iy = rr_gsb.get_sb_y(); - ipin_rr_node_grid_side = TOP; - break; - case LEFT: /* LEFT = 3 */ - /* For the bording, we should take special care */ - /* Check if left side chan width is 0 or not */ - chan_side = TOP; - /* Build the connection block: ipin and ipin_grid_side */ - /* RIGHT side INPUT Pins of Grid[x][y+1] */ - ix = rr_gsb.get_sb_x(); - iy = rr_gsb.get_sb_y() + 1; - ipin_rr_node_grid_side = RIGHT; - break; - default: - vpr_printf(TIO_MESSAGE_ERROR, - "(File:%s, [LINE%d])Invalid side index!\n", - __FILE__, __LINE__); - exit(1); - } - - /* If there is no channel at this side, we skip ipin_node annotation */ - if (0 == rr_gsb.get_chan_width(chan_side)) { - continue; - } - /* Collect IPIN rr_nodes*/ - temp_ipin_rr_node = get_grid_side_pin_rr_nodes(&(num_temp_ipin_rr_nodes), - IPIN, ix, iy, ipin_rr_node_grid_side, - rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->rr_node_indices); - /* Fill the ipin nodes of RRGSB */ - for (int inode = 0; inode < num_temp_ipin_rr_nodes; ++inode) { - rr_gsb.add_ipin_node(temp_ipin_rr_node[inode], side_manager.get_side(), ipin_rr_node_grid_side); - } - /* Free */ - num_temp_ipin_rr_nodes = 0; - my_free(temp_ipin_rr_node); - } - - return rr_gsb; - -} - -/************************************************************************ - * Add a edge connecting two rr_nodes - * For src rr_node, update the edge list and update switch_id, - * For des rr_node, update the fan_in - ***********************************************************************/ -static -void add_one_edge_for_two_rr_nodes(t_rr_graph* rr_graph, - int src_rr_node_id, - int des_rr_node_id, - short switch_id) { - /* Check */ - assert ( (-1 < src_rr_node_id) && (src_rr_node_id < rr_graph->num_rr_nodes) ); - assert ( (-1 < des_rr_node_id) && (des_rr_node_id < rr_graph->num_rr_nodes) ); - - t_rr_node* src_rr_node = &(rr_graph->rr_node[src_rr_node_id]); - t_rr_node* des_rr_node = &(rr_graph->rr_node[des_rr_node_id]); - - /* Allocate edge and switch to src_rr_node */ - src_rr_node->num_edges++; - if (NULL == src_rr_node->edges) { - /* calloc */ - src_rr_node->edges = (int*) my_calloc( src_rr_node->num_edges, sizeof(int) ); - src_rr_node->switches = (short*) my_calloc( src_rr_node->num_edges, sizeof(short) ); - } else { - /* realloc */ - src_rr_node->edges = (int*) my_realloc(src_rr_node->edges, - src_rr_node->num_edges * sizeof(int)); - src_rr_node->switches = (short*) my_realloc(src_rr_node->switches, - src_rr_node->num_edges * sizeof(short)); - } - /* Fill edge and switch info */ - src_rr_node->edges[src_rr_node->num_edges - 1] = des_rr_node_id; - src_rr_node->switches[src_rr_node->num_edges - 1] = switch_id; - - /* Update the des_rr_node */ - des_rr_node->fan_in++; - - return; -} - -/************************************************************************ - * Create edges for each rr_node of a General Switch Blocks (GSB): - * 1. create edges between SOURCE and OPINs - * 2. create edges between IPINs and SINKs - * 3. create edges between CHANX | CHANY and IPINs (connections inside connection blocks) - * 4. create edges between OPINs, CHANX and CHANY (connections inside switch blocks) - * 5. create edges between OPINs and IPINs (direct-connections) - ***********************************************************************/ -static -void build_edges_for_one_tileable_rr_gsb(t_rr_graph* rr_graph, RRGSB* rr_gsb, - t_track2pin_map track2ipin_map, - t_pin2track_map opin2track_map, - t_track2track_map track2track_map) { - /* Check rr_gsb */ - assert (NULL != rr_gsb); - - /* Walk through each sides */ - for (size_t side = 0; side < rr_gsb->get_num_sides(); ++side) { - Side side_manager(side); - enum e_side gsb_side = side_manager.get_side(); - - /* Find OPINs */ - for (size_t inode = 0; inode < rr_gsb->get_num_opin_nodes(gsb_side); ++inode) { - t_rr_node* opin_node = rr_gsb->get_opin_node(gsb_side, inode); - /* 1. create edges between SOURCE and OPINs */ - int src_node_id = get_rr_node_index(opin_node->xlow, opin_node->ylow, - SOURCE, opin_node->ptc_num, - rr_graph->rr_node_indices); - /* add edges to the src_node */ - add_one_edge_for_two_rr_nodes(rr_graph, src_node_id, opin_node - rr_graph->rr_node, - opin_node->driver_switch); - /* 2. create edges between OPINs and CHANX|CHANY, using opin2track_map */ - int num_edges = opin2track_map[side_manager.to_size_t()][inode].size(); - for (int iedge = 0; iedge < num_edges; ++iedge) { - int track_node_id = opin2track_map[side_manager.to_size_t()][inode][iedge]; - /* add edges to the chan_node */ - add_one_edge_for_two_rr_nodes(rr_graph, opin_node - rr_graph->rr_node, track_node_id, - rr_graph->rr_node[track_node_id].driver_switch); - } - } - - /* Find IPINs */ - for (size_t inode = 0; inode < rr_gsb->get_num_ipin_nodes(gsb_side); ++inode) { - t_rr_node* ipin_node = rr_gsb->get_ipin_node(gsb_side, inode); - /* 3. create edges between IPINs and SINKs */ - int sink_node_id = get_rr_node_index(ipin_node->xlow, ipin_node->ylow, - SINK, ipin_node->ptc_num, - rr_graph->rr_node_indices); - /* add edges to connect the IPIN node to SINK nodes */ - add_one_edge_for_two_rr_nodes(rr_graph, ipin_node - rr_graph->rr_node, sink_node_id, - rr_graph->rr_node[sink_node_id].driver_switch); - } - /* Find CHANX or CHANY */ - for (size_t inode = 0; inode < rr_gsb->get_chan_width(gsb_side); ++inode) { - t_rr_node* chan_node = rr_gsb->get_chan_node(gsb_side, inode); - /* 4. create edges between CHANX|CHANY and IPINs, using ipin2track_map */ - int num_edges = track2ipin_map[side_manager.to_size_t()][inode].size(); - for (int iedge = 0; iedge < num_edges; ++iedge) { - int ipin_node_id = track2ipin_map[side_manager.to_size_t()][inode][iedge]; - /* add edges to the chan_node */ - add_one_edge_for_two_rr_nodes(rr_graph, chan_node - rr_graph->rr_node, ipin_node_id, - rr_graph->rr_node[ipin_node_id].driver_switch); - } - /* 5. create edges between CHANX|CHANY and CHANX|CHANY, using track2track_map */ - num_edges = track2track_map[side_manager.to_size_t()][inode].size(); - for (int iedge = 0; iedge < num_edges; ++iedge) { - int track_node_id = track2track_map[side_manager.to_size_t()][inode][iedge]; - /* add edges to the chan_node */ - add_one_edge_for_two_rr_nodes(rr_graph, chan_node - rr_graph->rr_node, track_node_id, - rr_graph->rr_node[track_node_id].driver_switch); - } - } - } - - return; -} - -/************************************************************************ - * Convert the pin_to_track_map[0..nodes_per_chan-1][0..height][0..3][pin_numbers] - * to the existing routing resources in the General Switch Block (GSB) - * The resulting matrix will be oragnized in - * pin2track_map[gsb_side][0..chan_width-1][ipin_indices] - ***********************************************************************/ -static -t_pin2track_map build_gsb_pin_to_track_map(const RRGSB& rr_gsb, - std::vector< std::vector > grids, - int** Fc, - bool is_Fc_out, - int***** pin_to_track_map) { - /* [0..gsb_side][0..num_tracks][0..Fc-1] */ - t_pin2track_map pin2track_map; - /* Resize the matrix */ - pin2track_map.resize(rr_gsb.get_num_sides()); - - /* Walk through each side */ - for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { - Side side_manager(side); - enum e_side gsb_side = side_manager.get_side(); - /* Get channel width and resize the matrix */ - size_t chan_width = rr_gsb.get_chan_width(gsb_side); - pin2track_map[side].resize(chan_width); - /* Find the ipin/opin nodes */ - size_t num_pin_nodes; - if (true == is_Fc_out) { /* Fc_out, we consider OPINs */ - num_pin_nodes = rr_gsb.get_num_opin_nodes(gsb_side); - } else { /* Fc_in, we consider IPINs */ - num_pin_nodes = rr_gsb.get_num_ipin_nodes(gsb_side); - } - for (size_t inode = 0; inode < num_pin_nodes; ++inode) { - t_rr_node* pin_node; - if (true == is_Fc_out) { /* Fc_out, we consider OPINs */ - pin_node = rr_gsb.get_opin_node(gsb_side, inode); - } else { /* Fc_in, we consider IPINs */ - pin_node = rr_gsb.get_ipin_node(gsb_side, inode); - } - /* For each IPIN, we find the type_descriptor, offset and pin_side on the grid */ - int grid_type_id = grids[pin_node->xlow][pin_node->ylow].type->index; - int offset = grid[pin_node->xlow][pin_node->ylow].offset; - enum e_side pin_side; - if (true == is_Fc_out) { /* Fc_out, we consider OPINs */ - pin_side = rr_gsb.get_opin_node_grid_side(gsb_side, inode); - } else { /* Fc_in, we consider IPINs */ - pin_side = rr_gsb.get_ipin_node_grid_side(gsb_side, inode); - } - /* Now, we fill the return matrix */ - /* Bypass empty array */ - if (NULL == pin_to_track_map[grid_type_id][pin_node->ptc_num][offset][0]) { - continue; - } - /* Get each track_id */ - for (int iconn = 0; iconn < Fc[grid_type_id][pin_node->ptc_num]; ++iconn) { - int track_id = pin_to_track_map[grid_type_id][pin_node->ptc_num][offset][pin_side][iconn]; - pin2track_map[gsb_side][track_id].push_back(inode); - } - } - } - - return pin2track_map; -} - -/************************************************************************ - * Build the track_to_ipin_map[gsb_side][0..chan_width-1][ipin_indices] - * based on the existing routing resources in the General Switch Block (GSB) - * This function supports both X-directional and Y-directional tracks - * The mapping is done in the following steps: - * 1. build a list of routing tracks which are allowed for connections - * We will check the Connection Block (CB) population of each routing track. - * By comparing current chan_y - ylow, we can determine if a CB connection - * is required for each routing track - * 2. Divide the routing tracks by segment types, so that we can balance - * the connections between IPINs and different types of routing tracks. - * 3. Scale the Fc of each pin to the actual number of routing tracks - * actual_Fc = (int) Fc * num_tracks / chan_width - * 4. Build ipin_to_track_map[gsb_side][0..num_ipin_nodes-1][track_indices] - * For each IPIN, we ensure at least one connection to the tracks. - * Then, we assign IPINs to tracks evenly while satisfying the actual_Fc - * 5. Convert the ipin_to_track_map to track_to_ipin_map - ***********************************************************************/ - -/************************************************************************ - * Build the opin_to_track_map[gsb_side][0..num_opin_nodes-1][track_indices] - * based on the existing routing resources in the General Switch Block (GSB) - * This function supports both X-directional and Y-directional tracks - * The mapping is done in the following steps: - * 1. Build a list of routing tracks whose starting points locate at this GSB - * (xlow - gsb_x == 0) - * 2. Divide the routing tracks by segment types, so that we can balance - * the connections between OPINs and different types of routing tracks. - * 3. Scale the Fc of each pin to the actual number of routing tracks - * actual_Fc = (int) Fc * num_tracks / chan_width - ***********************************************************************/ - -/************************************************************************ - * Add all direct clb-pin-to-clb-pin edges to given opin - ***********************************************************************/ -static -void build_direct_connections_for_one_gsb(t_rr_graph* rr_graph, - const DeviceCoordinator& device_size, - const DeviceCoordinator& from_grid_coordinator, - const t_grid_tile& from_grid, - const int delayless_switch, - const int num_directs, - const t_direct_inf *directs, - const t_clb_to_clb_directs *clb_to_clb_directs) { - t_type_ptr grid_type = from_grid.type; - - /* Iterate through all direct connections */ - for (int i = 0; i < num_directs; ++i) { - /* Bypass unmatched direct clb-to-clb connections */ - if (grid_type != clb_to_clb_directs[i].from_clb_type) { - continue; - } - bool swap; - int max_index, min_index; - /* Compute index of opin with regards to given pins */ - if ( clb_to_clb_directs[i].from_clb_pin_start_index - > clb_to_clb_directs[i].from_clb_pin_end_index) { - swap = true; - max_index = clb_to_clb_directs[i].from_clb_pin_start_index; - min_index = clb_to_clb_directs[i].from_clb_pin_end_index; - } else { - swap = false; - min_index = clb_to_clb_directs[i].from_clb_pin_start_index; - max_index = clb_to_clb_directs[i].from_clb_pin_end_index; - } - /* get every opin in the range */ - for (int opin = min_index; opin <= max_index; ++opin) { - int offset = opin - min_index; - /* This opin is specified to connect directly to an ipin, now compute which ipin to connect to */ - DeviceCoordinator to_grid_coordinator(from_grid_coordinator.get_x() + directs[i].x_offset, - from_grid_coordinator.get_y() + directs[i].y_offset); - if ( (to_grid_coordinator.get_x() < device_size.get_x() - 1) - && (to_grid_coordinator.get_y() < device_size.get_y() - 1) ) { - int ipin = OPEN; - if ( clb_to_clb_directs[i].to_clb_pin_start_index - > clb_to_clb_directs[i].to_clb_pin_end_index) { - if (true == swap) { - ipin = clb_to_clb_directs[i].to_clb_pin_end_index + offset; - } else { - ipin = clb_to_clb_directs[i].to_clb_pin_start_index - offset; - } - } else { - if(true == swap) { - ipin = clb_to_clb_directs[i].to_clb_pin_end_index - offset; - } else { - ipin = clb_to_clb_directs[i].to_clb_pin_start_index + offset; - } - } - /* Get the pin index in the rr_graph */ - int from_grid_ofs = from_grid.offset; - int to_grid_ofs = grid[to_grid_coordinator.get_x()][to_grid_coordinator.get_y()].offset; - int opin_node_id = get_rr_node_index(from_grid_coordinator.get_x(), - from_grid_coordinator.get_y() - from_grid_ofs, - OPIN, opin, rr_graph->rr_node_indices); - int ipin_node_id = get_rr_node_index(to_grid_coordinator.get_x(), - to_grid_coordinator.get_y() - to_grid_ofs, - IPIN, ipin, rr_graph->rr_node_indices); - /* add edges to the opin_node */ - add_one_edge_for_two_rr_nodes(rr_graph, opin_node_id, ipin_node_id, - delayless_switch); - } - } - } - - return; -} - - /************************************************************************ * Build the edges of each rr_node tile by tile: * We classify rr_nodes into a general switch block (GSB) data structure @@ -1640,12 +984,11 @@ void build_direct_connections_for_one_gsb(t_rr_graph* rr_graph, static void build_rr_graph_edges(t_rr_graph* rr_graph, const DeviceCoordinator& device_size, - std::vector< std::vector > grids, - std::vector device_chan_width, - std::vector segment_inf, + const std::vector< std::vector > grids, + const std::vector device_chan_width, + const std::vector segment_inf, int** Fc_in, int** Fc_out, - int***** ipin_to_track_map, int***** opin_to_track_map, - enum e_switch_block_type sb_type, int Fs) { + const enum e_switch_block_type sb_type, const int Fs) { DeviceCoordinator device_range(device_size.get_x() - 1, device_size.get_y() - 1); @@ -1657,13 +1000,19 @@ void build_rr_graph_edges(t_rr_graph* rr_graph, /* Create a GSB object */ RRGSB rr_gsb = build_one_tileable_rr_gsb(device_range, device_chan_width, segment_inf, gsb_coordinator, rr_graph); + DeviceCoordinator grid_coordinator = rr_gsb.get_grid_coordinator(); + /* adapt the track_to_ipin_lookup for the GSB nodes */ - t_pin2track_map ipin2track_map; /* [0..track_gsb_side][0..num_tracks][ipin_indices] */ - ipin2track_map = build_gsb_pin_to_track_map(rr_gsb, grids, Fc_in, false, ipin_to_track_map); + t_track2pin_map track2ipin_map; /* [0..track_gsb_side][0..num_tracks][ipin_indices] */ + /* Get the Fc index of the grid */ + int grid_Fc_in_index = grids[grid_coordinator.get_x()][grid_coordinator.get_x()].type->index; + track2ipin_map = build_gsb_track_to_ipin_map(rr_graph, rr_gsb, segment_inf, Fc_in[grid_Fc_in_index]); /* adapt the opin_to_track_map for the GSB nodes */ t_pin2track_map opin2track_map; /* [0..gsb_side][0..num_opin_node][track_indices] */ - opin2track_map = build_gsb_pin_to_track_map(rr_gsb, grids, Fc_out, true, opin_to_track_map); + /* Get the Fc index of the grid */ + int grid_Fc_out_index = grids[grid_coordinator.get_x()][grid_coordinator.get_x()].type->index; + opin2track_map = build_gsb_opin_to_track_map(rr_graph, rr_gsb, segment_inf, Fc_out[grid_Fc_out_index]); /* adapt the switch_block_conn for the GSB nodes */ t_track2track_map sb_conn; /* [0..from_gsb_side][0..chan_width-1][track_indices] */ @@ -1671,7 +1020,7 @@ void build_rr_graph_edges(t_rr_graph* rr_graph, /* Build edges for a GSB */ build_edges_for_one_tileable_rr_gsb(rr_graph, &rr_gsb, - ipin2track_map, opin2track_map, + track2ipin_map, opin2track_map, sb_conn); /* Finish this GSB, go to the next*/ } @@ -1686,7 +1035,7 @@ void build_rr_graph_edges(t_rr_graph* rr_graph, static void build_rr_graph_direct_connections(t_rr_graph* rr_graph, const DeviceCoordinator& device_size, - std::vector< std::vector > grids, + const std::vector< std::vector > grids, const int delayless_switch, const int num_directs, const t_direct_inf *directs, @@ -1702,7 +1051,7 @@ void build_rr_graph_direct_connections(t_rr_graph* rr_graph, continue; } DeviceCoordinator from_grid_coordinator(ix, iy); - build_direct_connections_for_one_gsb(rr_graph, device_size, + build_direct_connections_for_one_gsb(rr_graph, device_size, grids, from_grid_coordinator, grids[ix][iy], delayless_switch, @@ -1752,17 +1101,17 @@ void build_rr_graph_direct_connections(t_rr_graph* rr_graph, * a. cost_index * b. RC tree ***********************************************************************/ -void build_tileable_unidir_rr_graph(INP int L_num_types, - INP t_type_ptr types, INP int L_nx, INP int L_ny, - INP struct s_grid_tile **L_grid, INP int chan_width, - INP enum e_switch_block_type sb_type, INP int Fs, - INP int num_seg_types, - INP t_segment_inf * segment_inf, - INP int delayless_switch, - INP t_timing_inf timing_inf, INP int wire_to_ipin_switch, - INP enum e_base_cost_type base_cost_type, - INP t_direct_inf *directs, - INP int num_directs, INP boolean ignore_Fc_0, +void build_tileable_unidir_rr_graph(INP const int L_num_types, + INP t_type_ptr types, INP const int L_nx, INP const int L_ny, + INP const struct s_grid_tile **L_grid, INP const int chan_width, + INP const enum e_switch_block_type sb_type, INP const int Fs, + INP const int num_seg_types, + INP const t_segment_inf * segment_inf, + INP const int num_switches, INP int const delayless_switch, const int global_route_switch, + INP const t_timing_inf timing_inf, INP int const wire_to_ipin_switch, + INP const enum e_base_cost_type base_cost_type, + INP const t_direct_inf *directs, + INP const int num_directs, INP const boolean ignore_Fc_0, OUTP int *Warnings) { /* Create an empty graph */ t_rr_graph rr_graph; @@ -1856,23 +1205,6 @@ void build_tileable_unidir_rr_graph(INP int L_num_types, *Warnings |= RR_GRAPH_WARN_FC_CLIPPED; } - /* START IPINP MAP */ - /* Create ipin map lookups */ - int***** ipin_to_track_map = (int*****) my_calloc(L_num_types, sizeof(int****)); - boolean* perturb_ipins = alloc_and_load_perturb_ipins(chan_width, L_num_types, Fc_in, Fc_out, UNI_DIRECTIONAL); - for (int i = 0; i < L_num_types; ++i) { - ipin_to_track_map[i] = alloc_and_load_pin_to_track_map(RECEIVER, chan_width, Fc_in[i], &types[i], - perturb_ipins[i], UNI_DIRECTIONAL); - } - /* END IPINP MAP */ - - /* START OPINP MAP */ - /* Create opin map lookups */ - int***** opin_to_track_map = (int*****) my_calloc(L_num_types, sizeof(int****)); - for (int i = 0; i < L_num_types; ++i) { - opin_to_track_map[i] = alloc_and_load_pin_to_track_map(DRIVER, chan_width, Fc_out[i], &types[i], FALSE, UNI_DIRECTIONAL); - } - /************************************************************************ * 6. Build the connections tile by tile: * We classify rr_nodes into a general switch block (GSB) data structure @@ -1884,7 +1216,7 @@ void build_tileable_unidir_rr_graph(INP int L_num_types, /* Create edges for a tileable rr_graph */ build_rr_graph_edges(&rr_graph, device_size, grids, device_chan_width, segment_infs, - Fc_in, Fc_out, ipin_to_track_map, opin_to_track_map, + Fc_in, Fc_out, sb_type, Fs); /************************************************************************ @@ -1903,18 +1235,21 @@ void build_tileable_unidir_rr_graph(INP int L_num_types, * a. cost_index * b. RC tree ***********************************************************************/ + /* We set global variables for rr_nodes here, they will be updated by rr_graph_external */ + num_rr_nodes = rr_graph.num_rr_nodes; + rr_node = rr_graph.rr_node; + rr_node_indices = rr_graph.rr_node_indices; + rr_graph_externals(timing_inf, segment_inf, num_seg_types, chan_width, wire_to_ipin_switch, base_cost_type); /************************************************************************ * 9. Sanitizer for the rr_graph, check connectivities of rr_nodes ***********************************************************************/ + check_rr_graph(GRAPH_UNIDIR_TILEABLE, types, L_nx, L_ny, chan_width, Fs, + num_seg_types, num_switches, segment_inf, global_route_switch, + delayless_switch, wire_to_ipin_switch, Fc_in, Fc_out); - /* We set global variables for rr_nodes here, - */ - num_rr_nodes = rr_graph.num_rr_nodes; - rr_node = rr_graph.rr_node; - rr_node_indices = rr_graph.rr_node_indices; /************************************************************************ * 10. Free all temp stucts @@ -1929,19 +1264,6 @@ void build_tileable_unidir_rr_graph(INP int L_num_types, free_matrix(Fc_out,0, L_num_types, 0, sizeof(int)); Fc_out = NULL; } - if (perturb_ipins) { - free(perturb_ipins); - perturb_ipins = NULL; - } - if (opin_to_track_map) { - for (int i = 0; i < L_num_types; ++i) { - free_matrix4(opin_to_track_map[i], 0, types[i].num_pins - 1, 0, - types[i].height - 1, 0, 3, 0, sizeof(int)); - } - free(opin_to_track_map); - } - - free_type_pin_to_track_map(ipin_to_track_map, types); if(clb_to_clb_directs != NULL) { free(clb_to_clb_directs); } diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.h b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.h index 26e1f9cc7..7f26867a1 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.h +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.h @@ -1,15 +1,27 @@ #ifndef RR_GRAPH_TILEABLE_BUILDER_H #define RR_GRAPH_TILEABLE_BUILDER_H -void build_tileable_unidir_rr_graph(INP int L_num_types, - INP t_type_ptr types, INP int L_nx, INP int L_ny, - INP struct s_grid_tile **L_grid, INP int chan_width, - INP enum e_switch_block_type sb_type, INP int Fs, - INP int num_seg_types, - INP t_segment_inf * segment_inf, - INP int delayless_switch, - INP t_timing_inf timing_inf, INP int wire_to_ipin_switch, - INP enum e_base_cost_type base_cost_type, INP t_direct_inf *directs, - INP int num_directs, INP boolean ignore_Fc_0, OUTP int *Warnings); +#include + +#include "vpr_types.h" + +#include "chan_node_details.h" + +ChanNodeDetails build_unidir_chan_node_details(const size_t chan_width, const size_t max_seg_length, + const enum e_side device_side, + const std::vector segment_inf); + +void build_tileable_unidir_rr_graph(INP const int L_num_types, + INP t_type_ptr types, INP const int L_nx, INP const int L_ny, + INP const struct s_grid_tile **L_grid, INP const int chan_width, + INP const enum e_switch_block_type sb_type, INP const int Fs, + INP const int num_seg_types, + INP const t_segment_inf * segment_inf, + INP const int num_switches, INP int const delayless_switch, const int global_route_switch, + INP const t_timing_inf timing_inf, INP int const wire_to_ipin_switch, + INP const enum e_base_cost_type base_cost_type, + INP const t_direct_inf *directs, + INP const int num_directs, INP const boolean ignore_Fc_0, + OUTP int *Warnings); #endif diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.cpp b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.cpp new file mode 100755 index 000000000..e67e72e17 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.cpp @@ -0,0 +1,1346 @@ +/********************************************************** + * MIT License + * + * Copyright (c) 2018 LNIS - The University of Utah + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + ***********************************************************************/ + +/************************************************************************ + * Filename: rr_graph_tileable_gsb.cpp + * Created by: Xifan Tang + * Change history: + * +-------------------------------------+ + * | Date | Author | Notes + * +-------------------------------------+ + * | 2019/06/19 | Xifan Tang | Created + * +-------------------------------------+ + ***********************************************************************/ +/************************************************************************ + * This file contains a builder for track-to-track connections inside a + * tileable General Switch Block (GSB). + ***********************************************************************/ + +#include +#include + +#include +#include + +#include "vpr_types.h" +#include "rr_graph_util.h" +#include "rr_graph2.h" + +#include "rr_graph_tileable_gsb.h" +#include "rr_graph_tileable_builder.h" + +#include "fpga_x2p_backannotate_utils.h" + +#include "my_free_fwd.h" + +/************************************************************************ + * Internal data structures + ***********************************************************************/ +typedef std::vector> t_track_group; + +/************************************************************************ + * A enumeration to list the status of a track inside a GSB + * 1. start; 2. end; 3. passing + * This is used to group tracks which ease the building of + * track-to-track mapping matrix + ***********************************************************************/ +enum e_track_status { + TRACK_START, + TRACK_END, + TRACK_PASS, + NUM_TRACK_STATUS /* just a place holder to get the number of status */ +}; + +/************************************************************************ + * Check if a track starts from this GSB or not + * (xlow, ylow) should be same as the GSB side coordinator + * + * Check if a track ends at this GSB or not + * (xhigh, yhigh) should be same as the GSB side coordinator + ***********************************************************************/ +static +enum e_track_status determine_track_status_of_gsb(const RRGSB& rr_gsb, + const enum e_side gsb_side, + const size_t track_id) { + enum e_track_status track_status = TRACK_PASS; + /* Get the rr_node */ + t_rr_node* track_node = rr_gsb.get_chan_node(gsb_side, track_id); + /* Get the coordinators */ + DeviceCoordinator side_coordinator = rr_gsb.get_side_block_coordinator(gsb_side); + + /* INC_DIRECTION start_track: (xlow, ylow) should be same as the GSB side coordinator */ + if ( ((size_t)track_node->xlow == side_coordinator.get_x()) + && ((size_t)track_node->ylow == side_coordinator.get_y()) + && (OUT_PORT == rr_gsb.get_chan_node_direction(gsb_side, track_id)) ) { + /* Double check: start track should be an OUTPUT PORT of the GSB */ + track_status = TRACK_START; + } + /* INC_DIRECTION end_track: (xhigh, yhigh) should be same as the GSB side coordinator */ + if ( ((size_t)track_node->xhigh == side_coordinator.get_x()) + && ((size_t)track_node->yhigh == side_coordinator.get_y()) + && (IN_PORT == rr_gsb.get_chan_node_direction(gsb_side, track_id)) ) { + /* Double check: end track should be an INPUT PORT of the GSB */ + track_status = TRACK_END; + } + + return track_status; +} + + +/************************************************************************ + * Check if the GSB is in the Connection Block (CB) population list of the segment + * SB population of a L4 wire: 1 0 0 1 + * + * +----+ +----+ +----+ +----+ + * | CB |--->| CB |--->| CB |--->| CB | + * +----+ +----+ +----+ +----+ + * Engage CB connection Yes No No Yes + * + * We will find the offset between gsb_side_coordinator and (xlow,ylow) of the track + * Use the offset to check if the tracks should engage in this GSB connection + ***********************************************************************/ +static +bool is_gsb_in_track_cb_population(const RRGSB& rr_gsb, + const enum e_side gsb_side, + const int track_id, + const std::vector segment_inf) { + /* Get the rr_node */ + t_rr_node* track_node = rr_gsb.get_chan_node(gsb_side, track_id); + /* Get the coordinators */ + DeviceCoordinator side_coordinator = rr_gsb.get_side_block_coordinator(gsb_side); + + /* Get the offset */ + size_t offset = (side_coordinator.get_x() - track_node->xlow) + + (side_coordinator.get_y() - track_node->ylow); + + /* Get segment id */ + size_t seg_id = rr_gsb.get_chan_node_segment(gsb_side, track_id); + /* validate offset */ + assert (offset < (size_t)segment_inf[seg_id].cb_len); + + /* Get the SB population */ + bool in_cb_population = false; + if (TRUE == segment_inf[seg_id].cb[offset]) { + in_cb_population = true; + } + return in_cb_population; +} + +/************************************************************************ + * Check if the GSB is in the Switch Block (SB) population list of the segment + * SB population of a L3 wire: 1 0 0 1 + * + * +----+ +----+ +----+ +----+ + * | SB |--->| SB |--->| SB |--->| SB | + * +----+ +----+ +----+ +----+ + * Engage SB connection Yes No No Yes + * + * We will find the offset between gsb_side_coordinator and (xlow,ylow) of the track + * Use the offset to check if the tracks should engage in this GSB connection + ***********************************************************************/ +static +bool is_gsb_in_track_sb_population(const RRGSB& rr_gsb, + const enum e_side gsb_side, + const int track_id, + const std::vector segment_inf) { + /* Get the rr_node */ + t_rr_node* track_node = rr_gsb.get_chan_node(gsb_side, track_id); + /* Get the coordinators */ + DeviceCoordinator side_coordinator = rr_gsb.get_side_block_coordinator(gsb_side); + + /* Get the offset */ + size_t offset = (side_coordinator.get_x() - track_node->xlow) + + (side_coordinator.get_y() - track_node->ylow); + + /* Get segment id */ + size_t seg_id = rr_gsb.get_chan_node_segment(gsb_side, track_id); + /* validate offset */ + assert (offset < (size_t)segment_inf[seg_id].sb_len); + + /* Get the SB population */ + bool in_sb_population = false; + if (TRUE == segment_inf[seg_id].sb[offset]) { + in_sb_population = true; + } + return in_sb_population; +} + +/************************************************************************ + * Create a list of track_id based on the to_track and num_to_tracks + * We consider the following list [to_track, to_track + Fs/3 - 1] + * if the [to_track + Fs/3 - 1] exceeds the num_to_tracks, we start over from 0! +***********************************************************************/ +static +std::vector get_to_track_list(const int Fs, const int to_track, const int num_to_tracks) { + std::vector to_tracks; + for (int i = 0; i < Fs; i = i + 3) { + /* TODO: currently, for Fs > 3, I always search the next from_track until Fs is satisfied + * The optimal track selection should be done in a more scientific way!!! + */ + size_t to_track_i = to_track + i; + /* make sure the track id is still in range */ + if ( to_track_i > (size_t)num_to_tracks) { + to_track_i = to_track_i % num_to_tracks; + } + /* from track must be connected */ + to_tracks.push_back(to_track_i); + } + return to_tracks; +} + +/************************************************************************ + * This function aims to return the track indices that drive the from_track + * in a Switch Block + * The track_ids to return will depend on different topologies of SB + * SUBSET, UNIVERSAL, and WILTON. + ***********************************************************************/ +static +std::vector get_switch_block_to_track_id(const enum e_switch_block_type switch_block_type, + const int Fs, + const enum e_side from_side, + const int from_track, + const enum e_side to_side, + const int num_to_tracks) { + + /* This routine returns the track number to which the from_track should + * connect. It supports any Fs % 3 == 0, switch blocks. + */ + std::vector to_tracks; + + /* TODO: currently, for Fs > 3, I always search the next from_track until Fs is satisfied + * The optimal track selection should be done in a more scientific way!!! + */ + + assert (0 == Fs % 3); + + switch (switch_block_type) { + case SUBSET: /* NB: Global routing uses SUBSET too */ + to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); + /* Finish, we return */ + return to_tracks; + case UNIVERSAL: + if ( (from_side == LEFT) + || (from_side == RIGHT) ) { + /* For the prev_side, to_track is from_track + * For the next_side, to_track is num_to_tracks - 1 - from_track + * For the opposite_side, to_track is always from_track + */ + Side side_manager(from_side); + if ( (to_side == side_manager.get_opposite()) + || (to_side == side_manager.get_rotate_counterclockwise()) ) { + to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); + } else if (to_side == side_manager.get_rotate_clockwise()) { + to_tracks = get_to_track_list(Fs, num_to_tracks - 1 - from_track, num_to_tracks); + } + } + + if ( (from_side == TOP) + || (from_side == BOTTOM) ) { + /* For the next_side, to_track is from_track + * For the prev_side, to_track is num_to_tracks - 1 - from_track + * For the opposite_side, to_track is always from_track + */ + Side side_manager(from_side); + if ( (to_side == side_manager.get_opposite()) + || (to_side == side_manager.get_rotate_clockwise()) ) { + to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); + } else if (to_side == side_manager.get_rotate_counterclockwise()) { + to_tracks = get_to_track_list(Fs, num_to_tracks - 1 - from_track, num_to_tracks); + } + } + /* Finish, we return */ + return to_tracks; + /* End switch_block_type == UNIVERSAL case. */ + case WILTON: + /* See S. Wilton Phd thesis, U of T, 1996 p. 103 for details on following. */ + if (from_side == LEFT) { + if (to_side == RIGHT) { /* CHANX to CHANX */ + to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); + } else if (to_side == TOP) { /* from CHANX to CHANY */ + to_tracks = get_to_track_list(Fs, (num_to_tracks - (from_track % num_to_tracks)) % num_to_tracks, num_to_tracks); + } else if (to_side == BOTTOM) { + to_tracks = get_to_track_list(Fs, (num_to_tracks + from_track - 1) % num_to_tracks, num_to_tracks); + } + } else if (from_side == RIGHT) { + if (to_side == LEFT) { /* CHANX to CHANX */ + to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); + } else if (to_side == TOP) { /* from CHANX to CHANY */ + to_tracks = get_to_track_list(Fs, (num_to_tracks + from_track - 1) % num_to_tracks, num_to_tracks); + } else if (to_side == BOTTOM) { + to_tracks = get_to_track_list(Fs, (num_to_tracks - 2 - from_track) % num_to_tracks, num_to_tracks); + } + } else if (from_side == BOTTOM) { + if (to_side == TOP) { /* CHANY to CHANY */ + to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); + } else if (to_side == LEFT) { /* from CHANY to CHANX */ + to_tracks = get_to_track_list(Fs, (from_track + 1) % num_to_tracks, num_to_tracks); + } else if (to_side == RIGHT) { + to_tracks = get_to_track_list(Fs, (2 * num_to_tracks - 2 - from_track) % num_to_tracks, num_to_tracks); + } + } else if (from_side == TOP) { + if (to_side == BOTTOM) { /* CHANY to CHANY */ + to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); + } else if (to_side == LEFT) { /* from CHANY to CHANX */ + to_tracks = get_to_track_list(Fs, (num_to_tracks - (from_track % num_to_tracks)) % num_to_tracks, num_to_tracks); + } else if (to_side == RIGHT) { + to_tracks = get_to_track_list(Fs, (from_track + 1) % num_to_tracks, num_to_tracks); + } + } + /* Finish, we return */ + return to_tracks; + /* End switch_block_type == WILTON case. */ + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d]) Invalid switch block pattern !\n", + __FILE__, __LINE__); + exit(1); + } + + return to_tracks; +} + + +/************************************************************************ + * Build the track_to_track_map[from_side][0..chan_width-1][to_side][track_indices] + * For a group of from_track nodes and to_track nodes + * For each side of from_tracks, we call a routine to get the list of to_tracks + * Then, we fill the track2track_map + ***********************************************************************/ +static +void build_gsb_one_group_track_to_track_map(const t_rr_graph* rr_graph, + const RRGSB& rr_gsb, + const enum e_switch_block_type sb_type, + const int Fs, + const t_track_group from_tracks, /* [0..gsb_side][track_indices] */ + const t_track_group to_tracks, /* [0..gsb_side][track_indices] */ + t_track2track_map* track2track_map) { + for (size_t side = 0; side < from_tracks.size(); ++side) { + Side side_manager(side); + enum e_side gsb_side = side_manager.get_side(); + /* Find the other sides where the start tracks will locate */ + std::vector to_track_sides; + /* 0. opposite side */ + to_track_sides.push_back(side_manager.get_opposite()); + /* 1. prev side */ + /* Previous side definition: TOP => LEFT; RIGHT=>TOP; BOTTOM=>RIGHT; LEFT=>BOTTOM */ + to_track_sides.push_back(side_manager.get_rotate_counterclockwise()); + /* 2. next side */ + /* Next side definition: TOP => RIGHT; RIGHT=>BOTTOM; BOTTOM=>LEFT; LEFT=>TOP */ + to_track_sides.push_back(side_manager.get_rotate_clockwise()); + + for (size_t inode = 0; inode < from_tracks[side].size(); ++inode) { + for (size_t to_side_id = 0; to_side_id < to_track_sides.size(); ++to_side_id) { + enum e_side to_side = to_track_sides[to_side_id]; + Side to_side_manager(to_side); + size_t to_side_index = to_side_manager.to_size_t(); + /* Bypass those to_sides have no nodes */ + if (0 == to_tracks[to_side_index].size()) { + continue; + } + /* Get other track_ids depending on the switch block pattern */ + /* Find the track ids that will start at the other sides */ + std::vector to_track_ids = get_switch_block_to_track_id(sb_type, Fs, gsb_side, inode, + to_side, + to_tracks[to_side_index].size()); + /* Update the track2track_map: */ + for (size_t to_track_id = 0; to_track_id < to_track_ids.size(); ++to_track_id) { + size_t from_side_index = side_manager.to_size_t(); + size_t from_track_index = from_tracks[side][inode]; + size_t to_track_index = to_tracks[to_side_index][to_track_ids[to_track_id]]; + t_rr_node* to_track_node = rr_gsb.get_chan_node(to_side, to_track_index); + (*track2track_map)[from_side_index][from_track_index].push_back(to_track_node - rr_graph->rr_node); + } + } + } + } + + return; +} + +/************************************************************************ + * Build the track_to_track_map[from_side][0..chan_width-1][to_side][track_indices] + * based on the existing routing resources in the General Switch Block (GSB) + * The track_indices is the indices of tracks that the node at from_side and [0..chan_width-1] will drive + * IMPORTANT: the track_indices are the indicies in the GSB context, but not the rr_graph!!! + * We separate the connections into two groups: + * Group 1: the routing tracks start from this GSB + * We will apply switch block patterns (SUBSET, UNIVERSAL, WILTON) + * Group 2: the routing tracks do not start from this GSB (bypassing wires) + * We will apply switch block patterns (SUBSET, UNIVERSAL, WILTON) + * but we will check the Switch Block (SB) population of these + * routing segments, and determine which requires connections + * + * CHANY CHANY CHANY CHANY + * [0] [1] [2] [3] + * start yes no yes no + * end +-------------------------+ start Group 1 Group 2 + * no CHANX[0] | TOP | CHANX[0] yes TOP/BOTTOM TOP/BOTTOM + * | | CHANY[0,2] CHANY[1,3] + * yes CHANX[1] | | CHANX[1] no + * | LEFT RIGHT | + * no CHANX[2] | | CHANX[2] yes + * | | + * yes CHANX[3] | BOTTOM | CHANX[3] no + * +-------------------------+ + * CHANY CHANY CHANY CHANY + * [0] [1] [2] [3] + * start yes no yes no + * + * The mapping is done in the following steps: (For each side of the GSB) + * 1. Build a list of tracks that will start from this side + * if a track starts, its xlow/ylow is the same as the x,y of this gsb + * 2. Build a list of tracks on the other sides belonging to Group 1. + * Take the example of RIGHT side, we will collect + * a. tracks that will end at the LEFT side + * b. tracks that will start at the TOP side + * c. tracks that will start at the BOTTOM side + * 3. Apply switch block patterns to Group 1 (SUBSET, UNIVERSAL, WILTON) + * 4. Build a list of tracks on the other sides belonging to Group 1. + * Take the example of RIGHT side, we will collect + * a. tracks that will bypass at the TOP side + * b. tracks that will bypass at the BOTTOM side + * 5. Apply switch block patterns to Group 2 (SUBSET, UNIVERSAL, WILTON) + ***********************************************************************/ +t_track2track_map build_gsb_track_to_track_map(const t_rr_graph* rr_graph, + const RRGSB& rr_gsb, + const enum e_switch_block_type sb_type, + const int Fs, + const std::vector segment_inf) { + t_track2track_map track2track_map; /* [0..gsb_side][0..chan_width][track_indices] */ + + /* Categorize tracks into 3 groups: + * (1) tracks will start here + * (2) tracks will end here + * (2) tracks will just pass through the SB */ + t_track_group start_tracks; /* [0..gsb_side][track_indices] */ + t_track_group end_tracks; /* [0..gsb_side][track_indices] */ + t_track_group pass_tracks; /* [0..gsb_side][track_indices] */ + + /* resize to the number of sides */ + start_tracks.resize(rr_gsb.get_num_sides()); + end_tracks.resize(rr_gsb.get_num_sides()); + pass_tracks.resize(rr_gsb.get_num_sides()); + + /* Walk through each side */ + for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { + Side side_manager(side); + enum e_side gsb_side = side_manager.get_side(); + /* Build a list of tracks that will start from this side */ + for (size_t inode = 0; inode < rr_gsb.get_chan_width(gsb_side); ++inode) { + /* check if this track will start from here */ + enum e_track_status track_status = determine_track_status_of_gsb(rr_gsb, gsb_side, inode); + switch (track_status) { + case TRACK_START: + /* update starting track list */ + start_tracks[gsb_side].push_back(inode); + break; + case TRACK_END: + /* Update end track list */ + end_tracks[gsb_side].push_back(inode); + break; + case TRACK_PASS: + /* We need to check Switch block population of this track + * The track node will not be considered if there supposed to be no SB at this position + */ + if (true == is_gsb_in_track_sb_population(rr_gsb, gsb_side, inode, segment_inf)) { + /* Update passing track list */ + pass_tracks[gsb_side].push_back(inode); + } + break; + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d]) Invalid track status!\n", + __FILE__, __LINE__); + exit(1); + } + } + } + + /* Allocate track2track map */ + track2track_map.resize(rr_gsb.get_num_sides()); + for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { + Side side_manager(side); + enum e_side gsb_side = side_manager.get_side(); + /* allocate track2track_map[gsb_side] */ + track2track_map[side].resize(rr_gsb.get_chan_width(gsb_side)); + for (size_t inode = 0; inode < rr_gsb.get_chan_width(gsb_side); ++inode) { + /* allocate track2track_map[gsb_side][inode] */ + track2track_map[side][inode].clear(); + } + } + + /* For Group 1: we build connections between end_tracks and start_tracks*/ + build_gsb_one_group_track_to_track_map(rr_graph, rr_gsb, + sb_type, Fs, + end_tracks, start_tracks, + &track2track_map); + + /* For Group 2: we build connections between end_tracks and start_tracks*/ + /* Currently, I use the same Switch Block pattern for the passing tracks and end tracks, + * TODO: This can be improved with different patterns! + */ + build_gsb_one_group_track_to_track_map(rr_graph, rr_gsb, + sb_type, Fs, + pass_tracks, start_tracks, + &track2track_map); + + return track2track_map; +} + +/* Build a RRChan Object with the given channel type and coorindators */ +static +RRChan build_one_tileable_rr_chan(const DeviceCoordinator& chan_coordinator, + const t_rr_type chan_type, + const t_rr_graph* rr_graph, + const ChanNodeDetails& chan_details) { + int chan_width = 0; + t_rr_node** chan_rr_nodes = NULL; + + /* Create a rr_chan object and check if it is unique in the graph */ + RRChan rr_chan; + /* Fill the information */ + rr_chan.set_type(chan_type); + + /* Collect rr_nodes for this channel */ + chan_rr_nodes = get_chan_rr_nodes(&chan_width, chan_type, chan_coordinator.get_x(), chan_coordinator.get_y(), + rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->rr_node_indices); + + /* Reserve */ + /* rr_chan.reserve_node(size_t(chan_width)); */ + + /* Fill the rr_chan */ + for (size_t itrack = 0; itrack < size_t(chan_width); ++itrack) { + size_t iseg = chan_details.get_track_segment_id(itrack); + rr_chan.add_node(chan_rr_nodes[itrack], iseg); + } + + /* Free rr_nodes */ + my_free(chan_rr_nodes); + + return rr_chan; +} + +/*********************************************************************** + * Build a General Switch Block (GSB) + * which includes: + * [I] 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 + * + * -------------- -------------- + * | | CBY | | + * | Grid | ChanY | Grid | + * | [x][y+1] | [x][y+1] | [x+1][y+1] | + * | | | | + * -------------- -------------- + * ---------- + * ChanX & CBX | 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 + * + * [II] A X-direction Connection Block [x][y] + * The connection block shares the same routing channel[x][y] with the Switch Block + * We just need to fill the ipin nodes at TOP and BOTTOM sides + * as well as properly fill the ipin_grid_side information + * [III] A Y-direction Connection Block [x][y+1] + * The connection block shares the same routing channel[x][y+1] with the Switch Block + * We just need to fill the ipin nodes at LEFT and RIGHT sides + * as well as properly fill the ipin_grid_side information + ***********************************************************************/ +RRGSB build_one_tileable_rr_gsb(const DeviceCoordinator& device_range, + const std::vector device_chan_width, + const std::vector segment_inf, + const DeviceCoordinator& gsb_coordinator, + t_rr_graph* rr_graph) { + /* Create an object to return */ + RRGSB rr_gsb; + + /* Check */ + assert(gsb_coordinator.get_x() <= device_range.get_x()); + assert(gsb_coordinator.get_y() <= device_range.get_y()); + + /* Coordinator initialization */ + rr_gsb.set_coordinator(gsb_coordinator.get_x(), gsb_coordinator.get_y()); + + /* Basic information*/ + rr_gsb.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_gsb.get_num_sides(); ++side) { + /* Local variables inside this for loop */ + Side side_manager(side); + DeviceCoordinator coordinator = rr_gsb.get_side_block_coordinator(side_manager.get_side()); + RRChan rr_chan; + 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 => ? */ + /* Build a segment details, where we need the segment ids for building rr_chan + * We do not care starting and ending points here, so set chan_side as NUM_SIDES + */ + ChanNodeDetails chanx_details = build_unidir_chan_node_details(device_chan_width[0], device_range.get_x() - 1, + NUM_SIDES, segment_inf); + ChanNodeDetails chany_details = build_unidir_chan_node_details(device_chan_width[1], device_range.get_y() - 1, + NUM_SIDES, segment_inf); + + switch (side) { + case TOP: /* TOP = 0 */ + /* For the bording, we should take special care */ + if (gsb_coordinator.get_y() == device_range.get_y()) { + rr_gsb.clear_one_side(side_manager.get_side()); + break; + } + /* Routing channels*/ + /* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */ + /* Create a rr_chan object and check if it is unique in the graph */ + rr_chan = build_one_tileable_rr_chan(coordinator, CHANY, rr_graph, chany_details); + chan_dir_to_port_dir_mapping[0] = OUT_PORT; /* INC_DIRECTION => OUT_PORT */ + chan_dir_to_port_dir_mapping[1] = IN_PORT; /* DEC_DIRECTION => IN_PORT */ + + /* Build the Switch block: opin and opin_grid_side */ + /* 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, gsb_coordinator.get_x(), gsb_coordinator.get_y() + 1, 1, + rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->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, gsb_coordinator.get_x() + 1, gsb_coordinator.get_y() + 1, 3, + rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->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 RIGHT: /* RIGHT = 1 */ + /* For the bording, we should take special care */ + if (gsb_coordinator.get_x() == device_range.get_x()) { + rr_gsb.clear_one_side(side_manager.get_side()); + break; + } + /* Routing channels*/ + /* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */ + /* Collect rr_nodes for Tracks for top: chany[x][y+1] */ + /* Create a rr_chan object and check if it is unique in the graph */ + rr_chan = build_one_tileable_rr_chan(coordinator, CHANX, rr_graph, chanx_details); + chan_dir_to_port_dir_mapping[0] = OUT_PORT; /* INC_DIRECTION => OUT_PORT */ + chan_dir_to_port_dir_mapping[1] = IN_PORT; /* DEC_DIRECTION => IN_PORT */ + + /* Build the Switch block: opin and opin_grid_side */ + /* 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, gsb_coordinator.get_x() + 1, gsb_coordinator.get_y() + 1, 2, + rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->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, gsb_coordinator.get_x() + 1, gsb_coordinator.get_y(), 0, + rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->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 BOTTOM: /* BOTTOM = 2*/ + /* For the bording, we should take special care */ + if (gsb_coordinator.get_y() == 0) { + rr_gsb.clear_one_side(side_manager.get_side()); + break; + } + /* Routing channels*/ + /* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */ + /* Collect rr_nodes for Tracks for bottom: chany[x][y] */ + /* Create a rr_chan object and check if it is unique in the graph */ + rr_chan = build_one_tileable_rr_chan(coordinator, CHANY, rr_graph, chany_details); + chan_dir_to_port_dir_mapping[0] = IN_PORT; /* INC_DIRECTION => IN_PORT */ + chan_dir_to_port_dir_mapping[1] = OUT_PORT; /* DEC_DIRECTION => OUT_PORT */ + + /* Build the Switch block: opin and opin_grid_side */ + /* 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, gsb_coordinator.get_x() + 1, gsb_coordinator.get_y(), 3, + rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->rr_node_indices); + /* 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, gsb_coordinator.get_x(), gsb_coordinator.get_y(), 1, + rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->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 LEFT: /* LEFT = 3 */ + /* For the bording, we should take special care */ + if (gsb_coordinator.get_x() == 0) { + rr_gsb.clear_one_side(side_manager.get_side()); + break; + } + /* Routing channels*/ + /* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */ + /* Collect rr_nodes for Tracks for left: chanx[x][y] */ + /* Create a rr_chan object and check if it is unique in the graph */ + rr_chan = build_one_tileable_rr_chan(coordinator, CHANX, rr_graph, chanx_details); + chan_dir_to_port_dir_mapping[0] = IN_PORT; /* INC_DIRECTION => IN_PORT */ + chan_dir_to_port_dir_mapping[1] = OUT_PORT; /* DEC_DIRECTION => OUT_PORT */ + + /* Build the Switch block: opin and opin_grid_side */ + /* 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, gsb_coordinator.get_x(), gsb_coordinator.get_y() + 1, 2, + rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->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, gsb_coordinator.get_x(), gsb_coordinator.get_y(), 0, + rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->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[1] = TOP; + break; + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d])Invalid side index!\n", + __FILE__, __LINE__); + exit(1); + } + + /* Organize a vector of port direction */ + if (0 < rr_chan.get_chan_width()) { + std::vector rr_chan_dir; + rr_chan_dir.resize(rr_chan.get_chan_width()); + for (size_t itrack = 0; itrack < rr_chan.get_chan_width(); ++itrack) { + /* Identify the directionality, record it in rr_node_direction */ + if (INC_DIRECTION == rr_chan.get_node(itrack)->direction) { + rr_chan_dir[itrack] = chan_dir_to_port_dir_mapping[0]; + } else { + assert (DEC_DIRECTION == rr_chan.get_node(itrack)->direction); + rr_chan_dir[itrack] = chan_dir_to_port_dir_mapping[1]; + } + } + /* Fill chan_rr_nodes */ + rr_gsb.add_chan_node(side_manager.get_side(), rr_chan, rr_chan_dir); + } + + /* 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_gsb.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_gsb.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_gsb.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; + } + + /* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */ + for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { + /* Local variables inside this for loop */ + Side side_manager(side); + size_t ix; + size_t iy; + enum e_side chan_side; + int num_temp_ipin_rr_nodes = 0; + t_rr_node** temp_ipin_rr_node = NULL; + enum e_side ipin_rr_node_grid_side; + + switch (side) { + case TOP: /* TOP = 0 */ + /* For the bording, we should take special care */ + /* Check if left side chan width is 0 or not */ + chan_side = LEFT; + /* Build the connection block: ipin and ipin_grid_side */ + /* BOTTOM side INPUT Pins of Grid[x][y+1] */ + ix = rr_gsb.get_sb_x(); + iy = rr_gsb.get_sb_y() + 1; + ipin_rr_node_grid_side = BOTTOM; + break; + case RIGHT: /* RIGHT = 1 */ + /* For the bording, we should take special care */ + /* Check if TOP side chan width is 0 or not */ + chan_side = TOP; + /* Build the connection block: ipin and ipin_grid_side */ + /* LEFT side INPUT Pins of Grid[x+1][y+1] */ + ix = rr_gsb.get_sb_x() + 1; + iy = rr_gsb.get_sb_y() + 1; + ipin_rr_node_grid_side = LEFT; + break; + case BOTTOM: /* BOTTOM = 2*/ + /* For the bording, we should take special care */ + /* Check if left side chan width is 0 or not */ + chan_side = LEFT; + /* Build the connection block: ipin and ipin_grid_side */ + /* TOP side INPUT Pins of Grid[x][y] */ + ix = rr_gsb.get_sb_x(); + iy = rr_gsb.get_sb_y(); + ipin_rr_node_grid_side = TOP; + break; + case LEFT: /* LEFT = 3 */ + /* For the bording, we should take special care */ + /* Check if left side chan width is 0 or not */ + chan_side = TOP; + /* Build the connection block: ipin and ipin_grid_side */ + /* RIGHT side INPUT Pins of Grid[x][y+1] */ + ix = rr_gsb.get_sb_x(); + iy = rr_gsb.get_sb_y() + 1; + ipin_rr_node_grid_side = RIGHT; + break; + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d])Invalid side index!\n", + __FILE__, __LINE__); + exit(1); + } + + /* If there is no channel at this side, we skip ipin_node annotation */ + if (0 == rr_gsb.get_chan_width(chan_side)) { + continue; + } + /* Collect IPIN rr_nodes*/ + temp_ipin_rr_node = get_grid_side_pin_rr_nodes(&(num_temp_ipin_rr_nodes), + IPIN, ix, iy, ipin_rr_node_grid_side, + rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->rr_node_indices); + /* Fill the ipin nodes of RRGSB */ + for (int inode = 0; inode < num_temp_ipin_rr_nodes; ++inode) { + rr_gsb.add_ipin_node(temp_ipin_rr_node[inode], side_manager.get_side(), ipin_rr_node_grid_side); + } + /* Free */ + num_temp_ipin_rr_nodes = 0; + my_free(temp_ipin_rr_node); + } + + return rr_gsb; +} + +/************************************************************************ + * Add a edge connecting two rr_nodes + * For src rr_node, update the edge list and update switch_id, + * For des rr_node, update the fan_in + ***********************************************************************/ +static +void add_one_edge_for_two_rr_nodes(const t_rr_graph* rr_graph, + const int src_rr_node_id, + const int des_rr_node_id, + const short switch_id) { + /* Check */ + assert ( (-1 < src_rr_node_id) && (src_rr_node_id < rr_graph->num_rr_nodes) ); + assert ( (-1 < des_rr_node_id) && (des_rr_node_id < rr_graph->num_rr_nodes) ); + + t_rr_node* src_rr_node = &(rr_graph->rr_node[src_rr_node_id]); + t_rr_node* des_rr_node = &(rr_graph->rr_node[des_rr_node_id]); + + /* Allocate edge and switch to src_rr_node */ + src_rr_node->num_edges++; + if (NULL == src_rr_node->edges) { + /* calloc */ + src_rr_node->edges = (int*) my_calloc( src_rr_node->num_edges, sizeof(int) ); + src_rr_node->switches = (short*) my_calloc( src_rr_node->num_edges, sizeof(short) ); + } else { + /* realloc */ + src_rr_node->edges = (int*) my_realloc(src_rr_node->edges, + src_rr_node->num_edges * sizeof(int)); + src_rr_node->switches = (short*) my_realloc(src_rr_node->switches, + src_rr_node->num_edges * sizeof(short)); + } + /* Fill edge and switch info */ + src_rr_node->edges[src_rr_node->num_edges - 1] = des_rr_node_id; + src_rr_node->switches[src_rr_node->num_edges - 1] = switch_id; + + /* Update the des_rr_node */ + des_rr_node->fan_in++; + + return; +} + +/************************************************************************ + * Create edges for each rr_node of a General Switch Blocks (GSB): + * 1. create edges between SOURCE and OPINs + * 2. create edges between IPINs and SINKs + * 3. create edges between CHANX | CHANY and IPINs (connections inside connection blocks) + * 4. create edges between OPINs, CHANX and CHANY (connections inside switch blocks) + * 5. create edges between OPINs and IPINs (direct-connections) + ***********************************************************************/ +void build_edges_for_one_tileable_rr_gsb(const t_rr_graph* rr_graph, const RRGSB* rr_gsb, + const t_track2pin_map track2ipin_map, + const t_pin2track_map opin2track_map, + const t_track2track_map track2track_map) { + /* Check rr_gsb */ + assert (NULL != rr_gsb); + + /* Walk through each sides */ + for (size_t side = 0; side < rr_gsb->get_num_sides(); ++side) { + Side side_manager(side); + enum e_side gsb_side = side_manager.get_side(); + + /* Find OPINs */ + for (size_t inode = 0; inode < rr_gsb->get_num_opin_nodes(gsb_side); ++inode) { + t_rr_node* opin_node = rr_gsb->get_opin_node(gsb_side, inode); + /* 1. create edges between SOURCE and OPINs */ + int src_node_id = get_rr_node_index(opin_node->xlow, opin_node->ylow, + SOURCE, opin_node->ptc_num, + rr_graph->rr_node_indices); + /* add edges to the src_node */ + add_one_edge_for_two_rr_nodes(rr_graph, src_node_id, opin_node - rr_graph->rr_node, + opin_node->driver_switch); + /* 2. create edges between OPINs and CHANX|CHANY, using opin2track_map */ + int num_edges = opin2track_map[side_manager.to_size_t()][inode].size(); + for (int iedge = 0; iedge < num_edges; ++iedge) { + int track_node_id = opin2track_map[side_manager.to_size_t()][inode][iedge]; + /* add edges to the chan_node */ + add_one_edge_for_two_rr_nodes(rr_graph, opin_node - rr_graph->rr_node, track_node_id, + rr_graph->rr_node[track_node_id].driver_switch); + } + } + + /* Find IPINs */ + for (size_t inode = 0; inode < rr_gsb->get_num_ipin_nodes(gsb_side); ++inode) { + t_rr_node* ipin_node = rr_gsb->get_ipin_node(gsb_side, inode); + /* 3. create edges between IPINs and SINKs */ + int sink_node_id = get_rr_node_index(ipin_node->xlow, ipin_node->ylow, + SINK, ipin_node->ptc_num, + rr_graph->rr_node_indices); + /* add edges to connect the IPIN node to SINK nodes */ + add_one_edge_for_two_rr_nodes(rr_graph, ipin_node - rr_graph->rr_node, sink_node_id, + rr_graph->rr_node[sink_node_id].driver_switch); + } + /* Find CHANX or CHANY */ + for (size_t inode = 0; inode < rr_gsb->get_chan_width(gsb_side); ++inode) { + t_rr_node* chan_node = rr_gsb->get_chan_node(gsb_side, inode); + /* 4. create edges between CHANX|CHANY and IPINs, using ipin2track_map */ + int num_edges = track2ipin_map[side_manager.to_size_t()][inode].size(); + for (int iedge = 0; iedge < num_edges; ++iedge) { + int ipin_node_id = track2ipin_map[side_manager.to_size_t()][inode][iedge]; + /* add edges to the chan_node */ + add_one_edge_for_two_rr_nodes(rr_graph, chan_node - rr_graph->rr_node, ipin_node_id, + rr_graph->rr_node[ipin_node_id].driver_switch); + } + /* 5. create edges between CHANX|CHANY and CHANX|CHANY, using track2track_map */ + num_edges = track2track_map[side_manager.to_size_t()][inode].size(); + for (int iedge = 0; iedge < num_edges; ++iedge) { + int track_node_id = track2track_map[side_manager.to_size_t()][inode][iedge]; + /* add edges to the chan_node */ + add_one_edge_for_two_rr_nodes(rr_graph, chan_node - rr_graph->rr_node, track_node_id, + rr_graph->rr_node[track_node_id].driver_switch); + } + } + } + + return; +} + +/************************************************************************ + * Build track2ipin_map for an IPIN + * 1. build a list of routing tracks which are allowed for connections + * We will check the Connection Block (CB) population of each routing track. + * By comparing current chan_y - ylow, we can determine if a CB connection + * is required for each routing track + * 2. Divide the routing tracks by segment types, so that we can balance + * the connections between IPINs and different types of routing tracks. + * 3. Scale the Fc of each pin to the actual number of routing tracks + * actual_Fc = (int) Fc * num_tracks / chan_width + ***********************************************************************/ +static +void build_gsb_one_ipin_track2pin_map(const t_rr_graph* rr_graph, + const RRGSB& rr_gsb, + const enum e_side ipin_side, + const size_t ipin_node_id, + const size_t Fc, + const size_t offset, + const std::vector segment_inf, + t_track2pin_map* track2ipin_map) { + /* Get a list of segment_ids*/ + enum e_side chan_side = rr_gsb.get_cb_chan_side(ipin_side); + std::vector seg_list = rr_gsb.get_chan_segment_ids(chan_side); + size_t chan_width = rr_gsb.get_chan_width(chan_side); + Side ipin_side_manager(ipin_side); + t_rr_node* ipin_node = rr_gsb.get_ipin_node(ipin_side, ipin_node_id); + + for (size_t iseg = 0; iseg < seg_list.size(); ++iseg) { + /* Get a list of node that have the segment id */ + std::vector track_list = rr_gsb.get_chan_node_ids_by_segment_ids(chan_side, seg_list[iseg]); + /* Refine the track_list: keep those will have connection blocks in the GSB */ + std::vector actual_track_list; + for (size_t inode = 0; inode < track_list.size(); ++inode) { + /* Check if tracks allow connection blocks in the GSB*/ + if (false == is_gsb_in_track_cb_population(rr_gsb, chan_side, track_list[inode], segment_inf)) { + continue; /* Bypass condition */ + } + /* Push the node to actual_track_list */ + actual_track_list.push_back(track_list[inode]); + } + /* Check the actual track list */ + assert (0 == actual_track_list.size() % 2); + + /* Scale Fc */ + int actual_Fc = Fc * (float)(actual_track_list.size() / chan_width); + /* Minimum Fc should be 2 : ensure we will connect to a pair of routing tracks */ + actual_Fc = std::max(2, actual_Fc); + /* Compute the step between two connection from this IPIN to tracks: + * step = W' / Fc', W' and Fc' are the adapted W and Fc from actual_track_list and Fc_in + */ + size_t track_step = actual_track_list.size() / actual_Fc; + /* Track step mush be a multiple of 2!!!*/ + if (0 != track_step % 2) { + track_step--; /* minus 1 to increase connectivity */ + } + /* Make sure step should be at least 2 */ + track_step = std::max(2, (int)track_step); + /* Adapt offset to the range of actual_track_list */ + size_t actual_offset = offset % actual_track_list.size(); + /* rotate the track list by an offset */ + std::rotate(actual_track_list.begin(), actual_track_list.begin() + actual_offset, actual_track_list.end()); + + /* Assign tracks: since we assign 2 track per round, we increment itrack by 2* step */ + for (size_t itrack = 0; itrack < actual_track_list.size(); itrack = itrack + 2 * track_step) { + /* Update pin2track map */ + size_t ipin_side_index = ipin_side_manager.to_size_t(); + size_t track_index = actual_track_list[itrack]; + size_t ipin_index = ipin_node - rr_graph->rr_node; + (*track2ipin_map)[ipin_side_index][track_index].push_back(ipin_index); + (*track2ipin_map)[ipin_side_index][track_index + 1].push_back(ipin_index); + } + } + + return; +} + +/************************************************************************ + * Build opin2track_map for an OPIN + * 1. build a list of routing tracks which are allowed for connections + * We will check the Switch Block (SB) population of each routing track. + * By comparing current chan_y - ylow, we can determine if a SB connection + * is required for each routing track + * 2. Divide the routing tracks by segment types, so that we can balance + * the connections between OPINs and different types of routing tracks. + * 3. Scale the Fc of each pin to the actual number of routing tracks + * actual_Fc = (int) Fc * num_tracks / chan_width + ***********************************************************************/ +static +void build_gsb_one_opin_pin2track_map(const t_rr_graph* rr_graph, + const RRGSB& rr_gsb, + const enum e_side opin_side, + const size_t opin_node_id, + const size_t Fc, + const size_t offset, + const std::vector segment_inf, + t_pin2track_map* opin2track_map) { + /* Get a list of segment_ids*/ + std::vector seg_list = rr_gsb.get_chan_segment_ids(opin_side); + enum e_side chan_side = opin_side; + size_t chan_width = rr_gsb.get_chan_width(chan_side); + Side opin_side_manager(opin_side); + + for (size_t iseg = 0; iseg < seg_list.size(); ++iseg) { + /* Get a list of node that have the segment id */ + std::vector track_list = rr_gsb.get_chan_node_ids_by_segment_ids(chan_side, seg_list[iseg]); + /* Refine the track_list: keep those will have connection blocks in the GSB */ + std::vector actual_track_list; + for (size_t inode = 0; inode < track_list.size(); ++inode) { + /* Check if tracks allow connection blocks in the GSB*/ + if ( (false == is_gsb_in_track_sb_population(rr_gsb, chan_side, track_list[inode], segment_inf)) + && (TRACK_START != determine_track_status_of_gsb(rr_gsb, chan_side, track_list[inode])) ) { + continue; /* Bypass condition */ + } + /* Push the node to actual_track_list */ + actual_track_list.push_back(track_list[inode]); + } + + /* Scale Fc */ + int actual_Fc = Fc * (float)(actual_track_list.size() / chan_width); + /* Minimum Fc should be 1 : ensure we will drive 1 routing track */ + actual_Fc = std::max(1, actual_Fc); + /* Compute the step between two connection from this IPIN to tracks: + * step = W' / Fc', W' and Fc' are the adapted W and Fc from actual_track_list and Fc_in + */ + size_t track_step = actual_track_list.size() / actual_Fc; + /* Track step mush be a multiple of 2!!!*/ + /* Make sure step should be at least 1 */ + track_step = std::max(1, (int)track_step); + /* Adapt offset to the range of actual_track_list */ + size_t actual_offset = offset % actual_track_list.size(); + /* rotate the track list by an offset */ + std::rotate(actual_track_list.begin(), actual_track_list.begin() + actual_offset, actual_track_list.end()); + + /* Assign tracks */ + for (size_t itrack = 0; itrack < actual_track_list.size(); itrack = itrack + track_step) { + /* Update pin2track map */ + size_t opin_side_index = opin_side_manager.to_size_t(); + size_t track_index = actual_track_list[itrack]; + size_t track_rr_node_index = rr_gsb.get_chan_node(chan_side, track_index) - rr_graph->rr_node; + (*opin2track_map)[opin_side_index][opin_node_id].push_back(track_rr_node_index); + } + } + + return; +} + + +/************************************************************************ + * Build the track_to_ipin_map[gsb_side][0..chan_width-1][ipin_indices] + * based on the existing routing resources in the General Switch Block (GSB) + * This function supports both X-directional and Y-directional tracks + * The mapping is done in the following steps: + * 1. Build ipin_to_track_map[gsb_side][0..num_ipin_nodes-1][track_indices] + * For each IPIN, we ensure at least one connection to the tracks. + * Then, we assign IPINs to tracks evenly while satisfying the actual_Fc + * 2. Convert the ipin_to_track_map to track_to_ipin_map + ***********************************************************************/ +t_track2pin_map build_gsb_track_to_ipin_map(t_rr_graph* rr_graph, + const RRGSB& rr_gsb, + const std::vector segment_inf, + const int* Fc_in) { + t_track2pin_map track2ipin_map; + /* Resize the matrix */ + track2ipin_map.resize(rr_gsb.get_num_sides()); + + /* offset counter: it aims to balance the track-to-IPIN for each connection block */ + std::vector offset; + for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { + Side side_manager(side); + enum e_side ipin_side = side_manager.get_side(); + /* Get the chan_side */ + enum e_side chan_side = rr_gsb.get_cb_chan_side(ipin_side); + Side chan_side_manager(chan_side); + offset.resize(chan_side_manager.to_size_t()); + } + /* Initial offset */ + offset.assign(offset.size(), 0); + + /* Walk through each side */ + for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { + Side side_manager(side); + enum e_side ipin_side = side_manager.get_side(); + /* Get the chan_side */ + enum e_side chan_side = rr_gsb.get_cb_chan_side(ipin_side); + Side chan_side_manager(chan_side); + /* This track2pin mapping is for Connection Blocks, so we only care two sides! */ + /* Get channel width and resize the matrix */ + size_t chan_width = rr_gsb.get_chan_width(chan_side); + track2ipin_map[side].resize(chan_width); + /* Find the ipin/opin nodes */ + for (size_t inode = 0; inode < rr_gsb.get_num_ipin_nodes(ipin_side); ++inode) { + t_rr_node* ipin_node = rr_gsb.get_ipin_node(ipin_side, inode); + /* Get Fc of the ipin */ + int ipin_Fc = Fc_in[ipin_node->ptc_num]; + /* skip Fc = 0 */ + if (0 == ipin_Fc) { + continue; + } + /* Build track2ipin_map for this IPIN */ + build_gsb_one_ipin_track2pin_map(rr_graph, rr_gsb, ipin_side, inode, ipin_Fc, + /* Give an offset for the first track that this ipin will connect to */ + offset[chan_side_manager.to_size_t()], + segment_inf, &track2ipin_map); + /* update offset */ + offset[chan_side_manager.to_size_t()] += 2; + } + } + + return track2ipin_map; +} + +/************************************************************************ + * Build the opin_to_track_map[gsb_side][0..num_opin_nodes-1][track_indices] + * based on the existing routing resources in the General Switch Block (GSB) + * This function supports both X-directional and Y-directional tracks + * The mapping is done in the following steps: + * 1. Build a list of routing tracks whose starting points locate at this GSB + * (xlow - gsb_x == 0) + * 2. Divide the routing tracks by segment types, so that we can balance + * the connections between OPINs and different types of routing tracks. + * 3. Scale the Fc of each pin to the actual number of routing tracks + * actual_Fc = (int) Fc * num_tracks / chan_width + ***********************************************************************/ +t_pin2track_map build_gsb_opin_to_track_map(t_rr_graph* rr_graph, + const RRGSB& rr_gsb, + const std::vector segment_inf, + const int* Fc_out) { + t_pin2track_map opin2track_map; + /* Resize the matrix */ + opin2track_map.resize(rr_gsb.get_num_sides()); + + /* offset counter: it aims to balance the OPIN-to-track for each switch block */ + std::vector offset; + for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { + /* Get the chan_side: which is the same as the opin side */ + Side side_manager(side); + offset.resize(side_manager.to_size_t()); + } + /* Initial offset */ + offset.assign(offset.size(), 0); + + /* Walk through each side */ + for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { + Side side_manager(side); + enum e_side opin_side = side_manager.get_side(); + /* Get the chan_side */ + /* This track2pin mapping is for Connection Blocks, so we only care two sides! */ + /* Get channel width and resize the matrix */ + size_t num_opin_nodes = rr_gsb.get_num_opin_nodes(opin_side); + opin2track_map[side].resize(num_opin_nodes); + /* Find the ipin/opin nodes */ + for (size_t inode = 0; inode < num_opin_nodes; ++inode) { + t_rr_node* opin_node = rr_gsb.get_opin_node(opin_side, inode); + /* Get Fc of the ipin */ + int opin_Fc = Fc_out[opin_node->ptc_num]; + /* skip Fc = 0 */ + if (0 == opin_Fc) { + continue; + } + /* Build track2ipin_map for this IPIN */ + build_gsb_one_opin_pin2track_map(rr_graph, rr_gsb, opin_side, inode, opin_Fc, + /* Give an offset for the first track that this ipin will connect to */ + offset[side_manager.to_size_t()], + segment_inf, &opin2track_map); + /* update offset */ + offset[side_manager.to_size_t()] += 2; + } + } + + return opin2track_map; +} + + +/************************************************************************ + * Add all direct clb-pin-to-clb-pin edges to given opin + ***********************************************************************/ +void build_direct_connections_for_one_gsb(t_rr_graph* rr_graph, + const DeviceCoordinator& device_size, + const std::vector> grids, + const DeviceCoordinator& from_grid_coordinator, + const t_grid_tile& from_grid, + const int delayless_switch, + const int num_directs, + const t_direct_inf *directs, + const t_clb_to_clb_directs *clb_to_clb_directs) { + t_type_ptr grid_type = from_grid.type; + + /* Iterate through all direct connections */ + for (int i = 0; i < num_directs; ++i) { + /* Bypass unmatched direct clb-to-clb connections */ + if (grid_type != clb_to_clb_directs[i].from_clb_type) { + continue; + } + bool swap; + int max_index, min_index; + /* Compute index of opin with regards to given pins */ + if ( clb_to_clb_directs[i].from_clb_pin_start_index + > clb_to_clb_directs[i].from_clb_pin_end_index) { + swap = true; + max_index = clb_to_clb_directs[i].from_clb_pin_start_index; + min_index = clb_to_clb_directs[i].from_clb_pin_end_index; + } else { + swap = false; + min_index = clb_to_clb_directs[i].from_clb_pin_start_index; + max_index = clb_to_clb_directs[i].from_clb_pin_end_index; + } + /* get every opin in the range */ + for (int opin = min_index; opin <= max_index; ++opin) { + int offset = opin - min_index; + /* This opin is specified to connect directly to an ipin, now compute which ipin to connect to */ + DeviceCoordinator to_grid_coordinator(from_grid_coordinator.get_x() + directs[i].x_offset, + from_grid_coordinator.get_y() + directs[i].y_offset); + if ( (to_grid_coordinator.get_x() < device_size.get_x() - 1) + && (to_grid_coordinator.get_y() < device_size.get_y() - 1) ) { + int ipin = OPEN; + if ( clb_to_clb_directs[i].to_clb_pin_start_index + > clb_to_clb_directs[i].to_clb_pin_end_index) { + if (true == swap) { + ipin = clb_to_clb_directs[i].to_clb_pin_end_index + offset; + } else { + ipin = clb_to_clb_directs[i].to_clb_pin_start_index - offset; + } + } else { + if(true == swap) { + ipin = clb_to_clb_directs[i].to_clb_pin_end_index - offset; + } else { + ipin = clb_to_clb_directs[i].to_clb_pin_start_index + offset; + } + } + /* Get the pin index in the rr_graph */ + int from_grid_ofs = from_grid.offset; + int to_grid_ofs = grids[to_grid_coordinator.get_x()][to_grid_coordinator.get_y()].offset; + int opin_node_id = get_rr_node_index(from_grid_coordinator.get_x(), + from_grid_coordinator.get_y() - from_grid_ofs, + OPIN, opin, rr_graph->rr_node_indices); + int ipin_node_id = get_rr_node_index(to_grid_coordinator.get_x(), + to_grid_coordinator.get_y() - to_grid_ofs, + IPIN, ipin, rr_graph->rr_node_indices); + /* add edges to the opin_node */ + add_one_edge_for_two_rr_nodes(rr_graph, opin_node_id, ipin_node_id, + delayless_switch); + } + } + } + + return; +} + +/************************************************************************ + * End of file : rr_graph_tileable_gsb.cpp + ***********************************************************************/ diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.h b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.h new file mode 100755 index 000000000..8097139b3 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.h @@ -0,0 +1,62 @@ +#ifndef RR_GRAPH_TILEABLE_GSB_H +#define RR_GRAPH_TILEABLE_GSB_H + +#include + +#include "vtr_ndmatrix.h" + +#include "rr_blocks.h" +#include "fpga_x2p_types.h" + + +/************************************************************************ + * Data stuctures related to the functions + ***********************************************************************/ +typedef std::vector>> t_track2track_map; +typedef std::vector>> t_track2pin_map; +typedef std::vector>> t_pin2track_map; + +/************************************************************************ + * Functions + ***********************************************************************/ +t_track2track_map build_gsb_track_to_track_map(const t_rr_graph* rr_graph, + const RRGSB& rr_gsb, + const enum e_switch_block_type sb_type, + const int Fs, + const std::vector segment_inf); + +RRGSB build_one_tileable_rr_gsb(const DeviceCoordinator& device_range, + const std::vector device_chan_width, + const std::vector segment_inf, + const DeviceCoordinator& gsb_coordinator, + t_rr_graph* rr_graph); + +void build_edges_for_one_tileable_rr_gsb(const t_rr_graph* rr_graph, const RRGSB* rr_gsb, + const t_track2pin_map track2ipin_map, + const t_pin2track_map opin2track_map, + const t_track2track_map track2track_map); + +t_track2pin_map build_gsb_track_to_ipin_map(t_rr_graph* rr_graph, + const RRGSB& rr_gsb, + const std::vector segment_inf, + const int* Fc_in); + +t_pin2track_map build_gsb_opin_to_track_map(t_rr_graph* rr_graph, + const RRGSB& rr_gsb, + const std::vector segment_inf, + const int* Fc_out); + +void build_direct_connections_for_one_gsb(t_rr_graph* rr_graph, + const DeviceCoordinator& device_size, + const std::vector> grids, + const DeviceCoordinator& from_grid_coordinator, + const t_grid_tile& from_grid, + const int delayless_switch, + const int num_directs, + const t_direct_inf *directs, + const t_clb_to_clb_directs *clb_to_clb_directs); + + + +#endif + diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_sbox.cpp b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_sbox.cpp deleted file mode 100755 index df894c81a..000000000 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_sbox.cpp +++ /dev/null @@ -1,461 +0,0 @@ -/********************************************************** - * MIT License - * - * Copyright (c) 2018 LNIS - The University of Utah - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - ***********************************************************************/ - -/************************************************************************ - * Filename: rr_graph_tileable_sbox.cpp - * Created by: Xifan Tang - * Change history: - * +-------------------------------------+ - * | Date | Author | Notes - * +-------------------------------------+ - * | 2019/06/19 | Xifan Tang | Created - * +-------------------------------------+ - ***********************************************************************/ -/************************************************************************ - * This file contains a builder for track-to-track connections inside a - * tileable General Switch Block (GSB). - ***********************************************************************/ - -#include -#include - -#include - -#include "vpr_types.h" -#include "rr_graph_tileable_sbox.h" - -/************************************************************************ - * Internal data structures - ***********************************************************************/ -typedef std::vector> t_track_group; - -/************************************************************************ - * A enumeration to list the status of a track inside a GSB - * 1. start; 2. end; 3. passing - * This is used to group tracks which ease the building of - * track-to-track mapping matrix - ***********************************************************************/ -enum e_track_status { - TRACK_START, - TRACK_END, - TRACK_PASS, - NUM_TRACK_STATUS /* just a place holder to get the number of status */ -}; - -/************************************************************************ - * Check if a track starts from this GSB or not - * (xlow, ylow) should be same as the GSB side coordinator - * - * Check if a track ends at this GSB or not - * (xhigh, yhigh) should be same as the GSB side coordinator - ***********************************************************************/ -static -enum e_track_status determine_track_status_of_gsb(const RRGSB& rr_gsb, - const enum e_side gsb_side, - const size_t track_id) { - enum e_track_status track_status = TRACK_PASS; - /* Get the rr_node */ - t_rr_node* track_node = rr_gsb.get_chan_node(gsb_side, track_id); - /* Get the coordinators */ - DeviceCoordinator side_coordinator = rr_gsb.get_side_block_coordinator(gsb_side); - - /* INC_DIRECTION start_track: (xlow, ylow) should be same as the GSB side coordinator */ - if ( ((size_t)track_node->xlow == side_coordinator.get_x()) - && ((size_t)track_node->ylow == side_coordinator.get_y()) - && (OUT_PORT == rr_gsb.get_chan_node_direction(gsb_side, track_id)) ) { - /* Double check: start track should be an OUTPUT PORT of the GSB */ - track_status = TRACK_START; - } - /* INC_DIRECTION end_track: (xhigh, yhigh) should be same as the GSB side coordinator */ - if ( ((size_t)track_node->xhigh == side_coordinator.get_x()) - && ((size_t)track_node->yhigh == side_coordinator.get_y()) - && (IN_PORT == rr_gsb.get_chan_node_direction(gsb_side, track_id)) ) { - /* Double check: end track should be an INPUT PORT of the GSB */ - track_status = TRACK_END; - } - - return track_status; -} - -/************************************************************************ - * Check if the GSB is in the Switch Block (SB) population list of the segment - * SB population of a L3 wire: 1 0 0 1 - * - * +----+ +----+ +----+ +----+ - * | SB |--->| SB |--->| SB |--->| SB | - * +----+ +----+ +----+ +----+ - * Engage SB connection Yes No No Yes - * - * We will find the offset between gsb_side_coordinator and (xlow,ylow) of the track - * Use the offset to check if the tracks should engage in this GSB connection - ***********************************************************************/ -static -bool is_gsb_in_track_sb_population(const RRGSB& rr_gsb, - const enum e_side gsb_side, - const int track_id, - const std::vector segment_inf) { - /* Get the rr_node */ - t_rr_node* track_node = rr_gsb.get_chan_node(gsb_side, track_id); - /* Get the coordinators */ - DeviceCoordinator side_coordinator = rr_gsb.get_side_block_coordinator(gsb_side); - - /* Get the offset */ - size_t offset = (side_coordinator.get_x() - track_node->xlow) - + (side_coordinator.get_y() - track_node->ylow); - - /* Get segment id */ - size_t seg_id = rr_gsb.get_chan_node_segment(gsb_side, track_id); - /* validate offset */ - assert (offset < (size_t)segment_inf[seg_id].sb_len); - - /* Get the SB population */ - bool in_sb_population = false; - if (TRUE == segment_inf[seg_id].sb[offset]) { - in_sb_population = true; - } - return in_sb_population; -} - -/************************************************************************ - * Create a list of track_id based on the to_track and num_to_tracks - * We consider the following list [to_track, to_track + Fs/3 - 1] - * if the [to_track + Fs/3 - 1] exceeds the num_to_tracks, we start over from 0! -***********************************************************************/ -static -std::vector get_to_track_list(const int Fs, const int to_track, const int num_to_tracks) { - std::vector to_tracks; - for (int i = 0; i < Fs; i = i + 3) { - /* TODO: currently, for Fs > 3, I always search the next from_track until Fs is satisfied - * The optimal track selection should be done in a more scientific way!!! - */ - size_t to_track_i = to_track + i; - /* make sure the track id is still in range */ - if ( to_track_i > (size_t)num_to_tracks) { - to_track_i = to_track_i % num_to_tracks; - } - /* from track must be connected */ - to_tracks.push_back(to_track_i); - } - return to_tracks; -} - -/************************************************************************ - * This function aims to return the track indices that drive the from_track - * in a Switch Block - * The track_ids to return will depend on different topologies of SB - * SUBSET, UNIVERSAL, and WILTON. - ***********************************************************************/ -static -std::vector get_switch_block_to_track_id(const enum e_switch_block_type switch_block_type, - const int Fs, - const enum e_side from_side, - const int from_track, - const enum e_side to_side, - const int num_to_tracks) { - - /* This routine returns the track number to which the from_track should - * connect. It supports any Fs % 3 == 0, switch blocks. - */ - std::vector to_tracks; - - /* TODO: currently, for Fs > 3, I always search the next from_track until Fs is satisfied - * The optimal track selection should be done in a more scientific way!!! - */ - - assert (0 == Fs % 3); - - switch (switch_block_type) { - case SUBSET: /* NB: Global routing uses SUBSET too */ - to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); - /* Finish, we return */ - return to_tracks; - case UNIVERSAL: - if ( (from_side == LEFT) - || (from_side == RIGHT) ) { - /* For the prev_side, to_track is from_track - * For the next_side, to_track is num_to_tracks - 1 - from_track - * For the opposite_side, to_track is always from_track - */ - Side side_manager(from_side); - if ( (to_side == side_manager.get_opposite()) - || (to_side == side_manager.get_rotate_counterclockwise()) ) { - to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); - } else if (to_side == side_manager.get_rotate_clockwise()) { - to_tracks = get_to_track_list(Fs, num_to_tracks - 1 - from_track, num_to_tracks); - } - } - - if ( (from_side == TOP) - || (from_side == BOTTOM) ) { - /* For the next_side, to_track is from_track - * For the prev_side, to_track is num_to_tracks - 1 - from_track - * For the opposite_side, to_track is always from_track - */ - Side side_manager(from_side); - if ( (to_side == side_manager.get_opposite()) - || (to_side == side_manager.get_rotate_clockwise()) ) { - to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); - } else if (to_side == side_manager.get_rotate_counterclockwise()) { - to_tracks = get_to_track_list(Fs, num_to_tracks - 1 - from_track, num_to_tracks); - } - } - /* Finish, we return */ - return to_tracks; - /* End switch_block_type == UNIVERSAL case. */ - case WILTON: - /* See S. Wilton Phd thesis, U of T, 1996 p. 103 for details on following. */ - if (from_side == LEFT) { - if (to_side == RIGHT) { /* CHANX to CHANX */ - to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); - } else if (to_side == TOP) { /* from CHANX to CHANY */ - to_tracks = get_to_track_list(Fs, (num_to_tracks - (from_track % num_to_tracks)) % num_to_tracks, num_to_tracks); - } else if (to_side == BOTTOM) { - to_tracks = get_to_track_list(Fs, (num_to_tracks + from_track - 1) % num_to_tracks, num_to_tracks); - } - } else if (from_side == RIGHT) { - if (to_side == LEFT) { /* CHANX to CHANX */ - to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); - } else if (to_side == TOP) { /* from CHANX to CHANY */ - to_tracks = get_to_track_list(Fs, (num_to_tracks + from_track - 1) % num_to_tracks, num_to_tracks); - } else if (to_side == BOTTOM) { - to_tracks = get_to_track_list(Fs, (num_to_tracks - 2 - from_track) % num_to_tracks, num_to_tracks); - } - } else if (from_side == BOTTOM) { - if (to_side == TOP) { /* CHANY to CHANY */ - to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); - } else if (to_side == LEFT) { /* from CHANY to CHANX */ - to_tracks = get_to_track_list(Fs, (from_track + 1) % num_to_tracks, num_to_tracks); - } else if (to_side == RIGHT) { - to_tracks = get_to_track_list(Fs, (2 * num_to_tracks - 2 - from_track) % num_to_tracks, num_to_tracks); - } - } else if (from_side == TOP) { - if (to_side == BOTTOM) { /* CHANY to CHANY */ - to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); - } else if (to_side == LEFT) { /* from CHANY to CHANX */ - to_tracks = get_to_track_list(Fs, (num_to_tracks - (from_track % num_to_tracks)) % num_to_tracks, num_to_tracks); - } else if (to_side == RIGHT) { - to_tracks = get_to_track_list(Fs, (from_track + 1) % num_to_tracks, num_to_tracks); - } - } - /* Finish, we return */ - return to_tracks; - /* End switch_block_type == WILTON case. */ - default: - vpr_printf(TIO_MESSAGE_ERROR, - "(File:%s, [LINE%d]) Invalid switch block pattern !\n", - __FILE__, __LINE__); - exit(1); - } - - return to_tracks; -} - - -/************************************************************************ - * Build the track_to_track_map[from_side][0..chan_width-1][to_side][track_indices] - * For a group of from_track nodes and to_track nodes - * For each side of from_tracks, we call a routine to get the list of to_tracks - * Then, we fill the track2track_map - ***********************************************************************/ -static -void build_gsb_one_group_track_to_track_map(const t_rr_graph* rr_graph, - const RRGSB& rr_gsb, - const enum e_switch_block_type sb_type, - const int Fs, - const t_track_group from_tracks, /* [0..gsb_side][track_indices] */ - const t_track_group to_tracks, /* [0..gsb_side][track_indices] */ - t_track2track_map* track2track_map) { - for (size_t side = 0; side < from_tracks.size(); ++side) { - Side side_manager(side); - enum e_side gsb_side = side_manager.get_side(); - /* Find the other sides where the start tracks will locate */ - std::vector to_track_sides; - /* 0. opposite side */ - to_track_sides.push_back(side_manager.get_opposite()); - /* 1. prev side */ - /* Previous side definition: TOP => LEFT; RIGHT=>TOP; BOTTOM=>RIGHT; LEFT=>BOTTOM */ - to_track_sides.push_back(side_manager.get_rotate_counterclockwise()); - /* 2. next side */ - /* Next side definition: TOP => RIGHT; RIGHT=>BOTTOM; BOTTOM=>LEFT; LEFT=>TOP */ - to_track_sides.push_back(side_manager.get_rotate_clockwise()); - - for (size_t inode = 0; inode < from_tracks[side].size(); ++inode) { - for (size_t to_side_id = 0; to_side_id < to_track_sides.size(); ++to_side_id) { - enum e_side to_side = to_track_sides[to_side_id]; - Side to_side_manager(to_side); - size_t to_side_index = to_side_manager.to_size_t(); - /* Bypass those to_sides have no nodes */ - if (0 == to_tracks[to_side_index].size()) { - continue; - } - /* Get other track_ids depending on the switch block pattern */ - /* Find the track ids that will start at the other sides */ - std::vector to_track_ids = get_switch_block_to_track_id(sb_type, Fs, gsb_side, inode, - to_side, - to_tracks[to_side_index].size()); - /* Update the track2track_map: */ - for (size_t to_track_id = 0; to_track_id < to_track_ids.size(); ++to_track_id) { - size_t from_side_index = side_manager.to_size_t(); - size_t from_track_index = from_tracks[side][inode]; - size_t to_track_index = to_tracks[to_side_index][to_track_ids[to_track_id]]; - t_rr_node* to_track_node = rr_gsb.get_chan_node(to_side, to_track_index); - (*track2track_map)[from_side_index][from_track_index].push_back(to_track_node - rr_graph->rr_node); - } - } - } - } - - return; -} - -/************************************************************************ - * Build the track_to_track_map[from_side][0..chan_width-1][to_side][track_indices] - * based on the existing routing resources in the General Switch Block (GSB) - * The track_indices is the indices of tracks that the node at from_side and [0..chan_width-1] will drive - * IMPORTANT: the track_indices are the indicies in the GSB context, but not the rr_graph!!! - * We separate the connections into two groups: - * Group 1: the routing tracks start from this GSB - * We will apply switch block patterns (SUBSET, UNIVERSAL, WILTON) - * Group 2: the routing tracks do not start from this GSB (bypassing wires) - * We will apply switch block patterns (SUBSET, UNIVERSAL, WILTON) - * but we will check the Switch Block (SB) population of these - * routing segments, and determine which requires connections - * - * CHANY CHANY CHANY CHANY - * [0] [1] [2] [3] - * start yes no yes no - * end +-------------------------+ start Group 1 Group 2 - * no CHANX[0] | TOP | CHANX[0] yes TOP/BOTTOM TOP/BOTTOM - * | | CHANY[0,2] CHANY[1,3] - * yes CHANX[1] | | CHANX[1] no - * | LEFT RIGHT | - * no CHANX[2] | | CHANX[2] yes - * | | - * yes CHANX[3] | BOTTOM | CHANX[3] no - * +-------------------------+ - * CHANY CHANY CHANY CHANY - * [0] [1] [2] [3] - * start yes no yes no - * - * The mapping is done in the following steps: (For each side of the GSB) - * 1. Build a list of tracks that will start from this side - * if a track starts, its xlow/ylow is the same as the x,y of this gsb - * 2. Build a list of tracks on the other sides belonging to Group 1. - * Take the example of RIGHT side, we will collect - * a. tracks that will end at the LEFT side - * b. tracks that will start at the TOP side - * c. tracks that will start at the BOTTOM side - * 3. Apply switch block patterns to Group 1 (SUBSET, UNIVERSAL, WILTON) - * 4. Build a list of tracks on the other sides belonging to Group 1. - * Take the example of RIGHT side, we will collect - * a. tracks that will bypass at the TOP side - * b. tracks that will bypass at the BOTTOM side - * 5. Apply switch block patterns to Group 2 (SUBSET, UNIVERSAL, WILTON) - ***********************************************************************/ -t_track2track_map build_gsb_track_to_track_map(const t_rr_graph* rr_graph, - const RRGSB& rr_gsb, - const enum e_switch_block_type sb_type, - const int Fs, - const std::vector segment_inf) { - t_track2track_map track2track_map; /* [0..gsb_side][0..chan_width][track_indices] */ - - /* Categorize tracks into 3 groups: - * (1) tracks will start here - * (2) tracks will end here - * (2) tracks will just pass through the SB */ - t_track_group start_tracks; /* [0..gsb_side][track_indices] */ - t_track_group end_tracks; /* [0..gsb_side][track_indices] */ - t_track_group pass_tracks; /* [0..gsb_side][track_indices] */ - - /* resize to the number of sides */ - start_tracks.resize(rr_gsb.get_num_sides()); - end_tracks.resize(rr_gsb.get_num_sides()); - pass_tracks.resize(rr_gsb.get_num_sides()); - - /* Walk through each side */ - for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { - Side side_manager(side); - enum e_side gsb_side = side_manager.get_side(); - /* Build a list of tracks that will start from this side */ - for (size_t inode = 0; inode < rr_gsb.get_chan_width(gsb_side); ++inode) { - /* check if this track will start from here */ - enum e_track_status track_status = determine_track_status_of_gsb(rr_gsb, gsb_side, inode); - switch (track_status) { - case TRACK_START: - /* update starting track list */ - start_tracks[gsb_side].push_back(inode); - break; - case TRACK_END: - /* Update end track list */ - end_tracks[gsb_side].push_back(inode); - break; - case TRACK_PASS: - /* We need to check Switch block population of this track - * The track node will not be considered if there supposed to be no SB at this position - */ - if (true == is_gsb_in_track_sb_population(rr_gsb, gsb_side, inode, segment_inf)) { - /* Update passing track list */ - pass_tracks[gsb_side].push_back(inode); - } - break; - default: - vpr_printf(TIO_MESSAGE_ERROR, - "(File:%s, [LINE%d]) Invalid track status!\n", - __FILE__, __LINE__); - exit(1); - } - } - } - - /* Allocate track2track map */ - track2track_map.resize(rr_gsb.get_num_sides()); - for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { - Side side_manager(side); - enum e_side gsb_side = side_manager.get_side(); - /* allocate track2track_map[gsb_side] */ - track2track_map[side].resize(rr_gsb.get_chan_width(gsb_side)); - for (size_t inode = 0; inode < rr_gsb.get_chan_width(gsb_side); ++inode) { - /* allocate track2track_map[gsb_side][inode] */ - track2track_map[side][inode].clear(); - } - } - - /* For Group 1: we build connections between end_tracks and start_tracks*/ - build_gsb_one_group_track_to_track_map(rr_graph, rr_gsb, - sb_type, Fs, - end_tracks, start_tracks, - &track2track_map); - - /* For Group 2: we build connections between end_tracks and start_tracks*/ - /* Currently, I use the same Switch Block pattern for the passing tracks and end tracks, - * TODO: This can be improved with different patterns! - */ - build_gsb_one_group_track_to_track_map(rr_graph, rr_gsb, - sb_type, Fs, - pass_tracks, start_tracks, - &track2track_map); - - return track2track_map; -} - diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_sbox.h b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_sbox.h deleted file mode 100755 index 3079cbea8..000000000 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_sbox.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef RR_GRAPH_TILEABLE_SBOX_H -#define RR_GRAPH_TILEABLE_SBOX_H - -#include - -#include "vtr_ndmatrix.h" - -#include "rr_blocks.h" -#include "fpga_x2p_types.h" - -typedef std::vector>> t_track2track_map; - -t_track2track_map build_gsb_track_to_track_map(const t_rr_graph* rr_graph, - const RRGSB& rr_gsb, - const enum e_switch_block_type sb_type, - const int Fs, - const std::vector segment_inf); - -#endif - 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 cb8de00d3..d150b53a6 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.cpp @@ -125,6 +125,24 @@ std::vector RRChan::get_segment_ids() const { return seg_list; } +/* Get a list of nodes whose segment_id is specified */ +std::vector RRChan::get_node_ids_by_segment_ids(size_t seg_id) const { + std::vector node_list; + + /* make sure a clean start */ + node_list.clear(); + + /* Traverse node_segments */ + for (size_t inode = 0; inode < get_chan_width(); ++inode) { + /* Try to find the node_segment id in the list */ + if ( seg_id == node_segments_[inode] ) { + node_list.push_back(inode); + } + } + + return node_list; +} + /* Mutators */ void RRChan::set(const RRChan& rr_chan) { /* Ensure a clean start */ @@ -611,6 +629,22 @@ RRChan RRGSB::get_chan(enum e_side side) const { return chan_node_[side_manager.to_size_t()]; } +/* Get a list of segments used in this routing channel */ +std::vector RRGSB::get_chan_segment_ids(enum e_side side) const { + Side side_manager(side); + assert(side_manager.validate()); + + /* Ensure the side is valid in the context of this switch block */ + assert( validate_side(side) ); + + return get_chan(side).get_segment_ids(); +} + +/* Get a list of rr_nodes whose sed_id is specified */ +std::vector RRGSB::get_chan_node_ids_by_segment_ids(enum e_side side, size_t seg_id) const { + return get_chan(side).get_node_ids_by_segment_ids(seg_id); +} + /* get a rr_node at a given side and track_id */ t_rr_node* RRGSB::get_chan_node(enum e_side side, size_t track_id) const { Side side_manager(side); @@ -1302,6 +1336,24 @@ enum e_side RRGSB::get_cb_chan_side(t_rr_type cb_type) const { } } +/* Get the side of routing channel in the GSB according to the side of IPIN */ +enum e_side RRGSB::get_cb_chan_side(enum e_side ipin_side) const { + switch(ipin_side) { + case TOP: + return LEFT; + case RIGHT: + return TOP; + case BOTTOM: + return LEFT; + case LEFT: + return TOP; + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d])Invalid type of ipin_side!\n", + __FILE__, __LINE__); + exit(1); + } +} DeviceCoordinator RRGSB::get_side_block_coordinator(enum e_side side) const { Side side_manager(side); @@ -1337,6 +1389,13 @@ DeviceCoordinator RRGSB::get_side_block_coordinator(enum e_side side) const { return ret; } +DeviceCoordinator RRGSB::get_grid_coordinator() const { + DeviceCoordinator ret(get_sb_x(), get_sb_y()); + ret.set_y(ret.get_y() + 1); + + return ret; +} + /* Public Accessors Verilog writer */ const char* RRGSB::gen_cb_verilog_routing_track_name(t_rr_type cb_type, size_t track_id) const { 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 475be8ab4..a1cd95856 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.h @@ -84,6 +84,7 @@ class RRChan { int get_node_segment(size_t track_num) const; bool is_mirror(const RRChan& cand) const; /* evaluate if two RR_chan is mirror to each other */ std::vector get_segment_ids() const; /* Get a list of segments used in this routing channel */ + std::vector get_node_ids_by_segment_ids(size_t seg_id) const; /* Get a list of segments used in this routing channel */ public: /* Mutators */ void set(const RRChan&); /* copy */ void set_type(t_rr_type type); /* modify type */ @@ -188,6 +189,8 @@ class RRGSB { size_t get_max_chan_width() const; /* Get the maximum number of routing tracks on all sides */ enum PORTS get_chan_node_direction(enum e_side side, size_t track_id) const; /* Get the direction of a rr_node at a given side and track_id */ RRChan get_chan(enum e_side side) const; /* get a rr_node at a given side and track_id */ + std::vector get_chan_segment_ids(enum e_side side) const; /* Get a list of segments used in this routing channel */ + std::vector get_chan_node_ids_by_segment_ids(enum e_side side, size_t seg_id) const; /* Get a list of segments used in this routing channel */ t_rr_node* get_chan_node(enum e_side side, size_t track_id) const; /* get a rr_node at a given side and track_id */ size_t get_chan_node_segment(enum e_side side, size_t track_id) const; /* get the segment id of a channel rr_node */ size_t get_num_ipin_nodes(enum e_side side) const; /* Get the number of IPIN rr_nodes on a side */ @@ -232,7 +235,9 @@ class RRGSB { size_t get_cb_y(t_rr_type cb_type) const; /* get the y coordinator of this X/Y-direction block */ DeviceCoordinator get_cb_coordinator(t_rr_type cb_type) const; /* Get the coordinator of the X/Y-direction CB */ enum e_side get_cb_chan_side(t_rr_type cb_type) const; /* get the side of a Connection block */ + enum e_side get_cb_chan_side(enum e_side ipin_side) const; /* get the side of a Connection block */ DeviceCoordinator get_side_block_coordinator(enum e_side side) const; + DeviceCoordinator get_grid_coordinator() const; public: /* Verilog writer */ const char* gen_sb_verilog_module_name() const; const char* gen_sb_verilog_instance_name() const; diff --git a/vpr7_x2p/vpr/SRC/route/check_rr_graph.c b/vpr7_x2p/vpr/SRC/route/check_rr_graph.c index 770dc130a..17fc4b34e 100755 --- a/vpr7_x2p/vpr/SRC/route/check_rr_graph.c +++ b/vpr7_x2p/vpr/SRC/route/check_rr_graph.c @@ -23,15 +23,12 @@ static void check_pass_transistors(int from_node); /************************ Subroutine definitions ****************************/ -void check_rr_graph(INP t_graph_type graph_type, INP t_type_ptr types, - INP int L_nx, INP int L_ny, INP int nodes_per_chan, INP int Fs, - INP int num_seg_types, INP int num_switches, - INP t_segment_inf * segment_inf, INP int global_route_switch, - INP int delayless_switch, INP int wire_to_ipin_switch, - t_seg_details * seg_details, int **Fc_in, int **Fc_out, - int *****opin_to_track_map, int *****ipin_to_track_map, - t_ivec **** track_to_ipin_lookup, t_ivec *** switch_block_conn, - boolean * perturb_ipins) { +void check_rr_graph(INP const t_graph_type graph_type, INP t_type_ptr types, + INP const int L_nx, INP const int L_ny, INP const int nodes_per_chan, INP int Fs, + INP const int num_seg_types, INP const int num_switches, + INP const t_segment_inf * segment_inf, INP const int global_route_switch, + INP const int delayless_switch, INP const int wire_to_ipin_switch, + int **Fc_in, int **Fc_out) { int *num_edges_from_current_to_node; /* [0..num_rr_nodes-1] */ int *total_edges_to_node; /* [0..num_rr_nodes-1] */ diff --git a/vpr7_x2p/vpr/SRC/route/check_rr_graph.h b/vpr7_x2p/vpr/SRC/route/check_rr_graph.h index 2dd21a124..0d2d06bdf 100755 --- a/vpr7_x2p/vpr/SRC/route/check_rr_graph.h +++ b/vpr7_x2p/vpr/SRC/route/check_rr_graph.h @@ -1,26 +1,20 @@ #ifndef CHECK_RR_GRAPH_H #define CHECK_RR_GRAPH_H -void check_rr_graph(INP t_graph_type graph_type, +void check_rr_graph(INP const t_graph_type graph_type, INP t_type_ptr types, - INP int L_nx, - INP int L_ny, - INP int nodes_per_chan, - INP int Fs, - INP int num_seg_types, - INP int num_switches, - INP t_segment_inf * segment_inf, - INP int global_route_switch, - INP int delayless_switch, - INP int wire_to_ipin_switch, - t_seg_details * seg_details, + INP const int L_nx, + INP const int L_ny, + INP const int nodes_per_chan, + INP const int Fs, + INP const int num_seg_types, + INP const int num_switches, + INP const t_segment_inf * segment_inf, + INP const int global_route_switch, + INP const int delayless_switch, + INP const int wire_to_ipin_switch, int ** Fc_in, - int ** Fc_out, - int *****opin_to_track_map, - int *****ipin_to_track_map, - t_ivec **** track_to_ipin_lookup, - t_ivec *** switch_block_conn, - boolean * perturb_ipins); + int ** Fc_out); void check_node(int inode, enum e_route_type route_type); diff --git a/vpr7_x2p/vpr/SRC/route/rr_graph.c b/vpr7_x2p/vpr/SRC/route/rr_graph.c index 51c4a5035..b111fc149 100755 --- a/vpr7_x2p/vpr/SRC/route/rr_graph.c +++ b/vpr7_x2p/vpr/SRC/route/rr_graph.c @@ -458,9 +458,7 @@ void build_rr_graph(INP t_graph_type graph_type, INP int L_num_types, check_rr_graph(graph_type, types, L_nx, L_ny, nodes_per_chan, Fs, num_seg_types, num_switches, segment_inf, global_route_switch, - delayless_switch, wire_to_ipin_switch, seg_details, Fc_in, Fc_out, - opin_to_track_map, ipin_to_track_map, track_to_ipin_lookup, - switch_block_conn, perturb_ipins); + delayless_switch, wire_to_ipin_switch, Fc_in, Fc_out); /* Free all temp structs */ if (seg_details) { @@ -514,9 +512,9 @@ void build_rr_graph(INP t_graph_type graph_type, INP int L_num_types, } } -void rr_graph_externals(t_timing_inf timing_inf, - t_segment_inf * segment_inf, int num_seg_types, int nodes_per_chan, - int wire_to_ipin_switch, enum e_base_cost_type base_cost_type) { +void rr_graph_externals(const t_timing_inf timing_inf, + const t_segment_inf * segment_inf, const int num_seg_types, const int nodes_per_chan, + const int wire_to_ipin_switch, const enum e_base_cost_type base_cost_type) { add_rr_graph_C_from_switches(timing_inf.C_ipin_cblock); alloc_and_load_rr_indexed_data(segment_inf, num_seg_types, rr_node_indices, nodes_per_chan, wire_to_ipin_switch, base_cost_type); diff --git a/vpr7_x2p/vpr/SRC/route/rr_graph.h b/vpr7_x2p/vpr/SRC/route/rr_graph.h index c8cb18aa3..9e23b0187 100755 --- a/vpr7_x2p/vpr/SRC/route/rr_graph.h +++ b/vpr7_x2p/vpr/SRC/route/rr_graph.h @@ -59,9 +59,9 @@ alloc_and_load_actual_fc(INP int L_num_types, INP t_type_ptr types, INP int nodes_per_chan, INP boolean is_Fc_out, INP enum e_directionality directionality, OUTP boolean * Fc_clipped, INP boolean ignore_Fc_0); -void rr_graph_externals(t_timing_inf timing_inf, - t_segment_inf * segment_inf, int num_seg_types, int nodes_per_chan, - int wire_to_ipin_switch, enum e_base_cost_type base_cost_type); +void rr_graph_externals(const t_timing_inf timing_inf, + const t_segment_inf * segment_inf, const int num_seg_types, const int nodes_per_chan, + const int wire_to_ipin_switch, const enum e_base_cost_type base_cost_type); /* Xifan Tang: Functions shared by tileable rr_graph generator */ diff --git a/vpr7_x2p/vpr/SRC/route/rr_graph_indexed_data.c b/vpr7_x2p/vpr/SRC/route/rr_graph_indexed_data.c index 9a4f6e7a8..476d093b9 100755 --- a/vpr7_x2p/vpr/SRC/route/rr_graph_indexed_data.c +++ b/vpr7_x2p/vpr/SRC/route/rr_graph_indexed_data.c @@ -25,7 +25,7 @@ static float get_average_opin_delay(t_ivec *** L_rr_node_indices, static void load_rr_indexed_data_T_values(int index_start, int num_indices_to_load, t_rr_type rr_type, int nodes_per_chan, - t_ivec *** L_rr_node_indices, t_segment_inf * segment_inf); + t_ivec *** L_rr_node_indices, const t_segment_inf * segment_inf); /******************** Subroutine definitions *********************************/ @@ -42,7 +42,7 @@ static void load_rr_indexed_data_T_values(int index_start, * etc. more expensive than others. I give each segment type in an * * x-channel its own cost_index, and each segment type in a y-channel its * * own cost_index. */ -void alloc_and_load_rr_indexed_data(INP t_segment_inf * segment_inf, +void alloc_and_load_rr_indexed_data(INP const t_segment_inf * segment_inf, INP int num_segment, INP t_ivec *** L_rr_node_indices, INP int nodes_per_chan, int wire_to_ipin_switch, enum e_base_cost_type base_cost_type) { @@ -258,7 +258,7 @@ static float get_average_opin_delay(t_ivec *** L_rr_node_indices, static void load_rr_indexed_data_T_values(int index_start, int num_indices_to_load, t_rr_type rr_type, int nodes_per_chan, - t_ivec *** L_rr_node_indices, t_segment_inf * segment_inf) { + t_ivec *** L_rr_node_indices, const t_segment_inf * segment_inf) { /* Loads the average propagation times through segments of each index type * * for either all CHANX segment types or all CHANY segment types. It does * diff --git a/vpr7_x2p/vpr/SRC/route/rr_graph_indexed_data.h b/vpr7_x2p/vpr/SRC/route/rr_graph_indexed_data.h index 1ec5ca8ab..e5c03aa9f 100755 --- a/vpr7_x2p/vpr/SRC/route/rr_graph_indexed_data.h +++ b/vpr7_x2p/vpr/SRC/route/rr_graph_indexed_data.h @@ -1,3 +1,3 @@ -void alloc_and_load_rr_indexed_data(t_segment_inf * segment_inf, +void alloc_and_load_rr_indexed_data(const t_segment_inf * segment_inf, int num_segment, t_ivec *** L_rr_node_indices, int nodes_per_chan, int wire_to_ipin_switch, enum e_base_cost_type base_cost_type); diff --git a/vpr7_x2p/vpr/SRC/util/vpr_utils.c b/vpr7_x2p/vpr/SRC/util/vpr_utils.c index a7c1dbf3a..93ef9fe24 100755 --- a/vpr7_x2p/vpr/SRC/util/vpr_utils.c +++ b/vpr7_x2p/vpr/SRC/util/vpr_utils.c @@ -1165,8 +1165,8 @@ void alloc_and_load_idirect_from_blk_pin(t_direct_inf* directs, int num_directs, * This data structure supplements the the info in the "directs" data structure * TODO: The function that does this parsing in placement is poorly done because it lacks generality on heterogeniety, should replace with this one */ -t_clb_to_clb_directs * alloc_and_load_clb_to_clb_directs(INP t_direct_inf *directs, - INP int num_directs) { +t_clb_to_clb_directs * alloc_and_load_clb_to_clb_directs(INP const t_direct_inf *directs, + INP const int num_directs) { int i, j; t_clb_to_clb_directs *clb_to_clb_directs; char *pb_type_name, *port_name; diff --git a/vpr7_x2p/vpr/SRC/util/vpr_utils.h b/vpr7_x2p/vpr/SRC/util/vpr_utils.h index 51eb05da9..721b7dec1 100755 --- a/vpr7_x2p/vpr/SRC/util/vpr_utils.h +++ b/vpr7_x2p/vpr/SRC/util/vpr_utils.h @@ -41,7 +41,7 @@ void alloc_and_load_idirect_from_blk_pin(t_direct_inf* directs, int num_directs, void parse_direct_pin_name(char * src_string, int line, int * start_pin_index, int * end_pin_index, char * pb_type_name, char * port_name); -t_clb_to_clb_directs *alloc_and_load_clb_to_clb_directs(INP t_direct_inf *directs, INP int num_directs); +t_clb_to_clb_directs *alloc_and_load_clb_to_clb_directs(INP const t_direct_inf *directs, INP const int num_directs); void free_cb(t_pb *pb); From 548242b3682cfcfd514006254f9c78c3a638452c Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 20 Jun 2019 21:06:26 -0600 Subject: [PATCH 11/25] plug-in tileable rr generator which can be enable by a XML property --- .../libarchfpga/SRC/include/physical_types.h | 1 + vpr7_x2p/libarchfpga/SRC/read_xml_arch_file.c | 19 ++++++ vpr7_x2p/vpr/SRC/base/SetupVPR.c | 1 + vpr7_x2p/vpr/SRC/base/place_and_route.c | 13 ++-- vpr7_x2p/vpr/SRC/base/vpr_types.h | 1 + .../rr_graph/rr_graph_tileable_builder.c | 2 +- .../rr_graph/rr_graph_tileable_builder.h | 2 +- vpr7_x2p/vpr/SRC/route/route_common.c | 13 ++-- vpr7_x2p/vpr/SRC/route/rr_graph.c | 67 +++++++++++++++++++ 9 files changed, 109 insertions(+), 10 deletions(-) diff --git a/vpr7_x2p/libarchfpga/SRC/include/physical_types.h b/vpr7_x2p/libarchfpga/SRC/include/physical_types.h index 6947b5896..bdc991718 100644 --- a/vpr7_x2p/libarchfpga/SRC/include/physical_types.h +++ b/vpr7_x2p/libarchfpga/SRC/include/physical_types.h @@ -928,6 +928,7 @@ typedef struct s_direct_inf { /* Detailed routing architecture */ typedef struct s_arch t_arch; struct s_arch { + bool tileable; /* Xifan TANG: tileable rr_graph support */ t_chan_width_dist Chans; enum e_switch_block_type SBType; float R_minW_nmos; diff --git a/vpr7_x2p/libarchfpga/SRC/read_xml_arch_file.c b/vpr7_x2p/libarchfpga/SRC/read_xml_arch_file.c index 0b24fe426..ff8ececa1 100644 --- a/vpr7_x2p/libarchfpga/SRC/read_xml_arch_file.c +++ b/vpr7_x2p/libarchfpga/SRC/read_xml_arch_file.c @@ -2062,6 +2062,25 @@ static void ProcessLayout(INOUTP ezxml_t Node, OUTP struct s_arch *arch) { arch->clb_grid.Aspect); } } + /* Xifan TANG: Tileable Routing Support + * Load tileable_routing if applicable + */ + arch->tileable = false; + Prop = FindProperty(Node, "tileable_routing", FALSE); + if (Prop != NULL) { + if ( 0 == strcmp("on", Prop)) { + arch->tileable = true; + } + ezxml_set_attr(Node, "tileable_routing", NULL); + } + if (true == arch->tileable) { + vpr_printf(TIO_MESSAGE_INFO, + "Tileable routing architecture generation is enabled.\n"); + } else { + vpr_printf(TIO_MESSAGE_INFO, + "Tileable routing architecture generation is disable. FPGA may not be tileable! \n"); + } + } /* Takes in node pointing to and loads all the diff --git a/vpr7_x2p/vpr/SRC/base/SetupVPR.c b/vpr7_x2p/vpr/SRC/base/SetupVPR.c index e6ee0720e..09441daa1 100644 --- a/vpr7_x2p/vpr/SRC/base/SetupVPR.c +++ b/vpr7_x2p/vpr/SRC/base/SetupVPR.c @@ -542,6 +542,7 @@ static void SetupRoutingArch(INP t_arch Arch, RoutingArch->directionality = BI_DIRECTIONAL; if (Arch.Segments) RoutingArch->directionality = Arch.Segments[0].directionality; + RoutingArch->tileable = Arch.tileable; } static void SetupRouterOpts(INP t_options Options, INP boolean TimingEnabled, diff --git a/vpr7_x2p/vpr/SRC/base/place_and_route.c b/vpr7_x2p/vpr/SRC/base/place_and_route.c index 4e26c1b84..e314e0882 100644 --- a/vpr7_x2p/vpr/SRC/base/place_and_route.c +++ b/vpr7_x2p/vpr/SRC/base/place_and_route.c @@ -296,10 +296,15 @@ static int binary_search_place_and_route(struct s_placer_opts placer_opts, if (router_opts.route_type == GLOBAL) { graph_type = GRAPH_GLOBAL; - } else { - graph_type = ( - det_routing_arch.directionality == BI_DIRECTIONAL ? - GRAPH_BIDIR : GRAPH_UNIDIR); + /* Xifan Tang: tileable undirectional rr_graph support */ + } else if (BI_DIRECTIONAL == det_routing_arch.directionality) { + graph_type = GRAPH_BIDIR; + } else if (UNI_DIRECTIONAL == det_routing_arch.directionality) { + if (true == det_routing_arch.tileable) { + graph_type = GRAPH_UNIDIR_TILEABLE; + } else { + graph_type = GRAPH_UNIDIR; + } } max_pins_per_clb = 0; diff --git a/vpr7_x2p/vpr/SRC/base/vpr_types.h b/vpr7_x2p/vpr/SRC/base/vpr_types.h index 53b0cd303..2e77e5702 100755 --- a/vpr7_x2p/vpr/SRC/base/vpr_types.h +++ b/vpr7_x2p/vpr/SRC/base/vpr_types.h @@ -815,6 +815,7 @@ struct s_det_routing_arch { float R_minW_pmos; int num_swseg_pattern; /*Xifan TANG: Switch Segment Pattern Support*/ short opin_to_wire_switch; /* mrFPGA: Xifan TANG*/ + bool tileable; /* Xifan Tang: tileable rr_graph support */ }; /* Defines the detailed routing architecture of the FPGA. Only important * diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c index e8d4a0365..8815d1ac5 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c @@ -1103,7 +1103,7 @@ void build_rr_graph_direct_connections(t_rr_graph* rr_graph, ***********************************************************************/ void build_tileable_unidir_rr_graph(INP const int L_num_types, INP t_type_ptr types, INP const int L_nx, INP const int L_ny, - INP const struct s_grid_tile **L_grid, INP const int chan_width, + INP struct s_grid_tile **L_grid, INP const int chan_width, INP const enum e_switch_block_type sb_type, INP const int Fs, INP const int num_seg_types, INP const t_segment_inf * segment_inf, diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.h b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.h index 7f26867a1..879d05ce1 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.h +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.h @@ -13,7 +13,7 @@ ChanNodeDetails build_unidir_chan_node_details(const size_t chan_width, const si void build_tileable_unidir_rr_graph(INP const int L_num_types, INP t_type_ptr types, INP const int L_nx, INP const int L_ny, - INP const struct s_grid_tile **L_grid, INP const int chan_width, + INP struct s_grid_tile **L_grid, INP const int chan_width, INP const enum e_switch_block_type sb_type, INP const int Fs, INP const int num_seg_types, INP const t_segment_inf * segment_inf, diff --git a/vpr7_x2p/vpr/SRC/route/route_common.c b/vpr7_x2p/vpr/SRC/route/route_common.c index 80a5298b5..165b54f4a 100755 --- a/vpr7_x2p/vpr/SRC/route/route_common.c +++ b/vpr7_x2p/vpr/SRC/route/route_common.c @@ -273,10 +273,15 @@ boolean try_route(int width_fac, struct s_router_opts router_opts, if (router_opts.route_type == GLOBAL) { graph_type = GRAPH_GLOBAL; - } else { - graph_type = ( - det_routing_arch.directionality == BI_DIRECTIONAL ? - GRAPH_BIDIR : GRAPH_UNIDIR); + /* Xifan Tang: tileable undirectional rr_graph support */ + } else if (BI_DIRECTIONAL == det_routing_arch.directionality) { + graph_type = GRAPH_BIDIR; + } else if (UNI_DIRECTIONAL == det_routing_arch.directionality) { + if (true == det_routing_arch.tileable) { + graph_type = GRAPH_UNIDIR_TILEABLE; + } else { + graph_type = GRAPH_UNIDIR; + } } /* Set the channel widths */ diff --git a/vpr7_x2p/vpr/SRC/route/rr_graph.c b/vpr7_x2p/vpr/SRC/route/rr_graph.c index b111fc149..730d30b96 100755 --- a/vpr7_x2p/vpr/SRC/route/rr_graph.c +++ b/vpr7_x2p/vpr/SRC/route/rr_graph.c @@ -16,6 +16,8 @@ #include "read_xml_arch_file.h" #include "ReadOptions.h" +#include "rr_graph_tileable_builder.h" + /* Xifan TANG: SWSEG SUPPORT */ #include "rr_graph_swseg.h" /* end */ @@ -180,10 +182,31 @@ static void print_distribution(FILE * fptr, static t_seg_details *alloc_and_load_global_route_seg_details( INP int nodes_per_chan, INP int global_route_switch); +static +void build_classic_rr_graph(INP t_graph_type graph_type, INP int L_num_types, + INP t_type_ptr types, INP int L_nx, INP int L_ny, + INP struct s_grid_tile **L_grid, INP int chan_width, + INP struct s_chan_width_dist *chan_capacity_inf, + INP enum e_switch_block_type sb_type, INP int Fs, INP int num_seg_types, + INP int num_switches, INP t_segment_inf * segment_inf, + INP int global_route_switch, INP int delayless_switch, + INP t_timing_inf timing_inf, INP int wire_to_ipin_switch, + INP enum e_base_cost_type base_cost_type, INP t_direct_inf *directs, + INP int num_directs, INP boolean ignore_Fc_0, OUTP int *Warnings, + /*Xifan TANG: Switch Segment Pattern Support*/ + INP int num_swseg_pattern, INP t_swseg_pattern_inf* swseg_patterns, + INP boolean opin_to_cb_fast_edges, INP boolean opin_logic_eq_edges); + + /* UDSD Modifications by WMF End */ /******************* Subroutine definitions *******************************/ +/************************************************************************* + * Top-level function of rr_graph builder + * Xifan TANG: this top function can branch between tileable rr_graph generator + * and the classical rr_graph generator + ************************************************************************/ void build_rr_graph(INP t_graph_type graph_type, INP int L_num_types, INP t_type_ptr types, INP int L_nx, INP int L_ny, INP struct s_grid_tile **L_grid, INP int chan_width, @@ -197,6 +220,50 @@ void build_rr_graph(INP t_graph_type graph_type, INP int L_num_types, /*Xifan TANG: Switch Segment Pattern Support*/ INP int num_swseg_pattern, INP t_swseg_pattern_inf* swseg_patterns, INP boolean opin_to_cb_fast_edges, INP boolean opin_logic_eq_edges) { + /* Branch here */ + if (GRAPH_UNIDIR_TILEABLE == graph_type) { + build_tileable_unidir_rr_graph(L_num_types, types, + L_nx, L_ny, L_grid, + chan_width, + sb_type, Fs, num_seg_types, segment_inf, + num_switches, global_route_switch, delayless_switch, + timing_inf, wire_to_ipin_switch, + base_cost_type, directs, num_directs, ignore_Fc_0, Warnings); + } else { + build_classic_rr_graph(graph_type, L_num_types, types, + L_nx, L_ny, L_grid, + chan_width, chan_capacity_inf, + sb_type, Fs, num_seg_types, num_switches, segment_inf, + global_route_switch, delayless_switch, + timing_inf, wire_to_ipin_switch, + base_cost_type, directs, num_directs, ignore_Fc_0, Warnings, + num_swseg_pattern, swseg_patterns, + opin_to_cb_fast_edges, opin_logic_eq_edges); + + } + + return; +} + + +/* Xifan TANG: I rename the classical rr_graph builder here. + * We can have a clean build_rr_graph top function, + * where we branch for tileable routing and classical */ +static +void build_classic_rr_graph(INP t_graph_type graph_type, INP int L_num_types, + INP t_type_ptr types, INP int L_nx, INP int L_ny, + INP struct s_grid_tile **L_grid, INP int chan_width, + INP struct s_chan_width_dist *chan_capacity_inf, + INP enum e_switch_block_type sb_type, INP int Fs, INP int num_seg_types, + INP int num_switches, INP t_segment_inf * segment_inf, + INP int global_route_switch, INP int delayless_switch, + INP t_timing_inf timing_inf, INP int wire_to_ipin_switch, + INP enum e_base_cost_type base_cost_type, INP t_direct_inf *directs, + INP int num_directs, INP boolean ignore_Fc_0, OUTP int *Warnings, + /*Xifan TANG: Switch Segment Pattern Support*/ + INP int num_swseg_pattern, INP t_swseg_pattern_inf* swseg_patterns, + INP boolean opin_to_cb_fast_edges, INP boolean opin_logic_eq_edges) { + /* Temp structures used to build graph */ int nodes_per_chan, i, j; t_seg_details *seg_details = NULL; From d48fd959a92b6c1e2956ea2e9b480bf47c65ae7e Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 20 Jun 2019 22:30:26 -0600 Subject: [PATCH 12/25] keep bug fixing for tileable rr_graph generator --- .../rr_graph/rr_graph_tileable_builder.c | 52 +++++++++++++++---- .../rr_graph/rr_graph_tileable_builder.h | 5 +- 2 files changed, 45 insertions(+), 12 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c index 8815d1ac5..fd662d188 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c @@ -361,7 +361,8 @@ enum e_side determine_io_grid_pin_side(const DeviceCoordinator& device_size, } else if (0 == grid_coordinator.get_x()) { /* LEFT side IO of FPGA */ return RIGHT; /* Such I/O has only Right side pins */ } else { - vpr_printf(TIO_MESSAGE_ERROR, "(File:%s, [LINE%d])I/O Grid is in the center part of FPGA! Currently unsupported!\n", + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d]) I/O Grid is in the center part of FPGA! Currently unsupported!\n", __FILE__, __LINE__); exit(1); } @@ -458,7 +459,7 @@ std::vector estimate_num_rr_nodes_per_type(const DeviceCoordinator& devi if (IO_TYPE == grid[ix][iy].type) { DeviceCoordinator io_device_size(device_size.get_x() - 1, device_size.get_y() - 1); DeviceCoordinator grid_coordinator(ix, iy); - io_side = determine_io_grid_pin_side(device_size, grid_coordinator); + io_side = determine_io_grid_pin_side(io_device_size, grid_coordinator); } /* get the number of OPINs */ num_rr_nodes_per_type[OPIN] += get_grid_num_pins(grids[ix][iy], DRIVER, io_side); @@ -532,8 +533,9 @@ void load_one_node_to_rr_graph_fast_lookup(t_rr_graph* rr_graph, const int node_ const int ptc_num) { /* check the size of ivec (nelem), * if the ptc_num exceeds the size limit, we realloc the ivec */ - if (ptc_num > rr_graph->rr_node_indices[node_type][x][y].nelem - 1) { - rr_graph->rr_node_indices[node_type][x][y].list = (int*) my_realloc(rr_graph->rr_node_indices[node_type][x][y].list, sizeof(int) * ptc_num); + if (ptc_num + 1 > rr_graph->rr_node_indices[node_type][x][y].nelem) { + rr_graph->rr_node_indices[node_type][x][y].nelem = ptc_num + 1; + rr_graph->rr_node_indices[node_type][x][y].list = (int*) my_realloc(rr_graph->rr_node_indices[node_type][x][y].list, sizeof(int) * (ptc_num + 1)); } /* fill the lookup table */ rr_graph->rr_node_indices[node_type][x][y].list[ptc_num] = node_index; @@ -818,7 +820,7 @@ void load_rr_nodes_basic_info(t_rr_graph* rr_graph, /* If this is the block on borders, we consider IO side */ if (IO_TYPE == grid[ix][iy].type) { DeviceCoordinator io_device_size(device_size.get_x() - 1, device_size.get_y() - 1); - io_side = determine_io_grid_pin_side(device_size, grid_coordinator); + io_side = determine_io_grid_pin_side(io_device_size, grid_coordinator); } /* Configure rr_nodes for this grid */ load_one_grid_rr_nodes_basic_info(grid_coordinator, grid[ix][iy], io_side, @@ -921,8 +923,6 @@ void load_rr_nodes_basic_info(t_rr_graph* rr_graph, rr_graph->rr_node[inode].track_ids.end() ); } - - return; } @@ -1107,8 +1107,10 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types, INP const enum e_switch_block_type sb_type, INP const int Fs, INP const int num_seg_types, INP const t_segment_inf * segment_inf, - INP const int num_switches, INP int const delayless_switch, const int global_route_switch, - INP const t_timing_inf timing_inf, INP int const wire_to_ipin_switch, + INP const int num_switches, INP const int delayless_switch, + INP const int global_route_switch, + INP const t_timing_inf timing_inf, + INP const int wire_to_ipin_switch, INP const enum e_base_cost_type base_cost_type, INP const t_direct_inf *directs, INP const int num_directs, INP const boolean ignore_Fc_0, @@ -1122,6 +1124,10 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types, /* Reset warning flag */ *Warnings = RR_GRAPH_NO_WARN; + /* Print useful information on screen */ + vpr_printf(TIO_MESSAGE_INFO, + "Creating tileable Routing Resource(RR) graph...\n"); + /* Create a matrix of grid */ DeviceCoordinator device_size(L_nx + 2, L_ny + 2); std::vector< std::vector > grids; @@ -1129,7 +1135,7 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types, grids.resize(L_nx + 2); for (int ix = 0; ix < (L_nx + 2); ++ix) { grids[ix].resize(L_ny + 2); - for (int iy = 0; ix < (L_ny + 2); ++iy) { + for (int iy = 0; iy < (L_ny + 2); ++iy) { grids[ix][iy] = L_grid[ix][iy]; } } @@ -1168,6 +1174,9 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types, tileable_rr_graph_init_rr_node(&(rr_graph.rr_node[i])); } + vpr_printf(TIO_MESSAGE_INFO, + "%d RR graph nodes allocated.\n", rr_graph.num_rr_nodes); + /************************************************************************ * 4. Initialize the basic information of rr_nodes: * coordinators: xlow, ylow, xhigh, yhigh, @@ -1175,9 +1184,13 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types, * grid_info : pb_graph_pin ***********************************************************************/ alloc_rr_graph_fast_lookup(device_size, &rr_graph); + load_rr_nodes_basic_info(&rr_graph, device_size, grids, device_chan_width, segment_infs, wire_to_ipin_switch, delayless_switch); + vpr_printf(TIO_MESSAGE_INFO, + "Built node basic information and fast-look.\n"); + /************************************************************************ * 5.1 Create the connectivity of OPINs * a. Evenly assign connections to OPINs to routing tracks @@ -1205,6 +1218,9 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types, *Warnings |= RR_GRAPH_WARN_FC_CLIPPED; } + vpr_printf(TIO_MESSAGE_INFO, + "Actual Fc numbers loaded.\n"); + /************************************************************************ * 6. Build the connections tile by tile: * We classify rr_nodes into a general switch block (GSB) data structure @@ -1219,6 +1235,9 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types, Fc_in, Fc_out, sb_type, Fs); + vpr_printf(TIO_MESSAGE_INFO, + "Regular edges of RR graph built.\n"); + /************************************************************************ * 7. Build direction connection lists ***********************************************************************/ @@ -1230,6 +1249,9 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types, build_rr_graph_direct_connections(&rr_graph, device_size, grids, delayless_switch, num_directs, directs, clb_to_clb_directs); + vpr_printf(TIO_MESSAGE_INFO, + "Direct-connection edges of RR graph built.\n"); + /************************************************************************ * 8. Allocate external data structures * a. cost_index @@ -1246,10 +1268,20 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types, /************************************************************************ * 9. Sanitizer for the rr_graph, check connectivities of rr_nodes ***********************************************************************/ + + /* Print useful information on screen */ + vpr_printf(TIO_MESSAGE_INFO, + "Create a tileable RR graph with %d nodes\n", + num_rr_nodes); + check_rr_graph(GRAPH_UNIDIR_TILEABLE, types, L_nx, L_ny, chan_width, Fs, num_seg_types, num_switches, segment_inf, global_route_switch, delayless_switch, wire_to_ipin_switch, Fc_in, Fc_out); + /* Print useful information on screen */ + vpr_printf(TIO_MESSAGE_INFO, + "Tileable Routing Resource(RR) graph pass checking.\n"); + /************************************************************************ * 10. Free all temp stucts diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.h b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.h index 879d05ce1..2792a5680 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.h +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.h @@ -17,8 +17,9 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types, INP const enum e_switch_block_type sb_type, INP const int Fs, INP const int num_seg_types, INP const t_segment_inf * segment_inf, - INP const int num_switches, INP int const delayless_switch, const int global_route_switch, - INP const t_timing_inf timing_inf, INP int const wire_to_ipin_switch, + INP const int num_switches, INP const int delayless_switch, + const int global_route_switch, + INP const t_timing_inf timing_inf, INP const int wire_to_ipin_switch, INP const enum e_base_cost_type base_cost_type, INP const t_direct_inf *directs, INP const int num_directs, INP const boolean ignore_Fc_0, From 41954056ceba08d73e5c1789578e152d2e80df02 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 21 Jun 2019 17:58:46 -0600 Subject: [PATCH 13/25] many bug fixing for tileable rr_graph generator. Still debugging --- .../SRC/device/rr_graph/chan_node_details.cpp | 45 ++- .../SRC/device/rr_graph/chan_node_details.h | 6 +- .../rr_graph/rr_graph_tileable_builder.c | 330 +++++++++++------- .../device/rr_graph/rr_graph_tileable_gsb.cpp | 88 +++-- .../device/rr_graph/rr_graph_tileable_gsb.h | 4 +- vpr7_x2p/vpr/SRC/route/rr_graph.c | 3 + 6 files changed, 318 insertions(+), 158 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/chan_node_details.cpp b/vpr7_x2p/vpr/SRC/device/rr_graph/chan_node_details.cpp index a717cd36a..070d45aa4 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/chan_node_details.cpp +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/chan_node_details.cpp @@ -73,6 +73,15 @@ size_t ChanNodeDetails::get_track_node_id(size_t track_id) const { return track_node_ids_[track_id]; } +/* Return a copy of vector */ +std::vector ChanNodeDetails::get_track_node_ids() const { + std::vector copy; + for (size_t inode = 0; inode < get_chan_width(); ++inode) { + copy.push_back(track_node_ids_[inode]); + } + return copy; +} + e_direction ChanNodeDetails::get_track_direction(size_t track_id) const { assert(validate_track_id(track_id)); return track_direction_[track_id]; @@ -111,9 +120,6 @@ std::vector ChanNodeDetails::get_seg_group(size_t track_id) const { /* Make sure a clean start */ group.clear(); - /* track_id is the first element */ - group.push_back(track_id); - for (size_t itrack = track_id; itrack < get_chan_width(); ++itrack) { if ( (get_track_direction(itrack) == get_track_direction(track_id) ) && (get_track_segment_length(itrack) == get_track_segment_length(track_id)) ) { @@ -146,9 +152,13 @@ std::vector ChanNodeDetails::get_seg_group_node_id(std::vector s } /* Get the number of tracks that starts in this routing channel */ -size_t ChanNodeDetails::get_num_starting_tracks() const { +size_t ChanNodeDetails::get_num_starting_tracks(enum e_direction track_direction) const { size_t counter = 0; for (size_t itrack = 0; itrack < get_chan_width(); ++itrack) { + /* Bypass unmatched track_direction */ + if (track_direction != get_track_direction(itrack)) { + continue; + } if (false == is_track_start(itrack)) { continue; } @@ -158,9 +168,13 @@ size_t ChanNodeDetails::get_num_starting_tracks() const { } /* Get the number of tracks that ends in this routing channel */ -size_t ChanNodeDetails::get_num_ending_tracks() const { +size_t ChanNodeDetails::get_num_ending_tracks(enum e_direction track_direction) const { size_t counter = 0; for (size_t itrack = 0; itrack < get_chan_width(); ++itrack) { + /* Bypass unmatched track_direction */ + if (track_direction != get_track_direction(itrack)) { + continue; + } if (false == is_track_end(itrack)) { continue; } @@ -169,6 +183,7 @@ size_t ChanNodeDetails::get_num_ending_tracks() const { return counter; } + /************************************************************************ * Mutators ***********************************************************************/ @@ -198,6 +213,15 @@ void ChanNodeDetails::set_track_node_id(size_t track_index, size_t track_node_id track_node_ids_[track_index] = track_node_id; } +/* Update the node_ids from a vector */ +void ChanNodeDetails::set_track_node_ids(std::vector track_node_ids) { + /* the size of vector should match chan_width */ + assert ( get_chan_width() == track_node_ids.size() ); + for (size_t inode = 0; inode < track_node_ids.size(); ++inode) { + track_node_ids_[inode] = track_node_ids[inode]; + } +} + /* Set tracks with a given direction to start */ void ChanNodeDetails::set_tracks_start(e_direction track_direction) { for (size_t inode = 0; inode < get_chan_width(); ++inode) { @@ -220,6 +244,11 @@ void ChanNodeDetails::set_tracks_end(e_direction track_direction) { /* rotate the track_node_id by an offset */ void ChanNodeDetails::rotate_track_node_id(size_t offset, e_direction track_direction, bool counter_rotate) { + /* Direct return if offset = 0*/ + if (0 == offset) { + return; + } + /* Rotate the node_ids by groups * A group begins from a track_start and ends before another track_start */ @@ -237,11 +266,13 @@ void ChanNodeDetails::rotate_track_node_id(size_t offset, e_direction track_dire std::vector track_group = get_seg_group(itrack); /* Build a vector of the node ids of the tracks */ std::vector track_group_node_id = get_seg_group_node_id(track_group); + /* adapt offset to the range of track_group_node_id */ + size_t actual_offset = offset % track_group_node_id.size(); /* Rotate or Counter rotate */ if (true == counter_rotate) { - std::rotate(track_group_node_id.begin(), track_group_node_id.end() - offset, track_group_node_id.end()); + std::rotate(track_group_node_id.rbegin(), track_group_node_id.rbegin() + actual_offset, track_group_node_id.rend()); } else { - std::rotate(track_group_node_id.begin(), track_group_node_id.begin() + offset, track_group_node_id.end()); + std::rotate(track_group_node_id.begin(), track_group_node_id.begin() + actual_offset, track_group_node_id.end()); } /* Update the node_ids */ for (size_t inode = 0; inode < track_group.size(); ++inode) { diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/chan_node_details.h b/vpr7_x2p/vpr/SRC/device/rr_graph/chan_node_details.h index 1b75cf8eb..a5a5da042 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/chan_node_details.h +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/chan_node_details.h @@ -75,6 +75,7 @@ class ChanNodeDetails { public: /* Accessors */ size_t get_chan_width() const; size_t get_track_node_id(size_t track_id) const; + std::vector get_track_node_ids() const; e_direction get_track_direction(size_t track_id) const; size_t get_track_segment_length(size_t track_id) const; size_t get_track_segment_id(size_t track_id) const; @@ -82,12 +83,13 @@ class ChanNodeDetails { bool is_track_end(size_t track_id) const; std::vector get_seg_group(size_t track_id) const; std::vector get_seg_group_node_id(std::vector seg_group) const; - size_t get_num_starting_tracks() const; - size_t get_num_ending_tracks() const; + size_t get_num_starting_tracks(enum e_direction track_direction) const; + size_t get_num_ending_tracks(enum e_direction track_direction) const; public: /* Mutators */ void reserve(size_t chan_width); /* Reserve the capacitcy of vectors */ void add_track(size_t track_node_id, e_direction track_direction, size_t seg_id, size_t seg_length, size_t is_start, size_t is_end); void set_track_node_id(size_t track_index, size_t track_node_id); + void set_track_node_ids(std::vector track_node_ids); void set_tracks_start(e_direction track_direction); void set_tracks_end(e_direction track_direction); void rotate_track_node_id(size_t offset, e_direction track_direction, bool counter_rotate); /* rotate the track_node_id by an offset */ diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c index fd662d188..061f057ab 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c @@ -254,10 +254,10 @@ std::vector get_num_tracks_per_seg_type(const size_t chan_width, * +---------------------------------------+--------------+ * | 10 | <--------MUX | Yes | No | * +---------------------------------------+--------------+ - * | 11 | --------> | No | - * +---------------------------------+ - * | 12 | <-------- | No | - * +---------------------------------+ + * | 11 | -------->MUX | No | Yes | + * +------------------------------------------------------+ + * | 12 | <-------- | No | No | + * +------------------------------------------------------+ * * 3. SPECIAL for fringes: TOP|RIGHT|BOTTOM|RIGHT * if device_side is NUM_SIDES, we assume this channel does not locate on borders @@ -383,8 +383,9 @@ std::vector get_grid_side_pins(const t_grid_tile& cur_grid, pin_list.clear(); for (int ipin = 0; ipin < cur_grid.type->num_pins; ++ipin) { + int class_id = cur_grid.type->pin_class[ipin]; if ( (1 == cur_grid.type->pinloc[pin_height][pin_side][ipin]) - && (pin_type == cur_grid.type->pin_class[ipin]) ) { + && (pin_type == cur_grid.type->class_inf[class_id].type) ) { pin_list.push_back(ipin); } } @@ -400,24 +401,52 @@ static size_t get_grid_num_pins(const t_grid_tile& cur_grid, const enum e_pin_type pin_type, const enum e_side io_side) { size_t num_pins = 0; Side io_side_manager(io_side); - /* For IO_TYPE sides */ - for (size_t side = 0; side < NUM_SIDES; ++side) { - Side side_manager(side); - /* skip unwanted sides */ - if ( (IO_TYPE == cur_grid.type) - && (side != io_side_manager.to_size_t()) ) { - continue; + + /* Consider capacity of the grid */ + for (int iblk = 0; iblk < cur_grid.type->capacity; ++iblk) { + /* For IO_TYPE sides */ + for (size_t side = 0; side < NUM_SIDES; ++side) { + Side side_manager(side); + /* skip unwanted sides */ + if ( (IO_TYPE == cur_grid.type) + && (side != io_side_manager.to_size_t()) ) { + continue; + } + /* Get pin list */ + for (int height = 0; height < cur_grid.type->height; ++height) { + std::vector pin_list = get_grid_side_pins(cur_grid, pin_type, side_manager.get_side(), height); + num_pins += pin_list.size(); + } } - /* Get pin list */ - for (int height = 0; height < cur_grid.type->height; ++height) { - std::vector pin_list = get_grid_side_pins(cur_grid, pin_type, side_manager.get_side(), height); - num_pins += pin_list.size(); - } } return num_pins; } +/************************************************************************ + * Get the number of pins for a grid (either OPIN or IPIN) + * For IO_TYPE, only one side will be used, we consider one side of pins + * For others, we consider all the sides + ***********************************************************************/ +static +size_t get_grid_num_classes(const t_grid_tile& cur_grid, const enum e_pin_type pin_type) { + size_t num_classes = 0; + + /* Consider capacity of the grid */ + for (int iblk = 0; iblk < cur_grid.type->capacity; ++iblk) { + for (int iclass = 0; iclass < cur_grid.type->num_class; ++iclass) { + /* Bypass unmatched pin_type */ + if (pin_type != cur_grid.type->class_inf[iclass].type) { + continue; + } + num_classes++; + } + } + + return num_classes; +} + + /************************************************************************ * Estimate the number of rr_nodes per category: * CHANX, CHANY, IPIN, OPIN, SOURCE, SINK @@ -444,8 +473,8 @@ std::vector estimate_num_rr_nodes_per_type(const DeviceCoordinator& devi * Note that the number of SOURCE nodes are the same as OPINs * and the number of SINK nodes are the same as IPINs ***********************************************************************/ - for (size_t ix = 0; ix < grids.size(); ++ix) { - for (size_t iy = 0; iy < grids[ix].size(); ++iy) { + for (size_t ix = 0; ix < device_size.get_x(); ++ix) { + for (size_t iy = 0; iy < device_size.get_y(); ++iy) { /* Skip EMPTY tiles */ if (EMPTY_TYPE == grids[ix][iy].type) { continue; @@ -465,11 +494,12 @@ std::vector estimate_num_rr_nodes_per_type(const DeviceCoordinator& devi num_rr_nodes_per_type[OPIN] += get_grid_num_pins(grids[ix][iy], DRIVER, io_side); /* get the number of IPINs */ num_rr_nodes_per_type[IPIN] += get_grid_num_pins(grids[ix][iy], RECEIVER, io_side); + /* SOURCE: number of classes whose type is DRIVER */ + num_rr_nodes_per_type[SOURCE] += get_grid_num_classes(grid[ix][iy], DRIVER); + /* SINK: number of classes whose type is RECEIVER */ + num_rr_nodes_per_type[SINK] += get_grid_num_classes(grid[ix][iy], RECEIVER); } } - /* SOURCE and SINK */ - num_rr_nodes_per_type[SOURCE] = num_rr_nodes_per_type[OPIN]; - num_rr_nodes_per_type[SINK] = num_rr_nodes_per_type[IPIN]; /************************************************************************ * 2. Assign the segments for each routing channel, @@ -491,15 +521,18 @@ std::vector estimate_num_rr_nodes_per_type(const DeviceCoordinator& devi for (size_t ix = 1; ix < device_size.get_x() - 1; ++ix) { enum e_side chan_side = NUM_SIDES; /* For LEFT side of FPGA */ - if (0 == ix) { + if (1 == ix) { chan_side = LEFT; } /* For RIGHT side of FPGA */ - if (grids.size() - 2 == ix) { + if (device_size.get_x() - 2 == ix) { chan_side = RIGHT; } ChanNodeDetails chanx_details = build_unidir_chan_node_details(chan_width[0], device_size.get_x() - 2, chan_side, segment_infs); - num_rr_nodes_per_type[CHANX] += chanx_details.get_num_starting_tracks(); + /* When an INC_DIRECTION CHANX starts, we need a new rr_node */ + num_rr_nodes_per_type[CHANX] += chanx_details.get_num_starting_tracks(INC_DIRECTION); + /* When an DEC_DIRECTION CHANX ends, we need a new rr_node */ + num_rr_nodes_per_type[CHANX] += chanx_details.get_num_ending_tracks(DEC_DIRECTION); } } @@ -508,18 +541,29 @@ std::vector estimate_num_rr_nodes_per_type(const DeviceCoordinator& devi for (size_t iy = 1; iy < device_size.get_y() - 1; ++iy) { enum e_side chan_side = NUM_SIDES; /* For LEFT side of FPGA */ - if (0 == iy) { + if (1 == iy) { chan_side = BOTTOM; } /* For RIGHT side of FPGA */ - if (grids[ix].size() - 2 == iy) { + if (device_size.get_y() - 2 == iy) { chan_side = TOP; } ChanNodeDetails chany_details = build_unidir_chan_node_details(chan_width[1], device_size.get_y() - 2, chan_side, segment_infs); - num_rr_nodes_per_type[CHANY] += chany_details.get_num_starting_tracks(); + /* When an INC_DIRECTION CHANX starts, we need a new rr_node */ + num_rr_nodes_per_type[CHANY] += chany_details.get_num_starting_tracks(INC_DIRECTION); + /* When an DEC_DIRECTION CHANX ends, we need a new rr_node */ + num_rr_nodes_per_type[CHANY] += chany_details.get_num_ending_tracks(DEC_DIRECTION); } } + vpr_printf(TIO_MESSAGE_INFO, "Estimate %lu SOURCE nodes.\n", num_rr_nodes_per_type[SOURCE]); + vpr_printf(TIO_MESSAGE_INFO, "Estimate %lu SINK nodes.\n", num_rr_nodes_per_type[SINK] ); + vpr_printf(TIO_MESSAGE_INFO, "Estimate %lu OPIN nodes.\n", num_rr_nodes_per_type[OPIN] ); + vpr_printf(TIO_MESSAGE_INFO, "Estimate %lu IPIN nodes.\n", num_rr_nodes_per_type[IPIN] ); + vpr_printf(TIO_MESSAGE_INFO, "Estimate %lu CHANX nodes.\n", num_rr_nodes_per_type[CHANY] ); + vpr_printf(TIO_MESSAGE_INFO, "Estimate %lu CHANY nodes.\n", num_rr_nodes_per_type[CHANY] ); + + return num_rr_nodes_per_type; } @@ -554,69 +598,81 @@ void load_one_grid_rr_nodes_basic_info(const DeviceCoordinator& grid_coordinator t_rr_graph* rr_graph, size_t* cur_node_id, const int wire_to_ipin_switch, const int delayless_switch) { - Side io_side_manager(io_side); - /* Walk through the height of each grid, - * get pins and configure the rr_nodes */ - for (int height = 0; height < cur_grid.type->height; ++height) { - /* Walk through sides */ - for (size_t side = 0; side < NUM_SIDES; ++side) { - Side side_manager(side); - /* skip unwanted sides */ - if ( (IO_TYPE == cur_grid.type) - && (side != io_side_manager.to_size_t()) ) { - continue; - } - /* Find OPINs */ - /* Configure pins by pins */ - std::vector opin_list = get_grid_side_pins(cur_grid, DRIVER, side_manager.get_side(), height); - for (size_t pin = 0; pin < opin_list.size(); ++pin) { - /* Configure the rr_node for the OPIN */ - rr_graph->rr_node[*cur_node_id].type = OPIN; - rr_graph->rr_node[*cur_node_id].xlow = grid_coordinator.get_x(); - rr_graph->rr_node[*cur_node_id].xhigh = grid_coordinator.get_x(); - rr_graph->rr_node[*cur_node_id].ylow = grid_coordinator.get_y(); - rr_graph->rr_node[*cur_node_id].yhigh = grid_coordinator.get_y(); - rr_graph->rr_node[*cur_node_id].ptc_num = opin_list[pin]; - rr_graph->rr_node[*cur_node_id].capacity = 1; - rr_graph->rr_node[*cur_node_id].occ = 0; - /* cost index is a FIXED value for OPIN */ - rr_graph->rr_node[*cur_node_id].cost_index = OPIN_COST_INDEX; - /* Switch info */ - rr_graph->rr_node[*cur_node_id].driver_switch = delayless_switch; - /* fill fast look-up table */ - load_one_node_to_rr_graph_fast_lookup(rr_graph, *cur_node_id, - rr_graph->rr_node[*cur_node_id].type, - rr_graph->rr_node[*cur_node_id].xlow, - rr_graph->rr_node[*cur_node_id].ylow, - rr_graph->rr_node[*cur_node_id].ptc_num); - /* Update node counter */ - (*cur_node_id)++; - } - /* Find IPINs */ - /* Configure pins by pins */ - std::vector ipin_list = get_grid_side_pins(cur_grid, RECEIVER, side_manager.get_side(), height); - for (size_t pin = 0; pin < ipin_list.size(); ++pin) { - rr_graph->rr_node[*cur_node_id].type = IPIN; - rr_graph->rr_node[*cur_node_id].xlow = grid_coordinator.get_x(); - rr_graph->rr_node[*cur_node_id].xhigh = grid_coordinator.get_x(); - rr_graph->rr_node[*cur_node_id].ylow = grid_coordinator.get_y(); - rr_graph->rr_node[*cur_node_id].yhigh = grid_coordinator.get_y(); - rr_graph->rr_node[*cur_node_id].ptc_num = opin_list[pin]; - rr_graph->rr_node[*cur_node_id].capacity = 1; - rr_graph->rr_node[*cur_node_id].occ = 0; - /* cost index is a FIXED value for IPIN */ - rr_graph->rr_node[*cur_node_id].cost_index = IPIN_COST_INDEX; - /* Switch info */ - rr_graph->rr_node[*cur_node_id].driver_switch = wire_to_ipin_switch; - /* fill fast look-up table */ - load_one_node_to_rr_graph_fast_lookup(rr_graph, *cur_node_id, - rr_graph->rr_node[*cur_node_id].type, - rr_graph->rr_node[*cur_node_id].xlow, - rr_graph->rr_node[*cur_node_id].ylow, - rr_graph->rr_node[*cur_node_id].ptc_num); - /* Update node counter */ - (*cur_node_id)++; - } + Side io_side_manager(io_side); + + /* Consider capacity of the grid */ + for (int iblk = 0; iblk < cur_grid.type->capacity; ++iblk) { + /* Walk through the height of each grid, + * get pins and configure the rr_nodes */ + for (int height = 0; height < cur_grid.type->height; ++height) { + /* Walk through sides */ + for (size_t side = 0; side < NUM_SIDES; ++side) { + Side side_manager(side); + /* skip unwanted sides */ + if ( (IO_TYPE == cur_grid.type) + && (side != io_side_manager.to_size_t()) ) { + continue; + } + /* Find OPINs */ + /* Configure pins by pins */ + std::vector opin_list = get_grid_side_pins(cur_grid, DRIVER, side_manager.get_side(), height); + for (size_t pin = 0; pin < opin_list.size(); ++pin) { + /* Configure the rr_node for the OPIN */ + rr_graph->rr_node[*cur_node_id].type = OPIN; + rr_graph->rr_node[*cur_node_id].xlow = grid_coordinator.get_x(); + rr_graph->rr_node[*cur_node_id].xhigh = grid_coordinator.get_x(); + rr_graph->rr_node[*cur_node_id].ylow = grid_coordinator.get_y(); + rr_graph->rr_node[*cur_node_id].yhigh = grid_coordinator.get_y(); + rr_graph->rr_node[*cur_node_id].ptc_num = opin_list[pin]; + rr_graph->rr_node[*cur_node_id].capacity = 1; + rr_graph->rr_node[*cur_node_id].occ = 0; + /* cost index is a FIXED value for OPIN */ + rr_graph->rr_node[*cur_node_id].cost_index = OPIN_COST_INDEX; + /* Switch info */ + rr_graph->rr_node[*cur_node_id].driver_switch = delayless_switch; + /* fill fast look-up table */ + load_one_node_to_rr_graph_fast_lookup(rr_graph, *cur_node_id, + rr_graph->rr_node[*cur_node_id].type, + rr_graph->rr_node[*cur_node_id].xlow, + rr_graph->rr_node[*cur_node_id].ylow, + rr_graph->rr_node[*cur_node_id].ptc_num); + /* Update node counter */ + (*cur_node_id)++; + } /* End of loading OPIN rr_nodes */ + /* Find IPINs */ + /* Configure pins by pins */ + std::vector ipin_list = get_grid_side_pins(cur_grid, RECEIVER, side_manager.get_side(), height); + for (size_t pin = 0; pin < ipin_list.size(); ++pin) { + rr_graph->rr_node[*cur_node_id].type = IPIN; + rr_graph->rr_node[*cur_node_id].xlow = grid_coordinator.get_x(); + rr_graph->rr_node[*cur_node_id].xhigh = grid_coordinator.get_x(); + rr_graph->rr_node[*cur_node_id].ylow = grid_coordinator.get_y(); + rr_graph->rr_node[*cur_node_id].yhigh = grid_coordinator.get_y(); + rr_graph->rr_node[*cur_node_id].ptc_num = ipin_list[pin]; + rr_graph->rr_node[*cur_node_id].capacity = 1; + rr_graph->rr_node[*cur_node_id].occ = 0; + /* cost index is a FIXED value for IPIN */ + rr_graph->rr_node[*cur_node_id].cost_index = IPIN_COST_INDEX; + /* Switch info */ + rr_graph->rr_node[*cur_node_id].driver_switch = wire_to_ipin_switch; + /* fill fast look-up table */ + load_one_node_to_rr_graph_fast_lookup(rr_graph, *cur_node_id, + rr_graph->rr_node[*cur_node_id].type, + rr_graph->rr_node[*cur_node_id].xlow, + rr_graph->rr_node[*cur_node_id].ylow, + rr_graph->rr_node[*cur_node_id].ptc_num); + /* Update node counter */ + (*cur_node_id)++; + } /* End of loading IPIN rr_nodes */ + } /* End of side enumeration */ + } /* End of height enumeration */ + } /* End of capacity enumeration */ + + /* Consider capacity of the grid */ + for (int iblk = 0; iblk < cur_grid.type->capacity; ++iblk) { + /* Walk through the height of each grid, + * get pins and configure the rr_nodes */ + for (int height = 0; height < cur_grid.type->height; ++height) { /* Set a SOURCE or a SINK rr_node for each class */ for (int iclass = 0; iclass < cur_grid.type->num_class; ++iclass) { /* Set a SINK rr_node for the OPIN */ @@ -815,6 +871,10 @@ void load_rr_nodes_basic_info(t_rr_graph* rr_graph, if (EMPTY_TYPE == grids[ix][iy].type) { continue; } + /* We only build rr_nodes for grids with offset=0 */ + if (0 < grids[ix][iy].offset) { + continue; + } DeviceCoordinator grid_coordinator(ix, iy); enum e_side io_side = NUM_SIDES; /* If this is the block on borders, we consider IO side */ @@ -829,13 +889,29 @@ void load_rr_nodes_basic_info(t_rr_graph* rr_graph, } } + /* FIXME: DEBUG CODES TO BE REMOVED + std::vector node_cnt; + node_cnt.resize(NUM_RR_TYPES); + for (int inode = 0; inode < rr_graph->num_rr_nodes; ++inode) { + node_cnt[rr_graph->rr_node[inode].type]++; + } + vpr_printf(TIO_MESSAGE_INFO, "Load basic information to %lu SOURCE NODE.\n", node_cnt[SOURCE]); + vpr_printf(TIO_MESSAGE_INFO, "Load basic information to %lu SINK NODE.\n", node_cnt[SINK]); + vpr_printf(TIO_MESSAGE_INFO, "Load basic information to %lu OPIN NODE.\n", node_cnt[OPIN]); + vpr_printf(TIO_MESSAGE_INFO, "Load basic information to %lu IPIN NODE.\n", node_cnt[IPIN]); + */ + /* For X-direction Channel: CHANX */ for (size_t iy = 0; iy < device_size.get_y() - 1; ++iy) { + /* Keep a vector of node_ids for the channels, because we will rotate them when walking through ix */ + std::vector track_node_ids; + /* Make sure a clean start */ + track_node_ids.clear(); for (size_t ix = 1; ix < device_size.get_x() - 1; ++ix) { DeviceCoordinator chan_coordinator(ix, iy); enum e_side chan_side = NUM_SIDES; /* For LEFT side of FPGA */ - if (0 == ix) { + if (1 == ix) { chan_side = LEFT; } /* For RIGHT side of FPGA */ @@ -843,37 +919,47 @@ void load_rr_nodes_basic_info(t_rr_graph* rr_graph, chan_side = RIGHT; } ChanNodeDetails chanx_details = build_unidir_chan_node_details(chan_width[0], device_size.get_x() - 2, chan_side, segment_infs); - /* Configure CHANX in this channel */ - load_one_chan_rr_nodes_basic_info(chan_coordinator, CHANX, - &chanx_details, - segment_infs, - CHANX_COST_INDEX_START, - rr_graph, &cur_node_id); - /* Rotate the chanx_details by an offset of 1*/ + /* Force node_ids from the previous chanx */ + if (0 < track_node_ids.size()) { + chanx_details.set_track_node_ids(track_node_ids); + } + /* Rotate the chanx_details by an offset of ix - 1, the distance to the most left channel */ /* For INC_DIRECTION, we use clockwise rotation * node_id A ----> -----> node_id D * node_id B ----> / ----> node_id A * node_id C ----> / ----> node_id B * node_id D ----> ----> node_id C */ - chanx_details.rotate_track_node_id(1, INC_DIRECTION, false); + chanx_details.rotate_track_node_id(ix - 1, INC_DIRECTION, false); /* For DEC_DIRECTION, we use clockwise rotation * node_id A <----- <----- node_id B * node_id B <----- \ <----- node_id C * node_id C <----- \ <----- node_id D * node_id D <----- <----- node_id A */ - chanx_details.rotate_track_node_id(1, DEC_DIRECTION, true); + chanx_details.rotate_track_node_id(ix - 1, DEC_DIRECTION, true); + /* Configure CHANX in this channel */ + load_one_chan_rr_nodes_basic_info(chan_coordinator, CHANX, + &chanx_details, + segment_infs, + CHANX_COST_INDEX_START, + rr_graph, &cur_node_id); + /* Get a copy of node_ids */ + track_node_ids = chanx_details.get_track_node_ids(); } } /* For Y-direction Channel: CHANX */ for (size_t ix = 0; ix < device_size.get_x() - 1; ++ix) { + /* Keep a vector of node_ids for the channels, because we will rotate them when walking through ix */ + std::vector track_node_ids; + /* Make sure a clean start */ + track_node_ids.clear(); for (size_t iy = 1; iy < device_size.get_y() - 1; ++iy) { DeviceCoordinator chan_coordinator(ix, iy); enum e_side chan_side = NUM_SIDES; /* For LEFT side of FPGA */ - if (0 == iy) { + if (1 == iy) { chan_side = BOTTOM; } /* For RIGHT side of FPGA */ @@ -881,12 +967,10 @@ void load_rr_nodes_basic_info(t_rr_graph* rr_graph, chan_side = TOP; } ChanNodeDetails chany_details = build_unidir_chan_node_details(chan_width[1], device_size.get_y() - 2, chan_side, segment_infs); - /* Configure CHANX in this channel */ - load_one_chan_rr_nodes_basic_info(chan_coordinator, CHANY, - &chany_details, - segment_infs, - CHANX_COST_INDEX_START + segment_infs.size(), - rr_graph, &cur_node_id); + /* Force node_ids from the previous chanx */ + if (0 < track_node_ids.size()) { + chany_details.set_track_node_ids(track_node_ids); + } /* Rotate the chany_details by an offset of 1*/ /* For INC_DIRECTION, we use clockwise rotation * node_id A ----> -----> node_id D @@ -894,14 +978,22 @@ void load_rr_nodes_basic_info(t_rr_graph* rr_graph, * node_id C ----> / ----> node_id B * node_id D ----> ----> node_id C */ - chany_details.rotate_track_node_id(1, INC_DIRECTION, false); + chany_details.rotate_track_node_id(iy - 1, INC_DIRECTION, false); /* For DEC_DIRECTION, we use clockwise rotation * node_id A <----- <----- node_id B * node_id B <----- \ <----- node_id C * node_id C <----- \ <----- node_id D * node_id D <----- <----- node_id A */ - chany_details.rotate_track_node_id(1, DEC_DIRECTION, true); + chany_details.rotate_track_node_id(iy - 1, DEC_DIRECTION, true); + /* Configure CHANX in this channel */ + load_one_chan_rr_nodes_basic_info(chan_coordinator, CHANY, + &chany_details, + segment_infs, + CHANX_COST_INDEX_START + segment_infs.size(), + rr_graph, &cur_node_id); + /* Get a copy of node_ids */ + track_node_ids = chany_details.get_track_node_ids(); } } @@ -1005,13 +1097,13 @@ void build_rr_graph_edges(t_rr_graph* rr_graph, /* adapt the track_to_ipin_lookup for the GSB nodes */ t_track2pin_map track2ipin_map; /* [0..track_gsb_side][0..num_tracks][ipin_indices] */ /* Get the Fc index of the grid */ - int grid_Fc_in_index = grids[grid_coordinator.get_x()][grid_coordinator.get_x()].type->index; + int grid_Fc_in_index = grids[grid_coordinator.get_x()][grid_coordinator.get_y()].type->index; track2ipin_map = build_gsb_track_to_ipin_map(rr_graph, rr_gsb, segment_inf, Fc_in[grid_Fc_in_index]); /* adapt the opin_to_track_map for the GSB nodes */ t_pin2track_map opin2track_map; /* [0..gsb_side][0..num_opin_node][track_indices] */ /* Get the Fc index of the grid */ - int grid_Fc_out_index = grids[grid_coordinator.get_x()][grid_coordinator.get_x()].type->index; + int grid_Fc_out_index = grids[grid_coordinator.get_x()][grid_coordinator.get_y()].type->index; opin2track_map = build_gsb_opin_to_track_map(rr_graph, rr_gsb, segment_inf, Fc_out[grid_Fc_out_index]); /* adapt the switch_block_conn for the GSB nodes */ @@ -1019,7 +1111,7 @@ void build_rr_graph_edges(t_rr_graph* rr_graph, sb_conn = build_gsb_track_to_track_map(rr_graph, rr_gsb, sb_type, Fs, segment_inf); /* Build edges for a GSB */ - build_edges_for_one_tileable_rr_gsb(rr_graph, &rr_gsb, + build_edges_for_one_tileable_rr_gsb(rr_graph, grids, &rr_gsb, track2ipin_map, opin2track_map, sb_conn); /* Finish this GSB, go to the next*/ @@ -1218,9 +1310,6 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types, *Warnings |= RR_GRAPH_WARN_FC_CLIPPED; } - vpr_printf(TIO_MESSAGE_INFO, - "Actual Fc numbers loaded.\n"); - /************************************************************************ * 6. Build the connections tile by tile: * We classify rr_nodes into a general switch block (GSB) data structure @@ -1235,9 +1324,6 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types, Fc_in, Fc_out, sb_type, Fs); - vpr_printf(TIO_MESSAGE_INFO, - "Regular edges of RR graph built.\n"); - /************************************************************************ * 7. Build direction connection lists ***********************************************************************/ @@ -1249,8 +1335,12 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types, build_rr_graph_direct_connections(&rr_graph, device_size, grids, delayless_switch, num_directs, directs, clb_to_clb_directs); + size_t num_edges = 0; + for (int inode = 0; inode < rr_graph.num_rr_nodes; ++inode) { + num_edges += rr_graph.rr_node[inode].num_edges; + } vpr_printf(TIO_MESSAGE_INFO, - "Direct-connection edges of RR graph built.\n"); + "%lu edges of RR graph built.\n", num_edges); /************************************************************************ * 8. Allocate external data structures diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.cpp b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.cpp index e67e72e17..933b94d05 100755 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.cpp +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.cpp @@ -131,8 +131,8 @@ bool is_gsb_in_track_cb_population(const RRGSB& rr_gsb, DeviceCoordinator side_coordinator = rr_gsb.get_side_block_coordinator(gsb_side); /* Get the offset */ - size_t offset = (side_coordinator.get_x() - track_node->xlow) - + (side_coordinator.get_y() - track_node->ylow); + size_t offset = std::abs((int)side_coordinator.get_x() - track_node->xlow) + + std::abs((int)side_coordinator.get_y() - track_node->ylow); /* Get segment id */ size_t seg_id = rr_gsb.get_chan_node_segment(gsb_side, track_id); @@ -170,8 +170,8 @@ bool is_gsb_in_track_sb_population(const RRGSB& rr_gsb, DeviceCoordinator side_coordinator = rr_gsb.get_side_block_coordinator(gsb_side); /* Get the offset */ - size_t offset = (side_coordinator.get_x() - track_node->xlow) - + (side_coordinator.get_y() - track_node->ylow); + size_t offset = std::abs((int)side_coordinator.get_x() - track_node->xlow) + + std::abs((int)side_coordinator.get_y() - track_node->ylow); /* Get segment id */ size_t seg_id = rr_gsb.get_chan_node_segment(gsb_side, track_id); @@ -198,9 +198,9 @@ std::vector get_to_track_list(const int Fs, const int to_track, const in /* TODO: currently, for Fs > 3, I always search the next from_track until Fs is satisfied * The optimal track selection should be done in a more scientific way!!! */ - size_t to_track_i = to_track + i; + int to_track_i = to_track + i; /* make sure the track id is still in range */ - if ( to_track_i > (size_t)num_to_tracks) { + if ( to_track_i > num_to_tracks) { to_track_i = to_track_i % num_to_tracks; } /* from track must be connected */ @@ -368,6 +368,9 @@ void build_gsb_one_group_track_to_track_map(const t_rr_graph* rr_graph, size_t from_side_index = side_manager.to_size_t(); size_t from_track_index = from_tracks[side][inode]; size_t to_track_index = to_tracks[to_side_index][to_track_ids[to_track_id]]; + printf("from_track(size=%lu): %lu , to_track_ids[%lu]:%lu, to_track_index: %lu in a group of %lu tracks\n", + from_tracks[side].size(), inode, to_track_id, to_track_ids[to_track_id], + to_track_index, to_tracks[to_side_index].size()); t_rr_node* to_track_node = rr_gsb.get_chan_node(to_side, to_track_index); (*track2track_map)[from_side_index][from_track_index].push_back(to_track_node - rr_graph->rr_node); } @@ -453,11 +456,11 @@ t_track2track_map build_gsb_track_to_track_map(const t_rr_graph* rr_graph, switch (track_status) { case TRACK_START: /* update starting track list */ - start_tracks[gsb_side].push_back(inode); + start_tracks[side].push_back(inode); break; case TRACK_END: /* Update end track list */ - end_tracks[gsb_side].push_back(inode); + end_tracks[side].push_back(inode); break; case TRACK_PASS: /* We need to check Switch block population of this track @@ -465,7 +468,7 @@ t_track2track_map build_gsb_track_to_track_map(const t_rr_graph* rr_graph, */ if (true == is_gsb_in_track_sb_population(rr_gsb, gsb_side, inode, segment_inf)) { /* Update passing track list */ - pass_tracks[gsb_side].push_back(inode); + pass_tracks[side].push_back(inode); } break; default: @@ -917,6 +920,17 @@ void add_one_edge_for_two_rr_nodes(const t_rr_graph* rr_graph, return; } +/************************************************************************ + * Get the class index of a grid pin + ***********************************************************************/ +static +int get_grid_pin_class_index(const t_grid_tile& cur_grid, + const int pin_index) { + /* check */ + assert ( pin_index < cur_grid.type->num_pins); + return cur_grid.type->pin_class[pin_index]; +} + /************************************************************************ * Create edges for each rr_node of a General Switch Blocks (GSB): * 1. create edges between SOURCE and OPINs @@ -925,7 +939,9 @@ void add_one_edge_for_two_rr_nodes(const t_rr_graph* rr_graph, * 4. create edges between OPINs, CHANX and CHANY (connections inside switch blocks) * 5. create edges between OPINs and IPINs (direct-connections) ***********************************************************************/ -void build_edges_for_one_tileable_rr_gsb(const t_rr_graph* rr_graph, const RRGSB* rr_gsb, +void build_edges_for_one_tileable_rr_gsb(const t_rr_graph* rr_graph, + const std::vector< std::vector > grids, + const RRGSB* rr_gsb, const t_track2pin_map track2ipin_map, const t_pin2track_map opin2track_map, const t_track2track_map track2track_map) { @@ -940,9 +956,10 @@ void build_edges_for_one_tileable_rr_gsb(const t_rr_graph* rr_graph, const RRGSB /* Find OPINs */ for (size_t inode = 0; inode < rr_gsb->get_num_opin_nodes(gsb_side); ++inode) { t_rr_node* opin_node = rr_gsb->get_opin_node(gsb_side, inode); + int src_node_ptc_num = get_grid_pin_class_index(grids[opin_node->xlow][opin_node->ylow], opin_node->ptc_num); /* 1. create edges between SOURCE and OPINs */ int src_node_id = get_rr_node_index(opin_node->xlow, opin_node->ylow, - SOURCE, opin_node->ptc_num, + SOURCE, src_node_ptc_num, rr_graph->rr_node_indices); /* add edges to the src_node */ add_one_edge_for_two_rr_nodes(rr_graph, src_node_id, opin_node - rr_graph->rr_node, @@ -960,27 +977,38 @@ void build_edges_for_one_tileable_rr_gsb(const t_rr_graph* rr_graph, const RRGSB /* Find IPINs */ for (size_t inode = 0; inode < rr_gsb->get_num_ipin_nodes(gsb_side); ++inode) { t_rr_node* ipin_node = rr_gsb->get_ipin_node(gsb_side, inode); + int sink_node_ptc_num = get_grid_pin_class_index(grids[ipin_node->xlow][ipin_node->ylow], ipin_node->ptc_num); /* 3. create edges between IPINs and SINKs */ int sink_node_id = get_rr_node_index(ipin_node->xlow, ipin_node->ylow, - SINK, ipin_node->ptc_num, + SINK, sink_node_ptc_num, rr_graph->rr_node_indices); /* add edges to connect the IPIN node to SINK nodes */ add_one_edge_for_two_rr_nodes(rr_graph, ipin_node - rr_graph->rr_node, sink_node_id, rr_graph->rr_node[sink_node_id].driver_switch); } /* Find CHANX or CHANY */ + /* For TRACKs to IPINs, we only care LEFT and TOP sides + * Skip RIGHT and BOTTOM for the ipin2track_map since they should be handled in other GSBs + */ + if ( (side_manager.get_side() == rr_gsb->get_cb_chan_side(CHANX)) + || (side_manager.get_side() == rr_gsb->get_cb_chan_side(CHANY)) ) { + /* 4. create edges between CHANX|CHANY and IPINs, using ipin2track_map */ + for (size_t inode = 0; inode < rr_gsb->get_chan_width(gsb_side); ++inode) { + t_rr_node* chan_node = rr_gsb->get_chan_node(gsb_side, inode); + int num_edges = track2ipin_map[side_manager.to_size_t()][inode].size(); + for (int iedge = 0; iedge < num_edges; ++iedge) { + int ipin_node_id = track2ipin_map[side_manager.to_size_t()][inode][iedge]; + /* add edges to the chan_node */ + add_one_edge_for_two_rr_nodes(rr_graph, chan_node - rr_graph->rr_node, ipin_node_id, + rr_graph->rr_node[ipin_node_id].driver_switch); + } + } + } + + /* 5. create edges between CHANX|CHANY and CHANX|CHANY, using track2track_map */ for (size_t inode = 0; inode < rr_gsb->get_chan_width(gsb_side); ++inode) { t_rr_node* chan_node = rr_gsb->get_chan_node(gsb_side, inode); - /* 4. create edges between CHANX|CHANY and IPINs, using ipin2track_map */ - int num_edges = track2ipin_map[side_manager.to_size_t()][inode].size(); - for (int iedge = 0; iedge < num_edges; ++iedge) { - int ipin_node_id = track2ipin_map[side_manager.to_size_t()][inode][iedge]; - /* add edges to the chan_node */ - add_one_edge_for_two_rr_nodes(rr_graph, chan_node - rr_graph->rr_node, ipin_node_id, - rr_graph->rr_node[ipin_node_id].driver_switch); - } - /* 5. create edges between CHANX|CHANY and CHANX|CHANY, using track2track_map */ - num_edges = track2track_map[side_manager.to_size_t()][inode].size(); + int num_edges = track2track_map[side_manager.to_size_t()][inode].size(); for (int iedge = 0; iedge < num_edges; ++iedge) { int track_node_id = track2track_map[side_manager.to_size_t()][inode][iedge]; /* add edges to the chan_node */ @@ -1015,6 +1043,7 @@ void build_gsb_one_ipin_track2pin_map(const t_rr_graph* rr_graph, t_track2pin_map* track2ipin_map) { /* Get a list of segment_ids*/ enum e_side chan_side = rr_gsb.get_cb_chan_side(ipin_side); + Side chan_side_manager(chan_side); std::vector seg_list = rr_gsb.get_chan_segment_ids(chan_side); size_t chan_width = rr_gsb.get_chan_width(chan_side); Side ipin_side_manager(ipin_side); @@ -1058,11 +1087,11 @@ void build_gsb_one_ipin_track2pin_map(const t_rr_graph* rr_graph, /* Assign tracks: since we assign 2 track per round, we increment itrack by 2* step */ for (size_t itrack = 0; itrack < actual_track_list.size(); itrack = itrack + 2 * track_step) { /* Update pin2track map */ - size_t ipin_side_index = ipin_side_manager.to_size_t(); + size_t chan_side_index = chan_side_manager.to_size_t(); size_t track_index = actual_track_list[itrack]; size_t ipin_index = ipin_node - rr_graph->rr_node; - (*track2ipin_map)[ipin_side_index][track_index].push_back(ipin_index); - (*track2ipin_map)[ipin_side_index][track_index + 1].push_back(ipin_index); + (*track2ipin_map)[chan_side_index][track_index].push_back(ipin_index); + (*track2ipin_map)[chan_side_index][track_index + 1].push_back(ipin_index); } } @@ -1181,14 +1210,15 @@ t_track2pin_map build_gsb_track_to_ipin_map(t_rr_graph* rr_graph, /* This track2pin mapping is for Connection Blocks, so we only care two sides! */ /* Get channel width and resize the matrix */ size_t chan_width = rr_gsb.get_chan_width(chan_side); - track2ipin_map[side].resize(chan_width); + track2ipin_map[chan_side_manager.to_size_t()].resize(chan_width); /* Find the ipin/opin nodes */ for (size_t inode = 0; inode < rr_gsb.get_num_ipin_nodes(ipin_side); ++inode) { t_rr_node* ipin_node = rr_gsb.get_ipin_node(ipin_side, inode); /* Get Fc of the ipin */ int ipin_Fc = Fc_in[ipin_node->ptc_num]; /* skip Fc = 0 */ - if (0 == ipin_Fc) { + if ( (-1 == ipin_Fc) + || (0 == ipin_Fc) ) { continue; } /* Build track2ipin_map for this IPIN */ @@ -1249,7 +1279,9 @@ t_pin2track_map build_gsb_opin_to_track_map(t_rr_graph* rr_graph, /* Get Fc of the ipin */ int opin_Fc = Fc_out[opin_node->ptc_num]; /* skip Fc = 0 */ - if (0 == opin_Fc) { + printf("opin_Fc[%d]=%d\n", opin_node->ptc_num, opin_Fc); + if ( (-1 == opin_Fc) + || (0 == opin_Fc) ) { continue; } /* Build track2ipin_map for this IPIN */ diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.h b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.h index 8097139b3..439ff5b97 100755 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.h +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.h @@ -31,7 +31,9 @@ RRGSB build_one_tileable_rr_gsb(const DeviceCoordinator& device_range, const DeviceCoordinator& gsb_coordinator, t_rr_graph* rr_graph); -void build_edges_for_one_tileable_rr_gsb(const t_rr_graph* rr_graph, const RRGSB* rr_gsb, +void build_edges_for_one_tileable_rr_gsb(const t_rr_graph* rr_graph, + const std::vector< std::vector > grids, + const RRGSB* rr_gsb, const t_track2pin_map track2ipin_map, const t_pin2track_map opin2track_map, const t_track2track_map track2track_map); diff --git a/vpr7_x2p/vpr/SRC/route/rr_graph.c b/vpr7_x2p/vpr/SRC/route/rr_graph.c index 730d30b96..6a5b557e6 100755 --- a/vpr7_x2p/vpr/SRC/route/rr_graph.c +++ b/vpr7_x2p/vpr/SRC/route/rr_graph.c @@ -692,6 +692,9 @@ alloc_and_load_actual_fc(INP int L_num_types, INP t_type_ptr types, float *Fc = (float *) my_malloc(sizeof(float) * types[i].num_pins); /* [0..num_pins-1] */ for (j = 0; j < types[i].num_pins; ++j) { Fc[j] = types[i].Fc[j]; + + /* Xifan Tang: give an initial value! */ + /* Result[i][j] = 0; */ if(Fc[j] == 0 && ignore_Fc_0 == FALSE) { /* Special case indicating that this pin does not connect to general-purpose routing */ From 7c38b32eb11808dfdea5b846f06e518d7f176dad Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 21 Jun 2019 22:51:11 -0600 Subject: [PATCH 14/25] keep bug fixing for tileable rr_graph generator --- .../rr_graph/rr_graph_tileable_builder.c | 19 ++-- .../device/rr_graph/rr_graph_tileable_gsb.cpp | 88 +++++++++++++++---- .../device/rr_graph/rr_graph_tileable_gsb.h | 6 +- vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.cpp | 4 +- vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.h | 4 +- vpr7_x2p/vpr/SRC/route/rr_graph.c | 2 +- 6 files changed, 86 insertions(+), 37 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c index 061f057ab..55c85765e 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c @@ -1082,29 +1082,24 @@ void build_rr_graph_edges(t_rr_graph* rr_graph, int** Fc_in, int** Fc_out, const enum e_switch_block_type sb_type, const int Fs) { - DeviceCoordinator device_range(device_size.get_x() - 1, device_size.get_y() - 1); + DeviceCoordinator gsb_range(device_size.get_x() - 2, device_size.get_y() - 2); /* Go Switch Block by Switch Block */ - for (size_t ix = 0; ix < device_size.get_x(); ++ix) { - for (size_t iy = 0; iy < device_size.get_y(); ++iy) { + for (size_t ix = 0; ix <= gsb_range.get_x(); ++ix) { + for (size_t iy = 0; iy <= gsb_range.get_y(); ++iy) { + vpr_printf(TIO_MESSAGE_INFO, "Building edges for GSB[%lu][%lu]\n", ix, iy); DeviceCoordinator gsb_coordinator(ix, iy); /* Create a GSB object */ - RRGSB rr_gsb = build_one_tileable_rr_gsb(device_range, device_chan_width, segment_inf, gsb_coordinator, rr_graph); - - DeviceCoordinator grid_coordinator = rr_gsb.get_grid_coordinator(); + RRGSB rr_gsb = build_one_tileable_rr_gsb(gsb_range, device_chan_width, segment_inf, gsb_coordinator, rr_graph); /* adapt the track_to_ipin_lookup for the GSB nodes */ t_track2pin_map track2ipin_map; /* [0..track_gsb_side][0..num_tracks][ipin_indices] */ - /* Get the Fc index of the grid */ - int grid_Fc_in_index = grids[grid_coordinator.get_x()][grid_coordinator.get_y()].type->index; - track2ipin_map = build_gsb_track_to_ipin_map(rr_graph, rr_gsb, segment_inf, Fc_in[grid_Fc_in_index]); + track2ipin_map = build_gsb_track_to_ipin_map(rr_graph, rr_gsb, grids, segment_inf, Fc_in); /* adapt the opin_to_track_map for the GSB nodes */ t_pin2track_map opin2track_map; /* [0..gsb_side][0..num_opin_node][track_indices] */ - /* Get the Fc index of the grid */ - int grid_Fc_out_index = grids[grid_coordinator.get_x()][grid_coordinator.get_y()].type->index; - opin2track_map = build_gsb_opin_to_track_map(rr_graph, rr_gsb, segment_inf, Fc_out[grid_Fc_out_index]); + opin2track_map = build_gsb_opin_to_track_map(rr_graph, rr_gsb, grids, segment_inf, Fc_out); /* adapt the switch_block_conn for the GSB nodes */ t_track2track_map sb_conn; /* [0..from_gsb_side][0..chan_width-1][track_indices] */ diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.cpp b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.cpp index 933b94d05..c20e2d892 100755 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.cpp +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.cpp @@ -44,6 +44,7 @@ #include #include "vpr_types.h" +#include "globals.h" #include "rr_graph_util.h" #include "rr_graph2.h" @@ -200,9 +201,11 @@ std::vector get_to_track_list(const int Fs, const int to_track, const in */ int to_track_i = to_track + i; /* make sure the track id is still in range */ - if ( to_track_i > num_to_tracks) { + if ( to_track_i > num_to_tracks - 1) { to_track_i = to_track_i % num_to_tracks; } + /* Ensure we are in the range */ + assert (to_track_i < num_to_tracks); /* from track must be connected */ to_tracks.push_back(to_track_i); } @@ -368,9 +371,9 @@ void build_gsb_one_group_track_to_track_map(const t_rr_graph* rr_graph, size_t from_side_index = side_manager.to_size_t(); size_t from_track_index = from_tracks[side][inode]; size_t to_track_index = to_tracks[to_side_index][to_track_ids[to_track_id]]; - printf("from_track(size=%lu): %lu , to_track_ids[%lu]:%lu, to_track_index: %lu in a group of %lu tracks\n", - from_tracks[side].size(), inode, to_track_id, to_track_ids[to_track_id], - to_track_index, to_tracks[to_side_index].size()); + //printf("from_track(size=%lu): %lu , to_track_ids[%lu]:%lu, to_track_index: %lu in a group of %lu tracks\n", + // from_tracks[side].size(), inode, to_track_id, to_track_ids[to_track_id], + // to_track_index, to_tracks[to_side_index].size()); t_rr_node* to_track_node = rr_gsb.get_chan_node(to_side, to_track_index); (*track2track_map)[from_side_index][from_track_index].push_back(to_track_node - rr_graph->rr_node); } @@ -526,8 +529,10 @@ RRChan build_one_tileable_rr_chan(const DeviceCoordinator& chan_coordinator, rr_chan.set_type(chan_type); /* Collect rr_nodes for this channel */ - chan_rr_nodes = get_chan_rr_nodes(&chan_width, chan_type, chan_coordinator.get_x(), chan_coordinator.get_y(), - rr_graph->num_rr_nodes, rr_graph->rr_node, rr_graph->rr_node_indices); + chan_rr_nodes = get_chan_rr_nodes(&chan_width, chan_type, + chan_coordinator.get_x(), chan_coordinator.get_y(), + rr_graph->num_rr_nodes, rr_graph->rr_node, + rr_graph->rr_node_indices); /* Reserve */ /* rr_chan.reserve_node(size_t(chan_width)); */ @@ -1066,7 +1071,7 @@ void build_gsb_one_ipin_track2pin_map(const t_rr_graph* rr_graph, assert (0 == actual_track_list.size() % 2); /* Scale Fc */ - int actual_Fc = Fc * (float)(actual_track_list.size() / chan_width); + int actual_Fc = Fc * actual_track_list.size() / chan_width; /* Minimum Fc should be 2 : ensure we will connect to a pair of routing tracks */ actual_Fc = std::max(2, actual_Fc); /* Compute the step between two connection from this IPIN to tracks: @@ -1085,14 +1090,31 @@ void build_gsb_one_ipin_track2pin_map(const t_rr_graph* rr_graph, std::rotate(actual_track_list.begin(), actual_track_list.begin() + actual_offset, actual_track_list.end()); /* Assign tracks: since we assign 2 track per round, we increment itrack by 2* step */ + int track_cnt = 0; for (size_t itrack = 0; itrack < actual_track_list.size(); itrack = itrack + 2 * track_step) { /* Update pin2track map */ size_t chan_side_index = chan_side_manager.to_size_t(); - size_t track_index = actual_track_list[itrack]; size_t ipin_index = ipin_node - rr_graph->rr_node; + /* track_index may exceed the chan_width(), adapt it */ + size_t track_index = actual_track_list[itrack] % chan_width; + (*track2ipin_map)[chan_side_index][track_index].push_back(ipin_index); - (*track2ipin_map)[chan_side_index][track_index + 1].push_back(ipin_index); + + /* track_index may exceed the chan_width(), adapt it */ + track_index = (actual_track_list[itrack] + 1) % chan_width; + + (*track2ipin_map)[chan_side_index][track_index].push_back(ipin_index); + + track_cnt += 2; + /* Stop when we have enough Fc */ + if (actual_Fc == track_cnt) { + break; + } } + + /* Ensure the number of tracks is similar to Fc */ + //printf("Fc_in=%d, track_cnt=%d\n", actual_Fc, track_cnt); + assert (actual_Fc == track_cnt); } return; @@ -1131,8 +1153,11 @@ void build_gsb_one_opin_pin2track_map(const t_rr_graph* rr_graph, std::vector actual_track_list; for (size_t inode = 0; inode < track_list.size(); ++inode) { /* Check if tracks allow connection blocks in the GSB*/ - if ( (false == is_gsb_in_track_sb_population(rr_gsb, chan_side, track_list[inode], segment_inf)) - && (TRACK_START != determine_track_status_of_gsb(rr_gsb, chan_side, track_list[inode])) ) { + if (false == is_gsb_in_track_sb_population(rr_gsb, chan_side, + track_list[inode], segment_inf)) { + continue; /* Bypass condition */ + } + if (TRACK_START != determine_track_status_of_gsb(rr_gsb, chan_side, track_list[inode])) { continue; /* Bypass condition */ } /* Push the node to actual_track_list */ @@ -1140,7 +1165,7 @@ void build_gsb_one_opin_pin2track_map(const t_rr_graph* rr_graph, } /* Scale Fc */ - int actual_Fc = Fc * (float)(actual_track_list.size() / chan_width); + int actual_Fc = Fc * actual_track_list.size() / chan_width; /* Minimum Fc should be 1 : ensure we will drive 1 routing track */ actual_Fc = std::max(1, actual_Fc); /* Compute the step between two connection from this IPIN to tracks: @@ -1156,13 +1181,24 @@ void build_gsb_one_opin_pin2track_map(const t_rr_graph* rr_graph, std::rotate(actual_track_list.begin(), actual_track_list.begin() + actual_offset, actual_track_list.end()); /* Assign tracks */ + int track_cnt = 0; for (size_t itrack = 0; itrack < actual_track_list.size(); itrack = itrack + track_step) { /* Update pin2track map */ size_t opin_side_index = opin_side_manager.to_size_t(); size_t track_index = actual_track_list[itrack]; size_t track_rr_node_index = rr_gsb.get_chan_node(chan_side, track_index) - rr_graph->rr_node; (*opin2track_map)[opin_side_index][opin_node_id].push_back(track_rr_node_index); + /* update track counter */ + track_cnt++; + /* Stop when we have enough Fc */ + if (actual_Fc == track_cnt) { + break; + } } + + /* Ensure the number of tracks is similar to Fc */ + //printf("Fc_out=%lu, scaled_Fc_out=%d, track_cnt=%d, actual_track_cnt=%lu/%lu\n", Fc, actual_Fc, track_cnt, actual_track_list.size(), chan_width); + assert (actual_Fc == track_cnt); } return; @@ -1181,13 +1217,15 @@ void build_gsb_one_opin_pin2track_map(const t_rr_graph* rr_graph, ***********************************************************************/ t_track2pin_map build_gsb_track_to_ipin_map(t_rr_graph* rr_graph, const RRGSB& rr_gsb, + const std::vector> grids, const std::vector segment_inf, - const int* Fc_in) { + int** Fc_in) { t_track2pin_map track2ipin_map; /* Resize the matrix */ track2ipin_map.resize(rr_gsb.get_num_sides()); /* offset counter: it aims to balance the track-to-IPIN for each connection block */ + size_t offset_size = 0; std::vector offset; for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { Side side_manager(side); @@ -1195,9 +1233,11 @@ t_track2pin_map build_gsb_track_to_ipin_map(t_rr_graph* rr_graph, /* Get the chan_side */ enum e_side chan_side = rr_gsb.get_cb_chan_side(ipin_side); Side chan_side_manager(chan_side); - offset.resize(chan_side_manager.to_size_t()); + /* resize offset to the maximum chan_side*/ + offset_size = std::max(offset_size, chan_side_manager.to_size_t() + 1); } /* Initial offset */ + offset.resize(offset_size); offset.assign(offset.size(), 0); /* Walk through each side */ @@ -1214,8 +1254,13 @@ t_track2pin_map build_gsb_track_to_ipin_map(t_rr_graph* rr_graph, /* Find the ipin/opin nodes */ for (size_t inode = 0; inode < rr_gsb.get_num_ipin_nodes(ipin_side); ++inode) { t_rr_node* ipin_node = rr_gsb.get_ipin_node(ipin_side, inode); + /* Skip EMPTY type */ + if (EMPTY_TYPE == grids[ipin_node->xlow][ipin_node->ylow].type) { + continue; + } + int grid_type_index = grids[ipin_node->xlow][ipin_node->ylow].type->index; /* Get Fc of the ipin */ - int ipin_Fc = Fc_in[ipin_node->ptc_num]; + int ipin_Fc = Fc_in[grid_type_index][ipin_node->ptc_num]; /* skip Fc = 0 */ if ( (-1 == ipin_Fc) || (0 == ipin_Fc) ) { @@ -1228,6 +1273,7 @@ t_track2pin_map build_gsb_track_to_ipin_map(t_rr_graph* rr_graph, segment_inf, &track2ipin_map); /* update offset */ offset[chan_side_manager.to_size_t()] += 2; + printf("offset[%lu]=%lu\n", chan_side_manager.to_size_t(), offset[chan_side_manager.to_size_t()]); } } @@ -1248,8 +1294,9 @@ t_track2pin_map build_gsb_track_to_ipin_map(t_rr_graph* rr_graph, ***********************************************************************/ t_pin2track_map build_gsb_opin_to_track_map(t_rr_graph* rr_graph, const RRGSB& rr_gsb, + const std::vector> grids, const std::vector segment_inf, - const int* Fc_out) { + int** Fc_out) { t_pin2track_map opin2track_map; /* Resize the matrix */ opin2track_map.resize(rr_gsb.get_num_sides()); @@ -1276,10 +1323,15 @@ t_pin2track_map build_gsb_opin_to_track_map(t_rr_graph* rr_graph, /* Find the ipin/opin nodes */ for (size_t inode = 0; inode < num_opin_nodes; ++inode) { t_rr_node* opin_node = rr_gsb.get_opin_node(opin_side, inode); + /* Skip EMPTY type */ + if (EMPTY_TYPE == grids[opin_node->xlow][opin_node->ylow].type) { + continue; + } + int grid_type_index = grids[opin_node->xlow][opin_node->ylow].type->index; /* Get Fc of the ipin */ - int opin_Fc = Fc_out[opin_node->ptc_num]; + int opin_Fc = Fc_out[grid_type_index][opin_node->ptc_num]; /* skip Fc = 0 */ - printf("opin_Fc[%d]=%d\n", opin_node->ptc_num, opin_Fc); + //printf("opin_Fc[%d]=%d\n", opin_node->ptc_num, opin_Fc); if ( (-1 == opin_Fc) || (0 == opin_Fc) ) { continue; diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.h b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.h index 439ff5b97..da752d7de 100755 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.h +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.h @@ -40,13 +40,15 @@ void build_edges_for_one_tileable_rr_gsb(const t_rr_graph* rr_graph, t_track2pin_map build_gsb_track_to_ipin_map(t_rr_graph* rr_graph, const RRGSB& rr_gsb, + const std::vector> grids, const std::vector segment_inf, - const int* Fc_in); + int** Fc_in); t_pin2track_map build_gsb_opin_to_track_map(t_rr_graph* rr_graph, const RRGSB& rr_gsb, + const std::vector> grids, const std::vector segment_inf, - const int* Fc_out); + int** Fc_out); void build_direct_connections_for_one_gsb(t_rr_graph* rr_graph, const DeviceCoordinator& device_size, 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 d150b53a6..1232d1fed 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.cpp @@ -1598,7 +1598,7 @@ void RRGSB::add_chan_node(enum e_side node_side, RRChan& rr_chan, std::vector rr_chan_dir); /* 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 add_ipin_node(t_rr_node* node, const enum e_side node_side, const 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, const enum e_side node_side, const 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_sb_num_reserved_conf_bits(size_t num_reserved_conf_bits); void set_sb_conf_bits_lsb(size_t conf_bits_lsb); void set_sb_conf_bits_msb(size_t conf_bits_msb); diff --git a/vpr7_x2p/vpr/SRC/route/rr_graph.c b/vpr7_x2p/vpr/SRC/route/rr_graph.c index 6a5b557e6..a4dfed184 100755 --- a/vpr7_x2p/vpr/SRC/route/rr_graph.c +++ b/vpr7_x2p/vpr/SRC/route/rr_graph.c @@ -694,7 +694,7 @@ alloc_and_load_actual_fc(INP int L_num_types, INP t_type_ptr types, Fc[j] = types[i].Fc[j]; /* Xifan Tang: give an initial value! */ - /* Result[i][j] = 0; */ + Result[i][j] = -1; if(Fc[j] == 0 && ignore_Fc_0 == FALSE) { /* Special case indicating that this pin does not connect to general-purpose routing */ From 2837f44df2c84a6e99d2101663a117455803fa16 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 22 Jun 2019 20:41:06 -0600 Subject: [PATCH 15/25] bug fixing for tileable rr_graph generator. --- .../SRC/device/rr_graph/chan_node_details.cpp | 26 ++-- .../rr_graph/rr_graph_tileable_builder.c | 146 ++++++++++++------ .../device/rr_graph/rr_graph_tileable_gsb.cpp | 2 +- 3 files changed, 117 insertions(+), 57 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/chan_node_details.cpp b/vpr7_x2p/vpr/SRC/device/rr_graph/chan_node_details.cpp index 070d45aa4..a623e0df3 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/chan_node_details.cpp +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/chan_node_details.cpp @@ -121,17 +121,19 @@ std::vector ChanNodeDetails::get_seg_group(size_t track_id) const { group.clear(); for (size_t itrack = track_id; itrack < get_chan_width(); ++itrack) { - if ( (get_track_direction(itrack) == get_track_direction(track_id) ) - && (get_track_segment_length(itrack) == get_track_segment_length(track_id)) ) { - if ( (false == is_track_start(itrack)) - || ( (true == is_track_start(itrack)) && (itrack == track_id)) ) { - group.push_back(itrack); - continue; - } - /* Stop if this another starting point */ - if (true == is_track_start(itrack)) { - break; - } + if ( (get_track_direction(itrack) != get_track_direction(track_id) ) + || (get_track_segment_id(itrack) != get_track_segment_id(track_id)) ) { + /* Bypass any nodes in different direction and segment information*/ + continue; + } + if ( (false == is_track_start(itrack)) + || ( (true == is_track_start(itrack)) && (itrack == track_id)) ) { + group.push_back(itrack); + continue; + } + /* Stop if this another starting point */ + if (true == is_track_start(itrack)) { + break; } } return group; @@ -227,6 +229,7 @@ void ChanNodeDetails::set_tracks_start(e_direction track_direction) { for (size_t inode = 0; inode < get_chan_width(); ++inode) { /* Bypass non-match tracks */ if (track_direction != get_track_direction(inode)) { + continue; /* Pass condition*/ } track_start_[inode] = true; } @@ -237,6 +240,7 @@ void ChanNodeDetails::set_tracks_end(e_direction track_direction) { for (size_t inode = 0; inode < get_chan_width(); ++inode) { /* Bypass non-match tracks */ if (track_direction != get_track_direction(inode)) { + continue; /* Pass condition*/ } track_end_[inode] = true; } diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c index 55c85765e..b0a5de294 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c @@ -753,6 +753,7 @@ void load_one_chan_rr_nodes_basic_info(const DeviceCoordinator& chan_coordinator chan_details->set_track_node_id(itrack, *cur_node_id); /* cost index depends on the segment index */ rr_graph->rr_node[*cur_node_id].cost_index = cost_index_offset + seg_id; + /* Update node counter */ (*cur_node_id)++; /* Finish here, go to next */ @@ -776,6 +777,7 @@ void load_one_chan_rr_nodes_basic_info(const DeviceCoordinator& chan_coordinator rr_graph->rr_node[*cur_node_id].driver_switch = segment_infs[seg_id].opin_switch; /* cost index depends on the segment index */ rr_graph->rr_node[*cur_node_id].cost_index = cost_index_offset + seg_id; + /* Update node counter */ (*cur_node_id)++; /* Finish here, go to next */ @@ -791,7 +793,11 @@ void load_one_chan_rr_nodes_basic_info(const DeviceCoordinator& chan_coordinator /* set xhigh/yhigh and push changes to track_ids */ rr_graph->rr_node[rr_node_id].xhigh = chan_coordinator.get_x(); rr_graph->rr_node[rr_node_id].yhigh = chan_coordinator.get_y(); - rr_graph->rr_node[rr_node_id].track_ids.push_back(itrack); + /* Do not update track_ids for length-1 wires, they should have only 1 track_id */ + if ( (rr_graph->rr_node[rr_node_id].xhigh > rr_graph->rr_node[rr_node_id].xlow) + || (rr_graph->rr_node[rr_node_id].yhigh > rr_graph->rr_node[rr_node_id].ylow) ) { + rr_graph->rr_node[rr_node_id].track_ids.push_back(itrack); + } /* Finish here, go to next */ } /* For DEC direction, an starting point requires an update on xlow and ylow */ @@ -802,23 +808,37 @@ void load_one_chan_rr_nodes_basic_info(const DeviceCoordinator& chan_coordinator /* Do a quick check, make sure we do not mistakenly modify other nodes */ assert(chan_type == rr_graph->rr_node[rr_node_id].type); assert(chan_details->get_track_direction(itrack) == rr_graph->rr_node[rr_node_id].direction); - /* set xhigh/yhigh and push changes to track_ids */ + /* set xlow/ylow and push changes to track_ids */ rr_graph->rr_node[rr_node_id].xlow = chan_coordinator.get_x(); rr_graph->rr_node[rr_node_id].ylow = chan_coordinator.get_y(); - rr_graph->rr_node[rr_node_id].track_ids.push_back(itrack); + /* Do not update track_ids for length-1 wires, they should have only 1 track_id */ + if ( (rr_graph->rr_node[rr_node_id].xhigh > rr_graph->rr_node[rr_node_id].xlow) + || (rr_graph->rr_node[rr_node_id].yhigh > rr_graph->rr_node[rr_node_id].ylow) ) { + rr_graph->rr_node[rr_node_id].track_ids.push_back(itrack); + } /* Finish here, go to next */ } + /* Finish processing starting and ending tracks */ + if ( (true== chan_details->is_track_start(itrack)) + || (true == chan_details->is_track_end(itrack)) ) { + /* Finish here, go to next */ + continue; + } /* For other nodes, we get the node_id and just update track_ids */ - if ( (false == chan_details->is_track_start(itrack)) - && (false == chan_details->is_track_end(itrack)) ) { - /* Get the node_id */ - size_t rr_node_id = chan_details->get_track_node_id(itrack); - /* Do a quick check, make sure we do not mistakenly modify other nodes */ - assert(chan_type == rr_graph->rr_node[rr_node_id].type); - assert(chan_details->get_track_direction(itrack) == rr_graph->rr_node[rr_node_id].direction); - rr_graph->rr_node[rr_node_id].track_ids.push_back(itrack); - /* Finish here, go to next */ - } + /* Ensure those nodes are neither starting nor ending points */ + assert( (false == chan_details->is_track_start(itrack)) + && (false == chan_details->is_track_end(itrack)) ); + /* Get the node_id */ + size_t rr_node_id = chan_details->get_track_node_id(itrack); + /* Do a quick check, make sure we do not mistakenly modify other nodes */ + assert(chan_type == rr_graph->rr_node[rr_node_id].type); + assert(chan_details->get_track_direction(itrack) == rr_graph->rr_node[rr_node_id].direction); + /* Update track_ids */ + rr_graph->rr_node[rr_node_id].track_ids.push_back(itrack); + /* Finish here, go to next */ + } + + for (size_t itrack = 0; itrack < chan_details->get_chan_width(); ++itrack) { /* fill fast look-up table */ /* Get node_id */ int track_node_id = chan_details->get_track_node_id(itrack); @@ -921,23 +941,33 @@ void load_rr_nodes_basic_info(t_rr_graph* rr_graph, ChanNodeDetails chanx_details = build_unidir_chan_node_details(chan_width[0], device_size.get_x() - 2, chan_side, segment_infs); /* Force node_ids from the previous chanx */ if (0 < track_node_ids.size()) { + /* Rotate should be done based on a typical case of routing tracks. + * Tracks on the borders are not regularly started and ended, + * which causes the node_rotation malfunction + */ + ChanNodeDetails chanx_details_tt = build_unidir_chan_node_details(chan_width[0], device_size.get_x() - 2, NUM_SIDES, segment_infs); + chanx_details_tt.set_track_node_ids(track_node_ids); + + /* Rotate the chanx_details by an offset of ix - 1, the distance to the most left channel */ + /* For INC_DIRECTION, we use clockwise rotation + * node_id A ----> -----> node_id D + * node_id B ----> / ----> node_id A + * node_id C ----> / ----> node_id B + * node_id D ----> ----> node_id C + */ + chanx_details_tt.rotate_track_node_id(1, INC_DIRECTION, true); + /* For DEC_DIRECTION, we use clockwise rotation + * node_id A <----- <----- node_id B + * node_id B <----- \ <----- node_id C + * node_id C <----- \ <----- node_id D + * node_id D <----- <----- node_id A + */ + chanx_details_tt.rotate_track_node_id(1, DEC_DIRECTION, false); + + track_node_ids = chanx_details_tt.get_track_node_ids(); chanx_details.set_track_node_ids(track_node_ids); } - /* Rotate the chanx_details by an offset of ix - 1, the distance to the most left channel */ - /* For INC_DIRECTION, we use clockwise rotation - * node_id A ----> -----> node_id D - * node_id B ----> / ----> node_id A - * node_id C ----> / ----> node_id B - * node_id D ----> ----> node_id C - */ - chanx_details.rotate_track_node_id(ix - 1, INC_DIRECTION, false); - /* For DEC_DIRECTION, we use clockwise rotation - * node_id A <----- <----- node_id B - * node_id B <----- \ <----- node_id C - * node_id C <----- \ <----- node_id D - * node_id D <----- <----- node_id A - */ - chanx_details.rotate_track_node_id(ix - 1, DEC_DIRECTION, true); + /* Configure CHANX in this channel */ load_one_chan_rr_nodes_basic_info(chan_coordinator, CHANX, &chanx_details, @@ -958,7 +988,7 @@ void load_rr_nodes_basic_info(t_rr_graph* rr_graph, for (size_t iy = 1; iy < device_size.get_y() - 1; ++iy) { DeviceCoordinator chan_coordinator(ix, iy); enum e_side chan_side = NUM_SIDES; - /* For LEFT side of FPGA */ + /* For BOTTOM side of FPGA */ if (1 == iy) { chan_side = BOTTOM; } @@ -969,23 +999,32 @@ void load_rr_nodes_basic_info(t_rr_graph* rr_graph, ChanNodeDetails chany_details = build_unidir_chan_node_details(chan_width[1], device_size.get_y() - 2, chan_side, segment_infs); /* Force node_ids from the previous chanx */ if (0 < track_node_ids.size()) { + /* Rotate should be done based on a typical case of routing tracks. + * Tracks on the borders are not regularly started and ended, + * which causes the node_rotation malfunction + */ + ChanNodeDetails chany_details_tt = build_unidir_chan_node_details(chan_width[1], device_size.get_y() - 2, NUM_SIDES, segment_infs); + + chany_details_tt.set_track_node_ids(track_node_ids); + /* Rotate the chany_details by an offset of 1*/ + /* For INC_DIRECTION, we use clockwise rotation + * node_id A ----> -----> node_id D + * node_id B ----> / ----> node_id A + * node_id C ----> / ----> node_id B + * node_id D ----> ----> node_id C + */ + chany_details_tt.rotate_track_node_id(1, INC_DIRECTION, true); + /* For DEC_DIRECTION, we use clockwise rotation + * node_id A <----- <----- node_id B + * node_id B <----- \ <----- node_id C + * node_id C <----- \ <----- node_id D + * node_id D <----- <----- node_id A + */ + chany_details_tt.rotate_track_node_id(1, DEC_DIRECTION, false); + + track_node_ids = chany_details_tt.get_track_node_ids(); chany_details.set_track_node_ids(track_node_ids); } - /* Rotate the chany_details by an offset of 1*/ - /* For INC_DIRECTION, we use clockwise rotation - * node_id A ----> -----> node_id D - * node_id B ----> / ----> node_id A - * node_id C ----> / ----> node_id B - * node_id D ----> ----> node_id C - */ - chany_details.rotate_track_node_id(iy - 1, INC_DIRECTION, false); - /* For DEC_DIRECTION, we use clockwise rotation - * node_id A <----- <----- node_id B - * node_id B <----- \ <----- node_id C - * node_id C <----- \ <----- node_id D - * node_id D <----- <----- node_id A - */ - chany_details.rotate_track_node_id(iy - 1, DEC_DIRECTION, true); /* Configure CHANX in this channel */ load_one_chan_rr_nodes_basic_info(chan_coordinator, CHANY, &chany_details, @@ -999,6 +1038,23 @@ void load_rr_nodes_basic_info(t_rr_graph* rr_graph, /* Check */ assert ((int)cur_node_id == rr_graph->num_rr_nodes); + for (int inode = 0; inode < rr_graph->num_rr_nodes; ++inode) { + /* Check: we only support straight wires now. + * CHANY: xlow=xhigh CHANY:ylow=yhigh + */ + if (CHANX == rr_graph->rr_node[inode].type) { + assert (rr_graph->rr_node[inode].ylow == rr_graph->rr_node[inode].yhigh); + } else if (CHANY == rr_graph->rr_node[inode].type) { + assert (rr_graph->rr_node[inode].xlow == rr_graph->rr_node[inode].xhigh); + } else { + assert ( (SOURCE == rr_graph->rr_node[inode].type) + || (SINK == rr_graph->rr_node[inode].type) + || (OPIN == rr_graph->rr_node[inode].type) + || (IPIN == rr_graph->rr_node[inode].type)); + assert (rr_graph->rr_node[inode].xlow == rr_graph->rr_node[inode].xhigh); + assert (rr_graph->rr_node[inode].ylow == rr_graph->rr_node[inode].yhigh); + } + } /* Reverse the track_ids of CHANX and CHANY nodes in DEC_DIRECTION*/ for (int inode = 0; inode < rr_graph->num_rr_nodes; ++inode) { @@ -1087,7 +1143,7 @@ void build_rr_graph_edges(t_rr_graph* rr_graph, /* Go Switch Block by Switch Block */ for (size_t ix = 0; ix <= gsb_range.get_x(); ++ix) { for (size_t iy = 0; iy <= gsb_range.get_y(); ++iy) { - vpr_printf(TIO_MESSAGE_INFO, "Building edges for GSB[%lu][%lu]\n", ix, iy); + //vpr_printf(TIO_MESSAGE_INFO, "Building edges for GSB[%lu][%lu]\n", ix, iy); DeviceCoordinator gsb_coordinator(ix, iy); /* Create a GSB object */ diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.cpp b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.cpp index c20e2d892..79a0590f4 100755 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.cpp +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.cpp @@ -1273,7 +1273,7 @@ t_track2pin_map build_gsb_track_to_ipin_map(t_rr_graph* rr_graph, segment_inf, &track2ipin_map); /* update offset */ offset[chan_side_manager.to_size_t()] += 2; - printf("offset[%lu]=%lu\n", chan_side_manager.to_size_t(), offset[chan_side_manager.to_size_t()]); + //printf("offset[%lu]=%lu\n", chan_side_manager.to_size_t(), offset[chan_side_manager.to_size_t()]); } } From 59df3056689323ac20b910ca50a0482596c46c29 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sun, 23 Jun 2019 16:40:13 -0600 Subject: [PATCH 16/25] bug fixing and reorganize rr_graph builder source files --- vpr7_x2p/vpr/SRC/base/vpr_types.h | 5 + .../rr_graph/rr_graph_builder_utils.cpp | 257 +++++++ .../device/rr_graph/rr_graph_builder_utils.h | 34 + .../tileable_chan_details_builder.cpp | 254 +++++++ .../rr_graph/tileable_chan_details_builder.h | 11 + ...uilder.c => tileable_rr_graph_builder.cpp} | 650 +++++------------- ..._builder.h => tileable_rr_graph_builder.h} | 11 +- ...able_gsb.cpp => tileable_rr_graph_gsb.cpp} | 94 +-- ...tileable_gsb.h => tileable_rr_graph_gsb.h} | 5 +- vpr7_x2p/vpr/SRC/route/check_rr_graph.c | 65 +- vpr7_x2p/vpr/SRC/route/check_rr_graph.h | 16 +- vpr7_x2p/vpr/SRC/route/rr_graph.c | 9 +- 12 files changed, 803 insertions(+), 608 deletions(-) create mode 100644 vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_builder_utils.cpp create mode 100644 vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_builder_utils.h create mode 100644 vpr7_x2p/vpr/SRC/device/rr_graph/tileable_chan_details_builder.cpp create mode 100644 vpr7_x2p/vpr/SRC/device/rr_graph/tileable_chan_details_builder.h rename vpr7_x2p/vpr/SRC/device/rr_graph/{rr_graph_tileable_builder.c => tileable_rr_graph_builder.cpp} (70%) rename vpr7_x2p/vpr/SRC/device/rr_graph/{rr_graph_tileable_builder.h => tileable_rr_graph_builder.h} (70%) rename vpr7_x2p/vpr/SRC/device/rr_graph/{rr_graph_tileable_gsb.cpp => tileable_rr_graph_gsb.cpp} (93%) rename vpr7_x2p/vpr/SRC/device/rr_graph/{rr_graph_tileable_gsb.h => tileable_rr_graph_gsb.h} (95%) diff --git a/vpr7_x2p/vpr/SRC/base/vpr_types.h b/vpr7_x2p/vpr/SRC/base/vpr_types.h index 2e77e5702..02a0d3657 100755 --- a/vpr7_x2p/vpr/SRC/base/vpr_types.h +++ b/vpr7_x2p/vpr/SRC/base/vpr_types.h @@ -36,6 +36,7 @@ #include "arch_types.h" #include #include +#include /******************************************************************************* * Global data types and constants @@ -908,6 +909,10 @@ typedef enum e_rr_type { SOURCE = 0, SINK, IPIN, OPIN, CHANX, CHANY, INTRA_CLUSTER_EDGE, NUM_RR_TYPES } t_rr_type; +constexpr std::array rr_node_typename { { + "SOURCE", "SINK", "IPIN", "OPIN", "CHANX", "CHANY", "INTRA_CLUSTER_EDGE", "NUM_RR_TYPES" +} }; + /* Type of a routing resource node. x-directed channel segment, * * y-directed channel segment, input pin to a clb to pad, output * * from a clb or pad (i.e. output pin of a net) and: * diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_builder_utils.cpp b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_builder_utils.cpp new file mode 100644 index 000000000..58d22aeca --- /dev/null +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_builder_utils.cpp @@ -0,0 +1,257 @@ +/********************************************************** + * MIT License + * + * Copyright (c) 2018 LNIS - The University of Utah + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + ***********************************************************************/ + +/************************************************************************ + * Filename: rr_graph_builder_utils.cpp + * Created by: Xifan Tang + * Change history: + * +-------------------------------------+ + * | Date | Author | Notes + * +-------------------------------------+ + * | 2019/06/23 | Xifan Tang | Created + * +-------------------------------------+ + ***********************************************************************/ +/************************************************************************ + * This file contains most utilized functions for rr_graph builders + ***********************************************************************/ + +#include +#include + +#include +#include + +#include "rr_graph_builder_utils.h" +#include "globals.h" + +/************************************************************************ + * Initialize a rr_node + ************************************************************************/ +void tileable_rr_graph_init_rr_node(t_rr_node* cur_rr_node) { + cur_rr_node->xlow = 0; + cur_rr_node->xhigh = 0; + cur_rr_node->ylow = 0; + cur_rr_node->xhigh = 0; + + cur_rr_node->ptc_num = 0; + cur_rr_node->track_ids.clear(); + + cur_rr_node->cost_index = 0; + cur_rr_node->occ = 0; + cur_rr_node->fan_in = 0; + cur_rr_node->num_edges = 0; + cur_rr_node->type = NUM_RR_TYPES; + cur_rr_node->edges = NULL; + cur_rr_node->switches = NULL; + + cur_rr_node->driver_switch = 0; + cur_rr_node->unbuf_switched = 0; + cur_rr_node->buffered = 0; + cur_rr_node->R = 0.; + cur_rr_node->C = 0.; + + cur_rr_node->direction = BI_DIRECTION; /* Give an invalid value, easy to check errors */ + cur_rr_node->drivers = SINGLE; + cur_rr_node->num_wire_drivers = 0; + cur_rr_node->num_opin_drivers = 0; + + cur_rr_node->num_drive_rr_nodes = 0; + cur_rr_node->drive_rr_nodes = NULL; + cur_rr_node->drive_switches = NULL; + + cur_rr_node->vpack_net_num_changed = FALSE; + cur_rr_node->is_parasitic_net = FALSE; + cur_rr_node->is_in_heap = FALSE; + + cur_rr_node->sb_num_drive_rr_nodes = 0; + cur_rr_node->sb_drive_rr_nodes = NULL; + cur_rr_node->sb_drive_switches = NULL; + + cur_rr_node->pb = NULL; + + cur_rr_node->name_mux = NULL; + cur_rr_node->id_path = -1; + + cur_rr_node->prev_node = -1; + cur_rr_node->prev_edge = -1; + cur_rr_node->net_num = -1; + cur_rr_node->vpack_net_num = -1; + + cur_rr_node->prev_node_in_pack = -1; + cur_rr_node->prev_edge_in_pack = -1; + cur_rr_node->net_num_in_pack = -1; + + cur_rr_node->pb_graph_pin = NULL; + cur_rr_node->tnode = NULL; + + cur_rr_node->pack_intrinsic_cost = 0.; + cur_rr_node->z = 0; + + return; +} + + +/************************************************************************ + * Get the class index of a grid pin + ***********************************************************************/ +int get_grid_pin_class_index(const t_grid_tile& cur_grid, + const int pin_index) { + /* check */ + assert ( pin_index < cur_grid.type->num_pins); + return cur_grid.type->pin_class[pin_index]; +} + +/* Deteremine the side of a io grid */ +enum e_side determine_io_grid_pin_side(const DeviceCoordinator& device_size, + const DeviceCoordinator& grid_coordinator) { + /* TOP side IO of FPGA */ + if (device_size.get_y() == grid_coordinator.get_y()) { + return BOTTOM; /* Such I/O has only Bottom side pins */ + } else if (device_size.get_x() == grid_coordinator.get_x()) { /* RIGHT side IO of FPGA */ + return LEFT; /* Such I/O has only Left side pins */ + } else if (0 == grid_coordinator.get_y()) { /* BOTTOM side IO of FPGA */ + return TOP; /* Such I/O has only Top side pins */ + } else if (0 == grid_coordinator.get_x()) { /* LEFT side IO of FPGA */ + return RIGHT; /* Such I/O has only Right side pins */ + } else { + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d]) I/O Grid is in the center part of FPGA! Currently unsupported!\n", + __FILE__, __LINE__); + exit(1); + } +} + +/************************************************************************ + * Get a list of pin_index for a grid (either OPIN or IPIN) + * For IO_TYPE, only one side will be used, we consider one side of pins + * For others, we consider all the sides + ***********************************************************************/ +std::vector get_grid_side_pins(const t_grid_tile& cur_grid, + const enum e_pin_type pin_type, + const enum e_side pin_side, + const int pin_height) { + std::vector pin_list; + /* Make sure a clear start */ + pin_list.clear(); + + for (int ipin = 0; ipin < cur_grid.type->num_pins; ++ipin) { + int class_id = cur_grid.type->pin_class[ipin]; + if ( (1 == cur_grid.type->pinloc[pin_height][pin_side][ipin]) + && (pin_type == cur_grid.type->class_inf[class_id].type) ) { + pin_list.push_back(ipin); + } + } + return pin_list; +} + +/************************************************************************ + * Get the number of pins for a grid (either OPIN or IPIN) + * For IO_TYPE, only one side will be used, we consider one side of pins + * For others, we consider all the sides + ***********************************************************************/ +size_t get_grid_num_pins(const t_grid_tile& cur_grid, + const enum e_pin_type pin_type, + const enum e_side io_side) { + size_t num_pins = 0; + Side io_side_manager(io_side); + + /* For IO_TYPE sides */ + for (size_t side = 0; side < NUM_SIDES; ++side) { + Side side_manager(side); + /* skip unwanted sides */ + if ( (IO_TYPE == cur_grid.type) + && (side != io_side_manager.to_size_t()) ) { + continue; + } + /* Get pin list */ + for (int height = 0; height < cur_grid.type->height; ++height) { + std::vector pin_list = get_grid_side_pins(cur_grid, pin_type, side_manager.get_side(), height); + num_pins += pin_list.size(); + } + } + + return num_pins; +} + +/************************************************************************ + * Get the number of pins for a grid (either OPIN or IPIN) + * For IO_TYPE, only one side will be used, we consider one side of pins + * For others, we consider all the sides + ***********************************************************************/ +size_t get_grid_num_classes(const t_grid_tile& cur_grid, + const enum e_pin_type pin_type) { + size_t num_classes = 0; + + for (int iclass = 0; iclass < cur_grid.type->num_class; ++iclass) { + /* Bypass unmatched pin_type */ + if (pin_type != cur_grid.type->class_inf[iclass].type) { + continue; + } + num_classes++; + } + + return num_classes; +} + + + +/************************************************************************ + * Add a edge connecting two rr_nodes + * For src rr_node, update the edge list and update switch_id, + * For des rr_node, update the fan_in + ***********************************************************************/ +void add_one_edge_for_two_rr_nodes(const t_rr_graph* rr_graph, + const int src_rr_node_id, + const int des_rr_node_id, + const short switch_id) { + /* Check */ + assert ( (-1 < src_rr_node_id) && (src_rr_node_id < rr_graph->num_rr_nodes) ); + assert ( (-1 < des_rr_node_id) && (des_rr_node_id < rr_graph->num_rr_nodes) ); + + t_rr_node* src_rr_node = &(rr_graph->rr_node[src_rr_node_id]); + t_rr_node* des_rr_node = &(rr_graph->rr_node[des_rr_node_id]); + + /* Allocate edge and switch to src_rr_node */ + src_rr_node->num_edges++; + if (NULL == src_rr_node->edges) { + /* calloc */ + src_rr_node->edges = (int*) my_calloc( src_rr_node->num_edges, sizeof(int) ); + src_rr_node->switches = (short*) my_calloc( src_rr_node->num_edges, sizeof(short) ); + } else { + /* realloc */ + src_rr_node->edges = (int*) my_realloc(src_rr_node->edges, + src_rr_node->num_edges * sizeof(int)); + src_rr_node->switches = (short*) my_realloc(src_rr_node->switches, + src_rr_node->num_edges * sizeof(short)); + } + /* Fill edge and switch info */ + src_rr_node->edges[src_rr_node->num_edges - 1] = des_rr_node_id; + src_rr_node->switches[src_rr_node->num_edges - 1] = switch_id; + + /* Update the des_rr_node */ + des_rr_node->fan_in++; + + return; +} + diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_builder_utils.h b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_builder_utils.h new file mode 100644 index 000000000..fb565e0e3 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_builder_utils.h @@ -0,0 +1,34 @@ +#ifndef RR_GRAPH_BUILDER_UTILS_H +#define RR_GRAPH_BUILDER_UTILS_H + +#include "vpr_types.h" +#include "fpga_x2p_types.h" +#include "device_coordinator.h" + +void tileable_rr_graph_init_rr_node(t_rr_node* cur_rr_node); + +int get_grid_pin_class_index(const t_grid_tile& cur_grid, + const int pin_index); + +enum e_side determine_io_grid_pin_side(const DeviceCoordinator& device_size, + const DeviceCoordinator& grid_coordinator); + +std::vector get_grid_side_pins(const t_grid_tile& cur_grid, + const enum e_pin_type pin_type, + const enum e_side pin_side, + const int pin_height); + +size_t get_grid_num_pins(const t_grid_tile& cur_grid, + const enum e_pin_type pin_type, + const enum e_side io_side); + +size_t get_grid_num_classes(const t_grid_tile& cur_grid, + const enum e_pin_type pin_type); + +void add_one_edge_for_two_rr_nodes(const t_rr_graph* rr_graph, + const int src_rr_node_id, + const int des_rr_node_id, + const short switch_id); + +#endif + diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_chan_details_builder.cpp b/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_chan_details_builder.cpp new file mode 100644 index 000000000..bc52119f0 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_chan_details_builder.cpp @@ -0,0 +1,254 @@ +/********************************************************** + * MIT License + * + * Copyright (c) 2018 LNIS - The University of Utah + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + ***********************************************************************/ + +/************************************************************************ + * Filename: tileable_chan_details_builder.cpp + * Created by: Xifan Tang + * Change history: + * +-------------------------------------+ + * | Date | Author | Notes + * +-------------------------------------+ + * | 2019/06/23 | Xifan Tang | Created + * +-------------------------------------+ + ***********************************************************************/ +/************************************************************************ + * This file contains a builder for the ChanNodeDetails data structure + * Different from VPR rr_graph builders, this builder aims to create a + * highly regular routing channel. Thus, it is called tileable, + * which brings significant advantage in producing large FPGA fabrics. + ***********************************************************************/ + +#include +#include +#include +#include + +#include "tileable_chan_details_builder.h" + +/************************************************************************ + * Generate the number of tracks for each types of routing segments + * w.r.t. the frequency of each of segments and channel width + * Note that if we dertermine the number of tracks per type using + * chan_width * segment_frequency / total_freq may cause + * The total track num may not match the chan_width, + * therefore, we assign tracks one by one until we meet the frequency requirement + * In this way, we can assign the number of tracks with repect to frequency + ***********************************************************************/ +static +std::vector get_num_tracks_per_seg_type(const size_t chan_width, + const std::vector segment_inf, + const bool use_full_seg_groups) { + std::vector result; + std::vector demand; + /* Make sure a clean start */ + result.resize(segment_inf.size()); + demand.resize(segment_inf.size()); + + /* Scale factor so we can divide by any length + * and still use integers */ + /* Get the sum of frequency */ + size_t scale = 1; + size_t freq_sum = 0; + for (size_t iseg = 0; iseg < segment_inf.size(); ++iseg) { + scale *= segment_inf[iseg].length; + freq_sum += segment_inf[iseg].frequency; + } + size_t reduce = scale * freq_sum; + + /* Init assignments to 0 and set the demand values */ + /* Get the fraction of each segment type considering the frequency: + * num_track_per_seg = chan_width * (freq_of_seg / sum_freq) + */ + for (size_t iseg = 0; iseg < segment_inf.size(); ++iseg) { + result[iseg] = 0; + demand[iseg] = scale * chan_width * segment_inf[iseg].frequency; + if (true == use_full_seg_groups) { + demand[iseg] /= segment_inf[iseg].length; + } + } + + /* check if the sum of num_tracks, matches the chan_width */ + /* Keep assigning tracks until we use them up */ + size_t assigned = 0; + size_t size = 0; + size_t imax = 0; + while (assigned < chan_width) { + /* Find current maximum demand */ + double max = 0; + for (size_t iseg = 0; iseg < segment_inf.size(); ++iseg) { + if (demand[iseg] > max) { + imax = iseg; + } + max = std::max(demand[iseg], max); + } + + /* Assign tracks to the type and reduce the types demand */ + size = (use_full_seg_groups ? segment_inf[imax].length : 1); + demand[imax] -= reduce; + result[imax] += size; + assigned += size; + } + + /* Undo last assignment if we were closer to goal without it */ + if ((assigned - chan_width) > (size / 2)) { + result[imax] -= size; + } + + return result; +} + +/************************************************************************ + * Build details of routing tracks in a channel + * The function will + * 1. Assign the segments for each routing channel, + * To be specific, for each routing track, we assign a routing segment. + * The assignment is subject to users' specifications, such as + * a. length of each type of segment + * b. frequency of each type of segment. + * c. routing channel width + * + * 2. The starting point of each segment in the channel will be assigned + * For each segment group with same directionality (tracks have the same length), + * every L track will be a starting point (where L denotes the length of segments) + * In this case, if the number of tracks is not a multiple of L, + * indeed we may have some | Yes | No | + * +---------------------------------------+--------------+ + * | 1 | <--------MUX | Yes | No | + * +---------------------------------------+--------------+ + * | 2 | --------> | No | No | + * +---------------------------------------+--------------+ + * | 3 | <-------- | No | No | + * +---------------------------------------+--------------+ + * | 4 | --------> | No | No | + * +---------------------------------------+--------------+ + * | 5 | <-------- | No | No | + * +---------------------------------------+--------------+ + * | 7 | -------->MUX | No | Yes | + * +---------------------------------------+--------------+ + * | 8 | MUX<-------- | No | Yes | + * +---------------------------------------+--------------+ + * | 9 | MUX--------> | Yes | No | + * +---------------------------------------+--------------+ + * | 10 | <--------MUX | Yes | No | + * +---------------------------------------+--------------+ + * | 11 | -------->MUX | No | Yes | + * +------------------------------------------------------+ + * | 12 | <-------- | No | No | + * +------------------------------------------------------+ + * + * 3. SPECIAL for fringes: TOP|RIGHT|BOTTOM|RIGHT + * if device_side is NUM_SIDES, we assume this channel does not locate on borders + * All segments will start and ends with no exception + * + * 4. IMPORTANT: we should be aware that channel width maybe different + * in X-direction and Y-direction channels!!! + * So we will load segment details for different channels + ***********************************************************************/ +ChanNodeDetails build_unidir_chan_node_details(const size_t chan_width, const size_t max_seg_length, + const enum e_side device_side, + const std::vector segment_inf) { + ChanNodeDetails chan_node_details; + size_t actual_chan_width = chan_width; + /* Correct the chan_width: it should be an even number */ + if (0 != actual_chan_width % 2) { + actual_chan_width++; /* increment it to be even */ + } + assert (0 == actual_chan_width % 2); + + /* Reserve channel width */ + chan_node_details.reserve(chan_width); + /* Return if zero width is forced */ + if (0 == actual_chan_width) { + return chan_node_details; + } + + /* Find the number of segments required by each group */ + std::vector num_tracks = get_num_tracks_per_seg_type(actual_chan_width/2, segment_inf, TRUE); + + /* Add node to ChanNodeDetails */ + size_t cur_track = 0; + for (size_t iseg = 0; iseg < segment_inf.size(); ++iseg) { + /* segment length will be set to maxium segment length if this is a longwire */ + size_t seg_len = segment_inf[iseg].length; + if (TRUE == segment_inf[iseg].longline) { + seg_len = max_seg_length; + } + for (size_t itrack = 0; itrack < num_tracks[iseg]; ++itrack) { + bool seg_start = false; + bool seg_end = false; + /* Every first track of a group of Length-N wires, we set a starting point */ + if (0 == itrack % seg_len) { + seg_start = true; + } + /* Every last track of a group of Length-N wires, we set an ending point */ + if (seg_len - 1 == itrack % seg_len) { + seg_end = true; + } + /* Since this is a unidirectional routing architecture, + * Add a pair of tracks, 1 INC_DIRECTION track and 1 DEC_DIRECTION track + */ + chan_node_details.add_track(cur_track, INC_DIRECTION, iseg, seg_len, seg_start, seg_end); + cur_track++; + chan_node_details.add_track(cur_track, DEC_DIRECTION, iseg, seg_len, seg_start, seg_end); + cur_track++; + } + } + /* Check if all the tracks have been satisified */ + assert (cur_track == actual_chan_width); + + /* If this is on the border of a device, segments should start */ + switch (device_side) { + case TOP: + case RIGHT: + /* INC_DIRECTION should all end */ + chan_node_details.set_tracks_end(INC_DIRECTION); + /* DEC_DIRECTION should all start */ + chan_node_details.set_tracks_start(DEC_DIRECTION); + break; + case BOTTOM: + case LEFT: + /* INC_DIRECTION should all start */ + chan_node_details.set_tracks_start(INC_DIRECTION); + /* DEC_DIRECTION should all end */ + chan_node_details.set_tracks_end(DEC_DIRECTION); + break; + case NUM_SIDES: + break; + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d]) Invalid device_side!\n", + __FILE__, __LINE__); + exit(1); + } + + return chan_node_details; +} + diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_chan_details_builder.h b/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_chan_details_builder.h new file mode 100644 index 000000000..3031d3ef3 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_chan_details_builder.h @@ -0,0 +1,11 @@ +#ifndef TILEABLE_CHAN_DETAILS_BUILDER_H +#define TILEABLE_CHAN_DETAILS_BUILDER_H + +#include "vpr_types.h" +#include "chan_node_details.h" + +ChanNodeDetails build_unidir_chan_node_details(const size_t chan_width, const size_t max_seg_length, + const enum e_side device_side, + const std::vector segment_inf); + +#endif diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c b/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_builder.cpp similarity index 70% rename from vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c rename to vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_builder.cpp index b0a5de294..bdcff462b 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.c +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_builder.cpp @@ -23,7 +23,7 @@ ***********************************************************************/ /************************************************************************ - * Filename: rr_graph_tileable_builder.c + * Filename: rr_graph_tileable_builder.cpp * Created by: Xifan Tang * Change history: * +-------------------------------------+ @@ -59,12 +59,15 @@ #include "check_rr_graph.h" #include "route_common.h" #include "fpga_x2p_types.h" -#include "rr_graph_tileable_builder.h" #include "rr_blocks.h" #include "chan_node_details.h" #include "device_coordinator.h" -#include "rr_graph_tileable_gsb.h" + +#include "rr_graph_builder_utils.h" +#include "tileable_chan_details_builder.h" +#include "tileable_rr_graph_gsb.h" +#include "tileable_rr_graph_builder.h" /************************************************************************ * Local data stuctures in the file @@ -74,379 +77,6 @@ * Local function in the file ***********************************************************************/ -/************************************************************************ - * Initialize a rr_node - ************************************************************************/ -static -void tileable_rr_graph_init_rr_node(t_rr_node* cur_rr_node) { - cur_rr_node->xlow = 0; - cur_rr_node->xhigh = 0; - cur_rr_node->ylow = 0; - cur_rr_node->xhigh = 0; - - cur_rr_node->ptc_num = 0; - cur_rr_node->track_ids.clear(); - - cur_rr_node->cost_index = 0; - cur_rr_node->occ = 0; - cur_rr_node->fan_in = 0; - cur_rr_node->num_edges = 0; - cur_rr_node->type = NUM_RR_TYPES; - cur_rr_node->edges = NULL; - cur_rr_node->switches = NULL; - - cur_rr_node->driver_switch = 0; - cur_rr_node->unbuf_switched = 0; - cur_rr_node->buffered = 0; - cur_rr_node->R = 0.; - cur_rr_node->C = 0.; - - cur_rr_node->direction = BI_DIRECTION; /* Give an invalid value, easy to check errors */ - cur_rr_node->drivers = SINGLE; - cur_rr_node->num_wire_drivers = 0; - cur_rr_node->num_opin_drivers = 0; - - cur_rr_node->num_drive_rr_nodes = 0; - cur_rr_node->drive_rr_nodes = NULL; - cur_rr_node->drive_switches = NULL; - - cur_rr_node->vpack_net_num_changed = FALSE; - cur_rr_node->is_parasitic_net = FALSE; - cur_rr_node->is_in_heap = FALSE; - - cur_rr_node->sb_num_drive_rr_nodes = 0; - cur_rr_node->sb_drive_rr_nodes = NULL; - cur_rr_node->sb_drive_switches = NULL; - - cur_rr_node->pb = NULL; - - cur_rr_node->name_mux = NULL; - cur_rr_node->id_path = -1; - - cur_rr_node->prev_node = -1; - cur_rr_node->prev_edge = -1; - cur_rr_node->net_num = -1; - cur_rr_node->vpack_net_num = -1; - - cur_rr_node->prev_node_in_pack = -1; - cur_rr_node->prev_edge_in_pack = -1; - cur_rr_node->net_num_in_pack = -1; - - cur_rr_node->pb_graph_pin = NULL; - cur_rr_node->tnode = NULL; - - cur_rr_node->pack_intrinsic_cost = 0.; - cur_rr_node->z = 0; - - return; -} - -/************************************************************************ - * Generate the number of tracks for each types of routing segments - * w.r.t. the frequency of each of segments and channel width - * Note that if we dertermine the number of tracks per type using - * chan_width * segment_frequency / total_freq may cause - * The total track num may not match the chan_width, - * therefore, we assign tracks one by one until we meet the frequency requirement - * In this way, we can assign the number of tracks with repect to frequency - ***********************************************************************/ -static -std::vector get_num_tracks_per_seg_type(const size_t chan_width, - const std::vector segment_inf, - const bool use_full_seg_groups) { - std::vector result; - std::vector demand; - /* Make sure a clean start */ - result.resize(segment_inf.size()); - demand.resize(segment_inf.size()); - - /* Scale factor so we can divide by any length - * and still use integers */ - /* Get the sum of frequency */ - size_t scale = 1; - size_t freq_sum = 0; - for (size_t iseg = 0; iseg < segment_inf.size(); ++iseg) { - scale *= segment_inf[iseg].length; - freq_sum += segment_inf[iseg].frequency; - } - size_t reduce = scale * freq_sum; - - /* Init assignments to 0 and set the demand values */ - /* Get the fraction of each segment type considering the frequency: - * num_track_per_seg = chan_width * (freq_of_seg / sum_freq) - */ - for (size_t iseg = 0; iseg < segment_inf.size(); ++iseg) { - result[iseg] = 0; - demand[iseg] = scale * chan_width * segment_inf[iseg].frequency; - if (true == use_full_seg_groups) { - demand[iseg] /= segment_inf[iseg].length; - } - } - - /* check if the sum of num_tracks, matches the chan_width */ - /* Keep assigning tracks until we use them up */ - size_t assigned = 0; - size_t size = 0; - size_t imax = 0; - while (assigned < chan_width) { - /* Find current maximum demand */ - double max = 0; - for (size_t iseg = 0; iseg < segment_inf.size(); ++iseg) { - if (demand[iseg] > max) { - imax = iseg; - } - max = std::max(demand[iseg], max); - } - - /* Assign tracks to the type and reduce the types demand */ - size = (use_full_seg_groups ? segment_inf[imax].length : 1); - demand[imax] -= reduce; - result[imax] += size; - assigned += size; - } - - /* Undo last assignment if we were closer to goal without it */ - if ((assigned - chan_width) > (size / 2)) { - result[imax] -= size; - } - - return result; -} - -/************************************************************************ - * Build details of routing tracks in a channel - * The function will - * 1. Assign the segments for each routing channel, - * To be specific, for each routing track, we assign a routing segment. - * The assignment is subject to users' specifications, such as - * a. length of each type of segment - * b. frequency of each type of segment. - * c. routing channel width - * - * 2. The starting point of each segment in the channel will be assigned - * For each segment group with same directionality (tracks have the same length), - * every L track will be a starting point (where L denotes the length of segments) - * In this case, if the number of tracks is not a multiple of L, - * indeed we may have some | Yes | No | - * +---------------------------------------+--------------+ - * | 1 | <--------MUX | Yes | No | - * +---------------------------------------+--------------+ - * | 2 | --------> | No | No | - * +---------------------------------------+--------------+ - * | 3 | <-------- | No | No | - * +---------------------------------------+--------------+ - * | 4 | --------> | No | No | - * +---------------------------------------+--------------+ - * | 5 | <-------- | No | No | - * +---------------------------------------+--------------+ - * | 7 | -------->MUX | No | Yes | - * +---------------------------------------+--------------+ - * | 8 | MUX<-------- | No | Yes | - * +---------------------------------------+--------------+ - * | 9 | MUX--------> | Yes | No | - * +---------------------------------------+--------------+ - * | 10 | <--------MUX | Yes | No | - * +---------------------------------------+--------------+ - * | 11 | -------->MUX | No | Yes | - * +------------------------------------------------------+ - * | 12 | <-------- | No | No | - * +------------------------------------------------------+ - * - * 3. SPECIAL for fringes: TOP|RIGHT|BOTTOM|RIGHT - * if device_side is NUM_SIDES, we assume this channel does not locate on borders - * All segments will start and ends with no exception - * - * 4. IMPORTANT: we should be aware that channel width maybe different - * in X-direction and Y-direction channels!!! - * So we will load segment details for different channels - ***********************************************************************/ -ChanNodeDetails build_unidir_chan_node_details(const size_t chan_width, const size_t max_seg_length, - const enum e_side device_side, - const std::vector segment_inf) { - ChanNodeDetails chan_node_details; - size_t actual_chan_width = chan_width; - /* Correct the chan_width: it should be an even number */ - if (0 != actual_chan_width % 2) { - actual_chan_width++; /* increment it to be even */ - } - assert (0 == actual_chan_width % 2); - - /* Reserve channel width */ - chan_node_details.reserve(chan_width); - /* Return if zero width is forced */ - if (0 == actual_chan_width) { - return chan_node_details; - } - - /* Find the number of segments required by each group */ - std::vector num_tracks = get_num_tracks_per_seg_type(actual_chan_width/2, segment_inf, TRUE); - - /* Add node to ChanNodeDetails */ - size_t cur_track = 0; - for (size_t iseg = 0; iseg < segment_inf.size(); ++iseg) { - /* segment length will be set to maxium segment length if this is a longwire */ - size_t seg_len = segment_inf[iseg].length; - if (TRUE == segment_inf[iseg].longline) { - seg_len = max_seg_length; - } - for (size_t itrack = 0; itrack < num_tracks[iseg]; ++itrack) { - bool seg_start = false; - bool seg_end = false; - /* Every first track of a group of Length-N wires, we set a starting point */ - if (0 == itrack % seg_len) { - seg_start = true; - } - /* Every last track of a group of Length-N wires, we set an ending point */ - if (seg_len - 1 == itrack % seg_len) { - seg_end = true; - } - /* Since this is a unidirectional routing architecture, - * Add a pair of tracks, 1 INC_DIRECTION track and 1 DEC_DIRECTION track - */ - chan_node_details.add_track(cur_track, INC_DIRECTION, iseg, seg_len, seg_start, seg_end); - cur_track++; - chan_node_details.add_track(cur_track, DEC_DIRECTION, iseg, seg_len, seg_start, seg_end); - cur_track++; - } - } - /* Check if all the tracks have been satisified */ - assert (cur_track == actual_chan_width); - - /* If this is on the border of a device, segments should start */ - switch (device_side) { - case TOP: - case RIGHT: - /* INC_DIRECTION should all end */ - chan_node_details.set_tracks_end(INC_DIRECTION); - /* DEC_DIRECTION should all start */ - chan_node_details.set_tracks_start(DEC_DIRECTION); - break; - case BOTTOM: - case LEFT: - /* INC_DIRECTION should all start */ - chan_node_details.set_tracks_start(INC_DIRECTION); - /* DEC_DIRECTION should all end */ - chan_node_details.set_tracks_end(DEC_DIRECTION); - break; - case NUM_SIDES: - break; - default: - vpr_printf(TIO_MESSAGE_ERROR, - "(File:%s, [LINE%d]) Invalid device_side!\n", - __FILE__, __LINE__); - exit(1); - } - - return chan_node_details; -} - -/* Deteremine the side of a io grid */ -static -enum e_side determine_io_grid_pin_side(const DeviceCoordinator& device_size, - const DeviceCoordinator& grid_coordinator) { - /* TOP side IO of FPGA */ - if (device_size.get_y() == grid_coordinator.get_y()) { - return BOTTOM; /* Such I/O has only Bottom side pins */ - } else if (device_size.get_x() == grid_coordinator.get_x()) { /* RIGHT side IO of FPGA */ - return LEFT; /* Such I/O has only Left side pins */ - } else if (0 == grid_coordinator.get_y()) { /* BOTTOM side IO of FPGA */ - return TOP; /* Such I/O has only Top side pins */ - } else if (0 == grid_coordinator.get_x()) { /* LEFT side IO of FPGA */ - return RIGHT; /* Such I/O has only Right side pins */ - } else { - vpr_printf(TIO_MESSAGE_ERROR, - "(File:%s, [LINE%d]) I/O Grid is in the center part of FPGA! Currently unsupported!\n", - __FILE__, __LINE__); - exit(1); - } -} - -/************************************************************************ - * Get a list of pin_index for a grid (either OPIN or IPIN) - * For IO_TYPE, only one side will be used, we consider one side of pins - * For others, we consider all the sides - ***********************************************************************/ -static -std::vector get_grid_side_pins(const t_grid_tile& cur_grid, - const enum e_pin_type pin_type, - const enum e_side pin_side, - const int pin_height) { - std::vector pin_list; - /* Make sure a clear start */ - pin_list.clear(); - - for (int ipin = 0; ipin < cur_grid.type->num_pins; ++ipin) { - int class_id = cur_grid.type->pin_class[ipin]; - if ( (1 == cur_grid.type->pinloc[pin_height][pin_side][ipin]) - && (pin_type == cur_grid.type->class_inf[class_id].type) ) { - pin_list.push_back(ipin); - } - } - return pin_list; -} - -/************************************************************************ - * Get the number of pins for a grid (either OPIN or IPIN) - * For IO_TYPE, only one side will be used, we consider one side of pins - * For others, we consider all the sides - ***********************************************************************/ -static -size_t get_grid_num_pins(const t_grid_tile& cur_grid, const enum e_pin_type pin_type, const enum e_side io_side) { - size_t num_pins = 0; - Side io_side_manager(io_side); - - /* Consider capacity of the grid */ - for (int iblk = 0; iblk < cur_grid.type->capacity; ++iblk) { - /* For IO_TYPE sides */ - for (size_t side = 0; side < NUM_SIDES; ++side) { - Side side_manager(side); - /* skip unwanted sides */ - if ( (IO_TYPE == cur_grid.type) - && (side != io_side_manager.to_size_t()) ) { - continue; - } - /* Get pin list */ - for (int height = 0; height < cur_grid.type->height; ++height) { - std::vector pin_list = get_grid_side_pins(cur_grid, pin_type, side_manager.get_side(), height); - num_pins += pin_list.size(); - } - } - } - - return num_pins; -} - -/************************************************************************ - * Get the number of pins for a grid (either OPIN or IPIN) - * For IO_TYPE, only one side will be used, we consider one side of pins - * For others, we consider all the sides - ***********************************************************************/ -static -size_t get_grid_num_classes(const t_grid_tile& cur_grid, const enum e_pin_type pin_type) { - size_t num_classes = 0; - - /* Consider capacity of the grid */ - for (int iblk = 0; iblk < cur_grid.type->capacity; ++iblk) { - for (int iclass = 0; iclass < cur_grid.type->num_class; ++iclass) { - /* Bypass unmatched pin_type */ - if (pin_type != cur_grid.type->class_inf[iclass].type) { - continue; - } - num_classes++; - } - } - - return num_classes; -} - - /************************************************************************ * Estimate the number of rr_nodes per category: * CHANX, CHANY, IPIN, OPIN, SOURCE, SINK @@ -600,106 +230,34 @@ void load_one_grid_rr_nodes_basic_info(const DeviceCoordinator& grid_coordinator const int wire_to_ipin_switch, const int delayless_switch) { Side io_side_manager(io_side); - /* Consider capacity of the grid */ - for (int iblk = 0; iblk < cur_grid.type->capacity; ++iblk) { - /* Walk through the height of each grid, - * get pins and configure the rr_nodes */ - for (int height = 0; height < cur_grid.type->height; ++height) { - /* Walk through sides */ - for (size_t side = 0; side < NUM_SIDES; ++side) { - Side side_manager(side); - /* skip unwanted sides */ - if ( (IO_TYPE == cur_grid.type) - && (side != io_side_manager.to_size_t()) ) { - continue; - } - /* Find OPINs */ - /* Configure pins by pins */ - std::vector opin_list = get_grid_side_pins(cur_grid, DRIVER, side_manager.get_side(), height); - for (size_t pin = 0; pin < opin_list.size(); ++pin) { - /* Configure the rr_node for the OPIN */ - rr_graph->rr_node[*cur_node_id].type = OPIN; - rr_graph->rr_node[*cur_node_id].xlow = grid_coordinator.get_x(); - rr_graph->rr_node[*cur_node_id].xhigh = grid_coordinator.get_x(); - rr_graph->rr_node[*cur_node_id].ylow = grid_coordinator.get_y(); - rr_graph->rr_node[*cur_node_id].yhigh = grid_coordinator.get_y(); - rr_graph->rr_node[*cur_node_id].ptc_num = opin_list[pin]; - rr_graph->rr_node[*cur_node_id].capacity = 1; - rr_graph->rr_node[*cur_node_id].occ = 0; - /* cost index is a FIXED value for OPIN */ - rr_graph->rr_node[*cur_node_id].cost_index = OPIN_COST_INDEX; - /* Switch info */ - rr_graph->rr_node[*cur_node_id].driver_switch = delayless_switch; - /* fill fast look-up table */ - load_one_node_to_rr_graph_fast_lookup(rr_graph, *cur_node_id, - rr_graph->rr_node[*cur_node_id].type, - rr_graph->rr_node[*cur_node_id].xlow, - rr_graph->rr_node[*cur_node_id].ylow, - rr_graph->rr_node[*cur_node_id].ptc_num); - /* Update node counter */ - (*cur_node_id)++; - } /* End of loading OPIN rr_nodes */ - /* Find IPINs */ - /* Configure pins by pins */ - std::vector ipin_list = get_grid_side_pins(cur_grid, RECEIVER, side_manager.get_side(), height); - for (size_t pin = 0; pin < ipin_list.size(); ++pin) { - rr_graph->rr_node[*cur_node_id].type = IPIN; - rr_graph->rr_node[*cur_node_id].xlow = grid_coordinator.get_x(); - rr_graph->rr_node[*cur_node_id].xhigh = grid_coordinator.get_x(); - rr_graph->rr_node[*cur_node_id].ylow = grid_coordinator.get_y(); - rr_graph->rr_node[*cur_node_id].yhigh = grid_coordinator.get_y(); - rr_graph->rr_node[*cur_node_id].ptc_num = ipin_list[pin]; - rr_graph->rr_node[*cur_node_id].capacity = 1; - rr_graph->rr_node[*cur_node_id].occ = 0; - /* cost index is a FIXED value for IPIN */ - rr_graph->rr_node[*cur_node_id].cost_index = IPIN_COST_INDEX; - /* Switch info */ - rr_graph->rr_node[*cur_node_id].driver_switch = wire_to_ipin_switch; - /* fill fast look-up table */ - load_one_node_to_rr_graph_fast_lookup(rr_graph, *cur_node_id, - rr_graph->rr_node[*cur_node_id].type, - rr_graph->rr_node[*cur_node_id].xlow, - rr_graph->rr_node[*cur_node_id].ylow, - rr_graph->rr_node[*cur_node_id].ptc_num); - /* Update node counter */ - (*cur_node_id)++; - } /* End of loading IPIN rr_nodes */ - } /* End of side enumeration */ - } /* End of height enumeration */ - } /* End of capacity enumeration */ - - /* Consider capacity of the grid */ - for (int iblk = 0; iblk < cur_grid.type->capacity; ++iblk) { - /* Walk through the height of each grid, - * get pins and configure the rr_nodes */ - for (int height = 0; height < cur_grid.type->height; ++height) { - /* Set a SOURCE or a SINK rr_node for each class */ - for (int iclass = 0; iclass < cur_grid.type->num_class; ++iclass) { - /* Set a SINK rr_node for the OPIN */ - if ( DRIVER == cur_grid.type->class_inf[iclass].type) { - rr_graph->rr_node[*cur_node_id].type = SOURCE; - } - if ( RECEIVER == cur_grid.type->class_inf[iclass].type) { - rr_graph->rr_node[*cur_node_id].type = SINK; - } + /* Walk through the height of each grid, + * get pins and configure the rr_nodes */ + for (int height = 0; height < cur_grid.type->height; ++height) { + /* Walk through sides */ + for (size_t side = 0; side < NUM_SIDES; ++side) { + Side side_manager(side); + /* skip unwanted sides */ + if ( (IO_TYPE == cur_grid.type) + && (side != io_side_manager.to_size_t()) ) { + continue; + } + /* Find OPINs */ + /* Configure pins by pins */ + std::vector opin_list = get_grid_side_pins(cur_grid, DRIVER, side_manager.get_side(), height); + for (size_t pin = 0; pin < opin_list.size(); ++pin) { + /* Configure the rr_node for the OPIN */ + rr_graph->rr_node[*cur_node_id].type = OPIN; rr_graph->rr_node[*cur_node_id].xlow = grid_coordinator.get_x(); rr_graph->rr_node[*cur_node_id].xhigh = grid_coordinator.get_x(); rr_graph->rr_node[*cur_node_id].ylow = grid_coordinator.get_y(); rr_graph->rr_node[*cur_node_id].yhigh = grid_coordinator.get_y(); - rr_graph->rr_node[*cur_node_id].ptc_num = iclass; - /* FIXME: need to confirm if the capacity should be the number of pins in this class*/ - rr_graph->rr_node[*cur_node_id].capacity = cur_grid.type->class_inf[iclass].num_pins; + rr_graph->rr_node[*cur_node_id].ptc_num = opin_list[pin]; + rr_graph->rr_node[*cur_node_id].capacity = 1; rr_graph->rr_node[*cur_node_id].occ = 0; - /* cost index is a FIXED value for SOURCE and SINK */ - if (SOURCE == rr_graph->rr_node[*cur_node_id].type) { - rr_graph->rr_node[*cur_node_id].cost_index = SOURCE_COST_INDEX; - } - if (SINK == rr_graph->rr_node[*cur_node_id].type) { - rr_graph->rr_node[*cur_node_id].cost_index = SINK_COST_INDEX; - } + /* cost index is a FIXED value for OPIN */ + rr_graph->rr_node[*cur_node_id].cost_index = OPIN_COST_INDEX; /* Switch info */ rr_graph->rr_node[*cur_node_id].driver_switch = delayless_switch; - /* TODO: should we set pb_graph_pin here? */ /* fill fast look-up table */ load_one_node_to_rr_graph_fast_lookup(rr_graph, *cur_node_id, rr_graph->rr_node[*cur_node_id].type, @@ -708,9 +266,75 @@ void load_one_grid_rr_nodes_basic_info(const DeviceCoordinator& grid_coordinator rr_graph->rr_node[*cur_node_id].ptc_num); /* Update node counter */ (*cur_node_id)++; + } /* End of loading OPIN rr_nodes */ + /* Find IPINs */ + /* Configure pins by pins */ + std::vector ipin_list = get_grid_side_pins(cur_grid, RECEIVER, side_manager.get_side(), height); + for (size_t pin = 0; pin < ipin_list.size(); ++pin) { + rr_graph->rr_node[*cur_node_id].type = IPIN; + rr_graph->rr_node[*cur_node_id].xlow = grid_coordinator.get_x(); + rr_graph->rr_node[*cur_node_id].xhigh = grid_coordinator.get_x(); + rr_graph->rr_node[*cur_node_id].ylow = grid_coordinator.get_y(); + rr_graph->rr_node[*cur_node_id].yhigh = grid_coordinator.get_y(); + rr_graph->rr_node[*cur_node_id].ptc_num = ipin_list[pin]; + rr_graph->rr_node[*cur_node_id].capacity = 1; + rr_graph->rr_node[*cur_node_id].occ = 0; + /* cost index is a FIXED value for IPIN */ + rr_graph->rr_node[*cur_node_id].cost_index = IPIN_COST_INDEX; + /* Switch info */ + rr_graph->rr_node[*cur_node_id].driver_switch = wire_to_ipin_switch; + /* fill fast look-up table */ + load_one_node_to_rr_graph_fast_lookup(rr_graph, *cur_node_id, + rr_graph->rr_node[*cur_node_id].type, + rr_graph->rr_node[*cur_node_id].xlow, + rr_graph->rr_node[*cur_node_id].ylow, + rr_graph->rr_node[*cur_node_id].ptc_num); + /* Update node counter */ + (*cur_node_id)++; + } /* End of loading IPIN rr_nodes */ + } /* End of side enumeration */ + } /* End of height enumeration */ + + /* Walk through the height of each grid, + * get pins and configure the rr_nodes */ + for (int height = 0; height < cur_grid.type->height; ++height) { + /* Set a SOURCE or a SINK rr_node for each class */ + for (int iclass = 0; iclass < cur_grid.type->num_class; ++iclass) { + /* Set a SINK rr_node for the OPIN */ + if ( DRIVER == cur_grid.type->class_inf[iclass].type) { + rr_graph->rr_node[*cur_node_id].type = SOURCE; + } + if ( RECEIVER == cur_grid.type->class_inf[iclass].type) { + rr_graph->rr_node[*cur_node_id].type = SINK; } - } - } + rr_graph->rr_node[*cur_node_id].xlow = grid_coordinator.get_x(); + rr_graph->rr_node[*cur_node_id].xhigh = grid_coordinator.get_x(); + rr_graph->rr_node[*cur_node_id].ylow = grid_coordinator.get_y(); + rr_graph->rr_node[*cur_node_id].yhigh = grid_coordinator.get_y(); + rr_graph->rr_node[*cur_node_id].ptc_num = iclass; + /* FIXME: need to confirm if the capacity should be the number of pins in this class*/ + rr_graph->rr_node[*cur_node_id].capacity = cur_grid.type->class_inf[iclass].num_pins; + rr_graph->rr_node[*cur_node_id].occ = 0; + /* cost index is a FIXED value for SOURCE and SINK */ + if (SOURCE == rr_graph->rr_node[*cur_node_id].type) { + rr_graph->rr_node[*cur_node_id].cost_index = SOURCE_COST_INDEX; + } + if (SINK == rr_graph->rr_node[*cur_node_id].type) { + rr_graph->rr_node[*cur_node_id].cost_index = SINK_COST_INDEX; + } + /* Switch info */ + rr_graph->rr_node[*cur_node_id].driver_switch = delayless_switch; + /* TODO: should we set pb_graph_pin here? */ + /* fill fast look-up table */ + load_one_node_to_rr_graph_fast_lookup(rr_graph, *cur_node_id, + rr_graph->rr_node[*cur_node_id].type, + rr_graph->rr_node[*cur_node_id].xlow, + rr_graph->rr_node[*cur_node_id].ylow, + rr_graph->rr_node[*cur_node_id].ptc_num); + /* Update node counter */ + (*cur_node_id)++; + } /* End of height enumeration */ + } /* End of pin_class enumeration */ return; } @@ -1117,17 +741,72 @@ void alloc_rr_graph_fast_lookup(const DeviceCoordinator& device_size, return; } +/************************************************************************ + * Build the edges for all the SOURCE and SINKs nodes: + * 1. create edges between SOURCE and OPINs + ***********************************************************************/ +static +void build_rr_graph_edges_for_source_nodes(t_rr_graph* rr_graph, + const std::vector< std::vector > grids) { + for (int inode = 0; inode < rr_graph->num_rr_nodes; ++inode) { + /* Bypass all the non OPIN nodes */ + if (OPIN != rr_graph->rr_node[inode].type) { + continue; + } + /* Now, we have an OPIN node, we get the source node index */ + int xlow = rr_graph->rr_node[inode].xlow; + int ylow = rr_graph->rr_node[inode].ylow; + int src_node_ptc_num = get_grid_pin_class_index(grids[xlow][ylow], + rr_graph->rr_node[inode].ptc_num); + /* 1. create edges between SOURCE and OPINs */ + int src_node_id = get_rr_node_index(xlow, ylow, + SOURCE, src_node_ptc_num, + rr_graph->rr_node_indices); + /* add edges to the src_node */ + add_one_edge_for_two_rr_nodes(rr_graph, src_node_id, inode, + rr_graph->rr_node[inode].driver_switch); + } + return; +} + +/************************************************************************ + * Build the edges for all the SINKs nodes: + * 1. create edges between IPINs and SINKs + ***********************************************************************/ +static +void build_rr_graph_edges_for_sink_nodes(t_rr_graph* rr_graph, + const std::vector< std::vector > grids) { + for (int inode = 0; inode < rr_graph->num_rr_nodes; ++inode) { + /* Bypass all the non IPIN nodes */ + if (IPIN != rr_graph->rr_node[inode].type) { + continue; + } + /* Now, we have an OPIN node, we get the source node index */ + int xlow = rr_graph->rr_node[inode].xlow; + int ylow = rr_graph->rr_node[inode].ylow; + int sink_node_ptc_num = get_grid_pin_class_index(grids[xlow][ylow], + rr_graph->rr_node[inode].ptc_num); + /* 1. create edges between IPINs and SINKs */ + int sink_node_id = get_rr_node_index(xlow, ylow, + SINK, sink_node_ptc_num, + rr_graph->rr_node_indices); + /* add edges to connect the IPIN node to SINK nodes */ + add_one_edge_for_two_rr_nodes(rr_graph, inode, sink_node_id, + rr_graph->rr_node[inode].driver_switch); + } + + return; +} + /************************************************************************ * Build the edges of each rr_node tile by tile: * We classify rr_nodes into a general switch block (GSB) data structure * where we create edges to each rr_nodes in the GSB with respect to * Fc_in and Fc_out, switch block patterns * For each GSB: - * 1. create edges between SOURCE and OPINs - * 2. create edges between IPINs and SINKs - * 3. create edges between CHANX | CHANY and IPINs (connections inside connection blocks) - * 4. create edges between OPINs, CHANX and CHANY (connections inside switch blocks) - * 5. create edges between OPINs and IPINs (direct-connections) + * 1. create edges between CHANX | CHANY and IPINs (connections inside connection blocks) + * 2. create edges between OPINs, CHANX and CHANY (connections inside switch blocks) + * 3. create edges between OPINs and IPINs (direct-connections) ***********************************************************************/ static void build_rr_graph_edges(t_rr_graph* rr_graph, @@ -1138,6 +817,10 @@ void build_rr_graph_edges(t_rr_graph* rr_graph, int** Fc_in, int** Fc_out, const enum e_switch_block_type sb_type, const int Fs) { + /* Create edges for SOURCE and SINK nodes for a tileable rr_graph */ + build_rr_graph_edges_for_source_nodes(rr_graph, grids); + build_rr_graph_edges_for_sink_nodes(rr_graph, grids); + DeviceCoordinator gsb_range(device_size.get_x() - 2, device_size.get_y() - 2); /* Go Switch Block by Switch Block */ @@ -1162,7 +845,7 @@ void build_rr_graph_edges(t_rr_graph* rr_graph, sb_conn = build_gsb_track_to_track_map(rr_graph, rr_gsb, sb_type, Fs, segment_inf); /* Build edges for a GSB */ - build_edges_for_one_tileable_rr_gsb(rr_graph, grids, &rr_gsb, + build_edges_for_one_tileable_rr_gsb(rr_graph, &rr_gsb, track2ipin_map, opin2track_map, sb_conn); /* Finish this GSB, go to the next*/ @@ -1251,7 +934,6 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types, INP const int num_seg_types, INP const t_segment_inf * segment_inf, INP const int num_switches, INP const int delayless_switch, - INP const int global_route_switch, INP const t_timing_inf timing_inf, INP const int wire_to_ipin_switch, INP const enum e_base_cost_type base_cost_type, @@ -1317,9 +999,6 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types, tileable_rr_graph_init_rr_node(&(rr_graph.rr_node[i])); } - vpr_printf(TIO_MESSAGE_INFO, - "%d RR graph nodes allocated.\n", rr_graph.num_rr_nodes); - /************************************************************************ * 4. Initialize the basic information of rr_nodes: * coordinators: xlow, ylow, xhigh, yhigh, @@ -1331,9 +1010,6 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types, load_rr_nodes_basic_info(&rr_graph, device_size, grids, device_chan_width, segment_infs, wire_to_ipin_switch, delayless_switch); - vpr_printf(TIO_MESSAGE_INFO, - "Built node basic information and fast-look.\n"); - /************************************************************************ * 5.1 Create the connectivity of OPINs * a. Evenly assign connections to OPINs to routing tracks @@ -1369,7 +1045,6 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types, * In addition, we will also handle direct-connections: * Add edges that bridge OPINs and IPINs to the rr_graph ***********************************************************************/ - /* Create edges for a tileable rr_graph */ build_rr_graph_edges(&rr_graph, device_size, grids, device_chan_width, segment_infs, Fc_in, Fc_out, @@ -1415,9 +1090,8 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types, "Create a tileable RR graph with %d nodes\n", num_rr_nodes); - check_rr_graph(GRAPH_UNIDIR_TILEABLE, types, L_nx, L_ny, chan_width, Fs, - num_seg_types, num_switches, segment_inf, global_route_switch, - delayless_switch, wire_to_ipin_switch, Fc_in, Fc_out); + check_rr_graph(GRAPH_UNIDIR_TILEABLE, L_nx, L_ny, + num_switches, Fc_in); /* Print useful information on screen */ vpr_printf(TIO_MESSAGE_INFO, diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.h b/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_builder.h similarity index 70% rename from vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.h rename to vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_builder.h index 2792a5680..827adbbc8 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_builder.h +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_builder.h @@ -1,16 +1,10 @@ -#ifndef RR_GRAPH_TILEABLE_BUILDER_H -#define RR_GRAPH_TILEABLE_BUILDER_H +#ifndef TILEABLE_RR_GRAPH_BUILDER_H +#define TILEABLE_RR_GRAPH_BUILDER_H #include #include "vpr_types.h" -#include "chan_node_details.h" - -ChanNodeDetails build_unidir_chan_node_details(const size_t chan_width, const size_t max_seg_length, - const enum e_side device_side, - const std::vector segment_inf); - void build_tileable_unidir_rr_graph(INP const int L_num_types, INP t_type_ptr types, INP const int L_nx, INP const int L_ny, INP struct s_grid_tile **L_grid, INP const int chan_width, @@ -18,7 +12,6 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types, INP const int num_seg_types, INP const t_segment_inf * segment_inf, INP const int num_switches, INP const int delayless_switch, - const int global_route_switch, INP const t_timing_inf timing_inf, INP const int wire_to_ipin_switch, INP const enum e_base_cost_type base_cost_type, INP const t_direct_inf *directs, diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.cpp b/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_gsb.cpp similarity index 93% rename from vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.cpp rename to vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_gsb.cpp index 79a0590f4..1b944ac8b 100755 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.cpp +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_gsb.cpp @@ -23,7 +23,7 @@ ***********************************************************************/ /************************************************************************ - * Filename: rr_graph_tileable_gsb.cpp + * Filename: tileable_rr_graph_gsb.cpp * Created by: Xifan Tang * Change history: * +-------------------------------------+ @@ -48,8 +48,9 @@ #include "rr_graph_util.h" #include "rr_graph2.h" -#include "rr_graph_tileable_gsb.h" -#include "rr_graph_tileable_builder.h" +#include "rr_graph_builder_utils.h" +#include "tileable_chan_details_builder.h" +#include "tileable_rr_graph_gsb.h" #include "fpga_x2p_backannotate_utils.h" @@ -885,67 +886,13 @@ RRGSB build_one_tileable_rr_gsb(const DeviceCoordinator& device_range, return rr_gsb; } -/************************************************************************ - * Add a edge connecting two rr_nodes - * For src rr_node, update the edge list and update switch_id, - * For des rr_node, update the fan_in - ***********************************************************************/ -static -void add_one_edge_for_two_rr_nodes(const t_rr_graph* rr_graph, - const int src_rr_node_id, - const int des_rr_node_id, - const short switch_id) { - /* Check */ - assert ( (-1 < src_rr_node_id) && (src_rr_node_id < rr_graph->num_rr_nodes) ); - assert ( (-1 < des_rr_node_id) && (des_rr_node_id < rr_graph->num_rr_nodes) ); - - t_rr_node* src_rr_node = &(rr_graph->rr_node[src_rr_node_id]); - t_rr_node* des_rr_node = &(rr_graph->rr_node[des_rr_node_id]); - - /* Allocate edge and switch to src_rr_node */ - src_rr_node->num_edges++; - if (NULL == src_rr_node->edges) { - /* calloc */ - src_rr_node->edges = (int*) my_calloc( src_rr_node->num_edges, sizeof(int) ); - src_rr_node->switches = (short*) my_calloc( src_rr_node->num_edges, sizeof(short) ); - } else { - /* realloc */ - src_rr_node->edges = (int*) my_realloc(src_rr_node->edges, - src_rr_node->num_edges * sizeof(int)); - src_rr_node->switches = (short*) my_realloc(src_rr_node->switches, - src_rr_node->num_edges * sizeof(short)); - } - /* Fill edge and switch info */ - src_rr_node->edges[src_rr_node->num_edges - 1] = des_rr_node_id; - src_rr_node->switches[src_rr_node->num_edges - 1] = switch_id; - - /* Update the des_rr_node */ - des_rr_node->fan_in++; - - return; -} - -/************************************************************************ - * Get the class index of a grid pin - ***********************************************************************/ -static -int get_grid_pin_class_index(const t_grid_tile& cur_grid, - const int pin_index) { - /* check */ - assert ( pin_index < cur_grid.type->num_pins); - return cur_grid.type->pin_class[pin_index]; -} - /************************************************************************ * Create edges for each rr_node of a General Switch Blocks (GSB): - * 1. create edges between SOURCE and OPINs - * 2. create edges between IPINs and SINKs - * 3. create edges between CHANX | CHANY and IPINs (connections inside connection blocks) - * 4. create edges between OPINs, CHANX and CHANY (connections inside switch blocks) - * 5. create edges between OPINs and IPINs (direct-connections) + * 1. create edges between CHANX | CHANY and IPINs (connections inside connection blocks) + * 2. create edges between OPINs, CHANX and CHANY (connections inside switch blocks) + * 3. create edges between OPINs and IPINs (direct-connections) ***********************************************************************/ void build_edges_for_one_tileable_rr_gsb(const t_rr_graph* rr_graph, - const std::vector< std::vector > grids, const RRGSB* rr_gsb, const t_track2pin_map track2ipin_map, const t_pin2track_map opin2track_map, @@ -961,15 +908,8 @@ void build_edges_for_one_tileable_rr_gsb(const t_rr_graph* rr_graph, /* Find OPINs */ for (size_t inode = 0; inode < rr_gsb->get_num_opin_nodes(gsb_side); ++inode) { t_rr_node* opin_node = rr_gsb->get_opin_node(gsb_side, inode); - int src_node_ptc_num = get_grid_pin_class_index(grids[opin_node->xlow][opin_node->ylow], opin_node->ptc_num); - /* 1. create edges between SOURCE and OPINs */ - int src_node_id = get_rr_node_index(opin_node->xlow, opin_node->ylow, - SOURCE, src_node_ptc_num, - rr_graph->rr_node_indices); - /* add edges to the src_node */ - add_one_edge_for_two_rr_nodes(rr_graph, src_node_id, opin_node - rr_graph->rr_node, - opin_node->driver_switch); - /* 2. create edges between OPINs and CHANX|CHANY, using opin2track_map */ + + /* 1. create edges between OPINs and CHANX|CHANY, using opin2track_map */ int num_edges = opin2track_map[side_manager.to_size_t()][inode].size(); for (int iedge = 0; iedge < num_edges; ++iedge) { int track_node_id = opin2track_map[side_manager.to_size_t()][inode][iedge]; @@ -979,25 +919,13 @@ void build_edges_for_one_tileable_rr_gsb(const t_rr_graph* rr_graph, } } - /* Find IPINs */ - for (size_t inode = 0; inode < rr_gsb->get_num_ipin_nodes(gsb_side); ++inode) { - t_rr_node* ipin_node = rr_gsb->get_ipin_node(gsb_side, inode); - int sink_node_ptc_num = get_grid_pin_class_index(grids[ipin_node->xlow][ipin_node->ylow], ipin_node->ptc_num); - /* 3. create edges between IPINs and SINKs */ - int sink_node_id = get_rr_node_index(ipin_node->xlow, ipin_node->ylow, - SINK, sink_node_ptc_num, - rr_graph->rr_node_indices); - /* add edges to connect the IPIN node to SINK nodes */ - add_one_edge_for_two_rr_nodes(rr_graph, ipin_node - rr_graph->rr_node, sink_node_id, - rr_graph->rr_node[sink_node_id].driver_switch); - } /* Find CHANX or CHANY */ /* For TRACKs to IPINs, we only care LEFT and TOP sides * Skip RIGHT and BOTTOM for the ipin2track_map since they should be handled in other GSBs */ if ( (side_manager.get_side() == rr_gsb->get_cb_chan_side(CHANX)) || (side_manager.get_side() == rr_gsb->get_cb_chan_side(CHANY)) ) { - /* 4. create edges between CHANX|CHANY and IPINs, using ipin2track_map */ + /* 2. create edges between CHANX|CHANY and IPINs, using ipin2track_map */ for (size_t inode = 0; inode < rr_gsb->get_chan_width(gsb_side); ++inode) { t_rr_node* chan_node = rr_gsb->get_chan_node(gsb_side, inode); int num_edges = track2ipin_map[side_manager.to_size_t()][inode].size(); @@ -1010,7 +938,7 @@ void build_edges_for_one_tileable_rr_gsb(const t_rr_graph* rr_graph, } } - /* 5. create edges between CHANX|CHANY and CHANX|CHANY, using track2track_map */ + /* 3. create edges between CHANX|CHANY and CHANX|CHANY, using track2track_map */ for (size_t inode = 0; inode < rr_gsb->get_chan_width(gsb_side); ++inode) { t_rr_node* chan_node = rr_gsb->get_chan_node(gsb_side, inode); int num_edges = track2track_map[side_manager.to_size_t()][inode].size(); diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.h b/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_gsb.h similarity index 95% rename from vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.h rename to vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_gsb.h index da752d7de..6d98e1aa8 100755 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_tileable_gsb.h +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_gsb.h @@ -1,5 +1,5 @@ -#ifndef RR_GRAPH_TILEABLE_GSB_H -#define RR_GRAPH_TILEABLE_GSB_H +#ifndef TILEABLE_RR_GRAPH_GSB_H +#define TILEABLE_RR_GRAPH_GSB_H #include @@ -32,7 +32,6 @@ RRGSB build_one_tileable_rr_gsb(const DeviceCoordinator& device_range, t_rr_graph* rr_graph); void build_edges_for_one_tileable_rr_gsb(const t_rr_graph* rr_graph, - const std::vector< std::vector > grids, const RRGSB* rr_gsb, const t_track2pin_map track2ipin_map, const t_pin2track_map opin2track_map, diff --git a/vpr7_x2p/vpr/SRC/route/check_rr_graph.c b/vpr7_x2p/vpr/SRC/route/check_rr_graph.c index 17fc4b34e..b3fb098a9 100755 --- a/vpr7_x2p/vpr/SRC/route/check_rr_graph.c +++ b/vpr7_x2p/vpr/SRC/route/check_rr_graph.c @@ -22,13 +22,26 @@ static boolean rr_node_is_global_clb_ipin(int inode); static void check_pass_transistors(int from_node); /************************ Subroutine definitions ****************************/ +/**************************************************************************** + * Print detailed information of a node to ease debugging + ****************************************************************************/ +static +void print_rr_node_details(t_rr_node* cur_rr_node) { + vpr_printf(TIO_MESSAGE_INFO, + "\tNode %d details: type=%s, (xlow,ylow)=(%d,%d)->(xhigh,yhigh)=(%d,%d), ptc_num=%d\n", + cur_rr_node - rr_node, + rr_node_typename[cur_rr_node->type], + cur_rr_node->xlow, cur_rr_node->ylow, + cur_rr_node->xhigh, cur_rr_node->yhigh, + cur_rr_node->ptc_num); + return; +} -void check_rr_graph(INP const t_graph_type graph_type, INP t_type_ptr types, - INP const int L_nx, INP const int L_ny, INP const int nodes_per_chan, INP int Fs, - INP const int num_seg_types, INP const int num_switches, - INP const t_segment_inf * segment_inf, INP const int global_route_switch, - INP const int delayless_switch, INP const int wire_to_ipin_switch, - int **Fc_in, int **Fc_out) { + +void check_rr_graph(INP const t_graph_type graph_type, + INP const int L_nx, INP const int L_ny, + INP const int num_switches, + int **Fc_in) { int *num_edges_from_current_to_node; /* [0..num_rr_nodes-1] */ int *total_edges_to_node; /* [0..num_rr_nodes-1] */ @@ -63,7 +76,9 @@ void check_rr_graph(INP const t_graph_type graph_type, INP t_type_ptr types, to_node = rr_node[inode].edges[iedge]; if (to_node < 0 || to_node >= num_rr_nodes) { - vpr_printf(TIO_MESSAGE_ERROR, "in check_rr_graph: node %d has an edge %d.\n", inode, to_node); + vpr_printf(TIO_MESSAGE_ERROR, "in check_rr_graph: node %d has an edge %d.\n", inode, to_node); + print_rr_node_details(&rr_node[inode]); + vpr_printf(TIO_MESSAGE_ERROR, "\tEdge is out of range.\n"); exit(1); } @@ -75,6 +90,7 @@ void check_rr_graph(INP const t_graph_type graph_type, INP t_type_ptr types, if (switch_type < 0 || switch_type >= num_switches) { vpr_printf(TIO_MESSAGE_ERROR, "in check_rr_graph: node %d has a switch type %d.\n", inode, switch_type); + print_rr_node_details(&rr_node[inode]); vpr_printf(TIO_MESSAGE_ERROR, "\tSwitch type is out of range.\n"); exit(1); } @@ -96,6 +112,8 @@ void check_rr_graph(INP const t_graph_type graph_type, INP t_type_ptr types, || (rr_type != CHANX && rr_type != CHANY)) { vpr_printf(TIO_MESSAGE_ERROR, "in check_rr_graph: node %d connects to node %d %d times.\n", inode, to_node, num_edges_from_current_to_node[to_node]); + print_rr_node_details(&rr_node[inode]); + print_rr_node_details(&rr_node[to_node]); exit(1); } @@ -106,6 +124,8 @@ void check_rr_graph(INP const t_graph_type graph_type, INP t_type_ptr types, || switch_types_from_current_to_node[to_node] != BUF_AND_PTRANS_FLAG) { vpr_printf(TIO_MESSAGE_ERROR, "in check_rr_graph: node %d connects to node %d %d times.\n", inode, to_node, num_edges_from_current_to_node[to_node]); + print_rr_node_details(&rr_node[inode]); + print_rr_node_details(&rr_node[to_node]); exit(1); } } @@ -157,10 +177,12 @@ void check_rr_graph(INP const t_graph_type graph_type, INP t_type_ptr types, if (!is_chain && !is_fringe && !is_wire) { vpr_printf(TIO_MESSAGE_ERROR, "in check_rr_graph: node %d has no fanin.\n", inode); + print_rr_node_details(&rr_node[inode]); exit(1); } else if (!is_chain && !is_fringe_warning_sent) { vpr_printf(TIO_MESSAGE_WARNING, "in check_rr_graph: fringe node %d has no fanin.\n", inode); vpr_printf(TIO_MESSAGE_WARNING, "\tThis is possible on the fringe for low Fc_out, N, and certain Lengths\n"); + print_rr_node_details(&rr_node[inode]); is_fringe_warning_sent = TRUE; } } @@ -170,6 +192,7 @@ void check_rr_graph(INP const t_graph_type graph_type, INP t_type_ptr types, if (total_edges_to_node[inode] != 0) { vpr_printf(TIO_MESSAGE_ERROR, "in check_rr_graph: SOURCE node %d has a fanin of %d, expected 0.\n", inode, total_edges_to_node[inode]); + print_rr_node_details(&rr_node[inode]); exit(1); } } @@ -224,18 +247,21 @@ void check_node(int inode, enum e_route_type route_type) { if (xlow > xhigh || ylow > yhigh) { vpr_printf(TIO_MESSAGE_ERROR, "in check_node: rr endpoints are (%d,%d) and (%d,%d).\n", xlow, ylow, xhigh, yhigh); + print_rr_node_details(&rr_node[inode]); exit(1); } if (xlow < 0 || xhigh > nx + 1 || ylow < 0 || yhigh > ny + 1) { vpr_printf(TIO_MESSAGE_ERROR, "in check_node: rr endpoints (%d,%d) and (%d,%d) are out of range.\n", xlow, ylow, xhigh, yhigh); + print_rr_node_details(&rr_node[inode]); exit(1); } if (ptc_num < 0) { vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) had a ptc_num of %d.\n", inode, rr_type, ptc_num); + print_rr_node_details(&rr_node[inode]); exit(1); } @@ -253,11 +279,13 @@ void check_node(int inode, enum e_route_type route_type) { if (type == NULL) { vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d (type %d) is at an illegal clb location (%d, %d).\n", inode, rr_type, xlow, ylow); + print_rr_node_details(&rr_node[inode]); exit(1); } if (xlow != xhigh || ylow != (yhigh - type->height + 1)) { vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d (type %d) has endpoints (%d,%d) and (%d,%d)\n", inode, rr_type, xlow, ylow, xhigh, yhigh); + print_rr_node_details(&rr_node[inode]); exit(1); } break; @@ -276,11 +304,13 @@ void check_node(int inode, enum e_route_type route_type) { /* end */ vpr_printf(TIO_MESSAGE_ERROR, "in check_node: CHANX out of range for endpoints (%d,%d) and (%d,%d)\n", xlow, ylow, xhigh, yhigh); + print_rr_node_details(&rr_node[inode]); exit(1); } if (route_type == GLOBAL && xlow != xhigh) { vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d spans multiple channel segments (not allowed for global routing).\n", inode); + print_rr_node_details(&rr_node[inode]); exit(1); } break; @@ -299,11 +329,13 @@ void check_node(int inode, enum e_route_type route_type) { /* end */ vpr_printf(TIO_MESSAGE_ERROR, "Error in check_node: CHANY out of range for endpoints (%d,%d) and (%d,%d)\n", xlow, ylow, xhigh, yhigh); + print_rr_node_details(&rr_node[inode]); exit(1); } if (route_type == GLOBAL && ylow != yhigh) { vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d spans multiple channel segments (not allowed for global routing).\n", inode); + print_rr_node_details(&rr_node[inode]); exit(1); } break; @@ -323,11 +355,13 @@ void check_node(int inode, enum e_route_type route_type) { || type->class_inf[ptc_num].type != DRIVER) { vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) had a ptc_num of %d.\n", inode, rr_type, ptc_num); + print_rr_node_details(&rr_node[inode]); exit(1); } if (type->class_inf[ptc_num].num_pins != capacity) { vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) had a capacity of %d.\n", inode, rr_type, capacity); + print_rr_node_details(&rr_node[inode]); exit(1); } break; @@ -338,11 +372,13 @@ void check_node(int inode, enum e_route_type route_type) { || type->class_inf[ptc_num].type != RECEIVER) { vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) had a ptc_num of %d.\n", inode, rr_type, ptc_num); + print_rr_node_details(&rr_node[inode]); exit(1); } if (type->class_inf[ptc_num].num_pins != capacity) { vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) has a capacity of %d.\n", inode, rr_type, capacity); + print_rr_node_details(&rr_node[inode]); exit(1); } break; @@ -353,12 +389,14 @@ void check_node(int inode, enum e_route_type route_type) { || type->class_inf[type->pin_class[ptc_num]].type != DRIVER) { vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) had a ptc_num of %d.\n", inode, rr_type, ptc_num); + print_rr_node_details(&rr_node[inode]); exit(1); } if (capacity != 1) { vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) has a capacity of %d.\n", inode, rr_type, capacity); + print_rr_node_details(&rr_node[inode]); exit(1); } break; @@ -368,11 +406,13 @@ void check_node(int inode, enum e_route_type route_type) { || type->class_inf[type->pin_class[ptc_num]].type != RECEIVER) { vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) had a ptc_num of %d.\n", inode, rr_type, ptc_num); + print_rr_node_details(&rr_node[inode]); exit(1); } if (capacity != 1) { vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) has a capacity of %d.\n", inode, rr_type, capacity); + print_rr_node_details(&rr_node[inode]); exit(1); } break; @@ -389,12 +429,14 @@ void check_node(int inode, enum e_route_type route_type) { if (ptc_num >= nodes_per_chan) { vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) has a ptc_num of %d.\n", inode, rr_type, ptc_num); + print_rr_node_details(&rr_node[inode]); exit(1); } if (capacity != tracks_per_node) { vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) has a capacity of %d.\n", inode, rr_type, capacity); + print_rr_node_details(&rr_node[inode]); exit(1); } break; @@ -411,12 +453,14 @@ void check_node(int inode, enum e_route_type route_type) { if (ptc_num >= nodes_per_chan) { vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) has a ptc_num of %d.\n", inode, rr_type, ptc_num); + print_rr_node_details(&rr_node[inode]); exit(1); } if (capacity != tracks_per_node) { vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) has a capacity of %d.\n", inode, rr_type, capacity); + print_rr_node_details(&rr_node[inode]); exit(1); } break; @@ -436,6 +480,7 @@ void check_node(int inode, enum e_route_type route_type) { * If such a node was ever used in a final routing (not just in an rr_graph), other * * error checks in check_routing will catch it. */ vpr_printf(TIO_MESSAGE_WARNING, "in check_node: node %d has no edges.\n", inode); + print_rr_node_details(&rr_node[inode]); } } @@ -443,6 +488,7 @@ void check_node(int inode, enum e_route_type route_type) { if (num_edges != 0) { vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d is a sink, but has %d edges.\n", inode, num_edges); + print_rr_node_details(&rr_node[inode]); exit(1); } } @@ -456,6 +502,7 @@ void check_node(int inode, enum e_route_type route_type) { if (C < 0. || R < 0.) { vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d of type %d has R = %g and C = %g.\n", inode, rr_type, R, C); + print_rr_node_details(&rr_node[inode]); exit(1); } } @@ -464,6 +511,7 @@ void check_node(int inode, enum e_route_type route_type) { if (C != 0. || R != 0.) { vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d of type %d has R = %g and C = %g.\n", inode, rr_type, R, C); + print_rr_node_details(&rr_node[inode]); exit(1); } } @@ -472,6 +520,7 @@ void check_node(int inode, enum e_route_type route_type) { if (cost_index < 0 || cost_index >= num_rr_indexed_data) { vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d cost index (%d) is out of range.\n", inode, cost_index); + print_rr_node_details(&rr_node[inode]); exit(1); } } @@ -531,6 +580,8 @@ static void check_pass_transistors(int from_node) { vpr_printf(TIO_MESSAGE_ERROR, "connection from node %d to node %d uses a pass transistor (switch type %d)\n", from_node, to_node, from_switch_type); vpr_printf(TIO_MESSAGE_ERROR, "but there is no corresponding pass transistor edge in the other direction.\n"); + print_rr_node_details(&rr_node[from_node]); + print_rr_node_details(&rr_node[to_node]); exit(1); } diff --git a/vpr7_x2p/vpr/SRC/route/check_rr_graph.h b/vpr7_x2p/vpr/SRC/route/check_rr_graph.h index 0d2d06bdf..eb7a9e971 100755 --- a/vpr7_x2p/vpr/SRC/route/check_rr_graph.h +++ b/vpr7_x2p/vpr/SRC/route/check_rr_graph.h @@ -2,19 +2,9 @@ #define CHECK_RR_GRAPH_H void check_rr_graph(INP const t_graph_type graph_type, - INP t_type_ptr types, - INP const int L_nx, - INP const int L_ny, - INP const int nodes_per_chan, - INP const int Fs, - INP const int num_seg_types, - INP const int num_switches, - INP const t_segment_inf * segment_inf, - INP const int global_route_switch, - INP const int delayless_switch, - INP const int wire_to_ipin_switch, - int ** Fc_in, - int ** Fc_out); + INP const int L_nx, INP const int L_ny, + INP const int num_switches, + int **Fc_in); void check_node(int inode, enum e_route_type route_type); diff --git a/vpr7_x2p/vpr/SRC/route/rr_graph.c b/vpr7_x2p/vpr/SRC/route/rr_graph.c index a4dfed184..ff6d76b3f 100755 --- a/vpr7_x2p/vpr/SRC/route/rr_graph.c +++ b/vpr7_x2p/vpr/SRC/route/rr_graph.c @@ -16,7 +16,7 @@ #include "read_xml_arch_file.h" #include "ReadOptions.h" -#include "rr_graph_tileable_builder.h" +#include "tileable_rr_graph_builder.h" /* Xifan TANG: SWSEG SUPPORT */ #include "rr_graph_swseg.h" @@ -226,7 +226,7 @@ void build_rr_graph(INP t_graph_type graph_type, INP int L_num_types, L_nx, L_ny, L_grid, chan_width, sb_type, Fs, num_seg_types, segment_inf, - num_switches, global_route_switch, delayless_switch, + num_switches, delayless_switch, timing_inf, wire_to_ipin_switch, base_cost_type, directs, num_directs, ignore_Fc_0, Warnings); } else { @@ -523,9 +523,8 @@ void build_classic_rr_graph(INP t_graph_type graph_type, INP int L_num_types, } else ; - check_rr_graph(graph_type, types, L_nx, L_ny, nodes_per_chan, Fs, - num_seg_types, num_switches, segment_inf, global_route_switch, - delayless_switch, wire_to_ipin_switch, Fc_in, Fc_out); + check_rr_graph(graph_type, L_nx, L_ny, + num_switches, Fc_in); /* Free all temp structs */ if (seg_details) { From cdd4af9c58b07726db0c78d8021154fd58bacde4 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sun, 23 Jun 2019 18:11:13 -0600 Subject: [PATCH 17/25] vpr likes the tileable rr_graph while fpga_x2p does not --- .../rr_graph/rr_graph_builder_utils.cpp | 47 ++++++++++++++ .../device/rr_graph/rr_graph_builder_utils.h | 4 ++ .../rr_graph/tileable_rr_graph_builder.cpp | 62 +++++-------------- .../device/rr_graph/tileable_rr_graph_gsb.cpp | 49 +++++++++++---- 4 files changed, 105 insertions(+), 57 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_builder_utils.cpp b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_builder_utils.cpp index 58d22aeca..f639dc0fe 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_builder_utils.cpp +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_builder_utils.cpp @@ -255,3 +255,50 @@ void add_one_edge_for_two_rr_nodes(const t_rr_graph* rr_graph, return; } +/************************************************************************ + * Get the coordinator of a starting point of a routing track + * For routing tracks in INC_DIRECTION + * (xlow, ylow) should be the starting point + * + * For routing tracks in DEC_DIRECTION + * (xhigh, yhigh) should be the starting point + ***********************************************************************/ +DeviceCoordinator get_track_rr_node_start_coordinator(const t_rr_node* track_rr_node) { + /* Make sure we have CHANX or CHANY */ + assert ( (CHANX == track_rr_node->type) ||(CHANY == track_rr_node->type) ); + + DeviceCoordinator start_coordinator; + + if (INC_DIRECTION == track_rr_node->direction) { + start_coordinator.set(track_rr_node->xlow, track_rr_node->ylow); + } else { + assert (DEC_DIRECTION == track_rr_node->direction); + start_coordinator.set(track_rr_node->xhigh, track_rr_node->yhigh); + } + + return start_coordinator; +} + +/************************************************************************ + * Get the coordinator of a end point of a routing track + * For routing tracks in INC_DIRECTION + * (xhigh, yhigh) should be the starting point + * + * For routing tracks in DEC_DIRECTION + * (xlow, ylow) should be the starting point + ***********************************************************************/ +DeviceCoordinator get_track_rr_node_end_coordinator(const t_rr_node* track_rr_node) { + /* Make sure we have CHANX or CHANY */ + assert ( (CHANX == track_rr_node->type) ||(CHANY == track_rr_node->type) ); + + DeviceCoordinator start_coordinator; + + if (INC_DIRECTION == track_rr_node->direction) { + start_coordinator.set(track_rr_node->xhigh, track_rr_node->yhigh); + } else { + assert (DEC_DIRECTION == track_rr_node->direction); + start_coordinator.set(track_rr_node->xlow, track_rr_node->ylow); + } + + return start_coordinator; +} diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_builder_utils.h b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_builder_utils.h index fb565e0e3..2c353580f 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_builder_utils.h +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_builder_utils.h @@ -30,5 +30,9 @@ void add_one_edge_for_two_rr_nodes(const t_rr_graph* rr_graph, const int des_rr_node_id, const short switch_id); +DeviceCoordinator get_track_rr_node_start_coordinator(const t_rr_node* track_rr_node); + +DeviceCoordinator get_track_rr_node_end_coordinator(const t_rr_node* track_rr_node); + #endif diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_builder.cpp b/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_builder.cpp index bdcff462b..3e3ee145a 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_builder.cpp +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_builder.cpp @@ -359,8 +359,12 @@ void load_one_chan_rr_nodes_basic_info(const DeviceCoordinator& chan_coordinator */ for (size_t itrack = 0; itrack < chan_details->get_chan_width(); ++itrack) { /* For INC direction, a starting point requires a new chan rr_node */ - if ( (true == chan_details->is_track_start(itrack)) - && (INC_DIRECTION == chan_details->get_track_direction(itrack)) ) { + if ( ( (true == chan_details->is_track_start(itrack)) + && (INC_DIRECTION == chan_details->get_track_direction(itrack)) ) + /* For DEC direction, an ending point requires a new chan rr_node */ + || + ( (true == chan_details->is_track_end(itrack)) + && (DEC_DIRECTION == chan_details->get_track_direction(itrack)) ) ) { /* Use a new chan rr_node */ rr_graph->rr_node[*cur_node_id].type = chan_type; rr_graph->rr_node[*cur_node_id].xlow = chan_coordinator.get_x(); @@ -382,33 +386,14 @@ void load_one_chan_rr_nodes_basic_info(const DeviceCoordinator& chan_coordinator (*cur_node_id)++; /* Finish here, go to next */ } - /* For DEC direction, an ending point requires a new chan rr_node */ - if ( (true == chan_details->is_track_end(itrack)) - && (DEC_DIRECTION == chan_details->get_track_direction(itrack)) ) { - /* Use a new chan rr_node */ - rr_graph->rr_node[*cur_node_id].type = chan_type; - rr_graph->rr_node[*cur_node_id].xhigh = chan_coordinator.get_x(); - rr_graph->rr_node[*cur_node_id].yhigh = chan_coordinator.get_y(); - rr_graph->rr_node[*cur_node_id].direction = chan_details->get_track_direction(itrack); - rr_graph->rr_node[*cur_node_id].ptc_num = itrack; - rr_graph->rr_node[*cur_node_id].track_ids.push_back(itrack); - rr_graph->rr_node[*cur_node_id].capacity = 1; - rr_graph->rr_node[*cur_node_id].occ = 0; - /* Update chan_details with node_id */ - chan_details->set_track_node_id(itrack, *cur_node_id); - /* assign switch id */ - size_t seg_id = chan_details->get_track_segment_id(itrack); - rr_graph->rr_node[*cur_node_id].driver_switch = segment_infs[seg_id].opin_switch; - /* cost index depends on the segment index */ - rr_graph->rr_node[*cur_node_id].cost_index = cost_index_offset + seg_id; - /* Update node counter */ - (*cur_node_id)++; - /* Finish here, go to next */ - } /* For INC direction, an ending point requires an update on xhigh and yhigh */ - if ( (true == chan_details->is_track_end(itrack)) - && (INC_DIRECTION == chan_details->get_track_direction(itrack)) ) { + if ( ( (true == chan_details->is_track_end(itrack)) + && (INC_DIRECTION == chan_details->get_track_direction(itrack)) ) + || + /* For DEC direction, an starting point requires an update on xlow and ylow */ + ( (true == chan_details->is_track_start(itrack)) + && (DEC_DIRECTION == chan_details->get_track_direction(itrack)) ) ) { /* Get the node_id */ size_t rr_node_id = chan_details->get_track_node_id(itrack); /* Do a quick check, make sure we do not mistakenly modify other nodes */ @@ -424,24 +409,7 @@ void load_one_chan_rr_nodes_basic_info(const DeviceCoordinator& chan_coordinator } /* Finish here, go to next */ } - /* For DEC direction, an starting point requires an update on xlow and ylow */ - if ( (true == chan_details->is_track_start(itrack)) - && (DEC_DIRECTION == chan_details->get_track_direction(itrack)) ) { - /* Get the node_id */ - size_t rr_node_id = chan_details->get_track_node_id(itrack); - /* Do a quick check, make sure we do not mistakenly modify other nodes */ - assert(chan_type == rr_graph->rr_node[rr_node_id].type); - assert(chan_details->get_track_direction(itrack) == rr_graph->rr_node[rr_node_id].direction); - /* set xlow/ylow and push changes to track_ids */ - rr_graph->rr_node[rr_node_id].xlow = chan_coordinator.get_x(); - rr_graph->rr_node[rr_node_id].ylow = chan_coordinator.get_y(); - /* Do not update track_ids for length-1 wires, they should have only 1 track_id */ - if ( (rr_graph->rr_node[rr_node_id].xhigh > rr_graph->rr_node[rr_node_id].xlow) - || (rr_graph->rr_node[rr_node_id].yhigh > rr_graph->rr_node[rr_node_id].ylow) ) { - rr_graph->rr_node[rr_node_id].track_ids.push_back(itrack); - } - /* Finish here, go to next */ - } + /* Finish processing starting and ending tracks */ if ( (true== chan_details->is_track_start(itrack)) || (true == chan_details->is_track_end(itrack)) ) { @@ -660,7 +628,7 @@ void load_rr_nodes_basic_info(t_rr_graph* rr_graph, } } - /* Check */ + /* A quick check */ assert ((int)cur_node_id == rr_graph->num_rr_nodes); for (int inode = 0; inode < rr_graph->num_rr_nodes; ++inode) { /* Check: we only support straight wires now. @@ -668,8 +636,10 @@ void load_rr_nodes_basic_info(t_rr_graph* rr_graph, */ if (CHANX == rr_graph->rr_node[inode].type) { assert (rr_graph->rr_node[inode].ylow == rr_graph->rr_node[inode].yhigh); + assert (rr_graph->rr_node[inode].xlow <= rr_graph->rr_node[inode].xhigh); } else if (CHANY == rr_graph->rr_node[inode].type) { assert (rr_graph->rr_node[inode].xlow == rr_graph->rr_node[inode].xhigh); + assert (rr_graph->rr_node[inode].ylow <= rr_graph->rr_node[inode].yhigh); } else { assert ( (SOURCE == rr_graph->rr_node[inode].type) || (SINK == rr_graph->rr_node[inode].type) diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_gsb.cpp b/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_gsb.cpp index 1b944ac8b..d9cfd1429 100755 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_gsb.cpp +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_gsb.cpp @@ -91,16 +91,25 @@ enum e_track_status determine_track_status_of_gsb(const RRGSB& rr_gsb, /* Get the coordinators */ DeviceCoordinator side_coordinator = rr_gsb.get_side_block_coordinator(gsb_side); + /* Get the coordinator of where the track starts */ + DeviceCoordinator track_start = get_track_rr_node_start_coordinator(track_node); + /* INC_DIRECTION start_track: (xlow, ylow) should be same as the GSB side coordinator */ - if ( ((size_t)track_node->xlow == side_coordinator.get_x()) - && ((size_t)track_node->ylow == side_coordinator.get_y()) + /* DEC_DIRECTION start_track: (xhigh, yhigh) should be same as the GSB side coordinator */ + if ( (track_start.get_x() == side_coordinator.get_x()) + && (track_start.get_y() == side_coordinator.get_y()) && (OUT_PORT == rr_gsb.get_chan_node_direction(gsb_side, track_id)) ) { /* Double check: start track should be an OUTPUT PORT of the GSB */ track_status = TRACK_START; } + + /* Get the coordinator of where the track ends */ + DeviceCoordinator track_end = get_track_rr_node_end_coordinator(track_node); + /* INC_DIRECTION end_track: (xhigh, yhigh) should be same as the GSB side coordinator */ - if ( ((size_t)track_node->xhigh == side_coordinator.get_x()) - && ((size_t)track_node->yhigh == side_coordinator.get_y()) + /* DEC_DIRECTION end_track: (xlow, ylow) should be same as the GSB side coordinator */ + if ( (track_end.get_x() == side_coordinator.get_x()) + && (track_end.get_y() == side_coordinator.get_y()) && (IN_PORT == rr_gsb.get_chan_node_direction(gsb_side, track_id)) ) { /* Double check: end track should be an INPUT PORT of the GSB */ track_status = TRACK_END; @@ -132,9 +141,11 @@ bool is_gsb_in_track_cb_population(const RRGSB& rr_gsb, /* Get the coordinators */ DeviceCoordinator side_coordinator = rr_gsb.get_side_block_coordinator(gsb_side); + DeviceCoordinator track_start = get_track_rr_node_start_coordinator(track_node); + /* Get the offset */ - size_t offset = std::abs((int)side_coordinator.get_x() - track_node->xlow) - + std::abs((int)side_coordinator.get_y() - track_node->ylow); + size_t offset = std::abs((int)side_coordinator.get_x() - (int)track_start.get_x()) + + std::abs((int)side_coordinator.get_y() - (int)track_start.get_y()); /* Get segment id */ size_t seg_id = rr_gsb.get_chan_node_segment(gsb_side, track_id); @@ -171,9 +182,11 @@ bool is_gsb_in_track_sb_population(const RRGSB& rr_gsb, /* Get the coordinators */ DeviceCoordinator side_coordinator = rr_gsb.get_side_block_coordinator(gsb_side); + DeviceCoordinator track_start = get_track_rr_node_start_coordinator(track_node); + /* Get the offset */ - size_t offset = std::abs((int)side_coordinator.get_x() - track_node->xlow) - + std::abs((int)side_coordinator.get_y() - track_node->ylow); + size_t offset = std::abs((int)side_coordinator.get_x() - (int)track_start.get_x()) + + std::abs((int)side_coordinator.get_y() - (int)track_start.get_y()); /* Get segment id */ size_t seg_id = rr_gsb.get_chan_node_segment(gsb_side, track_id); @@ -1298,6 +1311,20 @@ void build_direct_connections_for_one_gsb(t_rr_graph* rr_graph, if (grid_type != clb_to_clb_directs[i].from_clb_type) { continue; } + + /* This opin is specified to connect directly to an ipin, + * now compute which ipin to connect to + */ + DeviceCoordinator to_grid_coordinator(from_grid_coordinator.get_x() + directs[i].x_offset, + from_grid_coordinator.get_y() + directs[i].y_offset); + + /* Bypass unmatched direct clb-to-clb connections */ + t_type_ptr to_grid_type = grids[to_grid_coordinator.get_x()][to_grid_coordinator.get_y()].type; + /* Check if to_grid if the same grid */ + if (to_grid_type != clb_to_clb_directs[i].to_clb_type) { + continue; + } + bool swap; int max_index, min_index; /* Compute index of opin with regards to given pins */ @@ -1311,12 +1338,11 @@ void build_direct_connections_for_one_gsb(t_rr_graph* rr_graph, min_index = clb_to_clb_directs[i].from_clb_pin_start_index; max_index = clb_to_clb_directs[i].from_clb_pin_end_index; } + /* get every opin in the range */ for (int opin = min_index; opin <= max_index; ++opin) { int offset = opin - min_index; - /* This opin is specified to connect directly to an ipin, now compute which ipin to connect to */ - DeviceCoordinator to_grid_coordinator(from_grid_coordinator.get_x() + directs[i].x_offset, - from_grid_coordinator.get_y() + directs[i].y_offset); + if ( (to_grid_coordinator.get_x() < device_size.get_x() - 1) && (to_grid_coordinator.get_y() < device_size.get_y() - 1) ) { int ipin = OPEN; @@ -1334,6 +1360,7 @@ void build_direct_connections_for_one_gsb(t_rr_graph* rr_graph, ipin = clb_to_clb_directs[i].to_clb_pin_start_index + offset; } } + /* Get the pin index in the rr_graph */ int from_grid_ofs = from_grid.offset; int to_grid_ofs = grids[to_grid_coordinator.get_x()][to_grid_coordinator.get_y()].offset; From 0d62661c7137a6abaf4db9db2f85e6f89d787802 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sun, 23 Jun 2019 20:52:38 -0600 Subject: [PATCH 18/25] bug fixing and spot critical bugs in directlist parser --- .../rr_graph/tileable_rr_graph_builder.cpp | 16 +++++++++++++++- .../device/rr_graph/tileable_rr_graph_gsb.cpp | 8 ++++++-- .../fpga_x2p/base/fpga_x2p_backannotate_utils.c | 1 + .../SRC/fpga_x2p/base/fpga_x2p_unique_routing.c | 11 ++++++----- 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_builder.cpp b/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_builder.cpp index 3e3ee145a..1c013ed2e 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_builder.cpp +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_builder.cpp @@ -858,6 +858,17 @@ void build_rr_graph_direct_connections(t_rr_graph* rr_graph, return; } +/************************************************************************ + * Reset driver switch of a rr_graph + ***********************************************************************/ +static +void clear_rr_graph_driver_switch(const t_rr_graph* rr_graph) { + for (int inode = 0; inode < rr_graph->num_rr_nodes; ++inode) { + rr_graph->rr_node[inode].driver_switch = 0; + } + return; +} + /************************************************************************ * Main function of this file * Builder for a detailed uni-directional tileable rr_graph @@ -1038,6 +1049,9 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types, vpr_printf(TIO_MESSAGE_INFO, "%lu edges of RR graph built.\n", num_edges); + /* Clear driver switches of the rr_graph */ + clear_rr_graph_driver_switch(&rr_graph); + /************************************************************************ * 8. Allocate external data structures * a. cost_index @@ -1046,7 +1060,7 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types, /* We set global variables for rr_nodes here, they will be updated by rr_graph_external */ num_rr_nodes = rr_graph.num_rr_nodes; rr_node = rr_graph.rr_node; - rr_node_indices = rr_graph.rr_node_indices; + rr_node_indices = rr_graph.rr_node_indices; rr_graph_externals(timing_inf, segment_inf, num_seg_types, chan_width, wire_to_ipin_switch, base_cost_type); diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_gsb.cpp b/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_gsb.cpp index d9cfd1429..0eae4486a 100755 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_gsb.cpp +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_gsb.cpp @@ -354,7 +354,7 @@ void build_gsb_one_group_track_to_track_map(const t_rr_graph* rr_graph, t_track2track_map* track2track_map) { for (size_t side = 0; side < from_tracks.size(); ++side) { Side side_manager(side); - enum e_side gsb_side = side_manager.get_side(); + enum e_side from_side = side_manager.get_side(); /* Find the other sides where the start tracks will locate */ std::vector to_track_sides; /* 0. opposite side */ @@ -375,9 +375,13 @@ void build_gsb_one_group_track_to_track_map(const t_rr_graph* rr_graph, if (0 == to_tracks[to_side_index].size()) { continue; } + /* Bypass those from_side is same as to_side */ + if (from_side == to_side) { + continue; + } /* Get other track_ids depending on the switch block pattern */ /* Find the track ids that will start at the other sides */ - std::vector to_track_ids = get_switch_block_to_track_id(sb_type, Fs, gsb_side, inode, + std::vector to_track_ids = get_switch_block_to_track_id(sb_type, Fs, from_side, inode, to_side, to_tracks[to_side_index].size()); /* Update the track2track_map: */ 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 d72b582af..005770a38 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 @@ -1800,6 +1800,7 @@ void identify_rr_node_driver_switch(t_det_routing_arch RoutingArch, } LL_rr_node[inode].driver_switch = LL_rr_node[inode].drive_switches[0]; for (iedge = 0; iedge < LL_rr_node[inode].num_drive_rr_nodes; iedge++) { + if (LL_rr_node[inode].driver_switch != LL_rr_node[inode].drive_switches[iedge]) assert (LL_rr_node[inode].driver_switch == LL_rr_node[inode].drive_switches[iedge]); } } 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 d8de7bfb8..76ca32ca9 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 @@ -1340,11 +1340,12 @@ DeviceRRGSB build_device_rr_gsb(boolean output_sb_xml, char* sb_xml_dir, if (TRUE == output_sb_xml) { std::string fname_prefix(sb_xml_dir); /* Add slash if needed */ - if ('/' != fname_prefix.back()) { - fname_prefix += "/"; - } - fname_prefix += "rotated_"; - write_rr_switch_block_to_xml(fname_prefix, rotated_rr_sb); + //if ('/' != fname_prefix.back()) { + // fname_prefix += "/"; + //} + //fname_prefix += "rotated_"; + //write_rr_switch_block_to_xml(fname_prefix, rotated_rr_sb); + write_rr_switch_block_to_xml(fname_prefix, rr_sb); } } } From fd301eeb66cde1563d3f11f536ac92b2457ee21a Mon Sep 17 00:00:00 2001 From: tangxifan Date: Mon, 24 Jun 2019 17:33:29 -0600 Subject: [PATCH 19/25] many bug fixing and now start improving the routability of tileable rr_graph --- .../rr_graph/rr_graph_builder_utils.cpp | 20 ++++ .../device/rr_graph/rr_graph_builder_utils.h | 2 + .../tileable_chan_details_builder.cpp | 7 +- .../rr_graph/tileable_rr_graph_builder.cpp | 97 +++++++++++++++++-- .../device/rr_graph/tileable_rr_graph_gsb.cpp | 27 +++--- .../base/fpga_x2p_backannotate_utils.c | 1 + .../fpga_x2p/base/fpga_x2p_pbtypes_utils.c | 2 + .../fpga_x2p/base/fpga_x2p_rr_graph_utils.c | 74 +++++++++++++- .../fpga_x2p/base/fpga_x2p_rr_graph_utils.h | 7 ++ .../fpga_x2p/base/fpga_x2p_unique_routing.c | 46 ++++----- 10 files changed, 234 insertions(+), 49 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_builder_utils.cpp b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_builder_utils.cpp index f639dc0fe..aa08c67fd 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_builder_utils.cpp +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_builder_utils.cpp @@ -302,3 +302,23 @@ DeviceCoordinator get_track_rr_node_end_coordinator(const t_rr_node* track_rr_no return start_coordinator; } + +/************************************************************************ + * Get the ptc of a routing track in the channel where it ends + * For routing tracks in INC_DIRECTION + * the ptc is the last of track_ids + * + * For routing tracks in DEC_DIRECTION + * the ptc is the first of track_ids + ***********************************************************************/ +short get_track_rr_node_end_track_id(const t_rr_node* track_rr_node) { + /* Make sure we have CHANX or CHANY */ + assert ( (CHANX == track_rr_node->type) ||(CHANY == track_rr_node->type) ); + + if (INC_DIRECTION == track_rr_node->direction) { + return track_rr_node->track_ids.back(); + } + assert (DEC_DIRECTION == track_rr_node->direction); + return track_rr_node->track_ids.front(); +} + diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_builder_utils.h b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_builder_utils.h index 2c353580f..07ed2f543 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_builder_utils.h +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_builder_utils.h @@ -34,5 +34,7 @@ DeviceCoordinator get_track_rr_node_start_coordinator(const t_rr_node* track_rr_ DeviceCoordinator get_track_rr_node_end_coordinator(const t_rr_node* track_rr_node); +short get_track_rr_node_end_track_id(const t_rr_node* track_rr_node); + #endif diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_chan_details_builder.cpp b/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_chan_details_builder.cpp index bc52119f0..80854e9ef 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_chan_details_builder.cpp +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_chan_details_builder.cpp @@ -191,7 +191,7 @@ ChanNodeDetails build_unidir_chan_node_details(const size_t chan_width, const si } /* Find the number of segments required by each group */ - std::vector num_tracks = get_num_tracks_per_seg_type(actual_chan_width/2, segment_inf, TRUE); + std::vector num_tracks = get_num_tracks_per_seg_type(actual_chan_width/2, segment_inf, FALSE); /* Add node to ChanNodeDetails */ size_t cur_track = 0; @@ -208,8 +208,9 @@ ChanNodeDetails build_unidir_chan_node_details(const size_t chan_width, const si if (0 == itrack % seg_len) { seg_start = true; } - /* Every last track of a group of Length-N wires, we set an ending point */ - if (seg_len - 1 == itrack % seg_len) { + /* Every last track of a group of Length-N wires or this is the last track in this group, we set an ending point */ + if ( (seg_len - 1 == itrack % seg_len) + || (itrack == num_tracks[iseg] - 1) ) { seg_end = true; } /* Since this is a unidirectional routing architecture, diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_builder.cpp b/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_builder.cpp index 1c013ed2e..81a31efd2 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_builder.cpp +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_builder.cpp @@ -868,6 +868,75 @@ void clear_rr_graph_driver_switch(const t_rr_graph* rr_graph) { } return; } + +/************************************************************************ + * Sort the edges of rr_nodes by node type and ptc_num + * 1. node type priority: (follow the index of t_rr_type + * SOURCE, SINK, IPIN, OPIN, CHANX, CHANY, INTRA_CLUSTER_EDGE, NUM_RR_TYPES + * 2. node ptc_num (feature number): from low to high + * The ptc_num only matters when two nodes have the same type + ***********************************************************************/ +static +void sort_rr_graph_edges(t_rr_graph* rr_graph) { + for (int inode = 0; inode < rr_graph->num_rr_nodes; ++inode) { + /* Create a copy of the edges and switches of this node */ + std::vector sorted_edges; + std::vector sorted_switches; + + /* Ensure a clean start */ + sorted_edges.clear(); + sorted_switches.clear(); + + /* Build the vectors w.r.t. to the order of node_type and ptc_num */ + for (int iedge = 0; iedge < rr_graph->rr_node[inode].num_edges; ++iedge) { + /* For blank edges: directly push_back */ + if (0 == sorted_edges.size()) { + sorted_edges.push_back(rr_graph->rr_node[inode].edges[iedge]); + sorted_switches.push_back(rr_graph->rr_node[inode].switches[iedge]); + continue; + } + + /* Start sorting since the edges are not empty */ + size_t insert_pos = sorted_edges.size(); /* the pos to insert. By default, it is the last element */ + size_t i_to_node = rr_graph->rr_node[inode].edges[iedge]; /* node_id of the edge connects to */ + for (size_t jedge = 0; jedge < sorted_edges.size(); ++jedge) { + size_t j_to_node = sorted_edges[jedge]; + /* Sort by node_type and ptc_num */ + if (rr_graph->rr_node[i_to_node].type < rr_graph->rr_node[j_to_node].type) { + /* iedge should be ahead of jedge */ + insert_pos = jedge; + break; /* least type should stay in the front of the vector */ + } else if (rr_graph->rr_node[i_to_node].type == rr_graph->rr_node[j_to_node].type) { + /* Special as track_ids vary, we consider the last track_ids for those node has the same type as inode */ + if (rr_graph->rr_node[i_to_node].type == rr_graph->rr_node[inode].type) { + if (get_track_rr_node_end_track_id(&(rr_graph->rr_node[i_to_node])) + < get_track_rr_node_end_track_id(&(rr_graph->rr_node[j_to_node])) ) { + insert_pos = jedge; + break; /* least type should stay in the front of the vector */ + } + } else if (rr_graph->rr_node[i_to_node].ptc_num < rr_graph->rr_node[j_to_node].ptc_num) { + /* Now a lower ptc_num will win */ + insert_pos = jedge; + break; /* least type should stay in the front of the vector */ + } + } + } + /* We find the position, inserted to the vector */ + sorted_edges.insert(sorted_edges.begin() + insert_pos, i_to_node); + sorted_switches.insert(sorted_switches.begin() + insert_pos, rr_graph->rr_node[inode].switches[iedge]); + } + + /* Overwrite the edges and switches with sorted numbers */ + for (size_t iedge = 0; iedge < sorted_edges.size(); ++iedge) { + rr_graph->rr_node[inode].edges[iedge] = sorted_edges[iedge]; + } + for (size_t iedge = 0; iedge < sorted_switches.size(); ++iedge) { + rr_graph->rr_node[inode].switches[iedge] = sorted_switches[iedge]; + } + } + + return; +} /************************************************************************ * Main function of this file @@ -1019,12 +1088,12 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types, } /************************************************************************ - * 6. Build the connections tile by tile: - * We classify rr_nodes into a general switch block (GSB) data structure - * where we create edges to each rr_nodes in the GSB with respect to - * Fc_in and Fc_out, switch block patterns - * In addition, we will also handle direct-connections: - * Add edges that bridge OPINs and IPINs to the rr_graph + * 6.1 Build the connections tile by tile: + * We classify rr_nodes into a general switch block (GSB) data structure + * where we create edges to each rr_nodes in the GSB with respect to + * Fc_in and Fc_out, switch block patterns + * In addition, we will also handle direct-connections: + * Add edges that bridge OPINs and IPINs to the rr_graph ***********************************************************************/ /* Create edges for a tileable rr_graph */ build_rr_graph_edges(&rr_graph, device_size, grids, device_chan_width, segment_infs, @@ -1032,7 +1101,7 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types, sb_type, Fs); /************************************************************************ - * 7. Build direction connection lists + * 6.2 Build direction connection lists ***********************************************************************/ /* Create data structure of direct-connections */ t_clb_to_clb_directs* clb_to_clb_directs = NULL; @@ -1042,6 +1111,14 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types, build_rr_graph_direct_connections(&rr_graph, device_size, grids, delayless_switch, num_directs, directs, clb_to_clb_directs); + /************************************************************************ + * 6.3 Sort the edges of rr_nodes by node type and ptc_num + * During the edge construction, edges are out of orders, + * which are not easy to build tileable routing architecture + * This step can be skipped when you do not use FPGA X2P + ***********************************************************************/ + sort_rr_graph_edges(&rr_graph); + size_t num_edges = 0; for (int inode = 0; inode < rr_graph.num_rr_nodes; ++inode) { num_edges += rr_graph.rr_node[inode].num_edges; @@ -1053,7 +1130,7 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types, clear_rr_graph_driver_switch(&rr_graph); /************************************************************************ - * 8. Allocate external data structures + * 7. Allocate external data structures * a. cost_index * b. RC tree ***********************************************************************/ @@ -1066,7 +1143,7 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types, wire_to_ipin_switch, base_cost_type); /************************************************************************ - * 9. Sanitizer for the rr_graph, check connectivities of rr_nodes + * 8. Sanitizer for the rr_graph, check connectivities of rr_nodes ***********************************************************************/ /* Print useful information on screen */ @@ -1083,7 +1160,7 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types, /************************************************************************ - * 10. Free all temp stucts + * 9. Free all temp stucts ***********************************************************************/ /* Free all temp structs */ diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_gsb.cpp b/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_gsb.cpp index 0eae4486a..c784ad1d2 100755 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_gsb.cpp +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_gsb.cpp @@ -1108,6 +1108,11 @@ void build_gsb_one_opin_pin2track_map(const t_rr_graph* rr_graph, /* Push the node to actual_track_list */ actual_track_list.push_back(track_list[inode]); } + + /* Go the next segment if offset is zero or actual_track_list is empty */ + if (0 == actual_track_list.size()) { + continue; + } /* Scale Fc */ int actual_Fc = Fc * actual_track_list.size() / chan_width; @@ -1122,8 +1127,12 @@ void build_gsb_one_opin_pin2track_map(const t_rr_graph* rr_graph, track_step = std::max(1, (int)track_step); /* Adapt offset to the range of actual_track_list */ size_t actual_offset = offset % actual_track_list.size(); - /* rotate the track list by an offset */ - std::rotate(actual_track_list.begin(), actual_track_list.begin() + actual_offset, actual_track_list.end()); + + /* No need to rotate if offset is zero */ + if (0 < actual_offset) { + /* rotate the track list by an offset */ + std::rotate(actual_track_list.begin(), actual_track_list.begin() + actual_offset, actual_track_list.end()); + } /* Assign tracks */ int track_cnt = 0; @@ -1248,11 +1257,8 @@ t_pin2track_map build_gsb_opin_to_track_map(t_rr_graph* rr_graph, /* offset counter: it aims to balance the OPIN-to-track for each switch block */ std::vector offset; - for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { - /* Get the chan_side: which is the same as the opin side */ - Side side_manager(side); - offset.resize(side_manager.to_size_t()); - } + /* Get the chan_side: which is the same as the opin side */ + offset.resize(rr_gsb.get_num_sides()); /* Initial offset */ offset.assign(offset.size(), 0); @@ -1275,8 +1281,7 @@ t_pin2track_map build_gsb_opin_to_track_map(t_rr_graph* rr_graph, int grid_type_index = grids[opin_node->xlow][opin_node->ylow].type->index; /* Get Fc of the ipin */ int opin_Fc = Fc_out[grid_type_index][opin_node->ptc_num]; - /* skip Fc = 0 */ - //printf("opin_Fc[%d]=%d\n", opin_node->ptc_num, opin_Fc); + /* skip Fc = 0 or unintialized, those pins are in the */ if ( (-1 == opin_Fc) || (0 == opin_Fc) ) { continue; @@ -1286,8 +1291,8 @@ t_pin2track_map build_gsb_opin_to_track_map(t_rr_graph* rr_graph, /* Give an offset for the first track that this ipin will connect to */ offset[side_manager.to_size_t()], segment_inf, &opin2track_map); - /* update offset */ - offset[side_manager.to_size_t()] += 2; + /* update offset: aim to rotate starting tracks by 1*/ + offset[side_manager.to_size_t()] += 1; } } 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 005770a38..0a34e9ab9 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 @@ -3137,6 +3137,7 @@ void spice_backannotate_vpr_post_route_info(t_det_routing_arch RoutingArch, /* Build previous node lists for each rr_node */ vpr_printf(TIO_MESSAGE_INFO, "Building previous node list for all Routing Resource Nodes...\n"); build_prev_node_list_rr_nodes(num_rr_nodes, rr_node); + //sort_rr_graph_drive_rr_nodes(num_rr_nodes, rr_node); /* Build driver switches for each rr_node*/ vpr_printf(TIO_MESSAGE_INFO, "Identifying driver switches for all Routing Resource Nodes...\n"); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_pbtypes_utils.c b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_pbtypes_utils.c index ed0898f73..748e62ef5 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_pbtypes_utils.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_pbtypes_utils.c @@ -2528,6 +2528,7 @@ void link_one_pb_graph_node_pin_to_phy_pb_graph_pin(t_pb_graph_pin* cur_pb_graph } /* Create the link */ cur_pb_graph_pin->physical_pb_graph_pin = phy_pb_graph_pin; + /* vpr_printf (TIO_MESSAGE_INFO, " match pin (%s[%d]->%s[%d]) to (%s[%d]->%s[%d]) rotate_offset_acc=%d\n", cur_pb_graph_pin->parent_node->pb_type->name, cur_pb_graph_pin->parent_node->placement_index, @@ -2537,6 +2538,7 @@ void link_one_pb_graph_node_pin_to_phy_pb_graph_pin(t_pb_graph_pin* cur_pb_graph phy_pb_graph_pin->port->name, phy_pb_graph_pin->pin_number, cur_pb_graph_pin->port->phy_mode_pin_rotate_offset_acc ); + */ /* Accumulate the phy_mode_pin offset when we have a matched */ if (0 != cur_pb_graph_pin->port->physical_mode_pin_rotate_offset) { cur_pb_graph_pin->port->phy_mode_pin_rotate_offset_acc += cur_pb_graph_pin->port->physical_mode_pin_rotate_offset; diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_rr_graph_utils.c b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_rr_graph_utils.c index e5312fcb4..d3ed17587 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_rr_graph_utils.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_rr_graph_utils.c @@ -10,6 +10,7 @@ #include #include #include +#include /* Include vpr structs*/ #include "util.h" @@ -25,6 +26,8 @@ #include "fpga_x2p_pbtypes_utils.h" #include "fpga_x2p_rr_graph_utils.h" +#include "rr_graph_builder_utils.h" + /* Initial rr_graph */ void init_rr_graph(INOUTP t_rr_graph* local_rr_graph) { /* Give zero and NULL to all the contents */ @@ -954,8 +957,8 @@ void build_prev_node_list_rr_nodes(int LL_num_rr_nodes, if (0 == LL_rr_node[inode].fan_in) { continue; } - LL_rr_node[inode].drive_rr_nodes = (t_rr_node**)my_malloc(sizeof(t_rr_node*)*LL_rr_node[inode].num_drive_rr_nodes); - LL_rr_node[inode].drive_switches = (int*)my_malloc(sizeof(int)*LL_rr_node[inode].num_drive_rr_nodes); + LL_rr_node[inode].drive_rr_nodes = (t_rr_node**)my_malloc(sizeof(t_rr_node*) * LL_rr_node[inode].num_drive_rr_nodes); + LL_rr_node[inode].drive_switches = (int*)my_malloc(sizeof(int) * LL_rr_node[inode].num_drive_rr_nodes); } /* Initialize */ for (inode = 0; inode < LL_num_rr_nodes; inode++) { @@ -985,6 +988,73 @@ void build_prev_node_list_rr_nodes(int LL_num_rr_nodes, return; } +/************************************************************************ + * Sort the drive_rr_nodes by node type and ptc_num + * 1. node type priority: (follow the index of t_rr_type + * SOURCE, SINK, IPIN, OPIN, CHANX, CHANY, INTRA_CLUSTER_EDGE, NUM_RR_TYPES + * 2. node ptc_num (feature number): from low to high + * The ptc_num only matters when two nodes have the same type + ***********************************************************************/ +void sort_rr_graph_drive_rr_nodes(int LL_num_rr_nodes, + t_rr_node* LL_rr_node) { + for (int inode = 0; inode < LL_num_rr_nodes; ++inode) { + /* Create a copy of the edges and switches of this node */ + std::vector sorted_drive_nodes; + std::vector sorted_drive_switches; + + /* Ensure a clean start */ + sorted_drive_nodes.clear(); + sorted_drive_switches.clear(); + + /* Build the vectors w.r.t. to the order of node_type and ptc_num */ + for (int i_from_node = 0; i_from_node < LL_rr_node[inode].num_drive_rr_nodes; ++i_from_node) { + /* For blank edges: directly push_back */ + if (0 == sorted_drive_nodes.size()) { + sorted_drive_nodes.push_back(LL_rr_node[inode].drive_rr_nodes[i_from_node]); + sorted_drive_switches.push_back(LL_rr_node[inode].drive_switches[i_from_node]); + continue; + } + + /* Start sorting since the edges are not empty */ + size_t insert_pos = sorted_drive_nodes.size(); /* the pos to insert. By default, it is the last element */ + for (size_t j_from_node = 0; j_from_node < sorted_drive_nodes.size(); ++j_from_node) { + /* Sort by node_type and ptc_num */ + if (LL_rr_node[inode].drive_rr_nodes[i_from_node]->type < sorted_drive_nodes[j_from_node]->type) { + /* iedge should be ahead of jedge */ + insert_pos = j_from_node; + break; /* least type should stay in the front of the vector */ + } else if (LL_rr_node[inode].drive_rr_nodes[i_from_node]->type == sorted_drive_nodes[j_from_node]->type) { + /* Special as track_ids vary, we consider the last track_ids for those node has the same type as inode */ + if (LL_rr_node[i_from_node].type == LL_rr_node[inode].type) { + if (get_track_rr_node_end_track_id(&(LL_rr_node[i_from_node])) + < get_track_rr_node_end_track_id(&(LL_rr_node[j_from_node])) ) { + insert_pos = j_from_node; + break; /* least type should stay in the front of the vector */ + } + /* Now a lower ptc_num will win */ + } else if (LL_rr_node[inode].drive_rr_nodes[i_from_node]->ptc_num < sorted_drive_nodes[j_from_node]->ptc_num) { + insert_pos = j_from_node; + break; /* least type should stay in the front of the vector */ + } + } + } + /* We find the position, inserted to the vector */ + sorted_drive_nodes.insert(sorted_drive_nodes.begin() + insert_pos, LL_rr_node[inode].drive_rr_nodes[i_from_node]); + sorted_drive_switches.insert(sorted_drive_switches.begin() + insert_pos, LL_rr_node[inode].drive_switches[i_from_node]); + } + + /* Overwrite the edges and switches with sorted numbers */ + for (size_t iedge = 0; iedge < sorted_drive_nodes.size(); ++iedge) { + LL_rr_node[inode].drive_rr_nodes[iedge] = sorted_drive_nodes[iedge]; + } + for (size_t iedge = 0; iedge < sorted_drive_switches.size(); ++iedge) { + LL_rr_node[inode].drive_switches[iedge] = sorted_drive_switches[iedge]; + } + } + + return; +} + void alloc_and_load_prev_node_list_rr_graph_rr_nodes(t_rr_graph* local_rr_graph) { build_prev_node_list_rr_nodes(local_rr_graph->num_rr_nodes, local_rr_graph->rr_node); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_rr_graph_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_rr_graph_utils.h index defd3e569..f7326f439 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_rr_graph_utils.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_rr_graph_utils.h @@ -1,3 +1,5 @@ +#ifndef FPGA_X2P_RR_GRAPH_UTILS_H +#define FPGA_X2P_RR_GRAPH_UTILS_H void init_rr_graph(INOUTP t_rr_graph* local_rr_graph); @@ -89,6 +91,9 @@ void free_rr_graph_traceback(t_rr_graph* local_rr_graph, void build_prev_node_list_rr_nodes(int LL_num_rr_nodes, t_rr_node* LL_rr_node); +void sort_rr_graph_drive_rr_nodes(int LL_num_rr_nodes, + t_rr_node* LL_rr_node); + void alloc_and_load_prev_node_list_rr_graph_rr_nodes(t_rr_graph* local_rr_graph); void backannotate_rr_graph_routing_results_to_net_name(t_rr_graph* local_rr_graph); @@ -106,3 +111,5 @@ void get_chan_rr_node_end_coordinate(t_rr_node* chan_rr_node, int* x_end, int* y_end); int get_rr_node_wire_length(t_rr_node* src_rr_node); + +#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 76ca32ca9..4adc81da9 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 @@ -1247,7 +1247,6 @@ RRGSB rotate_rr_switch_block_for_mirror(DeviceCoordinator& device_range, return rotated_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. @@ -1258,22 +1257,23 @@ DeviceRRGSB build_device_rr_gsb(boolean output_sb_xml, char* sb_xml_dir, t_ivec*** LL_rr_node_indices, int num_segments, t_rr_indexed_data* LL_rr_indexed_data) { /* Create an object */ - DeviceRRGSB LL_drive_rr_gsb; + DeviceRRGSB LL_device_rr_gsb; /* Initialize */ DeviceCoordinator sb_range((size_t)nx, (size_t)ny); DeviceCoordinator reserve_range((size_t)nx + 1, (size_t)ny + 1); - LL_drive_rr_gsb.reserve(reserve_range); + LL_device_rr_gsb.reserve(reserve_range); /* For each switch block, determine the size of array */ for (size_t ix = 0; ix <= sb_range.get_x(); ++ix) { for (size_t iy = 0; iy <= sb_range.get_y(); ++iy) { - RRGSB rr_sb = build_rr_gsb(sb_range, ix, iy, - LL_num_rr_nodes, LL_rr_node, - LL_rr_node_indices, - num_segments, LL_rr_indexed_data); - DeviceCoordinator sb_coordinator = rr_sb.get_sb_coordinator(); - LL_drive_rr_gsb.add_rr_gsb(sb_coordinator, rr_sb); + RRGSB rr_gsb = build_rr_gsb(sb_range, ix, iy, + LL_num_rr_nodes, LL_rr_node, + LL_rr_node_indices, + num_segments, LL_rr_indexed_data); + /* Add to device_rr_gsb */ + DeviceCoordinator sb_coordinator = rr_gsb.get_sb_coordinator(); + LL_device_rr_gsb.add_rr_gsb(sb_coordinator, rr_gsb); } } /* Report number of unique mirrors */ @@ -1283,7 +1283,7 @@ DeviceRRGSB build_device_rr_gsb(boolean output_sb_xml, char* sb_xml_dir, if (TRUE == output_sb_xml) { - write_device_rr_gsb_to_xml(sb_xml_dir, LL_drive_rr_gsb); + write_device_rr_gsb_to_xml(sb_xml_dir, LL_device_rr_gsb); /* Skip rotating mirror searching */ vpr_printf(TIO_MESSAGE_INFO, @@ -1294,36 +1294,36 @@ DeviceRRGSB build_device_rr_gsb(boolean output_sb_xml, char* sb_xml_dir, /* Build a list of unique modules for each Switch Block */ /* Build a list of unique modules for each side of each Switch Block */ - LL_drive_rr_gsb.build_unique_module(); + LL_device_rr_gsb.build_unique_module(); vpr_printf(TIO_MESSAGE_INFO, "Detect %lu routing segments used by switch blocks.\n", - LL_drive_rr_gsb.get_num_segments()); + LL_device_rr_gsb.get_num_segments()); /* Report number of unique CB Modules */ vpr_printf(TIO_MESSAGE_INFO, "Detect %d independent connection blocks from %d X-channel connection blocks.\n", - LL_drive_rr_gsb.get_num_cb_unique_module(CHANX), (nx + 0) * (ny + 1) ); + LL_device_rr_gsb.get_num_cb_unique_module(CHANX), (nx + 0) * (ny + 1) ); vpr_printf(TIO_MESSAGE_INFO, "Detect %d independent connection blocks from %d Y-channel connection blocks.\n", - LL_drive_rr_gsb.get_num_cb_unique_module(CHANY), (nx + 1) * (ny + 0) ); + LL_device_rr_gsb.get_num_cb_unique_module(CHANY), (nx + 1) * (ny + 0) ); /* Report number of unique SB modules */ vpr_printf(TIO_MESSAGE_INFO, "Detect %d independent switch blocks from %d switch blocks.\n", - LL_drive_rr_gsb.get_num_sb_unique_module(), (nx + 1) * (ny + 1) ); + LL_device_rr_gsb.get_num_sb_unique_module(), (nx + 1) * (ny + 1) ); /* Report number of unique mirrors */ - for (size_t side = 0; side < LL_drive_rr_gsb.get_max_num_sides(); ++side) { + for (size_t side = 0; side < LL_device_rr_gsb.get_max_num_sides(); ++side) { Side side_manager(side); /* get segment ids */ - for (size_t iseg = 0; iseg < LL_drive_rr_gsb.get_num_segments(); ++iseg) { + for (size_t iseg = 0; iseg < LL_device_rr_gsb.get_num_segments(); ++iseg) { vpr_printf(TIO_MESSAGE_INFO, "For side %s, segment id %lu: Detect %d independent switch blocks from %d switch blocks.\n", - side_manager.c_str(), LL_drive_rr_gsb.get_segment_id(iseg), - LL_drive_rr_gsb.get_num_sb_unique_submodule(side_manager.get_side(), iseg), + side_manager.c_str(), LL_device_rr_gsb.get_segment_id(iseg), + LL_device_rr_gsb.get_num_sb_unique_submodule(side_manager.get_side(), iseg), (nx + 1) * (ny + 1) ); } } @@ -1335,8 +1335,8 @@ DeviceRRGSB build_device_rr_gsb(boolean output_sb_xml, char* sb_xml_dir, for (size_t ix = 0; ix <= sb_range.get_x(); ++ix) { for (size_t iy = 0; iy <= sb_range.get_y(); ++iy) { - RRGSB rr_sb = LL_drive_rr_gsb.get_gsb(ix, iy); - RRGSB rotated_rr_sb = rotate_rr_switch_block_for_mirror(sb_range, rr_sb); + RRGSB rr_gsb = LL_device_rr_gsb.get_gsb(ix, iy); + RRGSB rotated_rr_sb = rotate_rr_switch_block_for_mirror(sb_range, rr_gsb); if (TRUE == output_sb_xml) { std::string fname_prefix(sb_xml_dir); /* Add slash if needed */ @@ -1345,12 +1345,12 @@ DeviceRRGSB build_device_rr_gsb(boolean output_sb_xml, char* sb_xml_dir, //} //fname_prefix += "rotated_"; //write_rr_switch_block_to_xml(fname_prefix, rotated_rr_sb); - write_rr_switch_block_to_xml(fname_prefix, rr_sb); + write_rr_switch_block_to_xml(fname_prefix, rr_gsb); } } } - return LL_drive_rr_gsb; + return LL_device_rr_gsb; } From 785b560bd5422f775e9bb839ba4c9336a78f96a0 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Mon, 24 Jun 2019 22:46:56 -0600 Subject: [PATCH 20/25] sorted drive_rr_nodes for RR GSBs, #. of SBs should be constant now --- .../rr_graph/tileable_rr_graph_builder.cpp | 5 +- .../fpga_x2p/base/fpga_x2p_unique_routing.c | 189 ++++++++++++++++++ vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.cpp | 31 ++- 3 files changed, 213 insertions(+), 12 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_builder.cpp b/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_builder.cpp index 81a31efd2..582e5a5e7 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_builder.cpp +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_builder.cpp @@ -1117,14 +1117,15 @@ void build_tileable_unidir_rr_graph(INP const int L_num_types, * which are not easy to build tileable routing architecture * This step can be skipped when you do not use FPGA X2P ***********************************************************************/ - sort_rr_graph_edges(&rr_graph); + //sort_rr_graph_edges(&rr_graph); size_t num_edges = 0; for (int inode = 0; inode < rr_graph.num_rr_nodes; ++inode) { num_edges += rr_graph.rr_node[inode].num_edges; } vpr_printf(TIO_MESSAGE_INFO, - "%lu edges of RR graph built.\n", num_edges); + "%lu edges of RR graph built.\n", + num_edges); /* Clear driver switches of the rr_graph */ clear_rr_graph_driver_switch(&rr_graph); 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 4adc81da9..848c35b57 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 @@ -1247,6 +1247,193 @@ RRGSB rotate_rr_switch_block_for_mirror(DeviceCoordinator& device_range, return rotated_rr_switch_block; } +/* sort drive_rr_nodes of a rr_node inside rr_gsb subject to the index of rr_gsb array */ +static +void sort_rr_gsb_one_ipin_node_drive_rr_nodes(const RRGSB& rr_gsb, + t_rr_node* ipin_node, + enum e_side ipin_chan_side) { + /* Create a copy of the edges and switches of this node */ + std::vector sorted_drive_nodes; + std::vector sorted_drive_switches; + + /* Ensure a clean start */ + sorted_drive_nodes.clear(); + sorted_drive_switches.clear(); + + /* Build the vectors w.r.t. to the order of node_type and ptc_num */ + for (int i_from_node = 0; i_from_node < ipin_node->num_drive_rr_nodes; ++i_from_node) { + /* For blank edges: directly push_back */ + if (0 == sorted_drive_nodes.size()) { + sorted_drive_nodes.push_back(ipin_node->drive_rr_nodes[i_from_node]); + sorted_drive_switches.push_back(ipin_node->drive_switches[i_from_node]); + continue; + } + + /* Start sorting since the edges are not empty */ + size_t insert_pos = sorted_drive_nodes.size(); /* the pos to insert. By default, it is the last element */ + for (size_t j_from_node = 0; j_from_node < sorted_drive_nodes.size(); ++j_from_node) { + /* Sort by node_type and ptc_num */ + if (ipin_node->drive_rr_nodes[i_from_node]->type < sorted_drive_nodes[j_from_node]->type) { + /* iedge should be ahead of jedge */ + insert_pos = j_from_node; + break; /* least type should stay in the front of the vector */ + } else if (ipin_node->drive_rr_nodes[i_from_node]->type + == sorted_drive_nodes[j_from_node]->type) { + /* For channel node, we do not know the node direction + * But we are pretty sure it is either IN_PORT or OUT_PORT + * So we just try and find what is valid + */ + enum PORTS i_from_node_direction = IN_PORT; + if (-1 == rr_gsb.get_node_index(ipin_node->drive_rr_nodes[i_from_node], + ipin_chan_side, + IN_PORT)) { + i_from_node_direction = OUT_PORT; + } + enum PORTS j_from_node_direction = IN_PORT; + if (-1 != rr_gsb.get_node_index(sorted_drive_nodes[j_from_node], + ipin_chan_side, + IN_PORT)) { + j_from_node_direction = OUT_PORT; + } + /* Now a lower ptc_num will win */ + if ( rr_gsb.get_node_index(ipin_node->drive_rr_nodes[i_from_node], ipin_chan_side, i_from_node_direction) + < rr_gsb.get_node_index(sorted_drive_nodes[j_from_node], ipin_chan_side, j_from_node_direction) ) { + insert_pos = j_from_node; + break; /* least type should stay in the front of the vector */ + } + } + } + /* We find the position, inserted to the vector */ + sorted_drive_nodes.insert(sorted_drive_nodes.begin() + insert_pos, ipin_node->drive_rr_nodes[i_from_node]); + sorted_drive_switches.insert(sorted_drive_switches.begin() + insert_pos, ipin_node->drive_switches[i_from_node]); + } + + /* Overwrite the edges and switches with sorted numbers */ + for (size_t iedge = 0; iedge < sorted_drive_nodes.size(); ++iedge) { + ipin_node->drive_rr_nodes[iedge] = sorted_drive_nodes[iedge]; + } + for (size_t iedge = 0; iedge < sorted_drive_switches.size(); ++iedge) { + ipin_node->drive_switches[iedge] = sorted_drive_switches[iedge]; + } + + return; +} + +/* sort drive_rr_nodes of a rr_node inside rr_gsb subject to the index of rr_gsb array */ +static +void sort_rr_gsb_one_chan_node_drive_rr_nodes(const RRGSB& rr_gsb, + t_rr_node* chan_node, + enum e_side chan_side) { + + /* If this is a passing wire, we return directly. + * The passing wire will be handled in other GSBs + */ + if (true == rr_gsb.is_sb_node_imply_short_connection(chan_node)) { + /* Double check if the interc lies inside a channel wire, that is interc between segments */ + assert(true == rr_gsb.is_sb_node_exist_opposite_side(chan_node, chan_side)); + return; + } + + /* Create a copy of the edges and switches of this node */ + std::vector sorted_drive_nodes; + std::vector sorted_drive_switches; + + /* Ensure a clean start */ + sorted_drive_nodes.clear(); + sorted_drive_switches.clear(); + + /* Build the vectors w.r.t. to the order of node_type and ptc_num */ + for (int i_from_node = 0; i_from_node < chan_node->num_drive_rr_nodes; ++i_from_node) { + /* For blank edges: directly push_back */ + if (0 == sorted_drive_nodes.size()) { + sorted_drive_nodes.push_back(chan_node->drive_rr_nodes[i_from_node]); + sorted_drive_switches.push_back(chan_node->drive_switches[i_from_node]); + continue; + } + + /* Start sorting since the edges are not empty */ + size_t insert_pos = sorted_drive_nodes.size(); /* the pos to insert. By default, it is the last element */ + for (size_t j_from_node = 0; j_from_node < sorted_drive_nodes.size(); ++j_from_node) { + /* Sort by node_type and ptc_num */ + if (chan_node->drive_rr_nodes[i_from_node]->type < sorted_drive_nodes[j_from_node]->type) { + /* iedge should be ahead of jedge */ + insert_pos = j_from_node; + break; /* least type should stay in the front of the vector */ + } else if (chan_node->drive_rr_nodes[i_from_node]->type + == sorted_drive_nodes[j_from_node]->type) { + /* For channel node, we do not know the node direction + * But we are pretty sure it is either IN_PORT or OUT_PORT + * So we just try and find what is valid + */ + enum e_side i_from_node_side = NUM_SIDES; + int i_from_node_index = -1; + rr_gsb.get_node_side_and_index(chan_node->drive_rr_nodes[i_from_node], + IN_PORT, &i_from_node_side, &i_from_node_index); + /* check */ + if (! ( (NUM_SIDES != i_from_node_side) && (-1 != i_from_node_index) ) ) + assert ( (NUM_SIDES != i_from_node_side) && (-1 != i_from_node_index) ); + + enum e_side j_from_node_side = NUM_SIDES; + int j_from_node_index = -1; + rr_gsb.get_node_side_and_index(sorted_drive_nodes[j_from_node], + IN_PORT, &j_from_node_side, &j_from_node_index); + /* check */ + assert ( (NUM_SIDES != j_from_node_side) && (-1 != j_from_node_index) ); + /* Now a lower ptc_num will win */ + if ( i_from_node_index < j_from_node_index) { + insert_pos = j_from_node; + break; /* least type should stay in the front of the vector */ + } + } + } + /* We find the position, inserted to the vector */ + sorted_drive_nodes.insert(sorted_drive_nodes.begin() + insert_pos, chan_node->drive_rr_nodes[i_from_node]); + sorted_drive_switches.insert(sorted_drive_switches.begin() + insert_pos, chan_node->drive_switches[i_from_node]); + } + + /* Overwrite the edges and switches with sorted numbers */ + for (size_t iedge = 0; iedge < sorted_drive_nodes.size(); ++iedge) { + chan_node->drive_rr_nodes[iedge] = sorted_drive_nodes[iedge]; + } + for (size_t iedge = 0; iedge < sorted_drive_switches.size(); ++iedge) { + chan_node->drive_switches[iedge] = sorted_drive_switches[iedge]; + } + + return; + +} + +/* sort drive_rr_nodes of each rr_node subject to the index of rr_gsb array */ +static +void sort_rr_gsb_drive_rr_nodes(const RRGSB& rr_gsb) { + /* Sort the drive_rr_nodes for each rr_node */ + for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { + Side gsb_side_manager(side); + enum e_side gsb_side = gsb_side_manager.get_side(); + /* For IPIN node: sort drive_rr_nodes according to the index in the routing channels */ + for (size_t inode = 0; inode < rr_gsb.get_num_ipin_nodes(gsb_side); ++inode) { + /* Get the chan side, so we have the routing tracks */ + enum e_side ipin_chan_side = rr_gsb.get_cb_chan_side(gsb_side); + sort_rr_gsb_one_ipin_node_drive_rr_nodes(rr_gsb, + rr_gsb.get_ipin_node(gsb_side, inode), + ipin_chan_side); + } + /* For CHANX | CHANY node: sort drive_rr_nodes according to the index in the routing channels */ + for (size_t inode = 0; inode < rr_gsb.get_chan_width(gsb_side); ++inode) { + /* Bypass IN_PORT */ + if (IN_PORT == rr_gsb.get_chan_node_direction(gsb_side, inode)) { + continue; + } + /* Get the chan side, so we have the routing tracks */ + sort_rr_gsb_one_chan_node_drive_rr_nodes(rr_gsb, + rr_gsb.get_chan_node(gsb_side, inode), + gsb_side); + } + } + + return; +} + /* 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. @@ -1271,6 +1458,8 @@ DeviceRRGSB build_device_rr_gsb(boolean output_sb_xml, char* sb_xml_dir, LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices, num_segments, LL_rr_indexed_data); + /* sort drive_rr_nodes */ + sort_rr_gsb_drive_rr_nodes(rr_gsb); /* Add to device_rr_gsb */ DeviceCoordinator sb_coordinator = rr_gsb.get_sb_coordinator(); LL_device_rr_gsb.add_rr_gsb(sb_coordinator, rr_gsb); 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 1232d1fed..fcc60d57a 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.cpp @@ -1882,8 +1882,10 @@ void RRGSB::mirror_side_chan_node_direction(enum e_side side) { void RRGSB::swap_chan_node(enum e_side src_side, enum e_side des_side) { Side src_side_manager(src_side); Side des_side_manager(des_side); - std::swap(chan_node_[src_side_manager.to_size_t()], chan_node_[des_side_manager.to_size_t()]); - std::swap(chan_node_direction_[src_side_manager.to_size_t()], chan_node_direction_[des_side_manager.to_size_t()]); + std::swap(chan_node_[src_side_manager.to_size_t()], + chan_node_[des_side_manager.to_size_t()]); + std::swap(chan_node_direction_[src_side_manager.to_size_t()], + chan_node_direction_[des_side_manager.to_size_t()]); return; } @@ -1891,8 +1893,10 @@ void RRGSB::swap_chan_node(enum e_side src_side, enum e_side des_side) { void RRGSB::swap_opin_node(enum e_side src_side, enum e_side des_side) { Side src_side_manager(src_side); Side des_side_manager(des_side); - std::swap(opin_node_[src_side_manager.to_size_t()], opin_node_[des_side_manager.to_size_t()]); - std::swap(opin_node_grid_side_[src_side_manager.to_size_t()], opin_node_grid_side_[des_side_manager.to_size_t()]); + std::swap(opin_node_[src_side_manager.to_size_t()], + opin_node_[des_side_manager.to_size_t()]); + std::swap(opin_node_grid_side_[src_side_manager.to_size_t()], + opin_node_grid_side_[des_side_manager.to_size_t()]); return; } @@ -1900,27 +1904,34 @@ void RRGSB::swap_opin_node(enum e_side src_side, enum e_side des_side) { void RRGSB::swap_ipin_node(enum e_side src_side, enum e_side des_side) { Side src_side_manager(src_side); Side des_side_manager(des_side); - std::swap(ipin_node_[src_side_manager.to_size_t()], ipin_node_[des_side_manager.to_size_t()]); - std::swap(ipin_node_grid_side_[src_side_manager.to_size_t()], ipin_node_grid_side_[des_side_manager.to_size_t()]); + std::swap(ipin_node_[src_side_manager.to_size_t()], + ipin_node_[des_side_manager.to_size_t()]); + std::swap(ipin_node_grid_side_[src_side_manager.to_size_t()], + ipin_node_grid_side_[des_side_manager.to_size_t()]); return; } /* Reverse the vector of the OPIN rr_nodes on a side */ void RRGSB::reverse_opin_node(enum e_side side) { Side side_manager(side); - std::reverse(opin_node_[side_manager.to_size_t()].begin(), opin_node_[side_manager.to_size_t()].end()); - std::reverse(opin_node_grid_side_[side_manager.to_size_t()].begin(), opin_node_grid_side_[side_manager.to_size_t()].end()); + std::reverse(opin_node_[side_manager.to_size_t()].begin(), + opin_node_[side_manager.to_size_t()].end()); + std::reverse(opin_node_grid_side_[side_manager.to_size_t()].begin(), + opin_node_grid_side_[side_manager.to_size_t()].end()); return; } /* Reverse the vector of the OPIN rr_nodes on a side */ void RRGSB::reverse_ipin_node(enum e_side side) { Side side_manager(side); - std::reverse(ipin_node_[side_manager.to_size_t()].begin(), ipin_node_[side_manager.to_size_t()].end()); - std::reverse(ipin_node_grid_side_[side_manager.to_size_t()].begin(), ipin_node_grid_side_[side_manager.to_size_t()].end()); + std::reverse(ipin_node_[side_manager.to_size_t()].begin(), + ipin_node_[side_manager.to_size_t()].end()); + std::reverse(ipin_node_grid_side_[side_manager.to_size_t()].begin(), + ipin_node_grid_side_[side_manager.to_size_t()].end()); return; } +/* Reset the RRGSB to pristine state */ void RRGSB::clear() { /* Clean all the vectors */ assert(validate_num_sides()); From a88263a4c260d716192ef38747ed805c98550ae9 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 25 Jun 2019 11:17:22 -0600 Subject: [PATCH 21/25] update rr_block writer to include IPINs in XML files --- .../fpga_x2p/base/fpga_x2p_unique_routing.c | 23 +---- vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.cpp | 36 ++++++++ vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.h | 4 + .../vpr/SRC/fpga_x2p/base/write_rr_blocks.cpp | 92 +++++++++++++------ .../vpr/SRC/fpga_x2p/base/write_rr_blocks.h | 2 +- 5 files changed, 110 insertions(+), 47 deletions(-) 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 848c35b57..11a15bdea 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 @@ -1279,25 +1279,12 @@ void sort_rr_gsb_one_ipin_node_drive_rr_nodes(const RRGSB& rr_gsb, break; /* least type should stay in the front of the vector */ } else if (ipin_node->drive_rr_nodes[i_from_node]->type == sorted_drive_nodes[j_from_node]->type) { - /* For channel node, we do not know the node direction - * But we are pretty sure it is either IN_PORT or OUT_PORT - * So we just try and find what is valid - */ - enum PORTS i_from_node_direction = IN_PORT; - if (-1 == rr_gsb.get_node_index(ipin_node->drive_rr_nodes[i_from_node], - ipin_chan_side, - IN_PORT)) { - i_from_node_direction = OUT_PORT; - } - enum PORTS j_from_node_direction = IN_PORT; - if (-1 != rr_gsb.get_node_index(sorted_drive_nodes[j_from_node], - ipin_chan_side, - IN_PORT)) { - j_from_node_direction = OUT_PORT; - } + int i_from_node_track_index = rr_gsb.get_chan_node_index(ipin_chan_side, ipin_node->drive_rr_nodes[i_from_node]); + int j_from_node_track_index = rr_gsb.get_chan_node_index(ipin_chan_side, sorted_drive_nodes[j_from_node]); + /* We must have a valide node index */ + assert ( (-1 != i_from_node_track_index) && (-1 != j_from_node_track_index) ); /* Now a lower ptc_num will win */ - if ( rr_gsb.get_node_index(ipin_node->drive_rr_nodes[i_from_node], ipin_chan_side, i_from_node_direction) - < rr_gsb.get_node_index(sorted_drive_nodes[j_from_node], ipin_chan_side, j_from_node_direction) ) { + if ( i_from_node_track_index < j_from_node_track_index ) { insert_pos = j_from_node; break; /* least type should stay in the front of the vector */ } 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 fcc60d57a..2669e2e0a 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.cpp @@ -1258,6 +1258,17 @@ bool RRGSB::is_sb_mirror(const RRGSB& cand) const { /* Public Accessors: Cooridinator conversion */ +/* get the x coordinator of this GSB */ +size_t RRGSB::get_x() const { + return coordinator_.get_x(); +} + +/* get the y coordinator of this GSB */ +size_t RRGSB::get_y() const { + return coordinator_.get_y(); +} + + /* get the x coordinator of this switch block */ size_t RRGSB::get_sb_x() const { return coordinator_.get_x(); @@ -1431,6 +1442,21 @@ const char* RRGSB::gen_sb_verilog_module_name() const { return ret; } +const char* RRGSB::gen_gsb_verilog_module_name() const { + std::string x_str = std::to_string(get_sb_x()); + std::string y_str = std::to_string(get_sb_y()); + + char* ret = (char*)my_malloc(sizeof(char)* + ( 2 + 1 + + x_str.length() + 2 + + y_str.length() + 1 + + 1)); + sprintf (ret, "gsb_%s__%s_", + x_str.c_str(), y_str.c_str()); + + return ret; +} + const char* RRGSB::gen_sb_verilog_instance_name() const { char* ret = (char*)my_malloc(sizeof(char)* ( strlen(gen_sb_verilog_module_name()) + 3 @@ -1441,6 +1467,16 @@ const char* RRGSB::gen_sb_verilog_instance_name() const { return ret; } +const char* RRGSB::gen_gsb_verilog_instance_name() const { + char* ret = (char*)my_malloc(sizeof(char)* + ( strlen(gen_gsb_verilog_module_name()) + 3 + + 1)); + sprintf (ret, "%s_0_", + gen_gsb_verilog_module_name()); + + return ret; +} + /* Public Accessors Verilog writer */ const char* RRGSB::gen_sb_verilog_side_module_name(enum e_side side, size_t seg_id) const { Side side_manager(side); 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 1b1e5b5fd..7128cc996 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.h @@ -228,6 +228,8 @@ class RRGSB { bool is_cb_exist(t_rr_type cb_type) const; /* check if the candidate SB is a mirror of the current one */ size_t get_hint_rotate_offset(const RRGSB& cand) const; /* Determine an initial offset in rotating the candidate Switch Block to find a mirror matching*/ public: /* Cooridinator conversion and output */ + size_t get_x() const; /* get the x coordinator of this switch block */ + size_t get_y() const; /* get the y coordinator of this switch block */ size_t get_sb_x() const; /* get the x coordinator of this switch block */ size_t get_sb_y() const; /* get the y coordinator of this switch block */ DeviceCoordinator get_sb_coordinator() const; /* Get the coordinator of the SB */ @@ -239,6 +241,8 @@ class RRGSB { DeviceCoordinator get_side_block_coordinator(enum e_side side) const; DeviceCoordinator get_grid_coordinator() const; public: /* Verilog writer */ + const char* gen_gsb_verilog_module_name() const; + const char* gen_gsb_verilog_instance_name() const; const char* gen_sb_verilog_module_name() const; const char* gen_sb_verilog_instance_name() const; const char* gen_sb_verilog_side_module_name(enum e_side side, size_t seg_id) const; diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/write_rr_blocks.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/base/write_rr_blocks.cpp index fe525d6ab..2357bfd50 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/write_rr_blocks.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/write_rr_blocks.cpp @@ -11,10 +11,10 @@ #include "write_rr_blocks.h" -void write_rr_switch_block_to_xml(std::string fname_prefix, RRGSB& rr_sb) { +void write_rr_switch_block_to_xml(std::string fname_prefix, RRGSB& rr_gsb) { /* Prepare file name */ std::string fname(fname_prefix); - fname += rr_sb.gen_sb_verilog_module_name(); + fname += rr_gsb.gen_gsb_verilog_module_name(); fname += ".xml"; vpr_printf(TIO_MESSAGE_INFO, "Output SB XML: %s\r", fname.c_str()); @@ -25,30 +25,69 @@ void write_rr_switch_block_to_xml(std::string fname_prefix, RRGSB& rr_sb) { fp.open(fname, std::fstream::out | std::fstream::trunc); /* Output location of the Switch Block */ - fp << "" << std::endl; + fp << "" << std::endl; /* Output each side */ - for (size_t side = 0; side < rr_sb.get_num_sides(); ++side) { - Side side_manager(side); + for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { + Side gsb_side_manager(side); + enum e_side gsb_side = gsb_side; + + /* Output IPIN nodes */ + for (size_t inode = 0; inode < rr_gsb.get_num_ipin_nodes(gsb_side); ++inode) { + t_rr_node* cur_rr_node = rr_gsb.get_ipin_node(gsb_side, inode); + /* General information of this IPIN */ + fp << "\t<" << rr_node_typename[cur_rr_node->type] + << " side=\"" << gsb_side_manager.to_string() + << "\" index=\"" << inode + << "\" mux_size=\"" << cur_rr_node->num_drive_rr_nodes + << "\">" + << std::endl; + /* General information of each driving nodes */ + for (int jnode = 0; jnode < cur_rr_node->num_drive_rr_nodes; ++jnode) { + enum e_side chan_side = rr_gsb.get_cb_chan_side(gsb_side); + Side chan_side_manager(chan_side); + + /* For channel node, we do not know the node direction + * But we are pretty sure it is either IN_PORT or OUT_PORT + * So we just try and find what is valid + */ + int drive_node_index = rr_gsb.get_chan_node_index(chan_side, cur_rr_node->drive_rr_nodes[jnode]); + /* We must have a valide node index */ + assert (-1 != drive_node_index); + + size_t des_segment_id = rr_gsb.get_chan_node_segment(chan_side, drive_node_index); + + fp << "\t\tdrive_rr_nodes[jnode]->type] + << "\" side=\"" << chan_side_manager.to_string() + << "\" index=\"" << drive_node_index + << "\" segment_id=\"" << des_segment_id + << "\"/>" + << std::endl; + } + fp << "\ttype] + << ">" + << std::endl; + } + /* Output chan nodes */ - for (size_t inode = 0; inode < rr_sb.get_chan_width(side_manager.get_side()); ++inode) { + for (size_t inode = 0; inode < rr_gsb.get_chan_width(gsb_side); ++inode) { /* We only care OUT_PORT */ - if (OUT_PORT != rr_sb.get_chan_node_direction(side_manager.get_side(), inode)) { + if (OUT_PORT != rr_gsb.get_chan_node_direction(gsb_side, inode)) { continue; } /* Output drivers */ size_t num_drive_rr_nodes = 0; t_rr_node** drive_rr_nodes = 0; - t_rr_node* cur_rr_node = rr_sb.get_chan_node(side_manager.get_side(), inode); + t_rr_node* cur_rr_node = rr_gsb.get_chan_node(gsb_side, inode); /* Output node information: location, index, side */ - size_t src_segment_id = rr_sb.get_chan_node_segment(side_manager.get_side(), inode); + size_t src_segment_id = rr_gsb.get_chan_node_segment(gsb_side, inode); /* Check if this node is directly connected to the node on the opposite side */ - if (true == rr_sb.is_sb_node_imply_short_connection(cur_rr_node)) { + if (true == rr_gsb.is_sb_node_imply_short_connection(cur_rr_node)) { /* Double check if the interc lies inside a channel wire, that is interc between segments */ - assert(true == rr_sb.is_sb_node_exist_opposite_side(cur_rr_node, side_manager.get_side())); + assert(true == rr_gsb.is_sb_node_exist_opposite_side(cur_rr_node, gsb_side)); num_drive_rr_nodes = 0; drive_rr_nodes = NULL; } else { @@ -56,8 +95,8 @@ void write_rr_switch_block_to_xml(std::string fname_prefix, RRGSB& rr_sb) { drive_rr_nodes = cur_rr_node->drive_rr_nodes; } - fp << "\t<" << convert_chan_type_to_string(cur_rr_node->type) - << " side=\"" << side_manager.to_string() + fp << "\t<" << rr_node_typename[cur_rr_node->type] + << " side=\"" << gsb_side_manager.to_string() << "\" index=\"" << inode << "\" segment_id=\"" << src_segment_id << "\" mux_size=\"" << num_drive_rr_nodes @@ -66,10 +105,10 @@ void write_rr_switch_block_to_xml(std::string fname_prefix, RRGSB& rr_sb) { /* Direct connection: output the node on the opposite side */ if (0 == num_drive_rr_nodes) { - Side oppo_side = side_manager.get_opposite(); - fp << "\t\ttype) + Side oppo_side = gsb_side_manager.get_opposite(); + fp << "\t\ttype] << "\" side=\"" << oppo_side.to_string() - << "\" index=\"" << rr_sb.get_node_index(cur_rr_node, oppo_side.get_side(), IN_PORT) + << "\" index=\"" << rr_gsb.get_node_index(cur_rr_node, oppo_side.get_side(), IN_PORT) << "\" segment_id=\"" << src_segment_id << "\"/>" << std::endl; @@ -77,22 +116,19 @@ void write_rr_switch_block_to_xml(std::string fname_prefix, RRGSB& rr_sb) { for (size_t jnode = 0; jnode < num_drive_rr_nodes; ++jnode) { enum e_side drive_node_side = NUM_SIDES; int drive_node_index = -1; - rr_sb.get_node_side_and_index(drive_rr_nodes[jnode], IN_PORT, &drive_node_side, &drive_node_index); + rr_gsb.get_node_side_and_index(drive_rr_nodes[jnode], IN_PORT, &drive_node_side, &drive_node_index); Side drive_side(drive_node_side); - std::string node_type_str; if (OPIN == drive_rr_nodes[jnode]->type) { - node_type_str = "opin"; - Side grid_side(rr_sb.get_opin_node_grid_side(drive_node_side, drive_node_index)); - fp << "\t\t" << std::endl; } else { - node_type_str = convert_chan_type_to_string(drive_rr_nodes[jnode]->type); - size_t des_segment_id = rr_sb.get_chan_node_segment(drive_node_side, drive_node_index); - fp << "\t\ttype] << "\" side=\"" << drive_side.to_string() << "\" index=\"" << drive_node_index << "\" segment_id=\"" << des_segment_id @@ -107,7 +143,7 @@ void write_rr_switch_block_to_xml(std::string fname_prefix, RRGSB& rr_sb) { } } - fp << "" + fp << "" << std::endl; /* close a file */ @@ -130,8 +166,8 @@ void write_device_rr_gsb_to_xml(char* sb_xml_dir, /* For each switch block, an XML file will be outputted */ for (size_t ix = 0; ix < sb_range.get_x(); ++ix) { for (size_t iy = 0; iy < sb_range.get_y(); ++iy) { - RRGSB rr_sb = LL_device_rr_gsb.get_gsb(ix, iy); - write_rr_switch_block_to_xml(fname_prefix, rr_sb); + RRGSB rr_gsb = LL_device_rr_gsb.get_gsb(ix, iy); + write_rr_switch_block_to_xml(fname_prefix, rr_gsb); } } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/write_rr_blocks.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/write_rr_blocks.h index 49001e6ee..803b9aa5e 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/write_rr_blocks.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/write_rr_blocks.h @@ -1,7 +1,7 @@ #ifndef WRITE_RR_BLOCKS_H #define WRITE_RR_BLOCKS_H -void write_rr_switch_block_to_xml(std::string fname_prefix, RRGSB& rr_sb); +void write_rr_switch_block_to_xml(std::string fname_prefix, RRGSB& rr_gsb); void write_device_rr_gsb_to_xml(char* sb_xml_dir, DeviceRRGSB& LL_device_rr_gsb); From 4d3b5f12b4bab4ed501ca885e978181e12c7b95d Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 25 Jun 2019 14:15:29 -0600 Subject: [PATCH 22/25] fixed bugs for UNIVERSAL and WILTON switch blocks --- .../k6_N10_sram_chain_HC_template.xml | 2 +- .../rr_graph/rr_graph_builder_utils.cpp | 85 +++++++ .../device/rr_graph/rr_graph_builder_utils.h | 5 + .../device/rr_graph/tileable_rr_graph_gsb.cpp | 85 ++++--- .../fpga_x2p/base/fpga_x2p_unique_routing.c | 228 ++++-------------- vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.cpp | 2 +- .../vpr/SRC/fpga_x2p/base/write_rr_blocks.cpp | 4 +- 7 files changed, 196 insertions(+), 215 deletions(-) diff --git a/fpga_flow/arch/template/k6_N10_sram_chain_HC_template.xml b/fpga_flow/arch/template/k6_N10_sram_chain_HC_template.xml index a56d6b3cb..06e75d911 100644 --- a/fpga_flow/arch/template/k6_N10_sram_chain_HC_template.xml +++ b/fpga_flow/arch/template/k6_N10_sram_chain_HC_template.xml @@ -150,7 +150,7 @@ - + diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_builder_utils.cpp b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_builder_utils.cpp index aa08c67fd..ecab27502 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_builder_utils.cpp +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_builder_utils.cpp @@ -255,6 +255,91 @@ void add_one_edge_for_two_rr_nodes(const t_rr_graph* rr_graph, return; } + +/************************************************************************ + * Add a set of edges for a source rr_node + * For src rr_node, update the edge list and update switch_id, + * For des rr_node, update the fan_in + ***********************************************************************/ +void add_edges_for_two_rr_nodes(const t_rr_graph* rr_graph, + const int src_rr_node_id, + const std::vector des_rr_node_ids, + const std::vector driver_switches) { + /* Check src_rr_node id is in range */ + assert ( (-1 < src_rr_node_id) && (src_rr_node_id < rr_graph->num_rr_nodes) ); + + t_rr_node* src_rr_node = &(rr_graph->rr_node[src_rr_node_id]); + + /* Check des_rr_node and driver_switches should match in size */ + assert ( des_rr_node_ids.size() == driver_switches.size() ); + + /* Get a stamp of the current num_edges of src_rr_node */ + int start_edge_id = src_rr_node->num_edges; + + /* To avoid adding redundant edges, + * we will search the edge list and + * check if each des_rr_node_id already exists + * We rebuild a vector des_rr_node_ids_to_add where redundancy is removed + */ + std::vector des_rr_node_ids_to_add; + std::vector driver_switches_to_add; + for (size_t inode = 0; inode < des_rr_node_ids.size(); ++inode) { + /* search */ + bool is_redundant = false; + for (int iedge = 0; iedge < src_rr_node->num_edges; ++iedge) { + if (des_rr_node_ids[inode] == src_rr_node->edges[iedge]) { + is_redundant = true; + break; + } + } + /* add or skip */ + if (true == is_redundant) { + continue; /* go to the next */ + } + assert (false == is_redundant); + /* add to the list */ + des_rr_node_ids_to_add.push_back(des_rr_node_ids[inode]); + driver_switches_to_add.push_back(driver_switches[inode]); + } + + /* Allocate edge and switch to src_rr_node */ + src_rr_node->num_edges += des_rr_node_ids_to_add.size(); + if (NULL == src_rr_node->edges) { + /* calloc */ + src_rr_node->edges = (int*) my_calloc( src_rr_node->num_edges, sizeof(int) ); + src_rr_node->switches = (short*) my_calloc( src_rr_node->num_edges, sizeof(short) ); + } else { + /* realloc */ + src_rr_node->edges = (int*) my_realloc(src_rr_node->edges, + src_rr_node->num_edges * sizeof(int)); + src_rr_node->switches = (short*) my_realloc(src_rr_node->switches, + src_rr_node->num_edges * sizeof(short)); + } + + for (size_t inode = 0; inode < des_rr_node_ids_to_add.size(); ++inode) { + /* Check des_rr_node id is in range */ + int des_rr_node_id = des_rr_node_ids_to_add[inode]; + assert ( (-1 < des_rr_node_id) && (des_rr_node_id < rr_graph->num_rr_nodes) ); + + t_rr_node* des_rr_node = &(rr_graph->rr_node[des_rr_node_id]); + + /* Fill edge and switch info */ + src_rr_node->edges[start_edge_id] = des_rr_node_id; + src_rr_node->switches[start_edge_id] = driver_switches_to_add[inode]; + + /* Update the des_rr_node */ + des_rr_node->fan_in++; + /* Increment the start_edge_id */ + start_edge_id++; + } + + /* Check */ + assert( start_edge_id == src_rr_node->num_edges ); + + return; + +} + /************************************************************************ * Get the coordinator of a starting point of a routing track * For routing tracks in INC_DIRECTION diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_builder_utils.h b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_builder_utils.h index 07ed2f543..6c5471b5c 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_builder_utils.h +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_builder_utils.h @@ -30,6 +30,11 @@ void add_one_edge_for_two_rr_nodes(const t_rr_graph* rr_graph, const int des_rr_node_id, const short switch_id); +void add_edges_for_two_rr_nodes(const t_rr_graph* rr_graph, + const int src_rr_node_id, + const std::vector des_rr_node, + const std::vector driver_switches); + DeviceCoordinator get_track_rr_node_start_coordinator(const t_rr_node* track_rr_node); DeviceCoordinator get_track_rr_node_end_coordinator(const t_rr_node* track_rr_node); diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_gsb.cpp b/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_gsb.cpp index c784ad1d2..f039a687f 100755 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_gsb.cpp +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_gsb.cpp @@ -209,6 +209,9 @@ bool is_gsb_in_track_sb_population(const RRGSB& rr_gsb, static std::vector get_to_track_list(const int Fs, const int to_track, const int num_to_tracks) { std::vector to_tracks; + /* Ensure a clear start */ + to_tracks.clear(); + for (int i = 0; i < Fs; i = i + 3) { /* TODO: currently, for Fs > 3, I always search the next from_track until Fs is satisfied * The optimal track selection should be done in a more scientific way!!! @@ -244,6 +247,8 @@ std::vector get_switch_block_to_track_id(const enum e_switch_block_type * connect. It supports any Fs % 3 == 0, switch blocks. */ std::vector to_tracks; + /* Ensure a clear start */ + to_tracks.clear(); /* TODO: currently, for Fs > 3, I always search the next from_track until Fs is satisfied * The optimal track selection should be done in a more scientific way!!! @@ -251,9 +256,12 @@ std::vector get_switch_block_to_track_id(const enum e_switch_block_type assert (0 == Fs % 3); + /* Adapt from_track to fit in the range of num_to_tracks */ + size_t actual_from_track = from_track % num_to_tracks; + switch (switch_block_type) { case SUBSET: /* NB: Global routing uses SUBSET too */ - to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); + to_tracks = get_to_track_list(Fs, actual_from_track, num_to_tracks); /* Finish, we return */ return to_tracks; case UNIVERSAL: @@ -266,9 +274,9 @@ std::vector get_switch_block_to_track_id(const enum e_switch_block_type Side side_manager(from_side); if ( (to_side == side_manager.get_opposite()) || (to_side == side_manager.get_rotate_counterclockwise()) ) { - to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); + to_tracks = get_to_track_list(Fs, actual_from_track, num_to_tracks); } else if (to_side == side_manager.get_rotate_clockwise()) { - to_tracks = get_to_track_list(Fs, num_to_tracks - 1 - from_track, num_to_tracks); + to_tracks = get_to_track_list(Fs, num_to_tracks - 1 - actual_from_track, num_to_tracks); } } @@ -281,9 +289,9 @@ std::vector get_switch_block_to_track_id(const enum e_switch_block_type Side side_manager(from_side); if ( (to_side == side_manager.get_opposite()) || (to_side == side_manager.get_rotate_clockwise()) ) { - to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); + to_tracks = get_to_track_list(Fs, actual_from_track, num_to_tracks); } else if (to_side == side_manager.get_rotate_counterclockwise()) { - to_tracks = get_to_track_list(Fs, num_to_tracks - 1 - from_track, num_to_tracks); + to_tracks = get_to_track_list(Fs, num_to_tracks - 1 - actual_from_track, num_to_tracks); } } /* Finish, we return */ @@ -293,35 +301,35 @@ std::vector get_switch_block_to_track_id(const enum e_switch_block_type /* See S. Wilton Phd thesis, U of T, 1996 p. 103 for details on following. */ if (from_side == LEFT) { if (to_side == RIGHT) { /* CHANX to CHANX */ - to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); + to_tracks = get_to_track_list(Fs, actual_from_track, num_to_tracks); } else if (to_side == TOP) { /* from CHANX to CHANY */ - to_tracks = get_to_track_list(Fs, (num_to_tracks - (from_track % num_to_tracks)) % num_to_tracks, num_to_tracks); + to_tracks = get_to_track_list(Fs, (num_to_tracks - actual_from_track ) % num_to_tracks, num_to_tracks); } else if (to_side == BOTTOM) { - to_tracks = get_to_track_list(Fs, (num_to_tracks + from_track - 1) % num_to_tracks, num_to_tracks); + to_tracks = get_to_track_list(Fs, (num_to_tracks + actual_from_track - 1) % num_to_tracks, num_to_tracks); } } else if (from_side == RIGHT) { if (to_side == LEFT) { /* CHANX to CHANX */ - to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); + to_tracks = get_to_track_list(Fs, actual_from_track, num_to_tracks); } else if (to_side == TOP) { /* from CHANX to CHANY */ - to_tracks = get_to_track_list(Fs, (num_to_tracks + from_track - 1) % num_to_tracks, num_to_tracks); + to_tracks = get_to_track_list(Fs, (num_to_tracks + actual_from_track - 1) % num_to_tracks, num_to_tracks); } else if (to_side == BOTTOM) { - to_tracks = get_to_track_list(Fs, (num_to_tracks - 2 - from_track) % num_to_tracks, num_to_tracks); + to_tracks = get_to_track_list(Fs, (2 * num_to_tracks - 2 - actual_from_track) % num_to_tracks, num_to_tracks); } } else if (from_side == BOTTOM) { if (to_side == TOP) { /* CHANY to CHANY */ - to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); + to_tracks = get_to_track_list(Fs, actual_from_track, num_to_tracks); } else if (to_side == LEFT) { /* from CHANY to CHANX */ - to_tracks = get_to_track_list(Fs, (from_track + 1) % num_to_tracks, num_to_tracks); + to_tracks = get_to_track_list(Fs, (actual_from_track + 1) % num_to_tracks, num_to_tracks); } else if (to_side == RIGHT) { - to_tracks = get_to_track_list(Fs, (2 * num_to_tracks - 2 - from_track) % num_to_tracks, num_to_tracks); + to_tracks = get_to_track_list(Fs, (2 * num_to_tracks - 2 - actual_from_track) % num_to_tracks, num_to_tracks); } } else if (from_side == TOP) { if (to_side == BOTTOM) { /* CHANY to CHANY */ to_tracks = get_to_track_list(Fs, from_track, num_to_tracks); } else if (to_side == LEFT) { /* from CHANY to CHANX */ - to_tracks = get_to_track_list(Fs, (num_to_tracks - (from_track % num_to_tracks)) % num_to_tracks, num_to_tracks); + to_tracks = get_to_track_list(Fs, (num_to_tracks - actual_from_track) % num_to_tracks, num_to_tracks); } else if (to_side == RIGHT) { - to_tracks = get_to_track_list(Fs, (from_track + 1) % num_to_tracks, num_to_tracks); + to_tracks = get_to_track_list(Fs, (actual_from_track + 1) % num_to_tracks, num_to_tracks); } } /* Finish, we return */ @@ -388,11 +396,22 @@ void build_gsb_one_group_track_to_track_map(const t_rr_graph* rr_graph, for (size_t to_track_id = 0; to_track_id < to_track_ids.size(); ++to_track_id) { size_t from_side_index = side_manager.to_size_t(); size_t from_track_index = from_tracks[side][inode]; + /* Check the id is still in the range !*/ + assert ( to_track_ids[to_track_id] < to_tracks[to_side_index].size() ); size_t to_track_index = to_tracks[to_side_index][to_track_ids[to_track_id]]; //printf("from_track(size=%lu): %lu , to_track_ids[%lu]:%lu, to_track_index: %lu in a group of %lu tracks\n", // from_tracks[side].size(), inode, to_track_id, to_track_ids[to_track_id], // to_track_index, to_tracks[to_side_index].size()); t_rr_node* to_track_node = rr_gsb.get_chan_node(to_side, to_track_index); + + /* Check if the to_track_node is already in the list ! */ + std::vector::iterator it = std::find((*track2track_map)[from_side_index][from_track_index].begin(), + (*track2track_map)[from_side_index][from_track_index].end(), + to_track_node - rr_graph->rr_node); + if (it != (*track2track_map)[from_side_index][from_track_index].end()) { + continue; /* the node_id is already in the list, go for the next */ + } + /* Clear, we should add to the list */ (*track2track_map)[from_side_index][from_track_index].push_back(to_track_node - rr_graph->rr_node); } } @@ -927,13 +946,15 @@ void build_edges_for_one_tileable_rr_gsb(const t_rr_graph* rr_graph, t_rr_node* opin_node = rr_gsb->get_opin_node(gsb_side, inode); /* 1. create edges between OPINs and CHANX|CHANY, using opin2track_map */ - int num_edges = opin2track_map[side_manager.to_size_t()][inode].size(); + std::vector driver_switches; + int num_edges = opin2track_map[gsb_side][inode].size(); for (int iedge = 0; iedge < num_edges; ++iedge) { int track_node_id = opin2track_map[side_manager.to_size_t()][inode][iedge]; - /* add edges to the chan_node */ - add_one_edge_for_two_rr_nodes(rr_graph, opin_node - rr_graph->rr_node, track_node_id, - rr_graph->rr_node[track_node_id].driver_switch); + driver_switches.push_back(rr_graph->rr_node[track_node_id].driver_switch); } + /* add edges to the opin_node */ + add_edges_for_two_rr_nodes(rr_graph, opin_node - rr_graph->rr_node, + opin2track_map[gsb_side][inode], driver_switches); } /* Find CHANX or CHANY */ @@ -945,26 +966,30 @@ void build_edges_for_one_tileable_rr_gsb(const t_rr_graph* rr_graph, /* 2. create edges between CHANX|CHANY and IPINs, using ipin2track_map */ for (size_t inode = 0; inode < rr_gsb->get_chan_width(gsb_side); ++inode) { t_rr_node* chan_node = rr_gsb->get_chan_node(gsb_side, inode); - int num_edges = track2ipin_map[side_manager.to_size_t()][inode].size(); + std::vector driver_switches; + int num_edges = track2ipin_map[gsb_side][inode].size(); for (int iedge = 0; iedge < num_edges; ++iedge) { - int ipin_node_id = track2ipin_map[side_manager.to_size_t()][inode][iedge]; - /* add edges to the chan_node */ - add_one_edge_for_two_rr_nodes(rr_graph, chan_node - rr_graph->rr_node, ipin_node_id, - rr_graph->rr_node[ipin_node_id].driver_switch); + int ipin_node_id = track2ipin_map[gsb_side][inode][iedge]; + driver_switches.push_back(rr_graph->rr_node[ipin_node_id].driver_switch); } + /* add edges to the chan_node */ + add_edges_for_two_rr_nodes(rr_graph, chan_node - rr_graph->rr_node, + track2ipin_map[gsb_side][inode], driver_switches); } } /* 3. create edges between CHANX|CHANY and CHANX|CHANY, using track2track_map */ for (size_t inode = 0; inode < rr_gsb->get_chan_width(gsb_side); ++inode) { t_rr_node* chan_node = rr_gsb->get_chan_node(gsb_side, inode); - int num_edges = track2track_map[side_manager.to_size_t()][inode].size(); + std::vector driver_switches; + int num_edges = track2track_map[gsb_side][inode].size(); for (int iedge = 0; iedge < num_edges; ++iedge) { - int track_node_id = track2track_map[side_manager.to_size_t()][inode][iedge]; - /* add edges to the chan_node */ - add_one_edge_for_two_rr_nodes(rr_graph, chan_node - rr_graph->rr_node, track_node_id, - rr_graph->rr_node[track_node_id].driver_switch); + int track_node_id = track2track_map[gsb_side][inode][iedge]; + driver_switches.push_back(rr_graph->rr_node[track_node_id].driver_switch); } + /* add edges to the chan_node */ + add_edges_for_two_rr_nodes(rr_graph, chan_node - rr_graph->rr_node, + track2track_map[gsb_side][inode], driver_switches); } } 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 11a15bdea..f82d740dc 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 @@ -1,7 +1,46 @@ -/***********************************/ -/* SPICE Modeling for VPR */ -/* Xifan TANG, EPFL/LSI */ -/***********************************/ +/********************************************************** + * MIT License + * + * Copyright (c) 2018 LNIS - The University of Utah + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + ***********************************************************************/ + +/************************************************************************ + * Filename: fpga_x2p_unique_routing.c + * Created by: Xifan Tang + * Change history: + * +-------------------------------------+ + * | Date | Author | Notes + * +-------------------------------------+ + * | 2019/06/25 | Xifan Tang | Created + * +-------------------------------------+ + ***********************************************************************/ +/************************************************************************ + * This file contains builders for the data structures + * 1. RRGSB: General Switch Block (GSB). + * 2. RRChan: Generic routing channels + * We also include functions to identify unique modules of + * Switch Blocks and Connection Blocks based on the data structures + * t_sb and t_cb + ***********************************************************************/ + #include #include #include @@ -1096,157 +1135,6 @@ RRGSB build_rr_gsb(DeviceCoordinator& device_range, return rr_gsb; } -/* Rotate the Switch block and try to add to rotatable mirrors */ -static -RRGSB rotate_rr_switch_block_for_mirror(DeviceCoordinator& device_range, - const RRGSB& rr_switch_block) { - RRGSB rotated_rr_switch_block; - rotated_rr_switch_block.set(rr_switch_block); - size_t Fco_offset = 1; - - /* For the 4 Switch Blocks at the four corners */ - /* 1. BOTTOM-LEFT corner: - * nothing to do. This is the base we like - */ - if ( ( 0 == rotated_rr_switch_block.get_sb_x()) - && ( 0 == rotated_rr_switch_block.get_sb_y()) ) { - return rotated_rr_switch_block; - } - - /* 2. TOP-LEFT corner: - * swap the opin_node between TOP and BOTTOM, - * swap the chan_node between TOP and BOTTOM, - */ - if ( ( 0 == rotated_rr_switch_block.get_sb_x()) - && (device_range.get_y() == rotated_rr_switch_block.get_sb_y()) ) { - rotated_rr_switch_block.swap_opin_node(TOP, BOTTOM); - rotated_rr_switch_block.swap_chan_node(TOP, BOTTOM); - return rotated_rr_switch_block; - } - - /* 3. TOP-RIGHT corner: - * swap the opin_node between TOP and BOTTOM, - * swap the chan_node between TOP and BOTTOM, - * swap the opin_node between LEFT and RIGHT, - * swap the chan_node between LEFT and RIGHT, - */ - if ( (device_range.get_x() == rotated_rr_switch_block.get_sb_x()) - && (device_range.get_y() == rotated_rr_switch_block.get_sb_y()) ) { - rotated_rr_switch_block.swap_opin_node(TOP, BOTTOM); - rotated_rr_switch_block.swap_chan_node(TOP, BOTTOM); - rotated_rr_switch_block.swap_opin_node(LEFT, RIGHT); - rotated_rr_switch_block.swap_chan_node(LEFT, RIGHT); - return rotated_rr_switch_block; - } - /* 4. BOTTOM-RIGHT corner: - * swap the opin_node between LEFT and RIGHT, - * swap the chan_node between LEFT and RIGHT, - */ - if ( (device_range.get_x() == rotated_rr_switch_block.get_sb_x()) - && (0 == rotated_rr_switch_block.get_sb_y()) ) { - rotated_rr_switch_block.swap_opin_node(LEFT, RIGHT); - rotated_rr_switch_block.swap_chan_node(LEFT, RIGHT); - return rotated_rr_switch_block; - } - - /* For Switch blocks on the borders */ - /* 1. BOTTOM side: - * nothing to do. This is the base we like - */ - if ( 0 == rotated_rr_switch_block.get_sb_y()) { - return rotated_rr_switch_block; - } - /* 2. TOP side: - * swap the opin_node between TOP and BOTTOM, - * swap the chan_node between TOP and BOTTOM, - */ - if (device_range.get_y() == rotated_rr_switch_block.get_sb_y() ) { - - /* For RIGHT SIDE: X-channel in INC_DIRECTION, rotate by an offset of its x-coordinator */ - rotated_rr_switch_block.rotate_side_chan_node_by_direction(RIGHT, INC_DIRECTION, Fco_offset * (rotated_rr_switch_block.get_sb_x() - 1)); - /* Rotate the same nodes on the opposite side */ - rotated_rr_switch_block.rotate_side_chan_node_by_direction(LEFT, INC_DIRECTION, Fco_offset * (rotated_rr_switch_block.get_sb_x() - 1)); - - /* For LEFT SIDE: X-channel in DEC_DIRECTION, rotate by an offset of its x-coordinator */ - rotated_rr_switch_block.counter_rotate_side_chan_node_by_direction(LEFT, DEC_DIRECTION, Fco_offset * (rotated_rr_switch_block.get_sb_x() - 1)); - /* Rotate the same nodes on the opposite side */ - rotated_rr_switch_block.counter_rotate_side_chan_node_by_direction(RIGHT, DEC_DIRECTION, Fco_offset * (rotated_rr_switch_block.get_sb_x() - 1)); - - //rotated_rr_switch_block.swap_opin_node(TOP, BOTTOM); - //rotated_rr_switch_block.swap_chan_node(TOP, BOTTOM); - //rotated_rr_switch_block.reverse_opin_node(TOP); - //rotated_rr_switch_block.reverse_opin_node(BOTTOM); - - return rotated_rr_switch_block; - } - /* 3. RIGHT side: - * swap the opin_node between LEFT and RIGHT, - * swap the chan_node between LEFT and RIGHT, - */ - if (device_range.get_x() == rotated_rr_switch_block.get_sb_x() ) { - - /* For TOP SIDE: Y-channel in INC_DIRECTION, rotate by an offset of its y-coordinator */ - rotated_rr_switch_block.rotate_side_chan_node_by_direction(TOP, INC_DIRECTION, Fco_offset * (rotated_rr_switch_block.get_sb_y() - 1)); - /* Rotate the same nodes on the opposite side */ - rotated_rr_switch_block.rotate_side_chan_node_by_direction(BOTTOM, INC_DIRECTION, Fco_offset * (rotated_rr_switch_block.get_sb_y() - 1)); - - /* For BOTTOM SIDE: Y-channel in DEC_DIRECTION, rotate by an offset of its y-coordinator */ - rotated_rr_switch_block.counter_rotate_side_chan_node_by_direction(BOTTOM, DEC_DIRECTION, Fco_offset * (rotated_rr_switch_block.get_sb_y() - 1)); - /* Rotate the same nodes on the opposite side */ - rotated_rr_switch_block.counter_rotate_side_chan_node_by_direction(TOP, DEC_DIRECTION, Fco_offset * (rotated_rr_switch_block.get_sb_y() - 1)); - - //rotated_rr_switch_block.swap_opin_node(LEFT, RIGHT); - //rotated_rr_switch_block.swap_chan_node(LEFT, RIGHT); - //rotated_rr_switch_block.reverse_opin_node(LEFT); - //rotated_rr_switch_block.reverse_opin_node(RIGHT); - - return rotated_rr_switch_block; - } - /* 4. LEFT side: - * nothing to do. This is the base we like - */ - if (0 == rotated_rr_switch_block.get_sb_x() ) { - return rotated_rr_switch_block; - } - - /* SB[1][1] is the baseline, we do not modify */ - if ( (1 == rotated_rr_switch_block.get_sb_x()) - && (1 == rotated_rr_switch_block.get_sb_y()) ) { - return rotated_rr_switch_block; - } - - /* Reach here, it means we have a SB at the center region */ - /* For TOP SIDE: Y-channel in INC_DIRECTION, rotate by an offset of its y-coordinator */ - if (1 < rotated_rr_switch_block.get_sb_y()) { - rotated_rr_switch_block.rotate_side_chan_node_by_direction(TOP, INC_DIRECTION, Fco_offset * (rotated_rr_switch_block.get_sb_y() - 1)); - /* Rotate the same nodes on the opposite side */ - rotated_rr_switch_block.rotate_side_chan_node_by_direction(BOTTOM, INC_DIRECTION, Fco_offset * (rotated_rr_switch_block.get_sb_y() - 1)); - } - - /* For RIGHT SIDE: X-channel in INC_DIRECTION, rotate by an offset of its x-coordinator */ - if (1 < rotated_rr_switch_block.get_sb_x()) { - rotated_rr_switch_block.rotate_side_chan_node_by_direction(RIGHT, INC_DIRECTION, Fco_offset * (rotated_rr_switch_block.get_sb_x() - 1)); - /* Rotate the same nodes on the opposite side */ - rotated_rr_switch_block.rotate_side_chan_node_by_direction(LEFT, INC_DIRECTION, Fco_offset * (rotated_rr_switch_block.get_sb_x() - 1)); - } - - /* For BOTTOM SIDE: Y-channel in DEC_DIRECTION, rotate by an offset of its y-coordinator */ - if ( 1 < rotated_rr_switch_block.get_sb_y()) { - rotated_rr_switch_block.counter_rotate_side_chan_node_by_direction(BOTTOM, DEC_DIRECTION, Fco_offset * (rotated_rr_switch_block.get_sb_y() - 1)); - /* Rotate the same nodes on the opposite side */ - rotated_rr_switch_block.counter_rotate_side_chan_node_by_direction(TOP, DEC_DIRECTION, Fco_offset * (rotated_rr_switch_block.get_sb_y() - 1)); - } - - /* For LEFT SIDE: X-channel in DEC_DIRECTION, rotate by an offset of its x-coordinator */ - if ( 1 < rotated_rr_switch_block.get_sb_x()) { - rotated_rr_switch_block.counter_rotate_side_chan_node_by_direction(LEFT, DEC_DIRECTION, Fco_offset * (rotated_rr_switch_block.get_sb_x() - 1)); - /* Rotate the same nodes on the opposite side */ - rotated_rr_switch_block.counter_rotate_side_chan_node_by_direction(RIGHT, DEC_DIRECTION, Fco_offset * (rotated_rr_switch_block.get_sb_x() - 1)); - } - - return rotated_rr_switch_block; -} - /* sort drive_rr_nodes of a rr_node inside rr_gsb subject to the index of rr_gsb array */ static void sort_rr_gsb_one_ipin_node_drive_rr_nodes(const RRGSB& rr_gsb, @@ -1504,33 +1392,9 @@ DeviceRRGSB build_device_rr_gsb(boolean output_sb_xml, char* sb_xml_dir, } } - /* Create directory if needed */ - if (TRUE == output_sb_xml) { - create_dir_path(sb_xml_dir); - } - - for (size_t ix = 0; ix <= sb_range.get_x(); ++ix) { - for (size_t iy = 0; iy <= sb_range.get_y(); ++iy) { - RRGSB rr_gsb = LL_device_rr_gsb.get_gsb(ix, iy); - RRGSB rotated_rr_sb = rotate_rr_switch_block_for_mirror(sb_range, rr_gsb); - if (TRUE == output_sb_xml) { - std::string fname_prefix(sb_xml_dir); - /* Add slash if needed */ - //if ('/' != fname_prefix.back()) { - // fname_prefix += "/"; - //} - //fname_prefix += "rotated_"; - //write_rr_switch_block_to_xml(fname_prefix, rotated_rr_sb); - write_rr_switch_block_to_xml(fname_prefix, rr_gsb); - } - } - } - return LL_device_rr_gsb; } - -/* Rotatable will be done in the next step -void identify_rotatable_switch_blocks(); -void identify_rotatable_connection_blocks(); -*/ +/************************************************************************ + * End of file : fpga_x2p_unique_routing.c + ***********************************************************************/ 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 2669e2e0a..d789b1154 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.cpp @@ -1447,7 +1447,7 @@ const char* RRGSB::gen_gsb_verilog_module_name() const { std::string y_str = std::to_string(get_sb_y()); char* ret = (char*)my_malloc(sizeof(char)* - ( 2 + 1 + ( 3 + 1 + x_str.length() + 2 + y_str.length() + 1 + 1)); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/write_rr_blocks.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/base/write_rr_blocks.cpp index 2357bfd50..e203bc75f 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/write_rr_blocks.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/write_rr_blocks.cpp @@ -31,7 +31,7 @@ void write_rr_switch_block_to_xml(std::string fname_prefix, RRGSB& rr_gsb) { /* Output each side */ for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { Side gsb_side_manager(side); - enum e_side gsb_side = gsb_side; + enum e_side gsb_side = gsb_side_manager.get_side(); /* Output IPIN nodes */ for (size_t inode = 0; inode < rr_gsb.get_num_ipin_nodes(gsb_side); ++inode) { @@ -117,7 +117,9 @@ void write_rr_switch_block_to_xml(std::string fname_prefix, RRGSB& rr_gsb) { enum e_side drive_node_side = NUM_SIDES; int drive_node_index = -1; rr_gsb.get_node_side_and_index(drive_rr_nodes[jnode], IN_PORT, &drive_node_side, &drive_node_index); + assert(-1 != drive_node_index); Side drive_side(drive_node_side); + if (OPIN == drive_rr_nodes[jnode]->type) { Side grid_side(rr_gsb.get_opin_node_grid_side(drive_node_side, drive_node_index)); fp << "\t\t Date: Tue, 25 Jun 2019 21:59:38 -0600 Subject: [PATCH 23/25] fixed critical bugs in pass_tracks identification and update regression test for tileable arch --- .../rr_graph/rr_graph_builder_utils.cpp | 8 +++---- .../rr_graph/tileable_rr_graph_builder.cpp | 4 ++-- .../device/rr_graph/tileable_rr_graph_gsb.cpp | 22 ++++++++++++++----- .../base/fpga_x2p_backannotate_utils.c | 1 + .../fpga_x2p/base/fpga_x2p_unique_routing.c | 1 + vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.cpp | 5 +++-- .../vpr/SRC/fpga_x2p/base/write_rr_blocks.cpp | 3 ++- vpr7_x2p/vpr/regression_verilog.sh | 2 +- 8 files changed, 30 insertions(+), 16 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_builder_utils.cpp b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_builder_utils.cpp index ecab27502..6b2ad94ed 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_builder_utils.cpp +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/rr_graph_builder_utils.cpp @@ -376,16 +376,16 @@ DeviceCoordinator get_track_rr_node_end_coordinator(const t_rr_node* track_rr_no /* Make sure we have CHANX or CHANY */ assert ( (CHANX == track_rr_node->type) ||(CHANY == track_rr_node->type) ); - DeviceCoordinator start_coordinator; + DeviceCoordinator end_coordinator; if (INC_DIRECTION == track_rr_node->direction) { - start_coordinator.set(track_rr_node->xhigh, track_rr_node->yhigh); + end_coordinator.set(track_rr_node->xhigh, track_rr_node->yhigh); } else { assert (DEC_DIRECTION == track_rr_node->direction); - start_coordinator.set(track_rr_node->xlow, track_rr_node->ylow); + end_coordinator.set(track_rr_node->xlow, track_rr_node->ylow); } - return start_coordinator; + return end_coordinator; } /************************************************************************ diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_builder.cpp b/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_builder.cpp index 582e5a5e7..26171ea56 100644 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_builder.cpp +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_builder.cpp @@ -434,7 +434,7 @@ void load_one_chan_rr_nodes_basic_info(const DeviceCoordinator& chan_coordinator /* fill fast look-up table */ /* Get node_id */ int track_node_id = chan_details->get_track_node_id(itrack); - /* CHANX requires a reverted (x,y) in the fast look-up table */ + /* CHANY requires a reverted (x,y) in the fast look-up table */ if (CHANX == chan_type) { load_one_node_to_rr_graph_fast_lookup(rr_graph, track_node_id, chan_type, @@ -442,7 +442,7 @@ void load_one_chan_rr_nodes_basic_info(const DeviceCoordinator& chan_coordinator chan_coordinator.get_x(), itrack); } - /* CHANY follows a regular (x,y) in the fast look-up table */ + /* CHANX follows a regular (x,y) in the fast look-up table */ if (CHANY == chan_type) { load_one_node_to_rr_graph_fast_lookup(rr_graph, track_node_id, chan_type, diff --git a/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_gsb.cpp b/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_gsb.cpp index f039a687f..1a411c39b 100755 --- a/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_gsb.cpp +++ b/vpr7_x2p/vpr/SRC/device/rr_graph/tileable_rr_graph_gsb.cpp @@ -373,7 +373,7 @@ void build_gsb_one_group_track_to_track_map(const t_rr_graph* rr_graph, /* 2. next side */ /* Next side definition: TOP => RIGHT; RIGHT=>BOTTOM; BOTTOM=>LEFT; LEFT=>TOP */ to_track_sides.push_back(side_manager.get_rotate_clockwise()); - + for (size_t inode = 0; inode < from_tracks[side].size(); ++inode) { for (size_t to_side_id = 0; to_side_id < to_track_sides.size(); ++to_side_id) { enum e_side to_side = to_track_sides[to_side_id]; @@ -387,6 +387,7 @@ void build_gsb_one_group_track_to_track_map(const t_rr_graph* rr_graph, if (from_side == to_side) { continue; } + /* Get other track_ids depending on the switch block pattern */ /* Find the track ids that will start at the other sides */ std::vector to_track_ids = get_switch_block_to_track_id(sb_type, Fs, from_side, inode, @@ -404,6 +405,11 @@ void build_gsb_one_group_track_to_track_map(const t_rr_graph* rr_graph, // to_track_index, to_tracks[to_side_index].size()); t_rr_node* to_track_node = rr_gsb.get_chan_node(to_side, to_track_index); + /* from_track should be IN_PORT */ + assert( IN_PORT == rr_gsb.get_chan_node_direction(from_side, from_track_index) ); + /* to_track should be OUT_PORT */ + assert( OUT_PORT == rr_gsb.get_chan_node_direction(to_side, to_track_index) ); + /* Check if the to_track_node is already in the list ! */ std::vector::iterator it = std::find((*track2track_map)[from_side_index][from_track_index].begin(), (*track2track_map)[from_side_index][from_track_index].end(), @@ -491,6 +497,12 @@ t_track2track_map build_gsb_track_to_track_map(const t_rr_graph* rr_graph, enum e_side gsb_side = side_manager.get_side(); /* Build a list of tracks that will start from this side */ for (size_t inode = 0; inode < rr_gsb.get_chan_width(gsb_side); ++inode) { + /* We need to check Switch block population of this track + * The track node will not be considered if there supposed to be no SB at this position + */ + if (false == is_gsb_in_track_sb_population(rr_gsb, gsb_side, inode, segment_inf)) { + continue; /* skip this node and go to the next */ + } /* check if this track will start from here */ enum e_track_status track_status = determine_track_status_of_gsb(rr_gsb, gsb_side, inode); switch (track_status) { @@ -503,11 +515,9 @@ t_track2track_map build_gsb_track_to_track_map(const t_rr_graph* rr_graph, end_tracks[side].push_back(inode); break; case TRACK_PASS: - /* We need to check Switch block population of this track - * The track node will not be considered if there supposed to be no SB at this position - */ - if (true == is_gsb_in_track_sb_population(rr_gsb, gsb_side, inode, segment_inf)) { - /* Update passing track list */ + /* Update passing track list */ + /* Note that the pass_track should be IN_PORT only !!! */ + if (IN_PORT == rr_gsb.get_chan_node_direction(gsb_side, inode)) { pass_tracks[side].push_back(inode); } break; 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 0a34e9ab9..b8e8e8112 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 @@ -1831,6 +1831,7 @@ t_rr_node** get_chan_rr_nodes(int* num_chan_rr_nodes, chan_rr_nodes = (t_rr_node**)my_malloc((*num_chan_rr_nodes)*sizeof(t_rr_node*)); /* Fill the array */ for (itrack = 0; itrack < (*num_chan_rr_nodes); itrack++) { + /* CHANX follows a weird way in searching rr_nodes */ inode = get_rr_node_index(x, y, CHANX, itrack, LL_rr_node_indices); chan_rr_nodes[itrack] = &(LL_rr_node[inode]); } 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 f82d740dc..486eba7de 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 @@ -1347,6 +1347,7 @@ DeviceRRGSB build_device_rr_gsb(boolean output_sb_xml, char* sb_xml_dir, if (TRUE == output_sb_xml) { + create_dir_path(sb_xml_dir); write_device_rr_gsb_to_xml(sb_xml_dir, LL_device_rr_gsb); /* Skip rotating mirror searching */ 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 d789b1154..0d860f77d 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.cpp @@ -1013,8 +1013,9 @@ bool RRGSB::is_sb_node_imply_short_connection(t_rr_node* src_node) const { int index; get_node_side_and_index(src_node->drive_rr_nodes[inode], IN_PORT, &side, &index); /* We need to be sure that drive_rr_node is part of the SB */ - if (((-1 == index) || (NUM_SIDES == side)) - && ((CHANX == src_node->drive_rr_nodes[inode]->type) || (CHANY == src_node->drive_rr_nodes[inode]->type))) { + if ( ((-1 == index) || (NUM_SIDES == side)) + && ( (CHANX == src_node->drive_rr_nodes[inode]->type) + || (CHANY == src_node->drive_rr_nodes[inode]->type) ) ) { return true; } } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/write_rr_blocks.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/base/write_rr_blocks.cpp index e203bc75f..307a7dc1a 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/write_rr_blocks.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/write_rr_blocks.cpp @@ -117,6 +117,7 @@ void write_rr_switch_block_to_xml(std::string fname_prefix, RRGSB& rr_gsb) { enum e_side drive_node_side = NUM_SIDES; int drive_node_index = -1; rr_gsb.get_node_side_and_index(drive_rr_nodes[jnode], IN_PORT, &drive_node_side, &drive_node_index); + if (-1 == drive_node_index) assert(-1 != drive_node_index); Side drive_side(drive_node_side); @@ -156,7 +157,7 @@ void write_rr_switch_block_to_xml(std::string fname_prefix, RRGSB& rr_gsb) { /* Output each rr_switch_block to a XML file */ void write_device_rr_gsb_to_xml(char* sb_xml_dir, - DeviceRRGSB& LL_device_rr_gsb) { + DeviceRRGSB& LL_device_rr_gsb) { std::string fname_prefix(sb_xml_dir); /* Add slash if needed */ if ('/' != fname_prefix.back()) { diff --git a/vpr7_x2p/vpr/regression_verilog.sh b/vpr7_x2p/vpr/regression_verilog.sh index 293d9e551..aa37554da 100644 --- a/vpr7_x2p/vpr/regression_verilog.sh +++ b/vpr7_x2p/vpr/regression_verilog.sh @@ -33,7 +33,7 @@ perl rewrite_path_in_file.pl -i $arch_xml_file -k $arch_ff_keyword $new_ff_path cd - # Run VPR -./vpr $arch_xml_file $blif_file --full_stats --nodisp --activity_file $act_file --fpga_verilog --fpga_verilog_dir $verilog_output_dirpath/$verilog_output_dirname --fpga_x2p_rename_illegal_port --fpga_bitstream_generator --fpga_verilog_print_top_testbench --fpga_verilog_print_input_blif_testbench --fpga_verilog_include_timing --fpga_verilog_include_signal_init --fpga_verilog_print_formal_verification_top_netlist --fpga_verilog_print_autocheck_top_testbench $verilog_reference --fpga_verilog_print_user_defined_template --route_chan_width $vpr_route_chan_width --fpga_verilog_include_icarus_simulator --fpga_verilog_print_report_timing_tcl --power --tech_properties $tech_file --fpga_verilog_print_sdc_pnr --fpga_verilog_print_sdc_analysis --fpga_x2p_compact_routing_hierarchy +./vpr $arch_xml_file $blif_file --full_stats --nodisp --activity_file $act_file --fpga_verilog --fpga_verilog_dir $verilog_output_dirpath/$verilog_output_dirname --fpga_x2p_rename_illegal_port --fpga_bitstream_generator --fpga_verilog_print_top_testbench --fpga_verilog_print_input_blif_testbench --fpga_verilog_include_timing --fpga_verilog_include_signal_init --fpga_verilog_print_formal_verification_top_netlist --fpga_verilog_print_autocheck_top_testbench $verilog_reference --fpga_verilog_print_user_defined_template --route_chan_width $vpr_route_chan_width --fpga_verilog_include_icarus_simulator --power --tech_properties $tech_file --fpga_verilog_print_sdc_pnr --fpga_verilog_print_sdc_analysis --fpga_x2p_compact_routing_hierarchy --fpga_verilog_print_report_timing_tcl cd $fpga_flow_scripts perl rewrite_path_in_file.pl -i $ff_path -o $new_ff_path -k $ff_keyword $ff_include_path From d50fb7ee1983a86866e7f7e52481ecda647e5179 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 26 Jun 2019 10:50:23 -0600 Subject: [PATCH 24/25] fixed the bug in determine passing wires for rr_gsb --- .../fpga_x2p/base/fpga_x2p_unique_routing.c | 15 +- vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.cpp | 117 +++++++--- vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.h | 2 +- .../vpr/SRC/fpga_x2p/base/write_rr_blocks.cpp | 4 +- .../bitstream/fpga_bitstream_routing.c | 10 +- .../vpr/SRC/fpga_x2p/verilog/verilog_api.c | 2 +- .../fpga_x2p/verilog/verilog_report_timing.c | 4 +- .../SRC/fpga_x2p/verilog/verilog_routing.c | 217 +----------------- .../SRC/fpga_x2p/verilog/verilog_routing.h | 1 - .../vpr/SRC/fpga_x2p/verilog/verilog_sdc.c | 6 +- 10 files changed, 121 insertions(+), 257 deletions(-) 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 486eba7de..82f8eb688 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 @@ -1197,18 +1197,19 @@ void sort_rr_gsb_one_ipin_node_drive_rr_nodes(const RRGSB& rr_gsb, /* sort drive_rr_nodes of a rr_node inside rr_gsb subject to the index of rr_gsb array */ static void sort_rr_gsb_one_chan_node_drive_rr_nodes(const RRGSB& rr_gsb, - t_rr_node* chan_node, - enum e_side chan_side) { + enum e_side chan_side, + size_t track_id) { /* If this is a passing wire, we return directly. * The passing wire will be handled in other GSBs */ - if (true == rr_gsb.is_sb_node_imply_short_connection(chan_node)) { - /* Double check if the interc lies inside a channel wire, that is interc between segments */ - assert(true == rr_gsb.is_sb_node_exist_opposite_side(chan_node, chan_side)); + if (true == rr_gsb.is_sb_node_passing_wire(chan_side, track_id)) { return; } + /* Get the chan_node */ + t_rr_node* chan_node = rr_gsb.get_chan_node(chan_side, track_id); + /* Create a copy of the edges and switches of this node */ std::vector sorted_drive_nodes; std::vector sorted_drive_switches; @@ -1301,8 +1302,8 @@ void sort_rr_gsb_drive_rr_nodes(const RRGSB& rr_gsb) { } /* Get the chan side, so we have the routing tracks */ sort_rr_gsb_one_chan_node_drive_rr_nodes(rr_gsb, - rr_gsb.get_chan_node(gsb_side, inode), - gsb_side); + gsb_side, + inode); } } 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 0d860f77d..766d7e00f 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.cpp @@ -1,3 +1,42 @@ +/********************************************************** + * MIT License + * + * Copyright (c) 2018 LNIS - The University of Utah + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + ***********************************************************************/ + +/************************************************************************ + * Filename: rr_blocks.cpp + * Created by: Xifan Tang + * Change history: + * +-------------------------------------+ + * | Date | Author | Notes + * +-------------------------------------+ + * | 2019/06/26 | Xifan Tang | Created + * +-------------------------------------+ + ***********************************************************************/ +/************************************************************************ + * This file contains member function for the data structures defined + * in rr_block.h + ***********************************************************************/ + #include #include #include @@ -7,6 +46,8 @@ #include "rr_blocks.h" +#include "rr_graph_builder_utils.h" + /* Member Functions of Class RRChan */ /* Constructors */ @@ -1003,24 +1044,53 @@ size_t RRGSB::get_cb_conf_bits_msb(t_rr_type cb_type) const { } } -/* Check if the node imply a short connection inside the SB, which happens to long wires across a FPGA fabric */ -bool RRGSB::is_sb_node_imply_short_connection(t_rr_node* src_node) const { +/************************************************************************ + * Check if the node indicates a passing wire across the Switch Block part of the GSB + * Therefore, we actually do the following check + * Check if a track starts from this GSB or not + * For INC_DIRECTION + * (xlow, ylow) should be same as the GSB side coordinator + * For DEC_DIRECTION + * (xhigh, yhigh) should be same as the GSB side coordinator + ***********************************************************************/ +bool RRGSB::is_sb_node_passing_wire(const enum e_side node_side, + const size_t track_id) const { - assert((CHANX == src_node->type) || (CHANY == src_node->type)); - - for (size_t inode = 0; inode < size_t(src_node->num_drive_rr_nodes); ++inode) { - enum e_side side; - int index; - get_node_side_and_index(src_node->drive_rr_nodes[inode], IN_PORT, &side, &index); - /* We need to be sure that drive_rr_node is part of the SB */ - if ( ((-1 == index) || (NUM_SIDES == side)) - && ( (CHANX == src_node->drive_rr_nodes[inode]->type) - || (CHANY == src_node->drive_rr_nodes[inode]->type) ) ) { - return true; - } + /* Get the rr_node */ + t_rr_node* track_node = get_chan_node(node_side, track_id); + /* Get the coordinators */ + DeviceCoordinator side_coordinator = get_side_block_coordinator(node_side); + + /* Get the coordinator of where the track starts */ + DeviceCoordinator track_start = get_track_rr_node_start_coordinator(track_node); + + /* INC_DIRECTION start_track: (xlow, ylow) should be same as the GSB side coordinator */ + /* DEC_DIRECTION start_track: (xhigh, yhigh) should be same as the GSB side coordinator */ + if ( (track_start.get_x() == side_coordinator.get_x()) + && (track_start.get_y() == side_coordinator.get_y()) + && (OUT_PORT == get_chan_node_direction(node_side, track_id)) ) { + /* Double check: start track should be an OUTPUT PORT of the GSB */ + return false; /* This is a starting point */ } - return false; + /* Get the coordinator of where the track ends */ + DeviceCoordinator track_end = get_track_rr_node_end_coordinator(track_node); + + /* INC_DIRECTION end_track: (xhigh, yhigh) should be same as the GSB side coordinator */ + /* DEC_DIRECTION end_track: (xlow, ylow) should be same as the GSB side coordinator */ + if ( (track_end.get_x() == side_coordinator.get_x()) + && (track_end.get_y() == side_coordinator.get_y()) + && (IN_PORT == get_chan_node_direction(node_side, track_id)) ) { + /* Double check: end track should be an INPUT PORT of the GSB */ + return false; /* This is an ending point */ + } + + /* Reach here it means that this will be a passing wire, + * we should be able to find the node on the opposite side of the GSB! + */ + assert (true == is_sb_node_exist_opposite_side(track_node, node_side)); + + return true; } /* check if the candidate SB satisfy the basic requirements on being a mirror of the current one */ @@ -2050,18 +2120,10 @@ bool RRGSB::is_sb_node_mirror(const RRGSB& cand, /* Ensure rr_nodes are either the output of short-connection or multiplexer */ t_rr_node* node = this->get_chan_node(node_side, track_id); t_rr_node* cand_node = cand.get_chan_node(node_side, track_id); - bool is_short_conkt = this->is_sb_node_imply_short_connection(node); + bool is_short_conkt = this->is_sb_node_passing_wire(node_side, track_id); - if (is_short_conkt != cand.is_sb_node_imply_short_connection(cand_node)) { + if (is_short_conkt != cand.is_sb_node_passing_wire(node_side, track_id)) { return false; - } - /* Find the driving rr_node in this sb */ - if (true == is_short_conkt) { - /* Ensure we have the same track id for the driving nodes */ - if ( this->is_sb_node_exist_opposite_side(node, node_side) - != cand.is_sb_node_exist_opposite_side(cand_node, node_side)) { - return false; - } } else { /* check driving rr_nodes */ if ( node->num_drive_rr_nodes != cand_node->num_drive_rr_nodes ) { return false; @@ -2156,7 +2218,7 @@ size_t RRGSB::get_track_id_first_short_connection(enum e_side node_side) const { /* Walk through chan_nodes and find the first short connection */ for (size_t inode = 0; inode < get_chan_width(node_side); ++inode) { - if (true == is_sb_node_imply_short_connection(get_chan_node(node_side, inode))) { + if (true == is_sb_node_passing_wire(node_side, inode)) { return inode; } } @@ -2989,3 +3051,6 @@ bool DeviceRRGSB::validate_cb_type(t_rr_type cb_type) const { return false; } +/************************************************************************ + * End of file : rr_blocks.cpp + ***********************************************************************/ 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 7128cc996..d95c08d75 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.h @@ -219,7 +219,7 @@ class RRGSB { size_t get_cb_num_conf_bits(t_rr_type cb_type) const; size_t get_cb_conf_bits_lsb(t_rr_type cb_type) const; size_t get_cb_conf_bits_msb(t_rr_type cb_type) const; - bool is_sb_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_sb_node_passing_wire(const enum e_side node_side, const size_t track_id) const; /* Check if the node imply a short connection inside the SB, which happens to long wires across a FPGA fabric */ bool is_sb_side_mirror(const RRGSB& cand, enum e_side side) const; /* check if a side of candidate SB is a mirror of the current one */ bool is_sb_side_segment_mirror(const RRGSB& cand, enum e_side side, size_t seg_id) const; /* check if all the routing segments of a side of candidate SB is a mirror of the current one */ bool is_sb_mirror(const RRGSB& cand) const; /* check if the candidate SB is a mirror of the current one */ diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/write_rr_blocks.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/base/write_rr_blocks.cpp index 307a7dc1a..beeddd6c8 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/write_rr_blocks.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/write_rr_blocks.cpp @@ -85,9 +85,7 @@ void write_rr_switch_block_to_xml(std::string fname_prefix, RRGSB& rr_gsb) { size_t src_segment_id = rr_gsb.get_chan_node_segment(gsb_side, inode); /* Check if this node is directly connected to the node on the opposite side */ - if (true == rr_gsb.is_sb_node_imply_short_connection(cur_rr_node)) { - /* Double check if the interc lies inside a channel wire, that is interc between segments */ - assert(true == rr_gsb.is_sb_node_exist_opposite_side(cur_rr_node, gsb_side)); + if (true == rr_gsb.is_sb_node_passing_wire(gsb_side, inode)) { num_drive_rr_nodes = 0; drive_rr_nodes = NULL; } else { diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/bitstream/fpga_bitstream_routing.c b/vpr7_x2p/vpr/SRC/fpga_x2p/bitstream/fpga_bitstream_routing.c index 8d855e42f..866de67b7 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/bitstream/fpga_bitstream_routing.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/bitstream/fpga_bitstream_routing.c @@ -216,7 +216,7 @@ void fpga_spice_generate_bitstream_switch_box_interc(FILE* fp, const RRGSB& rr_sb, t_sram_orgz_info* cur_sram_orgz_info, enum e_side chan_side, - t_rr_node* cur_rr_node) { + size_t chan_node_id) { int num_drive_rr_nodes = 0; t_rr_node** drive_rr_nodes = NULL; @@ -227,12 +227,12 @@ void fpga_spice_generate_bitstream_switch_box_interc(FILE* fp, __FILE__, __LINE__); exit(1); } + /* Get the rr_node */ + t_rr_node* cur_rr_node = rr_sb.get_chan_node(chan_side, chan_node_id); /* Determine if the interc lies inside a channel wire, that is interc between segments */ /* Check each num_drive_rr_nodes, see if they appear in the cur_sb_info */ - if (true == rr_sb.is_sb_node_imply_short_connection(cur_rr_node)) { - /* Double check if the interc lies inside a channel wire, that is interc between segments */ - assert(true == rr_sb.is_sb_node_exist_opposite_side(cur_rr_node, chan_side)); + if (true == rr_sb.is_sb_node_passing_wire(chan_side, chan_node_id)) { num_drive_rr_nodes = 0; drive_rr_nodes = NULL; } else { @@ -364,7 +364,7 @@ void fpga_spice_generate_bitstream_routing_switch_box_subckt(FILE* fp, if (OUT_PORT == rr_sb.get_chan_node_direction(side_manager.get_side(), itrack)) { fpga_spice_generate_bitstream_switch_box_interc(fp, rr_sb, cur_sram_orgz_info, side_manager.get_side(), - rr_sb.get_chan_node(side_manager.get_side(), itrack)); + itrack); } } } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c index 29ab3600e..3b4b381ef 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c @@ -255,7 +255,7 @@ void vpr_fpga_verilog(t_vpr_setup vpr_setup, /* Dump routing resources: switch blocks, connection blocks and channel tracks */ dump_verilog_routing_resources(sram_verilog_orgz_info, src_dir_path, rr_dir_path, Arch, &vpr_setup.RoutingArch, num_rr_nodes, rr_node, rr_node_indices, rr_indexed_data, - vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts, vpr_setup.FPGA_SPICE_Opts.compact_routing_hierarchy); + vpr_setup.FPGA_SPICE_Opts.compact_routing_hierarchy); /* Dump logic blocks * Branches to go: diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_report_timing.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_report_timing.c index de523bfd6..b6f56179c 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_report_timing.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_report_timing.c @@ -2764,7 +2764,7 @@ void verilog_generate_routing_wires_report_timing(FILE* fp, ||(CHANY == rr_sb.get_chan_node(side_manager.get_side(), itrack)->type)); /* We only care the output port and it should indicate a SB mux */ if ( (OUT_PORT != rr_sb.get_chan_node_direction(side_manager.get_side(), itrack)) - || (true == rr_sb.is_sb_node_imply_short_connection(rr_sb.get_chan_node(side_manager.get_side(), itrack)))) { + || (true == rr_sb.is_sb_node_passing_wire(side_manager.get_side(), itrack))) { continue; } /* Bypass if we have only 1 driving node */ @@ -3169,7 +3169,7 @@ void verilog_generate_routing_wire_report_timing(t_trpt_opts trpt_opts, ||(CHANY == rr_sb.get_chan_node(side_manager.get_side(), itrack)->type)); /* We only care the output port and it should indicate a SB mux */ if ( (OUT_PORT != rr_sb.get_chan_node_direction(side_manager.get_side(), itrack)) - || (false != rr_sb.is_sb_node_imply_short_connection(rr_sb.get_chan_node(side_manager.get_side(), itrack)))) { + || (false != rr_sb.is_sb_node_passing_wire(side_manager.get_side(), itrack))) { continue; } /* Bypass if we have only 1 driving node */ diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.c index 9d049bc70..47a1efec5 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.c @@ -308,68 +308,6 @@ void dump_verilog_routing_chan_subckt(char* verilog_dir, return; } -static -t_rr_node** verilog_get_grid_side_pin_rr_nodes(int* num_pin_rr_nodes, - t_rr_type pin_type, - int x, - int y, - int side, - t_ivec*** LL_rr_node_indices) { - int height, ipin, class_id, inode; - t_type_ptr type = NULL; - t_rr_node** ret = NULL; - enum e_pin_type pin_class_type; - int cur; - - /* Check */ - assert((!(0 > x))&&(!(x > (nx + 1)))); - assert((!(0 > y))&&(!(y > (ny + 1)))); - type = grid[x][y].type; - assert(NULL != type); - /* Assign the type of PIN*/ - switch (pin_type) { - case IPIN: - /* case SINK: */ - pin_class_type = RECEIVER; /* This is the end of a route path*/ - break; - /*case SOURCE:*/ - case OPIN: - pin_class_type = DRIVER; /* This is the start of a route path */ - break; - /* SINK and SOURCE are hypothesis nodes */ - default: - vpr_printf(TIO_MESSAGE_ERROR, "(File:%s, [LINE%d])Invalid pin_type!\n", __FILE__, __LINE__); - exit(1); - } - - /* Output the pins on the side*/ - (*num_pin_rr_nodes) = 0; - height = grid[x][y].offset; - for (ipin = 0; ipin < type->num_pins; ipin++) { - class_id = type->pin_class[ipin]; - if ((1 == type->pinloc[height][side][ipin])&&(pin_class_type == type->class_inf[class_id].type)) { - (*num_pin_rr_nodes)++; - } - } - /* Malloc */ - ret = (t_rr_node**)my_malloc(sizeof(t_rr_node*)*(*num_pin_rr_nodes)); - - /* Fill the return array*/ - cur = 0; - height = grid[x][y].offset; - for (ipin = 0; ipin < type->num_pins; ipin++) { - class_id = type->pin_class[ipin]; - if ((1 == type->pinloc[height][side][ipin])&&(pin_class_type == type->class_inf[class_id].type)) { - inode = get_rr_node_index(x, y, pin_type, ipin, LL_rr_node_indices); - ret[cur] = &(rr_node[inode]); - cur++; - } - } - assert(cur == (*num_pin_rr_nodes)); - - return ret; -} - void dump_verilog_grid_side_pin_with_given_index(FILE* fp, t_rr_type pin_type, int pin_index, int side, int x, int y, @@ -489,142 +427,6 @@ void dump_verilog_grid_side_pins(FILE* fp, return; } -/* Determine the channel coordinates in switch box subckt */ -static -void verilog_determine_src_chan_coordinate_switch_box(t_rr_node* src_rr_node, - t_rr_node* des_rr_node, - int side, - int switch_box_x, - int switch_box_y, - int* src_chan_x, - int* src_chan_y, - char** src_chan_port_name) { - /* Check */ - assert((!(0 > side))&&(side < 4)); - assert((CHANX == src_rr_node->type)||(CHANY == src_rr_node->type)); - assert((CHANX == des_rr_node->type)||(CHANY == des_rr_node->type)); - assert((!(0 > switch_box_x))&&(!(switch_box_x > (nx + 1)))); - assert((!(0 > switch_box_y))&&(!(switch_box_y > (ny + 1)))); - - /* Initialize*/ - (*src_chan_x) = 0; - (*src_chan_y) = 0; - (*src_chan_port_name) = NULL; - - switch (side) { - case 0: /*TOP*/ - /* The destination rr_node only have one condition!!! */ - assert((INC_DIRECTION == des_rr_node->direction)&&(CHANY == des_rr_node->type)); - /* Following cases: - * | - * / | \ - */ - if ((INC_DIRECTION == src_rr_node->direction)&&(CHANY == src_rr_node->type)) { - (*src_chan_x) = switch_box_x; - (*src_chan_y) = switch_box_y; - (*src_chan_port_name) = "in"; - } else if ((INC_DIRECTION == src_rr_node->direction)&&(CHANX == src_rr_node->type)) { - (*src_chan_x) = switch_box_x; - (*src_chan_y) = switch_box_y; - (*src_chan_port_name) = "in"; - } else if ((DEC_DIRECTION == src_rr_node->direction)&&(CHANX == src_rr_node->type)) { - (*src_chan_x) = switch_box_x + 1; - (*src_chan_y) = switch_box_y; - (*src_chan_port_name) = "in"; - } else { - vpr_printf(TIO_MESSAGE_ERROR, "(File:%s, [LINE%d])Invalid source channel!\n", __FILE__, __LINE__); - exit(1); - } - break; - case 1: /*RIGHT*/ - /* The destination rr_node only have one condition!!! */ - assert((INC_DIRECTION == des_rr_node->direction)&&(CHANX == des_rr_node->type)); - /* Following cases: - * \ - * --- ---- - * / - */ - if ((DEC_DIRECTION == src_rr_node->direction)&&(CHANY == src_rr_node->type)) { - (*src_chan_x) = switch_box_x; - (*src_chan_y) = switch_box_y + 1; - (*src_chan_port_name) = "in"; - } else if ((INC_DIRECTION == src_rr_node->direction)&&(CHANX == src_rr_node->type)) { - (*src_chan_x) = switch_box_x; - (*src_chan_y) = switch_box_y; - (*src_chan_port_name) = "in"; - } else if ((INC_DIRECTION == src_rr_node->direction)&&(CHANY == src_rr_node->type)) { - (*src_chan_x) = switch_box_x; - (*src_chan_y) = switch_box_y; - (*src_chan_port_name) = "in"; - } else { - vpr_printf(TIO_MESSAGE_ERROR, "(File:%s, [LINE%d])Invalid source channel!\n", __FILE__, __LINE__); - exit(1); - } - break; - case 2: /*BOTTOM*/ - /* The destination rr_node only have one condition!!! */ - assert((DEC_DIRECTION == des_rr_node->direction)&&(CHANY == des_rr_node->type)); - /* Following cases: - * | - * \ / - * | - */ - if ((DEC_DIRECTION == src_rr_node->direction)&&(CHANY == src_rr_node->type)) { - (*src_chan_x) = switch_box_x; - (*src_chan_y) = switch_box_y + 1; - (*src_chan_port_name) = "in"; - } else if ((INC_DIRECTION == src_rr_node->direction)&&(CHANX == src_rr_node->type)) { - (*src_chan_x) = switch_box_x; - (*src_chan_y) = switch_box_y; - (*src_chan_port_name) = "in"; - } else if ((DEC_DIRECTION == src_rr_node->direction)&&(CHANX == src_rr_node->type)) { - (*src_chan_x) = switch_box_x + 1; - (*src_chan_y) = switch_box_y; - (*src_chan_port_name) = "in"; - } else { - vpr_printf(TIO_MESSAGE_ERROR, "(File:%s, [LINE%d])Invalid source channel!\n", __FILE__, __LINE__); - exit(1); - } - break; - case 3: /*LEFT*/ - /* The destination rr_node only have one condition!!! */ - assert((DEC_DIRECTION == des_rr_node->direction)&&(CHANX == des_rr_node->type)); - /* Following cases: - * / - * --- ---- - * \ - */ - if ((DEC_DIRECTION == src_rr_node->direction)&&(CHANX == src_rr_node->type)) { - (*src_chan_x) = switch_box_x + 1; - (*src_chan_y) = switch_box_y; - (*src_chan_port_name) = "in"; - } else if ((INC_DIRECTION == src_rr_node->direction)&&(CHANY == src_rr_node->type)) { - (*src_chan_x) = switch_box_x; - (*src_chan_y) = switch_box_y; - (*src_chan_port_name) = "in"; - } else if ((DEC_DIRECTION == src_rr_node->direction)&&(CHANY == src_rr_node->type)) { - (*src_chan_x) = switch_box_x; - (*src_chan_y) = switch_box_y + 1; - (*src_chan_port_name) = "in"; - } else { - vpr_printf(TIO_MESSAGE_ERROR, "(File:%s, [LINE%d])Invalid source channel!\n", __FILE__, __LINE__); - exit(1); - } - break; - default: - vpr_printf(TIO_MESSAGE_ERROR,"(File:%s, [LINE%d])Invalid side!\n", __FILE__, __LINE__); - exit(1); - } - - /* Make sure the source rr_node (channel) is in the range*/ - assert((!((*src_chan_x) < src_rr_node->xlow))&&(!((*src_chan_x) > src_rr_node->xhigh))); - if (!((!((*src_chan_y) < src_rr_node->ylow))&&(!((*src_chan_y) > src_rr_node->yhigh)))) { - assert((!((*src_chan_y) < src_rr_node->ylow))&&(!((*src_chan_y) > src_rr_node->yhigh))); - } - - return; -} - void dump_verilog_switch_box_chan_port(FILE* fp, t_sb* cur_sb_info, int chan_side, @@ -680,6 +482,7 @@ void dump_verilog_unique_switch_box_chan_port(FILE* fp, /* Get the index in sb_info of cur_rr_node */ index = rr_sb.get_node_index(cur_rr_node, chan_side, cur_rr_node_direction); /* Make sure this node is included in this sb_info */ + if (!((-1 != index)&&(NUM_SIDES != chan_side))) assert((-1 != index)&&(NUM_SIDES != chan_side)); chan_rr_node_type = cur_rr_node->type; @@ -737,9 +540,7 @@ void dump_verilog_unique_switch_box_short_interc(FILE* fp, if (0 == actual_fan_in) { assert(drive_rr_node == cur_rr_node); } else { - Side side_manager(chan_side); - /* drive_rr_node = &(rr_node[cur_rr_node->prev_node]); */ - assert(1 == rr_node_drive_switch_box(drive_rr_node, cur_rr_node, rr_sb.get_sb_coordinator().get_x(), rr_sb.get_sb_coordinator().get_y(), side_manager.get_side())); + assert (1 == actual_fan_in); } int grid_x = drive_rr_node->xlow; @@ -1581,7 +1382,7 @@ void dump_verilog_unique_switch_box_interc(t_sram_orgz_info* cur_sram_orgz_info, FILE* fp, const RRGSB& rr_sb, enum e_side chan_side, - t_rr_node* cur_rr_node) { + size_t chan_node_id) { int num_drive_rr_nodes = 0; t_rr_node** drive_rr_nodes = NULL; @@ -1592,11 +1393,12 @@ void dump_verilog_unique_switch_box_interc(t_sram_orgz_info* cur_sram_orgz_info, exit(1); } + /* Get the node */ + t_rr_node* cur_rr_node = rr_sb.get_chan_node(chan_side, chan_node_id); + /* Determine if the interc lies inside a channel wire, that is interc between segments */ /* Check each num_drive_rr_nodes, see if they appear in the cur_sb_info */ - if (true == rr_sb.is_sb_node_imply_short_connection(cur_rr_node)) { - /* Double check if the interc lies inside a channel wire, that is interc between segments */ - assert(true == rr_sb.is_sb_node_exist_opposite_side(cur_rr_node, chan_side)); + if (true == rr_sb.is_sb_node_passing_wire(chan_side, chan_node_id)) { num_drive_rr_nodes = 0; drive_rr_nodes = NULL; } else { @@ -2072,7 +1874,7 @@ void dump_verilog_routing_switch_box_unique_side_module(t_sram_orgz_info* cur_sr } dump_verilog_unique_switch_box_interc(cur_sram_orgz_info, fp, rr_sb, side_manager.get_side(), - rr_sb.get_chan_node(side_manager.get_side(), itrack)); + itrack); } } @@ -2482,7 +2284,7 @@ void dump_verilog_routing_switch_box_unique_subckt(t_sram_orgz_info* cur_sram_or if (OUT_PORT == rr_gsb.get_chan_node_direction(side_manager.get_side(), itrack)) { dump_verilog_unique_switch_box_interc(cur_sram_orgz_info, fp, rr_sb, side_manager.get_side(), - rr_gsb.get_chan_node(side_manager.get_side(), itrack)); + itrack); } } } @@ -3962,7 +3764,6 @@ void dump_verilog_routing_resources(t_sram_orgz_info* cur_sram_orgz_info, int LL_num_rr_nodes, t_rr_node* LL_rr_node, t_ivec*** LL_rr_node_indices, t_rr_indexed_data* LL_rr_indexed_data, - t_syn_verilog_opts fpga_verilog_opts, boolean compact_routing_hierarchy) { assert(UNI_DIRECTIONAL == routing_arch->directionality); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.h index 98c4a4e67..d5a2433ea 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.h @@ -132,7 +132,6 @@ void dump_verilog_routing_resources(t_sram_orgz_info* cur_sram_orgz_info, int LL_num_rr_nodes, t_rr_node* LL_rr_node, t_ivec*** LL_rr_node_indices, t_rr_indexed_data* LL_rr_indexed_data, - t_syn_verilog_opts fpga_verilog_opts, boolean compact_routing_hierarchy); #endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_sdc.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_sdc.c index 2b9a4267e..99b975baf 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_sdc.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_sdc.c @@ -370,7 +370,7 @@ void verilog_generate_sdc_break_loop_sb(FILE* fp, ||(CHANY == chan_rr_node->type)); /* We only care the output port and it should indicate a SB mux */ if ( (OUT_PORT != rr_gsb.get_chan_node_direction(side_manager.get_side(), itrack)) - || (false != rr_gsb.is_sb_node_imply_short_connection(chan_rr_node))) { + || (false != rr_gsb.is_sb_node_passing_wire(side_manager.get_side(), itrack))) { continue; } /* Bypass if we have only 1 driving node */ @@ -741,7 +741,7 @@ void verilog_generate_sdc_constrain_sbs(t_sdc_opts sdc_opts, continue; } /* Constrain thru wires */ - if (false != rr_gsb.is_sb_node_imply_short_connection(chan_rr_node)) { + if (false != rr_gsb.is_sb_node_passing_wire(side_manager.get_side(), itrack)) { /* Set the max, min delay to 0? */ verilog_generate_sdc_constrain_one_sb_path(fp, rr_gsb, chan_rr_node, @@ -2510,7 +2510,7 @@ void verilog_generate_wire_report_timing_blockage_direction(FILE* fp, int LL_nx, int LL_ny) { int ix, iy; - int side, itrack, inode; + int side, itrack; t_sb* cur_sb_info = NULL; From c879e7f6c50bd01241dcb82f2e0992158746d70a Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 26 Jun 2019 11:33:02 -0600 Subject: [PATCH 25/25] fixed a critical bug when instanciating Connection blocks --- .../vpr/SRC/fpga_x2p/verilog/verilog_api.c | 4 +- .../verilog/verilog_compact_netlist.c | 43 ++++++++----------- .../verilog/verilog_compact_netlist.h | 8 +--- 3 files changed, 22 insertions(+), 33 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c index 3b4b381ef..f4888c25f 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_api.c @@ -262,8 +262,7 @@ void vpr_fpga_verilog(t_vpr_setup vpr_setup, * 1. a compact output * 2. a full-size output */ - dump_compact_verilog_logic_blocks(sram_verilog_orgz_info, src_dir_path, lb_dir_path, &Arch, - vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts); + dump_compact_verilog_logic_blocks(sram_verilog_orgz_info, src_dir_path, lb_dir_path, &Arch); /* Dump internal structures of submodules */ dump_verilog_submodules(sram_verilog_orgz_info, src_dir_path, submodule_dir_path, @@ -275,7 +274,6 @@ void vpr_fpga_verilog(t_vpr_setup vpr_setup, top_netlist_path, src_dir_path, submodule_dir_path, lb_dir_path, rr_dir_path, num_rr_nodes, rr_node, rr_node_indices, num_clocks, - vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts, vpr_setup.FPGA_SPICE_Opts.compact_routing_hierarchy, *(Arch.spice)); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_compact_netlist.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_compact_netlist.c index 059f023e9..064cb2623 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_compact_netlist.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_compact_netlist.c @@ -281,9 +281,7 @@ void dump_compact_verilog_one_physical_block(t_sram_orgz_info* cur_sram_orgz_inf char* verilog_dir_path, char* subckt_dir_path, t_type_ptr phy_block_type, - int border_side, - t_arch* arch, - t_syn_verilog_opts fpga_verilog_opts) { + int border_side) { int iz; int temp_reserved_conf_bits_msb; int temp_iopad_lsb, temp_iopad_msb; @@ -514,8 +512,7 @@ void dump_compact_verilog_one_physical_block(t_sram_orgz_info* cur_sram_orgz_inf void dump_compact_verilog_logic_blocks(t_sram_orgz_info* cur_sram_orgz_info, char* verilog_dir, char* subckt_dir, - t_arch* arch, - t_syn_verilog_opts fpga_verilog_opts) { + t_arch* arch) { int itype, iside, num_sides; int* stamped_spice_model_cnt = NULL; t_sram_orgz_info* stamped_sram_orgz_info = NULL; @@ -537,23 +534,20 @@ void dump_compact_verilog_logic_blocks(t_sram_orgz_info* cur_sram_orgz_info, for (iside = 0; iside < num_sides; iside++) { dump_compact_verilog_one_physical_block(cur_sram_orgz_info, verilog_dir, subckt_dir, - &type_descriptors[itype], iside, - arch, fpga_verilog_opts); + &type_descriptors[itype], iside); } continue; } else if (FILL_TYPE == &type_descriptors[itype]) { /* For CLB */ dump_compact_verilog_one_physical_block(cur_sram_orgz_info, verilog_dir, subckt_dir, - &type_descriptors[itype], -1, - arch, fpga_verilog_opts); + &type_descriptors[itype], -1); continue; } else { /* For heterogenenous blocks */ dump_compact_verilog_one_physical_block(cur_sram_orgz_info, verilog_dir, subckt_dir, - &type_descriptors[itype], -1, - arch, fpga_verilog_opts); + &type_descriptors[itype], -1); } } @@ -975,7 +969,7 @@ void dump_compact_verilog_defined_one_connection_box(t_sram_orgz_info* cur_sram_ static void dump_compact_verilog_defined_connection_boxes(t_sram_orgz_info* cur_sram_orgz_info, FILE* fp) { - int ix, iy; + DeviceCoordinator sb_range = device_rr_gsb.get_gsb_range(); /* Check the file handler*/ if (NULL == fp) { @@ -984,21 +978,23 @@ void dump_compact_verilog_defined_connection_boxes(t_sram_orgz_info* cur_sram_or exit(1); } - /* X - channels [1...nx][0..ny]*/ - for (iy = 0; iy < (ny + 1); iy++) { - for (ix = 1; ix < (nx + 1); ix++) { + /* Walk through GSBs */ + for (size_t ix = 0; ix < sb_range.get_x(); ++ix) { + for (size_t iy = 0; iy < sb_range.get_y(); ++iy) { const RRGSB& rr_gsb = device_rr_gsb.get_gsb(ix, iy); - if ((TRUE == is_cb_exist(CHANX, ix, iy)) + + /* Get X-channel CB coordinator */ + const DeviceCoordinator cbx_coordinator = rr_gsb.get_cb_coordinator(CHANX); + /* X - channels [1...nx][0..ny]*/ + if ((TRUE == is_cb_exist(CHANX, cbx_coordinator.get_x(), cbx_coordinator.get_x())) &&(true == rr_gsb.is_cb_exist(CHANX))) { dump_compact_verilog_defined_one_connection_box(cur_sram_orgz_info, fp, rr_gsb, CHANX); } - } - } - /* Y - channels [1...ny][0..nx]*/ - for (ix = 0; ix < (nx + 1); ix++) { - for (iy = 1; iy < (ny + 1); iy++) { - const RRGSB& rr_gsb = device_rr_gsb.get_gsb(ix, iy); - if ((TRUE == is_cb_exist(CHANY, ix, iy)) + + /* Get X-channel CB coordinator */ + const DeviceCoordinator cby_coordinator = rr_gsb.get_cb_coordinator(CHANY); + /* Y - channels [1...ny][0..nx]*/ + if ((TRUE == is_cb_exist(CHANY, cby_coordinator.get_x(), cby_coordinator.get_x())) &&(true == rr_gsb.is_cb_exist(CHANY))) { dump_compact_verilog_defined_one_connection_box(cur_sram_orgz_info, fp, rr_gsb, CHANY); } @@ -1180,7 +1176,6 @@ void dump_compact_verilog_top_netlist(t_sram_orgz_info* cur_sram_orgz_info, t_rr_node* LL_rr_node, t_ivec*** LL_rr_node_indices, int num_clock, - t_syn_verilog_opts fpga_verilog_opts, boolean compact_routing_hierarchy, t_spice verilog) { FILE* fp = NULL; diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_compact_netlist.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_compact_netlist.h index 1d4eaa7f5..87eb33f78 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_compact_netlist.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_compact_netlist.h @@ -5,15 +5,12 @@ void dump_compact_verilog_one_physical_block(t_sram_orgz_info* cur_sram_orgz_inf char* verilog_dir_path, char* subckt_dir_path, t_type_ptr phy_block_type, - int border_side, - t_arch* arch, - t_syn_verilog_opts fpga_verilog_opts); + int border_side); void dump_compact_verilog_logic_blocks(t_sram_orgz_info* cur_sram_orgz_info, char* verilog_dir, char* subckt_dir, - t_arch* arch, - t_syn_verilog_opts fpga_verilog_opts); + t_arch* arch); void dump_compact_verilog_top_netlist(t_sram_orgz_info* cur_sram_orgz_info, char* circuit_name, @@ -26,7 +23,6 @@ void dump_compact_verilog_top_netlist(t_sram_orgz_info* cur_sram_orgz_info, t_rr_node* LL_rr_node, t_ivec*** LL_rr_node_indices, int num_clock, - t_syn_verilog_opts fpga_verilog_opts, boolean compact_routing_hierarchy, t_spice verilog); #endif