diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp index e76c198e9..c4250bdcc 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp +++ b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp @@ -60,6 +60,54 @@ constexpr char* TOP_TB_CLOCK_REG_POSTFIX = "_reg"; constexpr char* AUTOCHECK_TOP_TESTBENCH_VERILOG_MODULE_POSTFIX = "_autocheck_top_tb"; +/******************************************************************** + * Identify global reset ports for programming + *******************************************************************/ +static +std::vector find_global_programming_reset_ports(const CircuitLibrary& circuit_lib, + const std::vector& global_ports) { + /* Try to find global reset ports for programming */ + std::vector global_prog_reset_ports; + for (const CircuitPortId& global_port : global_ports) { + VTR_ASSERT(true == circuit_lib.port_is_global(global_port)); + if (false == circuit_lib.port_is_prog(global_port)) { + continue; + } + VTR_ASSERT(true == circuit_lib.port_is_prog(global_port)); + VTR_ASSERT( (false == circuit_lib.port_is_reset(global_port)) + || (false == circuit_lib.port_is_set(global_port))); + if (true == circuit_lib.port_is_reset(global_port)) { + global_prog_reset_ports.push_back(global_port); + } + } + + return global_prog_reset_ports; +} + +/******************************************************************** + * Identify global set ports for programming + *******************************************************************/ +static +std::vector find_global_programming_set_ports(const CircuitLibrary& circuit_lib, + const std::vector& global_ports) { + /* Try to find global set ports for programming */ + std::vector global_prog_set_ports; + for (const CircuitPortId& global_port : global_ports) { + VTR_ASSERT(true == circuit_lib.port_is_global(global_port)); + if (false == circuit_lib.port_is_prog(global_port)) { + continue; + } + VTR_ASSERT(true == circuit_lib.port_is_prog(global_port)); + VTR_ASSERT( (false == circuit_lib.port_is_reset(global_port)) + || (false == circuit_lib.port_is_set(global_port))); + if (true == circuit_lib.port_is_set(global_port)) { + global_prog_set_ports.push_back(global_port); + } + } + + return global_prog_set_ports; +} + /******************************************************************** * Print local wires for flatten memory (standalone) configuration protocols *******************************************************************/ @@ -242,7 +290,9 @@ void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp, const ModuleManager& module_manager, const ModuleId& top_module, const CircuitLibrary& circuit_lib, - const std::vector& global_ports) { + const std::vector& global_ports, + const bool& active_global_prog_reset, + const bool& active_global_prog_set) { /* Validate the file stream */ valid_file_stream(fp); @@ -324,10 +374,13 @@ void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp, ModulePortId module_global_port = module_manager.find_module_port(top_module, circuit_lib.port_prefix(model_global_port)); VTR_ASSERT(true == module_manager.valid_module_port_id(top_module, module_global_port)); + /* For global programming reset port, we will active only when specified */ BasicPort stimuli_reset_port; + bool activate = true; if (true == circuit_lib.port_is_prog(model_global_port)) { stimuli_reset_port.set_name(std::string(TOP_TB_PROG_RESET_PORT_NAME)); stimuli_reset_port.set_width(1); + activate = active_global_prog_reset; } else { VTR_ASSERT_SAFE(false == circuit_lib.port_is_prog(model_global_port)); stimuli_reset_port.set_name(std::string(TOP_TB_RESET_PORT_NAME)); @@ -337,9 +390,15 @@ void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp, * The wiring will be inverted if the default value of the global port is 1 * Otherwise, the wiring will not be inverted! */ - print_verilog_wire_connection(fp, module_manager.module_port(top_module, module_global_port), - stimuli_reset_port, - 1 == circuit_lib.port_default_value(model_global_port)); + if (true == activate) { + print_verilog_wire_connection(fp, module_manager.module_port(top_module, module_global_port), + stimuli_reset_port, + 1 == circuit_lib.port_default_value(model_global_port)); + } else { + VTR_ASSERT_SAFE(false == activate); + print_verilog_wire_constant_values(fp, module_manager.module_port(top_module, module_global_port), + std::vector(1, circuit_lib.port_default_value(model_global_port))); + } } /* Connect global set ports to operating or programming set signal */ @@ -366,10 +425,13 @@ void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp, ModulePortId module_global_port = module_manager.find_module_port(top_module, circuit_lib.port_prefix(model_global_port)); VTR_ASSERT(true == module_manager.valid_module_port_id(top_module, module_global_port)); + /* For global programming set port, we will active only when specified */ BasicPort stimuli_set_port; + bool activate = true; if (true == circuit_lib.port_is_prog(model_global_port)) { stimuli_set_port.set_name(std::string(TOP_TB_PROG_SET_PORT_NAME)); stimuli_set_port.set_width(1); + activate = active_global_prog_set; } else { VTR_ASSERT_SAFE(false == circuit_lib.port_is_prog(model_global_port)); stimuli_set_port.set_name(std::string(TOP_TB_SET_PORT_NAME)); @@ -379,9 +441,15 @@ void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp, * The wiring will be inverted if the default value of the global port is 1 * Otherwise, the wiring will not be inverted! */ - print_verilog_wire_connection(fp, module_manager.module_port(top_module, module_global_port), - stimuli_set_port, - 1 == circuit_lib.port_default_value(model_global_port)); + if (true == activate) { + print_verilog_wire_connection(fp, module_manager.module_port(top_module, module_global_port), + stimuli_set_port, + 1 == circuit_lib.port_default_value(model_global_port)); + } else { + VTR_ASSERT_SAFE(false == activate); + print_verilog_wire_constant_values(fp, module_manager.module_port(top_module, module_global_port), + std::vector(1, circuit_lib.port_default_value(model_global_port))); + } } /* For the rest of global ports, wire them to constant signals */ @@ -584,6 +652,7 @@ void print_verilog_top_testbench_ports(std::fstream& fp, static size_t calculate_num_config_clock_cycles(const e_config_protocol_type& sram_orgz_type, const bool& fast_configuration, + const bool& bit_value_to_skip, const BitstreamManager& bitstream_manager, const FabricBitstream& fabric_bitstream) { size_t num_config_clock_cycles = 1 + fabric_bitstream.num_bits(); @@ -602,7 +671,7 @@ size_t calculate_num_config_clock_cycles(const e_config_protocol_type& sram_orgz size_t full_num_config_clock_cycles = num_config_clock_cycles; size_t num_bits_to_skip = 0; for (const FabricBitId& bit_id : fabric_bitstream.bits()) { - if (true == bitstream_manager.bit_value(fabric_bitstream.config_bit(bit_id))) { + if (bit_value_to_skip != bitstream_manager.bit_value(fabric_bitstream.config_bit(bit_id))) { break; } num_bits_to_skip++; @@ -623,7 +692,7 @@ size_t calculate_num_config_clock_cycles(const e_config_protocol_type& sram_orgz size_t full_num_config_clock_cycles = num_config_clock_cycles; num_config_clock_cycles = 1; for (const FabricBitId& bit_id : fabric_bitstream.bits()) { - if (true == fabric_bitstream.bit_din(bit_id)) { + if (bit_value_to_skip != fabric_bitstream.bit_din(bit_id)) { num_config_clock_cycles++; } } @@ -1008,11 +1077,11 @@ void print_verilog_top_testbench_generic_stimulus(std::fstream& fp, fp << std::endl; /* Programming set signal for configuration circuit : always disabled */ - print_verilog_comment(fp, "----- Begin programming set signal generation: always disabled -----"); + print_verilog_comment(fp, "----- Begin programming set signal generation -----"); print_verilog_pulse_stimuli(fp, prog_set_port, - 0, /* Initial value */ + 1, /* Initial value */ prog_clock_period / timescale, 0); - print_verilog_comment(fp, "----- End programming set signal generation: always disabled -----"); + print_verilog_comment(fp, "----- End programming set signal generation -----"); fp << std::endl; @@ -1526,41 +1595,11 @@ static void print_verilog_top_testbench_bitstream(std::fstream& fp, const e_config_protocol_type& config_protocol_type, const bool& fast_configuration, - const CircuitLibrary& circuit_lib, - const std::vector& global_ports, + const bool& bit_value_to_skip, const ModuleManager& module_manager, const ModuleId& top_module, const BitstreamManager& bitstream_manager, const FabricBitstream& fabric_bitstream) { - /* Try to find global reset/set ports for programming */ - std::vector global_prog_reset_ports; - std::vector global_prog_set_ports; - for (const CircuitPortId& global_port : global_ports) { - VTR_ASSERT(true == circuit_lib.port_is_global(global_port)); - if (false == circuit_lib.port_is_prog(global_port)) { - continue; - } - VTR_ASSERT(true == circuit_lib.port_is_prog(global_port)); - VTR_ASSERT( (false == circuit_lib.port_is_reset(global_port)) - || (false == circuit_lib.port_is_set(global_port))); - if (true == circuit_lib.port_is_reset(global_port)) { - global_prog_reset_ports.push_back(global_port); - } - if (true == circuit_lib.port_is_set(global_port)) { - global_prog_set_ports.push_back(global_port); - } - } - - bool apply_fast_configuration = fast_configuration; - if ( (global_prog_set_ports.empty() && global_prog_reset_ports.empty()) - && (true == fast_configuration)) { - VTR_LOG_WARN("None of global reset and set ports are defined for programming purpose. Fast configuration is turned off\n"); - } - bool bit_value_to_skip = find_bit_value_to_skip_for_fast_configuration(config_protocol_type, - apply_fast_configuration, - global_prog_reset_ports, - global_prog_set_ports, - bitstream_manager, fabric_bitstream); /* Branch on the type of configuration protocol */ switch (config_protocol_type) { @@ -1570,18 +1609,18 @@ void print_verilog_top_testbench_bitstream(std::fstream& fp, bitstream_manager, fabric_bitstream); break; case CONFIG_MEM_SCAN_CHAIN: - print_verilog_top_testbench_configuration_chain_bitstream(fp, apply_fast_configuration, + print_verilog_top_testbench_configuration_chain_bitstream(fp, fast_configuration, bit_value_to_skip, bitstream_manager, fabric_bitstream); break; case CONFIG_MEM_MEMORY_BANK: - print_verilog_top_testbench_memory_bank_bitstream(fp, apply_fast_configuration, + 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, apply_fast_configuration, + print_verilog_top_testbench_frame_decoder_bitstream(fp, fast_configuration, bit_value_to_skip, module_manager, top_module, fabric_bitstream); @@ -1652,6 +1691,23 @@ void print_verilog_top_testbench(const ModuleManager& module_manager, /* Preparation: find all the clock ports */ std::vector 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 global_prog_reset_ports = find_global_programming_reset_ports(circuit_lib, global_ports); + std::vector global_prog_set_ports = find_global_programming_set_ports(circuit_lib, global_ports); + + /* Identify if we can apply fast configuration */ + bool apply_fast_configuration = fast_configuration; + if ( (global_prog_set_ports.empty() && global_prog_reset_ports.empty()) + && (true == fast_configuration)) { + VTR_LOG_WARN("None of global reset and set ports are defined for programming purpose. Fast configuration is turned off\n"); + apply_fast_configuration = false; + } + bool bit_value_to_skip = find_bit_value_to_skip_for_fast_configuration(config_protocol.type(), + apply_fast_configuration, + global_prog_reset_ports, + global_prog_set_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, @@ -1663,7 +1719,8 @@ void print_verilog_top_testbench(const ModuleManager& module_manager, float op_clock_period = (1./simulation_parameters.operating_clock_frequency()); /* Estimate the number of configuration clock cycles */ size_t num_config_clock_cycles = calculate_num_config_clock_cycles(config_protocol.type(), - fast_configuration, + apply_fast_configuration, + bit_value_to_skip, bitstream_manager, fabric_bitstream); @@ -1674,10 +1731,38 @@ void print_verilog_top_testbench(const ModuleManager& module_manager, op_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, - circuit_lib, global_ports); + circuit_lib, global_ports, + active_global_prog_reset, + active_global_prog_set); /* Instanciate FPGA top-level module */ print_verilog_testbench_fpga_instance(fp, module_manager, top_module, @@ -1706,8 +1791,8 @@ void print_verilog_top_testbench(const ModuleManager& module_manager, /* load bitstream to FPGA fabric in a configuration phase */ print_verilog_top_testbench_bitstream(fp, config_protocol.type(), - fast_configuration, - circuit_lib, global_ports, + apply_fast_configuration, + bit_value_to_skip, module_manager, top_module, bitstream_manager, fabric_bitstream);