refactored SDC SB constrain generation
This commit is contained in:
parent
be574b0d45
commit
4b5ecc516b
|
@ -21,6 +21,8 @@
|
|||
#include "fpga_x2p_naming.h"
|
||||
#include "fpga_x2p_utils.h"
|
||||
|
||||
#include "build_routing_module_utils.h"
|
||||
|
||||
#include "sdc_writer_naming.h"
|
||||
#include "sdc_writer_utils.h"
|
||||
#include "pnr_sdc_writer.h"
|
||||
|
@ -305,6 +307,327 @@ void print_sdc_disable_routing_multiplexer_outputs(const std::string& sdc_dir,
|
|||
run_time_sec);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Break combinational loops in FPGA fabric, which mainly come from
|
||||
* loops of multiplexers.
|
||||
* To handle this, we disable the timing at outputs of Switch blocks
|
||||
* This function is designed for flatten routing hierarchy
|
||||
*******************************************************************/
|
||||
static
|
||||
void print_pnr_sdc_flatten_routing_disable_switch_block_outputs(const std::string& sdc_dir,
|
||||
const ModuleManager& module_manager,
|
||||
const DeviceRRGSB& L_device_rr_gsb) {
|
||||
/* Create the file name for Verilog netlist */
|
||||
std::string sdc_fname(sdc_dir + std::string(SDC_DISABLE_SB_OUTPUTS_FILE_NAME));
|
||||
|
||||
vpr_printf(TIO_MESSAGE_INFO,
|
||||
"Generating SDC for disable Switch Block outputs for P&R flow: %s ...",
|
||||
sdc_fname.c_str());
|
||||
|
||||
/* Start time count */
|
||||
clock_t t_start = clock();
|
||||
|
||||
/* Create the file stream */
|
||||
std::fstream fp;
|
||||
fp.open(sdc_fname, std::fstream::out | std::fstream::trunc);
|
||||
|
||||
check_file_handler(fp);
|
||||
|
||||
/* Generate the descriptions*/
|
||||
print_sdc_file_header(fp, std::string("Disable Switch Block outputs for PnR"));
|
||||
|
||||
/* Get the range of SB array */
|
||||
DeviceCoordinator sb_range = L_device_rr_gsb.get_gsb_range();
|
||||
/* Go for each SB */
|
||||
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 = L_device_rr_gsb.get_gsb(ix, iy);
|
||||
vtr::Point<size_t> gsb_coordinate(rr_gsb.get_sb_x(), rr_gsb.get_sb_y());
|
||||
std::string sb_instance_name = generate_switch_block_module_name(gsb_coordinate);
|
||||
|
||||
ModuleId sb_module = module_manager.find_module(sb_instance_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(sb_module));
|
||||
|
||||
/* Disable the outputs of the module */
|
||||
for (const BasicPort& output_port : module_manager.module_ports_by_type(sb_module, ModuleManager::MODULE_OUTPUT_PORT)) {
|
||||
fp << "set_disable_timing " << sb_instance_name << "/" << output_port.get_name() << std::endl;
|
||||
fp << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Close file handler */
|
||||
fp.close();
|
||||
|
||||
/* End time count */
|
||||
clock_t t_end = clock();
|
||||
|
||||
float run_time_sec = (float)(t_end - t_start) / CLOCKS_PER_SEC;
|
||||
vpr_printf(TIO_MESSAGE_INFO,
|
||||
"took %g seconds\n",
|
||||
run_time_sec);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Break combinational loops in FPGA fabric, which mainly come from
|
||||
* loops of multiplexers.
|
||||
* To handle this, we disable the timing at outputs of Switch blocks
|
||||
* This function is designed for compact routing hierarchy
|
||||
*******************************************************************/
|
||||
static
|
||||
void print_pnr_sdc_compact_routing_disable_switch_block_outputs(const std::string& sdc_dir,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const DeviceRRGSB& L_device_rr_gsb) {
|
||||
/* Create the file name for Verilog netlist */
|
||||
std::string sdc_fname(sdc_dir + std::string(SDC_DISABLE_SB_OUTPUTS_FILE_NAME));
|
||||
|
||||
vpr_printf(TIO_MESSAGE_INFO,
|
||||
"Generating SDC for disable Switch Block outputs for P&R flow: %s ...",
|
||||
sdc_fname.c_str());
|
||||
|
||||
/* Start time count */
|
||||
clock_t t_start = clock();
|
||||
|
||||
/* Create the file stream */
|
||||
std::fstream fp;
|
||||
fp.open(sdc_fname, std::fstream::out | std::fstream::trunc);
|
||||
|
||||
check_file_handler(fp);
|
||||
|
||||
/* Generate the descriptions*/
|
||||
print_sdc_file_header(fp, std::string("Disable Switch Block outputs for PnR"));
|
||||
|
||||
/* Build unique switch block modules */
|
||||
for (size_t isb = 0; isb < L_device_rr_gsb.get_num_sb_unique_module(); ++isb) {
|
||||
const RRGSB& rr_gsb = L_device_rr_gsb.get_sb_unique_module(isb);
|
||||
vtr::Point<size_t> gsb_coordinate(rr_gsb.get_sb_x(), rr_gsb.get_sb_y());
|
||||
std::string sb_module_name = generate_switch_block_module_name(gsb_coordinate);
|
||||
|
||||
ModuleId sb_module = module_manager.find_module(sb_module_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(sb_module));
|
||||
|
||||
/* Find all the instances in the top-level module */
|
||||
for (const size_t& instance_id : module_manager.child_module_instances(top_module, sb_module)) {
|
||||
std::string sb_instance_name = module_manager.instance_name(top_module, sb_module, instance_id);
|
||||
/* Disable the outputs of the module */
|
||||
for (const BasicPort& output_port : module_manager.module_ports_by_type(sb_module, ModuleManager::MODULE_OUTPUT_PORT)) {
|
||||
fp << "set_disable_timing " << sb_instance_name << "/" << output_port.get_name() << std::endl;
|
||||
fp << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Close file handler */
|
||||
fp.close();
|
||||
|
||||
/* End time count */
|
||||
clock_t t_end = clock();
|
||||
|
||||
float run_time_sec = (float)(t_end - t_start) / CLOCKS_PER_SEC;
|
||||
vpr_printf(TIO_MESSAGE_INFO,
|
||||
"took %g seconds\n",
|
||||
run_time_sec);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Find the timing constraints between the inputs and outputs of a routing
|
||||
* multiplexer in a Switch Block
|
||||
*******************************************************************/
|
||||
static
|
||||
float find_pnr_sdc_switch_tmax(const t_switch_inf& switch_inf) {
|
||||
return switch_inf.R * switch_inf.Cout + switch_inf.Tdel;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Set timing constraints between the inputs and outputs of a routing
|
||||
* multiplexer in a Switch Block
|
||||
*******************************************************************/
|
||||
static
|
||||
void print_pnr_sdc_constrain_sb_mux_timing(std::fstream& fp,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& sb_module,
|
||||
const RRGSB& rr_gsb,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_switch_inf>& switches,
|
||||
const e_side& output_node_side,
|
||||
t_rr_node* output_rr_node) {
|
||||
/* Validate file stream */
|
||||
check_file_handler(fp);
|
||||
|
||||
VTR_ASSERT( ( CHANX == output_rr_node->type )
|
||||
|| ( CHANY == output_rr_node->type ));
|
||||
|
||||
/* Find the module port corresponding to the output rr_node */
|
||||
ModulePortId module_output_port = find_switch_block_module_chan_port(module_manager,
|
||||
sb_module,
|
||||
rr_gsb,
|
||||
output_node_side,
|
||||
output_rr_node,
|
||||
OUT_PORT);
|
||||
|
||||
/* Find the module port corresponding to the fan-in rr_nodes of the output rr_node */
|
||||
std::vector<t_rr_node*> input_rr_nodes;
|
||||
for (int iedge = 0; iedge < output_rr_node->num_drive_rr_nodes; iedge++) {
|
||||
input_rr_nodes.push_back(output_rr_node->drive_rr_nodes[iedge]);
|
||||
}
|
||||
|
||||
std::vector<ModulePortId> module_input_ports = find_switch_block_module_input_ports(module_manager,
|
||||
sb_module,
|
||||
rr_gsb,
|
||||
grids,
|
||||
input_rr_nodes);
|
||||
|
||||
/* Find timing constraints for each path (edge) */
|
||||
std::map<ModulePortId, float> switch_delays;
|
||||
for (int iedge = 0; iedge < output_rr_node->num_drive_rr_nodes; iedge++) {
|
||||
/* Get the switch delay */
|
||||
int switch_id = output_rr_node->drive_switches[iedge];
|
||||
switch_delays[module_input_ports[iedge]] = find_pnr_sdc_switch_tmax(switches[switch_id]);
|
||||
}
|
||||
|
||||
/* Find the starting points */
|
||||
for (const ModulePortId& module_input_port : module_input_ports) {
|
||||
/* Constrain a path */
|
||||
print_pnr_sdc_constrain_module_port2port_timing(fp,
|
||||
module_manager, sb_module,
|
||||
module_input_port, module_output_port,
|
||||
switch_delays[module_input_port]);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Set timing constraints between the inputs and outputs of SBs,
|
||||
* which are connected by routing multiplexers with the given delays
|
||||
* specified in architectural XML file
|
||||
*
|
||||
* To enable block by block timing constraining, we generate the SDC
|
||||
* file for each unique SB module
|
||||
*******************************************************************/
|
||||
static
|
||||
void print_pnr_sdc_constrain_sb_timing(const std::string& sdc_dir,
|
||||
const ModuleManager& module_manager,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_switch_inf>& switches,
|
||||
const RRGSB& rr_gsb) {
|
||||
|
||||
/* Create the file name for Verilog netlist */
|
||||
vtr::Point<size_t> gsb_coordinate(rr_gsb.get_sb_x(), rr_gsb.get_sb_y());
|
||||
std::string sdc_fname(sdc_dir + generate_switch_block_module_name(gsb_coordinate) + std::string(SDC_FILE_NAME_POSTFIX));
|
||||
|
||||
/* Create the file stream */
|
||||
std::fstream fp;
|
||||
fp.open(sdc_fname, std::fstream::out | std::fstream::trunc);
|
||||
|
||||
/* Validate file stream */
|
||||
check_file_handler(fp);
|
||||
|
||||
std::string sb_module_name = generate_switch_block_module_name(gsb_coordinate);
|
||||
ModuleId sb_module = module_manager.find_module(sb_module_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(sb_module));
|
||||
|
||||
/* Generate the descriptions*/
|
||||
print_sdc_file_header(fp, std::string("Constrain timing of Switch Block " + sb_module_name + " outputs for PnR"));
|
||||
|
||||
for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) {
|
||||
Side side_manager(side);
|
||||
for (size_t itrack = 0; itrack < rr_gsb.get_chan_width(side_manager.get_side()); ++itrack) {
|
||||
t_rr_node* chan_rr_node = rr_gsb.get_chan_node(side_manager.get_side(), itrack);
|
||||
/* 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)) {
|
||||
continue;
|
||||
}
|
||||
/* Constrain thru wires */
|
||||
if (false != rr_gsb.is_sb_node_passing_wire(side_manager.get_side(), itrack)) {
|
||||
continue;
|
||||
}
|
||||
/* This is a MUX, constrain all the paths from an input to an output */
|
||||
print_pnr_sdc_constrain_sb_mux_timing(fp,
|
||||
module_manager, sb_module,
|
||||
rr_gsb,
|
||||
grids, switches,
|
||||
side_manager.get_side(),
|
||||
chan_rr_node);
|
||||
}
|
||||
}
|
||||
|
||||
/* Close file handler */
|
||||
fp.close();
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Print SDC timing constraints for Switch blocks
|
||||
* This function is designed for flatten routing hierarchy
|
||||
*******************************************************************/
|
||||
static
|
||||
void print_pnr_sdc_flatten_routing_constrain_sb_timing(const std::string& sdc_dir,
|
||||
const ModuleManager& module_manager,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_switch_inf>& switches,
|
||||
const DeviceRRGSB& L_device_rr_gsb) {
|
||||
vpr_printf(TIO_MESSAGE_INFO,
|
||||
"Generating SDC for constrain Switch Block timing for P&R flow...");
|
||||
|
||||
/* Start time count */
|
||||
clock_t t_start = clock();
|
||||
|
||||
/* Get the range of SB array */
|
||||
DeviceCoordinator sb_range = L_device_rr_gsb.get_gsb_range();
|
||||
/* Go for each SB */
|
||||
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 = L_device_rr_gsb.get_gsb(ix, iy);
|
||||
print_pnr_sdc_constrain_sb_timing(sdc_dir,
|
||||
module_manager,
|
||||
grids, switches,
|
||||
rr_gsb);
|
||||
}
|
||||
}
|
||||
|
||||
/* End time count */
|
||||
clock_t t_end = clock();
|
||||
|
||||
float run_time_sec = (float)(t_end - t_start) / CLOCKS_PER_SEC;
|
||||
vpr_printf(TIO_MESSAGE_INFO,
|
||||
"took %g seconds\n",
|
||||
run_time_sec);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Break combinational loops in FPGA fabric, which mainly come from
|
||||
* loops of multiplexers.
|
||||
* To handle this, we disable the timing at outputs of Switch blocks
|
||||
* This function is designed for compact routing hierarchy
|
||||
*******************************************************************/
|
||||
static
|
||||
void print_pnr_sdc_compact_routing_constrain_sb_timing(const std::string& sdc_dir,
|
||||
const ModuleManager& module_manager,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_switch_inf>& switches,
|
||||
const DeviceRRGSB& L_device_rr_gsb) {
|
||||
vpr_printf(TIO_MESSAGE_INFO,
|
||||
"Generating SDC for constrain Switch Block timing for P&R flow...");
|
||||
|
||||
/* Start time count */
|
||||
clock_t t_start = clock();
|
||||
|
||||
for (size_t isb = 0; isb < L_device_rr_gsb.get_num_sb_unique_module(); ++isb) {
|
||||
const RRGSB& rr_gsb = L_device_rr_gsb.get_sb_unique_module(isb);
|
||||
print_pnr_sdc_constrain_sb_timing(sdc_dir,
|
||||
module_manager,
|
||||
grids, switches,
|
||||
rr_gsb);
|
||||
}
|
||||
|
||||
/* End time count */
|
||||
clock_t t_end = clock();
|
||||
|
||||
float run_time_sec = (float)(t_end - t_start) / CLOCKS_PER_SEC;
|
||||
vpr_printf(TIO_MESSAGE_INFO,
|
||||
"took %g seconds\n",
|
||||
run_time_sec);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Top-level function to print a number of SDC files in different purpose
|
||||
* This function will generate files upon the options provided by users
|
||||
|
@ -315,12 +638,16 @@ void print_sdc_disable_routing_multiplexer_outputs(const std::string& sdc_dir,
|
|||
*******************************************************************/
|
||||
void print_pnr_sdc(const SdcOption& sdc_options,
|
||||
const float& critical_path_delay,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_switch_inf>& switches,
|
||||
const DeviceRRGSB& L_device_rr_gsb,
|
||||
const ModuleManager& module_manager,
|
||||
const MuxLibrary& mux_lib,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const ModuleManager& module_manager,
|
||||
const std::vector<CircuitPortId>& global_ports) {
|
||||
const std::vector<CircuitPortId>& global_ports,
|
||||
const bool& compact_routing_hierarchy) {
|
||||
|
||||
/* Part 1. Constrain global ports */
|
||||
/* Constrain global ports */
|
||||
if (true == sdc_options.constrain_global_port()) {
|
||||
print_pnr_sdc_global_ports(sdc_options.sdc_dir(), critical_path_delay, circuit_lib, global_ports);
|
||||
}
|
||||
|
@ -329,24 +656,66 @@ void print_pnr_sdc(const SdcOption& sdc_options,
|
|||
ModuleId top_module = module_manager.find_module(top_module_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(top_module));
|
||||
|
||||
/* Part 2. Output Design Constraints to disable outputs of memory cells */
|
||||
/* Output Design Constraints to disable outputs of memory cells */
|
||||
if (true == sdc_options.constrain_configurable_memory_outputs()) {
|
||||
print_pnr_sdc_constrain_configurable_memory_outputs(sdc_options.sdc_dir(), module_manager, top_module);
|
||||
}
|
||||
|
||||
/* 2. Break loops from Multiplexer Output */
|
||||
/* Break loops from Multiplexer Output */
|
||||
if (true == sdc_options.constrain_routing_multiplexer_outputs()) {
|
||||
print_sdc_disable_routing_multiplexer_outputs(sdc_options.sdc_dir(),
|
||||
mux_lib, circuit_lib,
|
||||
module_manager);
|
||||
}
|
||||
|
||||
/* TODO: 3. Break loops from any SB output */
|
||||
/* Break loops from any SB output */
|
||||
if (true == sdc_options.constrain_switch_block_outputs()) {
|
||||
if (true == compact_routing_hierarchy) {
|
||||
print_pnr_sdc_compact_routing_disable_switch_block_outputs(sdc_options.sdc_dir(),
|
||||
module_manager, top_module,
|
||||
L_device_rr_gsb);
|
||||
} else {
|
||||
VTR_ASSERT_SAFE (false == compact_routing_hierarchy);
|
||||
print_pnr_sdc_flatten_routing_disable_switch_block_outputs(sdc_options.sdc_dir(),
|
||||
module_manager,
|
||||
L_device_rr_gsb);
|
||||
}
|
||||
}
|
||||
|
||||
/* Output routing constraints for Switch Blocks */
|
||||
if (true == sdc_options.constrain_sb()) {
|
||||
if (true == compact_routing_hierarchy) {
|
||||
print_pnr_sdc_compact_routing_constrain_sb_timing(sdc_options.sdc_dir(),
|
||||
module_manager,
|
||||
grids, switches,
|
||||
L_device_rr_gsb);
|
||||
} else {
|
||||
VTR_ASSERT_SAFE (false == compact_routing_hierarchy);
|
||||
print_pnr_sdc_flatten_routing_constrain_sb_timing(sdc_options.sdc_dir(),
|
||||
module_manager,
|
||||
grids, switches,
|
||||
L_device_rr_gsb);
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: Output routing constraints for Connection Blocks */
|
||||
/*
|
||||
if (TRUE == sdc_opts.compact_routing_hierarchy) {
|
||||
verilog_generate_sdc_break_loop_sb(fp, LL_device_rr_gsb);
|
||||
} else {
|
||||
verilog_generate_sdc_break_loop_sb(fp, LL_nx, LL_ny);
|
||||
if (true == sdc_options.constrain_cb()) {
|
||||
if (true == compact_routing_hierarchy) {
|
||||
verilog_generate_sdc_constrain_cbs(sdc_opts, LL_nx, LL_ny, LL_device_rr_gsb);
|
||||
} else {
|
||||
VTR_ASSERT_SAFE (false == compact_routing_hierarchy);
|
||||
verilog_generate_sdc_constrain_cbs(sdc_opts,
|
||||
LL_nx, LL_ny);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/* TODO: Output routing constraints for Programmable blocks */
|
||||
/*
|
||||
if (true == sdc_options.constrain_grid()) {
|
||||
verilog_generate_sdc_constrain_pb_types(cur_sram_orgz_info,
|
||||
sdc_dir);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -12,9 +12,13 @@
|
|||
|
||||
void print_pnr_sdc(const SdcOption& sdc_options,
|
||||
const float& critical_path_delay,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_switch_inf>& switches,
|
||||
const DeviceRRGSB& L_device_rr_gsb,
|
||||
const ModuleManager& module_manager,
|
||||
const MuxLibrary& mux_lib,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const ModuleManager& module_manager,
|
||||
const std::vector<CircuitPortId>& global_ports);
|
||||
const std::vector<CircuitPortId>& global_ports,
|
||||
const bool& compact_routing_hierarchy);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -11,10 +11,14 @@
|
|||
*******************************************************************/
|
||||
void fpga_sdc_generator(const SdcOption& sdc_options,
|
||||
const float& critical_path_delay,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_switch_inf>& switches,
|
||||
const DeviceRRGSB& L_device_rr_gsb,
|
||||
const ModuleManager& module_manager,
|
||||
const MuxLibrary& mux_lib,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const ModuleManager& module_manager,
|
||||
const std::vector<CircuitPortId>& global_ports) {
|
||||
const std::vector<CircuitPortId>& global_ports,
|
||||
const bool& compact_routing_hierarchy) {
|
||||
vpr_printf(TIO_MESSAGE_INFO,
|
||||
"SDC generator starts...");
|
||||
|
||||
|
@ -22,7 +26,11 @@ void fpga_sdc_generator(const SdcOption& sdc_options,
|
|||
clock_t t_start = clock();
|
||||
|
||||
if (true == sdc_options.generate_sdc_pnr()) {
|
||||
print_pnr_sdc(sdc_options, critical_path_delay, mux_lib, circuit_lib, module_manager, global_ports);
|
||||
print_pnr_sdc(sdc_options, critical_path_delay,
|
||||
grids, switches, L_device_rr_gsb,
|
||||
module_manager, mux_lib,
|
||||
circuit_lib, global_ports,
|
||||
compact_routing_hierarchy);
|
||||
}
|
||||
|
||||
/* End time count */
|
||||
|
|
|
@ -9,9 +9,13 @@
|
|||
|
||||
void fpga_sdc_generator(const SdcOption& sdc_options,
|
||||
const float& critical_path_delay,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_switch_inf>& switches,
|
||||
const DeviceRRGSB& L_device_rr_gsb,
|
||||
const ModuleManager& module_manager,
|
||||
const MuxLibrary& mux_lib,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const ModuleManager& module_manager,
|
||||
const std::vector<CircuitPortId>& global_ports);
|
||||
const std::vector<CircuitPortId>& global_ports,
|
||||
const bool& compact_routing_hierarchy);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
#ifndef SDC_WRITER_NAMING_H
|
||||
#define SDC_WRITER_NAMING_H
|
||||
|
||||
constexpr char* SDC_FILE_NAME_POSTFIX = ".sdc";
|
||||
|
||||
constexpr char* SDC_GLOBAL_PORTS_FILE_NAME = "global_ports.sdc";
|
||||
constexpr char* SDC_BENCHMARK_ANALYSIS_FILE_NAME= "fpga_top_analysis.sdc";
|
||||
constexpr char* SDC_DISABLE_CONFIG_MEM_OUTPUTS_FILE_NAME = "disable_configurable_memory_outputs.sdc";
|
||||
constexpr char* SDC_DISABLE_MUX_OUTPUTS_FILE_NAME = "disable_routing_multiplexer_outputs.sdc";
|
||||
constexpr char* SDC_DISABLE_SB_OUTPUTS_FILE_NAME = "disable_sb_outputs.sdc";
|
||||
constexpr char* SDC_CB_FILE_NAME = "cb.sdc";
|
||||
constexpr char* SDC_SB_FILE_NAME = "sb.sdc";
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
*******************************************************************/
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
#include <iomanip>
|
||||
|
||||
#include "fpga_x2p_utils.h"
|
||||
|
||||
|
@ -50,3 +51,31 @@ std::string generate_sdc_port(const BasicPort& port) {
|
|||
|
||||
return sdc_line;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Constrain a path between two ports of a module with a given timing value
|
||||
*******************************************************************/
|
||||
void print_pnr_sdc_constrain_module_port2port_timing(std::fstream& fp,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& module_id,
|
||||
const ModulePortId& module_input_port_id,
|
||||
const ModulePortId& module_output_port_id,
|
||||
const float& tmax) {
|
||||
/* Validate file stream */
|
||||
check_file_handler(fp);
|
||||
|
||||
fp << "set_max_delay";
|
||||
|
||||
fp << " -from ";
|
||||
fp << module_manager.module_name(module_id) << "/";
|
||||
fp << generate_sdc_port(module_manager.module_port(module_id, module_input_port_id));
|
||||
|
||||
fp << " -to ";
|
||||
|
||||
fp << module_manager.module_name(module_id) << "/";
|
||||
fp << generate_sdc_port(module_manager.module_port(module_id, module_output_port_id));
|
||||
|
||||
fp << " " << std::setprecision(10) << tmax;
|
||||
|
||||
fp << std::endl;
|
||||
}
|
||||
|
|
|
@ -4,10 +4,18 @@
|
|||
#include <fstream>
|
||||
#include <string>
|
||||
#include "device_port.h"
|
||||
#include "module_manager.h"
|
||||
|
||||
void print_sdc_file_header(std::fstream& fp,
|
||||
const std::string& usage);
|
||||
|
||||
std::string generate_sdc_port(const BasicPort& port);
|
||||
|
||||
void print_pnr_sdc_constrain_module_port2port_timing(std::fstream& fp,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& module_id,
|
||||
const ModulePortId& module_input_port_id,
|
||||
const ModulePortId& module_output_port_id,
|
||||
const float& tmax);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -159,8 +159,10 @@ void vpr_fpga_x2p_tool_suites(t_vpr_setup vpr_setup,
|
|||
/* TODO: the critical path delay unit should be explicit! */
|
||||
fpga_sdc_generator(sdc_options,
|
||||
Arch.spice->spice_params.stimulate_params.vpr_crit_path_delay / 1e-9,
|
||||
mux_lib,
|
||||
Arch.spice->circuit_lib, module_manager, global_ports);
|
||||
grids, rr_switches, device_rr_gsb,
|
||||
module_manager, mux_lib,
|
||||
Arch.spice->circuit_lib, global_ports,
|
||||
TRUE == vpr_setup.FPGA_SPICE_Opts.compact_routing_hierarchy);
|
||||
}
|
||||
|
||||
/* Xifan Tang: Bitstream Generator */
|
||||
|
|
|
@ -0,0 +1,219 @@
|
|||
/********************************************************************
|
||||
* This file includes most utilized functions that are used to build modules
|
||||
* for global routing architecture of a FPGA fabric
|
||||
* Covering:
|
||||
* 1. Connection blocks
|
||||
* 2. Switch blocks
|
||||
*******************************************************************/
|
||||
#include "vtr_assert.h"
|
||||
#include "vtr_geometry.h"
|
||||
#include "device_coordinator.h"
|
||||
|
||||
#include "fpga_x2p_naming.h"
|
||||
|
||||
#include "build_routing_module_utils.h"
|
||||
|
||||
/*********************************************************************
|
||||
* Generate a port for a routing track of a swtich block
|
||||
********************************************************************/
|
||||
ModulePortId find_switch_block_module_chan_port(const ModuleManager& module_manager,
|
||||
const ModuleId& sb_module,
|
||||
const RRGSB& rr_gsb,
|
||||
const e_side& chan_side,
|
||||
t_rr_node* cur_rr_node,
|
||||
const PORTS& cur_rr_node_direction) {
|
||||
/* Get the index in sb_info of cur_rr_node */
|
||||
int index = rr_gsb.get_node_index(cur_rr_node, chan_side, cur_rr_node_direction);
|
||||
/* Make sure this node is included in this sb_info */
|
||||
VTR_ASSERT((-1 != index)&&(NUM_SIDES != chan_side));
|
||||
|
||||
DeviceCoordinator chan_rr_node_coordinator = rr_gsb.get_side_block_coordinator(chan_side);
|
||||
|
||||
vtr::Point<size_t> chan_port_coord(chan_rr_node_coordinator.get_x(), chan_rr_node_coordinator.get_y());
|
||||
std::string chan_port_name = generate_routing_track_port_name(rr_gsb.get_chan_node(chan_side, index)->type,
|
||||
chan_port_coord, index,
|
||||
rr_gsb.get_chan_node_direction(chan_side, index));
|
||||
|
||||
/* Must find a valid port id in the Switch Block module */
|
||||
ModulePortId chan_port_id = module_manager.find_module_port(sb_module, chan_port_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(sb_module, chan_port_id));
|
||||
return chan_port_id;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate an input port for routing multiplexer inside the switch block
|
||||
* In addition to give the Routing Resource node of the input
|
||||
* Users should provide the side of input, which is different case by case:
|
||||
* 1. When the input is a pin of a CLB/Logic Block, the input_side should
|
||||
* be the side of the node on its grid!
|
||||
* For example, the input pin is on the top side of a switch block
|
||||
* but on the right side of a switch block
|
||||
* +--------+
|
||||
* | |
|
||||
* | Grid |---+
|
||||
* | | |
|
||||
* +--------+ v input_pin
|
||||
* +----------------+
|
||||
* | Switch Block |
|
||||
* +----------------+
|
||||
* 2. When the input is a routing track, the input_side should be
|
||||
* the side of the node locating on the switch block
|
||||
********************************************************************/
|
||||
ModulePortId find_switch_block_module_input_port(const ModuleManager& module_manager,
|
||||
const ModuleId& sb_module,
|
||||
const RRGSB& rr_gsb,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const e_side& input_side,
|
||||
t_rr_node* input_rr_node) {
|
||||
/* Deposit an invalid value */
|
||||
ModulePortId input_port_id = ModulePortId::INVALID();
|
||||
/* Generate the input port object */
|
||||
switch (input_rr_node->type) {
|
||||
/* case SOURCE: */
|
||||
case OPIN: {
|
||||
/* Find the coordinator (grid_x and grid_y) for the input port */
|
||||
vtr::Point<size_t> input_port_coord(input_rr_node->xlow, input_rr_node->ylow);
|
||||
std::string input_port_name = generate_grid_side_port_name(grids,
|
||||
input_port_coord,
|
||||
input_side,
|
||||
input_rr_node->ptc_num);
|
||||
/* Must find a valid port id in the Switch Block module */
|
||||
input_port_id = module_manager.find_module_port(sb_module, input_port_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(sb_module, input_port_id));
|
||||
break;
|
||||
}
|
||||
case CHANX:
|
||||
case CHANY: {
|
||||
input_port_id = find_switch_block_module_chan_port(module_manager, sb_module,
|
||||
rr_gsb, input_side, input_rr_node, IN_PORT);
|
||||
break;
|
||||
}
|
||||
default: /* SOURCE, IPIN, SINK are invalid*/
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s, [LINE%d])Invalid rr_node type! Should be [OPIN|CHANX|CHANY].\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return input_port_id;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate a list of input ports for routing multiplexer inside the switch block
|
||||
********************************************************************/
|
||||
std::vector<ModulePortId> find_switch_block_module_input_ports(const ModuleManager& module_manager,
|
||||
const ModuleId& sb_module,
|
||||
const RRGSB& rr_gsb,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_rr_node*>& input_rr_nodes) {
|
||||
std::vector<ModulePortId> input_ports;
|
||||
|
||||
for (auto input_rr_node : input_rr_nodes) {
|
||||
enum e_side input_pin_side = NUM_SIDES;
|
||||
switch (input_rr_node->type) {
|
||||
case OPIN:
|
||||
input_pin_side = rr_gsb.get_opin_node_grid_side(input_rr_node);
|
||||
break;
|
||||
case CHANX:
|
||||
case CHANY: {
|
||||
/* The input could be at any side of the switch block, find it */
|
||||
int index = -1;
|
||||
rr_gsb.get_node_side_and_index(input_rr_node, IN_PORT, &input_pin_side, &index);
|
||||
VTR_ASSERT(NUM_SIDES != input_pin_side);
|
||||
break;
|
||||
}
|
||||
default: /* SOURCE, IPIN, SINK are invalid*/
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s, [LINE%d])Invalid rr_node type! Should be [OPIN|CHANX|CHANY].\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
input_ports.push_back(find_switch_block_module_input_port(module_manager, sb_module, rr_gsb, grids, input_pin_side, input_rr_node));
|
||||
}
|
||||
|
||||
return input_ports;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate an input port for routing multiplexer inside the connection block
|
||||
* which is the middle output of a routing track
|
||||
********************************************************************/
|
||||
ModulePortId find_connection_block_module_chan_port(const ModuleManager& module_manager,
|
||||
const ModuleId& cb_module,
|
||||
const RRGSB& rr_gsb,
|
||||
const t_rr_type& cb_type,
|
||||
t_rr_node* chan_rr_node) {
|
||||
ModulePortId input_port_id;
|
||||
/* Generate the input port object */
|
||||
switch (chan_rr_node->type) {
|
||||
case CHANX:
|
||||
case CHANY: {
|
||||
/* Create port description for the routing track middle output */
|
||||
vtr::Point<size_t> port_coord(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type));
|
||||
int chan_node_track_id = rr_gsb.get_cb_chan_node_index(cb_type, chan_rr_node);
|
||||
/* Create a port description for the middle output */
|
||||
std::string input_port_name = generate_routing_track_port_name(cb_type,
|
||||
port_coord, chan_node_track_id,
|
||||
IN_PORT);
|
||||
/* Must find a valid port id in the Switch Block module */
|
||||
input_port_id = module_manager.find_module_port(cb_module, input_port_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(cb_module, input_port_id));
|
||||
break;
|
||||
}
|
||||
default: /* OPIN, SOURCE, IPIN, SINK are invalid*/
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s, [LINE%d])Invalid rr_node type! Should be [OPIN|CHANX|CHANY].\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return input_port_id;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate a port for a routing track of a swtich block
|
||||
********************************************************************/
|
||||
ModulePortId find_connection_block_module_ipin_port(const ModuleManager& module_manager,
|
||||
const ModuleId& cb_module,
|
||||
const RRGSB& rr_gsb,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
t_rr_node* src_rr_node) {
|
||||
|
||||
/* Ensure the src_rr_node is an input pin of a CLB */
|
||||
VTR_ASSERT(IPIN == src_rr_node->type);
|
||||
/* Create port description for input pin of a CLB */
|
||||
vtr::Point<size_t> port_coord(src_rr_node->xlow, src_rr_node->ylow);
|
||||
/* Search all the sides of a SB, see this drive_rr_node is an INPUT of this SB */
|
||||
enum e_side cb_ipin_side = NUM_SIDES;
|
||||
int cb_ipin_index = -1;
|
||||
rr_gsb.get_node_side_and_index(src_rr_node, OUT_PORT, &cb_ipin_side, &cb_ipin_index);
|
||||
/* We need to be sure that drive_rr_node is part of the CB */
|
||||
VTR_ASSERT((-1 != cb_ipin_index)&&(NUM_SIDES != cb_ipin_side));
|
||||
std::string port_name = generate_grid_side_port_name(grids,
|
||||
port_coord,
|
||||
rr_gsb.get_ipin_node_grid_side(cb_ipin_side, cb_ipin_index),
|
||||
rr_gsb.get_ipin_node(cb_ipin_side, cb_ipin_index)->ptc_num);
|
||||
|
||||
/* Must find a valid port id in the Switch Block module */
|
||||
ModulePortId ipin_port_id = module_manager.find_module_port(cb_module, port_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(cb_module, ipin_port_id));
|
||||
return ipin_port_id;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate a list of routing track middle output ports
|
||||
* for routing multiplexer inside the connection block
|
||||
********************************************************************/
|
||||
std::vector<ModulePortId> find_connection_block_module_input_ports(const ModuleManager& module_manager,
|
||||
const ModuleId& cb_module,
|
||||
const RRGSB& rr_gsb,
|
||||
const t_rr_type& cb_type,
|
||||
const std::vector<t_rr_node*>& input_rr_nodes) {
|
||||
std::vector<ModulePortId> input_ports;
|
||||
|
||||
for (auto input_rr_node : input_rr_nodes) {
|
||||
input_ports.push_back(find_connection_block_module_chan_port(module_manager, cb_module, rr_gsb, cb_type, input_rr_node));
|
||||
}
|
||||
|
||||
return input_ports;
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
#ifndef BUILD_ROUTING_MODULE_UTILS_H
|
||||
#define BUILD_ROUTING_MODULE_UTILS_H
|
||||
|
||||
#include <vector>
|
||||
#include "rr_blocks.h"
|
||||
#include "module_manager.h"
|
||||
#include "sides.h"
|
||||
#include "vpr_types.h"
|
||||
|
||||
ModulePortId find_switch_block_module_chan_port(const ModuleManager& module_manager,
|
||||
const ModuleId& sb_module,
|
||||
const RRGSB& rr_gsb,
|
||||
const e_side& chan_side,
|
||||
t_rr_node* cur_rr_node,
|
||||
const PORTS& cur_rr_node_direction);
|
||||
|
||||
ModulePortId find_switch_block_module_input_port(const ModuleManager& module_manager,
|
||||
const ModuleId& sb_module,
|
||||
const RRGSB& rr_gsb,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const e_side& input_side,
|
||||
t_rr_node* input_rr_node);
|
||||
|
||||
std::vector<ModulePortId> find_switch_block_module_input_ports(const ModuleManager& module_manager,
|
||||
const ModuleId& sb_module,
|
||||
const RRGSB& rr_gsb,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_rr_node*>& input_rr_nodes);
|
||||
|
||||
ModulePortId find_connection_block_module_chan_port(const ModuleManager& module_manager,
|
||||
const ModuleId& cb_module,
|
||||
const RRGSB& rr_gsb,
|
||||
const t_rr_type& cb_type,
|
||||
t_rr_node* chan_rr_node);
|
||||
|
||||
ModulePortId find_connection_block_module_ipin_port(const ModuleManager& module_manager,
|
||||
const ModuleId& cb_module,
|
||||
const RRGSB& rr_gsb,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
t_rr_node* src_rr_node);
|
||||
|
||||
|
||||
std::vector<ModulePortId> find_connection_block_module_input_ports(const ModuleManager& module_manager,
|
||||
const ModuleId& cb_module,
|
||||
const RRGSB& rr_gsb,
|
||||
const t_rr_type& cb_type,
|
||||
const std::vector<t_rr_node*>& input_rr_nodes);
|
||||
|
||||
#endif
|
|
@ -21,135 +21,11 @@
|
|||
#include "fpga_x2p_utils.h"
|
||||
#include "module_manager_utils.h"
|
||||
#include "build_module_graph_utils.h"
|
||||
#include "build_routing_module_utils.h"
|
||||
|
||||
#include "build_routing_modules.h"
|
||||
#include "verilog_global.h"
|
||||
|
||||
/*********************************************************************
|
||||
* Generate a port for a routing track of a swtich block
|
||||
********************************************************************/
|
||||
static
|
||||
ModulePortId find_switch_block_module_chan_port(const ModuleManager& module_manager,
|
||||
const ModuleId& sb_module,
|
||||
const RRGSB& rr_gsb,
|
||||
const e_side& chan_side,
|
||||
t_rr_node* cur_rr_node,
|
||||
const PORTS& cur_rr_node_direction) {
|
||||
/* Get the index in sb_info of cur_rr_node */
|
||||
int index = rr_gsb.get_node_index(cur_rr_node, chan_side, cur_rr_node_direction);
|
||||
/* Make sure this node is included in this sb_info */
|
||||
VTR_ASSERT((-1 != index)&&(NUM_SIDES != chan_side));
|
||||
|
||||
DeviceCoordinator chan_rr_node_coordinator = rr_gsb.get_side_block_coordinator(chan_side);
|
||||
|
||||
vtr::Point<size_t> chan_port_coord(chan_rr_node_coordinator.get_x(), chan_rr_node_coordinator.get_y());
|
||||
std::string chan_port_name = generate_routing_track_port_name(rr_gsb.get_chan_node(chan_side, index)->type,
|
||||
chan_port_coord, index,
|
||||
rr_gsb.get_chan_node_direction(chan_side, index));
|
||||
|
||||
/* Must find a valid port id in the Switch Block module */
|
||||
ModulePortId chan_port_id = module_manager.find_module_port(sb_module, chan_port_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(sb_module, chan_port_id));
|
||||
return chan_port_id;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate an input port for routing multiplexer inside the switch block
|
||||
* In addition to give the Routing Resource node of the input
|
||||
* Users should provide the side of input, which is different case by case:
|
||||
* 1. When the input is a pin of a CLB/Logic Block, the input_side should
|
||||
* be the side of the node on its grid!
|
||||
* For example, the input pin is on the top side of a switch block
|
||||
* but on the right side of a switch block
|
||||
* +--------+
|
||||
* | |
|
||||
* | Grid |---+
|
||||
* | | |
|
||||
* +--------+ v input_pin
|
||||
* +----------------+
|
||||
* | Switch Block |
|
||||
* +----------------+
|
||||
* 2. When the input is a routing track, the input_side should be
|
||||
* the side of the node locating on the switch block
|
||||
********************************************************************/
|
||||
static
|
||||
ModulePortId find_switch_block_module_input_port(const ModuleManager& module_manager,
|
||||
const ModuleId& sb_module,
|
||||
const RRGSB& rr_gsb,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const e_side& input_side,
|
||||
t_rr_node* input_rr_node) {
|
||||
/* Deposit an invalid value */
|
||||
ModulePortId input_port_id = ModulePortId::INVALID();
|
||||
/* Generate the input port object */
|
||||
switch (input_rr_node->type) {
|
||||
/* case SOURCE: */
|
||||
case OPIN: {
|
||||
/* Find the coordinator (grid_x and grid_y) for the input port */
|
||||
vtr::Point<size_t> input_port_coord(input_rr_node->xlow, input_rr_node->ylow);
|
||||
std::string input_port_name = generate_grid_side_port_name(grids,
|
||||
input_port_coord,
|
||||
input_side,
|
||||
input_rr_node->ptc_num);
|
||||
/* Must find a valid port id in the Switch Block module */
|
||||
input_port_id = module_manager.find_module_port(sb_module, input_port_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(sb_module, input_port_id));
|
||||
break;
|
||||
}
|
||||
case CHANX:
|
||||
case CHANY: {
|
||||
input_port_id = find_switch_block_module_chan_port(module_manager, sb_module,
|
||||
rr_gsb, input_side, input_rr_node, IN_PORT);
|
||||
break;
|
||||
}
|
||||
default: /* SOURCE, IPIN, SINK are invalid*/
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s, [LINE%d])Invalid rr_node type! Should be [OPIN|CHANX|CHANY].\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return input_port_id;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate a list of input ports for routing multiplexer inside the switch block
|
||||
********************************************************************/
|
||||
static
|
||||
std::vector<ModulePortId> find_switch_block_module_input_ports(const ModuleManager& module_manager,
|
||||
const ModuleId& sb_module,
|
||||
const RRGSB& rr_gsb,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
const std::vector<t_rr_node*>& input_rr_nodes) {
|
||||
std::vector<ModulePortId> input_ports;
|
||||
|
||||
for (auto input_rr_node : input_rr_nodes) {
|
||||
enum e_side input_pin_side = NUM_SIDES;
|
||||
switch (input_rr_node->type) {
|
||||
case OPIN:
|
||||
input_pin_side = rr_gsb.get_opin_node_grid_side(input_rr_node);
|
||||
break;
|
||||
case CHANX:
|
||||
case CHANY: {
|
||||
/* The input could be at any side of the switch block, find it */
|
||||
int index = -1;
|
||||
rr_gsb.get_node_side_and_index(input_rr_node, IN_PORT, &input_pin_side, &index);
|
||||
VTR_ASSERT(NUM_SIDES != input_pin_side);
|
||||
break;
|
||||
}
|
||||
default: /* SOURCE, IPIN, SINK are invalid*/
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s, [LINE%d])Invalid rr_node type! Should be [OPIN|CHANX|CHANY].\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
input_ports.push_back(find_switch_block_module_input_port(module_manager, sb_module, rr_gsb, grids, input_pin_side, input_rr_node));
|
||||
}
|
||||
|
||||
return input_ports;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* Generate a short interconneciton in switch box
|
||||
* There are two cases should be noticed.
|
||||
|
@ -550,93 +426,6 @@ void build_switch_block_module(ModuleManager& module_manager,
|
|||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate an input port for routing multiplexer inside the connection block
|
||||
* which is the middle output of a routing track
|
||||
********************************************************************/
|
||||
static
|
||||
ModulePortId find_connection_block_module_chan_port(const ModuleManager& module_manager,
|
||||
const ModuleId& cb_module,
|
||||
const RRGSB& rr_gsb,
|
||||
const t_rr_type& cb_type,
|
||||
t_rr_node* chan_rr_node) {
|
||||
ModulePortId input_port_id;
|
||||
/* Generate the input port object */
|
||||
switch (chan_rr_node->type) {
|
||||
case CHANX:
|
||||
case CHANY: {
|
||||
/* Create port description for the routing track middle output */
|
||||
vtr::Point<size_t> port_coord(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type));
|
||||
int chan_node_track_id = rr_gsb.get_cb_chan_node_index(cb_type, chan_rr_node);
|
||||
/* Create a port description for the middle output */
|
||||
std::string input_port_name = generate_routing_track_port_name(cb_type,
|
||||
port_coord, chan_node_track_id,
|
||||
IN_PORT);
|
||||
/* Must find a valid port id in the Switch Block module */
|
||||
input_port_id = module_manager.find_module_port(cb_module, input_port_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(cb_module, input_port_id));
|
||||
break;
|
||||
}
|
||||
default: /* OPIN, SOURCE, IPIN, SINK are invalid*/
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s, [LINE%d])Invalid rr_node type! Should be [OPIN|CHANX|CHANY].\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return input_port_id;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate a port for a routing track of a swtich block
|
||||
********************************************************************/
|
||||
static
|
||||
ModulePortId find_connection_block_module_ipin_port(const ModuleManager& module_manager,
|
||||
const ModuleId& cb_module,
|
||||
const RRGSB& rr_gsb,
|
||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||
t_rr_node* src_rr_node) {
|
||||
|
||||
/* Ensure the src_rr_node is an input pin of a CLB */
|
||||
VTR_ASSERT(IPIN == src_rr_node->type);
|
||||
/* Create port description for input pin of a CLB */
|
||||
vtr::Point<size_t> port_coord(src_rr_node->xlow, src_rr_node->ylow);
|
||||
/* Search all the sides of a SB, see this drive_rr_node is an INPUT of this SB */
|
||||
enum e_side cb_ipin_side = NUM_SIDES;
|
||||
int cb_ipin_index = -1;
|
||||
rr_gsb.get_node_side_and_index(src_rr_node, OUT_PORT, &cb_ipin_side, &cb_ipin_index);
|
||||
/* We need to be sure that drive_rr_node is part of the CB */
|
||||
VTR_ASSERT((-1 != cb_ipin_index)&&(NUM_SIDES != cb_ipin_side));
|
||||
std::string port_name = generate_grid_side_port_name(grids,
|
||||
port_coord,
|
||||
rr_gsb.get_ipin_node_grid_side(cb_ipin_side, cb_ipin_index),
|
||||
rr_gsb.get_ipin_node(cb_ipin_side, cb_ipin_index)->ptc_num);
|
||||
|
||||
/* Must find a valid port id in the Switch Block module */
|
||||
ModulePortId ipin_port_id = module_manager.find_module_port(cb_module, port_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(cb_module, ipin_port_id));
|
||||
return ipin_port_id;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate a list of routing track middle output ports
|
||||
* for routing multiplexer inside the connection block
|
||||
********************************************************************/
|
||||
static
|
||||
std::vector<ModulePortId> find_connection_block_module_input_ports(const ModuleManager& module_manager,
|
||||
const ModuleId& cb_module,
|
||||
const RRGSB& rr_gsb,
|
||||
const t_rr_type& cb_type,
|
||||
const std::vector<t_rr_node*>& input_rr_nodes) {
|
||||
std::vector<ModulePortId> input_ports;
|
||||
|
||||
for (auto input_rr_node : input_rr_nodes) {
|
||||
input_ports.push_back(find_connection_block_module_chan_port(module_manager, cb_module, rr_gsb, cb_type, input_rr_node));
|
||||
}
|
||||
|
||||
return input_ports;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Print a short interconneciton in connection
|
||||
********************************************************************/
|
||||
|
|
Loading…
Reference in New Issue