[core] move child instance builder to a separated source file as these codes are expanding in size
This commit is contained in:
parent
bd265334b5
commit
6458580e3e
|
@ -16,6 +16,7 @@
|
|||
/* Headers from openfpgashell library */
|
||||
#include "build_module_graph_utils.h"
|
||||
#include "build_top_module.h"
|
||||
#include "build_top_module_child_instance.h"
|
||||
#include "build_top_module_connection.h"
|
||||
#include "build_top_module_directs.h"
|
||||
#include "build_top_module_memory.h"
|
||||
|
@ -32,637 +33,6 @@
|
|||
/* 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, false);
|
||||
/* 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) {
|
||||
vtr::ScopedStartFinishTimer timer("Add grid instances to top module");
|
||||
|
||||
/* 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 I/O grids */
|
||||
/* Create the coordinate range for each side of FPGA fabric */
|
||||
std::map<e_side, std::vector<vtr::Point<size_t>>> io_coordinates =
|
||||
generate_perimeter_grid_coordinates(grids);
|
||||
|
||||
for (const e_side& io_side : FPGA_SIDES_CLOCKWISE) {
|
||||
for (const vtr::Point<size_t>& io_coordinate : io_coordinates[io_side]) {
|
||||
t_physical_tile_type_ptr phy_tile_type =
|
||||
grids.get_physical_type(io_coordinate.x(), io_coordinate.y());
|
||||
/* Bypass EMPTY grid */
|
||||
if (true == is_empty_type(phy_tile_type)) {
|
||||
continue;
|
||||
}
|
||||
/* Skip width, height > 1 tiles (mostly heterogeneous blocks) */
|
||||
if ((0 < grids.get_width_offset(io_coordinate.x(), io_coordinate.y())) ||
|
||||
(0 < grids.get_height_offset(io_coordinate.x(), io_coordinate.y()))) {
|
||||
/* Find the root of this grid, the instance id should be valid.
|
||||
* We just copy it here
|
||||
*/
|
||||
vtr::Point<size_t> root_grid_coord(
|
||||
io_coordinate.x() -
|
||||
grids.get_width_offset(io_coordinate.x(), io_coordinate.y()),
|
||||
io_coordinate.y() -
|
||||
grids.get_height_offset(io_coordinate.x(), io_coordinate.y()));
|
||||
VTR_ASSERT(size_t(-1) !=
|
||||
grid_instance_ids[root_grid_coord.x()][root_grid_coord.y()]);
|
||||
grid_instance_ids[io_coordinate.x()][io_coordinate.y()] =
|
||||
grid_instance_ids[root_grid_coord.x()][root_grid_coord.y()];
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 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, phy_tile_type,
|
||||
io_side, io_coordinate);
|
||||
}
|
||||
}
|
||||
|
||||
/* Instanciate core grids
|
||||
* IMPORTANT: sequence matters here, it impacts the I/O indexing.
|
||||
* We should follow the same sequence as the build_io_location_map()!
|
||||
* If you change the sequence of walking through grids here, you should change
|
||||
* it in the build_io_location map()!
|
||||
*/
|
||||
for (size_t ix = 1; ix < grids.width() - 1; ++ix) {
|
||||
for (size_t iy = 1; iy < grids.height() - 1; ++iy) {
|
||||
t_physical_tile_type_ptr phy_tile_type = grids.get_physical_type(ix, iy);
|
||||
/* Bypass EMPTY grid */
|
||||
if (true == is_empty_type(phy_tile_type)) {
|
||||
continue;
|
||||
}
|
||||
/* Skip width or height > 1 tiles (mostly heterogeneous blocks) */
|
||||
if ((0 < grids.get_width_offset(ix, iy)) ||
|
||||
(0 < grids.get_height_offset(ix, iy))) {
|
||||
/* Find the root of this grid, the instance id should be valid.
|
||||
* We just copy it here
|
||||
*/
|
||||
vtr::Point<size_t> root_grid_coord(
|
||||
ix - grids.get_width_offset(ix, iy),
|
||||
iy - grids.get_height_offset(ix, iy));
|
||||
VTR_ASSERT(size_t(-1) !=
|
||||
grid_instance_ids[root_grid_coord.x()][root_grid_coord.y()]);
|
||||
grid_instance_ids[ix][iy] =
|
||||
grid_instance_ids[root_grid_coord.x()][root_grid_coord.y()];
|
||||
continue;
|
||||
}
|
||||
/* 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, phy_tile_type, NUM_SIDES, grid_coord);
|
||||
}
|
||||
}
|
||||
|
||||
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::ScopedStartFinishTimer timer("Add switch block instances to top module");
|
||||
|
||||
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, false);
|
||||
/* 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::ScopedStartFinishTimer timer(
|
||||
"Add connection block instances to top module");
|
||||
|
||||
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, false);
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Add the I/O children to the top-level module, which impacts the I/O indexing
|
||||
* This is the default function to build the I/O sequence/indexing
|
||||
* The I/O children is added in a maze shape
|
||||
* The function supports I/Os in the center of grids, starting from the
|
||||
*bottom-left corner and ending at the center
|
||||
*
|
||||
* +----------------------+
|
||||
* |+--------------------+|
|
||||
* ||+------------------+||
|
||||
* |||+----------------+|||
|
||||
* ||||+-------------->||||
|
||||
* ||||+---------------+|||
|
||||
* |||+-----------------+||
|
||||
* ||+-------------------+|
|
||||
* |+---------------------+
|
||||
* ^
|
||||
* io[0]
|
||||
*******************************************************************/
|
||||
static void add_top_module_io_children(
|
||||
ModuleManager& module_manager, const ModuleId& top_module,
|
||||
const DeviceGrid& grids, const vtr::Matrix<size_t>& grid_instance_ids) {
|
||||
/* Create the coordinate range for the perimeter I/Os of FPGA fabric */
|
||||
std::map<e_side, std::vector<vtr::Point<size_t>>> io_coordinates =
|
||||
generate_perimeter_grid_coordinates(grids);
|
||||
|
||||
for (const e_side& io_side : FPGA_SIDES_CLOCKWISE) {
|
||||
for (const vtr::Point<size_t>& io_coord : io_coordinates[io_side]) {
|
||||
t_physical_tile_type_ptr grid_type =
|
||||
grids.get_physical_type(io_coord.x(), io_coord.y());
|
||||
/* Bypass EMPTY grid */
|
||||
if (true == is_empty_type(grid_type)) {
|
||||
continue;
|
||||
}
|
||||
/* Skip width, height > 1 tiles (mostly heterogeneous blocks) */
|
||||
if ((0 < grids.get_width_offset(io_coord.x(), io_coord.y())) ||
|
||||
(0 < grids.get_height_offset(io_coord.x(), io_coord.y()))) {
|
||||
continue;
|
||||
}
|
||||
/* 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), io_side);
|
||||
ModuleId grid_module = module_manager.find_module(grid_module_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(grid_module));
|
||||
/* Add a I/O children to top_module*/
|
||||
module_manager.add_io_child(top_module, grid_module,
|
||||
grid_instance_ids[io_coord.x()][io_coord.y()],
|
||||
vtr::Point<int>(io_coord.x(), io_coord.y()));
|
||||
}
|
||||
}
|
||||
|
||||
/* Walk through the center grids */
|
||||
size_t xmin = 1;
|
||||
size_t xmax = grids.width() - 2;
|
||||
size_t ymin = 1;
|
||||
size_t ymax = grids.height() - 2;
|
||||
std::vector<vtr::Point<size_t>> coords;
|
||||
while (xmin < xmax && ymin < ymax) {
|
||||
for (size_t iy = ymin; iy < ymax + 1; iy++) {
|
||||
coords.push_back(vtr::Point<size_t>(xmin, iy));
|
||||
}
|
||||
for (size_t ix = xmin + 1; ix < xmax + 1; ix++) {
|
||||
coords.push_back(vtr::Point<size_t>(ix, ymax));
|
||||
}
|
||||
for (size_t iy = ymax - 1; iy > ymin; iy--) {
|
||||
coords.push_back(vtr::Point<size_t>(xmax, iy));
|
||||
}
|
||||
for (size_t ix = xmax; ix > xmin; ix--) {
|
||||
coords.push_back(vtr::Point<size_t>(ix, ymin));
|
||||
}
|
||||
xmin++;
|
||||
ymin++;
|
||||
xmax--;
|
||||
ymax--;
|
||||
}
|
||||
|
||||
/* If height is odd, add the missing horizental line */
|
||||
if ((grids.height() - 2) % 2 == 1) {
|
||||
if (ymin == ymax) {
|
||||
for (size_t ix = xmin; ix < xmax + 1; ix++) {
|
||||
coords.push_back(vtr::Point<size_t>(ix, ymin));
|
||||
}
|
||||
}
|
||||
}
|
||||
/* If width is odd, add the missing vertical line */
|
||||
if ((grids.width() - 2) % 2 == 1) {
|
||||
if (xmin == xmax) {
|
||||
for (size_t iy = ymin; iy < ymax + 1; iy++) {
|
||||
coords.push_back(vtr::Point<size_t>(xmin, iy));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Now walk through the coordinates */
|
||||
for (vtr::Point<size_t> coord : coords) {
|
||||
t_physical_tile_type_ptr grid_type =
|
||||
grids.get_physical_type(coord.x(), coord.y());
|
||||
/* Bypass EMPTY grid */
|
||||
if (true == is_empty_type(grid_type)) {
|
||||
continue;
|
||||
}
|
||||
/* Skip width or height > 1 tiles (mostly heterogeneous blocks) */
|
||||
if ((0 < grids.get_width_offset(coord.x(), coord.y())) ||
|
||||
(0 < grids.get_height_offset(coord.x(), coord.y()))) {
|
||||
continue;
|
||||
}
|
||||
/* 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), NUM_SIDES);
|
||||
ModuleId grid_module = module_manager.find_module(grid_module_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(grid_module));
|
||||
/* Add a I/O children to top_module*/
|
||||
module_manager.add_io_child(top_module, grid_module,
|
||||
grid_instance_ids[coord.x()][coord.y()],
|
||||
vtr::Point<int>(coord.x(), coord.y()));
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Add the fine-grained instances to the top module of FPGA fabric
|
||||
* The fine-grained instances include programmable blocks, connection blocks and
|
||||
*switch blocks, each of which is an instance under the top module
|
||||
*******************************************************************/
|
||||
static int build_top_module_fine_grained_child_instances(
|
||||
ModuleManager& module_manager, const ModuleId& top_module,
|
||||
MemoryBankShiftRegisterBanks& blwl_sr_banks,
|
||||
const CircuitLibrary& circuit_lib, const ClockNetwork& clk_ntwk,
|
||||
const RRClockSpatialLookup& rr_clock_lookup,
|
||||
const VprDeviceAnnotation& vpr_device_annotation, const DeviceGrid& grids,
|
||||
const TileAnnotation& tile_annotation, const RRGraphView& rr_graph,
|
||||
const DeviceRRGSB& device_rr_gsb, const TileDirect& tile_direct,
|
||||
const ArchDirect& arch_direct, const ConfigProtocol& config_protocol,
|
||||
const CircuitModelId& sram_model, const bool& frame_view,
|
||||
const bool& compact_routing_hierarchy, const bool& duplicate_grid_pin,
|
||||
const FabricKey& fabric_key) {
|
||||
int status = CMD_EXEC_SUCCESS;
|
||||
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);
|
||||
|
||||
/* Update I/O children list */
|
||||
add_top_module_io_children(module_manager, top_module, grids,
|
||||
grid_instance_ids);
|
||||
|
||||
/* Add nets when we need a complete fabric modeling,
|
||||
* which is required by downstream functions
|
||||
*/
|
||||
if (false == frame_view) {
|
||||
/* Reserve nets to be memory efficient */
|
||||
reserve_module_manager_module_nets(module_manager, top_module);
|
||||
|
||||
/* Add module nets to connect the sub modules */
|
||||
add_top_module_nets_connect_grids_and_gsbs(
|
||||
module_manager, top_module, vpr_device_annotation, 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, vpr_device_annotation, grids,
|
||||
grid_instance_ids, tile_direct, arch_direct);
|
||||
}
|
||||
|
||||
/* Add global ports from grid ports that are defined as global in tile
|
||||
* annotation */
|
||||
status = add_top_module_global_ports_from_grid_modules(
|
||||
module_manager, top_module, tile_annotation, vpr_device_annotation, grids,
|
||||
rr_graph, device_rr_gsb, cb_instance_ids, grid_instance_ids, clk_ntwk,
|
||||
rr_clock_lookup);
|
||||
if (CMD_EXEC_FATAL_ERROR == status) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Add GPIO ports from the sub-modules under this Verilog module
|
||||
* For top-level module, we follow a special sequencing for I/O modules. So we
|
||||
* rebuild the I/O children list here
|
||||
*/
|
||||
add_module_gpio_ports_from_child_modules(module_manager, top_module);
|
||||
|
||||
/* Organize the list of memory modules and instances
|
||||
* If we have an empty fabric key, we organize the memory modules as routine
|
||||
* Otherwise, we will load the fabric key directly
|
||||
*/
|
||||
if (true == fabric_key.empty()) {
|
||||
organize_top_module_memory_modules(
|
||||
module_manager, top_module, circuit_lib, config_protocol, sram_model,
|
||||
grids, grid_instance_ids, device_rr_gsb, sb_instance_ids, cb_instance_ids,
|
||||
compact_routing_hierarchy);
|
||||
} else {
|
||||
VTR_ASSERT_SAFE(false == fabric_key.empty());
|
||||
/* Throw a fatal error when the fabric key has a mismatch in region
|
||||
* organization. between architecture file and fabric key
|
||||
*/
|
||||
if (size_t(config_protocol.num_regions()) != fabric_key.regions().size()) {
|
||||
VTR_LOG_ERROR(
|
||||
"Fabric key has a different number of configurable regions (='%ld') "
|
||||
"than architecture definition (=%d)!\n",
|
||||
fabric_key.regions().size(), config_protocol.num_regions());
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
|
||||
status = load_top_module_memory_modules_from_fabric_key(
|
||||
module_manager, top_module, circuit_lib, config_protocol, fabric_key);
|
||||
if (CMD_EXEC_FATAL_ERROR == status) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = load_top_module_shift_register_banks_from_fabric_key(
|
||||
fabric_key, blwl_sr_banks);
|
||||
if (CMD_EXEC_FATAL_ERROR == status) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Update the memory organization in sub module (non-top) */
|
||||
status = load_submodules_memory_modules_from_fabric_key(
|
||||
module_manager, circuit_lib, config_protocol, fabric_key);
|
||||
if (CMD_EXEC_FATAL_ERROR == status) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
return CMD_EXEC_SUCCESS;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Add a instance of a tile module to the top module
|
||||
*******************************************************************/
|
||||
static size_t add_top_module_tile_instance(ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const FabricTile& fabric_tile,
|
||||
const FabricTileId& fabric_tile_id) {
|
||||
/* Find the module name for this type of grid */
|
||||
vtr::Point<size_t> tile_coord = fabric_tile.tile_coordinate(fabric_tile_id);
|
||||
FabricTileId unique_fabric_tile_id = fabric_tile.unique_tile(tile_coord);
|
||||
vtr::Point<size_t> unique_tile_coord =
|
||||
fabric_tile.tile_coordinate(unique_fabric_tile_id);
|
||||
std::string tile_module_name = generate_tile_module_name(unique_tile_coord);
|
||||
ModuleId tile_module = module_manager.find_module(tile_module_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(tile_module));
|
||||
/* Record the instance id */
|
||||
size_t tile_instance = module_manager.num_instance(top_module, tile_module);
|
||||
/* Add the module to top_module */
|
||||
module_manager.add_child_module(top_module, tile_module, false);
|
||||
/* Set an unique name to the instance
|
||||
* Note: it is your risk to gurantee the name is unique!
|
||||
*/
|
||||
std::string instance_name = generate_tile_module_name(tile_coord);
|
||||
module_manager.set_child_instance_name(top_module, tile_module, tile_instance,
|
||||
instance_name);
|
||||
return tile_instance;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Add all the tiles as sub-modules across the fabric
|
||||
* Here, we will iterate over the full fabric (coordinates)
|
||||
* and instanciate the tile 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 tiles |
|
||||
* | TOP side |
|
||||
* +-----------------------------------+
|
||||
*
|
||||
* +-----------+ +-----------------------------------+ +------------+
|
||||
* | | | | | |
|
||||
* | I/O tiles | | Core tiles | | I/O tiles |
|
||||
* | LEFT side | | (CLB, Heterogeneous blocks, etc.) | | RIGHT side |
|
||||
* | | | | | |
|
||||
* +-----------+ +-----------------------------------+ +------------+
|
||||
*
|
||||
* +-----------------------------------+
|
||||
* | I/O tiles |
|
||||
* | BOTTOM side |
|
||||
* +-----------------------------------+
|
||||
*
|
||||
*******************************************************************/
|
||||
static int add_top_module_tile_instances(ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
vtr::Matrix<size_t>& tile_instance_ids,
|
||||
const DeviceGrid& grids,
|
||||
const FabricTile& fabric_tile) {
|
||||
vtr::ScopedStartFinishTimer timer("Add tile instances to top module");
|
||||
int status = CMD_EXEC_SUCCESS;
|
||||
|
||||
/* Reserve an array for the instance ids */
|
||||
tile_instance_ids.resize({grids.width(), grids.height()});
|
||||
tile_instance_ids.fill(size_t(-1));
|
||||
|
||||
/* Instanciate I/O grids */
|
||||
/* Create the coordinate range for each side of FPGA fabric */
|
||||
std::map<e_side, std::vector<vtr::Point<size_t>>> io_coordinates =
|
||||
generate_perimeter_tile_coordinates(grids);
|
||||
|
||||
for (const e_side& io_side : FPGA_SIDES_CLOCKWISE) {
|
||||
for (const vtr::Point<size_t>& io_coord : io_coordinates[io_side]) {
|
||||
FabricTileId fabric_tile_id = fabric_tile.find_tile(io_coord);
|
||||
if (!fabric_tile.valid_tile_id(fabric_tile_id)) {
|
||||
continue;
|
||||
}
|
||||
/* Add a tile module to top_module*/
|
||||
tile_instance_ids[io_coord.x()][io_coord.y()] =
|
||||
add_top_module_tile_instance(module_manager, top_module, fabric_tile,
|
||||
fabric_tile_id);
|
||||
}
|
||||
}
|
||||
|
||||
/* Instanciate core grids
|
||||
* IMPORTANT: sequence matters here, it impacts the I/O indexing.
|
||||
* We should follow the same sequence as the build_io_location_map()!
|
||||
* If you change the sequence of walking through grids here, you should change
|
||||
* it in the build_io_location map()!
|
||||
*/
|
||||
for (size_t ix = 1; ix < grids.width() - 1; ++ix) {
|
||||
for (size_t iy = 1; iy < grids.height() - 1; ++iy) {
|
||||
vtr::Point<size_t> curr_coord(ix, iy);
|
||||
FabricTileId fabric_tile_id = fabric_tile.find_tile(curr_coord);
|
||||
if (!fabric_tile.valid_tile_id(fabric_tile_id)) {
|
||||
continue;
|
||||
}
|
||||
/* Add a tile module to top_module*/
|
||||
tile_instance_ids[curr_coord.x()][curr_coord.y()] =
|
||||
add_top_module_tile_instance(module_manager, top_module, fabric_tile,
|
||||
fabric_tile_id);
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Add the tile-level instances to the top module of FPGA fabric
|
||||
* and build connects between them
|
||||
*******************************************************************/
|
||||
static int build_top_module_tile_child_instances(
|
||||
ModuleManager& module_manager, const ModuleId& top_module,
|
||||
const DeviceGrid& grids, const FabricTile& fabric_tile) {
|
||||
int status = CMD_EXEC_SUCCESS;
|
||||
vtr::Matrix<size_t> tile_instance_ids;
|
||||
status = add_top_module_tile_instances(module_manager, top_module,
|
||||
tile_instance_ids, grids, fabric_tile);
|
||||
if (status != CMD_EXEC_SUCCESS) {
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
return CMD_EXEC_SUCCESS;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Print the top-level module for the FPGA fabric in Verilog format
|
||||
* This function will
|
||||
|
|
|
@ -0,0 +1,666 @@
|
|||
/********************************************************************
|
||||
* This file includes functions that are used to print the top-level
|
||||
* module for the FPGA fabric in Verilog format
|
||||
*******************************************************************/
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
|
||||
/* Headers from vtrutil library */
|
||||
#include "vtr_assert.h"
|
||||
#include "vtr_log.h"
|
||||
#include "vtr_time.h"
|
||||
|
||||
/* Headers from vpr library */
|
||||
#include "vpr_utils.h"
|
||||
|
||||
/* Headers from openfpgashell library */
|
||||
#include "build_module_graph_utils.h"
|
||||
#include "build_top_module_child_instance.h"
|
||||
#include "build_top_module_connection.h"
|
||||
#include "build_top_module_directs.h"
|
||||
#include "build_top_module_memory.h"
|
||||
#include "build_top_module_memory_bank.h"
|
||||
#include "build_top_module_utils.h"
|
||||
#include "command_exit_codes.h"
|
||||
#include "module_manager_memory_utils.h"
|
||||
#include "module_manager_utils.h"
|
||||
#include "openfpga_device_grid_utils.h"
|
||||
#include "openfpga_naming.h"
|
||||
#include "openfpga_reserved_words.h"
|
||||
#include "rr_gsb_utils.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, false);
|
||||
/* 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) {
|
||||
vtr::ScopedStartFinishTimer timer("Add grid instances to top module");
|
||||
|
||||
/* 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 I/O grids */
|
||||
/* Create the coordinate range for each side of FPGA fabric */
|
||||
std::map<e_side, std::vector<vtr::Point<size_t>>> io_coordinates =
|
||||
generate_perimeter_grid_coordinates(grids);
|
||||
|
||||
for (const e_side& io_side : FPGA_SIDES_CLOCKWISE) {
|
||||
for (const vtr::Point<size_t>& io_coordinate : io_coordinates[io_side]) {
|
||||
t_physical_tile_type_ptr phy_tile_type =
|
||||
grids.get_physical_type(io_coordinate.x(), io_coordinate.y());
|
||||
/* Bypass EMPTY grid */
|
||||
if (true == is_empty_type(phy_tile_type)) {
|
||||
continue;
|
||||
}
|
||||
/* Skip width, height > 1 tiles (mostly heterogeneous blocks) */
|
||||
if ((0 < grids.get_width_offset(io_coordinate.x(), io_coordinate.y())) ||
|
||||
(0 < grids.get_height_offset(io_coordinate.x(), io_coordinate.y()))) {
|
||||
/* Find the root of this grid, the instance id should be valid.
|
||||
* We just copy it here
|
||||
*/
|
||||
vtr::Point<size_t> root_grid_coord(
|
||||
io_coordinate.x() -
|
||||
grids.get_width_offset(io_coordinate.x(), io_coordinate.y()),
|
||||
io_coordinate.y() -
|
||||
grids.get_height_offset(io_coordinate.x(), io_coordinate.y()));
|
||||
VTR_ASSERT(size_t(-1) !=
|
||||
grid_instance_ids[root_grid_coord.x()][root_grid_coord.y()]);
|
||||
grid_instance_ids[io_coordinate.x()][io_coordinate.y()] =
|
||||
grid_instance_ids[root_grid_coord.x()][root_grid_coord.y()];
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 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, phy_tile_type,
|
||||
io_side, io_coordinate);
|
||||
}
|
||||
}
|
||||
|
||||
/* Instanciate core grids
|
||||
* IMPORTANT: sequence matters here, it impacts the I/O indexing.
|
||||
* We should follow the same sequence as the build_io_location_map()!
|
||||
* If you change the sequence of walking through grids here, you should change
|
||||
* it in the build_io_location map()!
|
||||
*/
|
||||
for (size_t ix = 1; ix < grids.width() - 1; ++ix) {
|
||||
for (size_t iy = 1; iy < grids.height() - 1; ++iy) {
|
||||
t_physical_tile_type_ptr phy_tile_type = grids.get_physical_type(ix, iy);
|
||||
/* Bypass EMPTY grid */
|
||||
if (true == is_empty_type(phy_tile_type)) {
|
||||
continue;
|
||||
}
|
||||
/* Skip width or height > 1 tiles (mostly heterogeneous blocks) */
|
||||
if ((0 < grids.get_width_offset(ix, iy)) ||
|
||||
(0 < grids.get_height_offset(ix, iy))) {
|
||||
/* Find the root of this grid, the instance id should be valid.
|
||||
* We just copy it here
|
||||
*/
|
||||
vtr::Point<size_t> root_grid_coord(
|
||||
ix - grids.get_width_offset(ix, iy),
|
||||
iy - grids.get_height_offset(ix, iy));
|
||||
VTR_ASSERT(size_t(-1) !=
|
||||
grid_instance_ids[root_grid_coord.x()][root_grid_coord.y()]);
|
||||
grid_instance_ids[ix][iy] =
|
||||
grid_instance_ids[root_grid_coord.x()][root_grid_coord.y()];
|
||||
continue;
|
||||
}
|
||||
/* 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, phy_tile_type, NUM_SIDES, grid_coord);
|
||||
}
|
||||
}
|
||||
|
||||
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::ScopedStartFinishTimer timer("Add switch block instances to top module");
|
||||
|
||||
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, false);
|
||||
/* 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::ScopedStartFinishTimer timer(
|
||||
"Add connection block instances to top module");
|
||||
|
||||
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, false);
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Add the I/O children to the top-level module, which impacts the I/O indexing
|
||||
* This is the default function to build the I/O sequence/indexing
|
||||
* The I/O children is added in a maze shape
|
||||
* The function supports I/Os in the center of grids, starting from the
|
||||
*bottom-left corner and ending at the center
|
||||
*
|
||||
* +----------------------+
|
||||
* |+--------------------+|
|
||||
* ||+------------------+||
|
||||
* |||+----------------+|||
|
||||
* ||||+-------------->||||
|
||||
* ||||+---------------+|||
|
||||
* |||+-----------------+||
|
||||
* ||+-------------------+|
|
||||
* |+---------------------+
|
||||
* ^
|
||||
* io[0]
|
||||
*******************************************************************/
|
||||
static void add_top_module_io_children(
|
||||
ModuleManager& module_manager, const ModuleId& top_module,
|
||||
const DeviceGrid& grids, const vtr::Matrix<size_t>& grid_instance_ids) {
|
||||
/* Create the coordinate range for the perimeter I/Os of FPGA fabric */
|
||||
std::map<e_side, std::vector<vtr::Point<size_t>>> io_coordinates =
|
||||
generate_perimeter_grid_coordinates(grids);
|
||||
|
||||
for (const e_side& io_side : FPGA_SIDES_CLOCKWISE) {
|
||||
for (const vtr::Point<size_t>& io_coord : io_coordinates[io_side]) {
|
||||
t_physical_tile_type_ptr grid_type =
|
||||
grids.get_physical_type(io_coord.x(), io_coord.y());
|
||||
/* Bypass EMPTY grid */
|
||||
if (true == is_empty_type(grid_type)) {
|
||||
continue;
|
||||
}
|
||||
/* Skip width, height > 1 tiles (mostly heterogeneous blocks) */
|
||||
if ((0 < grids.get_width_offset(io_coord.x(), io_coord.y())) ||
|
||||
(0 < grids.get_height_offset(io_coord.x(), io_coord.y()))) {
|
||||
continue;
|
||||
}
|
||||
/* 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), io_side);
|
||||
ModuleId grid_module = module_manager.find_module(grid_module_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(grid_module));
|
||||
/* Add a I/O children to top_module*/
|
||||
module_manager.add_io_child(top_module, grid_module,
|
||||
grid_instance_ids[io_coord.x()][io_coord.y()],
|
||||
vtr::Point<int>(io_coord.x(), io_coord.y()));
|
||||
}
|
||||
}
|
||||
|
||||
/* Walk through the center grids */
|
||||
size_t xmin = 1;
|
||||
size_t xmax = grids.width() - 2;
|
||||
size_t ymin = 1;
|
||||
size_t ymax = grids.height() - 2;
|
||||
std::vector<vtr::Point<size_t>> coords;
|
||||
while (xmin < xmax && ymin < ymax) {
|
||||
for (size_t iy = ymin; iy < ymax + 1; iy++) {
|
||||
coords.push_back(vtr::Point<size_t>(xmin, iy));
|
||||
}
|
||||
for (size_t ix = xmin + 1; ix < xmax + 1; ix++) {
|
||||
coords.push_back(vtr::Point<size_t>(ix, ymax));
|
||||
}
|
||||
for (size_t iy = ymax - 1; iy > ymin; iy--) {
|
||||
coords.push_back(vtr::Point<size_t>(xmax, iy));
|
||||
}
|
||||
for (size_t ix = xmax; ix > xmin; ix--) {
|
||||
coords.push_back(vtr::Point<size_t>(ix, ymin));
|
||||
}
|
||||
xmin++;
|
||||
ymin++;
|
||||
xmax--;
|
||||
ymax--;
|
||||
}
|
||||
|
||||
/* If height is odd, add the missing horizental line */
|
||||
if ((grids.height() - 2) % 2 == 1) {
|
||||
if (ymin == ymax) {
|
||||
for (size_t ix = xmin; ix < xmax + 1; ix++) {
|
||||
coords.push_back(vtr::Point<size_t>(ix, ymin));
|
||||
}
|
||||
}
|
||||
}
|
||||
/* If width is odd, add the missing vertical line */
|
||||
if ((grids.width() - 2) % 2 == 1) {
|
||||
if (xmin == xmax) {
|
||||
for (size_t iy = ymin; iy < ymax + 1; iy++) {
|
||||
coords.push_back(vtr::Point<size_t>(xmin, iy));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Now walk through the coordinates */
|
||||
for (vtr::Point<size_t> coord : coords) {
|
||||
t_physical_tile_type_ptr grid_type =
|
||||
grids.get_physical_type(coord.x(), coord.y());
|
||||
/* Bypass EMPTY grid */
|
||||
if (true == is_empty_type(grid_type)) {
|
||||
continue;
|
||||
}
|
||||
/* Skip width or height > 1 tiles (mostly heterogeneous blocks) */
|
||||
if ((0 < grids.get_width_offset(coord.x(), coord.y())) ||
|
||||
(0 < grids.get_height_offset(coord.x(), coord.y()))) {
|
||||
continue;
|
||||
}
|
||||
/* 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), NUM_SIDES);
|
||||
ModuleId grid_module = module_manager.find_module(grid_module_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(grid_module));
|
||||
/* Add a I/O children to top_module*/
|
||||
module_manager.add_io_child(top_module, grid_module,
|
||||
grid_instance_ids[coord.x()][coord.y()],
|
||||
vtr::Point<int>(coord.x(), coord.y()));
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Add the fine-grained instances to the top module of FPGA fabric
|
||||
* The fine-grained instances include programmable blocks, connection blocks and
|
||||
*switch blocks, each of which is an instance under the top module
|
||||
*******************************************************************/
|
||||
static int build_top_module_fine_grained_child_instances(
|
||||
ModuleManager& module_manager, const ModuleId& top_module,
|
||||
MemoryBankShiftRegisterBanks& blwl_sr_banks,
|
||||
const CircuitLibrary& circuit_lib, const ClockNetwork& clk_ntwk,
|
||||
const RRClockSpatialLookup& rr_clock_lookup,
|
||||
const VprDeviceAnnotation& vpr_device_annotation, const DeviceGrid& grids,
|
||||
const TileAnnotation& tile_annotation, const RRGraphView& rr_graph,
|
||||
const DeviceRRGSB& device_rr_gsb, const TileDirect& tile_direct,
|
||||
const ArchDirect& arch_direct, const ConfigProtocol& config_protocol,
|
||||
const CircuitModelId& sram_model, const bool& frame_view,
|
||||
const bool& compact_routing_hierarchy, const bool& duplicate_grid_pin,
|
||||
const FabricKey& fabric_key) {
|
||||
int status = CMD_EXEC_SUCCESS;
|
||||
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);
|
||||
|
||||
/* Update I/O children list */
|
||||
add_top_module_io_children(module_manager, top_module, grids,
|
||||
grid_instance_ids);
|
||||
|
||||
/* Add nets when we need a complete fabric modeling,
|
||||
* which is required by downstream functions
|
||||
*/
|
||||
if (false == frame_view) {
|
||||
/* Reserve nets to be memory efficient */
|
||||
reserve_module_manager_module_nets(module_manager, top_module);
|
||||
|
||||
/* Add module nets to connect the sub modules */
|
||||
add_top_module_nets_connect_grids_and_gsbs(
|
||||
module_manager, top_module, vpr_device_annotation, 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, vpr_device_annotation, grids,
|
||||
grid_instance_ids, tile_direct, arch_direct);
|
||||
}
|
||||
|
||||
/* Add global ports from grid ports that are defined as global in tile
|
||||
* annotation */
|
||||
status = add_top_module_global_ports_from_grid_modules(
|
||||
module_manager, top_module, tile_annotation, vpr_device_annotation, grids,
|
||||
rr_graph, device_rr_gsb, cb_instance_ids, grid_instance_ids, clk_ntwk,
|
||||
rr_clock_lookup);
|
||||
if (CMD_EXEC_FATAL_ERROR == status) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Add GPIO ports from the sub-modules under this Verilog module
|
||||
* For top-level module, we follow a special sequencing for I/O modules. So we
|
||||
* rebuild the I/O children list here
|
||||
*/
|
||||
add_module_gpio_ports_from_child_modules(module_manager, top_module);
|
||||
|
||||
/* Organize the list of memory modules and instances
|
||||
* If we have an empty fabric key, we organize the memory modules as routine
|
||||
* Otherwise, we will load the fabric key directly
|
||||
*/
|
||||
if (true == fabric_key.empty()) {
|
||||
organize_top_module_memory_modules(
|
||||
module_manager, top_module, circuit_lib, config_protocol, sram_model,
|
||||
grids, grid_instance_ids, device_rr_gsb, sb_instance_ids, cb_instance_ids,
|
||||
compact_routing_hierarchy);
|
||||
} else {
|
||||
VTR_ASSERT_SAFE(false == fabric_key.empty());
|
||||
/* Throw a fatal error when the fabric key has a mismatch in region
|
||||
* organization. between architecture file and fabric key
|
||||
*/
|
||||
if (size_t(config_protocol.num_regions()) != fabric_key.regions().size()) {
|
||||
VTR_LOG_ERROR(
|
||||
"Fabric key has a different number of configurable regions (='%ld') "
|
||||
"than architecture definition (=%d)!\n",
|
||||
fabric_key.regions().size(), config_protocol.num_regions());
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
|
||||
status = load_top_module_memory_modules_from_fabric_key(
|
||||
module_manager, top_module, circuit_lib, config_protocol, fabric_key);
|
||||
if (CMD_EXEC_FATAL_ERROR == status) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = load_top_module_shift_register_banks_from_fabric_key(
|
||||
fabric_key, blwl_sr_banks);
|
||||
if (CMD_EXEC_FATAL_ERROR == status) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Update the memory organization in sub module (non-top) */
|
||||
status = load_submodules_memory_modules_from_fabric_key(
|
||||
module_manager, circuit_lib, config_protocol, fabric_key);
|
||||
if (CMD_EXEC_FATAL_ERROR == status) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
return CMD_EXEC_SUCCESS;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Add a instance of a tile module to the top module
|
||||
*******************************************************************/
|
||||
static size_t add_top_module_tile_instance(ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const FabricTile& fabric_tile,
|
||||
const FabricTileId& fabric_tile_id) {
|
||||
/* Find the module name for this type of grid */
|
||||
vtr::Point<size_t> tile_coord = fabric_tile.tile_coordinate(fabric_tile_id);
|
||||
FabricTileId unique_fabric_tile_id = fabric_tile.unique_tile(tile_coord);
|
||||
vtr::Point<size_t> unique_tile_coord =
|
||||
fabric_tile.tile_coordinate(unique_fabric_tile_id);
|
||||
std::string tile_module_name = generate_tile_module_name(unique_tile_coord);
|
||||
ModuleId tile_module = module_manager.find_module(tile_module_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(tile_module));
|
||||
/* Record the instance id */
|
||||
size_t tile_instance = module_manager.num_instance(top_module, tile_module);
|
||||
/* Add the module to top_module */
|
||||
module_manager.add_child_module(top_module, tile_module, false);
|
||||
/* Set an unique name to the instance
|
||||
* Note: it is your risk to gurantee the name is unique!
|
||||
*/
|
||||
std::string instance_name = generate_tile_module_name(tile_coord);
|
||||
module_manager.set_child_instance_name(top_module, tile_module, tile_instance,
|
||||
instance_name);
|
||||
return tile_instance;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Add all the tiles as sub-modules across the fabric
|
||||
* Here, we will iterate over the full fabric (coordinates)
|
||||
* and instanciate the tile 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 tiles |
|
||||
* | TOP side |
|
||||
* +-----------------------------------+
|
||||
*
|
||||
* +-----------+ +-----------------------------------+ +------------+
|
||||
* | | | | | |
|
||||
* | I/O tiles | | Core tiles | | I/O tiles |
|
||||
* | LEFT side | | (CLB, Heterogeneous blocks, etc.) | | RIGHT side |
|
||||
* | | | | | |
|
||||
* +-----------+ +-----------------------------------+ +------------+
|
||||
*
|
||||
* +-----------------------------------+
|
||||
* | I/O tiles |
|
||||
* | BOTTOM side |
|
||||
* +-----------------------------------+
|
||||
*
|
||||
*******************************************************************/
|
||||
static int add_top_module_tile_instances(ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
vtr::Matrix<size_t>& tile_instance_ids,
|
||||
const DeviceGrid& grids,
|
||||
const FabricTile& fabric_tile) {
|
||||
vtr::ScopedStartFinishTimer timer("Add tile instances to top module");
|
||||
int status = CMD_EXEC_SUCCESS;
|
||||
|
||||
/* Reserve an array for the instance ids */
|
||||
tile_instance_ids.resize({grids.width(), grids.height()});
|
||||
tile_instance_ids.fill(size_t(-1));
|
||||
|
||||
/* Instanciate I/O grids */
|
||||
/* Create the coordinate range for each side of FPGA fabric */
|
||||
std::map<e_side, std::vector<vtr::Point<size_t>>> io_coordinates =
|
||||
generate_perimeter_tile_coordinates(grids);
|
||||
|
||||
for (const e_side& io_side : FPGA_SIDES_CLOCKWISE) {
|
||||
for (const vtr::Point<size_t>& io_coord : io_coordinates[io_side]) {
|
||||
FabricTileId fabric_tile_id = fabric_tile.find_tile(io_coord);
|
||||
if (!fabric_tile.valid_tile_id(fabric_tile_id)) {
|
||||
continue;
|
||||
}
|
||||
/* Add a tile module to top_module*/
|
||||
tile_instance_ids[io_coord.x()][io_coord.y()] =
|
||||
add_top_module_tile_instance(module_manager, top_module, fabric_tile,
|
||||
fabric_tile_id);
|
||||
}
|
||||
}
|
||||
|
||||
/* Instanciate core grids
|
||||
* IMPORTANT: sequence matters here, it impacts the I/O indexing.
|
||||
* We should follow the same sequence as the build_io_location_map()!
|
||||
* If you change the sequence of walking through grids here, you should change
|
||||
* it in the build_io_location map()!
|
||||
*/
|
||||
for (size_t ix = 1; ix < grids.width() - 1; ++ix) {
|
||||
for (size_t iy = 1; iy < grids.height() - 1; ++iy) {
|
||||
vtr::Point<size_t> curr_coord(ix, iy);
|
||||
FabricTileId fabric_tile_id = fabric_tile.find_tile(curr_coord);
|
||||
if (!fabric_tile.valid_tile_id(fabric_tile_id)) {
|
||||
continue;
|
||||
}
|
||||
/* Add a tile module to top_module*/
|
||||
tile_instance_ids[curr_coord.x()][curr_coord.y()] =
|
||||
add_top_module_tile_instance(module_manager, top_module, fabric_tile,
|
||||
fabric_tile_id);
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Add the tile-level instances to the top module of FPGA fabric
|
||||
* and build connects between them
|
||||
*******************************************************************/
|
||||
int build_top_module_tile_child_instances(
|
||||
ModuleManager& module_manager, const ModuleId& top_module,
|
||||
const DeviceGrid& grids, const FabricTile& fabric_tile) {
|
||||
int status = CMD_EXEC_SUCCESS;
|
||||
vtr::Matrix<size_t> tile_instance_ids;
|
||||
status = add_top_module_tile_instances(module_manager, top_module,
|
||||
tile_instance_ids, grids, fabric_tile);
|
||||
if (status != CMD_EXEC_SUCCESS) {
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
return CMD_EXEC_SUCCESS;
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
|
@ -0,0 +1,54 @@
|
|||
#ifndef BUILD_TOP_MODULE_CHILD_INSTANCE_H
|
||||
#define BUILD_TOP_MODULE_CHILD_INSTANCE_H
|
||||
|
||||
/********************************************************************
|
||||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "arch_direct.h"
|
||||
#include "circuit_library.h"
|
||||
#include "clock_network.h"
|
||||
#include "config_protocol.h"
|
||||
#include "decoder_library.h"
|
||||
#include "device_grid.h"
|
||||
#include "device_rr_gsb.h"
|
||||
#include "fabric_key.h"
|
||||
#include "fabric_tile.h"
|
||||
#include "memory_bank_shift_register_banks.h"
|
||||
#include "module_manager.h"
|
||||
#include "rr_clock_spatial_lookup.h"
|
||||
#include "rr_graph_view.h"
|
||||
#include "tile_annotation.h"
|
||||
#include "tile_direct.h"
|
||||
#include "vpr_device_annotation.h"
|
||||
#include "vtr_geometry.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
*******************************************************************/
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
int build_top_module_fine_grained_child_instances(
|
||||
ModuleManager& module_manager, const ModuleId& top_module,
|
||||
MemoryBankShiftRegisterBanks& blwl_sr_banks,
|
||||
const CircuitLibrary& circuit_lib, const ClockNetwork& clk_ntwk,
|
||||
const RRClockSpatialLookup& rr_clock_lookup,
|
||||
const VprDeviceAnnotation& vpr_device_annotation, const DeviceGrid& grids,
|
||||
const TileAnnotation& tile_annotation, const RRGraphView& rr_graph,
|
||||
const DeviceRRGSB& device_rr_gsb, const TileDirect& tile_direct,
|
||||
const ArchDirect& arch_direct, const ConfigProtocol& config_protocol,
|
||||
const CircuitModelId& sram_model, const bool& frame_view,
|
||||
const bool& compact_routing_hierarchy, const bool& duplicate_grid_pin,
|
||||
const FabricKey& fabric_key);
|
||||
|
||||
static int build_top_module_tile_child_instances(
|
||||
ModuleManager& module_manager, const ModuleId& top_module,
|
||||
const DeviceGrid& grids, const FabricTile& fabric_tile);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue