[Tool] Split io location mapping builder from fabric builder
This commit is contained in:
parent
1fd899ecee
commit
e4d974c5c8
|
@ -11,7 +11,10 @@ namespace openfpga {
|
|||
/**************************************************
|
||||
* Public Accessors
|
||||
*************************************************/
|
||||
size_t IoLocationMap::io_index(const size_t& x, const size_t& y, const size_t& z) const {
|
||||
size_t IoLocationMap::io_index(const size_t& x,
|
||||
const size_t& y,
|
||||
const size_t& z,
|
||||
const std::string& io_port_name) const {
|
||||
if (x >= io_indices_.size()) {
|
||||
return size_t(-1);
|
||||
}
|
||||
|
@ -24,10 +27,19 @@ size_t IoLocationMap::io_index(const size_t& x, const size_t& y, const size_t& z
|
|||
return size_t(-1);
|
||||
}
|
||||
|
||||
return io_indices_[x][y][z];
|
||||
auto result = io_indices_[x][y][z].find(io_port_name);
|
||||
if (result == io_indices_[x][y][z].end()) {
|
||||
return size_t(-1);
|
||||
}
|
||||
|
||||
return result->second;
|
||||
}
|
||||
|
||||
void IoLocationMap::set_io_index(const size_t& x, const size_t& y, const size_t& z, const size_t& io_index) {
|
||||
void IoLocationMap::set_io_index(const size_t& x,
|
||||
const size_t& y,
|
||||
const size_t& z,
|
||||
const std::string& io_port_name,
|
||||
const size_t& io_index) {
|
||||
if (x >= io_indices_.size()) {
|
||||
io_indices_.resize(x + 1);
|
||||
}
|
||||
|
@ -40,7 +52,7 @@ void IoLocationMap::set_io_index(const size_t& x, const size_t& y, const size_t&
|
|||
io_indices_[x][y].resize(z + 1);
|
||||
}
|
||||
|
||||
io_indices_[x][y][z] = io_index;
|
||||
io_indices_[x][y][z][io_port_name] = io_index;
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
*******************************************************************/
|
||||
#include <stddef.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
/* Begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
@ -15,24 +17,32 @@ namespace openfpga {
|
|||
* in the FPGA fabric, i.e., the module graph, and logical location
|
||||
* of the I/O in VPR coordinate system
|
||||
*
|
||||
* For example
|
||||
* io[0] io[1] io[2]
|
||||
* +-----------------+ +--------+
|
||||
* | | | | |
|
||||
* | I/O | I/O | | I/O |
|
||||
* | [0][y] | [0][y] | | [1][y] |
|
||||
* | [0] | [1] | | [0] |
|
||||
* +-----------------+ +--------+
|
||||
* For example:
|
||||
*
|
||||
* ioA[0] ioA[1] ioB[0] ioB[1] ioA[2]
|
||||
* +-----------------+ +--------+--------+ +--------+
|
||||
* | | | | | | | |
|
||||
* | I/O | I/O | | I/O | I/O | | I/O |
|
||||
* | [0][y] | [0][y] | | [1][y] | [1][y] | | [2][y] | ...
|
||||
* | [0] | [1] | | [0] | [1] | | [0] |
|
||||
* +-----------------+ +--------+--------+ +--------+
|
||||
*
|
||||
*******************************************************************/
|
||||
class IoLocationMap {
|
||||
public: /* Public aggregators */
|
||||
size_t io_index(const size_t& x, const size_t& y, const size_t& z) const;
|
||||
size_t io_index(const size_t& x,
|
||||
const size_t& y,
|
||||
const size_t& z,
|
||||
const std::string& io_port_name) const;
|
||||
public: /* Public mutators */
|
||||
void set_io_index(const size_t& x, const size_t& y, const size_t& z, const size_t& io_index);
|
||||
void set_io_index(const size_t& x,
|
||||
const size_t& y,
|
||||
const size_t& z,
|
||||
const std::string& io_port_name,
|
||||
const size_t& io_index);
|
||||
private: /* Internal Data */
|
||||
/* I/O index fast lookup by [x][y][z] location */
|
||||
std::vector<std::vector<std::vector<size_t>>> io_indices_;
|
||||
std::vector<std::vector<std::vector<std::map<std::string, size_t>>>> io_indices_;
|
||||
};
|
||||
|
||||
} /* End namespace openfpga*/
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "build_device_module.h"
|
||||
#include "fabric_hierarchy_writer.h"
|
||||
#include "fabric_key_writer.h"
|
||||
#include "build_fabric_io_location_map.h"
|
||||
#include "openfpga_build_fabric.h"
|
||||
|
||||
/* Include global variables of VPR */
|
||||
|
@ -100,7 +101,6 @@ int build_fabric(OpenfpgaContext& openfpga_ctx,
|
|||
VTR_LOG("\n");
|
||||
|
||||
curr_status = build_device_module_graph(openfpga_ctx.mutable_module_graph(),
|
||||
openfpga_ctx.mutable_io_location_map(),
|
||||
openfpga_ctx.mutable_decoder_lib(),
|
||||
const_cast<const OpenfpgaContext&>(openfpga_ctx),
|
||||
g_vpr_ctx.device(),
|
||||
|
@ -116,6 +116,10 @@ int build_fabric(OpenfpgaContext& openfpga_ctx,
|
|||
final_status = curr_status;
|
||||
}
|
||||
|
||||
/* Build I/O location map */
|
||||
openfpga_ctx.mutable_io_location_map() = build_fabric_io_location_map(openfpga_ctx.module_graph(),
|
||||
g_vpr_ctx.device().grid);
|
||||
|
||||
/* Output fabric key if user requested */
|
||||
if (true == cmd_context.option_enable(cmd, opt_write_fabric_key)) {
|
||||
std::string fkey_fname = cmd_context.option_value(cmd, opt_write_fabric_key);
|
||||
|
|
|
@ -30,7 +30,6 @@ namespace openfpga {
|
|||
* for a FPGA fabric
|
||||
*******************************************************************/
|
||||
int build_device_module_graph(ModuleManager& module_manager,
|
||||
IoLocationMap& io_location_map,
|
||||
DecoderLibrary& decoder_lib,
|
||||
const OpenfpgaContext& openfpga_ctx,
|
||||
const DeviceContext& vpr_device_ctx,
|
||||
|
@ -112,7 +111,6 @@ int build_device_module_graph(ModuleManager& module_manager,
|
|||
|
||||
/* Build FPGA fabric top-level module */
|
||||
status = build_top_module(module_manager,
|
||||
io_location_map,
|
||||
decoder_lib,
|
||||
openfpga_ctx.arch().circuit_lib,
|
||||
vpr_device_ctx.grid,
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
namespace openfpga {
|
||||
|
||||
int build_device_module_graph(ModuleManager& module_manager,
|
||||
IoLocationMap& io_location_map,
|
||||
DecoderLibrary& decoder_lib,
|
||||
const OpenfpgaContext& openfpga_ctx,
|
||||
const DeviceContext& vpr_device_ctx,
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
/********************************************************************
|
||||
* This file includes functions that are used to build the location
|
||||
* map information for the top-level module of the FPGA fabric
|
||||
* It helps OpenFPGA to link the I/O port index in top-level module
|
||||
* to the VPR I/O mapping results
|
||||
*******************************************************************/
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
|
||||
/* Headers from vtrutil library */
|
||||
#include "vtr_assert.h"
|
||||
#include "vtr_time.h"
|
||||
#include "vtr_log.h"
|
||||
|
||||
/* Headers from vpr library */
|
||||
#include "vpr_utils.h"
|
||||
|
||||
#include "openfpga_reserved_words.h"
|
||||
#include "openfpga_naming.h"
|
||||
|
||||
#include "build_fabric_io_location_map.h"
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
/********************************************************************
|
||||
* Find all the GPIO ports in the grid module
|
||||
* and cache their port/pin index in the top-level module
|
||||
*******************************************************************/
|
||||
IoLocationMap build_fabric_io_location_map(const ModuleManager& module_manager,
|
||||
const DeviceGrid& grids) {
|
||||
vtr::ScopedStartFinishTimer timer("Create I/O location mapping for top module");
|
||||
|
||||
IoLocationMap io_location_map;
|
||||
|
||||
std::map<std::string, size_t> io_counter;
|
||||
|
||||
/* Create the coordinate range for each side of FPGA fabric */
|
||||
std::vector<e_side> io_sides{TOP, RIGHT, BOTTOM, LEFT};
|
||||
std::map<e_side, std::vector<vtr::Point<size_t>>> io_coordinates;
|
||||
|
||||
/* TOP side*/
|
||||
for (size_t ix = 1; ix < grids.width() - 1; ++ix) {
|
||||
io_coordinates[TOP].push_back(vtr::Point<size_t>(ix, grids.height() - 1));
|
||||
}
|
||||
|
||||
/* RIGHT side */
|
||||
for (size_t iy = 1; iy < grids.height() - 1; ++iy) {
|
||||
io_coordinates[RIGHT].push_back(vtr::Point<size_t>(grids.width() - 1, iy));
|
||||
}
|
||||
|
||||
/* BOTTOM side*/
|
||||
for (size_t ix = 1; ix < grids.width() - 1; ++ix) {
|
||||
io_coordinates[BOTTOM].push_back(vtr::Point<size_t>(ix, 0));
|
||||
}
|
||||
|
||||
/* LEFT side */
|
||||
for (size_t iy = 1; iy < grids.height() - 1; ++iy) {
|
||||
io_coordinates[LEFT].push_back(vtr::Point<size_t>(0, iy));
|
||||
}
|
||||
|
||||
/* Walk through all the grids on the perimeter, which are I/O grids */
|
||||
for (const e_side& io_side : io_sides) {
|
||||
for (const vtr::Point<size_t>& io_coordinate : io_coordinates[io_side]) {
|
||||
/* Bypass EMPTY grid */
|
||||
if (true == is_empty_type(grids[io_coordinate.x()][io_coordinate.y()].type)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Skip width or height > 1 tiles (mostly heterogeneous blocks) */
|
||||
if ( (0 < grids[io_coordinate.x()][io_coordinate.y()].width_offset)
|
||||
|| (0 < grids[io_coordinate.x()][io_coordinate.y()].height_offset)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
t_physical_tile_type_ptr grid_type = grids[io_coordinate.x()][io_coordinate.y()].type;
|
||||
|
||||
/* Find the module name for this type of grid */
|
||||
std::string grid_module_name_prefix(GRID_MODULE_NAME_PREFIX);
|
||||
std::string grid_module_name = generate_grid_block_module_name(grid_module_name_prefix, std::string(grid_type->name), is_io_type(grid_type), io_side);
|
||||
ModuleId grid_module = module_manager.find_module(grid_module_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(grid_module));
|
||||
|
||||
/* Find all the GPIO ports in the grid module */
|
||||
|
||||
/* MUST DO: register in io location mapping!
|
||||
* I/O location mapping is a critical look-up for testbench generators
|
||||
* As we add the I/O grid instances to top module by following order:
|
||||
* TOP -> RIGHT -> BOTTOM -> LEFT
|
||||
* The I/O index will increase in this way as well.
|
||||
* This organization I/O indices is also consistent to the way
|
||||
* that GPIOs are wired in function connect_gpio_module()
|
||||
*
|
||||
* Note: if you change the GPIO function, you should update here as well!
|
||||
*/
|
||||
for (int z = 0; z < grids[io_coordinate.x()][io_coordinate.y()].type->capacity; ++z) {
|
||||
for (const BasicPort& gpio_port : module_manager.module_ports_by_type(grid_module, ModuleManager::MODULE_GPIO_PORT)) {
|
||||
auto curr_io_index = io_counter.find(gpio_port.get_name());
|
||||
/* Index always start from zero */
|
||||
if (curr_io_index == io_counter.end()) {
|
||||
io_counter[gpio_port.get_name()] = 0;
|
||||
}
|
||||
io_location_map.set_io_index(io_coordinate.x(), io_coordinate.y(), z,
|
||||
gpio_port.get_name(),
|
||||
io_counter[gpio_port.get_name()]);
|
||||
io_counter[gpio_port.get_name()]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check all the GPIO ports in the top-level module has been mapped */
|
||||
std::string top_module_name = generate_fpga_top_module_name();
|
||||
ModuleId top_module = module_manager.find_module(top_module_name);
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(top_module));
|
||||
|
||||
for (const BasicPort& gpio_port : module_manager.module_ports_by_type(top_module, ModuleManager::MODULE_GPIO_PORT)) {
|
||||
VTR_ASSERT(io_counter[gpio_port.get_name()] == gpio_port.get_width());
|
||||
}
|
||||
|
||||
return io_location_map;
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef BUILD_FABRIC_IO_LOCATION_MAP_H
|
||||
#define BUILD_FABRIC_IO_LOCATION_MAP_H
|
||||
|
||||
/********************************************************************
|
||||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
|
||||
#include <string>
|
||||
#include "device_grid.h"
|
||||
#include "io_location_map.h"
|
||||
#include "module_manager.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
*******************************************************************/
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
IoLocationMap build_fabric_io_location_map(const ModuleManager& module_manager,
|
||||
const DeviceGrid& grids);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
#endif
|
|
@ -92,7 +92,6 @@ size_t add_top_module_grid_instance(ModuleManager& module_manager,
|
|||
static
|
||||
vtr::Matrix<size_t> add_top_module_grid_instances(ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
IoLocationMap& io_location_map,
|
||||
const DeviceGrid& grids) {
|
||||
|
||||
vtr::ScopedStartFinishTimer timer("Add grid instances to top module");
|
||||
|
@ -178,21 +177,6 @@ vtr::Matrix<size_t> add_top_module_grid_instances(ModuleManager& module_manager,
|
|||
|
||||
/* Add a grid module to top_module*/
|
||||
grid_instance_ids[io_coordinate.x()][io_coordinate.y()] = add_top_module_grid_instance(module_manager, top_module, grids[io_coordinate.x()][io_coordinate.y()].type, io_side, io_coordinate);
|
||||
|
||||
/* MUST DO: register in io location mapping!
|
||||
* I/O location mapping is a critical look-up for testbench generators
|
||||
* As we add the I/O grid instances to top module by following order:
|
||||
* TOP -> RIGHT -> BOTTOM -> LEFT
|
||||
* The I/O index will increase in this way as well.
|
||||
* This organization I/O indices is also consistent to the way
|
||||
* that GPIOs are wired in function connect_gpio_module()
|
||||
*
|
||||
* Note: if you change the GPIO function, you should update here as well!
|
||||
*/
|
||||
for (int z = 0; z < grids[io_coordinate.x()][io_coordinate.y()].type->capacity; ++z) {
|
||||
io_location_map.set_io_index(io_coordinate.x(), io_coordinate.y(), z, io_counter);
|
||||
io_counter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -322,7 +306,6 @@ vtr::Matrix<size_t> add_top_module_connection_block_instances(ModuleManager& mod
|
|||
* 5. Add module nets/submodules to connect configuration ports
|
||||
*******************************************************************/
|
||||
int build_top_module(ModuleManager& module_manager,
|
||||
IoLocationMap& io_location_map,
|
||||
DecoderLibrary& decoder_lib,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const DeviceGrid& grids,
|
||||
|
@ -353,7 +336,7 @@ int build_top_module(ModuleManager& module_manager,
|
|||
|
||||
/* Add sub modules, which are grid, SB and CBX/CBY modules as instances */
|
||||
/* Add all the grids across the fabric */
|
||||
vtr::Matrix<size_t> grid_instance_ids = add_top_module_grid_instances(module_manager, top_module, io_location_map, grids);
|
||||
vtr::Matrix<size_t> grid_instance_ids = add_top_module_grid_instances(module_manager, top_module, grids);
|
||||
/* Add all the SBs across the fabric */
|
||||
vtr::Matrix<size_t> sb_instance_ids = add_top_module_switch_block_instances(module_manager, top_module, device_rr_gsb, compact_routing_hierarchy);
|
||||
/* Add all the CBX and CBYs across the fabric */
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#include "arch_direct.h"
|
||||
#include "config_protocol.h"
|
||||
#include "module_manager.h"
|
||||
#include "io_location_map.h"
|
||||
#include "fabric_key.h"
|
||||
|
||||
/********************************************************************
|
||||
|
@ -27,7 +26,6 @@
|
|||
namespace openfpga {
|
||||
|
||||
int build_top_module(ModuleManager& module_manager,
|
||||
IoLocationMap& io_location_map,
|
||||
DecoderLibrary& decoder_lib,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const DeviceGrid& grids,
|
||||
|
|
|
@ -118,7 +118,12 @@ void print_analysis_sdc_io_delays(std::fstream& fp,
|
|||
/* Find the index of the mapped GPIO in top-level FPGA fabric */
|
||||
size_t io_index = io_location_map.io_index(place_ctx.block_locs[atom_ctx.lookup.atom_clb(atom_blk)].loc.x,
|
||||
place_ctx.block_locs[atom_ctx.lookup.atom_clb(atom_blk)].loc.y,
|
||||
place_ctx.block_locs[atom_ctx.lookup.atom_clb(atom_blk)].loc.z);
|
||||
place_ctx.block_locs[atom_ctx.lookup.atom_clb(atom_blk)].loc.z,
|
||||
module_io_port.get_name());
|
||||
|
||||
if (size_t(-1) == io_index) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Ensure that IO index is in range */
|
||||
BasicPort module_mapped_io_port = module_io_port;
|
||||
|
|
|
@ -107,29 +107,38 @@ void print_verilog_simulation_info(const std::string& ini_fname,
|
|||
* For unused ports, by default we assume it is configured as inputs
|
||||
* TODO: this should be reworked to be consistent with bitstream
|
||||
*/
|
||||
std::string io_direction(total_gpio_width, '1');
|
||||
for (const AtomBlockId& atom_blk : atom_ctx.nlist.blocks()) {
|
||||
/* Bypass non-I/O atom blocks ! */
|
||||
if ( (AtomBlockType::INPAD != atom_ctx.nlist.block_type(atom_blk))
|
||||
&& (AtomBlockType::OUTPAD != atom_ctx.nlist.block_type(atom_blk)) ) {
|
||||
continue;
|
||||
}
|
||||
for (const BasicPort& module_io_port : module_manager.module_ports_by_type(top_module, ModuleManager::MODULE_GPIO_PORT)) {
|
||||
std::string io_direction(module_io_port.get_width(), '1');
|
||||
for (const AtomBlockId& atom_blk : atom_ctx.nlist.blocks()) {
|
||||
/* Bypass non-I/O atom blocks ! */
|
||||
if ( (AtomBlockType::INPAD != atom_ctx.nlist.block_type(atom_blk))
|
||||
&& (AtomBlockType::OUTPAD != atom_ctx.nlist.block_type(atom_blk)) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Find the index of the mapped GPIO in top-level FPGA fabric */
|
||||
size_t io_index = io_location_map.io_index(place_ctx.block_locs[atom_ctx.lookup.atom_clb(atom_blk)].loc.x,
|
||||
place_ctx.block_locs[atom_ctx.lookup.atom_clb(atom_blk)].loc.y,
|
||||
place_ctx.block_locs[atom_ctx.lookup.atom_clb(atom_blk)].loc.z);
|
||||
/* Find the index of the mapped GPIO in top-level FPGA fabric */
|
||||
size_t io_index = io_location_map.io_index(place_ctx.block_locs[atom_ctx.lookup.atom_clb(atom_blk)].loc.x,
|
||||
place_ctx.block_locs[atom_ctx.lookup.atom_clb(atom_blk)].loc.y,
|
||||
place_ctx.block_locs[atom_ctx.lookup.atom_clb(atom_blk)].loc.z,
|
||||
module_io_port.get_name());
|
||||
|
||||
if (AtomBlockType::INPAD == atom_ctx.nlist.block_type(atom_blk)) {
|
||||
io_direction[io_index] = '1';
|
||||
} else {
|
||||
VTR_ASSERT(AtomBlockType::OUTPAD == atom_ctx.nlist.block_type(atom_blk));
|
||||
io_direction[io_index] = '0';
|
||||
if (size_t(-1) == io_index) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (AtomBlockType::INPAD == atom_ctx.nlist.block_type(atom_blk)) {
|
||||
io_direction[io_index] = '1';
|
||||
} else {
|
||||
VTR_ASSERT(AtomBlockType::OUTPAD == atom_ctx.nlist.block_type(atom_blk));
|
||||
io_direction[io_index] = '0';
|
||||
}
|
||||
|
||||
std::string io_tag = "IO" + module_io_port.get_name();
|
||||
|
||||
/* Organize the vector to string */
|
||||
ini["SIMULATION_DECK"][io_tag] = io_direction;
|
||||
}
|
||||
}
|
||||
|
||||
/* Organize the vector to string */
|
||||
ini["SIMULATION_DECK"]["IO"] = io_direction;
|
||||
}
|
||||
|
||||
mINI::INIFile file(ini_fname);
|
||||
|
|
|
@ -170,7 +170,13 @@ void print_verilog_testbench_connect_fpga_ios(std::fstream& fp,
|
|||
/* Find the index of the mapped GPIO in top-level FPGA fabric */
|
||||
size_t io_index = io_location_map.io_index(place_ctx.block_locs[atom_ctx.lookup.atom_clb(atom_blk)].loc.x,
|
||||
place_ctx.block_locs[atom_ctx.lookup.atom_clb(atom_blk)].loc.y,
|
||||
place_ctx.block_locs[atom_ctx.lookup.atom_clb(atom_blk)].loc.z);
|
||||
place_ctx.block_locs[atom_ctx.lookup.atom_clb(atom_blk)].loc.z,
|
||||
module_io_port.get_name());
|
||||
|
||||
/* Bypass invalid index (not mapped to this GPIO port) */
|
||||
if (size_t(-1) == io_index) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Ensure that IO index is in range */
|
||||
BasicPort module_mapped_io_port = module_io_port;
|
||||
|
|
Loading…
Reference in New Issue