refactoring auto-check top Verilog testbench

This commit is contained in:
tangxifan 2019-11-03 17:41:29 -07:00
parent dc241e6c03
commit 0ec465d4e1
13 changed files with 447 additions and 315 deletions

View File

@ -22,11 +22,12 @@ arch1=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/template/k6_N10_sram_chain_HC_til
[BENCHMARKS]
# Pass
#bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/alu4/alu4.blif
# Fail, due to port does not match, i_15_ is dangling
# Pass, but port does not match, i_15_ is dangling
#bench1=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/apex2/apex2.blif
# To be tested
# Pass
#bench2=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/apex4/apex4.blif
#bench3=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/bigkey/bigkey.blif
bench3=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/bigkey/bigkey.blif
# To be tested
#bench4=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/clma/clma.blif
#bench5=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/des/des.blif
#bench6=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/mcnc_big20/diffeq/diffeq.blif

View File

@ -152,14 +152,10 @@ void vpr_fpga_verilog(ModuleManager& module_manager,
char* fm_dir_path = NULL;
char* top_netlist_file = NULL;
char* top_netlist_path = NULL;
char* top_testbench_file_name = NULL;
char* top_testbench_file_path = NULL;
char* blif_testbench_file_name = NULL;
char* blif_testbench_file_path = NULL;
char* bitstream_file_name = NULL;
char* bitstream_file_path = NULL;
char* autocheck_top_testbench_file_name = NULL;
char* autocheck_top_testbench_file_path = NULL;
char* chomped_parent_dir = NULL;
char* chomped_circuit_name = NULL;
@ -390,19 +386,31 @@ void vpr_fpga_verilog(ModuleManager& module_manager,
my_free(bitstream_file_path);
}
/* dump verilog testbench only for top-level: ONLY valid when bitstream is generated! */
if (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_top_testbench) {
top_testbench_file_name = my_strcat(chomped_circuit_name, top_testbench_verilog_file_postfix);
top_testbench_file_path = my_strcat(src_dir_path, top_testbench_file_name);
dump_verilog_top_testbench(sram_verilog_orgz_info, chomped_circuit_name, top_testbench_file_path,
src_dir_path, *(Arch.spice));
/* Free */
my_free(top_testbench_file_name);
my_free(top_testbench_file_path);
}
/* Collect global ports from the circuit library
* TODO: move outside this function
*/
std::vector<CircuitPortId> global_ports = find_circuit_library_global_ports(Arch.spice->circuit_lib);
/* dump verilog testbench only for top-level: ONLY valid when bitstream is generated! */
if (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_top_testbench) {
std::string top_testbench_file_path = std::string(src_dir_path)
+ std::string(chomped_circuit_name)
+ std::string(top_testbench_verilog_file_postfix);
/* TODO: this is an old function, to be shadowed */
dump_verilog_top_testbench(sram_verilog_orgz_info, chomped_circuit_name, top_testbench_file_path.c_str(),
src_dir_path, *(Arch.spice));
/* TODO: new function: to be tested */
print_verilog_top_testbench(module_manager, bitstream_manager, fabric_bitstream,
sram_verilog_orgz_info->type,
Arch.spice->circuit_lib, global_ports,
L_logical_blocks, device_size, L_grids, L_blocks,
std::string(chomped_circuit_name),
std::string(top_testbench_file_path + std::string(".bak")),
std::string(src_dir_path),
std::string(vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.reference_verilog_benchmark_file),
Arch.spice->spice_params);
}
if (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_formal_verification_top_netlist) {
std::string formal_verification_top_netlist_file_path = std::string(src_dir_path)
+ std::string(chomped_circuit_name)
@ -446,10 +454,12 @@ void vpr_fpga_verilog(ModuleManager& module_manager,
}
if (TRUE == vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.print_autocheck_top_testbench) {
autocheck_top_testbench_file_name = my_strcat(chomped_circuit_name, autocheck_top_testbench_verilog_file_postfix);
autocheck_top_testbench_file_path = my_strcat(src_dir_path, autocheck_top_testbench_file_name);
std::string autocheck_top_testbench_file_path = std::string(src_dir_path)
+ std::string(chomped_circuit_name)
+ std::string(autocheck_top_testbench_verilog_file_postfix);
/* TODO: this is an old function, to be shadowed */
dump_verilog_autocheck_top_testbench(sram_verilog_orgz_info, chomped_circuit_name,
autocheck_top_testbench_file_path, src_dir_path,
autocheck_top_testbench_file_path.c_str(), src_dir_path,
vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts, *(Arch.spice));
}

View File

@ -348,7 +348,7 @@ void dump_verilog_top_auto_testbench_check(FILE* fp){
void dump_verilog_autocheck_top_testbench(t_sram_orgz_info* cur_sram_orgz_info,
char* circuit_name,
char* top_netlist_name,
const char* top_netlist_name,
char* verilog_dir_path,
t_syn_verilog_opts fpga_verilog_opts,
t_spice verilog) {

View File

@ -1,89 +0,0 @@
/********************************************************************
* This file includes functions that are used to create
* an auto-check top-level testbench for a FPGA fabric
*******************************************************************/
#include <ctime>
#include <fstream>
#include "vtr_assert.h"
#include "fpga_x2p_utils.h"
#include "verilog_writer_utils.h"
#include "verilog_autocheck_top_testbench.h"
/********************************************************************
* The top-level function to generate a testbench, in order to verify:
* 1. Configuration phase of the FPGA fabric, where the bitstream is
* loaded to the configuration protocol of the FPGA fabric
* 2. Operating phase of the FPGA fabric, where input stimuli are
* fed to the I/Os of the FPGA fabric
*******************************************************************/
void print_verilog_autocheck_top_testbench(const ModuleManager& module_manager,
const BitstreamManager& bitstream_manager,
const CircuitLibrary& circuit_lib,
const std::vector<CircuitPortId>& global_ports,
const std::vector<t_logical_block>& L_logical_blocks,
const vtr::Point<size_t>& device_size,
const std::vector<std::vector<t_grid_tile>>& L_grids,
const std::vector<t_block>& L_blocks,
const std::string& circuit_name,
const std::string& verilog_fname,
const std::string& verilog_dir,
const t_syn_verilog_opts& fpga_verilog_opts,
const t_spice_params& simulation_parameters) {
vpr_printf(TIO_MESSAGE_INFO,
"Writing Autocheck Testbench for FPGA Top-level Verilog netlist for %s...",
circuit_name.c_str());
/* Start time count */
clock_t t_start = clock();
/* Create the file stream */
std::fstream fp;
fp.open(verilog_fname, std::fstream::out | std::fstream::trunc);
/* Validate the file stream */
check_file_handler(fp);
/* Generate a brief description on the Verilog file*/
std::string title = std::string("FPGA Verilog Testbench for Top-level netlist of Design: ") + circuit_name;
print_verilog_file_header(fp, title);
/* Print preprocessing flags and external netlists */
print_verilog_include_defines_preproc_file(fp, verilog_dir);
/* Start of testbench */
//dump_verilog_top_auto_testbench_ports(fp, cur_sram_orgz_info, circuit_name, fpga_verilog_opts);
/* Call defined top-level module */
//dump_verilog_top_testbench_call_top_module(cur_sram_orgz_info, fp,
// circuit_name, is_explicit_mapping);
/* Call defined benchmark */
//dump_verilog_top_auto_testbench_call_benchmark(fp, circuit_name);
/* Add stimuli for reset, set, clock and iopad signals */
//dump_verilog_top_testbench_stimuli(cur_sram_orgz_info, fp, verilog);
/* Add output autocheck */
//dump_verilog_top_auto_testbench_check(fp);
/* Add Icarus requirement */
//dump_verilog_timeout_and_vcd(fp, circuit_name , verilog, cur_sram_orgz_info);
/* Testbench ends*/
//fprintf(fp, "endmodule\n");
/* Close the file stream */
fp.close();
/* End time count */
clock_t t_end = clock();
float run_time_sec = (float)(t_end - t_start) / CLOCKS_PER_SEC;
vpr_printf(TIO_MESSAGE_INFO,
"took %g seconds\n",
run_time_sec);
}

View File

@ -1,33 +1,12 @@
#ifndef VERILOG_AUTOCHECK_TOP_TESTBENCH_H
#define VERILOG_AUTOCHECK_TOP_TESTBENCH_H
#include <string>
#include <vector>
#include "module_manager.h"
#include "bitstream_manager.h"
#include "circuit_library.h"
void dump_verilog_autocheck_top_testbench(t_sram_orgz_info* cur_sram_orgz_info,
char* circuit_name,
char* top_netlist_name,
const char* top_netlist_name,
char* verilog_dir_path,
t_syn_verilog_opts fpga_verilog_opts,
t_spice verilog);
/*
void print_verilog_autocheck_top_testbench(const ModuleManager& module_manager,
const BitstreamManager& bitstream_manager,
const CircuitLibrary& circuit_lib,
const std::vector<CircuitPortId>& global_ports,
const std::vector<t_logical_block>& L_logical_blocks,
const vtr::Point<size_t>& device_size,
const std::vector<std::vector<t_grid_tile>>& L_grids,
const std::vector<t_block>& L_blocks,
const std::string& circuit_name,
const std::string& verilog_fname,
const std::string& verilog_dir,
const t_syn_verilog_opts& fpga_verilog_opts,
const t_spice_params& simulation_parameters);
*/
#endif

View File

@ -24,6 +24,7 @@
/* Include FPGA Verilog headers*/
#include "verilog_global.h"
#include "verilog_writer_utils.h"
#include "verilog_testbench_utils.h"
#include "verilog_formal_random_top_testbench.h"
/********************************************************************
@ -175,61 +176,6 @@ void print_verilog_top_random_testbench_ports(std::fstream& fp,
fp << std::endl;
}
/********************************************************************
* Instanciate the FPGA fabric module
*******************************************************************/
static
void print_verilog_random_testbench_instance(std::fstream& fp,
const std::string& module_name,
const std::string& instance_name,
const std::string& module_input_port_postfix,
const std::string& module_output_port_postfix,
const std::string& output_port_postfix,
const std::vector<t_logical_block>& L_logical_blocks,
const bool& use_explicit_port_map) {
/* Validate the file stream */
check_file_handler(fp);
fp << "\t" << module_name << " " << instance_name << "(" << std::endl;
size_t port_counter = 0;
for (const t_logical_block& lb : L_logical_blocks) {
/* Bypass non-I/O logical blocks ! */
if ( (VPACK_INPAD != lb.type) && (VPACK_OUTPAD != lb.type) ) {
continue;
}
/* The first port does not need a comma */
if(0 < port_counter){
fp << "," << std::endl;
}
/* Input port follows the logical block name while output port requires a special postfix */
if (VPACK_INPAD == lb.type){
fp << "\t\t";
if (true == use_explicit_port_map) {
fp << "." << std::string(lb.name) << module_input_port_postfix << "(";
}
fp << std::string(lb.name);
if (true == use_explicit_port_map) {
fp << ")";
}
} else {
VTR_ASSERT_SAFE(VPACK_OUTPAD == lb.type);
fp << "\t\t";
if (true == use_explicit_port_map) {
fp << "." << std::string(lb.name) << module_output_port_postfix << "(";
}
fp << std::string(lb.name) << output_port_postfix;
if (true == use_explicit_port_map) {
fp << ")";
}
}
/* Update the counter */
port_counter++;
}
fp << "\t);" << std::endl;
}
/********************************************************************
* Instanciate the input benchmark module
*******************************************************************/
@ -248,12 +194,12 @@ void print_verilog_top_random_testbench_benchmark_instance(std::fstream& fp,
/* Do NOT use explicit port mapping here:
* VPR added a prefix of "out_" to the output ports of input benchmark
*/
print_verilog_random_testbench_instance(fp, reference_verilog_top_name,
std::string(BENCHMARK_INSTANCE_NAME),
std::string(),
std::string(),
std::string(BENCHMARK_PORT_POSTFIX), L_logical_blocks,
false);
print_verilog_testbench_benchmark_instance(fp, reference_verilog_top_name,
std::string(BENCHMARK_INSTANCE_NAME),
std::string(),
std::string(),
std::string(BENCHMARK_PORT_POSTFIX), L_logical_blocks,
false);
print_verilog_comment(fp, std::string("----- End reference Benchmark Instanication -------"));
@ -411,12 +357,12 @@ void print_verilog_random_testbench_fpga_instance(std::fstream& fp,
print_verilog_comment(fp, std::string("----- FPGA fabric instanciation -------"));
/* Always use explicit port mapping */
print_verilog_random_testbench_instance(fp, std::string(circuit_name + std::string(formal_verification_top_postfix)),
std::string(FPGA_INSTANCE_NAME),
std::string(formal_verification_top_module_port_postfix),
std::string(formal_verification_top_module_port_postfix),
std::string(FPGA_PORT_POSTFIX), L_logical_blocks,
true);
print_verilog_testbench_benchmark_instance(fp, std::string(circuit_name + std::string(formal_verification_top_postfix)),
std::string(FPGA_INSTANCE_NAME),
std::string(formal_verification_top_module_port_postfix),
std::string(formal_verification_top_module_port_postfix),
std::string(FPGA_PORT_POSTFIX), L_logical_blocks,
true);
print_verilog_comment(fp, std::string("----- End FPGA Fabric Instanication -------"));

View File

@ -17,6 +17,7 @@
#include "verilog_global.h"
#include "verilog_writer_utils.h"
#include "verilog_testbench_utils.h"
#include "verilog_preconfig_top_module.h"
/********************************************************************
@ -89,31 +90,6 @@ void print_verilog_preconfig_top_module_internal_wires(std::fstream& fp,
fp << std::endl;
}
/********************************************************************
* Print an instance of the FPGA top-level module
*******************************************************************/
static
void print_verilog_preconfig_top_instance(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& top_module) {
/* Validate the file stream */
check_file_handler(fp);
/* Include defined top-level module */
print_verilog_comment(fp, std::string("----- FPGA top-level module to be capsulated -----"));
/* Create an empty port-to-port name mapping, because we use default names */
std::map<std::string, BasicPort> port2port_name_map;
/* Use explicit port mapping for a clean instanciation */
print_verilog_module_instance(fp, module_manager, top_module,
std::string(formal_verification_top_module_uut_name),
port2port_name_map, true);
/* Add an empty line as a splitter */
fp << std::endl;
}
/********************************************************************
* Connect global ports of FPGA top module to constants except:
* 1. operating clock, which should be wired to the clock port of
@ -180,90 +156,6 @@ void print_verilog_preconfig_top_module_connect_global_ports(std::fstream& fp,
fp << std::endl;
}
/********************************************************************
* This function adds stimuli to I/Os of FPGA fabric
* 1. For mapped I/Os, this function will wire them to the input ports
* of the pre-configured FPGA top module
* 2. For unmapped I/Os, this function will assign a constant value
* by default
*******************************************************************/
static
void print_verilog_preconfig_top_module_connect_ios(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& top_module,
const std::vector<t_logical_block>& L_logical_blocks,
const vtr::Point<size_t>& device_size,
const std::vector<std::vector<t_grid_tile>>& L_grids,
const std::vector<t_block>& L_blocks) {
/* Validate the file stream */
check_file_handler(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];
/* Keep tracking which I/Os have been used */
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 t_logical_block& io_lb : L_logical_blocks) {
/* We only care I/O logical blocks !*/
if ( (VPACK_INPAD != io_lb.type) && (VPACK_OUTPAD != io_lb.type) ) {
continue;
}
/* Find the index of the mapped GPIO in top-level FPGA fabric */
size_t io_index = find_benchmark_io_index(io_lb, device_size, L_grids, L_blocks);
/* 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);
/* Create the port for benchmark I/O, due to BLIF benchmark, each I/O always has a size of 1 */
BasicPort benchmark_io_port(std::string(std::string(io_lb.name)+ std::string(formal_verification_top_module_port_postfix)), 1);
print_verilog_comment(fp, std::string("----- Blif Benchmark inout " + std::string(io_lb.name) + " is mapped to FPGA IOPAD " + module_mapped_io_port.get_name() + "[" + std::to_string(io_index) + "] -----"));
if (VPACK_INPAD == io_lb.type) {
print_verilog_wire_connection(fp, module_mapped_io_port, benchmark_io_port, false);
} else {
VTR_ASSERT(VPACK_OUTPAD == io_lb.type);
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;
}
/* 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 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(), verilog_default_signal_init_value);
print_verilog_wire_constant_values(fp, module_unused_io_port, default_values);
}
/* Add an empty line as a splitter */
fp << std::endl;
}
/********************************************************************
* Impose the bitstream on the configuration memories
* This function uses 'assign' syntax to impost the bitstream at mem port
@ -514,7 +406,8 @@ void print_verilog_preconfig_top_module(const ModuleManager& module_manager,
print_verilog_preconfig_top_module_internal_wires(fp, module_manager, top_module);
/* Instanciate FPGA top-level module */
print_verilog_preconfig_top_instance(fp, module_manager, top_module);
print_verilog_testbench_fpga_instance(fp, module_manager, top_module,
std::string(formal_verification_top_module_uut_name));
/* Find clock ports in benchmark */
std::vector<std::string> benchmark_clock_port_names = find_benchmark_clock_port_name(L_logical_blocks);
@ -525,9 +418,11 @@ void print_verilog_preconfig_top_module(const ModuleManager& module_manager,
benchmark_clock_port_names);
/* Connect I/Os to benchmark I/Os or constant driver */
print_verilog_preconfig_top_module_connect_ios(fp, module_manager, top_module,
L_logical_blocks, device_size, L_grids,
L_blocks);
print_verilog_testbench_connect_fpga_ios(fp, module_manager, top_module,
L_logical_blocks, device_size, L_grids,
L_blocks,
std::string(formal_verification_top_module_port_postfix),
(size_t)verilog_default_signal_init_value);
/* Assign FPGA internal SRAM/Memory ports to bitstream values */
print_verilog_preconfig_top_module_load_bitstream(fp, module_manager, top_module,

View File

@ -0,0 +1,178 @@
/********************************************************************
* This file includes most utilized functions that are used to create
* Verilog testbenches
*
* Note: please do NOT use global variables in this file
* so that we can make it free to use anywhere
*******************************************************************/
#include "vtr_assert.h"
#include "device_port.h"
#include "fpga_x2p_utils.h"
#include "fpga_x2p_benchmark_utils.h"
#include "verilog_writer_utils.h"
#include "verilog_testbench_utils.h"
/********************************************************************
* Print an instance of the FPGA top-level module
*******************************************************************/
void print_verilog_testbench_fpga_instance(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& top_module,
const std::string& top_instance_name) {
/* Validate the file stream */
check_file_handler(fp);
/* Include defined top-level module */
print_verilog_comment(fp, std::string("----- FPGA top-level module to be capsulated -----"));
/* Create an empty port-to-port name mapping, because we use default names */
std::map<std::string, BasicPort> port2port_name_map;
/* Use explicit port mapping for a clean instanciation */
print_verilog_module_instance(fp, module_manager, top_module,
top_instance_name,
port2port_name_map, true);
/* Add an empty line as a splitter */
fp << std::endl;
}
/********************************************************************
* Instanciate the input benchmark module
*******************************************************************/
void print_verilog_testbench_benchmark_instance(std::fstream& fp,
const std::string& module_name,
const std::string& instance_name,
const std::string& module_input_port_postfix,
const std::string& module_output_port_postfix,
const std::string& output_port_postfix,
const std::vector<t_logical_block>& L_logical_blocks,
const bool& use_explicit_port_map) {
/* Validate the file stream */
check_file_handler(fp);
fp << "\t" << module_name << " " << instance_name << "(" << std::endl;
size_t port_counter = 0;
for (const t_logical_block& lb : L_logical_blocks) {
/* Bypass non-I/O logical blocks ! */
if ( (VPACK_INPAD != lb.type) && (VPACK_OUTPAD != lb.type) ) {
continue;
}
/* The first port does not need a comma */
if(0 < port_counter){
fp << "," << std::endl;
}
/* Input port follows the logical block name while output port requires a special postfix */
if (VPACK_INPAD == lb.type){
fp << "\t\t";
if (true == use_explicit_port_map) {
fp << "." << std::string(lb.name) << module_input_port_postfix << "(";
}
fp << std::string(lb.name);
if (true == use_explicit_port_map) {
fp << ")";
}
} else {
VTR_ASSERT_SAFE(VPACK_OUTPAD == lb.type);
fp << "\t\t";
if (true == use_explicit_port_map) {
fp << "." << std::string(lb.name) << module_output_port_postfix << "(";
}
fp << std::string(lb.name) << output_port_postfix;
if (true == use_explicit_port_map) {
fp << ")";
}
}
/* Update the counter */
port_counter++;
}
fp << "\t);" << std::endl;
}
/********************************************************************
* This function adds stimuli to I/Os of FPGA fabric
* 1. For mapped I/Os, this function will wire them to the input ports
* of the pre-configured FPGA top module
* 2. For unmapped I/Os, this function will assign a constant value
* by default
*******************************************************************/
void print_verilog_testbench_connect_fpga_ios(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& top_module,
const std::vector<t_logical_block>& L_logical_blocks,
const vtr::Point<size_t>& device_size,
const std::vector<std::vector<t_grid_tile>>& L_grids,
const std::vector<t_block>& L_blocks,
const std::string& io_port_name_postfix,
const size_t& unused_io_value) {
/* Validate the file stream */
check_file_handler(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];
/* Keep tracking which I/Os have been used */
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 t_logical_block& io_lb : L_logical_blocks) {
/* We only care I/O logical blocks !*/
if ( (VPACK_INPAD != io_lb.type) && (VPACK_OUTPAD != io_lb.type) ) {
continue;
}
/* Find the index of the mapped GPIO in top-level FPGA fabric */
size_t io_index = find_benchmark_io_index(io_lb, device_size, L_grids, L_blocks);
/* 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);
/* Create the port for benchmark I/O, due to BLIF benchmark, each I/O always has a size of 1 */
BasicPort benchmark_io_port(std::string(std::string(io_lb.name)+ io_port_name_postfix), 1);
print_verilog_comment(fp, std::string("----- Blif Benchmark inout " + std::string(io_lb.name) + " is mapped to FPGA IOPAD " + module_mapped_io_port.get_name() + "[" + std::to_string(io_index) + "] -----"));
if (VPACK_INPAD == io_lb.type) {
print_verilog_wire_connection(fp, module_mapped_io_port, benchmark_io_port, false);
} else {
VTR_ASSERT(VPACK_OUTPAD == io_lb.type);
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;
}
/* 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 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;
}

View File

@ -0,0 +1,35 @@
#ifndef VERILOG_TESTBENCH_UTILS_H
#define VERILOG_TESTBENCH_UTILS_H
/* Include header files which are used in the function declaration */
#include <fstream>
#include <string>
#include <vector>
#include "module_manager.h"
#include "vpr_types.h"
void print_verilog_testbench_fpga_instance(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& top_module,
const std::string& top_instance_name);
void print_verilog_testbench_benchmark_instance(std::fstream& fp,
const std::string& module_name,
const std::string& instance_name,
const std::string& module_input_port_postfix,
const std::string& module_output_port_postfix,
const std::string& output_port_postfix,
const std::vector<t_logical_block>& L_logical_blocks,
const bool& use_explicit_port_map);
void print_verilog_testbench_connect_fpga_ios(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& top_module,
const std::vector<t_logical_block>& L_logical_blocks,
const vtr::Point<size_t>& device_size,
const std::vector<std::vector<t_grid_tile>>& L_grids,
const std::vector<t_block>& L_blocks,
const std::string& io_port_name_postfix,
const size_t& unused_io_value);
#endif

View File

@ -1329,7 +1329,7 @@ void dump_verilog_input_blif_testbench_stimuli(FILE* fp,
*/
void dump_verilog_top_testbench(t_sram_orgz_info* cur_sram_orgz_info,
char* circuit_name,
char* top_netlist_name,
const char* top_netlist_name,
char* verilog_dir_path,
t_spice verilog) {
FILE* fp = NULL;

View File

@ -1,3 +1,27 @@
#ifndef VERILOG_TOP_TESTBENCH
#define VERILOG_TOP_TESTBENCH
#include <string>
#include <vector>
#include "module_manager.h"
#include "bitstream_manager.h"
#include "circuit_library.h"
void print_verilog_top_testbench(const ModuleManager& module_manager,
const BitstreamManager& bitstream_manager,
const std::vector<ConfigBitId>& fabric_bitstream,
const e_sram_orgz& sram_orgz_type,
const CircuitLibrary& circuit_lib,
const std::vector<CircuitPortId>& global_ports,
const std::vector<t_logical_block>& L_logical_blocks,
const vtr::Point<size_t>& device_size,
const std::vector<std::vector<t_grid_tile>>& L_grids,
const std::vector<t_block>& L_blocks,
const std::string& circuit_name,
const std::string& verilog_fname,
const std::string& verilog_dir,
const std::string& reference_benchmark_file,
const t_spice_params& simulation_parameters);
void dump_verilog_top_testbench_global_ports(FILE* fp, t_llist* head,
enum e_dump_verilog_port_type dump_port_type);
@ -15,7 +39,7 @@ void dump_verilog_top_testbench_stimuli(t_sram_orgz_info* cur_sram_orgz_info,
void dump_verilog_top_testbench(t_sram_orgz_info* cur_sram_orgz_info,
char* circuit_name,
char* top_netlist_name,
const char* top_netlist_name,
char* verilog_dir_path,
t_spice verilog);
@ -23,3 +47,5 @@ void dump_verilog_input_blif_testbench(char* circuit_name,
char* top_netlist_name,
char* verilog_dir_path,
t_spice verilog);
#endif

View File

@ -6,6 +6,8 @@
#include <ctime>
#include <string>
#include <fstream>
#include <iomanip>
#include "vtr_assert.h"
/* Device-level header files */
@ -1210,3 +1212,131 @@ void print_verilog_formal_verification_mux_sram_ports_wiring(std::fstream& fp,
print_verilog_wire_connection(fp, mux_sram_output, formal_verification_port, false);
}
/********************************************************************
* Print stimuli for a pulse generation
*
* |<--- pulse width --->|
* +------ flip_value
* |
* initial_value ----------------------+
*
*******************************************************************/
void print_verilog_pulse_stimuli(std::fstream& fp,
const BasicPort& port,
const size_t& initial_value,
const float& pulse_width,
const size_t& flip_value) {
/* Validate the file stream */
check_file_handler(fp);
/* Config_done signal: indicate when configuration is finished */
fp << "initial" << std::endl;
fp << "\tbegin" << std::endl;
fp << "\t";
std::vector<size_t> initial_values(port.get_width(), initial_value);
print_verilog_wire_constant_values(fp, port, initial_values);
/* if flip_value is the same as initial value, we do not need to flip the signal ! */
if (flip_value != initial_value) {
fp << "\t" << "#" << std::setprecision(2) << pulse_width;
std::vector<size_t> port_flip_values(port.get_width(), flip_value);
print_verilog_wire_constant_values(fp, port, port_flip_values);
}
fp << "\tend" << std::endl;
/* Print an empty line as splitter */
fp << std::endl;
}
/********************************************************************
* Print stimuli for a pulse generation
* This function supports multiple signal switching under different pulse width
*
* |<-- wait condition -->|
* |<--- pulse width --->|
* +------ flip_values
* |
* initial_value ------- ... --------------------------------+
*
*******************************************************************/
void print_verilog_pulse_stimuli(std::fstream& fp,
const BasicPort& port,
const size_t& initial_value,
const std::vector<float>& pulse_widths,
const std::vector<size_t>& flip_values,
const std::string& wait_condition) {
/* Validate the file stream */
check_file_handler(fp);
/* Config_done signal: indicate when configuration is finished */
fp << "initial" << std::endl;
fp << "\tbegin" << std::endl;
fp << "\t";
std::vector<size_t> initial_values(port.get_width(), initial_value);
print_verilog_wire_constant_values(fp, port, initial_values);
/* Set a wait condition if specified */
if (false == wait_condition.empty()) {
fp << "\twait(" << wait_condition << ")" << std::endl;
}
/* Number of flip conditions and values should match */
VTR_ASSERT(flip_values.size() == pulse_widths.size());
for (size_t ipulse = 0; ipulse < pulse_widths.size(); ++ipulse) {
fp << "\t" << "#" << std::setprecision(2) << pulse_widths[ipulse];
std::vector<size_t> port_flip_value(port.get_width(), flip_values[ipulse]);
print_verilog_wire_constant_values(fp, port, port_flip_value);
}
fp << "\tend" << std::endl;
/* Print an empty line as splitter */
fp << std::endl;
}
/********************************************************************
* Print stimuli for a clock signal
* This function can support if the clock signal should wait for a period
* of time and then start
* pulse width
* |<----->|
* +-------+ +-------+
* | | | |
* initial_value --- ... ---+ +-------+ +------ ...
* |<--wait_condition-->|
*
*******************************************************************/
void print_verilog_clock_stimuli(std::fstream& fp,
const BasicPort& port,
const size_t& initial_value,
const float& pulse_width,
const std::string& wait_condition) {
/* Validate the file stream */
check_file_handler(fp);
/* Config_done signal: indicate when configuration is finished */
fp << "initial" << std::endl;
fp << "\tbegin" << std::endl;
fp << "\t";
std::vector<size_t> initial_values(port.get_width(), initial_value);
print_verilog_wire_constant_values(fp, port, initial_values);
fp << "\tend" << std::endl;
fp << "always";
/* Set a wait condition if specified */
if (true == wait_condition.empty()) {
fp << std::endl;
} else {
fp << " wait(" << wait_condition << ")" << std::endl;
}
fp << "\tbegin" << std::endl;
fp << "\t\t" << "#" << std::setprecision(2) << pulse_width;
print_verilog_wire_connection(fp, port, port, true);
fp << "\tend" << std::endl;
/* Print an empty line as splitter */
fp << std::endl;
}

View File

@ -6,6 +6,8 @@
#ifndef VERILOG_WRITER_UTILS_H
#define VERILOG_WRITER_UTILS_H
#include <fstream>
#include <vector>
#include <string>
#include "verilog_global.h"
#include "device_port.h"
@ -143,4 +145,23 @@ void print_verilog_formal_verification_mux_sram_ports_wiring(std::fstream& fp,
const size_t& num_conf_bits,
const BasicPort& fm_config_bus);
void print_verilog_pulse_stimuli(std::fstream& fp,
const BasicPort& port,
const size_t& initial_value,
const float& pulse_width,
const size_t& flip_value);
void print_verilog_pulse_stimuli(std::fstream& fp,
const BasicPort& port,
const size_t& initial_value,
const std::vector<float>& pulse_widths,
const std::vector<size_t>& flip_values,
const std::string& wait_condition);
void print_verilog_clock_stimuli(std::fstream& fp,
const BasicPort& port,
const size_t& initial_value,
const float& pulse_width,
const std::string& wait_condition);
#endif