Merge branch 'refactoring' into dev
This commit is contained in:
commit
45914e8afa
|
@ -53,7 +53,7 @@ bool is_vpr_rr_graph_supported(const RRGraph& rr_graph) {
|
||||||
* - physical pb_graph nodes and pb_graph pins
|
* - physical pb_graph nodes and pb_graph pins
|
||||||
* - circuit models for global routing architecture
|
* - circuit models for global routing architecture
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
void link_arch(OpenfpgaContext& openfpga_context,
|
void link_arch(OpenfpgaContext& openfpga_ctx,
|
||||||
const Command& cmd, const CommandContext& cmd_context) {
|
const Command& cmd, const CommandContext& cmd_context) {
|
||||||
|
|
||||||
vtr::ScopedStartFinishTimer timer("Link OpenFPGA architecture to VPR architecture");
|
vtr::ScopedStartFinishTimer timer("Link OpenFPGA architecture to VPR architecture");
|
||||||
|
@ -65,8 +65,8 @@ void link_arch(OpenfpgaContext& openfpga_context,
|
||||||
* - mode selection bits for pb_type and pb interconnect
|
* - mode selection bits for pb_type and pb interconnect
|
||||||
* - circuit models for pb_type and pb interconnect
|
* - circuit models for pb_type and pb interconnect
|
||||||
*/
|
*/
|
||||||
annotate_pb_types(g_vpr_ctx.device(), openfpga_context.arch(),
|
annotate_pb_types(g_vpr_ctx.device(), openfpga_ctx.arch(),
|
||||||
openfpga_context.mutable_vpr_device_annotation(),
|
openfpga_ctx.mutable_vpr_device_annotation(),
|
||||||
cmd_context.option_enable(cmd, opt_verbose));
|
cmd_context.option_enable(cmd, opt_verbose));
|
||||||
|
|
||||||
/* Annotate pb_graph_nodes
|
/* Annotate pb_graph_nodes
|
||||||
|
@ -75,21 +75,21 @@ void link_arch(OpenfpgaContext& openfpga_context,
|
||||||
* - Bind pins from operating pb_graph_node to their physical pb_graph_node pins
|
* - Bind pins from operating pb_graph_node to their physical pb_graph_node pins
|
||||||
*/
|
*/
|
||||||
annotate_pb_graph(g_vpr_ctx.device(),
|
annotate_pb_graph(g_vpr_ctx.device(),
|
||||||
openfpga_context.mutable_vpr_device_annotation(),
|
openfpga_ctx.mutable_vpr_device_annotation(),
|
||||||
cmd_context.option_enable(cmd, opt_verbose));
|
cmd_context.option_enable(cmd, opt_verbose));
|
||||||
|
|
||||||
/* Annotate routing architecture to circuit library */
|
/* Annotate routing architecture to circuit library */
|
||||||
annotate_rr_graph_circuit_models(g_vpr_ctx.device(),
|
annotate_rr_graph_circuit_models(g_vpr_ctx.device(),
|
||||||
openfpga_context.arch(),
|
openfpga_ctx.arch(),
|
||||||
openfpga_context.mutable_vpr_device_annotation(),
|
openfpga_ctx.mutable_vpr_device_annotation(),
|
||||||
cmd_context.option_enable(cmd, opt_verbose));
|
cmd_context.option_enable(cmd, opt_verbose));
|
||||||
|
|
||||||
/* Annotate net mapping to each rr_node
|
/* Annotate net mapping to each rr_node
|
||||||
*/
|
*/
|
||||||
openfpga_context.mutable_vpr_routing_annotation().init(g_vpr_ctx.device().rr_graph);
|
openfpga_ctx.mutable_vpr_routing_annotation().init(g_vpr_ctx.device().rr_graph);
|
||||||
|
|
||||||
annotate_rr_node_nets(g_vpr_ctx.device(), g_vpr_ctx.clustering(), g_vpr_ctx.routing(),
|
annotate_rr_node_nets(g_vpr_ctx.device(), g_vpr_ctx.clustering(), g_vpr_ctx.routing(),
|
||||||
openfpga_context.mutable_vpr_routing_annotation(),
|
openfpga_ctx.mutable_vpr_routing_annotation(),
|
||||||
cmd_context.option_enable(cmd, opt_verbose));
|
cmd_context.option_enable(cmd, opt_verbose));
|
||||||
|
|
||||||
/* Build the routing graph annotation
|
/* Build the routing graph annotation
|
||||||
|
@ -101,17 +101,16 @@ void link_arch(OpenfpgaContext& openfpga_context,
|
||||||
}
|
}
|
||||||
|
|
||||||
annotate_device_rr_gsb(g_vpr_ctx.device(),
|
annotate_device_rr_gsb(g_vpr_ctx.device(),
|
||||||
openfpga_context.mutable_device_rr_gsb(),
|
openfpga_ctx.mutable_device_rr_gsb(),
|
||||||
cmd_context.option_enable(cmd, opt_verbose));
|
cmd_context.option_enable(cmd, opt_verbose));
|
||||||
|
|
||||||
/* Build multiplexer library */
|
/* Build multiplexer library */
|
||||||
openfpga_context.mutable_mux_lib() = build_device_mux_library(g_vpr_ctx.device(),
|
openfpga_ctx.mutable_mux_lib() = build_device_mux_library(g_vpr_ctx.device(),
|
||||||
const_cast<const OpenfpgaContext&>(openfpga_context));
|
const_cast<const OpenfpgaContext&>(openfpga_ctx));
|
||||||
|
|
||||||
/* Build tile direct annotation */
|
/* Build tile direct annotation */
|
||||||
openfpga_context.mutable_tile_direct() = build_device_tile_direct(g_vpr_ctx.device(),
|
openfpga_ctx.mutable_tile_direct() = build_device_tile_direct(g_vpr_ctx.device(),
|
||||||
openfpga_context.arch().arch_direct,
|
openfpga_ctx.arch().arch_direct);
|
||||||
openfpga_context.arch().circuit_lib);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
#include "build_memory_modules.h"
|
#include "build_memory_modules.h"
|
||||||
#include "build_grid_modules.h"
|
#include "build_grid_modules.h"
|
||||||
#include "build_routing_modules.h"
|
#include "build_routing_modules.h"
|
||||||
//#include "build_top_module.h"
|
#include "build_top_module.h"
|
||||||
#include "build_device_module.h"
|
#include "build_device_module.h"
|
||||||
|
|
||||||
/* begin namespace openfpga */
|
/* begin namespace openfpga */
|
||||||
|
@ -97,12 +97,15 @@ ModuleManager build_device_module_graph(const DeviceContext& vpr_device_ctx,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Build FPGA fabric top-level module */
|
/* Build FPGA fabric top-level module */
|
||||||
//build_top_module(module_manager, arch.spice->circuit_lib,
|
build_top_module(module_manager, openfpga_ctx.arch().circuit_lib,
|
||||||
// device_size, grids, L_device_rr_gsb,
|
vpr_device_ctx.grid,
|
||||||
// clb2clb_directs,
|
vpr_device_ctx.rr_graph,
|
||||||
// arch.sram_inf.verilog_sram_inf_orgz->type, sram_model,
|
openfpga_ctx.device_rr_gsb(),
|
||||||
// TRUE == vpr_setup.FPGA_SPICE_Opts.compact_routing_hierarchy,
|
openfpga_ctx.tile_direct(),
|
||||||
// TRUE == vpr_setup.FPGA_SPICE_Opts.duplicate_grid_pin);
|
openfpga_ctx.arch().arch_direct,
|
||||||
|
openfpga_ctx.arch().config_protocol.type(),
|
||||||
|
sram_model,
|
||||||
|
compress_routing, duplicate_grid_pin);
|
||||||
|
|
||||||
/* Now a critical correction has to be done!
|
/* Now a critical correction has to be done!
|
||||||
* In the module construction, we always use prefix of ports because they are binded
|
* In the module construction, we always use prefix of ports because they are binded
|
||||||
|
@ -111,7 +114,7 @@ ModuleManager build_device_module_graph(const DeviceContext& vpr_device_ctx,
|
||||||
* rename the ports of primitive modules using lib_name instead of prefix
|
* rename the ports of primitive modules using lib_name instead of prefix
|
||||||
* (which have no children and are probably linked to a standard cell!)
|
* (which have no children and are probably linked to a standard cell!)
|
||||||
*/
|
*/
|
||||||
//rename_primitive_module_port_names(module_manager, arch.spice->circuit_lib);
|
rename_primitive_module_port_names(module_manager, openfpga_ctx.arch().circuit_lib);
|
||||||
|
|
||||||
return module_manager;
|
return module_manager;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,367 @@
|
||||||
|
/********************************************************************
|
||||||
|
* This file includes functions that are used to print the top-level
|
||||||
|
* module for the FPGA fabric in Verilog format
|
||||||
|
*******************************************************************/
|
||||||
|
#include <map>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
/* Headers from vtrutil library */
|
||||||
|
#include "vtr_assert.h"
|
||||||
|
#include "vtr_time.h"
|
||||||
|
#include "vtr_log.h"
|
||||||
|
|
||||||
|
/* Headers from vpr library */
|
||||||
|
#include "vpr_utils.h"
|
||||||
|
|
||||||
|
#include "rr_gsb_utils.h"
|
||||||
|
#include "openfpga_reserved_words.h"
|
||||||
|
#include "openfpga_naming.h"
|
||||||
|
#include "module_manager_utils.h"
|
||||||
|
#include "build_top_module_utils.h"
|
||||||
|
#include "build_top_module_connection.h"
|
||||||
|
#include "build_top_module_memory.h"
|
||||||
|
#include "build_top_module_directs.h"
|
||||||
|
|
||||||
|
#include "build_module_graph_utils.h"
|
||||||
|
#include "build_top_module.h"
|
||||||
|
|
||||||
|
/* begin namespace openfpga */
|
||||||
|
namespace openfpga {
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Add a instance of a grid module to the top module
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
size_t add_top_module_grid_instance(ModuleManager& module_manager,
|
||||||
|
const ModuleId& top_module,
|
||||||
|
t_physical_tile_type_ptr grid_type,
|
||||||
|
const e_side& border_side,
|
||||||
|
const vtr::Point<size_t>& grid_coord) {
|
||||||
|
/* Find the module name for this type of grid */
|
||||||
|
std::string grid_module_name_prefix(GRID_MODULE_NAME_PREFIX);
|
||||||
|
std::string grid_module_name = generate_grid_block_module_name(grid_module_name_prefix, std::string(grid_type->name), is_io_type(grid_type), border_side);
|
||||||
|
ModuleId grid_module = module_manager.find_module(grid_module_name);
|
||||||
|
VTR_ASSERT(true == module_manager.valid_module_id(grid_module));
|
||||||
|
/* Record the instance id */
|
||||||
|
size_t grid_instance = module_manager.num_instance(top_module, grid_module);
|
||||||
|
/* Add the module to top_module */
|
||||||
|
module_manager.add_child_module(top_module, grid_module);
|
||||||
|
/* Set an unique name to the instance
|
||||||
|
* Note: it is your risk to gurantee the name is unique!
|
||||||
|
*/
|
||||||
|
std::string instance_name = generate_grid_block_instance_name(grid_module_name_prefix, std::string(grid_type->name), is_io_type(grid_type), border_side, grid_coord);
|
||||||
|
module_manager.set_child_instance_name(top_module, grid_module, grid_instance, instance_name);
|
||||||
|
|
||||||
|
return grid_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Add all the grids as sub-modules across the fabric
|
||||||
|
* The grid modules are created for each unique type of grid (based
|
||||||
|
* on the type in data structure data_structure
|
||||||
|
* Here, we will iterate over the full fabric (coordinates)
|
||||||
|
* and instanciate the grid modules
|
||||||
|
*
|
||||||
|
* Return an 2-D array of instance ids of the grid modules that
|
||||||
|
* have been added
|
||||||
|
*
|
||||||
|
* This function assumes an island-style floorplanning for FPGA fabric
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* +-----------------------------------+
|
||||||
|
* | I/O grids |
|
||||||
|
* | TOP side |
|
||||||
|
* +-----------------------------------+
|
||||||
|
*
|
||||||
|
* +-----------+ +-----------------------------------+ +------------+
|
||||||
|
* | | | | | |
|
||||||
|
* | I/O grids | | Core grids | | I/O grids |
|
||||||
|
* | LEFT side | | (CLB, Heterogeneous blocks, etc.) | | RIGHT side |
|
||||||
|
* | | | | | |
|
||||||
|
* +-----------+ +-----------------------------------+ +------------+
|
||||||
|
*
|
||||||
|
* +-----------------------------------+
|
||||||
|
* | I/O grids |
|
||||||
|
* | BOTTOM side |
|
||||||
|
* +-----------------------------------+
|
||||||
|
*
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
vtr::Matrix<size_t> add_top_module_grid_instances(ModuleManager& module_manager,
|
||||||
|
const ModuleId& top_module,
|
||||||
|
const DeviceGrid& grids) {
|
||||||
|
/* Reserve an array for the instance ids */
|
||||||
|
vtr::Matrix<size_t> grid_instance_ids({grids.width(), grids.height()});
|
||||||
|
grid_instance_ids.fill(size_t(-1));
|
||||||
|
|
||||||
|
/* Instanciate core grids */
|
||||||
|
for (size_t ix = 1; ix < grids.width() - 1; ++ix) {
|
||||||
|
for (size_t iy = 1; iy < grids.height() - 1; ++iy) {
|
||||||
|
/* Bypass EMPTY grid */
|
||||||
|
if (true == is_empty_type(grids[ix][iy].type)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Skip width or height > 1 tiles (mostly heterogeneous blocks) */
|
||||||
|
if ( (0 < grids[ix][iy].width_offset)
|
||||||
|
|| (0 < grids[ix][iy].height_offset)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* We should not meet any I/O grid */
|
||||||
|
VTR_ASSERT(false == is_io_type(grids[ix][iy].type));
|
||||||
|
/* Add a grid module to top_module*/
|
||||||
|
vtr::Point<size_t> grid_coord(ix, iy);
|
||||||
|
grid_instance_ids[ix][iy] = add_top_module_grid_instance(module_manager, top_module,
|
||||||
|
grids[ix][iy].type,
|
||||||
|
NUM_SIDES, grid_coord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Instanciate I/O grids */
|
||||||
|
/* Create the coordinate range for each side of FPGA fabric */
|
||||||
|
std::vector<e_side> io_sides{TOP, RIGHT, BOTTOM, LEFT};
|
||||||
|
std::map<e_side, std::vector<vtr::Point<size_t>>> io_coordinates;
|
||||||
|
|
||||||
|
/* TOP side*/
|
||||||
|
for (size_t ix = 1; ix < grids.width() - 1; ++ix) {
|
||||||
|
io_coordinates[TOP].push_back(vtr::Point<size_t>(ix, grids.height() - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* RIGHT side */
|
||||||
|
for (size_t iy = 1; iy < grids.height() - 1; ++iy) {
|
||||||
|
io_coordinates[RIGHT].push_back(vtr::Point<size_t>(grids.width() - 1, iy));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* BOTTOM side*/
|
||||||
|
for (size_t ix = 1; ix < grids.width() - 1; ++ix) {
|
||||||
|
io_coordinates[BOTTOM].push_back(vtr::Point<size_t>(ix, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* LEFT side */
|
||||||
|
for (size_t iy = 1; iy < grids.height() - 1; ++iy) {
|
||||||
|
io_coordinates[LEFT].push_back(vtr::Point<size_t>(0, iy));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add instances of I/O grids to top_module */
|
||||||
|
for (const e_side& io_side : io_sides) {
|
||||||
|
for (const vtr::Point<size_t>& io_coordinate : io_coordinates[io_side]) {
|
||||||
|
/* Bypass EMPTY grid */
|
||||||
|
if (true == is_empty_type(grids[io_coordinate.x()][io_coordinate.y()].type)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Skip width, height > 1 tiles (mostly heterogeneous blocks) */
|
||||||
|
if ( (0 < grids[io_coordinate.x()][io_coordinate.y()].width_offset)
|
||||||
|
|| (0 < grids[io_coordinate.x()][io_coordinate.y()].height_offset)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* We should not meet any I/O grid */
|
||||||
|
VTR_ASSERT(true == is_io_type(grids[io_coordinate.x()][io_coordinate.y()].type));
|
||||||
|
/* Add a grid module to top_module*/
|
||||||
|
grid_instance_ids[io_coordinate.x()][io_coordinate.y()] = add_top_module_grid_instance(module_manager, top_module, grids[io_coordinate.x()][io_coordinate.y()].type, io_side, io_coordinate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return grid_instance_ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Add switch blocks across the FPGA fabric to the top-level module
|
||||||
|
* Return an 2-D array of instance ids of the switch blocks that
|
||||||
|
* have been added
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
vtr::Matrix<size_t> add_top_module_switch_block_instances(ModuleManager& module_manager,
|
||||||
|
const ModuleId& top_module,
|
||||||
|
const DeviceRRGSB& device_rr_gsb,
|
||||||
|
const bool& compact_routing_hierarchy) {
|
||||||
|
vtr::Point<size_t> sb_range = device_rr_gsb.get_gsb_range();
|
||||||
|
|
||||||
|
/* Reserve an array for the instance ids */
|
||||||
|
vtr::Matrix<size_t> sb_instance_ids({sb_range.x(), sb_range.y()});
|
||||||
|
sb_instance_ids.fill(size_t(-1));
|
||||||
|
|
||||||
|
for (size_t ix = 0; ix < sb_range.x(); ++ix) {
|
||||||
|
for (size_t iy = 0; iy < sb_range.y(); ++iy) {
|
||||||
|
/* If we use compact routing hierarchy, we should instanciate the unique module of SB */
|
||||||
|
const RRGSB& rr_gsb = device_rr_gsb.get_gsb(ix, iy);
|
||||||
|
|
||||||
|
if ( false == rr_gsb.is_sb_exist() ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
vtr::Point<size_t> sb_coordinate(rr_gsb.get_sb_x(), rr_gsb.get_sb_y());
|
||||||
|
if (true == compact_routing_hierarchy) {
|
||||||
|
vtr::Point<size_t> sb_coord(ix, iy);
|
||||||
|
const RRGSB& unique_mirror = device_rr_gsb.get_sb_unique_module(sb_coord);
|
||||||
|
sb_coordinate.set_x(unique_mirror.get_sb_x());
|
||||||
|
sb_coordinate.set_y(unique_mirror.get_sb_y());
|
||||||
|
}
|
||||||
|
std::string sb_module_name = generate_switch_block_module_name(sb_coordinate);
|
||||||
|
ModuleId sb_module = module_manager.find_module(sb_module_name);
|
||||||
|
VTR_ASSERT(true == module_manager.valid_module_id(sb_module));
|
||||||
|
/* Record the instance id */
|
||||||
|
sb_instance_ids[rr_gsb.get_sb_x()][rr_gsb.get_sb_y()] = module_manager.num_instance(top_module, sb_module);
|
||||||
|
/* Add the module to top_module */
|
||||||
|
module_manager.add_child_module(top_module, sb_module);
|
||||||
|
/* Set an unique name to the instance
|
||||||
|
* Note: it is your risk to gurantee the name is unique!
|
||||||
|
*/
|
||||||
|
module_manager.set_child_instance_name(top_module, sb_module,
|
||||||
|
sb_instance_ids[rr_gsb.get_sb_x()][rr_gsb.get_sb_y()],
|
||||||
|
generate_switch_block_module_name(vtr::Point<size_t>(rr_gsb.get_sb_x(), rr_gsb.get_sb_y())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb_instance_ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Add switch blocks across the FPGA fabric to the top-level module
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
vtr::Matrix<size_t> add_top_module_connection_block_instances(ModuleManager& module_manager,
|
||||||
|
const ModuleId& top_module,
|
||||||
|
const DeviceRRGSB& device_rr_gsb,
|
||||||
|
const t_rr_type& cb_type,
|
||||||
|
const bool& compact_routing_hierarchy) {
|
||||||
|
vtr::Point<size_t> cb_range = device_rr_gsb.get_gsb_range();
|
||||||
|
|
||||||
|
/* Reserve an array for the instance ids */
|
||||||
|
vtr::Matrix<size_t> cb_instance_ids({cb_range.x(), cb_range.y()});
|
||||||
|
cb_instance_ids.fill(size_t(-1));
|
||||||
|
|
||||||
|
for (size_t ix = 0; ix < cb_range.x(); ++ix) {
|
||||||
|
for (size_t iy = 0; iy < cb_range.y(); ++iy) {
|
||||||
|
/* Check if the connection block exists in the device!
|
||||||
|
* Some of them do NOT exist due to heterogeneous blocks (height > 1)
|
||||||
|
* We will skip those modules
|
||||||
|
*/
|
||||||
|
const RRGSB& rr_gsb = device_rr_gsb.get_gsb(ix, iy);
|
||||||
|
vtr::Point<size_t> cb_coordinate(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type));
|
||||||
|
if ( false == rr_gsb.is_cb_exist(cb_type) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* If we use compact routing hierarchy, we should instanciate the unique module of SB */
|
||||||
|
if (true == compact_routing_hierarchy) {
|
||||||
|
vtr::Point<size_t> cb_coord(ix, iy);
|
||||||
|
/* Note: use GSB coordinate when inquire for unique modules!!! */
|
||||||
|
const RRGSB& unique_mirror = device_rr_gsb.get_cb_unique_module(cb_type, cb_coord);
|
||||||
|
cb_coordinate.set_x(unique_mirror.get_cb_x(cb_type));
|
||||||
|
cb_coordinate.set_y(unique_mirror.get_cb_y(cb_type));
|
||||||
|
}
|
||||||
|
std::string cb_module_name = generate_connection_block_module_name(cb_type, cb_coordinate);
|
||||||
|
ModuleId cb_module = module_manager.find_module(cb_module_name);
|
||||||
|
VTR_ASSERT(true == module_manager.valid_module_id(cb_module));
|
||||||
|
/* Record the instance id */
|
||||||
|
cb_instance_ids[rr_gsb.get_cb_x(cb_type)][rr_gsb.get_cb_y(cb_type)] = module_manager.num_instance(top_module, cb_module);
|
||||||
|
/* Add the module to top_module */
|
||||||
|
module_manager.add_child_module(top_module, cb_module);
|
||||||
|
/* Set an unique name to the instance
|
||||||
|
* Note: it is your risk to gurantee the name is unique!
|
||||||
|
*/
|
||||||
|
std::string cb_instance_name = generate_connection_block_module_name(cb_type, vtr::Point<size_t>(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type)));
|
||||||
|
module_manager.set_child_instance_name(top_module, cb_module,
|
||||||
|
cb_instance_ids[rr_gsb.get_cb_x(cb_type)][rr_gsb.get_cb_y(cb_type)],
|
||||||
|
cb_instance_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cb_instance_ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Print the top-level module for the FPGA fabric in Verilog format
|
||||||
|
* This function will
|
||||||
|
* 1. name the top-level module
|
||||||
|
* 2. include dependent netlists
|
||||||
|
* - User defined netlists
|
||||||
|
* - Auto-generated netlists
|
||||||
|
* 3. Add the submodules to the top-level graph
|
||||||
|
* 4. Add module nets to connect datapath ports
|
||||||
|
* 5. Add module nets/submodules to connect configuration ports
|
||||||
|
*******************************************************************/
|
||||||
|
void build_top_module(ModuleManager& module_manager,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
const DeviceGrid& grids,
|
||||||
|
const RRGraph& rr_graph,
|
||||||
|
const DeviceRRGSB& device_rr_gsb,
|
||||||
|
const TileDirect& tile_direct,
|
||||||
|
const ArchDirect& arch_direct,
|
||||||
|
const e_config_protocol_type& sram_orgz_type,
|
||||||
|
const CircuitModelId& sram_model,
|
||||||
|
const bool& compact_routing_hierarchy,
|
||||||
|
const bool& duplicate_grid_pin) {
|
||||||
|
|
||||||
|
vtr::ScopedStartFinishTimer timer("Build FPGA fabric module");
|
||||||
|
|
||||||
|
/* Create a module as the top-level fabric, and add it to the module manager */
|
||||||
|
std::string top_module_name = generate_fpga_top_module_name();
|
||||||
|
ModuleId top_module = module_manager.add_module(top_module_name);
|
||||||
|
|
||||||
|
std::map<t_rr_type, vtr::Matrix<size_t>> cb_instance_ids;
|
||||||
|
|
||||||
|
/* Add sub modules, which are grid, SB and CBX/CBY modules as instances */
|
||||||
|
/* Add all the grids across the fabric */
|
||||||
|
vtr::Matrix<size_t> grid_instance_ids = add_top_module_grid_instances(module_manager, top_module, grids);
|
||||||
|
/* Add all the SBs across the fabric */
|
||||||
|
vtr::Matrix<size_t> sb_instance_ids = add_top_module_switch_block_instances(module_manager, top_module, device_rr_gsb, compact_routing_hierarchy);
|
||||||
|
/* Add all the CBX and CBYs across the fabric */
|
||||||
|
cb_instance_ids[CHANX] = add_top_module_connection_block_instances(module_manager, top_module, device_rr_gsb, CHANX, compact_routing_hierarchy);
|
||||||
|
cb_instance_ids[CHANY] = add_top_module_connection_block_instances(module_manager, top_module, device_rr_gsb, CHANY, compact_routing_hierarchy);
|
||||||
|
|
||||||
|
/* Add module nets to connect the sub modules */
|
||||||
|
add_top_module_nets_connect_grids_and_gsbs(module_manager, top_module,
|
||||||
|
grids, grid_instance_ids,
|
||||||
|
rr_graph, device_rr_gsb, sb_instance_ids, cb_instance_ids,
|
||||||
|
compact_routing_hierarchy, duplicate_grid_pin);
|
||||||
|
/* Add inter-CLB direct connections */
|
||||||
|
add_top_module_nets_tile_direct_connections(module_manager, top_module, circuit_lib,
|
||||||
|
grids, grid_instance_ids,
|
||||||
|
tile_direct, arch_direct);
|
||||||
|
|
||||||
|
/* Add global ports to the pb_module:
|
||||||
|
* This is a much easier job after adding sub modules (instances),
|
||||||
|
* we just need to find all the global ports from the child modules and build a list of it
|
||||||
|
*/
|
||||||
|
add_module_global_ports_from_child_modules(module_manager, top_module);
|
||||||
|
|
||||||
|
/* Add GPIO ports from the sub-modules under this Verilog module
|
||||||
|
* This is a much easier job after adding sub modules (instances),
|
||||||
|
* we just need to find all the I/O ports from the child modules and build a list of it
|
||||||
|
*/
|
||||||
|
add_module_gpio_ports_from_child_modules(module_manager, top_module);
|
||||||
|
|
||||||
|
/* Add shared SRAM ports from the sub-modules under this Verilog module
|
||||||
|
* This is a much easier job after adding sub modules (instances),
|
||||||
|
* we just need to find all the I/O ports from the child modules and build a list of it
|
||||||
|
*/
|
||||||
|
size_t module_num_shared_config_bits = find_module_num_shared_config_bits_from_child_modules(module_manager, top_module);
|
||||||
|
if (0 < module_num_shared_config_bits) {
|
||||||
|
add_reserved_sram_ports_to_module_manager(module_manager, top_module, module_num_shared_config_bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add SRAM ports from the sub-modules under this Verilog module
|
||||||
|
* This is a much easier job after adding sub modules (instances),
|
||||||
|
* we just need to find all the I/O ports from the child modules and build a list of it
|
||||||
|
*/
|
||||||
|
size_t module_num_config_bits = find_module_num_config_bits_from_child_modules(module_manager, top_module, circuit_lib, sram_model, sram_orgz_type);
|
||||||
|
if (0 < module_num_config_bits) {
|
||||||
|
add_sram_ports_to_module_manager(module_manager, top_module, circuit_lib, sram_model, sram_orgz_type, module_num_config_bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Organize the list of memory modules and instances */
|
||||||
|
organize_top_module_memory_modules(module_manager, top_module,
|
||||||
|
circuit_lib, sram_orgz_type, sram_model,
|
||||||
|
grids, grid_instance_ids,
|
||||||
|
device_rr_gsb, sb_instance_ids, cb_instance_ids,
|
||||||
|
compact_routing_hierarchy);
|
||||||
|
|
||||||
|
/* Add module nets to connect memory cells inside
|
||||||
|
* This is a one-shot addition that covers all the memory modules in this pb module!
|
||||||
|
*/
|
||||||
|
if (0 < module_manager.configurable_children(top_module).size()) {
|
||||||
|
add_top_module_nets_memory_config_bus(module_manager, top_module,
|
||||||
|
sram_orgz_type, circuit_lib.design_tech_type(sram_model));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* end namespace openfpga */
|
|
@ -0,0 +1,39 @@
|
||||||
|
#ifndef BUILD_TOP_MODULE_H
|
||||||
|
#define BUILD_TOP_MODULE_H
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Include header files that are required by function declaration
|
||||||
|
*******************************************************************/
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include "vtr_geometry.h"
|
||||||
|
#include "device_grid.h"
|
||||||
|
#include "rr_graph_obj.h"
|
||||||
|
#include "device_rr_gsb.h"
|
||||||
|
#include "circuit_library.h"
|
||||||
|
#include "tile_direct.h"
|
||||||
|
#include "arch_direct.h"
|
||||||
|
#include "module_manager.h"
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Function declaration
|
||||||
|
*******************************************************************/
|
||||||
|
|
||||||
|
/* begin namespace openfpga */
|
||||||
|
namespace openfpga {
|
||||||
|
|
||||||
|
void build_top_module(ModuleManager& module_manager,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
const DeviceGrid& grids,
|
||||||
|
const RRGraph& rr_graph,
|
||||||
|
const DeviceRRGSB& device_rr_gsb,
|
||||||
|
const TileDirect& tile_direct,
|
||||||
|
const ArchDirect& arch_direct,
|
||||||
|
const e_config_protocol_type& sram_orgz_type,
|
||||||
|
const CircuitModelId& sram_model,
|
||||||
|
const bool& compact_routing_hierarchy,
|
||||||
|
const bool& duplicate_grid_pin);
|
||||||
|
|
||||||
|
} /* end namespace openfpga */
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,151 @@
|
||||||
|
/********************************************************************
|
||||||
|
* This file includes functions that are used to add module nets
|
||||||
|
* for direct connections between CLBs/heterogeneous blocks
|
||||||
|
* in the top-level module of a FPGA fabric
|
||||||
|
*******************************************************************/
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
/* Headers from vtrutil library */
|
||||||
|
#include "vtr_assert.h"
|
||||||
|
#include "vtr_log.h"
|
||||||
|
|
||||||
|
/* Headers from openfpgautil library */
|
||||||
|
#include "openfpga_port.h"
|
||||||
|
|
||||||
|
/* Headers from vpr library */
|
||||||
|
#include "vpr_utils.h"
|
||||||
|
|
||||||
|
#include "openfpga_reserved_words.h"
|
||||||
|
#include "openfpga_naming.h"
|
||||||
|
#include "module_manager_utils.h"
|
||||||
|
|
||||||
|
#include "build_top_module_directs.h"
|
||||||
|
|
||||||
|
/* begin namespace openfpga */
|
||||||
|
namespace openfpga {
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Add module net for one direction connection between two CLBs or
|
||||||
|
* two grids
|
||||||
|
* This function will
|
||||||
|
* 1. find the pin id and port id of the source clb port in module manager
|
||||||
|
* 2. find the pin id and port id of the destination clb port in module manager
|
||||||
|
* 3. add a direct connection module to the top module
|
||||||
|
* 4. add a first module net and configure its source and sink,
|
||||||
|
* in order to connect the source pin to the input of the top module
|
||||||
|
* 4. add a second module net and configure its source and sink,
|
||||||
|
* in order to connect the sink pin to the output of the top module
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
void add_module_nets_tile_direct_connection(ModuleManager& module_manager,
|
||||||
|
const ModuleId& top_module,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
const DeviceGrid& grids,
|
||||||
|
const vtr::Matrix<size_t>& grid_instance_ids,
|
||||||
|
const TileDirect& tile_direct,
|
||||||
|
const TileDirectId& tile_direct_id,
|
||||||
|
const ArchDirect& arch_direct) {
|
||||||
|
vtr::Point<size_t> device_size(grids.width(), grids.height());
|
||||||
|
|
||||||
|
/* Find the module name of source clb */
|
||||||
|
vtr::Point<size_t> src_clb_coord = tile_direct.from_tile_coordinate(tile_direct_id);
|
||||||
|
t_physical_tile_type_ptr src_grid_type = grids[src_clb_coord.x()][src_clb_coord.y()].type;
|
||||||
|
e_side src_grid_border_side = find_grid_border_side(device_size, src_clb_coord);
|
||||||
|
std::string src_module_name_prefix(GRID_MODULE_NAME_PREFIX);
|
||||||
|
std::string src_module_name = generate_grid_block_module_name(src_module_name_prefix, std::string(src_grid_type->name), is_io_type(src_grid_type), src_grid_border_side);
|
||||||
|
ModuleId src_grid_module = module_manager.find_module(src_module_name);
|
||||||
|
VTR_ASSERT(true == module_manager.valid_module_id(src_grid_module));
|
||||||
|
/* Record the instance id */
|
||||||
|
size_t src_grid_instance = grid_instance_ids[src_clb_coord.x()][src_clb_coord.y()];
|
||||||
|
|
||||||
|
/* Find the module name of sink clb */
|
||||||
|
vtr::Point<size_t> des_clb_coord = tile_direct.to_tile_coordinate(tile_direct_id);
|
||||||
|
t_physical_tile_type_ptr sink_grid_type = grids[des_clb_coord.x()][des_clb_coord.y()].type;
|
||||||
|
e_side sink_grid_border_side = find_grid_border_side(device_size, des_clb_coord);
|
||||||
|
std::string sink_module_name_prefix(GRID_MODULE_NAME_PREFIX);
|
||||||
|
std::string sink_module_name = generate_grid_block_module_name(sink_module_name_prefix, std::string(sink_grid_type->name), is_io_type(sink_grid_type), sink_grid_border_side);
|
||||||
|
ModuleId sink_grid_module = module_manager.find_module(sink_module_name);
|
||||||
|
VTR_ASSERT(true == module_manager.valid_module_id(sink_grid_module));
|
||||||
|
/* Record the instance id */
|
||||||
|
size_t sink_grid_instance = grid_instance_ids[des_clb_coord.x()][des_clb_coord.y()];
|
||||||
|
|
||||||
|
/* Find the module id of a direct connection module */
|
||||||
|
CircuitModelId direct_circuit_model = arch_direct.circuit_model(tile_direct.arch_direct(tile_direct_id));
|
||||||
|
std::string direct_module_name = circuit_lib.model_name(direct_circuit_model);
|
||||||
|
ModuleId direct_module = module_manager.find_module(direct_module_name);
|
||||||
|
VTR_ASSERT(true == module_manager.valid_module_id(direct_module));
|
||||||
|
|
||||||
|
/* Find inputs and outputs of the direct circuit module */
|
||||||
|
std::vector<CircuitPortId> direct_input_ports = circuit_lib.model_ports_by_type(direct_circuit_model, CIRCUIT_MODEL_PORT_INPUT, true);
|
||||||
|
VTR_ASSERT(1 == direct_input_ports.size());
|
||||||
|
ModulePortId direct_input_port_id = module_manager.find_module_port(direct_module, circuit_lib.port_prefix(direct_input_ports[0]));
|
||||||
|
VTR_ASSERT(true == module_manager.valid_module_port_id(direct_module, direct_input_port_id));
|
||||||
|
VTR_ASSERT(1 == module_manager.module_port(direct_module, direct_input_port_id).get_width());
|
||||||
|
|
||||||
|
std::vector<CircuitPortId> direct_output_ports = circuit_lib.model_ports_by_type(direct_circuit_model, CIRCUIT_MODEL_PORT_OUTPUT, true);
|
||||||
|
VTR_ASSERT(1 == direct_output_ports.size());
|
||||||
|
ModulePortId direct_output_port_id = module_manager.find_module_port(direct_module, circuit_lib.port_prefix(direct_output_ports[0]));
|
||||||
|
VTR_ASSERT(true == module_manager.valid_module_port_id(direct_module, direct_output_port_id));
|
||||||
|
VTR_ASSERT(1 == module_manager.module_port(direct_module, direct_output_port_id).get_width());
|
||||||
|
|
||||||
|
/* Generate the pin name of source port/pin in the grid */
|
||||||
|
e_side src_pin_grid_side = tile_direct.from_tile_side(tile_direct_id);
|
||||||
|
size_t src_tile_pin = tile_direct.from_tile_pin(tile_direct_id);
|
||||||
|
size_t src_pin_width = grids[src_clb_coord.x()][src_clb_coord.y()].type->pin_width_offset[src_tile_pin];
|
||||||
|
size_t src_pin_height = grids[src_clb_coord.x()][src_clb_coord.y()].type->pin_height_offset[src_tile_pin];
|
||||||
|
std::string src_port_name = generate_grid_port_name(src_clb_coord, src_pin_width, src_pin_height, src_pin_grid_side, src_tile_pin, false);
|
||||||
|
ModulePortId src_port_id = module_manager.find_module_port(src_grid_module, src_port_name);
|
||||||
|
VTR_ASSERT(true == module_manager.valid_module_port_id(src_grid_module, src_port_id));
|
||||||
|
VTR_ASSERT(1 == module_manager.module_port(src_grid_module, src_port_id).get_width());
|
||||||
|
|
||||||
|
/* Generate the pin name of sink port/pin in the grid */
|
||||||
|
e_side sink_pin_grid_side = tile_direct.to_tile_side(tile_direct_id);
|
||||||
|
size_t sink_tile_pin = tile_direct.to_tile_pin(tile_direct_id);
|
||||||
|
size_t sink_pin_width = grids[des_clb_coord.x()][des_clb_coord.y()].type->pin_width_offset[src_tile_pin];
|
||||||
|
size_t sink_pin_height = grids[des_clb_coord.x()][des_clb_coord.y()].type->pin_height_offset[src_tile_pin];
|
||||||
|
|
||||||
|
std::string sink_port_name = generate_grid_port_name(des_clb_coord, sink_pin_width, sink_pin_height, sink_pin_grid_side, sink_tile_pin, false);
|
||||||
|
ModulePortId sink_port_id = module_manager.find_module_port(sink_grid_module, sink_port_name);
|
||||||
|
VTR_ASSERT(true == module_manager.valid_module_port_id(sink_grid_module, sink_port_id));
|
||||||
|
VTR_ASSERT(1 == module_manager.module_port(sink_grid_module, sink_port_id).get_width());
|
||||||
|
|
||||||
|
/* Add a submodule of direct connection module to the top-level module */
|
||||||
|
size_t direct_instance_id = module_manager.num_instance(top_module, direct_module);
|
||||||
|
module_manager.add_child_module(top_module, direct_module);
|
||||||
|
|
||||||
|
/* Create the 1st module net */
|
||||||
|
ModuleNetId net_direct_src = module_manager.create_module_net(top_module);
|
||||||
|
/* Connect the wire between src_pin of clb and direct_instance input*/
|
||||||
|
module_manager.add_module_net_source(top_module, net_direct_src, src_grid_module, src_grid_instance, src_port_id, 0);
|
||||||
|
module_manager.add_module_net_sink(top_module, net_direct_src, direct_module, direct_instance_id, direct_input_port_id, 0);
|
||||||
|
|
||||||
|
/* Create the 2nd module net */
|
||||||
|
ModuleNetId net_direct_sink = module_manager.create_module_net(top_module);
|
||||||
|
/* Connect the wire between direct_instance output and sink_pin of clb */
|
||||||
|
module_manager.add_module_net_source(top_module, net_direct_sink, direct_module, direct_instance_id, direct_output_port_id, 0);
|
||||||
|
module_manager.add_module_net_sink(top_module, net_direct_sink, sink_grid_module, sink_grid_instance, sink_port_id, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Add module net of clb-to-clb direct connections to module manager
|
||||||
|
* Note that the direct connections are not limited to CLBs only.
|
||||||
|
* It can be more generic and thus cover all the grid types,
|
||||||
|
* such as heterogeneous blocks
|
||||||
|
*******************************************************************/
|
||||||
|
void add_top_module_nets_tile_direct_connections(ModuleManager& module_manager,
|
||||||
|
const ModuleId& top_module,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
const DeviceGrid& grids,
|
||||||
|
const vtr::Matrix<size_t>& grid_instance_ids,
|
||||||
|
const TileDirect& tile_direct,
|
||||||
|
const ArchDirect& arch_direct) {
|
||||||
|
|
||||||
|
for (const TileDirectId& tile_direct_id : tile_direct.directs()) {
|
||||||
|
add_module_nets_tile_direct_connection(module_manager, top_module, circuit_lib,
|
||||||
|
grids, grid_instance_ids,
|
||||||
|
tile_direct, tile_direct_id,
|
||||||
|
arch_direct);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* end namespace openfpga */
|
|
@ -0,0 +1,33 @@
|
||||||
|
#ifndef BUILD_TOP_MODULE_DIRECTS_H
|
||||||
|
#define BUILD_TOP_MODULE_DIRECTS_H
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Include header files that are required by function declaration
|
||||||
|
*******************************************************************/
|
||||||
|
#include <vector>
|
||||||
|
#include "vtr_geometry.h"
|
||||||
|
#include "vtr_ndmatrix.h"
|
||||||
|
#include "arch_direct.h"
|
||||||
|
#include "tile_direct.h"
|
||||||
|
#include "device_grid.h"
|
||||||
|
#include "module_manager.h"
|
||||||
|
#include "circuit_library.h"
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Function declaration
|
||||||
|
*******************************************************************/
|
||||||
|
|
||||||
|
/* begin namespace openfpga */
|
||||||
|
namespace openfpga {
|
||||||
|
|
||||||
|
void add_top_module_nets_tile_direct_connections(ModuleManager& module_manager,
|
||||||
|
const ModuleId& top_module,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
const DeviceGrid& grids,
|
||||||
|
const vtr::Matrix<size_t>& grid_instance_ids,
|
||||||
|
const TileDirect& tile_direct,
|
||||||
|
const ArchDirect& arch_direct);
|
||||||
|
|
||||||
|
} /* end namespace openfpga */
|
||||||
|
|
||||||
|
#endif
|
|
@ -119,26 +119,250 @@ std::vector<size_t> find_physical_tile_pin_id(t_physical_tile_type_ptr physical_
|
||||||
return pin_ids;
|
return pin_ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Check if the grid coorindate given is in the device grid range
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
bool is_grid_coordinate_exist_in_device(const DeviceGrid& device_grid,
|
||||||
|
const vtr::Point<size_t>& grid_coordinate) {
|
||||||
|
return (grid_coordinate < vtr::Point<size_t>(device_grid.width(), device_grid.height()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Find the coordinate of a grid in a specific column
|
||||||
|
* with a given type
|
||||||
|
* This function will return the coordinate of the grid that satifies
|
||||||
|
* the type requirement
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
vtr::Point<size_t> find_grid_coordinate_given_type(const DeviceGrid& grids,
|
||||||
|
const std::vector<vtr::Point<size_t>>& candidate_coords,
|
||||||
|
const std::string& wanted_grid_type_name) {
|
||||||
|
for (vtr::Point<size_t> coord : candidate_coords) {
|
||||||
|
/* If the next column is not longer in device range, we can return */
|
||||||
|
if (false == is_grid_coordinate_exist_in_device(grids, coord)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (wanted_grid_type_name == std::string(grids[coord.x()][coord.y()].type->name)) {
|
||||||
|
return coord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Return an valid coordinate */
|
||||||
|
return vtr::Point<size_t>(grids.width(), grids.height());
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Find the coordinate of the destination clb/heterogeneous block
|
||||||
|
* considering intra column/row direct connections in core grids
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
vtr::Point<size_t> find_inter_direct_destination_coordinate(const DeviceGrid& grids,
|
||||||
|
const vtr::Point<size_t>& src_coord,
|
||||||
|
const std::string des_tile_type_name,
|
||||||
|
const ArchDirect& arch_direct,
|
||||||
|
const ArchDirectId& arch_direct_id) {
|
||||||
|
vtr::Point<size_t> des_coord(grids.width(), grids.height());
|
||||||
|
|
||||||
|
std::vector<size_t> first_search_space;
|
||||||
|
std::vector<size_t> second_search_space;
|
||||||
|
|
||||||
|
/* Cross column connection from Bottom to Top on Right
|
||||||
|
* The next column may NOT have the grid type we want!
|
||||||
|
* Think about heterogeneous architecture!
|
||||||
|
* Our search space will start from the next column
|
||||||
|
* and ends at the RIGHT side of fabric
|
||||||
|
*/
|
||||||
|
if (INTER_COLUMN == arch_direct.type(arch_direct_id)) {
|
||||||
|
if (POSITIVE_DIR == arch_direct.x_dir(arch_direct_id)) {
|
||||||
|
/* Our first search space will be in x-direction:
|
||||||
|
*
|
||||||
|
* x ... nx
|
||||||
|
* +-----+
|
||||||
|
* |Grid | ----->
|
||||||
|
* +-----+
|
||||||
|
*/
|
||||||
|
for (size_t ix = src_coord.x() + 1; ix < grids.width() - 1; ++ix) {
|
||||||
|
first_search_space.push_back(ix);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
VTR_ASSERT(NEGATIVE_DIR == arch_direct.x_dir(arch_direct_id));
|
||||||
|
/* Our first search space will be in x-direction:
|
||||||
|
*
|
||||||
|
* 1 ... x
|
||||||
|
* +-----+
|
||||||
|
* < -------|Grid |
|
||||||
|
* +-----+
|
||||||
|
*/
|
||||||
|
for (size_t ix = src_coord.x() - 1; ix >= 1; --ix) {
|
||||||
|
first_search_space.push_back(ix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Our second search space will be in y-direction:
|
||||||
|
*
|
||||||
|
* +------+
|
||||||
|
* | Grid | ny
|
||||||
|
* +------+
|
||||||
|
* | .
|
||||||
|
* | .
|
||||||
|
* v .
|
||||||
|
* +------+
|
||||||
|
* | Grid | 1
|
||||||
|
* +------+
|
||||||
|
*/
|
||||||
|
for (size_t iy = 1 ; iy < grids.height() - 1; ++iy) {
|
||||||
|
second_search_space.push_back(iy);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For negative direction, our second search space will be in y-direction:
|
||||||
|
*
|
||||||
|
* +------+
|
||||||
|
* | Grid | ny
|
||||||
|
* +------+
|
||||||
|
* ^ .
|
||||||
|
* | .
|
||||||
|
* | .
|
||||||
|
* +------+
|
||||||
|
* | Grid | 1
|
||||||
|
* +------+
|
||||||
|
*/
|
||||||
|
if (NEGATIVE_DIR == arch_direct.y_dir(arch_direct_id)) {
|
||||||
|
std::reverse(second_search_space.begin(), second_search_space.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Cross row connection from Bottom to Top on Right
|
||||||
|
* The next column may NOT have the grid type we want!
|
||||||
|
* Think about heterogeneous architecture!
|
||||||
|
* Our search space will start from the next column
|
||||||
|
* and ends at the RIGHT side of fabric
|
||||||
|
*/
|
||||||
|
if (INTER_ROW == arch_direct.type(arch_direct_id)) {
|
||||||
|
if (POSITIVE_DIR == arch_direct.y_dir(arch_direct_id)) {
|
||||||
|
/* Our first search space will be in y-direction:
|
||||||
|
*
|
||||||
|
* +------+
|
||||||
|
* | Grid | ny
|
||||||
|
* +------+
|
||||||
|
* ^ .
|
||||||
|
* | .
|
||||||
|
* | .
|
||||||
|
* +------+
|
||||||
|
* | Grid | y
|
||||||
|
* +------+
|
||||||
|
*/
|
||||||
|
for (size_t iy = src_coord.y() + 1; iy < grids.height() - 1; ++iy) {
|
||||||
|
first_search_space.push_back(iy);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
VTR_ASSERT(NEGATIVE_DIR == arch_direct.y_dir(arch_direct_id));
|
||||||
|
/* For negative y-direction,
|
||||||
|
* Our first search space will be in y-direction:
|
||||||
|
*
|
||||||
|
* +------+
|
||||||
|
* | Grid | ny
|
||||||
|
* +------+
|
||||||
|
* | .
|
||||||
|
* | .
|
||||||
|
* v .
|
||||||
|
* +------+
|
||||||
|
* | Grid | y
|
||||||
|
* +------+
|
||||||
|
*/
|
||||||
|
for (size_t iy = src_coord.y() - 1; iy >= 1; --iy) {
|
||||||
|
first_search_space.push_back(iy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Our second search space will be in x-direction:
|
||||||
|
*
|
||||||
|
* 1 ... nx
|
||||||
|
* +------+ +------+
|
||||||
|
* | Grid |------>| Grid |
|
||||||
|
* +------+ +------+
|
||||||
|
*/
|
||||||
|
for (size_t ix = 1 ; ix < grids.width() - 1; ++ix) {
|
||||||
|
second_search_space.push_back(ix);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For negative direction,
|
||||||
|
* our second search space will be in x-direction:
|
||||||
|
*
|
||||||
|
* 1 ... nx
|
||||||
|
* +------+ +------+
|
||||||
|
* | Grid |<------| Grid |
|
||||||
|
* +------+ +------+
|
||||||
|
*/
|
||||||
|
if (NEGATIVE_DIR == arch_direct.x_dir(arch_direct_id)) {
|
||||||
|
std::reverse(second_search_space.begin(), second_search_space.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t ix : first_search_space) {
|
||||||
|
std::vector<vtr::Point<size_t>> next_col_row_coords;
|
||||||
|
for (size_t iy : second_search_space) {
|
||||||
|
if (INTER_COLUMN == arch_direct.type(arch_direct_id)) {
|
||||||
|
next_col_row_coords.push_back(vtr::Point<size_t>(ix, iy));
|
||||||
|
} else {
|
||||||
|
VTR_ASSERT(INTER_ROW == arch_direct.type(arch_direct_id));
|
||||||
|
/* For cross-row connection, our search space is flipped */
|
||||||
|
next_col_row_coords.push_back(vtr::Point<size_t>(iy, ix));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vtr::Point<size_t> des_coord_cand = find_grid_coordinate_given_type(grids, next_col_row_coords, des_tile_type_name);
|
||||||
|
/* For a valid coordinate, we can return */
|
||||||
|
if (true == is_grid_coordinate_exist_in_device(grids, des_coord_cand)) {
|
||||||
|
return des_coord_cand;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return des_coord;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************************
|
||||||
|
* Report error for port matching failure
|
||||||
|
***************************************************************************************/
|
||||||
|
static
|
||||||
|
void report_direct_from_port_and_to_port_mismatch(const t_direct_inf& vpr_direct,
|
||||||
|
const BasicPort& from_tile_port,
|
||||||
|
const BasicPort& to_tile_port) {
|
||||||
|
VTR_LOG_ERROR("From_port '%s[%lu:%lu] of direct '%s' does not match to_port '%s[%lu:%lu]'!\n",
|
||||||
|
from_tile_port.get_name().c_str(),
|
||||||
|
from_tile_port.get_lsb(),
|
||||||
|
from_tile_port.get_msb(),
|
||||||
|
vpr_direct.name,
|
||||||
|
to_tile_port.get_name().c_str(),
|
||||||
|
to_tile_port.get_lsb(),
|
||||||
|
to_tile_port.get_msb());
|
||||||
|
}
|
||||||
|
|
||||||
/***************************************************************************************
|
/***************************************************************************************
|
||||||
* Build the point-to-point direct connections based on
|
* Build the point-to-point direct connections based on
|
||||||
* - original VPR arch definition
|
* - original VPR arch definition
|
||||||
* This is limited to the inner-column and inner-row connections
|
* This is limited to the inner-column and inner-row connections
|
||||||
|
* Note that the direct connections are not limited to CLBs only.
|
||||||
|
* It can be more generic and thus cover all the grid types,
|
||||||
|
* such as heterogeneous blocks
|
||||||
*
|
*
|
||||||
* Build the inner-column and inner-row connections
|
* This function supports the following type of direct connection:
|
||||||
*
|
* 1. Direct connection between tiles in the same column or row
|
||||||
* +------+
|
* +------+ +------+
|
||||||
* | Tile |
|
* | | | |
|
||||||
* +------+ +------+ +------+
|
* | Tile |----->| Tile |
|
||||||
* | or | Tile |--->| Tile |
|
* | | | |
|
||||||
* v +------+ +------+
|
* +------+ +------+
|
||||||
|
* | direction connection
|
||||||
|
* v
|
||||||
* +------+
|
* +------+
|
||||||
|
* | |
|
||||||
* | Tile |
|
* | Tile |
|
||||||
|
* | |
|
||||||
* +------+
|
* +------+
|
||||||
*
|
*
|
||||||
***************************************************************************************/
|
***************************************************************************************/
|
||||||
static
|
static
|
||||||
void build_inner_column_row_tile_direct(TileDirect& tile_direct,
|
void build_inner_column_row_tile_direct(TileDirect& tile_direct,
|
||||||
t_direct_inf& vpr_direct,
|
const t_direct_inf& vpr_direct,
|
||||||
const DeviceContext& device_ctx,
|
const DeviceContext& device_ctx,
|
||||||
const ArchDirectId& arch_direct_id) {
|
const ArchDirectId& arch_direct_id) {
|
||||||
/* Get the source tile and pin information */
|
/* Get the source tile and pin information */
|
||||||
|
@ -178,8 +402,7 @@ void build_inner_column_row_tile_direct(TileDirect& tile_direct,
|
||||||
/* We should try to the sink grid for inner-column/row direct connections */
|
/* We should try to the sink grid for inner-column/row direct connections */
|
||||||
vtr::Point<size_t> from_grid_coord(x, y);
|
vtr::Point<size_t> from_grid_coord(x, y);
|
||||||
vtr::Point<size_t> to_grid_coord(x + vpr_direct.x_offset, y + vpr_direct.y_offset);
|
vtr::Point<size_t> to_grid_coord(x + vpr_direct.x_offset, y + vpr_direct.y_offset);
|
||||||
if ((to_grid_coord.x() >= device_ctx.grid.width())
|
if (false == is_grid_coordinate_exist_in_device(device_ctx.grid, to_grid_coord)) {
|
||||||
|| (to_grid_coord.y() >= device_ctx.grid.height())) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,61 +423,60 @@ void build_inner_column_row_tile_direct(TileDirect& tile_direct,
|
||||||
|
|
||||||
/* If from port and to port do not match in sizes, error out */
|
/* If from port and to port do not match in sizes, error out */
|
||||||
if (from_pins.size() != to_pins.size()) {
|
if (from_pins.size() != to_pins.size()) {
|
||||||
VTR_LOG_ERROR("From_port '%s[%lu:%lu] of direct '%s' does not match to_port '%s[%lu:%lu]'!\n",
|
report_direct_from_port_and_to_port_mismatch(vpr_direct, from_tile_port, to_tile_port);
|
||||||
from_tile_port.get_name().c_str(),
|
|
||||||
from_tile_port.get_lsb(),
|
|
||||||
from_tile_port.get_msb(),
|
|
||||||
vpr_direct.name,
|
|
||||||
to_tile_port.get_name().c_str(),
|
|
||||||
to_tile_port.get_lsb(),
|
|
||||||
to_tile_port.get_msb());
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now add the tile direct */
|
/* Now add the tile direct */
|
||||||
for (size_t ipin = 0; ipin < from_pins.size(); ++ipin) {
|
for (size_t ipin = 0; ipin < from_pins.size(); ++ipin) {
|
||||||
TileDirectId tile_direct_id = tile_direct.add_direct(device_ctx.grid[x][y].type,
|
TileDirectId tile_direct_id = tile_direct.add_direct(from_grid_coord, vpr_direct.from_side, from_pins[ipin],
|
||||||
from_grid_coord, vpr_direct.from_side, from_pins[ipin],
|
|
||||||
device_ctx.grid[to_grid_coord.x()][to_grid_coord.y()].type,
|
|
||||||
to_grid_coord, vpr_direct.to_side, to_pins[ipin]);
|
to_grid_coord, vpr_direct.to_side, to_pins[ipin]);
|
||||||
tile_direct.set_arch_direct_id(tile_direct_id, arch_direct_id);
|
tile_direct.set_arch_direct_id(tile_direct_id, arch_direct_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************************************************
|
/********************************************************************
|
||||||
* Build the point-to-point direct connections based on
|
* Build the point-to-point direct connections based on
|
||||||
* - OpenFPGA arch definition
|
* - OpenFPGA arch definition
|
||||||
* This is limited to the inter-column and inter-row connections
|
* This is limited to the inter-column and inter-row connections
|
||||||
*
|
*
|
||||||
* Build the inter-column and inter-row connections
|
* Note that the direct connections are not limited to CLBs only.
|
||||||
|
* It can be more generic and thus cover all the grid types,
|
||||||
|
* such as heterogeneous blocks
|
||||||
*
|
*
|
||||||
* +------+ +------+
|
* This function supports the following type of direct connection:
|
||||||
* | Tile | | Tile |
|
*
|
||||||
* +------+ +------+
|
* 1. Direct connections across columns and rows
|
||||||
* | ^
|
* +------+
|
||||||
* | |
|
* | |
|
||||||
* +-------------
|
* | v
|
||||||
*
|
* +------+ | +------+
|
||||||
* +------+
|
* | | | | |
|
||||||
* | Tile |-------+
|
* | Grid | | | Grid |
|
||||||
* +------+ |
|
* | | | | |
|
||||||
|
* +------+ | +------+
|
||||||
* |
|
* |
|
||||||
* +------+ |
|
* +------+ | +------+
|
||||||
* | Tile |<------+
|
* | | | | |
|
||||||
|
* | Grid | | | Grid |
|
||||||
|
* | | | | |
|
||||||
|
* +------+ | +------+
|
||||||
|
* | |
|
||||||
* +------+
|
* +------+
|
||||||
*
|
*
|
||||||
|
* Note that: this will only apply to the core grids!
|
||||||
|
* I/Os or any blocks on the border of fabric are NOT supported!
|
||||||
*
|
*
|
||||||
***************************************************************************************/
|
*******************************************************************/
|
||||||
static
|
static
|
||||||
void build_inter_column_row_tile_direct(TileDirect& tile_direct,
|
void build_inter_column_row_tile_direct(TileDirect& tile_direct,
|
||||||
t_direct_inf& vpr_direct,
|
const t_direct_inf& vpr_direct,
|
||||||
const DeviceContext& device_ctx,
|
const DeviceContext& device_ctx,
|
||||||
const ArchDirect& arch_direct,
|
const ArchDirect& arch_direct,
|
||||||
const ArchDirectId& arch_direct_id,
|
const ArchDirectId& arch_direct_id) {
|
||||||
const CircuitLibrary& circuit_lib) {
|
|
||||||
/* Get the source tile and pin information */
|
/* Get the source tile and pin information */
|
||||||
std::string from_tile_name = parse_direct_tile_name(std::string(vpr_direct.from_pin));
|
std::string from_tile_name = parse_direct_tile_name(std::string(vpr_direct.from_pin));
|
||||||
PortParser from_tile_port_parser(std::string(vpr_direct.from_pin));
|
PortParser from_tile_port_parser(std::string(vpr_direct.from_pin));
|
||||||
|
@ -265,23 +487,49 @@ void build_inter_column_row_tile_direct(TileDirect& tile_direct,
|
||||||
PortParser to_tile_port_parser(std::string(vpr_direct.to_pin));
|
PortParser to_tile_port_parser(std::string(vpr_direct.to_pin));
|
||||||
const BasicPort& to_tile_port = to_tile_port_parser.port();
|
const BasicPort& to_tile_port = to_tile_port_parser.port();
|
||||||
|
|
||||||
/* Walk through the device fabric and find the grid that fit the source */
|
/* Go through the direct connection list, see if we need intra-column/row connection here */
|
||||||
for (size_t x = 0; x < device_ctx.grid.width(); ++x) {
|
if ( (INTER_COLUMN != arch_direct.type(arch_direct_id))
|
||||||
for (size_t y = 0; y < device_ctx.grid.height(); ++y) {
|
&& (INTER_ROW != arch_direct.type(arch_direct_id))) {
|
||||||
/* Bypass empty grid */
|
return;
|
||||||
if (true == is_empty_type(device_ctx.grid[x][y].type)) {
|
}
|
||||||
continue;
|
/* For cross-column connection, we will search the first valid grid in each column
|
||||||
|
* from y = 1 to y = ny
|
||||||
|
*
|
||||||
|
* +------+
|
||||||
|
* | Grid | y=ny
|
||||||
|
* +------+
|
||||||
|
* ^
|
||||||
|
* | search direction (when y_dir is negative)
|
||||||
|
* ...
|
||||||
|
* |
|
||||||
|
* +------+
|
||||||
|
* | Grid | y=1
|
||||||
|
* +------+
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
if (INTER_COLUMN == arch_direct.type(arch_direct_id)) {
|
||||||
|
for (size_t ix = 1; ix < device_ctx.grid.width() - 1; ++ix) {
|
||||||
|
std::vector<vtr::Point<size_t>> next_col_src_grid_coords;
|
||||||
|
/* For negative y- direction, we should start from y = ny */
|
||||||
|
for (size_t iy = 1; iy < device_ctx.grid.height() - 1; ++iy) {
|
||||||
|
next_col_src_grid_coords.push_back(vtr::Point<size_t>(ix, iy));
|
||||||
|
}
|
||||||
|
/* For positive y- direction, we should start from y = 1 */
|
||||||
|
if (POSITIVE_DIR == arch_direct.y_dir(arch_direct_id)) {
|
||||||
|
std::reverse(next_col_src_grid_coords.begin(), next_col_src_grid_coords.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Bypass the grid that does not fit the from_tile name */
|
/* Bypass the grid that does not fit the from_tile name */
|
||||||
if (from_tile_name != std::string(device_ctx.grid[x][y].type->name)) {
|
vtr::Point<size_t> from_grid_coord = find_grid_coordinate_given_type(device_ctx.grid, next_col_src_grid_coords, from_tile_name);
|
||||||
|
/* Skip if we do not have a valid coordinate for source CLB/heterogeneous block */
|
||||||
|
if (false == is_grid_coordinate_exist_in_device(device_ctx.grid, from_grid_coord)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try to find the pin in this tile */
|
/* Try to find the pin in this tile */
|
||||||
std::vector<size_t> from_pins = find_physical_tile_pin_id(device_ctx.grid[x][y].type,
|
std::vector<size_t> from_pins = find_physical_tile_pin_id(device_ctx.grid[from_grid_coord.x()][from_grid_coord.y()].type,
|
||||||
device_ctx.grid[x][y].width_offset,
|
device_ctx.grid[from_grid_coord.x()][from_grid_coord.y()].width_offset,
|
||||||
device_ctx.grid[x][y].height_offset,
|
device_ctx.grid[from_grid_coord.x()][from_grid_coord.y()].height_offset,
|
||||||
from_tile_port,
|
from_tile_port,
|
||||||
vpr_direct.from_side);
|
vpr_direct.from_side);
|
||||||
/* If nothing found, we can continue */
|
/* If nothing found, we can continue */
|
||||||
|
@ -289,18 +537,13 @@ void build_inter_column_row_tile_direct(TileDirect& tile_direct,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We should try to the sink grid for inner-column/row direct connections */
|
/* For a valid coordinate, we can find the coordinate of the destination clb */
|
||||||
vtr::Point<size_t> from_grid_coord(x, y);
|
vtr::Point<size_t> to_grid_coord = find_inter_direct_destination_coordinate(device_ctx.grid, from_grid_coord, to_tile_name, arch_direct, arch_direct_id);
|
||||||
vtr::Point<size_t> to_grid_coord(x + vpr_direct.x_offset, y + vpr_direct.y_offset);
|
/* If destination clb is valid, we should add something */
|
||||||
if ((to_grid_coord.x() >= device_ctx.grid.width())
|
if (false == is_grid_coordinate_exist_in_device(device_ctx.grid, to_grid_coord)) {
|
||||||
|| (to_grid_coord.y() >= device_ctx.grid.height())) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Bypass the grid that does not fit the from_tile name */
|
|
||||||
if (to_tile_name != std::string(device_ctx.grid[to_grid_coord.x()][to_grid_coord.y()].type->name)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* Try to find the pin in this tile */
|
/* Try to find the pin in this tile */
|
||||||
std::vector<size_t> to_pins = find_physical_tile_pin_id(device_ctx.grid[to_grid_coord.x()][to_grid_coord.y()].type,
|
std::vector<size_t> to_pins = find_physical_tile_pin_id(device_ctx.grid[to_grid_coord.x()][to_grid_coord.y()].type,
|
||||||
device_ctx.grid[to_grid_coord.x()][to_grid_coord.y()].width_offset,
|
device_ctx.grid[to_grid_coord.x()][to_grid_coord.y()].width_offset,
|
||||||
|
@ -314,26 +557,88 @@ void build_inter_column_row_tile_direct(TileDirect& tile_direct,
|
||||||
|
|
||||||
/* If from port and to port do not match in sizes, error out */
|
/* If from port and to port do not match in sizes, error out */
|
||||||
if (from_pins.size() != to_pins.size()) {
|
if (from_pins.size() != to_pins.size()) {
|
||||||
VTR_LOG_ERROR("From_port '%s[%lu:%lu] of direct '%s' does not match to_port '%s[%lu:%lu]'!\n",
|
report_direct_from_port_and_to_port_mismatch(vpr_direct, from_tile_port, to_tile_port);
|
||||||
from_tile_port.get_name().c_str(),
|
|
||||||
from_tile_port.get_lsb(),
|
|
||||||
from_tile_port.get_msb(),
|
|
||||||
vpr_direct.name,
|
|
||||||
to_tile_port.get_name().c_str(),
|
|
||||||
to_tile_port.get_lsb(),
|
|
||||||
to_tile_port.get_msb());
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now add the tile direct */
|
/* Now add the tile direct */
|
||||||
for (size_t ipin = 0; ipin < from_pins.size(); ++ipin) {
|
for (size_t ipin = 0; ipin < from_pins.size(); ++ipin) {
|
||||||
TileDirectId tile_direct_id = tile_direct.add_direct(device_ctx.grid[x][y].type,
|
TileDirectId tile_direct_id = tile_direct.add_direct(from_grid_coord, vpr_direct.from_side, from_pins[ipin],
|
||||||
from_grid_coord, vpr_direct.from_side, from_pins[ipin],
|
|
||||||
device_ctx.grid[to_grid_coord.x()][to_grid_coord.y()].type,
|
|
||||||
to_grid_coord, vpr_direct.to_side, to_pins[ipin]);
|
to_grid_coord, vpr_direct.to_side, to_pins[ipin]);
|
||||||
tile_direct.set_arch_direct_id(tile_direct_id, arch_direct_id);
|
tile_direct.set_arch_direct_id(tile_direct_id, arch_direct_id);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return; /* Go to next direct type */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reach here, it must be a cross-row connection */
|
||||||
|
VTR_ASSERT(INTER_ROW == arch_direct.type(arch_direct_id));
|
||||||
|
/* For cross-row connection, we will search the first valid grid in each column
|
||||||
|
* from x = 1 to x = nx
|
||||||
|
*
|
||||||
|
* x=1 x=nx
|
||||||
|
* +------+ +------+
|
||||||
|
* | Grid | <--- ... ---- | Grid |
|
||||||
|
* +------+ +------+
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
for (size_t iy = 1; iy < device_ctx.grid.height() - 1; ++iy) {
|
||||||
|
std::vector<vtr::Point<size_t>> next_col_src_grid_coords;
|
||||||
|
/* For negative x- direction, we should start from x = nx */
|
||||||
|
for (size_t ix = 1; ix < device_ctx.grid.width() - 1; ++ix) {
|
||||||
|
next_col_src_grid_coords.push_back(vtr::Point<size_t>(ix, iy));
|
||||||
|
}
|
||||||
|
/* For positive x- direction, we should start from x = 1 */
|
||||||
|
if (POSITIVE_DIR == arch_direct.x_dir(arch_direct_id)) {
|
||||||
|
std::reverse(next_col_src_grid_coords.begin(), next_col_src_grid_coords.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
vtr::Point<size_t> from_grid_coord = find_grid_coordinate_given_type(device_ctx.grid, next_col_src_grid_coords, from_tile_name);
|
||||||
|
/* Skip if we do not have a valid coordinate for source CLB/heterogeneous block */
|
||||||
|
if (false == is_grid_coordinate_exist_in_device(device_ctx.grid, from_grid_coord)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try to find the pin in this tile */
|
||||||
|
std::vector<size_t> from_pins = find_physical_tile_pin_id(device_ctx.grid[from_grid_coord.x()][from_grid_coord.y()].type,
|
||||||
|
device_ctx.grid[from_grid_coord.x()][from_grid_coord.y()].width_offset,
|
||||||
|
device_ctx.grid[from_grid_coord.x()][from_grid_coord.y()].height_offset,
|
||||||
|
from_tile_port,
|
||||||
|
vpr_direct.from_side);
|
||||||
|
/* If nothing found, we can continue */
|
||||||
|
if (0 == from_pins.size()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For a valid coordinate, we can find the coordinate of the destination clb */
|
||||||
|
vtr::Point<size_t> to_grid_coord = find_inter_direct_destination_coordinate(device_ctx.grid, from_grid_coord, to_tile_name, arch_direct, arch_direct_id);
|
||||||
|
/* If destination clb is valid, we should add something */
|
||||||
|
if (false == is_grid_coordinate_exist_in_device(device_ctx.grid, to_grid_coord)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try to find the pin in this tile */
|
||||||
|
std::vector<size_t> to_pins = find_physical_tile_pin_id(device_ctx.grid[to_grid_coord.x()][to_grid_coord.y()].type,
|
||||||
|
device_ctx.grid[to_grid_coord.x()][to_grid_coord.y()].width_offset,
|
||||||
|
device_ctx.grid[to_grid_coord.x()][to_grid_coord.y()].height_offset,
|
||||||
|
to_tile_port,
|
||||||
|
vpr_direct.to_side);
|
||||||
|
/* If nothing found, we can continue */
|
||||||
|
if (0 == to_pins.size()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If from port and to port do not match in sizes, error out */
|
||||||
|
if (from_pins.size() != to_pins.size()) {
|
||||||
|
report_direct_from_port_and_to_port_mismatch(vpr_direct, from_tile_port, to_tile_port);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now add the tile direct */
|
||||||
|
for (size_t ipin = 0; ipin < from_pins.size(); ++ipin) {
|
||||||
|
TileDirectId tile_direct_id = tile_direct.add_direct(from_grid_coord, vpr_direct.from_side, from_pins[ipin],
|
||||||
|
to_grid_coord, vpr_direct.to_side, to_pins[ipin]);
|
||||||
|
tile_direct.set_arch_direct_id(tile_direct_id, arch_direct_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -343,8 +648,7 @@ void build_inter_column_row_tile_direct(TileDirect& tile_direct,
|
||||||
* between tiles (programmable blocks)
|
* between tiles (programmable blocks)
|
||||||
***************************************************************************************/
|
***************************************************************************************/
|
||||||
TileDirect build_device_tile_direct(const DeviceContext& device_ctx,
|
TileDirect build_device_tile_direct(const DeviceContext& device_ctx,
|
||||||
const ArchDirect& arch_direct,
|
const ArchDirect& arch_direct) {
|
||||||
const CircuitLibrary& circuit_lib) {
|
|
||||||
vtr::ScopedStartFinishTimer timer("Build the annotation about direct connection between tiles");
|
vtr::ScopedStartFinishTimer timer("Build the annotation about direct connection between tiles");
|
||||||
|
|
||||||
TileDirect tile_direct;
|
TileDirect tile_direct;
|
||||||
|
@ -358,7 +662,12 @@ TileDirect build_device_tile_direct(const DeviceContext& device_ctx,
|
||||||
device_ctx.arch->Directs[idirect],
|
device_ctx.arch->Directs[idirect],
|
||||||
device_ctx,
|
device_ctx,
|
||||||
arch_direct_id);
|
arch_direct_id);
|
||||||
/* TODO: Build from OpenFPGA arch definition */
|
/* Build from OpenFPGA arch definition */
|
||||||
|
build_inter_column_row_tile_direct(tile_direct,
|
||||||
|
device_ctx.arch->Directs[idirect],
|
||||||
|
device_ctx,
|
||||||
|
arch_direct,
|
||||||
|
arch_direct_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return tile_direct;
|
return tile_direct;
|
||||||
|
|
|
@ -17,8 +17,7 @@
|
||||||
namespace openfpga {
|
namespace openfpga {
|
||||||
|
|
||||||
TileDirect build_device_tile_direct(const DeviceContext& device_ctx,
|
TileDirect build_device_tile_direct(const DeviceContext& device_ctx,
|
||||||
const ArchDirect& arch_direct,
|
const ArchDirect& arch_direct);
|
||||||
const CircuitLibrary& circuit_lib);
|
|
||||||
|
|
||||||
} /* end namespace openfpga */
|
} /* end namespace openfpga */
|
||||||
|
|
||||||
|
|
|
@ -15,12 +15,6 @@ TileDirect::tile_direct_range TileDirect::directs() const {
|
||||||
return vtr::make_range(direct_ids_.begin(), direct_ids_.end());
|
return vtr::make_range(direct_ids_.begin(), direct_ids_.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
t_physical_tile_type_ptr TileDirect::from_tile(const TileDirectId& direct_id) const {
|
|
||||||
/* Validate the direct_id */
|
|
||||||
VTR_ASSERT(valid_direct_id(direct_id));
|
|
||||||
return from_tiles_[direct_id];
|
|
||||||
}
|
|
||||||
|
|
||||||
vtr::Point<size_t> TileDirect::from_tile_coordinate(const TileDirectId& direct_id) const {
|
vtr::Point<size_t> TileDirect::from_tile_coordinate(const TileDirectId& direct_id) const {
|
||||||
/* Validate the direct_id */
|
/* Validate the direct_id */
|
||||||
VTR_ASSERT(valid_direct_id(direct_id));
|
VTR_ASSERT(valid_direct_id(direct_id));
|
||||||
|
@ -39,12 +33,6 @@ e_side TileDirect::from_tile_side(const TileDirectId& direct_id) const {
|
||||||
return from_tile_sides_[direct_id];
|
return from_tile_sides_[direct_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
t_physical_tile_type_ptr TileDirect::to_tile(const TileDirectId& direct_id) const {
|
|
||||||
/* Validate the direct_id */
|
|
||||||
VTR_ASSERT(valid_direct_id(direct_id));
|
|
||||||
return to_tiles_[direct_id];
|
|
||||||
}
|
|
||||||
|
|
||||||
vtr::Point<size_t> TileDirect::to_tile_coordinate(const TileDirectId& direct_id) const {
|
vtr::Point<size_t> TileDirect::to_tile_coordinate(const TileDirectId& direct_id) const {
|
||||||
/* Validate the direct_id */
|
/* Validate the direct_id */
|
||||||
VTR_ASSERT(valid_direct_id(direct_id));
|
VTR_ASSERT(valid_direct_id(direct_id));
|
||||||
|
@ -72,11 +60,9 @@ ArchDirectId TileDirect::arch_direct(const TileDirectId& direct_id) const {
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Private Mutators
|
* Private Mutators
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
TileDirectId TileDirect::add_direct(t_physical_tile_type_ptr from_tile,
|
TileDirectId TileDirect::add_direct(const vtr::Point<size_t>& from_tile_coord,
|
||||||
const vtr::Point<size_t>& from_tile_coord,
|
|
||||||
const e_side& from_tile_side,
|
const e_side& from_tile_side,
|
||||||
const size_t& from_tile_pin,
|
const size_t& from_tile_pin,
|
||||||
t_physical_tile_type_ptr to_tile,
|
|
||||||
const vtr::Point<size_t>& to_tile_coord,
|
const vtr::Point<size_t>& to_tile_coord,
|
||||||
const e_side& to_tile_side,
|
const e_side& to_tile_side,
|
||||||
const size_t& to_tile_pin) {
|
const size_t& to_tile_pin) {
|
||||||
|
@ -85,12 +71,10 @@ TileDirectId TileDirect::add_direct(t_physical_tile_type_ptr from_tile,
|
||||||
direct_ids_.push_back(direct);
|
direct_ids_.push_back(direct);
|
||||||
|
|
||||||
/* Allocate other attributes */
|
/* Allocate other attributes */
|
||||||
from_tiles_.push_back(from_tile);
|
|
||||||
from_tile_coords_.push_back(from_tile_coord);
|
from_tile_coords_.push_back(from_tile_coord);
|
||||||
from_tile_sides_.push_back(from_tile_side);
|
from_tile_sides_.push_back(from_tile_side);
|
||||||
from_tile_pins_.push_back(from_tile_pin);
|
from_tile_pins_.push_back(from_tile_pin);
|
||||||
|
|
||||||
to_tiles_.push_back(to_tile);
|
|
||||||
to_tile_coords_.push_back(to_tile_coord);
|
to_tile_coords_.push_back(to_tile_coord);
|
||||||
to_tile_sides_.push_back(to_tile_side);
|
to_tile_sides_.push_back(to_tile_side);
|
||||||
to_tile_pins_.push_back(to_tile_pin);
|
to_tile_pins_.push_back(to_tile_pin);
|
||||||
|
|
|
@ -33,21 +33,17 @@ class TileDirect {
|
||||||
typedef vtr::Range<tile_direct_iterator> tile_direct_range;
|
typedef vtr::Range<tile_direct_iterator> tile_direct_range;
|
||||||
public: /* Public aggregators */
|
public: /* Public aggregators */
|
||||||
tile_direct_range directs() const;
|
tile_direct_range directs() const;
|
||||||
t_physical_tile_type_ptr from_tile(const TileDirectId& direct_id) const;
|
|
||||||
vtr::Point<size_t> from_tile_coordinate(const TileDirectId& direct_id) const;
|
vtr::Point<size_t> from_tile_coordinate(const TileDirectId& direct_id) const;
|
||||||
e_side from_tile_side(const TileDirectId& direct_id) const;
|
e_side from_tile_side(const TileDirectId& direct_id) const;
|
||||||
size_t from_tile_pin(const TileDirectId& direct_id) const;
|
size_t from_tile_pin(const TileDirectId& direct_id) const;
|
||||||
t_physical_tile_type_ptr to_tile(const TileDirectId& direct_id) const;
|
|
||||||
vtr::Point<size_t> to_tile_coordinate(const TileDirectId& direct_id) const;
|
vtr::Point<size_t> to_tile_coordinate(const TileDirectId& direct_id) const;
|
||||||
e_side to_tile_side(const TileDirectId& direct_id) const;
|
e_side to_tile_side(const TileDirectId& direct_id) const;
|
||||||
size_t to_tile_pin(const TileDirectId& direct_id) const;
|
size_t to_tile_pin(const TileDirectId& direct_id) const;
|
||||||
ArchDirectId arch_direct(const TileDirectId& direct_id) const;
|
ArchDirectId arch_direct(const TileDirectId& direct_id) const;
|
||||||
public: /* Public mutators */
|
public: /* Public mutators */
|
||||||
TileDirectId add_direct(t_physical_tile_type_ptr from_tile,
|
TileDirectId add_direct(const vtr::Point<size_t>& from_tile_coord,
|
||||||
const vtr::Point<size_t>& from_tile_coord,
|
|
||||||
const e_side& from_tile_side,
|
const e_side& from_tile_side,
|
||||||
const size_t& from_tile_pin,
|
const size_t& from_tile_pin,
|
||||||
t_physical_tile_type_ptr to_tile,
|
|
||||||
const vtr::Point<size_t>& to_tile_coord,
|
const vtr::Point<size_t>& to_tile_coord,
|
||||||
const e_side& to_tile_side,
|
const e_side& to_tile_side,
|
||||||
const size_t& to_tile_pin);
|
const size_t& to_tile_pin);
|
||||||
|
@ -63,7 +59,6 @@ class TileDirect {
|
||||||
* - tile coordinate
|
* - tile coordinate
|
||||||
* - tile pin id
|
* - tile pin id
|
||||||
*/
|
*/
|
||||||
vtr::vector<TileDirectId, t_physical_tile_type_ptr> from_tiles_;
|
|
||||||
vtr::vector<TileDirectId, vtr::Point<size_t>> from_tile_coords_;
|
vtr::vector<TileDirectId, vtr::Point<size_t>> from_tile_coords_;
|
||||||
vtr::vector<TileDirectId, e_side> from_tile_sides_;
|
vtr::vector<TileDirectId, e_side> from_tile_sides_;
|
||||||
vtr::vector<TileDirectId, size_t> from_tile_pins_;
|
vtr::vector<TileDirectId, size_t> from_tile_pins_;
|
||||||
|
@ -73,7 +68,6 @@ class TileDirect {
|
||||||
* - tile coordinate
|
* - tile coordinate
|
||||||
* - tile pin id
|
* - tile pin id
|
||||||
*/
|
*/
|
||||||
vtr::vector<TileDirectId, t_physical_tile_type_ptr> to_tiles_;
|
|
||||||
vtr::vector<TileDirectId, vtr::Point<size_t>> to_tile_coords_;
|
vtr::vector<TileDirectId, vtr::Point<size_t>> to_tile_coords_;
|
||||||
vtr::vector<TileDirectId, e_side> to_tile_sides_;
|
vtr::vector<TileDirectId, e_side> to_tile_sides_;
|
||||||
vtr::vector<TileDirectId, size_t> to_tile_pins_;
|
vtr::vector<TileDirectId, size_t> to_tile_pins_;
|
||||||
|
|
Loading…
Reference in New Issue