[Tool] Split io location mapping builder from fabric builder

This commit is contained in:
tangxifan 2020-11-02 18:27:34 -07:00
parent 1fd899ecee
commit e4d974c5c8
12 changed files with 233 additions and 60 deletions

View File

@ -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 */

View File

@ -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*/

View File

@ -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);

View File

@ -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,

View File

@ -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,

View File

@ -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 */

View File

@ -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

View File

@ -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 */

View File

@ -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,

View File

@ -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;

View File

@ -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);

View File

@ -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;