break the configuration testbench. This commit is to spot which modification leads to the problem
This commit is contained in:
parent
85921dcc05
commit
cff5b5cfc1
|
@ -101,7 +101,7 @@ void rec_build_module_fabric_dependent_frame_bitstream(const BitstreamManager& b
|
|||
const std::vector<ConfigBlockId>& parent_blocks,
|
||||
const ModuleManager& module_manager,
|
||||
const std::vector<ModuleId>& parent_modules,
|
||||
const std::vector<bool>& addr_code,
|
||||
const std::vector<size_t>& addr_code,
|
||||
FabricBitstream& fabric_bitstream) {
|
||||
|
||||
/* Depth-first search: if we have any children in the parent_block,
|
||||
|
@ -154,17 +154,14 @@ void rec_build_module_fabric_dependent_frame_bitstream(const BitstreamManager& b
|
|||
child_modules.push_back(child_module);
|
||||
|
||||
/* Set address, apply binary conversion from the first to the last element in the address list */
|
||||
std::vector<bool> child_addr_code = addr_code;
|
||||
std::vector<size_t> child_addr_code = addr_code;
|
||||
|
||||
if (true == add_addr_code) {
|
||||
/* Find the address port from the decoder module */
|
||||
const ModulePortId& decoder_addr_port_id = module_manager.find_module_port(decoder_module, std::string(DECODER_ADDRESS_PORT_NAME));
|
||||
const BasicPort& decoder_addr_port = module_manager.module_port(decoder_module, decoder_addr_port_id);
|
||||
std::vector<size_t> addr_bits_vec = itobin_vec(child_id, decoder_addr_port.get_width());
|
||||
for (const size_t& bit : addr_bits_vec) {
|
||||
VTR_ASSERT((0 == bit) || (1 == bit));
|
||||
child_addr_code.push_back(bit);
|
||||
}
|
||||
child_addr_code.insert(child_addr_code.end(), addr_bits_vec.begin(), addr_bits_vec.end());
|
||||
}
|
||||
|
||||
/* Go recursively */
|
||||
|
@ -226,7 +223,7 @@ void build_module_fabric_dependent_bitstream(const ConfigProtocol& config_protoc
|
|||
std::vector<ConfigBlockId>(1, top_block),
|
||||
module_manager,
|
||||
std::vector<ModuleId>(1, top_module),
|
||||
std::vector<bool>(),
|
||||
std::vector<size_t>(),
|
||||
fabric_bitstream);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ ConfigBitId FabricBitstream::config_bit(const FabricBitId& bit_id) const {
|
|||
return config_bit_ids_[bit_id];
|
||||
}
|
||||
|
||||
std::vector<bool> FabricBitstream::bit_address(const FabricBitId& bit_id) const {
|
||||
std::vector<size_t> FabricBitstream::bit_address(const FabricBitId& bit_id) const {
|
||||
/* Ensure a valid id */
|
||||
VTR_ASSERT(true == valid_bit_id(bit_id));
|
||||
|
||||
|
@ -56,7 +56,7 @@ FabricBitId FabricBitstream::add_bit(const ConfigBitId& config_bit_id) {
|
|||
}
|
||||
|
||||
void FabricBitstream::set_bit_address(const FabricBitId& bit_id,
|
||||
const std::vector<bool>& address) {
|
||||
const std::vector<size_t>& address) {
|
||||
VTR_ASSERT(true == valid_bit_id(bit_id));
|
||||
bit_addresses_[bit_id] = address;
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ class FabricBitstream {
|
|||
ConfigBitId config_bit(const FabricBitId& bit_id) const;
|
||||
|
||||
/* Find the address of bitstream */
|
||||
std::vector<bool> bit_address(const FabricBitId& bit_id) const;
|
||||
std::vector<size_t> bit_address(const FabricBitId& bit_id) const;
|
||||
|
||||
/* Find the data-in of bitstream */
|
||||
bool bit_din(const FabricBitId& bit_id) const;
|
||||
|
@ -62,7 +62,7 @@ class FabricBitstream {
|
|||
FabricBitId add_bit(const ConfigBitId& config_bit_id);
|
||||
|
||||
void set_bit_address(const FabricBitId& bit_id,
|
||||
const std::vector<bool>& address);
|
||||
const std::vector<size_t>& address);
|
||||
|
||||
void set_bit_din(const FabricBitId& bit_id,
|
||||
const bool& din);
|
||||
|
@ -84,7 +84,7 @@ class FabricBitstream {
|
|||
* Here we store the binary format of the address, which can be loaded
|
||||
* to the configuration protocol directly
|
||||
*/
|
||||
vtr::vector<FabricBitId, std::vector<bool>> bit_addresses_;
|
||||
vtr::vector<FabricBitId, std::vector<size_t>> bit_addresses_;
|
||||
|
||||
/* Data input (Din) bits: this is designed for memory decoders */
|
||||
vtr::vector<FabricBitId, bool> bit_dins_;
|
||||
|
|
|
@ -41,7 +41,7 @@ constexpr char* TOP_TESTBENCH_FPGA_OUTPUT_POSTFIX = "_fpga";
|
|||
|
||||
constexpr char* TOP_TESTBENCH_CHECKFLAG_PORT_POSTFIX = "_flag";
|
||||
|
||||
constexpr char* TOP_TESTBENCH_CC_PROG_TASK_NAME = "prog_cycle_task";
|
||||
constexpr char* TOP_TESTBENCH_PROG_TASK_NAME = "prog_cycle_task";
|
||||
|
||||
constexpr char* TOP_TESTBENCH_SIM_START_PORT_NAME = "sim_start";
|
||||
|
||||
|
@ -79,12 +79,49 @@ void print_verilog_top_testbench_config_chain_port(std::fstream& fp) {
|
|||
fp << generate_verilog_port(VERILOG_PORT_WIRE, config_chain_tail_port) << ";" << std::endl;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Print local wires for frame-based decoder protocols
|
||||
*******************************************************************/
|
||||
static
|
||||
void print_verilog_top_testbench_frame_decoder_port(std::fstream& fp,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module) {
|
||||
/* Validate the file stream */
|
||||
valid_file_stream(fp);
|
||||
|
||||
/* Print the address port for the frame-based decoder here */
|
||||
print_verilog_comment(fp, std::string("---- Address port for frame-based decoder -----"));
|
||||
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);
|
||||
|
||||
fp << generate_verilog_port(VERILOG_PORT_REG, 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 -----"));
|
||||
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_WIRE, din_port) << ";" << std::endl;
|
||||
|
||||
/* Wire the programming clock to the enable signal */
|
||||
print_verilog_comment(fp, std::string("---- Wire enable port of frame-based decoder to programming clock -----"));
|
||||
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);
|
||||
|
||||
print_verilog_wire_connection(fp, en_port, prog_clock_port, false);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Print local wires for different types of configuration protocols
|
||||
*******************************************************************/
|
||||
static
|
||||
void print_verilog_top_testbench_config_protocol_port(std::fstream& fp,
|
||||
const e_config_protocol_type& sram_orgz_type) {
|
||||
const e_config_protocol_type& sram_orgz_type,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module) {
|
||||
switch(sram_orgz_type) {
|
||||
case CONFIG_MEM_STANDALONE:
|
||||
/* TODO */
|
||||
|
@ -95,6 +132,9 @@ void print_verilog_top_testbench_config_protocol_port(std::fstream& fp,
|
|||
case CONFIG_MEM_MEMORY_BANK:
|
||||
/* TODO */
|
||||
break;
|
||||
case CONFIG_MEM_FRAME_BASED:
|
||||
print_verilog_top_testbench_frame_decoder_port(fp, module_manager, top_module);
|
||||
break;
|
||||
default:
|
||||
VTR_LOGF_ERROR(__FILE__, __LINE__,
|
||||
"Invalid type of SRAM organization!\n");
|
||||
|
@ -398,7 +438,8 @@ 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, sram_orgz_type);
|
||||
print_verilog_top_testbench_config_protocol_port(fp, sram_orgz_type,
|
||||
module_manager, top_module);
|
||||
|
||||
/* Create a clock port if the benchmark have one but not in the default name!
|
||||
* We will wire the clock directly to the operating clock directly
|
||||
|
@ -506,15 +547,72 @@ void print_verilog_top_testbench_load_bitstream_task_configuration_chain(std::fs
|
|||
* 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_CC_PROG_TASK_NAME) << ";" << std::endl;
|
||||
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;
|
||||
print_verilog_wire_connection(fp, cc_head_port, cc_head_value, false);
|
||||
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 rising 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: address and data values during a programming clock cycle -----"));
|
||||
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@(posedge " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_port) << ");" << std::endl;
|
||||
|
||||
fp << "\t\t\t";
|
||||
print_verilog_wire_connection(fp, addr_port, addr_value, false);
|
||||
fp << std::endl;
|
||||
|
||||
fp << "\t\t\t";
|
||||
print_verilog_wire_connection(fp, din_port, din_value, false);
|
||||
fp << std::endl;
|
||||
|
||||
fp << "\tend" << std::endl;
|
||||
fp << "endtask" << std::endl;
|
||||
|
@ -528,7 +626,9 @@ void print_verilog_top_testbench_load_bitstream_task_configuration_chain(std::fs
|
|||
*******************************************************************/
|
||||
static
|
||||
void print_verilog_top_testbench_load_bitstream_task(std::fstream& fp,
|
||||
const e_config_protocol_type& sram_orgz_type) {
|
||||
const e_config_protocol_type& sram_orgz_type,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module) {
|
||||
switch (sram_orgz_type) {
|
||||
case CONFIG_MEM_STANDALONE:
|
||||
break;
|
||||
|
@ -540,6 +640,11 @@ void print_verilog_top_testbench_load_bitstream_task(std::fstream& fp,
|
|||
dump_verilog_top_testbench_stimuli_serial_version_tasks_memory_bank(cur_sram_orgz_info, fp);
|
||||
*/
|
||||
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");
|
||||
|
@ -721,7 +826,7 @@ void print_verilog_top_testbench_configuration_chain_bitstream(std::fstream& fp,
|
|||
* We will visit the fabric bitstream in a reverse way
|
||||
*/
|
||||
for (const FabricBitId& bit_id : fabric_bitstream.bits()) {
|
||||
fp << "\t\t" << std::string(TOP_TESTBENCH_CC_PROG_TASK_NAME);
|
||||
fp << "\t\t" << std::string(TOP_TESTBENCH_PROG_TASK_NAME);
|
||||
fp << "(1'b" << (size_t)bitstream_manager.bit_value(fabric_bitstream.config_bit(bit_id)) << ");" << std::endl;
|
||||
}
|
||||
|
||||
|
@ -741,6 +846,86 @@ void print_verilog_top_testbench_configuration_chain_bitstream(std::fstream& fp,
|
|||
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 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 << ";";
|
||||
|
||||
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;
|
||||
|
||||
/* Attention: the configuration chain protcol requires the last configuration bit is fed first
|
||||
* We will visit the fabric bitstream in a reverse way
|
||||
*/
|
||||
for (const FabricBitId& bit_id : fabric_bitstream.bits()) {
|
||||
fp << "\t\t" << std::string(TOP_TESTBENCH_PROG_TASK_NAME);
|
||||
fp << "(" << addr_port.get_width() << "'b";
|
||||
VTR_ASSERT(addr_port.get_width() == fabric_bitstream.bit_address(bit_id).size());
|
||||
for (const size_t& addr_bit : fabric_bitstream.bit_address(bit_id)) {
|
||||
fp << addr_bit;
|
||||
}
|
||||
fp << ", ";
|
||||
fp <<"1'b";
|
||||
if (true == fabric_bitstream.bit_din(bit_id)) {
|
||||
fp << "1";
|
||||
} else {
|
||||
VTR_ASSERT(false == fabric_bitstream.bit_din(bit_id));
|
||||
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 -----");
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Generate the stimuli for the top-level testbench
|
||||
* The simulation consists of two phases: configuration phase and operation phase
|
||||
|
@ -750,6 +935,8 @@ void print_verilog_top_testbench_configuration_chain_bitstream(std::fstream& fp,
|
|||
static
|
||||
void print_verilog_top_testbench_bitstream(std::fstream& fp,
|
||||
const e_config_protocol_type& sram_orgz_type,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const BitstreamManager& bitstream_manager,
|
||||
const FabricBitstream& fabric_bitstream) {
|
||||
/* Branch on the type of configuration protocol */
|
||||
|
@ -763,6 +950,11 @@ void print_verilog_top_testbench_bitstream(std::fstream& fp,
|
|||
case CONFIG_MEM_MEMORY_BANK:
|
||||
/* TODO */
|
||||
break;
|
||||
case CONFIG_MEM_FRAME_BASED:
|
||||
print_verilog_top_testbench_frame_decoder_bitstream(fp,
|
||||
module_manager, top_module,
|
||||
fabric_bitstream);
|
||||
break;
|
||||
default:
|
||||
VTR_LOGF_ERROR(__FILE__, __LINE__,
|
||||
"Invalid SRAM organization type!\n");
|
||||
|
@ -875,10 +1067,13 @@ void print_verilog_top_testbench(const ModuleManager& module_manager,
|
|||
explicit_port_mapping);
|
||||
|
||||
/* Print tasks used for loading bitstreams */
|
||||
print_verilog_top_testbench_load_bitstream_task(fp, sram_orgz_type);
|
||||
print_verilog_top_testbench_load_bitstream_task(fp,
|
||||
sram_orgz_type,
|
||||
module_manager, top_module);
|
||||
|
||||
/* load bitstream to FPGA fabric in a configuration phase */
|
||||
print_verilog_top_testbench_bitstream(fp, sram_orgz_type,
|
||||
module_manager, top_module,
|
||||
bitstream_manager, fabric_bitstream);
|
||||
|
||||
/* Add stimuli for reset, set, clock and iopad signals */
|
||||
|
|
Loading…
Reference in New Issue