refactoring auto-check top Verilog testbench
This commit is contained in:
parent
dc241e6c03
commit
0ec465d4e1
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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 -------"));
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue