Merge branch 'refactoring' into dev
This commit is contained in:
commit
3eeac94a6e
|
@ -1589,13 +1589,17 @@ struct t_clock_arch_spec {
|
|||
/* Detailed routing architecture */
|
||||
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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,33 +320,54 @@ void create_rr_graph(const t_graph_type graph_type,
|
|||
|
||||
free_rr_graph();
|
||||
|
||||
build_rr_graph(graph_type,
|
||||
block_types,
|
||||
grid,
|
||||
nodes_per_chan,
|
||||
det_routing_arch->switch_block_type,
|
||||
det_routing_arch->Fs,
|
||||
det_routing_arch->switchblocks,
|
||||
num_arch_switches,
|
||||
segment_inf,
|
||||
det_routing_arch->global_route_switch,
|
||||
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,
|
||||
trim_empty_channels,
|
||||
trim_obs_channels,
|
||||
directs, num_directs,
|
||||
&det_routing_arch->wire_to_rr_ipin_switch,
|
||||
Warnings);
|
||||
if (GRAPH_UNIDIR_TILEABLE != graph_type) {
|
||||
build_rr_graph(graph_type,
|
||||
block_types,
|
||||
grid,
|
||||
nodes_per_chan,
|
||||
det_routing_arch->switch_block_type,
|
||||
det_routing_arch->Fs,
|
||||
det_routing_arch->switchblocks,
|
||||
num_arch_switches,
|
||||
segment_inf,
|
||||
det_routing_arch->global_route_switch,
|
||||
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,
|
||||
trim_empty_channels,
|
||||
trim_obs_channels,
|
||||
directs, num_directs,
|
||||
&det_routing_arch->wire_to_rr_ipin_switch,
|
||||
Warnings);
|
||||
|
||||
if (clock_modeling == DEDICATED_NETWORK) {
|
||||
ClockRRGraphBuilder::create_and_append_clock_rr_graph(segment_inf,
|
||||
det_routing_arch->R_minW_nmos,
|
||||
det_routing_arch->R_minW_pmos,
|
||||
det_routing_arch->wire_to_rr_ipin_switch,
|
||||
base_cost_type);
|
||||
if (clock_modeling == DEDICATED_NETWORK) {
|
||||
ClockRRGraphBuilder::create_and_append_clock_rr_graph(segment_inf,
|
||||
det_routing_arch->R_minW_nmos,
|
||||
det_routing_arch->R_minW_pmos,
|
||||
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 */
|
||||
|
@ -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,10 +1052,10 @@ 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,
|
||||
int max_chan_width,
|
||||
int wire_to_rr_ipin_switch,
|
||||
enum e_base_cost_type base_cost_type) {
|
||||
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) {
|
||||
auto& device_ctx = g_vpr_ctx.device();
|
||||
|
||||
add_rr_graph_C_from_switches(device_ctx.rr_switch_inf[wire_to_rr_ipin_switch].Cin);
|
||||
|
@ -1152,14 +1147,14 @@ 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,
|
||||
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) {
|
||||
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) {
|
||||
//Initialize Fc of all blocks to zero
|
||||
auto zeros = vtr::Matrix<int>({size_t(max_pins), segment_inf.size()}, 0);
|
||||
std::vector<vtr::Matrix<int>> Fc(types.size(), zeros);
|
||||
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
***********************************************************************/
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
|
@ -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
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue