Merge branch 'refactoring' into dev

This commit is contained in:
tangxifan 2020-03-06 20:58:07 -07:00
commit 3eeac94a6e
22 changed files with 668 additions and 110 deletions

View File

@ -1590,12 +1590,16 @@ struct t_clock_arch_spec {
struct t_arch {
char* architecture_id; //Secure hash digest of the architecture file to uniquely identify this architecture
bool tileable;
t_chan_width_dist Chans;
enum e_switch_block_type SBType;
enum e_switch_block_type SBSubType;
std::vector<t_switchblock_inf> switchblocks;
float R_minW_nmos;
float R_minW_pmos;
int Fs;
int subFs;
float grid_logic_tile_area;
std::vector<t_segment_inf> Segments;
t_arch_switch_inf* Switches = nullptr;

View File

@ -2533,8 +2533,10 @@ static void ProcessModelPorts(pugi::xml_node port_group, t_model* model, std::se
static void ProcessLayout(pugi::xml_node layout_tag, t_arch* arch, const pugiutil::loc_data& loc_data) {
VTR_ASSERT(layout_tag.name() == std::string("layout"));
//Expect no attributes on <layout>
expect_only_attributes(layout_tag, {}, loc_data);
//Expect only tileable attributes on <layout>
//expect_only_attributes(layout_tag, {"tileable"}, loc_data);
arch->tileable = get_attribute(layout_tag, "tileable", loc_data).as_bool();
//Count the number of <auto_layout> or <fixed_layout> tags
size_t auto_layout_cnt = 0;
@ -2882,7 +2884,7 @@ static void ProcessDevice(pugi::xml_node Node, t_arch* arch, t_default_fc_spec&
//<switch_block> tag
Cur = get_single_child(Node, "switch_block", loc_data);
expect_only_attributes(Cur, {"type", "fs"}, loc_data);
//expect_only_attributes(Cur, {"type", "fs", "sub_type", "sub_fs"}, loc_data);
Prop = get_attribute(Cur, "type", loc_data).value();
if (strcmp(Prop, "wilton") == 0) {
arch->SBType = WILTON;
@ -2898,8 +2900,21 @@ static void ProcessDevice(pugi::xml_node Node, t_arch* arch, t_default_fc_spec&
"Unknown property %s for switch block type x\n", Prop);
}
Prop = get_attribute(Cur, "sub_type", loc_data, BoolToReqOpt(false)).value();
if (strcmp(Prop, "wilton") == 0) {
arch->SBSubType = WILTON;
} else if (strcmp(Prop, "universal") == 0) {
arch->SBSubType = UNIVERSAL;
} else if (strcmp(Prop, "subset") == 0) {
arch->SBSubType = SUBSET;
} else {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(Cur),
"Unknown property %s for switch block subtype x\n", Prop);
}
ReqOpt CUSTOM_SWITCHBLOCK_REQD = BoolToReqOpt(!custom_switch_block);
arch->Fs = get_attribute(Cur, "fs", loc_data, CUSTOM_SWITCHBLOCK_REQD).as_int(3);
arch->subFs = get_attribute(Cur, "sub_fs", loc_data, BoolToReqOpt(false)).as_int(3);
Cur = get_single_child(Node, "default_fc", loc_data, ReqOpt::OPTIONAL);
if (Cur) {

View File

@ -76,7 +76,7 @@
</tiles>
<!-- ODIN II specific config ends -->
<!-- Physical descriptions begin -->
<layout>
<layout tileable="true">
<auto_layout aspect_ratio="1.0">
<!--Perimeter of 'io' blocks with 'EMPTY' blocks at corners-->
<perimeter type="io" priority="100"/>
@ -110,7 +110,7 @@
<x distr="uniform" peak="1.000000"/>
<y distr="uniform" peak="1.000000"/>
</chan_width_distr>
<switch_block type="wilton" fs="3"/>
<switch_block type="wilton" fs="3" sub_type="subset" sub_fs="3"/>
<connection_block input_switch_name="ipin_cblock"/>
</device>
<switchlist>

View File

@ -309,9 +309,11 @@ static void SetupSwitches(const t_arch& Arch,
static void SetupRoutingArch(const t_arch& Arch,
t_det_routing_arch* RoutingArch) {
RoutingArch->switch_block_type = Arch.SBType;
RoutingArch->switch_block_subtype = Arch.SBSubType;
RoutingArch->R_minW_nmos = Arch.R_minW_nmos;
RoutingArch->R_minW_pmos = Arch.R_minW_pmos;
RoutingArch->Fs = Arch.Fs;
RoutingArch->subFs = Arch.subFs;
RoutingArch->directionality = BI_DIRECTIONAL;
if (Arch.Segments.size()) {
RoutingArch->directionality = Arch.Segments[0].directionality;

View File

@ -829,6 +829,11 @@ void vpr_create_rr_graph(t_vpr_setup& vpr_setup, const t_arch& arch, int chan_wi
graph_type = GRAPH_GLOBAL;
} else {
graph_type = (det_routing_arch->directionality == BI_DIRECTIONAL ? GRAPH_BIDIR : GRAPH_UNIDIR);
/* Branch on tileable routing */
if ( (UNI_DIRECTIONAL == det_routing_arch->directionality)
&& (true == arch.tileable) ) {
graph_type = GRAPH_UNIDIR_TILEABLE;
}
}
int warnings = 0;

View File

@ -148,6 +148,11 @@ struct DeviceContext : public Context {
/* RRGraph object */
RRGraph rr_graph;
/* Track ids for each rr_node in the rr_graph.
* This is used by drawer for tileable routing resource graph
*/
std::map<RRNodeId, std::vector<size_t>> rr_node_track_ids;
/* Structures to define the routing architecture of the FPGA. */
std::vector<t_rr_node> rr_nodes; /* autogenerated in build_rr_graph */

View File

@ -1004,6 +1004,12 @@ struct t_det_routing_arch {
enum e_switch_block_type switch_block_type;
std::vector<t_switchblock_inf> switchblocks;
/* Xifan Tang: subtype of switch blocks.
* Sub type and Fs are applied to pass tracks
*/
int subFs;
enum e_switch_block_type switch_block_subtype;
short global_route_switch;
short delayless_switch;
int wire_to_arch_ipin_switch;

View File

@ -583,6 +583,12 @@ class RRGraph {
/* Validate is the edge id does exist in the RRGraph */
bool valid_edge_id(const RREdgeId& edge) const;
/* Validate switch list */
bool valid_switch_id(const RRSwitchId& switch_id) const;
/* Validate segment list */
bool valid_segment_id(const RRSegmentId& segment_id) const;
public: /* Mutators */
/* Reserve the lists of nodes, edges, switches etc. to be memory efficient.
* This function is mainly used to reserve memory space inside RRGraph,
@ -835,12 +841,6 @@ class RRGraph {
bool validate_edge_src_nodes() const;
bool validate_edge_sink_nodes() const;
/* Validate switch list */
bool valid_switch_id(const RRSwitchId& switch_id) const;
/* Validate segment list */
bool valid_segment_id(const RRSegmentId& segment_id) const;
private: /* Internal Data */
/* Node related data */
size_t num_nodes_; /* Range of node ids */

View File

@ -1,6 +1,7 @@
#ifndef CHECK_RR_GRAPH_H
#define CHECK_RR_GRAPH_H
#include "physical_types.h"
#include "vpr_context.h"
void check_rr_graph(const t_graph_type graph_type,
const DeviceGrid& grid,

View File

@ -41,6 +41,8 @@
#include "rr_graph_obj_util.h"
#include "check_rr_graph_obj.h"
#include "tileable_rr_graph_builder.h"
#include "clb2clb_directs.h"
//#define VERBOSE
@ -236,30 +238,12 @@ void uniquify_edges(t_rr_edge_info_set& rr_edges_to_create);
void alloc_and_load_edges(RRGraph& rr_graph,
const t_rr_edge_info_set& rr_edges_to_create);
static void alloc_and_load_rr_switch_inf(const int num_arch_switches,
const float R_minW_nmos,
const float R_minW_pmos,
const int wire_to_arch_ipin_switch,
int* wire_to_rr_ipin_switch);
static
t_rr_switch_inf create_rr_switch_from_arch_switch(int arch_switch_idx,
const float R_minW_nmos,
const float R_minW_pmos);
static void remap_rr_node_switch_indices(const t_arch_switch_fanin& switch_fanin);
static void load_rr_switch_inf(const int num_arch_switches, const float R_minW_nmos, const float R_minW_pmos, const t_arch_switch_fanin& switch_fanin);
static void alloc_rr_switch_inf(t_arch_switch_fanin& switch_fanin);
static void rr_graph_externals(const std::vector<t_segment_inf>& segment_inf,
int max_chan_width,
int wire_to_rr_ipin_switch,
enum e_base_cost_type base_cost_type);
static t_clb_to_clb_directs* alloc_and_load_clb_to_clb_directs(const t_direct_inf* directs, const int num_directs, const int delayless_switch);
static void free_type_track_to_pin_map(t_track_to_pin_lookup& track_to_pin_map,
const std::vector<t_physical_tile_type>& types,
int max_chan_width);
@ -267,15 +251,6 @@ static void free_type_track_to_pin_map(t_track_to_pin_lookup& track_to_pin_map,
static t_seg_details* alloc_and_load_global_route_seg_details(const int global_route_switch,
int* num_seg_details = nullptr);
static std::vector<vtr::Matrix<int>> alloc_and_load_actual_fc(const std::vector<t_physical_tile_type>& types,
const int max_pins,
const std::vector<t_segment_inf>& segment_inf,
const int* sets_per_seg_type,
const int max_chan_width,
const e_fc_type fc_type,
const enum e_directionality directionality,
bool* Fc_clipped);
static RRNodeId pick_best_direct_connect_target_rr_node(const RRGraph& rr_graph,
const RRNodeId& from_rr,
const std::vector<RRNodeId>& candidate_rr_nodes);
@ -345,6 +320,7 @@ void create_rr_graph(const t_graph_type graph_type,
free_rr_graph();
if (GRAPH_UNIDIR_TILEABLE != graph_type) {
build_rr_graph(graph_type,
block_types,
grid,
@ -373,6 +349,26 @@ void create_rr_graph(const t_graph_type graph_type,
det_routing_arch->wire_to_rr_ipin_switch,
base_cost_type);
}
} else {
/* We do not support dedicated network for clocks in tileable rr_graph generation */
openfpga::build_tileable_unidir_rr_graph(block_types,
grid,
nodes_per_chan,
det_routing_arch->switch_block_type,
det_routing_arch->Fs,
det_routing_arch->switch_block_subtype,
det_routing_arch->subFs,
segment_inf,
det_routing_arch->wire_to_arch_ipin_switch,
det_routing_arch->delayless_switch,
det_routing_arch->R_minW_nmos,
det_routing_arch->R_minW_pmos,
base_cost_type,
directs, num_directs,
&det_routing_arch->wire_to_rr_ipin_switch,
false, /* Do not allow passing tracks to be wired to the same routing channels */
Warnings);
}
/* Xifan Tang - Create rr_graph object: load rr_nodes to the object */
//convert_rr_graph(segment_inf);
@ -836,7 +832,7 @@ static void build_rr_graph(const t_graph_type graph_type,
* and count how many different fan-ins exist for each arch switch.
* Then we create these rr switches and update the switch indices
* of rr_nodes to index into the rr_switch_inf array. */
static void alloc_and_load_rr_switch_inf(const int num_arch_switches, const float R_minW_nmos, const float R_minW_pmos, const int wire_to_arch_ipin_switch, int* wire_to_rr_ipin_switch) {
void alloc_and_load_rr_switch_inf(const int num_arch_switches, const float R_minW_nmos, const float R_minW_pmos, const int wire_to_arch_ipin_switch, int* wire_to_rr_ipin_switch) {
/* we will potentially be creating a couple of versions of each arch switch where
* each version corresponds to a different fan-in. We will need to fill device_ctx.rr_switch_inf
* with this expanded list of switches.
@ -962,7 +958,6 @@ static void load_rr_switch_inf(const int num_arch_switches, const float R_minW_n
}
static
t_rr_switch_inf create_rr_switch_from_arch_switch(int arch_switch_idx,
const float R_minW_nmos,
const float R_minW_pmos) {
@ -1057,7 +1052,7 @@ static void remap_rr_node_switch_indices(const t_arch_switch_fanin& switch_fanin
}
}
static void rr_graph_externals(const std::vector<t_segment_inf>& segment_inf,
void rr_graph_externals(const std::vector<t_segment_inf>& segment_inf,
int max_chan_width,
int wire_to_rr_ipin_switch,
enum e_base_cost_type base_cost_type) {
@ -1152,7 +1147,7 @@ static t_seg_details* alloc_and_load_global_route_seg_details(const int global_r
}
/* Calculates the number of track connections from each block pin to each segment type */
static std::vector<vtr::Matrix<int>> alloc_and_load_actual_fc(const std::vector<t_physical_tile_type>& types,
std::vector<vtr::Matrix<int>> alloc_and_load_actual_fc(const std::vector<t_physical_tile_type>& types,
const int max_pins,
const std::vector<t_segment_inf>& segment_inf,
const int* sets_per_seg_type,
@ -1509,6 +1504,7 @@ void free_rr_graph() {
/* Xifan Tang - Clear the rr_graph object */
device_ctx.rr_graph.clear();
device_ctx.rr_node_track_ids.clear();
}
static void build_rr_sinks_sources(const int i,
@ -2775,7 +2771,7 @@ static void build_unidir_rr_opins(const int i, const int j,
* 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
*/
static t_clb_to_clb_directs* alloc_and_load_clb_to_clb_directs(const t_direct_inf* directs, const int num_directs, int delayless_switch) {
t_clb_to_clb_directs* alloc_and_load_clb_to_clb_directs(const t_direct_inf* directs, const int num_directs, int delayless_switch) {
int i;
t_clb_to_clb_directs* clb_to_clb_directs;
char *tile_name, *port_name;

View File

@ -7,6 +7,7 @@
#define INCLUDE_TRACK_BUFFERS false
#include "device_grid.h"
#include "clb2clb_directs.h"
enum e_graph_type {
GRAPH_GLOBAL, /* One node per channel with wire capacity > 1 and full connectivity */
@ -56,4 +57,30 @@ void load_rr_switch_from_arch_switch(int arch_switch_idx,
t_non_configurable_rr_sets identify_non_configurable_rr_sets();
void rr_graph_externals(const std::vector<t_segment_inf>& segment_inf,
int max_chan_width,
int wire_to_rr_ipin_switch,
enum e_base_cost_type base_cost_type);
void alloc_and_load_rr_switch_inf(const int num_arch_switches,
const float R_minW_nmos,
const float R_minW_pmos,
const int wire_to_arch_ipin_switch,
int* wire_to_rr_ipin_switch);
t_clb_to_clb_directs* alloc_and_load_clb_to_clb_directs(const t_direct_inf* directs, const int num_directs, const int delayless_switch);
std::vector<vtr::Matrix<int>> alloc_and_load_actual_fc(const std::vector<t_physical_tile_type>& types,
const int max_pins,
const std::vector<t_segment_inf>& segment_inf,
const int* sets_per_seg_type,
const int max_chan_width,
const e_fc_type fc_type,
const enum e_directionality directionality,
bool* Fc_clipped);
t_rr_switch_inf create_rr_switch_from_arch_switch(int arch_switch_idx,
const float R_minW_nmos,
const float R_minW_pmos);
#endif

View File

@ -15,6 +15,21 @@
/* begin namespace openfpga */
namespace openfpga {
/************************************************************************
* Correct number of routing channel width to be compatible to
* uni-directional routing architecture
***********************************************************************/
size_t find_unidir_routing_channel_width(const size_t& chan_width) {
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 */
}
VTR_ASSERT(0 == actual_chan_width % 2);
return actual_chan_width;
}
/************************************************************************
* Get the class index of a grid pin
***********************************************************************/

View File

@ -15,6 +15,8 @@
/* begin namespace openfpga */
namespace openfpga {
size_t find_unidir_routing_channel_width(const size_t& chan_width);
int get_grid_pin_class_index(const t_grid_tile& cur_grid,
const int pin_index);

View File

@ -11,6 +11,7 @@
#include "vtr_assert.h"
#include "vtr_log.h"
#include "rr_graph_builder_utils.h"
#include "tileable_chan_details_builder.h"
/* begin namespace openfpga */
@ -25,7 +26,6 @@ namespace openfpga {
* 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<size_t> get_num_tracks_per_seg_type(const size_t& chan_width,
const std::vector<t_segment_inf>& segment_inf,
const bool& use_full_seg_groups) {
@ -167,11 +167,7 @@ ChanNodeDetails build_unidir_chan_node_details(const size_t& chan_width,
const bool& force_end,
const std::vector<t_segment_inf>& 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 */
}
size_t actual_chan_width = find_unidir_routing_channel_width(chan_width);
VTR_ASSERT(0 == actual_chan_width % 2);
/* Reserve channel width */

View File

@ -15,6 +15,10 @@
/* begin namespace openfpga */
namespace openfpga {
std::vector<size_t> get_num_tracks_per_seg_type(const size_t& chan_width,
const std::vector<t_segment_inf>& segment_inf,
const bool& use_full_seg_groups);
int adapt_to_tileable_route_chan_width(const int& chan_width, const std::vector<t_segment_inf>& segment_inf);
ChanNodeDetails build_unidir_chan_node_details(const size_t& chan_width,

View File

@ -0,0 +1,326 @@
/************************************************************************
* This file contains a builder for the complex rr_graph data structure
* Different from VPR rr_graph builders, this builder aims to create a
* highly regular rr_graph, where each Connection Block (CB), Switch
* Block (SB) is the same (except for those on the borders). Thus, the
* rr_graph is called tileable, which brings significant advantage in
* producing large FPGA fabrics.
***********************************************************************/
/* Headers from vtrutil library */
#include "vtr_assert.h"
#include "vtr_time.h"
#include "vtr_log.h"
#include "vtr_memory.h"
#include "vpr_error.h"
#include "vpr_utils.h"
#include "rr_graph.h"
#include "check_rr_graph.h"
#include "check_rr_graph_obj.h"
#include "rr_graph_builder_utils.h"
#include "tileable_chan_details_builder.h"
#include "tileable_rr_graph_node_builder.h"
#include "tileable_rr_graph_edge_builder.h"
#include "tileable_rr_graph_builder.h"
#include "globals.h"
/* begin namespace openfpga */
namespace openfpga {
/************************************************************************
* Main function of this file
* Builder for a detailed uni-directional tileable rr_graph
* Global graph is not supported here, the VPR rr_graph generator can be used
* It follows the procedures to complete the rr_graph generation
* 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. Estimate the number of nodes in the rr_graph
* This will estimate the number of
* a. IPINs, input pins of each grid
* b. OPINs, output pins of each grid
* c. SOURCE, virtual node which drives OPINs
* d. SINK, virtual node which is connected to IPINs
* e. CHANX and CHANY, routing segments of each channel
* 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
* 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
* 5. Create the switch block patterns,
* It is based on the type of switch block, the supported patterns are
* a. Disjoint, which connects routing track (i)th from (i)th and (i)th routing segments
* b. Universal, which connects routing track (i)th from (i)th and (M-i)th routing segments
* c. Wilton, which rotates the connection of Disjoint by 1 track
* 6. Allocate rr_graph, fill the node information
* For each node, fill
* a. basic information: coordinate(xlow, xhigh, ylow, yhigh), ptc_num
* b. edges (both incoming and outcoming)
* c. handle direct-connections
* 7. Build fast look-up for the rr_graph
* 8. Allocate external data structures
* a. cost_index
* b. RC tree
***********************************************************************/
void build_tileable_unidir_rr_graph(const std::vector<t_physical_tile_type>& types,
const DeviceGrid& grids,
const t_chan_width& chan_width,
const e_switch_block_type& sb_type, const int& Fs,
const e_switch_block_type& sb_subtype, const int& subFs,
const std::vector<t_segment_inf>& segment_inf,
const int& delayless_switch,
const int& wire_to_arch_ipin_switch,
const float R_minW_nmos,
const float R_minW_pmos,
const enum e_base_cost_type& base_cost_type,
const t_direct_inf *directs,
const int& num_directs,
int* wire_to_rr_ipin_switch,
const bool& wire_opposite_side,
int *Warnings) {
vtr::ScopedStartFinishTimer timer("Build tileable routing resource graph");
/* Reset warning flag */
*Warnings = RR_GRAPH_NO_WARN;
/* Create a matrix of grid */
/* Create a vector of channel width, we support X-direction and Y-direction has different W */
vtr::Point<size_t> device_chan_width(chan_width.x_max, chan_width.y_max);
VTR_LOG("X-direction routing channel width is %lu\n", device_chan_width.x());
VTR_LOG("Y-direction routing channel width is %lu\n", device_chan_width.y());
/* Get a mutable device ctx so that we have a mutable rr_graph */
DeviceContext& device_ctx = g_vpr_ctx.mutable_device();
/* The number of segments are in general small, reserve segments may not bring
* significant memory efficiency */
device_ctx.rr_graph.reserve_segments(segment_inf.size());
/* Create the segments */
for (size_t iseg = 0; iseg < segment_inf.size(); ++iseg) {
device_ctx.rr_graph.create_segment(segment_inf[iseg]);
}
/* TODO: Load architecture switch to rr_graph switches
* Draft the switches as internal data of RRGraph object
* These are temporary switches copied from arch switches
* We use them to build the edges
* We will reset all the switches in the function
* alloc_and_load_rr_switch_inf()
*/
/* TODO: Spot the switch id in the architecture switch list */
RRSwitchId wire_to_ipin_rr_switch = RRSwitchId::INVALID();
RRSwitchId delayless_rr_switch = RRSwitchId::INVALID();
device_ctx.rr_graph.reserve_switches(device_ctx.num_arch_switches);
/* Create the switches */
for (int iswitch = 0; iswitch < device_ctx.num_arch_switches; ++iswitch) {
const t_rr_switch_inf& temp_rr_switch = create_rr_switch_from_arch_switch(iswitch, R_minW_nmos, R_minW_pmos);
RRSwitchId rr_switch = device_ctx.rr_graph.create_switch(temp_rr_switch);
if (iswitch == wire_to_arch_ipin_switch) {
wire_to_ipin_rr_switch = rr_switch;
}
if (iswitch == delayless_switch) {
delayless_rr_switch = rr_switch;
}
}
/* Validate the special switches */
VTR_ASSERT(true == device_ctx.rr_graph.valid_switch_id(wire_to_ipin_rr_switch));
VTR_ASSERT(true == device_ctx.rr_graph.valid_switch_id(delayless_rr_switch));
/* A temp data about the driver switch ids for each rr_node */
vtr::vector<RRNodeId, RRSwitchId> rr_node_driver_switches;
/* A temp data about the track ids for each CHANX and CHANY rr_node */
std::map<RRNodeId, std::vector<size_t>> rr_node_track_ids;
/************************
* Allocate the rr_nodes
************************/
alloc_tileable_rr_graph_nodes(device_ctx.rr_graph,
rr_node_driver_switches,
grids,
device_chan_width,
segment_inf);
/************************
* Create all the rr_nodes
************************/
create_tileable_rr_graph_nodes(device_ctx.rr_graph,
rr_node_driver_switches,
rr_node_track_ids,
grids,
device_chan_width,
segment_inf,
wire_to_ipin_rr_switch,
delayless_rr_switch);
/************************************************************************
* Create the connectivity of OPINs
* a. Evenly assign connections to OPINs to routing tracks
* b. the connection pattern should be same across the fabric
*
* Create the connectivity of IPINs
* a. Evenly assign connections from routing tracks to IPINs
* b. the connection pattern should be same across the fabric
***********************************************************************/
/* Global routing uses a single longwire track */
int max_chan_width = find_unidir_routing_channel_width(chan_width.max);
VTR_ASSERT(max_chan_width > 0);
/* get maximum number of pins across all blocks */
int max_pins = types[0].num_pins;
for (const auto& type : types) {
if (is_empty_type(&type)) {
continue;
}
if (type.num_pins > max_pins) {
max_pins = type.num_pins;
}
}
/* Fc assignment still uses the old function from VPR.
* Should use tileable version so that we have can have full control
*/
std::vector<size_t> num_tracks = get_num_tracks_per_seg_type(max_chan_width / 2, segment_inf, false);
int* sets_per_seg_type = (int*)vtr::malloc(sizeof(int) * segment_inf.size());
VTR_ASSERT(num_tracks.size() == segment_inf.size());
for (size_t iseg = 0; iseg < num_tracks.size(); ++iseg) {
sets_per_seg_type[iseg] = num_tracks[iseg];
}
bool Fc_clipped = false;
/* [0..num_types-1][0..num_pins-1] */
std::vector<vtr::Matrix<int>> Fc_in;
Fc_in = alloc_and_load_actual_fc(types, max_pins, segment_inf, sets_per_seg_type, max_chan_width,
e_fc_type::IN, UNI_DIRECTIONAL, &Fc_clipped);
if (Fc_clipped) {
*Warnings |= RR_GRAPH_WARN_FC_CLIPPED;
}
Fc_clipped = false;
/* [0..num_types-1][0..num_pins-1] */
std::vector<vtr::Matrix<int>> Fc_out;
Fc_out = alloc_and_load_actual_fc(types, max_pins, segment_inf, sets_per_seg_type, max_chan_width,
e_fc_type::OUT, UNI_DIRECTIONAL, &Fc_clipped);
if (Fc_clipped) {
*Warnings |= RR_GRAPH_WARN_FC_CLIPPED;
}
/************************************************************************
* 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(device_ctx.rr_graph,
rr_node_driver_switches,
grids,
device_chan_width,
segment_inf,
Fc_in, Fc_out,
sb_type, Fs, sb_subtype, subFs,
wire_opposite_side);
/************************************************************************
* Build direction connection lists
* TODO: use tile direct builder
***********************************************************************/
/* 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, delayless_switch);
}
std::vector<t_direct_inf> arch_directs;
std::vector<t_clb_to_clb_directs> clb2clb_directs;
for (int idirect = 0; idirect < num_directs; ++idirect) {
arch_directs.push_back(directs[idirect]);
clb2clb_directs.push_back(clb_to_clb_directs[idirect]);
}
build_rr_graph_direct_connections(device_ctx.rr_graph, grids, delayless_rr_switch,
arch_directs, clb2clb_directs);
/* First time to build edges so that we can remap the architecture switch to rr_switch
* This is a must-do before function alloc_and_load_rr_switch_inf()
*/
device_ctx.rr_graph.rebuild_node_edges();
/* Allocate and load routing resource switches, which are derived from the switches from the architecture file,
* based on their fanin in the rr graph. This routine also adjusts the rr nodes to point to these new rr switches */
alloc_and_load_rr_switch_inf(device_ctx.num_arch_switches, R_minW_nmos, R_minW_pmos, wire_to_arch_ipin_switch, wire_to_rr_ipin_switch);
/* Save the channel widths for the newly constructed graph */
device_ctx.chan_width = chan_width;
/* Save the track ids for tileable routing resource graph */
device_ctx.rr_node_track_ids = rr_node_track_ids;
/************************************************************************
* Allocate external data structures
* a. cost_index
* b. RC tree
***********************************************************************/
rr_graph_externals(segment_inf, max_chan_width,
*wire_to_rr_ipin_switch, base_cost_type);
/* Rebuild the link between RRGraph node and segments
* Should be called only AFTER the function
* rr_graph_externals()
*/
for (const RRNodeId& inode : device_ctx.rr_graph.nodes()) {
if ( (CHANX != device_ctx.rr_graph.node_type(inode))
&& (CHANY != device_ctx.rr_graph.node_type(inode)) ) {
continue;
}
short irc_data = device_ctx.rr_graph.node_cost_index(inode);
short iseg = device_ctx.rr_indexed_data[irc_data].seg_index;
device_ctx.rr_graph.set_node_segment(inode, RRSegmentId(iseg));
}
/************************************************************************
* Sanitizer for the rr_graph, check connectivities of rr_nodes
***********************************************************************/
/* Essential check for rr_graph, build look-up and */
if (false == device_ctx.rr_graph.validate()) {
/* Error out if built-in validator of rr_graph fails */
vpr_throw(VPR_ERROR_ROUTE,
__FILE__,
__LINE__,
"Fundamental errors occurred when validating rr_graph object!\n");
}
check_rr_graph(GRAPH_UNIDIR, grids, types);
/* Error out if advanced checker of rr_graph fails */
if (false == check_rr_graph(device_ctx.rr_graph)) {
vpr_throw(VPR_ERROR_ROUTE,
__FILE__,
__LINE__,
"Advanced checking rr_graph object fails! Routing may still work "
"but not smooth\n");
}
/************************************************************************
* Free all temp stucts
***********************************************************************/
free(sets_per_seg_type);
if (nullptr != clb_to_clb_directs) {
free(clb_to_clb_directs);
}
}
} /* end namespace openfpga */

View File

@ -0,0 +1,38 @@
#ifndef TILEABLE_RR_GRAPH_BUILDER_H
#define TILEABLE_RR_GRAPH_BUILDER_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include <vector>
#include "physical_types.h"
#include "device_grid.h"
/********************************************************************
* Function declaration
*******************************************************************/
/* begin namespace openfpga */
namespace openfpga {
void build_tileable_unidir_rr_graph(const std::vector<t_physical_tile_type>& types,
const DeviceGrid& grids,
const t_chan_width& chan_width,
const e_switch_block_type& sb_type, const int& Fs,
const e_switch_block_type& sb_subtype, const int& subFs,
const std::vector<t_segment_inf>& segment_inf,
const int& delayless_switch,
const int& wire_to_arch_ipin_switch,
const float R_minW_nmos,
const float R_minW_pmos,
const enum e_base_cost_type& base_cost_type,
const t_direct_inf *directs,
const int& num_directs,
int* wire_to_rr_ipin_switch,
const bool& wire_opposite_side,
int *Warnings);
} /* end namespace openfpga */
#endif

View File

@ -92,7 +92,8 @@ void build_rr_graph_edges(RRGraph& rr_graph,
const DeviceGrid& grids,
const vtr::Point<size_t>& device_chan_width,
const std::vector<t_segment_inf>& segment_inf,
int** Fc_in, int** Fc_out,
const std::vector<vtr::Matrix<int>>& Fc_in,
const std::vector<vtr::Matrix<int>>& Fc_out,
const e_switch_block_type& sb_type, const int& Fs,
const e_switch_block_type& sb_subtype, const int& subFs,
const bool& wire_opposite_side) {

View File

@ -7,6 +7,7 @@
#include <vector>
/* Headers from vtrutil library */
#include "vtr_ndmatrix.h"
#include "vtr_geometry.h"
#include "physical_types.h"
@ -26,7 +27,8 @@ void build_rr_graph_edges(RRGraph& rr_graph,
const DeviceGrid& grids,
const vtr::Point<size_t>& device_chan_width,
const std::vector<t_segment_inf>& segment_inf,
int** Fc_in, int** Fc_out,
const std::vector<vtr::Matrix<int>>& Fc_in,
const std::vector<vtr::Matrix<int>>& Fc_out,
const e_switch_block_type& sb_type, const int& Fs,
const e_switch_block_type& sb_subtype, const int& subFs,
const bool& wire_opposite_side);

View File

@ -966,7 +966,7 @@ void build_gsb_one_ipin_track2pin_map(const RRGraph& rr_graph,
const RRGSB& rr_gsb,
const enum e_side& ipin_side,
const size_t& ipin_node_id,
const size_t& Fc,
const std::vector<int>& Fc,
const size_t& offset,
const std::vector<t_segment_inf>& segment_inf,
t_track2pin_map& track2ipin_map) {
@ -995,7 +995,7 @@ void build_gsb_one_ipin_track2pin_map(const RRGraph& rr_graph,
VTR_ASSERT(0 == actual_track_list.size() % 2);
/* Scale Fc */
int actual_Fc = std::ceil((float)Fc * (float)actual_track_list.size() / (float)chan_width);
int actual_Fc = std::ceil((float)Fc[iseg] * (float)actual_track_list.size() / (float)chan_width);
/* Minimum Fc should be 2 : ensure we will connect to a pair of routing tracks */
actual_Fc = std::max(1, actual_Fc);
/* Compute the step between two connection from this IPIN to tracks:
@ -1060,7 +1060,7 @@ void build_gsb_one_opin_pin2track_map(const RRGraph& rr_graph,
const RRGSB& rr_gsb,
const enum e_side& opin_side,
const size_t& opin_node_id,
const size_t& Fc,
const std::vector<int>& Fc,
const size_t& offset,
const std::vector<t_segment_inf>& segment_inf,
t_pin2track_map& opin2track_map) {
@ -1094,7 +1094,7 @@ void build_gsb_one_opin_pin2track_map(const RRGraph& rr_graph,
}
/* Scale Fc */
int actual_Fc = std::ceil((float)Fc * (float)actual_track_list.size() / (float)chan_width);
int actual_Fc = std::ceil((float)Fc[iseg] * (float)actual_track_list.size() / (float)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:
@ -1144,8 +1144,6 @@ void build_gsb_one_opin_pin2track_map(const RRGraph& rr_graph,
}
*/
}
return;
}
@ -1163,7 +1161,7 @@ t_track2pin_map build_gsb_track_to_ipin_map(const RRGraph& rr_graph,
const RRGSB& rr_gsb,
const DeviceGrid& grids,
const std::vector<t_segment_inf>& segment_inf,
int** Fc_in) {
const std::vector<vtr::Matrix<int>>& Fc_in) {
t_track2pin_map track2ipin_map;
/* Resize the matrix */
track2ipin_map.resize(rr_gsb.get_num_sides());
@ -1202,16 +1200,29 @@ t_track2pin_map build_gsb_track_to_ipin_map(const RRGraph& rr_graph,
if (true == is_empty_type(grids[rr_graph.node_xlow(ipin_node)][rr_graph.node_ylow(ipin_node)].type)) {
continue;
}
int grid_type_index = grids[rr_graph.node_xlow(ipin_node)][rr_graph.node_ylow(ipin_node)].type->index;
/* Get Fc of the ipin */
int ipin_Fc = Fc_in[grid_type_index][rr_graph.node_pin_num(ipin_node)];
/* skip Fc = 0 */
if ( (-1 == ipin_Fc)
|| (0 == ipin_Fc) ) {
/* skip Fc = 0 or unintialized, those pins are in the <directlist> */
bool skip_conn2track = true;
std::vector<int> ipin_Fc_out;
for (size_t iseg = 0; iseg < segment_inf.size(); ++iseg) {
int ipin_Fc = Fc_in[grid_type_index][rr_graph.node_pin_num(ipin_node)][iseg];
ipin_Fc_out.push_back(ipin_Fc);
if (0 != ipin_Fc) {
skip_conn2track = false;
break;
}
}
if (true == skip_conn2track) {
continue;
}
VTR_ASSERT(ipin_Fc_out.size() == segment_inf.size());
/* Build track2ipin_map for this IPIN */
build_gsb_one_ipin_track2pin_map(rr_graph, rr_gsb, ipin_side, inode, ipin_Fc,
build_gsb_one_ipin_track2pin_map(rr_graph, rr_gsb, ipin_side, inode, ipin_Fc_out,
/* Give an offset for the first track that this ipin will connect to */
offset[chan_side_manager.to_size_t()],
segment_inf, track2ipin_map);
@ -1240,7 +1251,7 @@ t_pin2track_map build_gsb_opin_to_track_map(const RRGraph& rr_graph,
const RRGSB& rr_gsb,
const DeviceGrid& grids,
const std::vector<t_segment_inf>& segment_inf,
int** Fc_out) {
const std::vector<vtr::Matrix<int>>& Fc_out) {
t_pin2track_map opin2track_map;
/* Resize the matrix */
opin2track_map.resize(rr_gsb.get_num_sides());
@ -1269,15 +1280,27 @@ t_pin2track_map build_gsb_opin_to_track_map(const RRGraph& rr_graph,
continue;
}
int grid_type_index = grids[rr_graph.node_xlow(opin_node)][rr_graph.node_ylow(opin_node)].type->index;
/* Get Fc of the ipin */
int opin_Fc = Fc_out[grid_type_index][rr_graph.node_pin_num(opin_node)];
/* skip Fc = 0 or unintialized, those pins are in the <directlist> */
if ( (-1 == opin_Fc)
|| (0 == opin_Fc) ) {
bool skip_conn2track = true;
std::vector<int> opin_Fc_out;
for (size_t iseg = 0; iseg < segment_inf.size(); ++iseg) {
int opin_Fc = Fc_out[grid_type_index][rr_graph.node_pin_num(opin_node)][iseg];
opin_Fc_out.push_back(opin_Fc);
if (0 != opin_Fc) {
skip_conn2track = false;
break;
}
}
if (true == skip_conn2track) {
continue;
}
VTR_ASSERT(opin_Fc_out.size() == segment_inf.size());
/* Build track2ipin_map for this IPIN */
build_gsb_one_opin_pin2track_map(rr_graph, rr_gsb, opin_side, inode, opin_Fc,
build_gsb_one_opin_pin2track_map(rr_graph, rr_gsb, opin_side, inode, opin_Fc_out,
/* Give an offset for the first track that this ipin will connect to */
offset[side_manager.to_size_t()],
segment_inf, opin2track_map);
@ -1293,4 +1316,94 @@ t_pin2track_map build_gsb_opin_to_track_map(const RRGraph& rr_graph,
return opin2track_map;
}
/************************************************************************
* Add all direct clb-pin-to-clb-pin edges to given opin
***********************************************************************/
void build_direct_connections_for_one_gsb(RRGraph& rr_graph,
const DeviceGrid& grids,
const vtr::Point<size_t>& from_grid_coordinate,
const RRSwitchId& delayless_switch,
const std::vector<t_direct_inf>& directs,
const std::vector<t_clb_to_clb_directs>& clb_to_clb_directs) {
VTR_ASSERT(directs.size() == clb_to_clb_directs.size());
const t_grid_tile& from_grid = grids[from_grid_coordinate.x()][from_grid_coordinate.y()];
t_physical_tile_type_ptr grid_type = from_grid.type;
/* Iterate through all direct connections */
for (size_t i = 0; i < directs.size(); ++i) {
/* Bypass unmatched direct clb-to-clb connections */
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
*/
vtr::Point<size_t> to_grid_coordinate(from_grid_coordinate.x() + directs[i].x_offset,
from_grid_coordinate.y() + directs[i].y_offset);
/* Bypass unmatched direct clb-to-clb connections */
t_physical_tile_type_ptr to_grid_type = grids[to_grid_coordinate.x()][to_grid_coordinate.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 */
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;
if ( (to_grid_coordinate.x() < grids.width() - 1)
&& (to_grid_coordinate.y() < grids.height() - 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_width_ofs = from_grid.width_offset;
int from_grid_height_ofs = from_grid.height_offset;
int to_grid_width_ofs = grids[to_grid_coordinate.x()][to_grid_coordinate.y()].width_offset;
int to_grid_height_ofs = grids[to_grid_coordinate.x()][to_grid_coordinate.y()].height_offset;
const RRNodeId& opin_node_id = rr_graph.find_node(from_grid_coordinate.x() - from_grid_width_ofs,
from_grid_coordinate.y() - from_grid_height_ofs,
OPIN, opin);
const RRNodeId& ipin_node_id = rr_graph.find_node(to_grid_coordinate.x() - to_grid_width_ofs,
to_grid_coordinate.y() - to_grid_height_ofs,
IPIN, ipin);
/* add edges to the opin_node */
rr_graph.create_edge(opin_node_id, ipin_node_id,
delayless_switch);
}
}
}
}
} /* end namespace openfpga */

View File

@ -59,13 +59,13 @@ t_track2pin_map build_gsb_track_to_ipin_map(const RRGraph& rr_graph,
const RRGSB& rr_gsb,
const DeviceGrid& grids,
const std::vector<t_segment_inf>& segment_inf,
int** Fc_in);
const std::vector<vtr::Matrix<int>>& Fc_in);
t_pin2track_map build_gsb_opin_to_track_map(const RRGraph& rr_graph,
const RRGSB& rr_gsb,
const DeviceGrid& grids,
const std::vector<t_segment_inf>& segment_inf,
int** Fc_out);
const std::vector<vtr::Matrix<int>>& Fc_out);
void build_direct_connections_for_one_gsb(RRGraph& rr_graph,
const DeviceGrid& grids,

View File

@ -376,8 +376,8 @@ void load_one_grid_opin_nodes_basic_info(RRGraph& rr_graph,
/* node bounding box */
rr_graph.set_node_bounding_box(node, vtr::Rect<short>(grid_coordinate.x() + width,
grid_coordinate.x() + width,
grid_coordinate.y() + height,
grid_coordinate.x() + width,
grid_coordinate.y() + height));
rr_graph.set_node_side(node, side_manager.get_side());
rr_graph.set_node_pin_num(node, pin_num);
@ -439,8 +439,8 @@ void load_one_grid_ipin_nodes_basic_info(RRGraph& rr_graph,
/* node bounding box */
rr_graph.set_node_bounding_box(node, vtr::Rect<short>(grid_coordinate.x() + width,
grid_coordinate.x() + width,
grid_coordinate.y() + height,
grid_coordinate.x() + width,
grid_coordinate.y() + height));
rr_graph.set_node_side(node, side_manager.get_side());
rr_graph.set_node_pin_num(node, pin_num);
@ -491,8 +491,8 @@ void load_one_grid_source_nodes_basic_info(RRGraph& rr_graph,
/* node bounding box */
rr_graph.set_node_bounding_box(node, vtr::Rect<short>(grid_coordinate.x(),
grid_coordinate.x(),
grid_coordinate.y(),
grid_coordinate.x(),
grid_coordinate.y()));
rr_graph.set_node_class_num(node, iclass);
@ -542,8 +542,8 @@ void load_one_grid_sink_nodes_basic_info(RRGraph& rr_graph,
/* node bounding box */
rr_graph.set_node_bounding_box(node, vtr::Rect<short>(grid_coordinate.x(),
grid_coordinate.x(),
grid_coordinate.y(),
grid_coordinate.x(),
grid_coordinate.y()));
rr_graph.set_node_class_num(node, iclass);