[Tool] Now Verilog testbench generator support adding dedicated stimuli for reset signals from benchmarks
This commit is contained in:
parent
82dd09a180
commit
0b49c22682
|
@ -49,6 +49,17 @@ std::string PinConstraints::pin_net(const openfpga::BasicPort& pin) const {
|
|||
return constrained_net_name;
|
||||
}
|
||||
|
||||
openfpga::BasicPort PinConstraints::net_pin(const std::string& net) const {
|
||||
openfpga::BasicPort constrained_pin;
|
||||
for (const PinConstraintId& pin_constraint : pin_constraints()) {
|
||||
if (net == pin_constraint_nets_[pin_constraint]) {
|
||||
constrained_pin = pin(pin_constraint);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return constrained_pin;
|
||||
}
|
||||
|
||||
bool PinConstraints::empty() const {
|
||||
return 0 == pin_constraint_ids_.size();
|
||||
}
|
||||
|
|
|
@ -57,6 +57,12 @@ class PinConstraints {
|
|||
*/
|
||||
std::string pin_net(const openfpga::BasicPort& pin) const;
|
||||
|
||||
/* Find the pin that a net is constrained to
|
||||
* If not found, the return port will be an invalid BasicPort
|
||||
* TODO: this function will only return the first pin found in the constraint list
|
||||
*/
|
||||
openfpga::BasicPort net_pin(const std::string& net) const;
|
||||
|
||||
/* Check if there are any pin constraints */
|
||||
bool empty() const;
|
||||
|
||||
|
|
|
@ -203,6 +203,8 @@ int fpga_verilog_testbench(const ModuleManager &module_manager,
|
|||
random_top_testbench_file_path,
|
||||
atom_ctx,
|
||||
netlist_annotation,
|
||||
module_manager,
|
||||
fabric_global_port_info,
|
||||
pin_constraints,
|
||||
simulation_setting,
|
||||
options.explicit_port_mapping());
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "openfpga_atom_netlist_utils.h"
|
||||
#include "simulation_utils.h"
|
||||
#include "fabric_global_port_info_utils.h"
|
||||
|
||||
#include "verilog_constants.h"
|
||||
#include "verilog_writer_utils.h"
|
||||
|
@ -168,6 +169,82 @@ void print_verilog_random_testbench_fpga_instance(std::fstream& fp,
|
|||
fp << std::endl;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Generate random stimulus for the reset port
|
||||
* This function is designed to drive the reset port of a benchmark module
|
||||
* The reset signal will be
|
||||
* - enabled in the 1st clock cycle
|
||||
* - disabled in the rest of clock cycles
|
||||
*******************************************************************/
|
||||
static
|
||||
void print_verilog_random_testbench_reset_stimuli(std::fstream& fp,
|
||||
const AtomContext& atom_ctx,
|
||||
const VprNetlistAnnotation& netlist_annotation,
|
||||
const ModuleManager& module_manager,
|
||||
const FabricGlobalPortInfo& global_ports,
|
||||
const PinConstraints& pin_constraints,
|
||||
const std::vector<std::string>& clock_port_names,
|
||||
const BasicPort& clock_port) {
|
||||
valid_file_stream(fp);
|
||||
|
||||
print_verilog_comment(fp, "----- Begin reset signal generation -----");
|
||||
|
||||
for (const AtomBlockId& atom_blk : atom_ctx.nlist.blocks()) {
|
||||
/* Bypass non-input atom blocks ! */
|
||||
if (AtomBlockType::INPAD != atom_ctx.nlist.block_type(atom_blk)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* The block may be renamed as it contains special characters which violate Verilog syntax */
|
||||
std::string block_name = atom_ctx.nlist.block_name(atom_blk);
|
||||
if (true == netlist_annotation.is_block_renamed(atom_blk)) {
|
||||
block_name = netlist_annotation.block_name(atom_blk);
|
||||
}
|
||||
|
||||
/* Bypass clock ports because their stimulus cannot be random */
|
||||
if (clock_port_names.end() != std::find(clock_port_names.begin(), clock_port_names.end(), block_name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Bypass any constained net that are mapped to a global port of the FPGA fabric
|
||||
* because their stimulus cannot be random
|
||||
*/
|
||||
if (false == port_is_fabric_global_reset_port(global_ports, module_manager, pin_constraints.net_pin(block_name))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Generete stimuli for this net which is how reset signal works */
|
||||
BasicPort reset_port(block_name, 1);
|
||||
size_t initial_value = 1;
|
||||
if (1 == global_ports.global_port_default_value(find_fabric_global_port(global_ports, module_manager, pin_constraints.net_pin(block_name)))) {
|
||||
initial_value = 0;
|
||||
}
|
||||
|
||||
fp << "initial" << std::endl;
|
||||
fp << "\tbegin" << std::endl;
|
||||
fp << "\t";
|
||||
std::vector<size_t> initial_values(reset_port.get_width(), initial_value);
|
||||
fp << "\t";
|
||||
fp << generate_verilog_port_constant_values(reset_port, initial_values);
|
||||
fp << ";" << std::endl;
|
||||
|
||||
/* Flip the reset at the second negative edge of the clock port
|
||||
* So the generic reset stimuli is applicable to both synchronous reset and asynchronous reset
|
||||
* This is because the reset is activated in a complete clock cycle
|
||||
* This gaurantees that even for synchronous reset, the reset can be sensed in the 1st rising/falling
|
||||
* edge of the clock signal
|
||||
*/
|
||||
fp << "\t@(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, clock_port) << ");" << std::endl;
|
||||
fp << "\t@(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, clock_port) << ");" << std::endl;
|
||||
print_verilog_wire_connection(fp, reset_port, reset_port, true);
|
||||
fp << "\tend" << std::endl;
|
||||
}
|
||||
|
||||
print_verilog_comment(fp, "----- End reset signal generation -----");
|
||||
|
||||
fp << std::endl;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Top-level function in this file:
|
||||
* Create a Verilog testbench using random input vectors
|
||||
|
@ -197,6 +274,8 @@ void print_verilog_random_top_testbench(const std::string& circuit_name,
|
|||
const std::string& verilog_fname,
|
||||
const AtomContext& atom_ctx,
|
||||
const VprNetlistAnnotation& netlist_annotation,
|
||||
const ModuleManager& module_manager,
|
||||
const FabricGlobalPortInfo& global_ports,
|
||||
const PinConstraints& pin_constraints,
|
||||
const SimulationSetting& simulation_parameters,
|
||||
const bool& explicit_port_mapping) {
|
||||
|
@ -240,8 +319,23 @@ void print_verilog_random_top_testbench(const std::string& circuit_name,
|
|||
pin_constraints,
|
||||
simulation_parameters,
|
||||
clock_ports);
|
||||
/* TODO: use the first clock now because we do not have information how the reset is
|
||||
* correlated to clock ports. Once we have such information, the limitation should be removed!
|
||||
*/
|
||||
print_verilog_random_testbench_reset_stimuli(fp,
|
||||
atom_ctx,
|
||||
netlist_annotation,
|
||||
module_manager,
|
||||
global_ports,
|
||||
pin_constraints,
|
||||
clock_port_names,
|
||||
clock_ports[0]);
|
||||
|
||||
print_verilog_testbench_random_stimuli(fp, atom_ctx,
|
||||
netlist_annotation,
|
||||
module_manager,
|
||||
global_ports,
|
||||
pin_constraints,
|
||||
clock_port_names,
|
||||
std::string(CHECKFLAG_PORT_POSTFIX),
|
||||
clock_ports);
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include <string>
|
||||
#include "vpr_context.h"
|
||||
#include "pin_constraints.h"
|
||||
#include "module_manager.h"
|
||||
#include "fabric_global_port_info.h"
|
||||
#include "simulation_setting.h"
|
||||
|
||||
/********************************************************************
|
||||
|
@ -20,6 +22,8 @@ void print_verilog_random_top_testbench(const std::string& circuit_name,
|
|||
const std::string& verilog_fname,
|
||||
const AtomContext& atom_ctx,
|
||||
const VprNetlistAnnotation& netlist_annotation,
|
||||
const ModuleManager& module_manager,
|
||||
const FabricGlobalPortInfo& global_ports,
|
||||
const PinConstraints& pin_constraints,
|
||||
const SimulationSetting& simulation_parameters,
|
||||
const bool& explicit_port_mapping);
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "verilog_port_types.h"
|
||||
|
||||
#include "module_manager_utils.h"
|
||||
#include "fabric_global_port_info_utils.h"
|
||||
|
||||
#include "verilog_constants.h"
|
||||
#include "verilog_writer_utils.h"
|
||||
|
@ -537,6 +538,9 @@ void print_verilog_testbench_clock_stimuli(std::fstream& fp,
|
|||
void print_verilog_testbench_random_stimuli(std::fstream& fp,
|
||||
const AtomContext& atom_ctx,
|
||||
const VprNetlistAnnotation& netlist_annotation,
|
||||
const ModuleManager& module_manager,
|
||||
const FabricGlobalPortInfo& global_ports,
|
||||
const PinConstraints& pin_constraints,
|
||||
const std::vector<std::string>& clock_port_names,
|
||||
const std::string& check_flag_port_postfix,
|
||||
const std::vector<BasicPort>& clock_ports) {
|
||||
|
@ -560,11 +564,18 @@ void print_verilog_testbench_random_stimuli(std::fstream& fp,
|
|||
block_name = netlist_annotation.block_name(atom_blk);
|
||||
}
|
||||
|
||||
/* Bypass clock ports */
|
||||
/* Bypass clock ports because their stimulus cannot be random */
|
||||
if (clock_port_names.end() != std::find(clock_port_names.begin(), clock_port_names.end(), block_name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Bypass any constained net that are mapped to a global port of the FPGA fabric
|
||||
* because their stimulus cannot be random
|
||||
*/
|
||||
if (true == port_is_fabric_global_reset_port(global_ports, module_manager, pin_constraints.net_pin(block_name))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* TODO: find the clock inputs will be initialized later */
|
||||
if (AtomBlockType::INPAD == atom_ctx.nlist.block_type(atom_blk)) {
|
||||
fp << "\t\t" << block_name << " <= 1'b0;" << std::endl;
|
||||
|
@ -620,11 +631,18 @@ void print_verilog_testbench_random_stimuli(std::fstream& fp,
|
|||
block_name = netlist_annotation.block_name(atom_blk);
|
||||
}
|
||||
|
||||
/* Bypass clock ports */
|
||||
/* Bypass clock ports because their stimulus cannot be random */
|
||||
if (clock_port_names.end() != std::find(clock_port_names.begin(), clock_port_names.end(), block_name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Bypass any constained net that are mapped to a global port of the FPGA fabric
|
||||
* because their stimulus cannot be random
|
||||
*/
|
||||
if (true == port_is_fabric_global_reset_port(global_ports, module_manager, pin_constraints.net_pin(block_name))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* TODO: find the clock inputs will be initialized later */
|
||||
if (AtomBlockType::INPAD == atom_ctx.nlist.block_type(atom_blk)) {
|
||||
fp << "\t\t" << block_name << " <= $random;" << std::endl;
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "vpr_context.h"
|
||||
#include "io_location_map.h"
|
||||
#include "vpr_netlist_annotation.h"
|
||||
#include "fabric_global_port_info.h"
|
||||
#include "pin_constraints.h"
|
||||
#include "simulation_setting.h"
|
||||
|
||||
|
@ -84,6 +85,9 @@ void print_verilog_testbench_clock_stimuli(std::fstream& fp,
|
|||
void print_verilog_testbench_random_stimuli(std::fstream& fp,
|
||||
const AtomContext& atom_ctx,
|
||||
const VprNetlistAnnotation& netlist_annotation,
|
||||
const ModuleManager& module_manager,
|
||||
const FabricGlobalPortInfo& global_ports,
|
||||
const PinConstraints& pin_constraints,
|
||||
const std::vector<std::string>& clock_port_names,
|
||||
const std::string& check_flag_port_postfix,
|
||||
const std::vector<BasicPort>& clock_ports);
|
||||
|
|
|
@ -47,7 +47,6 @@ constexpr char* TOP_TESTBENCH_PROG_TASK_NAME = "prog_cycle_task";
|
|||
|
||||
constexpr char* TOP_TESTBENCH_SIM_START_PORT_NAME = "sim_start";
|
||||
|
||||
constexpr int TOP_TESTBENCH_MAGIC_NUMBER_FOR_SIMULATION_TIME = 200;
|
||||
constexpr char* TOP_TESTBENCH_ERROR_COUNTER = "nb_error";
|
||||
|
||||
constexpr char* TOP_TB_RESET_PORT_NAME = "greset";
|
||||
|
@ -1931,6 +1930,54 @@ void print_verilog_top_testbench_bitstream(std::fstream& fp,
|
|||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Connect proper stimuli to the reset port
|
||||
* This function is designed to drive the reset port of a benchmark module
|
||||
*******************************************************************/
|
||||
static
|
||||
void print_verilog_top_testbench_reset_stimuli(std::fstream& fp,
|
||||
const AtomContext& atom_ctx,
|
||||
const VprNetlistAnnotation& netlist_annotation,
|
||||
const ModuleManager& module_manager,
|
||||
const FabricGlobalPortInfo& global_ports,
|
||||
const PinConstraints& pin_constraints,
|
||||
const std::vector<std::string>& clock_port_names) {
|
||||
valid_file_stream(fp);
|
||||
|
||||
print_verilog_comment(fp, "----- Begin reset signal generation -----");
|
||||
|
||||
for (const AtomBlockId& atom_blk : atom_ctx.nlist.blocks()) {
|
||||
/* Bypass non-input atom blocks ! */
|
||||
if (AtomBlockType::INPAD != atom_ctx.nlist.block_type(atom_blk)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* The block may be renamed as it contains special characters which violate Verilog syntax */
|
||||
std::string block_name = atom_ctx.nlist.block_name(atom_blk);
|
||||
if (true == netlist_annotation.is_block_renamed(atom_blk)) {
|
||||
block_name = netlist_annotation.block_name(atom_blk);
|
||||
}
|
||||
|
||||
/* Bypass clock ports because their stimulus cannot be random */
|
||||
if (clock_port_names.end() != std::find(clock_port_names.begin(), clock_port_names.end(), block_name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Bypass any constained net that are mapped to a global port of the FPGA fabric
|
||||
* because their stimulus cannot be random
|
||||
*/
|
||||
if (false == port_is_fabric_global_reset_port(global_ports, module_manager, pin_constraints.net_pin(block_name))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Connect stimuli to greset with an optional inversion, depending on the default value */
|
||||
BasicPort reset_port(block_name, 1);
|
||||
print_verilog_wire_connection(fp, reset_port,
|
||||
BasicPort(TOP_TB_RESET_PORT_NAME, 1),
|
||||
1 == global_ports.global_port_default_value(find_fabric_global_port(global_ports, module_manager, pin_constraints.net_pin(block_name))));
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Add auto-check codes for the full testbench
|
||||
* in particular for the configuration phase:
|
||||
|
@ -2164,9 +2211,20 @@ void print_verilog_top_testbench(const ModuleManager& 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)));
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#include "vtr_assert.h"
|
||||
#include "vtr_log.h"
|
||||
|
||||
#include "openfpga_naming.h"
|
||||
|
||||
#include "fabric_global_port_info_utils.h"
|
||||
|
||||
/* begin namespace openfpga */
|
||||
|
@ -58,4 +60,51 @@ std::vector<FabricGlobalPortId> find_fabric_global_programming_set_ports(const F
|
|||
return global_prog_set_ports;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Identify if a port is in the list of fabric global port
|
||||
* and its functionality is a reset port which is not used for programming FPGAs
|
||||
*******************************************************************/
|
||||
bool port_is_fabric_global_reset_port(const FabricGlobalPortInfo& fabric_global_port_info,
|
||||
const ModuleManager& module_manager,
|
||||
const BasicPort& port) {
|
||||
/* Find the top_module: the fabric global ports are always part of the ports of 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));
|
||||
|
||||
for (const FabricGlobalPortId& fabric_global_port_id : fabric_global_port_info.global_ports()) {
|
||||
if ( (false == fabric_global_port_info.global_port_is_reset(fabric_global_port_id))
|
||||
|| (true == fabric_global_port_info.global_port_is_prog(fabric_global_port_id))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BasicPort module_global_port = module_manager.module_port(top_module, fabric_global_port_info.global_module_port(fabric_global_port_id));
|
||||
if ( (true == module_global_port.mergeable(port))
|
||||
&& (true == module_global_port.contained(port)) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Find a global port with a given name
|
||||
*******************************************************************/
|
||||
FabricGlobalPortId find_fabric_global_port(const FabricGlobalPortInfo& fabric_global_port_info,
|
||||
const ModuleManager& module_manager,
|
||||
const BasicPort& port) {
|
||||
/* Find the top_module: the fabric global ports are always part of the ports of 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));
|
||||
|
||||
for (const FabricGlobalPortId& fabric_global_port_id : fabric_global_port_info.global_ports()) {
|
||||
BasicPort module_global_port = module_manager.module_port(top_module, fabric_global_port_info.global_module_port(fabric_global_port_id));
|
||||
if ( (true == module_global_port.mergeable(port))
|
||||
&& (true == module_global_port.contained(port)) ) {
|
||||
return fabric_global_port_id;
|
||||
}
|
||||
}
|
||||
return FabricGlobalPortId::INVALID();
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*******************************************************************/
|
||||
#include <vector>
|
||||
#include "fabric_global_port_info.h"
|
||||
#include "module_manager.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
|
@ -18,6 +19,14 @@ std::vector<FabricGlobalPortId> find_fabric_global_programming_reset_ports(const
|
|||
|
||||
std::vector<FabricGlobalPortId> find_fabric_global_programming_set_ports(const FabricGlobalPortInfo& fabric_global_port_info);
|
||||
|
||||
bool port_is_fabric_global_reset_port(const FabricGlobalPortInfo& fabric_global_port_info,
|
||||
const ModuleManager& module_manager,
|
||||
const BasicPort& port);
|
||||
|
||||
FabricGlobalPortId find_fabric_global_port(const FabricGlobalPortInfo& fabric_global_port_info,
|
||||
const ModuleManager& module_manager,
|
||||
const BasicPort& port);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue