[OpenFPGA Tool] Critical bug fix for Verilog testbenches for memory bank and frame-based configuration protocol

This commit is contained in:
tangxifan 2020-09-25 21:05:20 -06:00
parent 6bea712db0
commit 1b4e449179
3 changed files with 148 additions and 41 deletions

View File

@ -178,21 +178,34 @@ void print_verilog_top_testbench_memory_bank_port(std::fstream& fp,
fp << generate_verilog_port(VERILOG_PORT_REG, wl_addr_port) << ";" << std::endl;
/* Print the data-input port for the frame-based decoder here */
print_verilog_comment(fp, std::string("---- Data input port for frame-based decoder -----"));
print_verilog_comment(fp, std::string("---- Data input port for memory decoders -----"));
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);
fp << generate_verilog_port(VERILOG_PORT_REG, din_port) << ";" << std::endl;
/* Wire the INVERTED configuration done signal to the enable signal !!! */
print_verilog_comment(fp, std::string("---- Wire enable port of frame-based decoder to inverted configuration done signal -----"));
/* Generate enable signal waveform here:
* which is a 90 degree phase shift than the programming clock
*/
print_verilog_comment(fp, std::string("---- Wire enable port of memory decoders -----"));
ModulePortId en_port_id = module_manager.find_module_port(top_module,
std::string(DECODER_ENABLE_PORT_NAME));
BasicPort en_port = module_manager.module_port(top_module, en_port_id);
BasicPort en_register_port(std::string(en_port.get_name() + std::string(TOP_TB_CLOCK_REG_POSTFIX)), 1);
BasicPort config_done_port(std::string(TOP_TB_CONFIG_DONE_PORT_NAME), 1);
fp << generate_verilog_port(VERILOG_PORT_WIRE, en_port) << ";" << std::endl;
print_verilog_wire_connection(fp, en_port, config_done_port, true);
fp << generate_verilog_port(VERILOG_PORT_REG, en_register_port) << ";" << std::endl;
write_tab_to_file(fp, 1);
fp << "assign ";
fp << generate_verilog_port(VERILOG_PORT_CONKT, en_port);
fp << "= ";
fp << "~" << generate_verilog_port(VERILOG_PORT_CONKT, en_register_port);
fp << " & ";
fp << "~" << generate_verilog_port(VERILOG_PORT_CONKT, config_done_port);
fp << ";" << std::endl;
}
@ -201,8 +214,6 @@ void print_verilog_top_testbench_memory_bank_port(std::fstream& fp,
*******************************************************************/
static
void print_verilog_top_testbench_frame_decoder_port(std::fstream& fp,
const ConfigProtocol& config_protocol,
const CircuitLibrary& circuit_lib,
const ModuleManager& module_manager,
const ModuleId& top_module) {
/* Validate the file stream */
@ -223,33 +234,28 @@ void print_verilog_top_testbench_frame_decoder_port(std::fstream& fp,
BasicPort din_port = module_manager.module_port(top_module, din_port_id);
fp << generate_verilog_port(VERILOG_PORT_REG, din_port) << ";" << std::endl;
/* Wire the INVERTED configuration done signal to the enable signal !!! */
/* Generate enable signal waveform here:
* which is a 90 degree phase shift than the programming clock
*/
print_verilog_comment(fp, std::string("---- Wire enable port of frame-based decoders -----"));
ModulePortId en_port_id = module_manager.find_module_port(top_module,
std::string(DECODER_ENABLE_PORT_NAME));
BasicPort en_port = module_manager.module_port(top_module, en_port_id);
BasicPort en_register_port(std::string(en_port.get_name() + std::string(TOP_TB_CLOCK_REG_POSTFIX)), 1);
/* Find the circuit model of configurable memory
* Spot its BL port and generate stimuli based on BL port's attribute:
* - If the BL port is triggered by edge, use the inverted programming clock signal
* - If the BL port is a regular port, use the inverted configuration done signal
*/
const CircuitModelId& mem_model = config_protocol.memory_model();
VTR_ASSERT(true == circuit_lib.valid_model_id(mem_model));
std::vector<CircuitPortId> mem_model_bl_ports = circuit_lib.model_ports_by_type(mem_model, CIRCUIT_MODEL_PORT_BL);
VTR_ASSERT(1 == mem_model_bl_ports.size());
if (true == circuit_lib.port_is_edge_triggered(mem_model_bl_ports[0])) {
VTR_ASSERT_SAFE(false == circuit_lib.port_is_edge_triggered(mem_model_bl_ports[0]));
BasicPort prog_clock_port(std::string(TOP_TB_PROG_CLOCK_PORT_NAME), 1);
print_verilog_comment(fp, std::string("---- Wire enable port of frame-based decoder to inverted programming clock signal -----"));
fp << generate_verilog_port(VERILOG_PORT_WIRE, en_port) << ";" << std::endl;
print_verilog_wire_connection(fp, en_port, prog_clock_port, true);
} else {
BasicPort config_done_port(std::string(TOP_TB_CONFIG_DONE_PORT_NAME), 1);
print_verilog_comment(fp, std::string("---- Wire enable port of frame-based decoder to inverted configuration done signal -----"));
fp << generate_verilog_port(VERILOG_PORT_WIRE, en_port) << ";" << std::endl;
print_verilog_wire_connection(fp, en_port, config_done_port, true);
}
fp << generate_verilog_port(VERILOG_PORT_REG, en_register_port) << ";" << std::endl;
write_tab_to_file(fp, 1);
fp << "assign ";
fp << generate_verilog_port(VERILOG_PORT_CONKT, en_port);
fp << "= ";
fp << "~" << generate_verilog_port(VERILOG_PORT_CONKT, en_register_port);
fp << " & ";
fp << "~" << generate_verilog_port(VERILOG_PORT_CONKT, config_done_port);
fp << ";" << std::endl;
}
/********************************************************************
@ -258,7 +264,6 @@ void print_verilog_top_testbench_frame_decoder_port(std::fstream& fp,
static
void print_verilog_top_testbench_config_protocol_port(std::fstream& fp,
const ConfigProtocol& config_protocol,
const CircuitLibrary& circuit_lib,
const ModuleManager& module_manager,
const ModuleId& top_module) {
switch(config_protocol.type()) {
@ -272,7 +277,7 @@ void print_verilog_top_testbench_config_protocol_port(std::fstream& fp,
print_verilog_top_testbench_memory_bank_port(fp, module_manager, top_module);
break;
case CONFIG_MEM_FRAME_BASED:
print_verilog_top_testbench_frame_decoder_port(fp, config_protocol, circuit_lib,
print_verilog_top_testbench_frame_decoder_port(fp,
module_manager, top_module);
break;
default:
@ -525,7 +530,6 @@ void print_verilog_top_testbench_ports(std::fstream& fp,
const VprNetlistAnnotation& netlist_annotation,
const std::vector<std::string>& clock_port_names,
const ConfigProtocol& config_protocol,
const CircuitLibrary& circuit_lib,
const std::string& circuit_name){
/* Validate the file stream */
valid_file_stream(fp);
@ -599,7 +603,7 @@ void print_verilog_top_testbench_ports(std::fstream& fp,
fp << generate_verilog_port(VERILOG_PORT_REG, set_port) << ";" << std::endl;
/* Configuration ports depend on the organization of SRAMs */
print_verilog_top_testbench_config_protocol_port(fp, config_protocol, circuit_lib,
print_verilog_top_testbench_config_protocol_port(fp, config_protocol,
module_manager, top_module);
/* Create a clock port if the benchmark have one but not in the default name!
@ -816,9 +820,7 @@ void print_verilog_top_testbench_load_bitstream_task_memory_bank(std::fstream& f
/* Validate the file stream */
valid_file_stream(fp);
ModulePortId en_port_id = module_manager.find_module_port(top_module,
std::string(DECODER_ENABLE_PORT_NAME));
BasicPort en_port = module_manager.module_port(top_module, en_port_id);
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));
@ -851,7 +853,7 @@ void print_verilog_top_testbench_load_bitstream_task_memory_bank(std::fstream& f
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@(posedge " << generate_verilog_port(VERILOG_PORT_CONKT, en_port) << ");" << 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);
@ -898,9 +900,7 @@ void print_verilog_top_testbench_load_bitstream_task_frame_decoder(std::fstream&
/* Validate the file stream */
valid_file_stream(fp);
ModulePortId en_port_id = module_manager.find_module_port(top_module,
std::string(DECODER_ENABLE_PORT_NAME));
BasicPort en_port = module_manager.module_port(top_module, en_port_id);
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));
@ -926,7 +926,7 @@ void print_verilog_top_testbench_load_bitstream_task_frame_decoder(std::fstream&
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@(posedge " << generate_verilog_port(VERILOG_PORT_CONKT, en_port) << ");" << 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);
@ -1113,6 +1113,49 @@ void print_verilog_top_testbench_generic_stimulus(std::fstream& fp,
fp << std::endl;
}
/********************************************************************
* Print input stimuli for configuration protocol
* include:
* - memory bank
* 1. the enable signal
* - frame-based
* 1. the enable signal
*******************************************************************/
static
void print_verilog_top_testbench_configuration_protocol_stimulus(std::fstream& fp,
const e_config_protocol_type& config_protocol_type,
const ModuleManager& module_manager,
const ModuleId& top_module,
const float& prog_clock_period,
const float& timescale) {
/* Validate the file stream */
valid_file_stream(fp);
/* Branch on the type of configuration protocol */
switch (config_protocol_type) {
case CONFIG_MEM_STANDALONE:
break;
case CONFIG_MEM_SCAN_CHAIN:
break;
case CONFIG_MEM_MEMORY_BANK:
case CONFIG_MEM_FRAME_BASED: {
ModulePortId en_port_id = module_manager.find_module_port(top_module,
std::string(DECODER_ENABLE_PORT_NAME));
BasicPort en_port = module_manager.module_port(top_module, en_port_id);
BasicPort en_register_port(std::string(en_port.get_name() + std::string(TOP_TB_CLOCK_REG_POSTFIX)), 1);
print_verilog_comment(fp, std::string("---- Generate enable signal waveform -----"));
print_verilog_shifted_clock_stimuli(fp, en_register_port,
0.25 * prog_clock_period / timescale,
0.5 * prog_clock_period / timescale, 0);
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
@ -1711,7 +1754,7 @@ void print_verilog_top_testbench(const ModuleManager& module_manager,
/* Start of testbench */
print_verilog_top_testbench_ports(fp, module_manager, top_module,
atom_ctx, netlist_annotation, clock_port_names,
config_protocol, circuit_lib,
config_protocol,
circuit_name);
/* Find the clock period */
@ -1731,6 +1774,13 @@ void print_verilog_top_testbench(const ModuleManager& module_manager,
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

View File

@ -1294,6 +1294,57 @@ void print_verilog_pulse_stimuli(std::fstream& fp,
fp << std::endl;
}
/********************************************************************
* Print stimuli for a clock pulse generation
* This function supports the delay at the beginning of the waveform
*
* |<-- Initial delay -->|<--- pulse width --->|
* +------ flip_value
* |
* initial_value --------------------------------------------+
*
*******************************************************************/
void print_verilog_shifted_clock_stimuli(std::fstream& fp,
const BasicPort& port,
const float& initial_delay,
const float& pulse_width,
const size_t& initial_value) {
/* Validate the file stream */
VTR_ASSERT(true == valid_file_stream(fp));
/* Config_done signal: indicate when configuration is finished */
fp << "initial" << std::endl;
write_tab_to_file(fp, 1);
fp << "begin" << std::endl;
write_tab_to_file(fp, 1);
std::vector<size_t> initial_values(port.get_width(), initial_value);
write_tab_to_file(fp, 1);
fp << generate_verilog_port_constant_values(port, initial_values);
fp << ";" << std::endl;
write_tab_to_file(fp, 2);
fp << "#" << std::setprecision(10) << initial_delay;
fp << ";" << std::endl;
write_tab_to_file(fp, 2);
fp << "forever ";
fp << generate_verilog_port(VERILOG_PORT_CONKT, port);
fp << " = ";
fp << "#" << std::setprecision(10) << pulse_width;
fp << " ~" << generate_verilog_port(VERILOG_PORT_CONKT, port);
fp << ";" << std::endl;
write_tab_to_file(fp, 1);
fp << "end" << 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

View File

@ -161,6 +161,12 @@ 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_shifted_clock_stimuli(std::fstream& fp,
const BasicPort& port,
const float& initial_delay,
const float& pulse_width,
const size_t& initial_value);
void print_verilog_pulse_stimuli(std::fstream& fp,
const BasicPort& port,
const size_t& initial_value,