relax I/O circuit model checking to fit AIB interface. Adapt testbench generation for multiple types of I/O pads

This commit is contained in:
tangxifan 2020-03-27 20:09:50 -06:00
parent e601a648cc
commit ff9cc50527
4 changed files with 144 additions and 139 deletions

View File

@ -462,7 +462,9 @@ void check_circuit_library(const CircuitLibrary& circuit_lib) {
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);
iopad_port_types_required.push_back(CIRCUIT_MODEL_PORT_SRAM);
/* 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);

View File

@ -88,83 +88,84 @@ void print_analysis_sdc_io_delays(std::fstream& fp,
VTR_ASSERT(1 == operating_clock_ports.size());
/* In this function, we support only 1 type of I/Os */
VTR_ASSERT(1 == module_manager.module_ports_by_type(top_module, ModuleManager::MODULE_GPIO_PORT).size());
BasicPort module_io_port = module_manager.module_ports_by_type(top_module, ModuleManager::MODULE_GPIO_PORT)[0];
std::vector<BasicPort> module_io_ports = module_manager.module_ports_by_type(top_module, ModuleManager::MODULE_GPIO_PORT);
/* Keep tracking which I/Os have been used */
std::vector<bool> io_used(module_io_port.get_width(), false);
for (const BasicPort& module_io_port : module_io_ports) {
/* Keep tracking which I/Os have been used */
std::vector<bool> io_used(module_io_port.get_width(), false);
/* Find clock ports in benchmark */
std::vector<std::string> benchmark_clock_port_names = find_atom_netlist_clock_port_names(atom_ctx.nlist, netlist_annotation);
/* Find clock ports in benchmark */
std::vector<std::string> benchmark_clock_port_names = find_atom_netlist_clock_port_names(atom_ctx.nlist, netlist_annotation);
/* Print comments */
fp << "##################################################" << std::endl;
fp << "# Create input and output delays for used I/Os " << std::endl;
fp << "##################################################" << std::endl;
/* Print comments */
fp << "##################################################" << std::endl;
fp << "# Create input and output delays for used I/Os " << std::endl;
fp << "##################################################" << std::endl;
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 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;
}
/* clock net or constant generator should be disabled in timing analysis */
if (benchmark_clock_port_names.end() != std::find(benchmark_clock_port_names.begin(), benchmark_clock_port_names.end(), atom_ctx.nlist.block_name(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);
/* Ensure that IO index is in range */
BasicPort module_mapped_io_port = module_io_port;
/* Set the port pin index */
VTR_ASSERT(io_index < module_mapped_io_port.get_width());
module_mapped_io_port.set_width(io_index, io_index);
/* For input I/O, we set an input delay constraint correlated to the operating clock
* For output I/O, we set an output delay constraint correlated to the operating clock
*/
if (AtomBlockType::INPAD == atom_ctx.nlist.block_type(atom_blk)) {
print_sdc_set_port_input_delay(fp, module_mapped_io_port,
operating_clock_ports[0], critical_path_delay);
} else {
VTR_ASSERT(AtomBlockType::OUTPAD == atom_ctx.nlist.block_type(atom_blk));
print_sdc_set_port_output_delay(fp, module_mapped_io_port,
operating_clock_ports[0], critical_path_delay);
}
/* Mark this I/O has been used/wired */
io_used[io_index] = true;
}
/* clock net or constant generator should be disabled in timing analysis */
if (benchmark_clock_port_names.end() != std::find(benchmark_clock_port_names.begin(), benchmark_clock_port_names.end(), atom_ctx.nlist.block_name(atom_blk))) {
continue;
/* Add an empty line as a splitter */
fp << std::endl;
/* Print comments */
fp << "##################################################" << std::endl;
fp << "# Disable timing for unused I/Os " << std::endl;
fp << "##################################################" << std::endl;
/* Wire the unused iopads to a constant */
for (size_t io_index = 0; io_index < io_used.size(); ++io_index) {
/* Bypass used iopads */
if (true == io_used[io_index]) {
continue;
}
/* Wire to a contant */
BasicPort module_unused_io_port = module_io_port;
/* Set the port pin index */
module_unused_io_port.set_width(io_index, io_index);
print_sdc_disable_port_timing(fp, module_unused_io_port);
}
/* 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);
/* Ensure that IO index is in range */
BasicPort module_mapped_io_port = module_io_port;
/* Set the port pin index */
VTR_ASSERT(io_index < module_mapped_io_port.get_width());
module_mapped_io_port.set_width(io_index, io_index);
/* For input I/O, we set an input delay constraint correlated to the operating clock
* For output I/O, we set an output delay constraint correlated to the operating clock
*/
if (AtomBlockType::INPAD == atom_ctx.nlist.block_type(atom_blk)) {
print_sdc_set_port_input_delay(fp, module_mapped_io_port,
operating_clock_ports[0], critical_path_delay);
} else {
VTR_ASSERT(AtomBlockType::OUTPAD == atom_ctx.nlist.block_type(atom_blk));
print_sdc_set_port_output_delay(fp, module_mapped_io_port,
operating_clock_ports[0], critical_path_delay);
}
/* Mark this I/O has been used/wired */
io_used[io_index] = true;
/* Add an empty line as a splitter */
fp << std::endl;
}
/* Add an empty line as a splitter */
fp << std::endl;
/* Print comments */
fp << "##################################################" << std::endl;
fp << "# Disable timing for unused I/Os " << std::endl;
fp << "##################################################" << std::endl;
/* Wire the unused iopads to a constant */
for (size_t io_index = 0; io_index < io_used.size(); ++io_index) {
/* Bypass used iopads */
if (true == io_used[io_index]) {
continue;
}
/* Wire to a contant */
BasicPort module_unused_io_port = module_io_port;
/* Set the port pin index */
module_unused_io_port.set_width(io_index, io_index);
print_sdc_disable_port_timing(fp, module_unused_io_port);
}
/* Add an empty line as a splitter */
fp << std::endl;
}
/********************************************************************

View File

@ -132,86 +132,87 @@ void print_verilog_testbench_connect_fpga_ios(std::fstream& fp,
valid_file_stream(fp);
/* In this function, we support only 1 type of I/Os */
VTR_ASSERT(1 == module_manager.module_ports_by_type(top_module, ModuleManager::MODULE_GPIO_PORT).size());
BasicPort module_io_port = module_manager.module_ports_by_type(top_module, ModuleManager::MODULE_GPIO_PORT)[0];
std::vector<BasicPort> module_io_ports = module_manager.module_ports_by_type(top_module, ModuleManager::MODULE_GPIO_PORT);
/* Keep tracking which I/Os have been used */
std::vector<bool> io_used(module_io_port.get_width(), false);
for (const BasicPort& module_io_port : module_io_ports) {
std::vector<bool> io_used(module_io_port.get_width(), false);
/* See if this I/O should be wired to a benchmark input/output */
/* Add signals from blif benchmark and short-wire them to FPGA I/O PADs
* This brings convenience to checking functionality
*/
print_verilog_comment(fp, std::string("----- Link BLIF Benchmark I/Os to FPGA I/Os -----"));
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);
/* Ensure that IO index is in range */
BasicPort module_mapped_io_port = module_io_port;
/* Set the port pin index */
VTR_ASSERT(io_index < module_mapped_io_port.get_width());
module_mapped_io_port.set_width(io_index, io_index);
/* The block may be renamed as it contains special characters which violate Verilog syntax */
std::string block_name = atom_ctx.nlist.block_name(atom_blk);
if (true == netlist_annotation.is_block_renamed(atom_blk)) {
block_name = netlist_annotation.block_name(atom_blk);
}
/* Create the port for benchmark I/O, due to BLIF benchmark, each I/O always has a size of 1
* In addition, the input and output ports may have different postfix in naming
* due to verification context! Here, we give full customization on naming
/* See if this I/O should be wired to a benchmark input/output */
/* Add signals from blif benchmark and short-wire them to FPGA I/O PADs
* This brings convenience to checking functionality
*/
BasicPort benchmark_io_port;
if (AtomBlockType::INPAD == atom_ctx.nlist.block_type(atom_blk)) {
benchmark_io_port.set_name(std::string(block_name + io_input_port_name_postfix));
benchmark_io_port.set_width(1);
print_verilog_comment(fp, std::string("----- Blif Benchmark input " + block_name + " is mapped to FPGA IOPAD " + module_mapped_io_port.get_name() + "[" + std::to_string(io_index) + "] -----"));
print_verilog_wire_connection(fp, module_mapped_io_port, benchmark_io_port, false);
} else {
VTR_ASSERT(AtomBlockType::OUTPAD == atom_ctx.nlist.block_type(atom_blk));
benchmark_io_port.set_name(std::string(block_name + io_output_port_name_postfix));
benchmark_io_port.set_width(1);
print_verilog_comment(fp, std::string("----- Blif Benchmark output " + block_name + " is mapped to FPGA IOPAD " + module_mapped_io_port.get_name() + "[" + std::to_string(io_index) + "] -----"));
print_verilog_wire_connection(fp, benchmark_io_port, module_mapped_io_port, false);
print_verilog_comment(fp, std::string("----- Link BLIF Benchmark I/Os to FPGA I/Os -----"));
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);
/* Ensure that IO index is in range */
BasicPort module_mapped_io_port = module_io_port;
/* Set the port pin index */
VTR_ASSERT(io_index < module_mapped_io_port.get_width());
module_mapped_io_port.set_width(io_index, io_index);
/* The block may be renamed as it contains special characters which violate Verilog syntax */
std::string block_name = atom_ctx.nlist.block_name(atom_blk);
if (true == netlist_annotation.is_block_renamed(atom_blk)) {
block_name = netlist_annotation.block_name(atom_blk);
}
/* Create the port for benchmark I/O, due to BLIF benchmark, each I/O always has a size of 1
* In addition, the input and output ports may have different postfix in naming
* due to verification context! Here, we give full customization on naming
*/
BasicPort benchmark_io_port;
if (AtomBlockType::INPAD == atom_ctx.nlist.block_type(atom_blk)) {
benchmark_io_port.set_name(std::string(block_name + io_input_port_name_postfix));
benchmark_io_port.set_width(1);
print_verilog_comment(fp, std::string("----- Blif Benchmark input " + block_name + " is mapped to FPGA IOPAD " + module_mapped_io_port.get_name() + "[" + std::to_string(io_index) + "] -----"));
print_verilog_wire_connection(fp, module_mapped_io_port, benchmark_io_port, false);
} else {
VTR_ASSERT(AtomBlockType::OUTPAD == atom_ctx.nlist.block_type(atom_blk));
benchmark_io_port.set_name(std::string(block_name + io_output_port_name_postfix));
benchmark_io_port.set_width(1);
print_verilog_comment(fp, std::string("----- Blif Benchmark output " + block_name + " is mapped to FPGA IOPAD " + module_mapped_io_port.get_name() + "[" + std::to_string(io_index) + "] -----"));
print_verilog_wire_connection(fp, benchmark_io_port, module_mapped_io_port, false);
}
/* Mark this I/O has been used/wired */
io_used[io_index] = true;
}
/* Mark this I/O has been used/wired */
io_used[io_index] = true;
}
/* Add an empty line as a splitter */
fp << std::endl;
/* Add an empty line as a splitter */
fp << std::endl;
/* Wire the unused iopads to a constant */
print_verilog_comment(fp, std::string("----- Wire unused FPGA I/Os to constants -----"));
for (size_t io_index = 0; io_index < io_used.size(); ++io_index) {
/* Bypass used iopads */
if (true == io_used[io_index]) {
continue;
}
/* Wire the unused iopads to a constant */
print_verilog_comment(fp, std::string("----- Wire unused FPGA I/Os to constants -----"));
for (size_t io_index = 0; io_index < io_used.size(); ++io_index) {
/* Bypass used iopads */
if (true == io_used[io_index]) {
continue;
/* Wire to a contant */
BasicPort module_unused_io_port = module_io_port;
/* Set the port pin index */
module_unused_io_port.set_width(io_index, io_index);
std::vector<size_t> default_values(module_unused_io_port.get_width(), unused_io_value);
print_verilog_wire_constant_values(fp, module_unused_io_port, default_values);
}
/* Wire to a contant */
BasicPort module_unused_io_port = module_io_port;
/* Set the port pin index */
module_unused_io_port.set_width(io_index, io_index);
std::vector<size_t> default_values(module_unused_io_port.get_width(), unused_io_value);
print_verilog_wire_constant_values(fp, module_unused_io_port, default_values);
/* Add an empty line as a splitter */
fp << std::endl;
}
/* Add an empty line as a splitter */
fp << std::endl;
}
/********************************************************************

View File

@ -209,7 +209,7 @@
<port type="output" prefix="d_out" size="32"/>
<port type="clock" prefix="clk" size="1" is_global="true" default_val="0"/>
</circuit_model>
<circuit_model type="hard_logic" name="aib" prefix="aib" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/SpiceNetlists/aib.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/VerilogNetlists/aib.v">
<circuit_model type="iopad" name="aib" prefix="aib" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/SpiceNetlists/aib.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/VerilogNetlists/aib.v">
<design_technology type="cmos"/>
<input_buffer exist="true" circuit_model_name="INVTX1"/>
<output_buffer exist="true" circuit_model_name="INVTX1"/>
@ -218,6 +218,7 @@
<port type="output" prefix="rx_data" size="80"/>
<port type="clock" prefix="tx_clk" size="1" default_val="0"/>
<port type="clock" prefix="rx_clk" size="1" default_val="0"/>
<port type="inout" prefix="pad" size="80"/>
</circuit_model>
</circuit_library>
<configuration_protocol>