refactor memory organization at the top-level module
This commit is contained in:
parent
cfec8d70ab
commit
8c1158fc5c
|
@ -0,0 +1,563 @@
|
||||||
|
/********************************************************************
|
||||||
|
* 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>
|
||||||
|
|
||||||
|
#include "vtr_assert.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "device_port.h"
|
||||||
|
|
||||||
|
#include "fpga_x2p_naming.h"
|
||||||
|
#include "fpga_x2p_pbtypes_utils.h"
|
||||||
|
#include "module_manager_utils.h"
|
||||||
|
|
||||||
|
#include "globals.h"
|
||||||
|
#include "verilog_global.h"
|
||||||
|
|
||||||
|
#include "build_top_module_directs.h"
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Check if the grid coorindate given is in the device grid range
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
bool is_grid_coordinate_exist_in_device(const vtr::Point<size_t>& device_size,
|
||||||
|
const vtr::Point<size_t>& grid_coordinate) {
|
||||||
|
return (grid_coordinate < device_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* 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_clb2clb_direct_connection(ModuleManager& module_manager,
|
||||||
|
const ModuleId& top_module,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
const vtr::Point<size_t>& device_size,
|
||||||
|
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||||
|
const std::vector<std::vector<size_t>>& grid_instance_ids,
|
||||||
|
const vtr::Point<size_t>& src_clb_coord,
|
||||||
|
const vtr::Point<size_t>& des_clb_coord,
|
||||||
|
const t_clb_to_clb_directs& direct) {
|
||||||
|
/* Find the source port and destination port on the CLBs */
|
||||||
|
BasicPort src_clb_port;
|
||||||
|
BasicPort des_clb_port;
|
||||||
|
|
||||||
|
src_clb_port.set_width(direct.from_clb_pin_start_index, direct.from_clb_pin_end_index);
|
||||||
|
des_clb_port.set_width(direct.to_clb_pin_start_index, direct.to_clb_pin_end_index);
|
||||||
|
|
||||||
|
/* Check bandwidth match between from_clb and to_clb pins */
|
||||||
|
if (src_clb_port.get_width() != des_clb_port.get_width()) {
|
||||||
|
vpr_printf(TIO_MESSAGE_ERROR,
|
||||||
|
"(File:%s, [LINE%d]) Unmatch pin bandwidth in direct connection (name=%s)!\n",
|
||||||
|
__FILE__, __LINE__, direct.name);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find the module name of source clb */
|
||||||
|
t_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_verilog_file_name_prefix);
|
||||||
|
std::string src_module_name = generate_grid_block_module_name(src_module_name_prefix, std::string(src_grid_type->name), 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 */
|
||||||
|
t_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_verilog_file_name_prefix);
|
||||||
|
std::string sink_module_name = generate_grid_block_module_name(sink_module_name_prefix, std::string(sink_grid_type->name), 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 */
|
||||||
|
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, SPICE_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_lib_name(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, SPICE_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_lib_name(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());
|
||||||
|
|
||||||
|
for (size_t pin_id : src_clb_port.pins()) {
|
||||||
|
/* Generate the pin name of source port/pin in the grid */
|
||||||
|
size_t src_pin_height = find_grid_pin_height(grids, src_clb_coord, src_clb_port.pins()[pin_id]);
|
||||||
|
e_side src_pin_grid_side = find_grid_pin_side(device_size, grids, src_clb_coord, src_pin_height, src_clb_port.pins()[pin_id]);
|
||||||
|
std::string src_port_name = generate_grid_port_name(src_clb_coord, src_pin_height, src_pin_grid_side, src_clb_port.pins()[pin_id], 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 */
|
||||||
|
size_t sink_pin_height = find_grid_pin_height(grids, des_clb_coord, des_clb_port.pins()[pin_id]);
|
||||||
|
e_side sink_pin_grid_side = find_grid_pin_side(device_size, grids, des_clb_coord, sink_pin_height, des_clb_port.pins()[pin_id]);
|
||||||
|
std::string sink_port_name = generate_grid_port_name(des_clb_coord, sink_pin_height, sink_pin_grid_side, des_clb_port.pins()[pin_id], 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
|
||||||
|
*
|
||||||
|
* This function supports the following type of direct connection:
|
||||||
|
* 1. Direct connection between grids in the same column or row
|
||||||
|
* +------+ +------+
|
||||||
|
* | | | |
|
||||||
|
* | Grid |----->| Grid |
|
||||||
|
* | | | |
|
||||||
|
* +------+ +------+
|
||||||
|
* | direction connection
|
||||||
|
* v
|
||||||
|
* +------+
|
||||||
|
* | |
|
||||||
|
* | Grid |
|
||||||
|
* | |
|
||||||
|
* +------+
|
||||||
|
*
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
void add_top_module_nets_intra_clb2clb_direct_connections(ModuleManager& module_manager,
|
||||||
|
const ModuleId& top_module,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
const vtr::Point<size_t>& device_size,
|
||||||
|
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||||
|
const std::vector<std::vector<size_t>>& grid_instance_ids,
|
||||||
|
const std::vector<t_clb_to_clb_directs>& clb2clb_directs) {
|
||||||
|
/* Scan the grid, visit each grid and apply direct connections */
|
||||||
|
for (size_t ix = 0; ix < device_size.x(); ++ix) {
|
||||||
|
for (size_t iy = 0; iy < device_size.y(); ++iy) {
|
||||||
|
/* Bypass EMPTY_TYPE*/
|
||||||
|
if ( (NULL == grids[ix][iy].type)
|
||||||
|
|| (EMPTY_TYPE == grids[ix][iy].type)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Bypass any grid with a non-zero offset! They have been visited in the offset=0 case */
|
||||||
|
if (0 != grids[ix][iy].offset) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Check each clb2clb directs by comparing the source and destination clb types
|
||||||
|
* Direct connections are made only for those matched clbs
|
||||||
|
*/
|
||||||
|
for (const t_clb_to_clb_directs& direct : clb2clb_directs) {
|
||||||
|
/* Bypass unmatched clb type */
|
||||||
|
if (grids[ix][iy].type != direct.from_clb_type) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See if the destination CLB is in the bound */
|
||||||
|
vtr::Point<size_t> src_clb_coord(ix, iy);
|
||||||
|
vtr::Point<size_t> des_clb_coord(ix + direct.x_offset, iy + direct.y_offset);
|
||||||
|
if (false == is_grid_coordinate_exist_in_device(device_size, des_clb_coord)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if the destination clb_type matches */
|
||||||
|
if (grids[des_clb_coord.x()][des_clb_coord.y()].type == direct.to_clb_type) {
|
||||||
|
/* Add a module net for a direct connection with the two grids in top_model */
|
||||||
|
add_module_nets_clb2clb_direct_connection(module_manager, top_module, circuit_lib,
|
||||||
|
device_size, grids, grid_instance_ids,
|
||||||
|
src_clb_coord, des_clb_coord,
|
||||||
|
direct);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* 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 vtr::Point<size_t>& device_size,
|
||||||
|
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||||
|
const std::vector<vtr::Point<size_t>>& candidate_coords,
|
||||||
|
t_type_ptr wanted_grid_type) {
|
||||||
|
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(device_size, coord)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (wanted_grid_type == grids[coord.x()][coord.y()].type) {
|
||||||
|
return coord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Return an valid coordinate */
|
||||||
|
return vtr::Point<size_t>(size_t(-1), size_t(-1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Find the coordinate of the destination clb/heterogeneous block
|
||||||
|
* considering intra column/row direct connections in core grids
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
vtr::Point<size_t> find_intra_direct_destination_coordinate(const vtr::Point<size_t>& device_size,
|
||||||
|
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||||
|
const vtr::Point<size_t> src_coord,
|
||||||
|
const t_clb_to_clb_directs& direct) {
|
||||||
|
vtr::Point<size_t> des_coord(size_t(-1), size_t(-1));
|
||||||
|
t_type_ptr src_grid_type = grids[src_coord.x()][src_coord.y()].type;
|
||||||
|
|
||||||
|
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 (P2P_DIRECT_COLUMN == direct.interconnection_type) {
|
||||||
|
if (POSITIVE_DIR == direct.x_dir) {
|
||||||
|
/* Our first search space will be in x-direction:
|
||||||
|
*
|
||||||
|
* x ... nx
|
||||||
|
* +-----+
|
||||||
|
* |Grid | ----->
|
||||||
|
* +-----+
|
||||||
|
*/
|
||||||
|
for (size_t ix = src_coord.x() + 1; ix < device_size.x() - 1; ++ix) {
|
||||||
|
first_search_space.push_back(ix);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
VTR_ASSERT(NEGATIVE_DIR == direct.x_dir);
|
||||||
|
/* 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 < device_size.y() - 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 == direct.y_dir) {
|
||||||
|
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 (P2P_DIRECT_ROW == direct.interconnection_type) {
|
||||||
|
if (POSITIVE_DIR == direct.y_dir) {
|
||||||
|
/* Our first search space will be in y-direction:
|
||||||
|
*
|
||||||
|
* +------+
|
||||||
|
* | Grid | ny
|
||||||
|
* +------+
|
||||||
|
* ^ .
|
||||||
|
* | .
|
||||||
|
* | .
|
||||||
|
* +------+
|
||||||
|
* | Grid | y
|
||||||
|
* +------+
|
||||||
|
*/
|
||||||
|
for (size_t iy = src_coord.y() + 1; iy < device_size.y() - 1; ++iy) {
|
||||||
|
first_search_space.push_back(iy);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
VTR_ASSERT(NEGATIVE_DIR == direct.y_dir);
|
||||||
|
/* 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 < device_size.x() - 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 == direct.x_dir) {
|
||||||
|
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 (P2P_DIRECT_COLUMN == direct.interconnection_type) {
|
||||||
|
next_col_row_coords.push_back(vtr::Point<size_t>(ix, iy));
|
||||||
|
} else {
|
||||||
|
VTR_ASSERT(P2P_DIRECT_ROW == direct.interconnection_type);
|
||||||
|
/* 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(device_size, grids, next_col_row_coords, src_grid_type);
|
||||||
|
/* For a valid coordinate, we can return */
|
||||||
|
if ( (size_t(-1) != des_coord_cand.x())
|
||||||
|
&& (size_t(-1) != des_coord_cand.y()) ) {
|
||||||
|
return des_coord_cand;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return des_coord;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* This function supports the following type of direct connection:
|
||||||
|
*
|
||||||
|
* 1. Direct connections across columns and rows
|
||||||
|
* +------+
|
||||||
|
* | |
|
||||||
|
* | v
|
||||||
|
* +------+ | +------+
|
||||||
|
* | | | | |
|
||||||
|
* | Grid | | | Grid |
|
||||||
|
* | | | | |
|
||||||
|
* +------+ | +------+
|
||||||
|
* |
|
||||||
|
* +------+ | +------+
|
||||||
|
* | | | | |
|
||||||
|
* | 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
|
||||||
|
void add_top_module_nets_inter_clb2clb_direct_connections(ModuleManager& module_manager,
|
||||||
|
const ModuleId& top_module,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
const vtr::Point<size_t>& device_size,
|
||||||
|
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||||
|
const std::vector<std::vector<size_t>>& grid_instance_ids,
|
||||||
|
const std::vector<t_clb_to_clb_directs>& clb2clb_directs) {
|
||||||
|
|
||||||
|
std::vector<e_side> border_sides = {TOP, RIGHT, BOTTOM, LEFT};
|
||||||
|
|
||||||
|
/* Go through the direct connection list, see if we need intra-column/row connection here */
|
||||||
|
for (const t_clb_to_clb_directs& direct: clb2clb_directs) {
|
||||||
|
if ( (P2P_DIRECT_COLUMN != direct.interconnection_type)
|
||||||
|
&& (P2P_DIRECT_ROW != direct.interconnection_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 (P2P_DIRECT_COLUMN == direct.interconnection_type) {
|
||||||
|
for (size_t ix = 1; ix < device_size.x() - 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_size.y() - 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 == direct.y_dir) {
|
||||||
|
std::reverse(next_col_src_grid_coords.begin(), next_col_src_grid_coords.end());
|
||||||
|
}
|
||||||
|
vtr::Point<size_t> src_clb_coord = find_grid_coordinate_given_type(device_size, grids, next_col_src_grid_coords, direct.from_clb_type);
|
||||||
|
/* Skip if we do not have a valid coordinate for source CLB/heterogeneous block */
|
||||||
|
if ( (size_t(-1) == src_clb_coord.x())
|
||||||
|
|| (size_t(-1) == src_clb_coord.y()) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* For a valid coordinate, we can find the coordinate of the destination clb */
|
||||||
|
vtr::Point<size_t> des_clb_coord = find_intra_direct_destination_coordinate(device_size, grids, src_clb_coord, direct);
|
||||||
|
/* If destination clb is valid, we should add something */
|
||||||
|
if ( (size_t(-1) == des_clb_coord.x())
|
||||||
|
|| (size_t(-1) == des_clb_coord.y()) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
add_module_nets_clb2clb_direct_connection(module_manager, top_module, circuit_lib,
|
||||||
|
device_size, grids, grid_instance_ids,
|
||||||
|
src_clb_coord, des_clb_coord,
|
||||||
|
direct);
|
||||||
|
}
|
||||||
|
continue; /* Go to next direct type */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reach here, it must be a cross-row connection */
|
||||||
|
VTR_ASSERT(P2P_DIRECT_ROW == direct.interconnection_type);
|
||||||
|
/* 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_size.y() - 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_size.x() - 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 == direct.x_dir) {
|
||||||
|
std::reverse(next_col_src_grid_coords.begin(), next_col_src_grid_coords.end());
|
||||||
|
}
|
||||||
|
vtr::Point<size_t> src_clb_coord = find_grid_coordinate_given_type(device_size, grids, next_col_src_grid_coords, direct.from_clb_type);
|
||||||
|
/* Skip if we do not have a valid coordinate for source CLB/heterogeneous block */
|
||||||
|
if ( (size_t(-1) == src_clb_coord.x())
|
||||||
|
|| (size_t(-1) == src_clb_coord.y()) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* For a valid coordinate, we can find the coordinate of the destination clb */
|
||||||
|
vtr::Point<size_t> des_clb_coord = find_intra_direct_destination_coordinate(device_size, grids, src_clb_coord, direct);
|
||||||
|
/* If destination clb is valid, we should add something */
|
||||||
|
if ( (size_t(-1) == des_clb_coord.x())
|
||||||
|
|| (size_t(-1) == des_clb_coord.y()) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
add_module_nets_clb2clb_direct_connection(module_manager, top_module, circuit_lib,
|
||||||
|
device_size, grids, grid_instance_ids,
|
||||||
|
src_clb_coord, des_clb_coord,
|
||||||
|
direct);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* 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_clb2clb_direct_connections(ModuleManager& module_manager,
|
||||||
|
const ModuleId& top_module,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
const vtr::Point<size_t>& device_size,
|
||||||
|
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||||
|
const std::vector<std::vector<size_t>>& grid_instance_ids,
|
||||||
|
const std::vector<t_clb_to_clb_directs>& clb2clb_directs) {
|
||||||
|
|
||||||
|
add_top_module_nets_intra_clb2clb_direct_connections(module_manager, top_module, circuit_lib,
|
||||||
|
device_size, grids, grid_instance_ids,
|
||||||
|
clb2clb_directs);
|
||||||
|
|
||||||
|
add_top_module_nets_inter_clb2clb_direct_connections(module_manager, top_module, circuit_lib,
|
||||||
|
device_size, grids, grid_instance_ids,
|
||||||
|
clb2clb_directs);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
#ifndef BUILD_TOP_MODULE_DIRECTS_H
|
||||||
|
#define BUILD_TOP_MODULE_DIRECTS_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include "vtr_geometry.h"
|
||||||
|
#include "vpr_types.h"
|
||||||
|
#include "module_manager.h"
|
||||||
|
#include "circuit_library.h"
|
||||||
|
|
||||||
|
void add_top_module_nets_clb2clb_direct_connections(ModuleManager& module_manager,
|
||||||
|
const ModuleId& top_module,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
const vtr::Point<size_t>& device_size,
|
||||||
|
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||||
|
const std::vector<std::vector<size_t>>& grid_instance_ids,
|
||||||
|
const std::vector<t_clb_to_clb_directs>& clb2clb_directs);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,425 @@
|
||||||
|
/********************************************************************
|
||||||
|
* This file includes functions that are used to organize memories
|
||||||
|
* in the top module of FPGA fabric
|
||||||
|
*******************************************************************/
|
||||||
|
#include "vtr_assert.h"
|
||||||
|
|
||||||
|
#include "fpga_x2p_utils.h"
|
||||||
|
#include "fpga_x2p_naming.h"
|
||||||
|
|
||||||
|
#include "globals.h"
|
||||||
|
#include "verilog_global.h"
|
||||||
|
|
||||||
|
#include "module_manager_utils.h"
|
||||||
|
#include "build_top_module_memory.h"
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* This function adds the CBX/CBY of a tile
|
||||||
|
* to the memory modules and memory instances
|
||||||
|
* This function is designed for organizing memory modules in top-level
|
||||||
|
* module
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
void organize_top_module_tile_cb_modules(const ModuleManager& module_manager,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
const CircuitModelId& sram_model,
|
||||||
|
t_sram_orgz_info* cur_sram_orgz_info,
|
||||||
|
const std::vector<std::vector<size_t>>& cb_instance_ids,
|
||||||
|
const DeviceRRGSB& L_device_rr_gsb,
|
||||||
|
const RRGSB& rr_gsb,
|
||||||
|
const t_rr_type& cb_type,
|
||||||
|
const bool& compact_routing_hierarchy,
|
||||||
|
std::vector<ModuleId>& memory_modules,
|
||||||
|
std::vector<size_t>& memory_instances) {
|
||||||
|
/* If the CB does not exist, we can skip addition */
|
||||||
|
if ( (TRUE != is_cb_exist(cb_type, rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type)))
|
||||||
|
|| (true != rr_gsb.is_cb_exist(cb_type))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vtr::Point<size_t> cb_coord(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type));
|
||||||
|
/* If we use compact routing hierarchy, we should instanciate the unique module of SB */
|
||||||
|
if (true == compact_routing_hierarchy) {
|
||||||
|
const RRGSB& unique_mirror = L_device_rr_gsb.get_cb_unique_module(cb_type, DeviceCoordinator(cb_coord.x(), cb_coord.y()));
|
||||||
|
cb_coord.set_x(unique_mirror.get_cb_x(cb_type));
|
||||||
|
cb_coord.set_y(unique_mirror.get_cb_y(cb_type));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string cb_module_name = generate_connection_block_module_name(cb_type, cb_coord);
|
||||||
|
ModuleId cb_module = module_manager.find_module(cb_module_name);
|
||||||
|
VTR_ASSERT(true == module_manager.valid_module_id(cb_module));
|
||||||
|
|
||||||
|
/* Identify if this sub module includes configuration bits,
|
||||||
|
* we will update the memory module and instance list
|
||||||
|
*/
|
||||||
|
if (0 < find_module_num_config_bits(module_manager, cb_module,
|
||||||
|
circuit_lib, sram_model,
|
||||||
|
cur_sram_orgz_info->type)) {
|
||||||
|
memory_modules.push_back(cb_module);
|
||||||
|
memory_instances.push_back(cb_instance_ids[cb_coord.x()][cb_coord.y()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* This function adds the SB, CBX, CBY and Grid of a tile
|
||||||
|
* to the memory modules and memory instances
|
||||||
|
* This function is designed for organizing memory modules in top-level
|
||||||
|
* module
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
void organize_top_module_tile_memory_modules(const ModuleManager& module_manager,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
const CircuitModelId& sram_model,
|
||||||
|
t_sram_orgz_info* cur_sram_orgz_info,
|
||||||
|
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||||
|
const std::vector<std::vector<size_t>>& grid_instance_ids,
|
||||||
|
const DeviceRRGSB& L_device_rr_gsb,
|
||||||
|
const std::vector<std::vector<size_t>>& sb_instance_ids,
|
||||||
|
const std::map<t_rr_type, std::vector<std::vector<size_t>>>& cb_instance_ids,
|
||||||
|
const bool& compact_routing_hierarchy,
|
||||||
|
const vtr::Point<size_t>& tile_coord,
|
||||||
|
const e_side& tile_border_side,
|
||||||
|
std::vector<ModuleId>& memory_modules,
|
||||||
|
std::vector<size_t>& memory_instances) {
|
||||||
|
|
||||||
|
vtr::Point<size_t> gsb_coord_range(L_device_rr_gsb.get_gsb_range().get_x(), L_device_rr_gsb.get_gsb_range().get_y());
|
||||||
|
|
||||||
|
vtr::Point<size_t> gsb_coord(tile_coord.x(), tile_coord.y() - 1);
|
||||||
|
|
||||||
|
/* We do NOT consider SB and CBs if the gsb is not in the range! */
|
||||||
|
if ( (gsb_coord.x() < gsb_coord_range.x())
|
||||||
|
&& (gsb_coord.y() < gsb_coord_range.y()) ) {
|
||||||
|
const RRGSB& rr_gsb = L_device_rr_gsb.get_gsb(gsb_coord.x(), gsb_coord.y());
|
||||||
|
/* Find Switch Block: unique module id and instance id!
|
||||||
|
* Note that switch block does always exist in a GSB
|
||||||
|
*/
|
||||||
|
vtr::Point<size_t> sb_coord(rr_gsb.get_sb_x(), rr_gsb.get_sb_y());
|
||||||
|
/* If we use compact routing hierarchy, we should instanciate the unique module of SB */
|
||||||
|
if (true == compact_routing_hierarchy) {
|
||||||
|
const RRGSB& unique_mirror = L_device_rr_gsb.get_sb_unique_module(DeviceCoordinator(sb_coord.x(), sb_coord.y()));
|
||||||
|
sb_coord.set_x(unique_mirror.get_sb_x());
|
||||||
|
sb_coord.set_y(unique_mirror.get_sb_y());
|
||||||
|
}
|
||||||
|
std::string sb_module_name = generate_switch_block_module_name(sb_coord);
|
||||||
|
ModuleId sb_module = module_manager.find_module(sb_module_name);
|
||||||
|
VTR_ASSERT(true == module_manager.valid_module_id(sb_module));
|
||||||
|
|
||||||
|
/* Identify if this sub module includes configuration bits,
|
||||||
|
* we will update the memory module and instance list
|
||||||
|
*/
|
||||||
|
if (0 < find_module_num_config_bits(module_manager, sb_module,
|
||||||
|
circuit_lib, sram_model,
|
||||||
|
cur_sram_orgz_info->type)) {
|
||||||
|
memory_modules.push_back(sb_module);
|
||||||
|
memory_instances.push_back(sb_instance_ids[sb_coord.x()][sb_coord.y()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try to find and add CBX and CBY */
|
||||||
|
organize_top_module_tile_cb_modules(module_manager, circuit_lib,
|
||||||
|
sram_model, cur_sram_orgz_info,
|
||||||
|
cb_instance_ids.at(CHANX),
|
||||||
|
L_device_rr_gsb, rr_gsb, CHANX,
|
||||||
|
compact_routing_hierarchy,
|
||||||
|
memory_modules, memory_instances);
|
||||||
|
|
||||||
|
organize_top_module_tile_cb_modules(module_manager, circuit_lib,
|
||||||
|
sram_model, cur_sram_orgz_info,
|
||||||
|
cb_instance_ids.at(CHANY),
|
||||||
|
L_device_rr_gsb, rr_gsb, CHANY,
|
||||||
|
compact_routing_hierarchy,
|
||||||
|
memory_modules, memory_instances);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find the module name for this type of grid */
|
||||||
|
t_type_ptr grid_type = grids[tile_coord.x()][tile_coord.y()].type;
|
||||||
|
std::string grid_module_name_prefix(grid_verilog_file_name_prefix);
|
||||||
|
std::string grid_module_name = generate_grid_block_module_name(grid_module_name_prefix, std::string(grid_type->name), IO_TYPE == grid_type, tile_border_side);
|
||||||
|
ModuleId grid_module = module_manager.find_module(grid_module_name);
|
||||||
|
VTR_ASSERT(true == module_manager.valid_module_id(grid_module));
|
||||||
|
|
||||||
|
/* Identify if this sub module includes configuration bits,
|
||||||
|
* we will update the memory module and instance list
|
||||||
|
*/
|
||||||
|
if (0 < find_module_num_config_bits(module_manager, grid_module,
|
||||||
|
circuit_lib, sram_model,
|
||||||
|
cur_sram_orgz_info->type)) {
|
||||||
|
memory_modules.push_back(grid_module);
|
||||||
|
memory_instances.push_back(grid_instance_ids[tile_coord.x()][tile_coord.y()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Organize the list of memory modules and instances
|
||||||
|
* This function will record all the sub modules of the top-level module
|
||||||
|
* (those have memory ports) to two lists:
|
||||||
|
* 1. memory_modules records the module ids
|
||||||
|
* 2. memory_instances records the instance ids
|
||||||
|
* To keep a clean memory connection between sub modules and top-level module,
|
||||||
|
* the sequence of memory_modules and memory_instances will follow
|
||||||
|
* a chain of tiles considering their physical location
|
||||||
|
*
|
||||||
|
* Inter tile connection:
|
||||||
|
* +--------------------------------------------------------+
|
||||||
|
* | +------+------+-----+------+ |
|
||||||
|
* | | I/O | I/O | ... | I/O | |
|
||||||
|
* | | TOP | TOP | | TOP | |
|
||||||
|
* | +------+------+-----+------+ |
|
||||||
|
* | +---------------------------------->tail |
|
||||||
|
* | +------+ | +------+------+-----+------+ +------+ |
|
||||||
|
* | | | | | | | | | | | |
|
||||||
|
* | | I/O | | | Tile | Tile | ... | Tile | | I/O | |
|
||||||
|
* | | LEFT | | | [h+1]| [h+2]| | [n] | |RIGHT | |
|
||||||
|
* | +------+ | +------+------+-----+------+ +------+ |
|
||||||
|
* | +-------------------------------+ |
|
||||||
|
* | ... ... ... ... ... | ... |
|
||||||
|
* | +-------------------------------+ |
|
||||||
|
* | +------+ | +------+------+-----+------+ +------+ |
|
||||||
|
* | | | | | | | | | | | |
|
||||||
|
* | | I/O | | | Tile | Tile | ... | Tile | | I/O | |
|
||||||
|
* | | LEFT | | | [i+1]| [i+2]| | [j] | |RIGHT | |
|
||||||
|
* | +------+ | +------+------+-----+------+ +------+ |
|
||||||
|
* | +-------------------------------+ |
|
||||||
|
* | +------+ +------+------+-----+------+ | +------+ |
|
||||||
|
* | | | | | | | | | | | |
|
||||||
|
* | | I/O | | Tile | Tile | ... | Tile | | | I/O | |
|
||||||
|
* | | LEFT | | [0] | [1] | | [i] | | |RIGHT | |
|
||||||
|
* | +------+ +------+------+-----+------+ | +------+ |
|
||||||
|
* +-------------------------------------------+ |
|
||||||
|
* +------+------+-----+------+ |
|
||||||
|
* | I/O | I/O | ... | I/O | |
|
||||||
|
* |BOTTOM|BOTTOM| |BOTTOM| |
|
||||||
|
* +------+------+-----+------+ |
|
||||||
|
* head >-----------------------------------------------+
|
||||||
|
*
|
||||||
|
* Inner tile connection
|
||||||
|
*
|
||||||
|
* Tile
|
||||||
|
* +---------------+----------+
|
||||||
|
* <-+---------------+ + |
|
||||||
|
* | | | |
|
||||||
|
* | CLB | | CBY |
|
||||||
|
* | +-|-+ |
|
||||||
|
* | | | |
|
||||||
|
* +---------------+----------+
|
||||||
|
* | +-+----+-----+---<---
|
||||||
|
* | CBX | SB |
|
||||||
|
* | | |
|
||||||
|
* +---------------+----------+
|
||||||
|
*
|
||||||
|
*******************************************************************/
|
||||||
|
void organize_top_module_memory_modules(const ModuleManager& module_manager,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
const CircuitModelId& sram_model,
|
||||||
|
t_sram_orgz_info* cur_sram_orgz_info,
|
||||||
|
const vtr::Point<size_t>& device_size,
|
||||||
|
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||||
|
const std::vector<std::vector<size_t>>& grid_instance_ids,
|
||||||
|
const DeviceRRGSB& L_device_rr_gsb,
|
||||||
|
const std::vector<std::vector<size_t>>& sb_instance_ids,
|
||||||
|
const std::map<t_rr_type, std::vector<std::vector<size_t>>>& cb_instance_ids,
|
||||||
|
const bool& compact_routing_hierarchy,
|
||||||
|
std::vector<ModuleId>& memory_modules,
|
||||||
|
std::vector<size_t>& memory_instances) {
|
||||||
|
/* Ensure clean vectors to return */
|
||||||
|
VTR_ASSERT(true == memory_modules.empty());
|
||||||
|
VTR_ASSERT(true == memory_instances.empty());
|
||||||
|
|
||||||
|
/* First, organize the I/O tiles on the border */
|
||||||
|
/* Special for the I/O tileas on RIGHT and BOTTOM,
|
||||||
|
* which are only I/O blocks, which do NOT contain CBs and SBs
|
||||||
|
*/
|
||||||
|
std::vector<e_side> io_sides{BOTTOM, RIGHT, TOP, LEFT};
|
||||||
|
std::map<e_side, std::vector<vtr::Point<size_t>>> io_coords;
|
||||||
|
|
||||||
|
/* BOTTOM side I/Os */
|
||||||
|
for (size_t ix = 1; ix < device_size.x() - 1; ++ix) {
|
||||||
|
io_coords[BOTTOM].push_back(vtr::Point<size_t>(ix, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* RIGHT side I/Os */
|
||||||
|
for (size_t iy = 1; iy < device_size.y() - 1; ++iy) {
|
||||||
|
io_coords[RIGHT].push_back(vtr::Point<size_t>(device_size.x() - 1, iy));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TOP side I/Os */
|
||||||
|
for (size_t ix = 1; ix < device_size.x() - 1; ++ix) {
|
||||||
|
io_coords[TOP].push_back(vtr::Point<size_t>(ix, device_size.y() - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* LEFT side I/Os */
|
||||||
|
for (size_t iy = 1; iy < device_size.y() - 1; ++iy) {
|
||||||
|
io_coords[LEFT].push_back(vtr::Point<size_t>(0, iy));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const e_side& io_side : io_sides) {
|
||||||
|
for (const vtr::Point<size_t>& io_coord : io_coords[io_side]) {
|
||||||
|
/* Identify the GSB that surrounds the grid */
|
||||||
|
organize_top_module_tile_memory_modules(module_manager,
|
||||||
|
circuit_lib, sram_model, cur_sram_orgz_info,
|
||||||
|
grids, grid_instance_ids,
|
||||||
|
L_device_rr_gsb, sb_instance_ids, cb_instance_ids,
|
||||||
|
compact_routing_hierarchy,
|
||||||
|
io_coord, io_side,
|
||||||
|
memory_modules, memory_instances);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For the core grids */
|
||||||
|
std::vector<vtr::Point<size_t>> core_coords;
|
||||||
|
bool positive_direction = true;
|
||||||
|
for (size_t iy = 1; iy < device_size.y() - 1; ++iy) {
|
||||||
|
/* For positive direction: -----> */
|
||||||
|
if (true == positive_direction) {
|
||||||
|
for (size_t ix = 1; ix < device_size.x() - 1; ++ix) {
|
||||||
|
core_coords.push_back(vtr::Point<size_t>(ix, iy));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
VTR_ASSERT(false == positive_direction);
|
||||||
|
/* For negative direction: -----> */
|
||||||
|
for (size_t ix = device_size.x() - 2; ix >= 1; --ix) {
|
||||||
|
core_coords.push_back(vtr::Point<size_t>(ix, iy));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Flip the positive direction to be negative */
|
||||||
|
positive_direction = !positive_direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const vtr::Point<size_t>& core_coord : core_coords) {
|
||||||
|
organize_top_module_tile_memory_modules(module_manager,
|
||||||
|
circuit_lib, sram_model, cur_sram_orgz_info,
|
||||||
|
grids, grid_instance_ids,
|
||||||
|
L_device_rr_gsb, sb_instance_ids, cb_instance_ids,
|
||||||
|
compact_routing_hierarchy,
|
||||||
|
core_coord, NUM_SIDES,
|
||||||
|
memory_modules, memory_instances);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
* Add the port-to-port connection between all the memory modules
|
||||||
|
* and their parent module
|
||||||
|
*
|
||||||
|
* Create nets to wire the control signals of memory module to
|
||||||
|
* the configuration ports of primitive module
|
||||||
|
*
|
||||||
|
* Configuration Chain
|
||||||
|
* -------------------
|
||||||
|
*
|
||||||
|
* config_bus (head) config_bus (tail)
|
||||||
|
* | ^
|
||||||
|
* primitive | |
|
||||||
|
* +---------------------------------------------+
|
||||||
|
* | | | |
|
||||||
|
* | v | |
|
||||||
|
* | +-------------------------------------+ |
|
||||||
|
* | | CMOS-based Memory Modules | |
|
||||||
|
* | +-------------------------------------+ |
|
||||||
|
* | | | |
|
||||||
|
* | v v |
|
||||||
|
* | sram_out sram_outb |
|
||||||
|
* | |
|
||||||
|
* +---------------------------------------------+
|
||||||
|
*
|
||||||
|
* Memory bank
|
||||||
|
* -----------
|
||||||
|
*
|
||||||
|
* config_bus (BL) config_bus (WL)
|
||||||
|
* | |
|
||||||
|
* primitive | |
|
||||||
|
* +---------------------------------------------+
|
||||||
|
* | | | |
|
||||||
|
* | v v |
|
||||||
|
* | +-------------------------------------+ |
|
||||||
|
* | | CMOS-based Memory Modules | |
|
||||||
|
* | +-------------------------------------+ |
|
||||||
|
* | | | |
|
||||||
|
* | v v |
|
||||||
|
* | sram_out sram_outb |
|
||||||
|
* | |
|
||||||
|
* +---------------------------------------------+
|
||||||
|
*
|
||||||
|
**********************************************************************/
|
||||||
|
static
|
||||||
|
void add_top_module_nets_cmos_memory_config_bus(ModuleManager& module_manager,
|
||||||
|
const ModuleId& parent_module,
|
||||||
|
const std::vector<ModuleId>& memory_modules,
|
||||||
|
const std::vector<size_t>& memory_instances,
|
||||||
|
const e_sram_orgz& sram_orgz_type) {
|
||||||
|
/* Ensure that the size of memory_model vector matches the memory_module vector */
|
||||||
|
VTR_ASSERT(memory_modules.size() == memory_instances.size());
|
||||||
|
|
||||||
|
switch (sram_orgz_type) {
|
||||||
|
case SPICE_SRAM_STANDALONE:
|
||||||
|
/* Nothing to do */
|
||||||
|
break;
|
||||||
|
case SPICE_SRAM_SCAN_CHAIN: {
|
||||||
|
add_module_nets_cmos_memory_chain_config_bus(module_manager, parent_module, memory_modules, memory_instances, sram_orgz_type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SPICE_SRAM_MEMORY_BANK:
|
||||||
|
/* TODO: */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
vpr_printf(TIO_MESSAGE_ERROR,
|
||||||
|
"(File:%s,[LINE%d])Invalid type of SRAM organization!\n",
|
||||||
|
__FILE__, __LINE__);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* TODO:
|
||||||
|
* Add the port-to-port connection between a memory module
|
||||||
|
* and the configuration bus of a primitive module
|
||||||
|
*
|
||||||
|
* Create nets to wire the control signals of memory module to
|
||||||
|
* the configuration ports of primitive module
|
||||||
|
*
|
||||||
|
* Primitive module
|
||||||
|
* +----------------------------+
|
||||||
|
* | +--------+ |
|
||||||
|
* config | | | |
|
||||||
|
* ports --->|--------------->| Memory | |
|
||||||
|
* | | Module | |
|
||||||
|
* | | | |
|
||||||
|
* | +--------+ |
|
||||||
|
* +----------------------------+
|
||||||
|
* The detailed config ports really depend on the type
|
||||||
|
* of SRAM organization.
|
||||||
|
*
|
||||||
|
* The config_bus in the argument is the reserved address of configuration
|
||||||
|
* bus in the parent_module for this memory module
|
||||||
|
*
|
||||||
|
* The configuration bus connection will depend not only
|
||||||
|
* the design technology of the memory cells but also the
|
||||||
|
* configuration styles of FPGA fabric.
|
||||||
|
* Here we will branch on the design technology
|
||||||
|
*
|
||||||
|
* Note: this function SHOULD be called after the pb_type_module is created
|
||||||
|
* and its child module (logic_module and memory_module) is created!
|
||||||
|
*******************************************************************/
|
||||||
|
void add_top_module_nets_memory_config_bus(ModuleManager& module_manager,
|
||||||
|
const ModuleId& parent_module,
|
||||||
|
const std::vector<ModuleId>& memory_modules,
|
||||||
|
const std::vector<size_t>& memory_instances,
|
||||||
|
const e_sram_orgz& sram_orgz_type,
|
||||||
|
const e_spice_model_design_tech& mem_tech) {
|
||||||
|
switch (mem_tech) {
|
||||||
|
case SPICE_MODEL_DESIGN_CMOS:
|
||||||
|
add_top_module_nets_cmos_memory_config_bus(module_manager, parent_module,
|
||||||
|
memory_modules, memory_instances,
|
||||||
|
sram_orgz_type);
|
||||||
|
break;
|
||||||
|
case SPICE_MODEL_DESIGN_RRAM:
|
||||||
|
/* TODO: */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
vpr_printf(TIO_MESSAGE_ERROR,
|
||||||
|
"(File:%s,[LINE%d])Invalid type of memory design technology !\n",
|
||||||
|
__FILE__, __LINE__);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
#ifndef BUILD_TOP_MODULE_MEMORY_H
|
||||||
|
#define BUILD_TOP_MODULE_MEMORY_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include "module_manager.h"
|
||||||
|
#include "spice_types.h"
|
||||||
|
#include "circuit_library.h"
|
||||||
|
#include "rr_blocks.h"
|
||||||
|
|
||||||
|
void organize_top_module_memory_modules(const ModuleManager& module_manager,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
const CircuitModelId& sram_model,
|
||||||
|
t_sram_orgz_info* cur_sram_orgz_info,
|
||||||
|
const vtr::Point<size_t>& device_size,
|
||||||
|
const std::vector<std::vector<t_grid_tile>>& grids,
|
||||||
|
const std::vector<std::vector<size_t>>& grid_instance_ids,
|
||||||
|
const DeviceRRGSB& L_device_rr_gsb,
|
||||||
|
const std::vector<std::vector<size_t>>& sb_instance_ids,
|
||||||
|
const std::map<t_rr_type, std::vector<std::vector<size_t>>>& cb_instance_ids,
|
||||||
|
const bool& compact_routing_hierarchy,
|
||||||
|
std::vector<ModuleId>& memory_modules,
|
||||||
|
std::vector<size_t>& memory_instances);
|
||||||
|
|
||||||
|
void add_top_module_nets_memory_config_bus(ModuleManager& module_manager,
|
||||||
|
const ModuleId& parent_module,
|
||||||
|
const std::vector<ModuleId>& memory_modules,
|
||||||
|
const std::vector<size_t>& memory_instances,
|
||||||
|
const e_sram_orgz& sram_orgz_type,
|
||||||
|
const e_spice_model_design_tech& mem_tech);
|
||||||
|
|
||||||
|
#endif
|
|
@ -565,6 +565,113 @@ void add_module_nets_between_logic_and_memory_sram_bus(ModuleManager& module_man
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Connect all the memory modules under the parent module in a chain
|
||||||
|
*
|
||||||
|
* +--------+ +--------+ +--------+
|
||||||
|
* ccff_head --->| Memory |--->| Memory |--->... --->| Memory |----> ccff_tail
|
||||||
|
* | Module | | Module | | Module |
|
||||||
|
* | [0] | | [1] | | [N-1] |
|
||||||
|
* +--------+ +--------+ +--------+
|
||||||
|
* For the 1st memory module:
|
||||||
|
* net source is the configuration chain head of the primitive module
|
||||||
|
* net sink is the configuration chain head of the next memory module
|
||||||
|
*
|
||||||
|
* For the rest of memory modules:
|
||||||
|
* net source is the configuration chain tail of the previous memory module
|
||||||
|
* net sink is the configuration chain head of the next memory module
|
||||||
|
*/
|
||||||
|
void add_module_nets_cmos_memory_chain_config_bus(ModuleManager& module_manager,
|
||||||
|
const ModuleId& parent_module,
|
||||||
|
const std::vector<ModuleId>& memory_modules,
|
||||||
|
const std::vector<size_t>& memory_instances,
|
||||||
|
const e_sram_orgz& sram_orgz_type) {
|
||||||
|
for (size_t mem_index = 0; mem_index < memory_modules.size(); ++mem_index) {
|
||||||
|
ModuleId net_src_module_id;
|
||||||
|
size_t net_src_instance_id;
|
||||||
|
ModulePortId net_src_port_id;
|
||||||
|
|
||||||
|
ModuleId net_sink_module_id;
|
||||||
|
size_t net_sink_instance_id;
|
||||||
|
ModulePortId net_sink_port_id;
|
||||||
|
|
||||||
|
if (0 == mem_index) {
|
||||||
|
/* Find the port name of configuration chain head */
|
||||||
|
std::string src_port_name = generate_sram_port_name(sram_orgz_type, SPICE_MODEL_PORT_INPUT);
|
||||||
|
net_src_module_id = parent_module;
|
||||||
|
net_src_instance_id = 0;
|
||||||
|
net_src_port_id = module_manager.find_module_port(net_src_module_id, src_port_name);
|
||||||
|
|
||||||
|
/* Find the port name of next memory module */
|
||||||
|
std::string sink_port_name = generate_configuration_chain_head_name();
|
||||||
|
net_sink_module_id = memory_modules[mem_index];
|
||||||
|
net_sink_instance_id = memory_instances[mem_index];
|
||||||
|
net_sink_port_id = module_manager.find_module_port(net_sink_module_id, sink_port_name);
|
||||||
|
} else {
|
||||||
|
/* Find the port name of previous memory module */
|
||||||
|
std::string src_port_name = generate_configuration_chain_tail_name();
|
||||||
|
net_src_module_id = memory_modules[mem_index - 1];
|
||||||
|
net_src_instance_id = memory_instances[mem_index - 1];
|
||||||
|
net_src_port_id = module_manager.find_module_port(net_src_module_id, src_port_name);
|
||||||
|
|
||||||
|
/* Find the port name of next memory module */
|
||||||
|
std::string sink_port_name = generate_configuration_chain_head_name();
|
||||||
|
net_sink_module_id = memory_modules[mem_index];
|
||||||
|
net_sink_instance_id = memory_instances[mem_index];
|
||||||
|
net_sink_port_id = module_manager.find_module_port(net_sink_module_id, sink_port_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the pin id for source port */
|
||||||
|
BasicPort net_src_port = module_manager.module_port(net_src_module_id, net_src_port_id);
|
||||||
|
/* Get the pin id for sink port */
|
||||||
|
BasicPort net_sink_port = module_manager.module_port(net_sink_module_id, net_sink_port_id);
|
||||||
|
/* Port sizes of source and sink should match */
|
||||||
|
VTR_ASSERT(net_src_port.get_width() == net_sink_port.get_width());
|
||||||
|
|
||||||
|
/* Create a net for each pin */
|
||||||
|
for (size_t pin_id = 0; pin_id < net_src_port.pins().size(); ++pin_id) {
|
||||||
|
/* Create a net and add source and sink to it */
|
||||||
|
ModuleNetId net = module_manager.create_module_net(parent_module);
|
||||||
|
/* Add net source */
|
||||||
|
module_manager.add_module_net_source(parent_module, net, net_src_module_id, net_src_instance_id, net_src_port_id, net_src_port.pins()[pin_id]);
|
||||||
|
/* Add net sink */
|
||||||
|
module_manager.add_module_net_sink(parent_module, net, net_sink_module_id, net_sink_instance_id, net_sink_port_id, net_sink_port.pins()[pin_id]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For the last memory module:
|
||||||
|
* net source is the configuration chain tail of the previous memory module
|
||||||
|
* net sink is the configuration chain tail of the primitive module
|
||||||
|
*/
|
||||||
|
/* Find the port name of previous memory module */
|
||||||
|
std::string src_port_name = generate_configuration_chain_tail_name();
|
||||||
|
ModuleId net_src_module_id = memory_modules.back();
|
||||||
|
size_t net_src_instance_id = memory_instances.back();
|
||||||
|
ModulePortId net_src_port_id = module_manager.find_module_port(net_src_module_id, src_port_name);
|
||||||
|
|
||||||
|
/* Find the port name of next memory module */
|
||||||
|
std::string sink_port_name = generate_sram_port_name(sram_orgz_type, SPICE_MODEL_PORT_OUTPUT);
|
||||||
|
ModuleId net_sink_module_id = parent_module;
|
||||||
|
size_t net_sink_instance_id = 0;
|
||||||
|
ModulePortId net_sink_port_id = module_manager.find_module_port(net_sink_module_id, sink_port_name);
|
||||||
|
|
||||||
|
/* Get the pin id for source port */
|
||||||
|
BasicPort net_src_port = module_manager.module_port(net_src_module_id, net_src_port_id);
|
||||||
|
/* Get the pin id for sink port */
|
||||||
|
BasicPort net_sink_port = module_manager.module_port(net_sink_module_id, net_sink_port_id);
|
||||||
|
/* Port sizes of source and sink should match */
|
||||||
|
VTR_ASSERT(net_src_port.get_width() == net_sink_port.get_width());
|
||||||
|
|
||||||
|
/* Create a net for each pin */
|
||||||
|
for (size_t pin_id = 0; pin_id < net_src_port.pins().size(); ++pin_id) {
|
||||||
|
/* Create a net and add source and sink to it */
|
||||||
|
ModuleNetId net = module_manager.create_module_net(parent_module);
|
||||||
|
/* Add net source */
|
||||||
|
module_manager.add_module_net_source(parent_module, net, net_src_module_id, net_src_instance_id, net_src_port_id, net_src_port.pins()[pin_id]);
|
||||||
|
/* Add net sink */
|
||||||
|
module_manager.add_module_net_sink(parent_module, net, net_sink_module_id, net_sink_instance_id, net_sink_port_id, net_sink_port.pins()[pin_id]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*********************************************************************
|
/*********************************************************************
|
||||||
* Add the port-to-port connection between all the memory modules
|
* Add the port-to-port connection between all the memory modules
|
||||||
* and their parent module
|
* and their parent module
|
||||||
|
@ -623,106 +730,7 @@ void add_module_nets_cmos_memory_config_bus(ModuleManager& module_manager,
|
||||||
/* Nothing to do */
|
/* Nothing to do */
|
||||||
break;
|
break;
|
||||||
case SPICE_SRAM_SCAN_CHAIN: {
|
case SPICE_SRAM_SCAN_CHAIN: {
|
||||||
/* Connect all the memory modules under the parent module in a chain
|
add_module_nets_cmos_memory_chain_config_bus(module_manager, parent_module, memory_modules, memory_instances, sram_orgz_type);
|
||||||
*
|
|
||||||
* +--------+ +--------+ +--------+
|
|
||||||
* ccff_head --->| Memory |--->| Memory |--->... --->| Memory |----> ccff_tail
|
|
||||||
* | Module | | Module | | Module |
|
|
||||||
* | [0] | | [1] | | [N-1] |
|
|
||||||
* +--------+ +--------+ +--------+
|
|
||||||
* For the 1st memory module:
|
|
||||||
* net source is the configuration chain head of the primitive module
|
|
||||||
* net sink is the configuration chain head of the next memory module
|
|
||||||
*
|
|
||||||
* For the rest of memory modules:
|
|
||||||
* net source is the configuration chain tail of the previous memory module
|
|
||||||
* net sink is the configuration chain head of the next memory module
|
|
||||||
*/
|
|
||||||
for (size_t mem_index = 0; mem_index < memory_modules.size(); ++mem_index) {
|
|
||||||
ModuleId net_src_module_id;
|
|
||||||
size_t net_src_instance_id;
|
|
||||||
ModulePortId net_src_port_id;
|
|
||||||
|
|
||||||
ModuleId net_sink_module_id;
|
|
||||||
size_t net_sink_instance_id;
|
|
||||||
ModulePortId net_sink_port_id;
|
|
||||||
|
|
||||||
if (0 == mem_index) {
|
|
||||||
/* Find the port name of configuration chain head */
|
|
||||||
std::string src_port_name = generate_sram_port_name(sram_orgz_type, SPICE_MODEL_PORT_INPUT);
|
|
||||||
net_src_module_id = parent_module;
|
|
||||||
net_src_instance_id = 0;
|
|
||||||
net_src_port_id = module_manager.find_module_port(net_src_module_id, src_port_name);
|
|
||||||
|
|
||||||
/* Find the port name of next memory module */
|
|
||||||
std::string sink_port_name = generate_configuration_chain_head_name();
|
|
||||||
net_sink_module_id = memory_modules[mem_index];
|
|
||||||
net_sink_instance_id = memory_instances[mem_index];
|
|
||||||
net_sink_port_id = module_manager.find_module_port(net_sink_module_id, sink_port_name);
|
|
||||||
} else {
|
|
||||||
/* Find the port name of previous memory module */
|
|
||||||
std::string src_port_name = generate_configuration_chain_tail_name();
|
|
||||||
net_src_module_id = memory_modules[mem_index - 1];
|
|
||||||
net_src_instance_id = memory_instances[mem_index - 1];
|
|
||||||
net_src_port_id = module_manager.find_module_port(net_src_module_id, src_port_name);
|
|
||||||
|
|
||||||
/* Find the port name of next memory module */
|
|
||||||
std::string sink_port_name = generate_configuration_chain_head_name();
|
|
||||||
net_sink_module_id = memory_modules[mem_index];
|
|
||||||
net_sink_instance_id = memory_instances[mem_index];
|
|
||||||
net_sink_port_id = module_manager.find_module_port(net_sink_module_id, sink_port_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get the pin id for source port */
|
|
||||||
BasicPort net_src_port = module_manager.module_port(net_src_module_id, net_src_port_id);
|
|
||||||
/* Get the pin id for sink port */
|
|
||||||
BasicPort net_sink_port = module_manager.module_port(net_sink_module_id, net_sink_port_id);
|
|
||||||
/* Port sizes of source and sink should match */
|
|
||||||
VTR_ASSERT(net_src_port.get_width() == net_sink_port.get_width());
|
|
||||||
|
|
||||||
/* Create a net for each pin */
|
|
||||||
for (size_t pin_id = 0; pin_id < net_src_port.pins().size(); ++pin_id) {
|
|
||||||
/* Create a net and add source and sink to it */
|
|
||||||
ModuleNetId net = module_manager.create_module_net(parent_module);
|
|
||||||
/* Add net source */
|
|
||||||
module_manager.add_module_net_source(parent_module, net, net_src_module_id, net_src_instance_id, net_src_port_id, net_src_port.pins()[pin_id]);
|
|
||||||
/* Add net sink */
|
|
||||||
module_manager.add_module_net_sink(parent_module, net, net_sink_module_id, net_sink_instance_id, net_sink_port_id, net_sink_port.pins()[pin_id]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* For the last memory module:
|
|
||||||
* net source is the configuration chain tail of the previous memory module
|
|
||||||
* net sink is the configuration chain tail of the primitive module
|
|
||||||
*/
|
|
||||||
/* Find the port name of previous memory module */
|
|
||||||
std::string src_port_name = generate_configuration_chain_tail_name();
|
|
||||||
ModuleId net_src_module_id = memory_modules.back();
|
|
||||||
size_t net_src_instance_id = memory_instances.back();
|
|
||||||
ModulePortId net_src_port_id = module_manager.find_module_port(net_src_module_id, src_port_name);
|
|
||||||
|
|
||||||
/* Find the port name of next memory module */
|
|
||||||
std::string sink_port_name = generate_sram_port_name(sram_orgz_type, SPICE_MODEL_PORT_OUTPUT);
|
|
||||||
ModuleId net_sink_module_id = parent_module;
|
|
||||||
size_t net_sink_instance_id = 0;
|
|
||||||
ModulePortId net_sink_port_id = module_manager.find_module_port(net_sink_module_id, sink_port_name);
|
|
||||||
|
|
||||||
/* Get the pin id for source port */
|
|
||||||
BasicPort net_src_port = module_manager.module_port(net_src_module_id, net_src_port_id);
|
|
||||||
/* Get the pin id for sink port */
|
|
||||||
BasicPort net_sink_port = module_manager.module_port(net_sink_module_id, net_sink_port_id);
|
|
||||||
/* Port sizes of source and sink should match */
|
|
||||||
VTR_ASSERT(net_src_port.get_width() == net_sink_port.get_width());
|
|
||||||
|
|
||||||
/* Create a net for each pin */
|
|
||||||
for (size_t pin_id = 0; pin_id < net_src_port.pins().size(); ++pin_id) {
|
|
||||||
/* Create a net and add source and sink to it */
|
|
||||||
ModuleNetId net = module_manager.create_module_net(parent_module);
|
|
||||||
/* Add net source */
|
|
||||||
module_manager.add_module_net_source(parent_module, net, net_src_module_id, net_src_instance_id, net_src_port_id, net_src_port.pins()[pin_id]);
|
|
||||||
/* Add net sink */
|
|
||||||
module_manager.add_module_net_sink(parent_module, net, net_sink_module_id, net_sink_instance_id, net_sink_port_id, net_sink_port.pins()[pin_id]);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SPICE_SRAM_MEMORY_BANK:
|
case SPICE_SRAM_MEMORY_BANK:
|
||||||
|
|
|
@ -69,6 +69,12 @@ void add_module_nets_between_logic_and_memory_sram_bus(ModuleManager& module_man
|
||||||
const CircuitLibrary& circuit_lib,
|
const CircuitLibrary& circuit_lib,
|
||||||
const CircuitModelId& logic_model);
|
const CircuitModelId& logic_model);
|
||||||
|
|
||||||
|
void add_module_nets_cmos_memory_chain_config_bus(ModuleManager& module_manager,
|
||||||
|
const ModuleId& parent_module,
|
||||||
|
const std::vector<ModuleId>& memory_modules,
|
||||||
|
const std::vector<size_t>& memory_instances,
|
||||||
|
const e_sram_orgz& sram_orgz_type);
|
||||||
|
|
||||||
void add_module_nets_memory_config_bus(ModuleManager& module_manager,
|
void add_module_nets_memory_config_bus(ModuleManager& module_manager,
|
||||||
const ModuleId& parent_module,
|
const ModuleId& parent_module,
|
||||||
const std::vector<ModuleId>& memory_modules,
|
const std::vector<ModuleId>& memory_modules,
|
||||||
|
|
|
@ -2449,7 +2449,7 @@ const RRGSB& DeviceRRGSB::get_cb_unique_module(t_rr_type cb_type, size_t index)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Give a coordinator of a rr switch block, and return its unique mirror */
|
/* Give a coordinator of a rr switch block, and return its unique mirror */
|
||||||
const RRGSB& DeviceRRGSB::get_cb_unique_module(t_rr_type cb_type, DeviceCoordinator& coordinator) const {
|
const RRGSB& DeviceRRGSB::get_cb_unique_module(t_rr_type cb_type, const DeviceCoordinator& coordinator) const {
|
||||||
assert (validate_cb_type(cb_type));
|
assert (validate_cb_type(cb_type));
|
||||||
assert(validate_coordinator(coordinator));
|
assert(validate_coordinator(coordinator));
|
||||||
size_t cb_unique_module_id;
|
size_t cb_unique_module_id;
|
||||||
|
@ -2472,7 +2472,7 @@ const RRGSB& DeviceRRGSB::get_cb_unique_module(t_rr_type cb_type, DeviceCoordina
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Give a coordinator of a rr switch block, and return its unique mirror */
|
/* Give a coordinator of a rr switch block, and return its unique mirror */
|
||||||
const RRGSB DeviceRRGSB::get_sb_unique_module(DeviceCoordinator& coordinator) const {
|
const RRGSB DeviceRRGSB::get_sb_unique_module(const DeviceCoordinator& coordinator) const {
|
||||||
assert(validate_coordinator(coordinator));
|
assert(validate_coordinator(coordinator));
|
||||||
size_t sb_unique_module_id = sb_unique_module_id_[coordinator.get_x()][coordinator.get_y()];
|
size_t sb_unique_module_id = sb_unique_module_id_[coordinator.get_x()][coordinator.get_y()];
|
||||||
return get_sb_unique_module(sb_unique_module_id);
|
return get_sb_unique_module(sb_unique_module_id);
|
||||||
|
|
|
@ -338,9 +338,9 @@ class DeviceRRGSB {
|
||||||
const RRGSB get_sb_unique_submodule(size_t index, enum e_side side, size_t seg_id) const; /* Get a rr switch block which a unique mirror */
|
const RRGSB get_sb_unique_submodule(size_t index, enum e_side side, size_t seg_id) const; /* Get a rr switch block which a unique mirror */
|
||||||
const RRGSB get_sb_unique_submodule(DeviceCoordinator& coordinator, enum e_side side, size_t seg_id) const; /* Get a rr switch block which a unique mirror */
|
const RRGSB get_sb_unique_submodule(DeviceCoordinator& coordinator, enum e_side side, size_t seg_id) const; /* Get a rr switch block which a unique mirror */
|
||||||
const RRGSB get_sb_unique_module(size_t index) const; /* Get a rr switch block which a unique mirror */
|
const RRGSB get_sb_unique_module(size_t index) const; /* Get a rr switch block which a unique mirror */
|
||||||
const RRGSB get_sb_unique_module(DeviceCoordinator& coordinator) const; /* Get a rr switch block which a unique mirror */
|
const RRGSB get_sb_unique_module(const DeviceCoordinator& coordinator) const; /* Get a rr switch block which a unique mirror */
|
||||||
const RRGSB& get_cb_unique_module(t_rr_type cb_type, size_t index) const; /* Get a rr switch block which a unique mirror */
|
const RRGSB& get_cb_unique_module(t_rr_type cb_type, size_t index) const; /* Get a rr switch block which a unique mirror */
|
||||||
const RRGSB& get_cb_unique_module(t_rr_type cb_type, DeviceCoordinator& coordinator) const;
|
const RRGSB& get_cb_unique_module(t_rr_type cb_type, const DeviceCoordinator& coordinator) const;
|
||||||
size_t get_max_num_sides() const; /* Get the maximum number of sides across the switch blocks */
|
size_t get_max_num_sides() const; /* Get the maximum number of sides across the switch blocks */
|
||||||
size_t get_num_segments() const; /* Get the size of segment_ids */
|
size_t get_num_segments() const; /* Get the size of segment_ids */
|
||||||
size_t get_segment_id(size_t index) const; /* Get a segment id */
|
size_t get_segment_id(size_t index) const; /* Get a segment id */
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
#include "fpga_x2p_utils.h"
|
#include "fpga_x2p_utils.h"
|
||||||
#include "fpga_x2p_pbtypes_utils.h"
|
#include "fpga_x2p_pbtypes_utils.h"
|
||||||
#include "module_manager_utils.h"
|
#include "module_manager_utils.h"
|
||||||
|
#include "build_top_module_memory.h"
|
||||||
|
#include "build_top_module_directs.h"
|
||||||
|
|
||||||
#include "verilog_global.h"
|
#include "verilog_global.h"
|
||||||
#include "verilog_routing.h"
|
#include "verilog_routing.h"
|
||||||
|
@ -22,15 +24,6 @@
|
||||||
#include "verilog_module_writer.h"
|
#include "verilog_module_writer.h"
|
||||||
#include "verilog_top_module.h"
|
#include "verilog_top_module.h"
|
||||||
|
|
||||||
/********************************************************************
|
|
||||||
* Check if the grid coorindate given is in the device grid range
|
|
||||||
*******************************************************************/
|
|
||||||
static
|
|
||||||
bool is_grid_coordinate_exist_in_device(const vtr::Point<size_t>& device_size,
|
|
||||||
const vtr::Point<size_t>& grid_coordinate) {
|
|
||||||
return (grid_coordinate < device_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* Generate the name for a grid block, by considering
|
* Generate the name for a grid block, by considering
|
||||||
* 1. if it locates on the border with given device size
|
* 1. if it locates on the border with given device size
|
||||||
|
@ -236,6 +229,7 @@ std::vector<std::vector<size_t>> add_top_module_switch_block_instances(ModuleMan
|
||||||
const ModuleId& top_module,
|
const ModuleId& top_module,
|
||||||
const DeviceRRGSB& L_device_rr_gsb,
|
const DeviceRRGSB& L_device_rr_gsb,
|
||||||
const bool& compact_routing_hierarchy) {
|
const bool& compact_routing_hierarchy) {
|
||||||
|
/* TODO: deprecate DeviceCoordinator, use vtr::Point<size_t> only! */
|
||||||
DeviceCoordinator sb_range = L_device_rr_gsb.get_gsb_range();
|
DeviceCoordinator sb_range = L_device_rr_gsb.get_gsb_range();
|
||||||
|
|
||||||
/* Reserve an array for the instance ids */
|
/* Reserve an array for the instance ids */
|
||||||
|
@ -798,540 +792,6 @@ void add_top_module_nets_connect_grids_and_gsbs(ModuleManager& module_manager,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************
|
|
||||||
* 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_clb2clb_direct_connection(ModuleManager& module_manager,
|
|
||||||
const ModuleId& top_module,
|
|
||||||
const CircuitLibrary& circuit_lib,
|
|
||||||
const vtr::Point<size_t>& device_size,
|
|
||||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
|
||||||
const std::vector<std::vector<size_t>>& grid_instance_ids,
|
|
||||||
const vtr::Point<size_t>& src_clb_coord,
|
|
||||||
const vtr::Point<size_t>& des_clb_coord,
|
|
||||||
const t_clb_to_clb_directs& direct) {
|
|
||||||
/* Find the source port and destination port on the CLBs */
|
|
||||||
BasicPort src_clb_port;
|
|
||||||
BasicPort des_clb_port;
|
|
||||||
|
|
||||||
src_clb_port.set_width(direct.from_clb_pin_start_index, direct.from_clb_pin_end_index);
|
|
||||||
des_clb_port.set_width(direct.to_clb_pin_start_index, direct.to_clb_pin_end_index);
|
|
||||||
|
|
||||||
/* Check bandwidth match between from_clb and to_clb pins */
|
|
||||||
if (src_clb_port.get_width() != des_clb_port.get_width()) {
|
|
||||||
vpr_printf(TIO_MESSAGE_ERROR,
|
|
||||||
"(File:%s, [LINE%d]) Unmatch pin bandwidth in direct connection (name=%s)!\n",
|
|
||||||
__FILE__, __LINE__, direct.name);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find the module name of source clb */
|
|
||||||
t_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_verilog_file_name_prefix);
|
|
||||||
std::string src_module_name = generate_grid_block_module_name(src_module_name_prefix, std::string(src_grid_type->name), 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 */
|
|
||||||
t_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_verilog_file_name_prefix);
|
|
||||||
std::string sink_module_name = generate_grid_block_module_name(sink_module_name_prefix, std::string(sink_grid_type->name), 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 */
|
|
||||||
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, SPICE_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_lib_name(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, SPICE_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_lib_name(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());
|
|
||||||
|
|
||||||
for (size_t pin_id : src_clb_port.pins()) {
|
|
||||||
/* Generate the pin name of source port/pin in the grid */
|
|
||||||
size_t src_pin_height = find_grid_pin_height(grids, src_clb_coord, src_clb_port.pins()[pin_id]);
|
|
||||||
e_side src_pin_grid_side = find_grid_pin_side(device_size, grids, src_clb_coord, src_pin_height, src_clb_port.pins()[pin_id]);
|
|
||||||
std::string src_port_name = generate_grid_port_name(src_clb_coord, src_pin_height, src_pin_grid_side, src_clb_port.pins()[pin_id], 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 */
|
|
||||||
size_t sink_pin_height = find_grid_pin_height(grids, des_clb_coord, des_clb_port.pins()[pin_id]);
|
|
||||||
e_side sink_pin_grid_side = find_grid_pin_side(device_size, grids, des_clb_coord, sink_pin_height, des_clb_port.pins()[pin_id]);
|
|
||||||
std::string sink_port_name = generate_grid_port_name(des_clb_coord, sink_pin_height, sink_pin_grid_side, des_clb_port.pins()[pin_id], 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
|
|
||||||
*
|
|
||||||
* This function supports the following type of direct connection:
|
|
||||||
* 1. Direct connection between grids in the same column or row
|
|
||||||
* +------+ +------+
|
|
||||||
* | | | |
|
|
||||||
* | Grid |----->| Grid |
|
|
||||||
* | | | |
|
|
||||||
* +------+ +------+
|
|
||||||
* | direction connection
|
|
||||||
* v
|
|
||||||
* +------+
|
|
||||||
* | |
|
|
||||||
* | Grid |
|
|
||||||
* | |
|
|
||||||
* +------+
|
|
||||||
*
|
|
||||||
*******************************************************************/
|
|
||||||
static
|
|
||||||
void add_top_module_nets_intra_clb2clb_direct_connections(ModuleManager& module_manager,
|
|
||||||
const ModuleId& top_module,
|
|
||||||
const CircuitLibrary& circuit_lib,
|
|
||||||
const vtr::Point<size_t>& device_size,
|
|
||||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
|
||||||
const std::vector<std::vector<size_t>>& grid_instance_ids,
|
|
||||||
const std::vector<t_clb_to_clb_directs>& clb2clb_directs) {
|
|
||||||
/* Scan the grid, visit each grid and apply direct connections */
|
|
||||||
for (size_t ix = 0; ix < device_size.x(); ++ix) {
|
|
||||||
for (size_t iy = 0; iy < device_size.y(); ++iy) {
|
|
||||||
/* Bypass EMPTY_TYPE*/
|
|
||||||
if ( (NULL == grids[ix][iy].type)
|
|
||||||
|| (EMPTY_TYPE == grids[ix][iy].type)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* Bypass any grid with a non-zero offset! They have been visited in the offset=0 case */
|
|
||||||
if (0 != grids[ix][iy].offset) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* Check each clb2clb directs by comparing the source and destination clb types
|
|
||||||
* Direct connections are made only for those matched clbs
|
|
||||||
*/
|
|
||||||
for (const t_clb_to_clb_directs& direct : clb2clb_directs) {
|
|
||||||
/* Bypass unmatched clb type */
|
|
||||||
if (grids[ix][iy].type != direct.from_clb_type) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* See if the destination CLB is in the bound */
|
|
||||||
vtr::Point<size_t> src_clb_coord(ix, iy);
|
|
||||||
vtr::Point<size_t> des_clb_coord(ix + direct.x_offset, iy + direct.y_offset);
|
|
||||||
if (false == is_grid_coordinate_exist_in_device(device_size, des_clb_coord)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if the destination clb_type matches */
|
|
||||||
if (grids[des_clb_coord.x()][des_clb_coord.y()].type == direct.to_clb_type) {
|
|
||||||
/* Add a module net for a direct connection with the two grids in top_model */
|
|
||||||
add_module_nets_clb2clb_direct_connection(module_manager, top_module, circuit_lib,
|
|
||||||
device_size, grids, grid_instance_ids,
|
|
||||||
src_clb_coord, des_clb_coord,
|
|
||||||
direct);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/********************************************************************
|
|
||||||
* 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 vtr::Point<size_t>& device_size,
|
|
||||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
|
||||||
const std::vector<vtr::Point<size_t>>& candidate_coords,
|
|
||||||
t_type_ptr wanted_grid_type) {
|
|
||||||
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(device_size, coord)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (wanted_grid_type == grids[coord.x()][coord.y()].type) {
|
|
||||||
return coord;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Return an valid coordinate */
|
|
||||||
return vtr::Point<size_t>(size_t(-1), size_t(-1));
|
|
||||||
}
|
|
||||||
|
|
||||||
/********************************************************************
|
|
||||||
* Find the coordinate of the destination clb/heterogeneous block
|
|
||||||
* considering intra column/row direct connections in core grids
|
|
||||||
*******************************************************************/
|
|
||||||
static
|
|
||||||
vtr::Point<size_t> find_intra_direct_destination_coordinate(const vtr::Point<size_t>& device_size,
|
|
||||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
|
||||||
const vtr::Point<size_t> src_coord,
|
|
||||||
const t_clb_to_clb_directs& direct) {
|
|
||||||
vtr::Point<size_t> des_coord(size_t(-1), size_t(-1));
|
|
||||||
t_type_ptr src_grid_type = grids[src_coord.x()][src_coord.y()].type;
|
|
||||||
|
|
||||||
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 (P2P_DIRECT_COLUMN == direct.interconnection_type) {
|
|
||||||
if (POSITIVE_DIR == direct.x_dir) {
|
|
||||||
/* Our first search space will be in x-direction:
|
|
||||||
*
|
|
||||||
* x ... nx
|
|
||||||
* +-----+
|
|
||||||
* |Grid | ----->
|
|
||||||
* +-----+
|
|
||||||
*/
|
|
||||||
for (size_t ix = src_coord.x() + 1; ix < device_size.x() - 1; ++ix) {
|
|
||||||
first_search_space.push_back(ix);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
VTR_ASSERT(NEGATIVE_DIR == direct.x_dir);
|
|
||||||
/* 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 < device_size.y() - 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 == direct.y_dir) {
|
|
||||||
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 (P2P_DIRECT_ROW == direct.interconnection_type) {
|
|
||||||
if (POSITIVE_DIR == direct.y_dir) {
|
|
||||||
/* Our first search space will be in y-direction:
|
|
||||||
*
|
|
||||||
* +------+
|
|
||||||
* | Grid | ny
|
|
||||||
* +------+
|
|
||||||
* ^ .
|
|
||||||
* | .
|
|
||||||
* | .
|
|
||||||
* +------+
|
|
||||||
* | Grid | y
|
|
||||||
* +------+
|
|
||||||
*/
|
|
||||||
for (size_t iy = src_coord.y() + 1; iy < device_size.y() - 1; ++iy) {
|
|
||||||
first_search_space.push_back(iy);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
VTR_ASSERT(NEGATIVE_DIR == direct.y_dir);
|
|
||||||
/* 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 < device_size.x() - 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 == direct.x_dir) {
|
|
||||||
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 (P2P_DIRECT_COLUMN == direct.interconnection_type) {
|
|
||||||
next_col_row_coords.push_back(vtr::Point<size_t>(ix, iy));
|
|
||||||
} else {
|
|
||||||
VTR_ASSERT(P2P_DIRECT_ROW == direct.interconnection_type);
|
|
||||||
/* 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(device_size, grids, next_col_row_coords, src_grid_type);
|
|
||||||
/* For a valid coordinate, we can return */
|
|
||||||
if ( (size_t(-1) != des_coord_cand.x())
|
|
||||||
&& (size_t(-1) != des_coord_cand.y()) ) {
|
|
||||||
return des_coord_cand;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return des_coord;
|
|
||||||
}
|
|
||||||
|
|
||||||
/********************************************************************
|
|
||||||
* 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
|
|
||||||
*
|
|
||||||
* This function supports the following type of direct connection:
|
|
||||||
*
|
|
||||||
* 1. Direct connections across columns and rows
|
|
||||||
* +------+
|
|
||||||
* | |
|
|
||||||
* | v
|
|
||||||
* +------+ | +------+
|
|
||||||
* | | | | |
|
|
||||||
* | Grid | | | Grid |
|
|
||||||
* | | | | |
|
|
||||||
* +------+ | +------+
|
|
||||||
* |
|
|
||||||
* +------+ | +------+
|
|
||||||
* | | | | |
|
|
||||||
* | 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
|
|
||||||
void add_top_module_nets_inter_clb2clb_direct_connections(ModuleManager& module_manager,
|
|
||||||
const ModuleId& top_module,
|
|
||||||
const CircuitLibrary& circuit_lib,
|
|
||||||
const vtr::Point<size_t>& device_size,
|
|
||||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
|
||||||
const std::vector<std::vector<size_t>>& grid_instance_ids,
|
|
||||||
const std::vector<t_clb_to_clb_directs>& clb2clb_directs) {
|
|
||||||
|
|
||||||
std::vector<e_side> border_sides = {TOP, RIGHT, BOTTOM, LEFT};
|
|
||||||
|
|
||||||
/* Go through the direct connection list, see if we need intra-column/row connection here */
|
|
||||||
for (const t_clb_to_clb_directs& direct: clb2clb_directs) {
|
|
||||||
if ( (P2P_DIRECT_COLUMN != direct.interconnection_type)
|
|
||||||
&& (P2P_DIRECT_ROW != direct.interconnection_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 (P2P_DIRECT_COLUMN == direct.interconnection_type) {
|
|
||||||
for (size_t ix = 1; ix < device_size.x() - 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_size.y() - 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 == direct.y_dir) {
|
|
||||||
std::reverse(next_col_src_grid_coords.begin(), next_col_src_grid_coords.end());
|
|
||||||
}
|
|
||||||
vtr::Point<size_t> src_clb_coord = find_grid_coordinate_given_type(device_size, grids, next_col_src_grid_coords, direct.from_clb_type);
|
|
||||||
/* Skip if we do not have a valid coordinate for source CLB/heterogeneous block */
|
|
||||||
if ( (size_t(-1) == src_clb_coord.x())
|
|
||||||
|| (size_t(-1) == src_clb_coord.y()) ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* For a valid coordinate, we can find the coordinate of the destination clb */
|
|
||||||
vtr::Point<size_t> des_clb_coord = find_intra_direct_destination_coordinate(device_size, grids, src_clb_coord, direct);
|
|
||||||
/* If destination clb is valid, we should add something */
|
|
||||||
if ( (size_t(-1) == des_clb_coord.x())
|
|
||||||
|| (size_t(-1) == des_clb_coord.y()) ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
add_module_nets_clb2clb_direct_connection(module_manager, top_module, circuit_lib,
|
|
||||||
device_size, grids, grid_instance_ids,
|
|
||||||
src_clb_coord, des_clb_coord,
|
|
||||||
direct);
|
|
||||||
}
|
|
||||||
continue; /* Go to next direct type */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Reach here, it must be a cross-row connection */
|
|
||||||
VTR_ASSERT(P2P_DIRECT_ROW == direct.interconnection_type);
|
|
||||||
/* 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_size.y() - 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_size.x() - 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 == direct.x_dir) {
|
|
||||||
std::reverse(next_col_src_grid_coords.begin(), next_col_src_grid_coords.end());
|
|
||||||
}
|
|
||||||
vtr::Point<size_t> src_clb_coord = find_grid_coordinate_given_type(device_size, grids, next_col_src_grid_coords, direct.from_clb_type);
|
|
||||||
/* Skip if we do not have a valid coordinate for source CLB/heterogeneous block */
|
|
||||||
if ( (size_t(-1) == src_clb_coord.x())
|
|
||||||
|| (size_t(-1) == src_clb_coord.y()) ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* For a valid coordinate, we can find the coordinate of the destination clb */
|
|
||||||
vtr::Point<size_t> des_clb_coord = find_intra_direct_destination_coordinate(device_size, grids, src_clb_coord, direct);
|
|
||||||
/* If destination clb is valid, we should add something */
|
|
||||||
if ( (size_t(-1) == des_clb_coord.x())
|
|
||||||
|| (size_t(-1) == des_clb_coord.y()) ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
add_module_nets_clb2clb_direct_connection(module_manager, top_module, circuit_lib,
|
|
||||||
device_size, grids, grid_instance_ids,
|
|
||||||
src_clb_coord, des_clb_coord,
|
|
||||||
direct);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/********************************************************************
|
|
||||||
* 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
|
|
||||||
*******************************************************************/
|
|
||||||
static
|
|
||||||
void add_top_module_nets_clb2clb_direct_connections(ModuleManager& module_manager,
|
|
||||||
const ModuleId& top_module,
|
|
||||||
const CircuitLibrary& circuit_lib,
|
|
||||||
const vtr::Point<size_t>& device_size,
|
|
||||||
const std::vector<std::vector<t_grid_tile>>& grids,
|
|
||||||
const std::vector<std::vector<size_t>>& grid_instance_ids,
|
|
||||||
const std::vector<t_clb_to_clb_directs>& clb2clb_directs) {
|
|
||||||
|
|
||||||
add_top_module_nets_intra_clb2clb_direct_connections(module_manager, top_module, circuit_lib,
|
|
||||||
device_size, grids, grid_instance_ids,
|
|
||||||
clb2clb_directs);
|
|
||||||
|
|
||||||
add_top_module_nets_inter_clb2clb_direct_connections(module_manager, top_module, circuit_lib,
|
|
||||||
device_size, grids, grid_instance_ids,
|
|
||||||
clb2clb_directs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* Print the top-level module for the FPGA fabric in Verilog format
|
* Print the top-level module for the FPGA fabric in Verilog format
|
||||||
* This function will
|
* This function will
|
||||||
|
@ -1421,13 +881,21 @@ void print_verilog_top_module(ModuleManager& module_manager,
|
||||||
std::vector<ModuleId> memory_modules;
|
std::vector<ModuleId> memory_modules;
|
||||||
std::vector<size_t> memory_instances;
|
std::vector<size_t> memory_instances;
|
||||||
|
|
||||||
/* TODO: Add module nets to connect memory cells inside
|
/* Organize the list of memory modules and instances */
|
||||||
|
organize_top_module_memory_modules(module_manager,
|
||||||
|
circuit_lib, sram_model, cur_sram_orgz_info,
|
||||||
|
device_size, grids, grid_instance_ids,
|
||||||
|
L_device_rr_gsb, sb_instance_ids, cb_instance_ids,
|
||||||
|
compact_routing_hierarchy,
|
||||||
|
memory_modules, memory_instances);
|
||||||
|
|
||||||
|
/* Add module nets to connect memory cells inside
|
||||||
* This is a one-shot addition that covers all the memory modules in this pb module!
|
* This is a one-shot addition that covers all the memory modules in this pb module!
|
||||||
*/
|
*/
|
||||||
if (false == memory_modules.empty()) {
|
if (false == memory_modules.empty()) {
|
||||||
add_module_nets_memory_config_bus(module_manager, top_module,
|
add_top_module_nets_memory_config_bus(module_manager, top_module,
|
||||||
memory_modules, memory_instances,
|
memory_modules, memory_instances,
|
||||||
cur_sram_orgz_info->type, circuit_lib.design_tech_type(sram_model));
|
cur_sram_orgz_info->type, circuit_lib.design_tech_type(sram_model));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Start printing out Verilog netlists */
|
/* Start printing out Verilog netlists */
|
||||||
|
|
Loading…
Reference in New Issue