[Tool] Deprecate command 'write_verilog_testbench'
This commit is contained in:
parent
b719419931
commit
7ade48343c
|
@ -61,64 +61,6 @@ int write_fabric_verilog(OpenfpgaContext& openfpga_ctx,
|
|||
return CMD_EXEC_SUCCESS;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* A wrapper function to call the Verilog testbench generator of FPGA-Verilog
|
||||
*******************************************************************/
|
||||
int write_verilog_testbench(OpenfpgaContext& openfpga_ctx,
|
||||
const Command& cmd, const CommandContext& cmd_context) {
|
||||
|
||||
CommandOptionId opt_output_dir = cmd.option("file");
|
||||
CommandOptionId opt_fabric_netlist = cmd.option("fabric_netlist_file_path");
|
||||
CommandOptionId opt_pcf = cmd.option("pin_constraints_file");
|
||||
CommandOptionId opt_reference_benchmark = cmd.option("reference_benchmark_file_path");
|
||||
CommandOptionId opt_print_top_testbench = cmd.option("print_top_testbench");
|
||||
CommandOptionId opt_fast_configuration = cmd.option("fast_configuration");
|
||||
CommandOptionId opt_print_formal_verification_top_netlist = cmd.option("print_formal_verification_top_netlist");
|
||||
CommandOptionId opt_print_preconfig_top_testbench = cmd.option("print_preconfig_top_testbench");
|
||||
CommandOptionId opt_print_simulation_ini = cmd.option("print_simulation_ini");
|
||||
CommandOptionId opt_explicit_port_mapping = cmd.option("explicit_port_mapping");
|
||||
CommandOptionId opt_include_signal_init = cmd.option("include_signal_init");
|
||||
CommandOptionId opt_support_icarus_simulator = cmd.option("support_icarus_simulator");
|
||||
CommandOptionId opt_verbose = cmd.option("verbose");
|
||||
|
||||
/* This is an intermediate data structure which is designed to modularize the FPGA-Verilog
|
||||
* Keep it independent from any other outside data structures
|
||||
*/
|
||||
VerilogTestbenchOption options;
|
||||
options.set_output_directory(cmd_context.option_value(cmd, opt_output_dir));
|
||||
options.set_fabric_netlist_file_path(cmd_context.option_value(cmd, opt_fabric_netlist));
|
||||
options.set_reference_benchmark_file_path(cmd_context.option_value(cmd, opt_reference_benchmark));
|
||||
options.set_print_formal_verification_top_netlist(cmd_context.option_enable(cmd, opt_print_formal_verification_top_netlist));
|
||||
options.set_print_preconfig_top_testbench(cmd_context.option_enable(cmd, opt_print_preconfig_top_testbench));
|
||||
options.set_fast_configuration(cmd_context.option_enable(cmd, opt_fast_configuration));
|
||||
options.set_print_top_testbench(cmd_context.option_enable(cmd, opt_print_top_testbench));
|
||||
options.set_print_simulation_ini(cmd_context.option_value(cmd, opt_print_simulation_ini));
|
||||
options.set_explicit_port_mapping(cmd_context.option_enable(cmd, opt_explicit_port_mapping));
|
||||
options.set_include_signal_init(cmd_context.option_enable(cmd, opt_include_signal_init));
|
||||
options.set_support_icarus_simulator(cmd_context.option_enable(cmd, opt_support_icarus_simulator));
|
||||
options.set_verbose_output(cmd_context.option_enable(cmd, opt_verbose));
|
||||
|
||||
/* If pin constraints are enabled by command options, read the file */
|
||||
PinConstraints pin_constraints;
|
||||
if (true == cmd_context.option_enable(cmd, opt_pcf)) {
|
||||
pin_constraints = read_xml_pin_constraints(cmd_context.option_value(cmd, opt_pcf).c_str());
|
||||
}
|
||||
|
||||
return fpga_verilog_testbench(openfpga_ctx.module_graph(),
|
||||
openfpga_ctx.bitstream_manager(),
|
||||
openfpga_ctx.fabric_bitstream(),
|
||||
g_vpr_ctx.atom(),
|
||||
g_vpr_ctx.placement(),
|
||||
pin_constraints,
|
||||
openfpga_ctx.io_location_map(),
|
||||
openfpga_ctx.fabric_global_port_info(),
|
||||
openfpga_ctx.vpr_netlist_annotation(),
|
||||
openfpga_ctx.arch().circuit_lib,
|
||||
openfpga_ctx.simulation_setting(),
|
||||
openfpga_ctx.arch().config_protocol,
|
||||
options);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* A wrapper function to call the full testbench generator of FPGA-Verilog
|
||||
*******************************************************************/
|
||||
|
|
|
@ -18,9 +18,6 @@ namespace openfpga {
|
|||
int write_fabric_verilog(OpenfpgaContext& openfpga_ctx,
|
||||
const Command& cmd, const CommandContext& cmd_context);
|
||||
|
||||
int write_verilog_testbench(OpenfpgaContext& openfpga_ctx,
|
||||
const Command& cmd, const CommandContext& cmd_context);
|
||||
|
||||
int write_full_testbench(const OpenfpgaContext& openfpga_ctx,
|
||||
const Command& cmd, const CommandContext& cmd_context);
|
||||
|
||||
|
|
|
@ -54,74 +54,6 @@ ShellCommandId add_openfpga_write_fabric_verilog_command(openfpga::Shell<Openfpg
|
|||
return shell_cmd_id;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* - Add a command to Shell environment: write Verilog testbench
|
||||
* - Add associated options
|
||||
* - Add command dependency
|
||||
*******************************************************************/
|
||||
static
|
||||
ShellCommandId add_openfpga_write_verilog_testbench_command(openfpga::Shell<OpenfpgaContext>& shell,
|
||||
const ShellCommandClassId& cmd_class_id,
|
||||
const std::vector<ShellCommandId>& dependent_cmds) {
|
||||
Command shell_cmd("write_verilog_testbench");
|
||||
|
||||
/* Add an option '--file' in short '-f'*/
|
||||
CommandOptionId output_opt = shell_cmd.add_option("file", true, "Specify the output directory for Verilog netlists");
|
||||
shell_cmd.set_option_short_name(output_opt, "f");
|
||||
shell_cmd.set_option_require_value(output_opt, openfpga::OPT_STRING);
|
||||
|
||||
/* Add an option '--fabric_netlist_file_path'*/
|
||||
CommandOptionId fabric_netlist_opt = shell_cmd.add_option("fabric_netlist_file_path", false, "Specify the file path to the fabric Verilog netlist");
|
||||
shell_cmd.set_option_require_value(fabric_netlist_opt, openfpga::OPT_STRING);
|
||||
|
||||
/* Add an option '--pin_constraints_file in short '-pcf' */
|
||||
CommandOptionId pcf_opt = shell_cmd.add_option("pin_constraints_file", false, "Specify the file path to the pin constraints");
|
||||
shell_cmd.set_option_short_name(pcf_opt, "pcf");
|
||||
shell_cmd.set_option_require_value(pcf_opt, openfpga::OPT_STRING);
|
||||
|
||||
/* Add an option '--reference_benchmark_file_path'*/
|
||||
CommandOptionId ref_bm_opt = shell_cmd.add_option("reference_benchmark_file_path", true, "Specify the file path to the reference Verilog netlist");
|
||||
shell_cmd.set_option_require_value(ref_bm_opt, openfpga::OPT_STRING);
|
||||
|
||||
/* Add an option '--print_top_testbench' */
|
||||
shell_cmd.add_option("print_top_testbench", false, "Generate a full testbench for top-level fabric module with autocheck capability");
|
||||
|
||||
/* Add an option '--fast_configuration' */
|
||||
shell_cmd.add_option("fast_configuration", false, "Reduce the period of configuration by skip zero data points");
|
||||
|
||||
/* Add an option '--print_formal_verification_top_netlist' */
|
||||
shell_cmd.add_option("print_formal_verification_top_netlist", false, "Generate a top-level module which can be used in formal verification");
|
||||
|
||||
/* Add an option '--print_preconfig_top_testbench' */
|
||||
shell_cmd.add_option("print_preconfig_top_testbench", false, "Generate a pre-configured testbench for top-level fabric module with autocheck capability");
|
||||
|
||||
/* Add an option '--print_simulation_ini' */
|
||||
CommandOptionId sim_ini_opt = shell_cmd.add_option("print_simulation_ini", false, "Generate a .ini file as an exchangeable file to enable HDL simulations");
|
||||
shell_cmd.set_option_require_value(sim_ini_opt, openfpga::OPT_STRING);
|
||||
|
||||
/* Add an option '--explicit_port_mapping' */
|
||||
shell_cmd.add_option("explicit_port_mapping", false, "Use explicit port mapping in Verilog netlists");
|
||||
|
||||
/* Add an option '--include_signal_init' */
|
||||
shell_cmd.add_option("include_signal_init", false, "Initialize all the signals in Verilog testbenches");
|
||||
|
||||
/* Add an option '--support_icarus_simulator' */
|
||||
shell_cmd.add_option("support_icarus_simulator", false, "Fine-tune Verilog testbenches to support icarus simulator");
|
||||
|
||||
/* Add an option '--verbose' */
|
||||
shell_cmd.add_option("verbose", false, "Enable verbose output");
|
||||
|
||||
/* Add command to the Shell */
|
||||
ShellCommandId shell_cmd_id = shell.add_command(shell_cmd, "generate Verilog testbenches for full FPGA fabric");
|
||||
shell.set_command_class(shell_cmd_id, cmd_class_id);
|
||||
shell.set_command_execute_function(shell_cmd_id, write_verilog_testbench);
|
||||
|
||||
/* Add command dependency to the Shell */
|
||||
shell.set_command_dependency(shell_cmd_id, dependent_cmds);
|
||||
|
||||
return shell_cmd_id;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* - add a command to shell environment: write full testbench
|
||||
* - add associated options
|
||||
|
@ -327,16 +259,6 @@ void add_openfpga_verilog_commands(openfpga::Shell<OpenfpgaContext>& shell) {
|
|||
openfpga_verilog_cmd_class,
|
||||
fabric_verilog_dependent_cmds);
|
||||
|
||||
/********************************
|
||||
* Command 'write_verilog_testbench'
|
||||
*/
|
||||
/* The command 'write_verilog_testbench' should NOT be executed before 'build_fabric' */
|
||||
std::vector<ShellCommandId> verilog_testbench_dependent_cmds;
|
||||
verilog_testbench_dependent_cmds.push_back(build_fabric_cmd_id);
|
||||
add_openfpga_write_verilog_testbench_command(shell,
|
||||
openfpga_verilog_cmd_class,
|
||||
verilog_testbench_dependent_cmds);
|
||||
|
||||
/********************************
|
||||
* Command 'write_full_testbench'
|
||||
*/
|
||||
|
|
|
@ -139,119 +139,6 @@ void fpga_fabric_verilog(ModuleManager &module_manager,
|
|||
module_manager.num_modules());
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* A top-level function of FPGA-Verilog which focuses on fabric Verilog generation
|
||||
* This function will generate
|
||||
* - A wrapper module, which encapsulate the FPGA module in a Verilog module which have the same port as the input benchmark
|
||||
* - Testbench, where a FPGA module is configured with a bitstream and then driven by input vectors
|
||||
* - Pre-configured testbench, which can skip the configuration phase and pre-configure the FPGA module.
|
||||
* This testbench is created for quick verification and formal verification purpose.
|
||||
* - Verilog netlist including preprocessing flags and all the Verilog netlists that have been generated
|
||||
********************************************************************/
|
||||
int fpga_verilog_testbench(const ModuleManager &module_manager,
|
||||
const BitstreamManager &bitstream_manager,
|
||||
const FabricBitstream &fabric_bitstream,
|
||||
const AtomContext &atom_ctx,
|
||||
const PlacementContext &place_ctx,
|
||||
const PinConstraints& pin_constraints,
|
||||
const IoLocationMap &io_location_map,
|
||||
const FabricGlobalPortInfo &fabric_global_port_info,
|
||||
const VprNetlistAnnotation &netlist_annotation,
|
||||
const CircuitLibrary &circuit_lib,
|
||||
const SimulationSetting &simulation_setting,
|
||||
const ConfigProtocol &config_protocol,
|
||||
const VerilogTestbenchOption &options) {
|
||||
|
||||
vtr::ScopedStartFinishTimer timer("Write Verilog testbenches for FPGA fabric\n");
|
||||
|
||||
std::string src_dir_path = format_dir_path(options.output_directory());
|
||||
|
||||
std::string netlist_name = atom_ctx.nlist.netlist_name();
|
||||
|
||||
int status = CMD_EXEC_SUCCESS;
|
||||
|
||||
/* Create directories */
|
||||
create_directory(src_dir_path);
|
||||
|
||||
/* Output preprocessing flags for HDL simulations */
|
||||
print_verilog_simulation_preprocessing_flags(std::string(src_dir_path),
|
||||
options);
|
||||
|
||||
/* Generate wrapper module for FPGA fabric (mapped by the input benchmark and pre-configured testbench for verification */
|
||||
if (true == options.print_formal_verification_top_netlist()) {
|
||||
std::string formal_verification_top_netlist_file_path = src_dir_path + netlist_name + std::string(FORMAL_VERIFICATION_VERILOG_FILE_POSTFIX);
|
||||
status = print_verilog_preconfig_top_module(module_manager, bitstream_manager,
|
||||
config_protocol,
|
||||
circuit_lib, fabric_global_port_info,
|
||||
atom_ctx, place_ctx,
|
||||
pin_constraints,
|
||||
io_location_map,
|
||||
netlist_annotation,
|
||||
netlist_name,
|
||||
formal_verification_top_netlist_file_path,
|
||||
options.explicit_port_mapping());
|
||||
if (status == CMD_EXEC_FATAL_ERROR) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
if (true == options.print_preconfig_top_testbench()) {
|
||||
/* Generate top-level testbench using random vectors */
|
||||
std::string random_top_testbench_file_path = src_dir_path + netlist_name + std::string(RANDOM_TOP_TESTBENCH_VERILOG_FILE_POSTFIX);
|
||||
print_verilog_random_top_testbench(netlist_name,
|
||||
random_top_testbench_file_path,
|
||||
atom_ctx,
|
||||
netlist_annotation,
|
||||
module_manager,
|
||||
fabric_global_port_info,
|
||||
pin_constraints,
|
||||
simulation_setting,
|
||||
options.explicit_port_mapping());
|
||||
}
|
||||
|
||||
/* Generate full testbench for verification, including configuration phase and operating phase */
|
||||
if (true == options.print_top_testbench()) {
|
||||
std::string top_testbench_file_path = src_dir_path + netlist_name + std::string(AUTOCHECK_TOP_TESTBENCH_VERILOG_FILE_POSTFIX);
|
||||
print_verilog_top_testbench(module_manager,
|
||||
bitstream_manager, fabric_bitstream,
|
||||
circuit_lib,
|
||||
config_protocol,
|
||||
fabric_global_port_info,
|
||||
atom_ctx, place_ctx,
|
||||
pin_constraints,
|
||||
io_location_map,
|
||||
netlist_annotation,
|
||||
netlist_name,
|
||||
top_testbench_file_path,
|
||||
simulation_setting,
|
||||
options);
|
||||
}
|
||||
|
||||
/* Generate exchangeable files which contains simulation settings */
|
||||
if (true == options.print_simulation_ini()) {
|
||||
std::string simulation_ini_file_name = options.simulation_ini_path();
|
||||
VTR_ASSERT(true != options.simulation_ini_path().empty());
|
||||
print_verilog_simulation_info(simulation_ini_file_name,
|
||||
netlist_name,
|
||||
src_dir_path,
|
||||
atom_ctx, place_ctx, io_location_map,
|
||||
module_manager,
|
||||
config_protocol.type(),
|
||||
bitstream_manager.num_bits(),
|
||||
simulation_setting.num_clock_cycles(),
|
||||
simulation_setting.programming_clock_frequency(),
|
||||
simulation_setting.default_operating_clock_frequency());
|
||||
}
|
||||
|
||||
/* Generate a Verilog file including all the netlists that have been generated */
|
||||
print_verilog_testbench_include_netlists(src_dir_path,
|
||||
netlist_name,
|
||||
options.fabric_netlist_file_path(),
|
||||
options.reference_benchmark_file_path());
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* A top-level function of FPGA-Verilog which focuses on full testbench generation
|
||||
* This function will generate
|
||||
|
|
|
@ -43,20 +43,6 @@ void fpga_fabric_verilog(ModuleManager& module_manager,
|
|||
const DeviceRRGSB& device_rr_gsb,
|
||||
const FabricVerilogOption& options);
|
||||
|
||||
int fpga_verilog_testbench(const ModuleManager& module_manager,
|
||||
const BitstreamManager& bitstream_manager,
|
||||
const FabricBitstream& fabric_bitstream,
|
||||
const AtomContext& atom_ctx,
|
||||
const PlacementContext& place_ctx,
|
||||
const PinConstraints& pin_constraints,
|
||||
const IoLocationMap& io_location_map,
|
||||
const FabricGlobalPortInfo &fabric_global_port_info,
|
||||
const VprNetlistAnnotation& netlist_annotation,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const SimulationSetting& simulation_parameters,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const VerilogTestbenchOption& options);
|
||||
|
||||
int fpga_verilog_full_testbench(const ModuleManager& module_manager,
|
||||
const BitstreamManager& bitstream_manager,
|
||||
const FabricBitstream& fabric_bitstream,
|
||||
|
|
|
@ -945,229 +945,6 @@ void print_verilog_top_testbench_benchmark_instance(std::fstream& fp,
|
|||
fp << std::endl;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Print tasks (processes) in Verilog format,
|
||||
* which is very useful in generating stimuli for each clock cycle
|
||||
* This function is tuned for configuration-chain manipulation:
|
||||
* During each programming cycle, we feed the input of scan chain with a memory bit
|
||||
*******************************************************************/
|
||||
static
|
||||
void print_verilog_top_testbench_load_bitstream_task_configuration_chain(std::fstream& fp,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module) {
|
||||
|
||||
/* Validate the file stream */
|
||||
valid_file_stream(fp);
|
||||
|
||||
BasicPort prog_clock_port(std::string(TOP_TB_PROG_CLOCK_PORT_NAME), 1);
|
||||
ModulePortId cc_head_port_id = module_manager.find_module_port(top_module, generate_configuration_chain_head_name());
|
||||
BasicPort cc_head_port = module_manager.module_port(top_module, cc_head_port_id);
|
||||
BasicPort cc_head_value(generate_configuration_chain_head_name() + std::string("_val"), cc_head_port.get_width());
|
||||
|
||||
/* Add an empty line as splitter */
|
||||
fp << std::endl;
|
||||
|
||||
/* Feed the scan-chain input at each falling edge of programming clock
|
||||
* It aims at avoid racing the programming clock (scan-chain data changes at the rising edge).
|
||||
*/
|
||||
print_verilog_comment(fp, std::string("----- Task: input values during a programming clock cycle -----"));
|
||||
fp << "task " << std::string(TOP_TESTBENCH_PROG_TASK_NAME) << ";" << std::endl;
|
||||
fp << generate_verilog_port(VERILOG_PORT_INPUT, cc_head_value) << ";" << std::endl;
|
||||
fp << "\tbegin" << std::endl;
|
||||
fp << "\t\t@(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_port) << ");" << std::endl;
|
||||
fp << "\t\t\t";
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, cc_head_port);
|
||||
fp << " = ";
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, cc_head_value);
|
||||
fp << ";" << std::endl;
|
||||
|
||||
fp << "\tend" << std::endl;
|
||||
fp << "endtask" << std::endl;
|
||||
|
||||
/* Add an empty line as splitter */
|
||||
fp << std::endl;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Print tasks (processes) in Verilog format,
|
||||
* which is very useful in generating stimuli for each clock cycle
|
||||
* This function is tuned for memory bank manipulation:
|
||||
* During each programming cycle, we feed
|
||||
* - an address to the BL address port of top module
|
||||
* - an address to the WL address port of top module
|
||||
* - a data input to the din port of top module
|
||||
*******************************************************************/
|
||||
static
|
||||
void print_verilog_top_testbench_load_bitstream_task_memory_bank(std::fstream& fp,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module) {
|
||||
|
||||
/* Validate the file stream */
|
||||
valid_file_stream(fp);
|
||||
|
||||
BasicPort prog_clock_port(std::string(TOP_TB_PROG_CLOCK_PORT_NAME), 1);
|
||||
|
||||
ModulePortId bl_addr_port_id = module_manager.find_module_port(top_module,
|
||||
std::string(DECODER_BL_ADDRESS_PORT_NAME));
|
||||
BasicPort bl_addr_port = module_manager.module_port(top_module, bl_addr_port_id);
|
||||
BasicPort bl_addr_value = bl_addr_port;
|
||||
bl_addr_value.set_name(std::string(MEMORY_BL_PORT_NAME) + std::string("_val"));
|
||||
|
||||
ModulePortId wl_addr_port_id = module_manager.find_module_port(top_module,
|
||||
std::string(DECODER_WL_ADDRESS_PORT_NAME));
|
||||
BasicPort wl_addr_port = module_manager.module_port(top_module, wl_addr_port_id);
|
||||
BasicPort wl_addr_value = wl_addr_port;
|
||||
wl_addr_value.set_name(std::string(MEMORY_WL_PORT_NAME) + std::string("_val"));
|
||||
|
||||
ModulePortId din_port_id = module_manager.find_module_port(top_module,
|
||||
std::string(DECODER_DATA_IN_PORT_NAME));
|
||||
BasicPort din_port = module_manager.module_port(top_module, din_port_id);
|
||||
BasicPort din_value = din_port;
|
||||
din_value.set_name(std::string(DECODER_DATA_IN_PORT_NAME) + std::string("_val"));
|
||||
|
||||
/* Add an empty line as splitter */
|
||||
fp << std::endl;
|
||||
|
||||
/* Feed the address and data input at each falling edge of programming clock
|
||||
* As the enable signal is wired to the programming clock, we should synchronize
|
||||
* address and data with the enable signal
|
||||
*/
|
||||
print_verilog_comment(fp, std::string("----- Task: assign BL and WL address, and data values at rising edge of enable signal -----"));
|
||||
fp << "task " << std::string(TOP_TESTBENCH_PROG_TASK_NAME) << ";" << std::endl;
|
||||
fp << generate_verilog_port(VERILOG_PORT_INPUT, bl_addr_value) << ";" << std::endl;
|
||||
fp << generate_verilog_port(VERILOG_PORT_INPUT, wl_addr_value) << ";" << std::endl;
|
||||
fp << generate_verilog_port(VERILOG_PORT_INPUT, din_value) << ";" << std::endl;
|
||||
fp << "\tbegin" << std::endl;
|
||||
fp << "\t\t@(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_port) << ");" << std::endl;
|
||||
|
||||
fp << "\t\t\t";
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, bl_addr_port);
|
||||
fp << " = ";
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, bl_addr_value);
|
||||
fp << ";" << std::endl;
|
||||
fp << std::endl;
|
||||
|
||||
fp << "\t\t\t";
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, wl_addr_port);
|
||||
fp << " = ";
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, wl_addr_value);
|
||||
fp << ";" << std::endl;
|
||||
fp << std::endl;
|
||||
|
||||
fp << "\t\t\t";
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, din_port);
|
||||
fp << " = ";
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, din_value);
|
||||
fp << ";" << std::endl;
|
||||
fp << std::endl;
|
||||
|
||||
fp << "\tend" << std::endl;
|
||||
fp << "endtask" << std::endl;
|
||||
|
||||
/* Add an empty line as splitter */
|
||||
fp << std::endl;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Print tasks (processes) in Verilog format,
|
||||
* which is very useful in generating stimuli for each clock cycle
|
||||
* This function is tuned for frame-based memory manipulation:
|
||||
* During each programming cycle, we feed
|
||||
* - an address to the address port of top module
|
||||
* - a data input to the din port of top module
|
||||
*******************************************************************/
|
||||
static
|
||||
void print_verilog_top_testbench_load_bitstream_task_frame_decoder(std::fstream& fp,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module) {
|
||||
|
||||
/* Validate the file stream */
|
||||
valid_file_stream(fp);
|
||||
|
||||
BasicPort prog_clock_port(std::string(TOP_TB_PROG_CLOCK_PORT_NAME), 1);
|
||||
|
||||
ModulePortId addr_port_id = module_manager.find_module_port(top_module,
|
||||
std::string(DECODER_ADDRESS_PORT_NAME));
|
||||
BasicPort addr_port = module_manager.module_port(top_module, addr_port_id);
|
||||
BasicPort addr_value = addr_port;
|
||||
addr_value.set_name(std::string(DECODER_ADDRESS_PORT_NAME) + std::string("_val"));
|
||||
|
||||
ModulePortId din_port_id = module_manager.find_module_port(top_module,
|
||||
std::string(DECODER_DATA_IN_PORT_NAME));
|
||||
BasicPort din_port = module_manager.module_port(top_module, din_port_id);
|
||||
BasicPort din_value = din_port;
|
||||
din_value.set_name(std::string(DECODER_DATA_IN_PORT_NAME) + std::string("_val"));
|
||||
|
||||
/* Add an empty line as splitter */
|
||||
fp << std::endl;
|
||||
|
||||
/* Feed the address and data input at each falling edge of programming clock
|
||||
* As the enable signal is wired to the programming clock, we should synchronize
|
||||
* address and data with the enable signal
|
||||
*/
|
||||
print_verilog_comment(fp, std::string("----- Task: assign address and data values at rising edge of enable signal -----"));
|
||||
fp << "task " << std::string(TOP_TESTBENCH_PROG_TASK_NAME) << ";" << std::endl;
|
||||
fp << generate_verilog_port(VERILOG_PORT_INPUT, addr_value) << ";" << std::endl;
|
||||
fp << generate_verilog_port(VERILOG_PORT_INPUT, din_value) << ";" << std::endl;
|
||||
fp << "\tbegin" << std::endl;
|
||||
fp << "\t\t@(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_port) << ");" << std::endl;
|
||||
|
||||
fp << "\t\t\t";
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, addr_port);
|
||||
fp << " = ";
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, addr_value);
|
||||
fp << ";" << std::endl;
|
||||
fp << std::endl;
|
||||
|
||||
fp << "\t\t\t";
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, din_port);
|
||||
fp << " = ";
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, din_value);
|
||||
fp << ";" << std::endl;
|
||||
fp << std::endl;
|
||||
|
||||
fp << "\tend" << std::endl;
|
||||
fp << "endtask" << std::endl;
|
||||
|
||||
/* Add an empty line as splitter */
|
||||
fp << std::endl;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Print tasks, which is very useful in generating stimuli for each clock cycle
|
||||
*******************************************************************/
|
||||
static
|
||||
void print_verilog_top_testbench_load_bitstream_task(std::fstream& fp,
|
||||
const e_config_protocol_type& sram_orgz_type,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module) {
|
||||
switch (sram_orgz_type) {
|
||||
case CONFIG_MEM_STANDALONE:
|
||||
/* No need to have a specific task. Loading is done in 1 clock cycle */
|
||||
break;
|
||||
case CONFIG_MEM_SCAN_CHAIN:
|
||||
print_verilog_top_testbench_load_bitstream_task_configuration_chain(fp,
|
||||
module_manager,
|
||||
top_module);
|
||||
break;
|
||||
case CONFIG_MEM_MEMORY_BANK:
|
||||
print_verilog_top_testbench_load_bitstream_task_memory_bank(fp,
|
||||
module_manager,
|
||||
top_module);
|
||||
break;
|
||||
case CONFIG_MEM_FRAME_BASED:
|
||||
print_verilog_top_testbench_load_bitstream_task_frame_decoder(fp,
|
||||
module_manager,
|
||||
top_module);
|
||||
break;
|
||||
default:
|
||||
VTR_LOGF_ERROR(__FILE__, __LINE__,
|
||||
"Invalid type of SRAM organization!\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Print generatic input stimuli for the top testbench
|
||||
* include:
|
||||
|
@ -1370,477 +1147,6 @@ void print_verilog_top_testbench_configuration_protocol_stimulus(std::fstream& f
|
|||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Print stimulus for a FPGA fabric with a flatten memory (standalone) configuration protocol
|
||||
* We will load the bitstream in the second clock cycle, right after the first reset cycle
|
||||
*******************************************************************/
|
||||
static
|
||||
void print_verilog_top_testbench_vanilla_bitstream(std::fstream& fp,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const BitstreamManager& bitstream_manager,
|
||||
const FabricBitstream& fabric_bitstream) {
|
||||
/* Validate the file stream */
|
||||
valid_file_stream(fp);
|
||||
|
||||
/* Find Bit-Line and Word-Line port */
|
||||
BasicPort prog_clock_port(std::string(TOP_TB_PROG_CLOCK_PORT_NAME), 1);
|
||||
|
||||
/* Find Bit-Line and Word-Line port */
|
||||
ModulePortId bl_port_id = module_manager.find_module_port(top_module, std::string(MEMORY_BL_PORT_NAME));
|
||||
BasicPort bl_port = module_manager.module_port(top_module, bl_port_id);
|
||||
|
||||
ModulePortId wl_port_id = module_manager.find_module_port(top_module, std::string(MEMORY_WL_PORT_NAME));
|
||||
BasicPort wl_port = module_manager.module_port(top_module, wl_port_id);
|
||||
|
||||
/* Initial value should be the first configuration bits
|
||||
* In the rest of programming cycles,
|
||||
* configuration bits are fed at the falling edge of programming clock.
|
||||
* We do not care the value of scan_chain head during the first programming cycle
|
||||
* It is reset anyway
|
||||
*/
|
||||
std::vector<size_t> initial_bl_values(bl_port.get_width(), 0);
|
||||
std::vector<size_t> initial_wl_values(wl_port.get_width(), 0);
|
||||
|
||||
print_verilog_comment(fp, "----- Begin bitstream loading during configuration phase -----");
|
||||
fp << "initial" << std::endl;
|
||||
fp << "\tbegin" << std::endl;
|
||||
print_verilog_comment(fp, "----- Configuration chain default input -----");
|
||||
fp << "\t\t";
|
||||
fp << generate_verilog_port_constant_values(bl_port, initial_bl_values);
|
||||
fp << ";" << std::endl;
|
||||
fp << "\t\t";
|
||||
fp << generate_verilog_port_constant_values(wl_port, initial_wl_values);
|
||||
fp << ";" << std::endl;
|
||||
|
||||
fp << std::endl;
|
||||
|
||||
fp << "\t\t@(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_port) << ") begin" << std::endl;
|
||||
|
||||
/* Enable all the WLs */
|
||||
std::vector<size_t> enabled_wl_values(wl_port.get_width(), 1);
|
||||
fp << "\t\t\t";
|
||||
fp << generate_verilog_port_constant_values(wl_port, enabled_wl_values);
|
||||
fp << ";" << std::endl;
|
||||
|
||||
size_t ibit = 0;
|
||||
for (const FabricBitId& bit_id : fabric_bitstream.bits()) {
|
||||
BasicPort cur_bl_port(bl_port);
|
||||
cur_bl_port.set_width(ibit, ibit);
|
||||
|
||||
fp << "\t\t\t";
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, cur_bl_port);
|
||||
fp << " = ";
|
||||
fp << "1'b" << (size_t)bitstream_manager.bit_value(fabric_bitstream.config_bit(bit_id));
|
||||
fp << ";" << std::endl;
|
||||
|
||||
ibit++;
|
||||
}
|
||||
|
||||
fp << "\t\tend" << std::endl;
|
||||
|
||||
/* Disable all the WLs */
|
||||
fp << "\t\t@(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_port) << ");" << std::endl;
|
||||
|
||||
fp << "\t\t\t";
|
||||
fp << generate_verilog_port_constant_values(wl_port, initial_wl_values);
|
||||
fp << ";" << std::endl;
|
||||
|
||||
/* Raise the flag of configuration done when bitstream loading is complete */
|
||||
fp << "\t\t@(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_port) << ");" << std::endl;
|
||||
|
||||
BasicPort config_done_port(std::string(TOP_TB_CONFIG_DONE_PORT_NAME), 1);
|
||||
fp << "\t\t\t";
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, config_done_port);
|
||||
fp << " <= ";
|
||||
std::vector<size_t> config_done_enable_values(config_done_port.get_width(), 1);
|
||||
fp << generate_verilog_constant_values(config_done_enable_values);
|
||||
fp << ";" << std::endl;
|
||||
|
||||
fp << "\tend" << std::endl;
|
||||
print_verilog_comment(fp, "----- End bitstream loading during configuration phase -----");
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Print stimulus for a FPGA fabric with a configuration chain protocol
|
||||
* where configuration bits are programming in serial (one by one)
|
||||
* Task list:
|
||||
* 1. For clock signal, we should create voltage waveforms for two types of clock signals:
|
||||
* a. operation clock
|
||||
* b. programming clock
|
||||
* 2. For Set/Reset, we reset the chip after programming phase ends
|
||||
* and before operation phase starts
|
||||
* 3. For input/output clb nets (mapped to I/O grids),
|
||||
* we should create voltage waveforms only after programming phase
|
||||
*******************************************************************/
|
||||
static
|
||||
void print_verilog_top_testbench_configuration_chain_bitstream(std::fstream& fp,
|
||||
const bool& fast_configuration,
|
||||
const bool& bit_value_to_skip,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const BitstreamManager& bitstream_manager,
|
||||
const FabricBitstream& fabric_bitstream) {
|
||||
/* Validate the file stream */
|
||||
valid_file_stream(fp);
|
||||
|
||||
/* Initial value should be the first configuration bits
|
||||
* In the rest of programming cycles,
|
||||
* configuration bits are fed at the falling edge of programming clock.
|
||||
* We do not care the value of scan_chain head during the first programming cycle
|
||||
* It is reset anyway
|
||||
*/
|
||||
ModulePortId cc_head_port_id = module_manager.find_module_port(top_module, generate_configuration_chain_head_name());
|
||||
BasicPort config_chain_head_port = module_manager.module_port(top_module, cc_head_port_id);
|
||||
std::vector<size_t> initial_values(config_chain_head_port.get_width(), 0);
|
||||
|
||||
print_verilog_comment(fp, "----- Begin bitstream loading during configuration phase -----");
|
||||
fp << "initial" << std::endl;
|
||||
fp << "\tbegin" << std::endl;
|
||||
print_verilog_comment(fp, "----- Configuration chain default input -----");
|
||||
fp << "\t\t";
|
||||
fp << generate_verilog_port_constant_values(config_chain_head_port, initial_values);
|
||||
fp << ";";
|
||||
|
||||
fp << std::endl;
|
||||
|
||||
/* Find the longest bitstream */
|
||||
size_t regional_bitstream_max_size = find_fabric_regional_bitstream_max_size(fabric_bitstream);
|
||||
|
||||
/* For fast configuration, the bitstream size counts from the first bit '1' */
|
||||
size_t num_bits_to_skip = 0;
|
||||
if (true == fast_configuration) {
|
||||
num_bits_to_skip = find_configuration_chain_fabric_bitstream_size_to_be_skipped(fabric_bitstream, bitstream_manager, bit_value_to_skip);
|
||||
}
|
||||
VTR_ASSERT(num_bits_to_skip < regional_bitstream_max_size);
|
||||
|
||||
/* Reorganize the regional bitstreams to be the same size */
|
||||
ConfigChainFabricBitstream regional_bitstreams = build_config_chain_fabric_bitstream_by_region(bitstream_manager, fabric_bitstream);
|
||||
|
||||
/* Attention: when the fast configuration is enabled, we will start from the first bit '1'
|
||||
* This requires a reset signal (as we forced in the first clock cycle)
|
||||
*
|
||||
* Note that bitstream may come from different regions
|
||||
* The bitstream value to be loaded should be organized as follows
|
||||
*
|
||||
* cycleA
|
||||
* |
|
||||
* Region 0: 0|00000001111101010
|
||||
* Region 1: | 00000011010101
|
||||
* Region 2: | 0010101111000110
|
||||
*
|
||||
* Zero bits will be added to the head of those bitstreams are shorter
|
||||
* than the longest bitstream
|
||||
*/
|
||||
for (size_t ibit = num_bits_to_skip; ibit < regional_bitstream_max_size; ++ibit) {
|
||||
std::vector<size_t> curr_cc_head_val;
|
||||
curr_cc_head_val.reserve(fabric_bitstream.regions().size());
|
||||
for (const auto& region_bitstream : regional_bitstreams) {
|
||||
curr_cc_head_val.push_back((size_t)region_bitstream[ibit]);
|
||||
}
|
||||
|
||||
fp << "\t\t" << std::string(TOP_TESTBENCH_PROG_TASK_NAME);
|
||||
fp << "(" << generate_verilog_constant_values(curr_cc_head_val) << ");" << std::endl;
|
||||
}
|
||||
|
||||
/* Raise the flag of configuration done when bitstream loading is complete */
|
||||
BasicPort prog_clock_port(std::string(TOP_TB_PROG_CLOCK_PORT_NAME), 1);
|
||||
fp << "\t\t@(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_port) << ");" << std::endl;
|
||||
|
||||
BasicPort config_done_port(std::string(TOP_TB_CONFIG_DONE_PORT_NAME), 1);
|
||||
fp << "\t\t\t";
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, config_done_port);
|
||||
fp << " <= ";
|
||||
std::vector<size_t> config_done_enable_values(config_done_port.get_width(), 1);
|
||||
fp << generate_verilog_constant_values(config_done_enable_values);
|
||||
fp << ";" << std::endl;
|
||||
|
||||
fp << "\tend" << std::endl;
|
||||
print_verilog_comment(fp, "----- End bitstream loading during configuration phase -----");
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Print stimulus for a FPGA fabric with a memory bank configuration protocol
|
||||
* where configuration bits are programming in serial (one by one)
|
||||
*
|
||||
* We will use the programming task function created before
|
||||
*******************************************************************/
|
||||
static
|
||||
void print_verilog_top_testbench_memory_bank_bitstream(std::fstream& fp,
|
||||
const bool& fast_configuration,
|
||||
const bool& bit_value_to_skip,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const FabricBitstream& fabric_bitstream) {
|
||||
/* Validate the file stream */
|
||||
valid_file_stream(fp);
|
||||
|
||||
/* Feed addresss and data input pair one by one
|
||||
* Note: the first cycle is reserved for programming reset
|
||||
* We should give dummy values
|
||||
*/
|
||||
ModulePortId bl_addr_port_id = module_manager.find_module_port(top_module,
|
||||
std::string(DECODER_BL_ADDRESS_PORT_NAME));
|
||||
BasicPort bl_addr_port = module_manager.module_port(top_module, bl_addr_port_id);
|
||||
std::vector<size_t> initial_bl_addr_values(bl_addr_port.get_width(), 0);
|
||||
|
||||
ModulePortId wl_addr_port_id = module_manager.find_module_port(top_module,
|
||||
std::string(DECODER_WL_ADDRESS_PORT_NAME));
|
||||
BasicPort wl_addr_port = module_manager.module_port(top_module, wl_addr_port_id);
|
||||
std::vector<size_t> initial_wl_addr_values(wl_addr_port.get_width(), 0);
|
||||
|
||||
ModulePortId din_port_id = module_manager.find_module_port(top_module,
|
||||
std::string(DECODER_DATA_IN_PORT_NAME));
|
||||
BasicPort din_port = module_manager.module_port(top_module, din_port_id);
|
||||
std::vector<size_t> initial_din_values(din_port.get_width(), 0);
|
||||
|
||||
print_verilog_comment(fp, "----- Begin bitstream loading during configuration phase -----");
|
||||
fp << "initial" << std::endl;
|
||||
fp << "\tbegin" << std::endl;
|
||||
print_verilog_comment(fp, "----- Address port default input -----");
|
||||
fp << "\t\t";
|
||||
fp << generate_verilog_port_constant_values(bl_addr_port, initial_bl_addr_values);
|
||||
fp << ";";
|
||||
fp << std::endl;
|
||||
|
||||
fp << "\t\t";
|
||||
fp << generate_verilog_port_constant_values(wl_addr_port, initial_wl_addr_values);
|
||||
fp << ";";
|
||||
fp << std::endl;
|
||||
|
||||
print_verilog_comment(fp, "----- Data-input port default input -----");
|
||||
fp << "\t\t";
|
||||
fp << generate_verilog_port_constant_values(din_port, initial_din_values);
|
||||
fp << ";";
|
||||
|
||||
fp << std::endl;
|
||||
|
||||
/* Reorganize the fabric bitstream by the same address across regions */
|
||||
MemoryBankFabricBitstream fabric_bits_by_addr = build_memory_bank_fabric_bitstream_by_address(fabric_bitstream);
|
||||
|
||||
for (const auto& addr_din_pair : fabric_bits_by_addr) {
|
||||
/* When fast configuration is enabled,
|
||||
* the rule to skip any configuration bit should consider the whole data input values.
|
||||
* Only all the bits in the din port match the value to be skipped,
|
||||
* the programming cycle can be skipped!
|
||||
*/
|
||||
if (true == fast_configuration) {
|
||||
bool skip_curr_bits = true;
|
||||
for (const bool& bit : addr_din_pair.second) {
|
||||
if (bit_value_to_skip != bit) {
|
||||
skip_curr_bits = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (true == skip_curr_bits) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
fp << "\t\t" << std::string(TOP_TESTBENCH_PROG_TASK_NAME);
|
||||
fp << "(" << bl_addr_port.get_width() << "'b";
|
||||
VTR_ASSERT(bl_addr_port.get_width() == addr_din_pair.first.first.length());
|
||||
fp << addr_din_pair.first.first;
|
||||
|
||||
fp << ", ";
|
||||
fp << wl_addr_port.get_width() << "'b";
|
||||
VTR_ASSERT(wl_addr_port.get_width() == addr_din_pair.first.second.length());
|
||||
fp << addr_din_pair.first.second;
|
||||
|
||||
fp << ", ";
|
||||
fp << din_port.get_width() << "'b";
|
||||
VTR_ASSERT(din_port.get_width() == addr_din_pair.second.size());
|
||||
for (const bool& din_value : addr_din_pair.second) {
|
||||
if (true == din_value) {
|
||||
fp << "1";
|
||||
} else {
|
||||
VTR_ASSERT(false == din_value);
|
||||
fp << "0";
|
||||
}
|
||||
}
|
||||
fp << ");" << std::endl;
|
||||
}
|
||||
|
||||
/* Raise the flag of configuration done when bitstream loading is complete */
|
||||
BasicPort prog_clock_port(std::string(TOP_TB_PROG_CLOCK_PORT_NAME), 1);
|
||||
fp << "\t\t@(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_port) << ");" << std::endl;
|
||||
|
||||
BasicPort config_done_port(std::string(TOP_TB_CONFIG_DONE_PORT_NAME), 1);
|
||||
fp << "\t\t\t";
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, config_done_port);
|
||||
fp << " <= ";
|
||||
std::vector<size_t> config_done_enable_values(config_done_port.get_width(), 1);
|
||||
fp << generate_verilog_constant_values(config_done_enable_values);
|
||||
fp << ";" << std::endl;
|
||||
|
||||
fp << "\tend" << std::endl;
|
||||
print_verilog_comment(fp, "----- End bitstream loading during configuration phase -----");
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Print stimulus for a FPGA fabric with a frame-based configuration protocol
|
||||
* where configuration bits are programming in serial (one by one)
|
||||
*
|
||||
* We will use the programming task function created before
|
||||
*******************************************************************/
|
||||
static
|
||||
void print_verilog_top_testbench_frame_decoder_bitstream(std::fstream& fp,
|
||||
const bool& fast_configuration,
|
||||
const bool& bit_value_to_skip,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const FabricBitstream& fabric_bitstream) {
|
||||
/* Validate the file stream */
|
||||
valid_file_stream(fp);
|
||||
|
||||
/* Feed addresss and data input pair one by one
|
||||
* Note: the first cycle is reserved for programming reset
|
||||
* We should give dummy values
|
||||
*/
|
||||
ModulePortId addr_port_id = module_manager.find_module_port(top_module,
|
||||
std::string(DECODER_ADDRESS_PORT_NAME));
|
||||
BasicPort addr_port = module_manager.module_port(top_module, addr_port_id);
|
||||
std::vector<size_t> initial_addr_values(addr_port.get_width(), 0);
|
||||
|
||||
ModulePortId din_port_id = module_manager.find_module_port(top_module,
|
||||
std::string(DECODER_DATA_IN_PORT_NAME));
|
||||
BasicPort din_port = module_manager.module_port(top_module, din_port_id);
|
||||
std::vector<size_t> initial_din_values(din_port.get_width(), 0);
|
||||
|
||||
print_verilog_comment(fp, "----- Begin bitstream loading during configuration phase -----");
|
||||
fp << "initial" << std::endl;
|
||||
fp << "\tbegin" << std::endl;
|
||||
print_verilog_comment(fp, "----- Address port default input -----");
|
||||
fp << "\t\t";
|
||||
fp << generate_verilog_port_constant_values(addr_port, initial_addr_values);
|
||||
fp << ";";
|
||||
fp << std::endl;
|
||||
|
||||
print_verilog_comment(fp, "----- Data-input port default input -----");
|
||||
fp << "\t\t";
|
||||
fp << generate_verilog_port_constant_values(din_port, initial_din_values);
|
||||
fp << ";";
|
||||
|
||||
fp << std::endl;
|
||||
|
||||
/* Reorganize the fabric bitstream by the same address across regions */
|
||||
FrameFabricBitstream fabric_bits_by_addr = build_frame_based_fabric_bitstream_by_address(fabric_bitstream);
|
||||
|
||||
for (const auto& addr_din_pair : fabric_bits_by_addr) {
|
||||
/* When fast configuration is enabled,
|
||||
* the rule to skip any configuration bit should consider the whole data input values.
|
||||
* Only all the bits in the din port match the value to be skipped,
|
||||
* the programming cycle can be skipped!
|
||||
*/
|
||||
if (true == fast_configuration) {
|
||||
bool skip_curr_bits = true;
|
||||
for (const bool& bit : addr_din_pair.second) {
|
||||
if (bit_value_to_skip != bit) {
|
||||
skip_curr_bits = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (true == skip_curr_bits) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
fp << "\t\t" << std::string(TOP_TESTBENCH_PROG_TASK_NAME);
|
||||
fp << "(" << addr_port.get_width() << "'b";
|
||||
VTR_ASSERT(addr_port.get_width() == addr_din_pair.first.size());
|
||||
fp << addr_din_pair.first;
|
||||
fp << ", ";
|
||||
fp << din_port.get_width() << "'b";
|
||||
VTR_ASSERT(din_port.get_width() == addr_din_pair.second.size());
|
||||
for (const bool& din_value : addr_din_pair.second) {
|
||||
if (true == din_value) {
|
||||
fp << "1";
|
||||
} else {
|
||||
VTR_ASSERT(false == din_value);
|
||||
fp << "0";
|
||||
}
|
||||
}
|
||||
fp << ");" << std::endl;
|
||||
}
|
||||
|
||||
/* Disable the address and din
|
||||
fp << "\t\t" << std::string(TOP_TESTBENCH_PROG_TASK_NAME);
|
||||
fp << "(" << addr_port.get_width() << "'b";
|
||||
std::vector<size_t> all_zero_addr(addr_port.get_width(), 0);
|
||||
for (const size_t& addr_bit : all_zero_addr) {
|
||||
fp << addr_bit;
|
||||
}
|
||||
fp << ", ";
|
||||
fp << generate_verilog_constant_values(initial_din_values);
|
||||
fp << ");" << std::endl;
|
||||
*/
|
||||
|
||||
/* Raise the flag of configuration done when bitstream loading is complete */
|
||||
BasicPort prog_clock_port(std::string(TOP_TB_PROG_CLOCK_PORT_NAME), 1);
|
||||
fp << "\t\t@(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_port) << ");" << std::endl;
|
||||
|
||||
BasicPort config_done_port(std::string(TOP_TB_CONFIG_DONE_PORT_NAME), 1);
|
||||
fp << "\t\t\t";
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, config_done_port);
|
||||
fp << " <= ";
|
||||
std::vector<size_t> config_done_enable_values(config_done_port.get_width(), 1);
|
||||
fp << generate_verilog_constant_values(config_done_enable_values);
|
||||
fp << ";" << std::endl;
|
||||
|
||||
fp << "\tend" << std::endl;
|
||||
print_verilog_comment(fp, "----- End bitstream loading during configuration phase -----");
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Generate the stimuli for the top-level testbench
|
||||
* The simulation consists of two phases: configuration phase and operation phase
|
||||
* Configuration bits are loaded serially.
|
||||
* This is actually what we do for a physical FPGA
|
||||
*******************************************************************/
|
||||
static
|
||||
void print_verilog_top_testbench_bitstream(std::fstream& fp,
|
||||
const e_config_protocol_type& config_protocol_type,
|
||||
const bool& fast_configuration,
|
||||
const bool& bit_value_to_skip,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const BitstreamManager& bitstream_manager,
|
||||
const FabricBitstream& fabric_bitstream) {
|
||||
|
||||
/* Branch on the type of configuration protocol */
|
||||
switch (config_protocol_type) {
|
||||
case CONFIG_MEM_STANDALONE:
|
||||
print_verilog_top_testbench_vanilla_bitstream(fp,
|
||||
module_manager, top_module,
|
||||
bitstream_manager, fabric_bitstream);
|
||||
break;
|
||||
case CONFIG_MEM_SCAN_CHAIN:
|
||||
print_verilog_top_testbench_configuration_chain_bitstream(fp, fast_configuration,
|
||||
bit_value_to_skip,
|
||||
module_manager, top_module,
|
||||
bitstream_manager, fabric_bitstream);
|
||||
break;
|
||||
case CONFIG_MEM_MEMORY_BANK:
|
||||
print_verilog_top_testbench_memory_bank_bitstream(fp, fast_configuration,
|
||||
bit_value_to_skip,
|
||||
module_manager, top_module,
|
||||
fabric_bitstream);
|
||||
break;
|
||||
case CONFIG_MEM_FRAME_BASED:
|
||||
print_verilog_top_testbench_frame_decoder_bitstream(fp, fast_configuration,
|
||||
bit_value_to_skip,
|
||||
module_manager, top_module,
|
||||
fabric_bitstream);
|
||||
break;
|
||||
default:
|
||||
VTR_LOGF_ERROR(__FILE__, __LINE__,
|
||||
"Invalid SRAM organization type!\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Print stimulus for a FPGA fabric with a flatten memory (standalone) configuration protocol
|
||||
* We will load the bitstream in the second clock cycle, right after the first reset cycle
|
||||
|
@ -2534,263 +1840,6 @@ void print_verilog_top_testbench_check(std::fstream& fp,
|
|||
fp << std::endl;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* TODO: This top function will be deprecated!!! The only top function is
|
||||
* print_verilog_full_testbench()
|
||||
* 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
|
||||
* +----------+
|
||||
* | FPGA | +------------+
|
||||
* +----->| Fabric |------>| |
|
||||
* | | | | |
|
||||
* | +----------+ | |
|
||||
* | | Output |
|
||||
* random_input_vectors -----+ | Vector |---->Functional correct?
|
||||
* | | Comparator |
|
||||
* | +-----------+ | |
|
||||
* | | Input | | |
|
||||
* +----->| Benchmark |----->| |
|
||||
* +-----------+ +------------+
|
||||
*
|
||||
*******************************************************************/
|
||||
void print_verilog_top_testbench(const ModuleManager& module_manager,
|
||||
const BitstreamManager& bitstream_manager,
|
||||
const FabricBitstream& fabric_bitstream,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const FabricGlobalPortInfo& global_ports,
|
||||
const AtomContext& atom_ctx,
|
||||
const PlacementContext& place_ctx,
|
||||
const PinConstraints& pin_constraints,
|
||||
const IoLocationMap& io_location_map,
|
||||
const VprNetlistAnnotation& netlist_annotation,
|
||||
const std::string& circuit_name,
|
||||
const std::string& verilog_fname,
|
||||
const SimulationSetting& simulation_parameters,
|
||||
const VerilogTestbenchOption& options) {
|
||||
|
||||
bool fast_configuration = options.fast_configuration();
|
||||
bool explicit_port_mapping = options.explicit_port_mapping();
|
||||
|
||||
std::string timer_message = std::string("Write autocheck testbench for FPGA top-level Verilog netlist for '") + circuit_name + std::string("'");
|
||||
|
||||
/* Start time count */
|
||||
vtr::ScopedStartFinishTimer timer(timer_message);
|
||||
|
||||
/* Create the file stream */
|
||||
std::fstream fp;
|
||||
fp.open(verilog_fname, std::fstream::out | std::fstream::trunc);
|
||||
|
||||
/* Validate the file stream */
|
||||
check_file_stream(verilog_fname.c_str(), 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);
|
||||
|
||||
/* Find the top_module */
|
||||
ModuleId top_module = module_manager.find_module(generate_fpga_top_module_name());
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(top_module));
|
||||
|
||||
/* Preparation: find all the clock ports */
|
||||
std::vector<std::string> clock_port_names = find_atom_netlist_clock_port_names(atom_ctx.nlist, netlist_annotation);
|
||||
|
||||
/* Preparation: find all the reset/set ports for programming usage */
|
||||
std::vector<FabricGlobalPortId> global_prog_reset_ports = find_fabric_global_programming_reset_ports(global_ports);
|
||||
std::vector<FabricGlobalPortId> global_prog_set_ports = find_fabric_global_programming_set_ports(global_ports);
|
||||
|
||||
/* Identify if we can apply fast configuration */
|
||||
bool apply_fast_configuration = fast_configuration && is_fast_configuration_applicable(global_ports);
|
||||
bool bit_value_to_skip = false;
|
||||
if (true == apply_fast_configuration) {
|
||||
bit_value_to_skip = find_bit_value_to_skip_for_fast_configuration(config_protocol.type(),
|
||||
global_ports,
|
||||
bitstream_manager,
|
||||
fabric_bitstream);
|
||||
}
|
||||
|
||||
/* Start of testbench */
|
||||
print_verilog_top_testbench_ports(fp, module_manager, top_module,
|
||||
atom_ctx, netlist_annotation,
|
||||
clock_port_names,
|
||||
pin_constraints,
|
||||
simulation_parameters, config_protocol,
|
||||
circuit_name);
|
||||
|
||||
/* Find the clock period */
|
||||
float prog_clock_period = (1./simulation_parameters.programming_clock_frequency());
|
||||
float default_op_clock_period = (1./simulation_parameters.default_operating_clock_frequency());
|
||||
float max_op_clock_period = 0.;
|
||||
for (const SimulationClockId& clock_id : simulation_parameters.clocks()) {
|
||||
max_op_clock_period = std::max(max_op_clock_period, (float)(1./simulation_parameters.clock_frequency(clock_id)));
|
||||
}
|
||||
|
||||
/* Estimate the number of configuration clock cycles */
|
||||
size_t num_config_clock_cycles = calculate_num_config_clock_cycles(config_protocol.type(),
|
||||
apply_fast_configuration,
|
||||
bit_value_to_skip,
|
||||
bitstream_manager,
|
||||
fabric_bitstream);
|
||||
|
||||
/* Generate stimuli for general control signals */
|
||||
print_verilog_top_testbench_generic_stimulus(fp,
|
||||
simulation_parameters,
|
||||
num_config_clock_cycles,
|
||||
prog_clock_period,
|
||||
default_op_clock_period,
|
||||
VERILOG_SIM_TIMESCALE);
|
||||
|
||||
/* Generate stimuli for programming interface */
|
||||
print_verilog_top_testbench_configuration_protocol_stimulus(fp,
|
||||
config_protocol.type(),
|
||||
module_manager, top_module,
|
||||
prog_clock_period,
|
||||
VERILOG_SIM_TIMESCALE);
|
||||
|
||||
/* Identify the stimulus for global reset/set for programming purpose:
|
||||
* - If only reset port is seen we turn on Reset
|
||||
* - If only set port is seen we turn on Reset
|
||||
* - If both reset and set port is defined,
|
||||
* we pick the one which is consistent with the bit value to be skipped
|
||||
*/
|
||||
bool active_global_prog_reset = false;
|
||||
bool active_global_prog_set = false;
|
||||
|
||||
if (!global_prog_reset_ports.empty()) {
|
||||
active_global_prog_reset = true;
|
||||
}
|
||||
|
||||
if (!global_prog_set_ports.empty()) {
|
||||
active_global_prog_set = true;
|
||||
}
|
||||
|
||||
/* Ensure that at most only one of the two switches is activated */
|
||||
if ( (true == active_global_prog_reset)
|
||||
&& (true == active_global_prog_set) ) {
|
||||
/* If we will skip logic '0', we will activate programming reset */
|
||||
active_global_prog_reset = !bit_value_to_skip;
|
||||
/* If we will skip logic '1', we will activate programming set */
|
||||
active_global_prog_set = bit_value_to_skip;
|
||||
}
|
||||
|
||||
/* Generate stimuli for global ports or connect them to existed signals */
|
||||
print_verilog_top_testbench_global_ports_stimuli(fp,
|
||||
module_manager, top_module,
|
||||
pin_constraints,
|
||||
global_ports,
|
||||
simulation_parameters,
|
||||
active_global_prog_reset,
|
||||
active_global_prog_set);
|
||||
|
||||
/* Instanciate FPGA top-level module */
|
||||
print_verilog_testbench_fpga_instance(fp, module_manager, top_module,
|
||||
std::string(TOP_TESTBENCH_FPGA_INSTANCE_NAME),
|
||||
explicit_port_mapping);
|
||||
|
||||
/* Connect I/Os to benchmark I/Os or constant driver */
|
||||
print_verilog_testbench_connect_fpga_ios(fp, module_manager, top_module,
|
||||
atom_ctx, place_ctx, io_location_map,
|
||||
netlist_annotation,
|
||||
std::string(),
|
||||
std::string(TOP_TESTBENCH_FPGA_OUTPUT_POSTFIX),
|
||||
(size_t)VERILOG_DEFAULT_SIGNAL_INIT_VALUE);
|
||||
|
||||
/* Instanciate input benchmark */
|
||||
print_verilog_top_testbench_benchmark_instance(fp,
|
||||
circuit_name,
|
||||
atom_ctx,
|
||||
netlist_annotation,
|
||||
explicit_port_mapping);
|
||||
|
||||
/* Print tasks used for loading bitstreams */
|
||||
print_verilog_top_testbench_load_bitstream_task(fp,
|
||||
config_protocol.type(),
|
||||
module_manager, top_module);
|
||||
|
||||
/* load bitstream to FPGA fabric in a configuration phase */
|
||||
print_verilog_top_testbench_bitstream(fp, config_protocol.type(),
|
||||
apply_fast_configuration,
|
||||
bit_value_to_skip,
|
||||
module_manager, top_module,
|
||||
bitstream_manager, fabric_bitstream);
|
||||
|
||||
/* Add signal initialization:
|
||||
* Bypass writing codes to files due to the autogenerated codes are very large.
|
||||
*/
|
||||
if (true == options.include_signal_init()) {
|
||||
print_verilog_testbench_signal_initialization(fp,
|
||||
std::string(TOP_TESTBENCH_FPGA_INSTANCE_NAME),
|
||||
circuit_lib,
|
||||
module_manager,
|
||||
top_module);
|
||||
}
|
||||
|
||||
|
||||
/* Add stimuli for reset, set, clock and iopad signals */
|
||||
print_verilog_top_testbench_reset_stimuli(fp,
|
||||
atom_ctx,
|
||||
netlist_annotation,
|
||||
module_manager,
|
||||
global_ports,
|
||||
pin_constraints,
|
||||
clock_port_names);
|
||||
print_verilog_testbench_random_stimuli(fp, atom_ctx,
|
||||
netlist_annotation,
|
||||
module_manager,
|
||||
global_ports,
|
||||
pin_constraints,
|
||||
clock_port_names,
|
||||
std::string(TOP_TESTBENCH_CHECKFLAG_PORT_POSTFIX),
|
||||
std::vector<BasicPort>(1, BasicPort(std::string(TOP_TB_OP_CLOCK_PORT_NAME), 1)));
|
||||
|
||||
/* Add output autocheck */
|
||||
print_verilog_testbench_check(fp,
|
||||
std::string(AUTOCHECKED_SIMULATION_FLAG),
|
||||
std::string(TOP_TESTBENCH_SIM_START_PORT_NAME),
|
||||
std::string(TOP_TESTBENCH_REFERENCE_OUTPUT_POSTFIX),
|
||||
std::string(TOP_TESTBENCH_FPGA_OUTPUT_POSTFIX),
|
||||
std::string(TOP_TESTBENCH_CHECKFLAG_PORT_POSTFIX),
|
||||
std::string(TOP_TESTBENCH_ERROR_COUNTER),
|
||||
atom_ctx,
|
||||
netlist_annotation,
|
||||
clock_port_names,
|
||||
std::string(TOP_TB_OP_CLOCK_PORT_NAME));
|
||||
|
||||
/* Add autocheck for configuration phase */
|
||||
print_verilog_top_testbench_check(fp,
|
||||
std::string(AUTOCHECKED_SIMULATION_FLAG),
|
||||
std::string(TOP_TB_CONFIG_DONE_PORT_NAME),
|
||||
std::string(TOP_TESTBENCH_ERROR_COUNTER));
|
||||
|
||||
/* Find simulation time */
|
||||
float simulation_time = find_simulation_time_period(VERILOG_SIM_TIMESCALE,
|
||||
num_config_clock_cycles,
|
||||
1./simulation_parameters.programming_clock_frequency(),
|
||||
simulation_parameters.num_clock_cycles(),
|
||||
1./simulation_parameters.default_operating_clock_frequency());
|
||||
|
||||
|
||||
/* Add Icarus requirement:
|
||||
* Always ceil the simulation time so that we test a sufficient length of period!!!
|
||||
*/
|
||||
print_verilog_timeout_and_vcd(fp,
|
||||
std::string(circuit_name + std::string(AUTOCHECK_TOP_TESTBENCH_VERILOG_MODULE_POSTFIX)),
|
||||
std::string(circuit_name + std::string("_formal.vcd")),
|
||||
std::string(TOP_TESTBENCH_SIM_START_PORT_NAME),
|
||||
std::string(TOP_TESTBENCH_ERROR_COUNTER),
|
||||
std::ceil(simulation_time));
|
||||
|
||||
|
||||
/* Testbench ends*/
|
||||
print_verilog_module_end(fp, std::string(circuit_name) + std::string(AUTOCHECK_TOP_TESTBENCH_VERILOG_MODULE_POSTFIX));
|
||||
|
||||
/* Close the file stream */
|
||||
fp.close();
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* The top-level function to generate a full testbench, in order to verify:
|
||||
* 1. Configuration phase of the FPGA fabric, where the bitstream is
|
||||
|
|
|
@ -26,22 +26,6 @@
|
|||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
void print_verilog_top_testbench(const ModuleManager& module_manager,
|
||||
const BitstreamManager& bitstream_manager,
|
||||
const FabricBitstream& fabric_bitstream,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const FabricGlobalPortInfo& global_ports,
|
||||
const AtomContext& atom_ctx,
|
||||
const PlacementContext& place_ctx,
|
||||
const PinConstraints& pin_constraints,
|
||||
const IoLocationMap& io_location_map,
|
||||
const VprNetlistAnnotation& netlist_annotation,
|
||||
const std::string& circuit_name,
|
||||
const std::string& verilog_fname,
|
||||
const SimulationSetting& simulation_parameters,
|
||||
const VerilogTestbenchOption& options);
|
||||
|
||||
int print_verilog_full_testbench(const ModuleManager& module_manager,
|
||||
const BitstreamManager& bitstream_manager,
|
||||
const FabricBitstream& fabric_bitstream,
|
||||
|
|
Loading…
Reference in New Issue