Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support I/O interfaces for Embedded FPGAs #114

Merged
merged 18 commits into from
Nov 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .travis/fpga_verilog_reg_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ python3 openfpga_flow/scripts/run_fpga_task.py fpga_verilog/io/multi_io_capacity
echo -e "Testing Verilog generation with I/Os only on left and right sides of an FPGA ";
python3 openfpga_flow/scripts/run_fpga_task.py fpga_verilog/io/reduced_io --debug --show_thread_logs

echo -e "Testing Verilog generation with embedded I/Os for an FPGA ";
python3 openfpga_flow/scripts/run_fpga_task.py fpga_verilog/io/embedded_io --debug --show_thread_logs

echo -e "Testing Verilog generation with adder chain across an FPGA";
python3 openfpga_flow/scripts/run_fpga_task.py fpga_verilog/fabric_chain/adder_chain --debug --show_thread_logs

Expand Down
79 changes: 67 additions & 12 deletions libopenfpga/libarchopenfpga/src/check_circuit_library.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,66 @@ int check_power_gated_circuit_models(const CircuitLibrary& circuit_lib) {
return num_err;
}

/************************************************************************
* Check io has been defined and has input and output ports
* - We must have global I/O port, either its type is inout, input or output
* - For each IOPAD, we must have at least an input an output
***********************************************************************/
static
size_t check_io_circuit_model(const CircuitLibrary& circuit_lib) {
size_t num_err = 0;

/* Embedded I/O interface may not have inout port
* iopad_port_types_required.push_back(CIRCUIT_MODEL_PORT_INOUT);
* Some I/Os may not have SRAM port, such as AIB interface
* iopad_port_types_required.push_back(CIRCUIT_MODEL_PORT_SRAM);
*/
std::vector<enum e_circuit_model_port_type> iopad_port_types_required;
iopad_port_types_required.push_back(CIRCUIT_MODEL_PORT_INOUT);
num_err += check_circuit_model_port_required(circuit_lib, CIRCUIT_MODEL_IOPAD, iopad_port_types_required);

/* Each I/O cell must have
* - One of the following ports
* - At least 1 ASIC-to-FPGA (A2F) port that is defined as global I/O
* - At least 1 FPGA-to-ASIC (F2A) port that is defined as global I/O!
* - At least 1 regular port that is non-global which is connected to global routing architecture
*/
for (const auto& io_model : circuit_lib.models_by_type(CIRCUIT_MODEL_IOPAD)) {
bool has_global_io = false;
bool has_internal_connection = false;

for (const auto& port : circuit_lib.model_ports(io_model)) {
if ( (true == circuit_lib.port_is_io(port)
&& (true == circuit_lib.port_is_global(port)))) {
has_global_io = true;
continue; /* Go to next */
}
if ( (false == circuit_lib.port_is_io(port)
&& (false == circuit_lib.port_is_global(port)))
&& (CIRCUIT_MODEL_PORT_SRAM != circuit_lib.port_type(port))) {
has_internal_connection = true;
continue; /* Go to next */
}
}

if (false == has_global_io) {
VTR_LOGF_ERROR(__FILE__, __LINE__,
"I/O circuit model '%s' does not have any I/O port defined!\n",
circuit_lib.model_name(io_model).c_str());
num_err++;
}

if (false == has_internal_connection) {
VTR_LOGF_ERROR(__FILE__, __LINE__,
"I/O circuit model '%s' does not have any port connected to FPGA core!\n",
circuit_lib.model_name(io_model).c_str());
num_err++;
}
}

return num_err;
}

/************************************************************************
* Check points to make sure we have a valid circuit library
* Detailed checkpoints:
Expand All @@ -575,6 +635,10 @@ int check_power_gated_circuit_models(const CircuitLibrary& circuit_lib) {
* 8. FF must have at least a clock, an input and an output ports
* 9. LUT must have at least an input, an output and a SRAM ports
* 10. We must have default circuit models for these types: MUX, channel wires and wires
*
* Note:
* - NO modification on the circuit library is allowed!
* The circuit library should be read-only!!!
***********************************************************************/
bool check_circuit_library(const CircuitLibrary& circuit_lib) {
size_t num_err = 0;
Expand All @@ -595,20 +659,11 @@ bool check_circuit_library(const CircuitLibrary& circuit_lib) {
num_err += check_circuit_library_ports(circuit_lib);

/* 3. Check io has been defined and has input and output ports
* [a] We must have an IOPAD!
* [b] For each IOPAD, we must have at least an input, an output, an INOUT and an SRAM port
* [a] We must have global I/O port, either its type is inout, input or output
* [b] For each IOPAD, we must have at least an input an output
*/
num_err += check_circuit_model_required(circuit_lib, CIRCUIT_MODEL_IOPAD);

std::vector<enum e_circuit_model_port_type> iopad_port_types_required;
iopad_port_types_required.push_back(CIRCUIT_MODEL_PORT_INPUT);
iopad_port_types_required.push_back(CIRCUIT_MODEL_PORT_OUTPUT);
iopad_port_types_required.push_back(CIRCUIT_MODEL_PORT_INOUT);
/* Some I/Os may not have SRAM port, such as AIB interface
* iopad_port_types_required.push_back(CIRCUIT_MODEL_PORT_SRAM);
*/

num_err += check_circuit_model_port_required(circuit_lib, CIRCUIT_MODEL_IOPAD, iopad_port_types_required);
num_err += check_io_circuit_model(circuit_lib);

/* 4. Check mux has been defined and has input and output ports
* [a] We must have a MUX!
Expand Down
20 changes: 16 additions & 4 deletions openfpga/src/base/io_location_map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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);
}
Expand All @@ -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 */
32 changes: 21 additions & 11 deletions openfpga/src/base/io_location_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
*******************************************************************/
#include <stddef.h>
#include <vector>
#include <string>
#include <map>

/* Begin namespace openfpga */
namespace openfpga {
Expand All @@ -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*/
Expand Down
6 changes: 5 additions & 1 deletion openfpga/src/base/openfpga_build_fabric.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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(),
Expand All @@ -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);
Expand Down
2 changes: 0 additions & 2 deletions openfpga/src/fabric/build_device_module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
1 change: 0 additions & 1 deletion openfpga/src/fabric/build_device_module.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
124 changes: 124 additions & 0 deletions openfpga/src/fabric/build_fabric_io_location_map.cpp
Original file line number Diff line number Diff line change
@@ -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 */
Loading