diff --git a/libopenfpga/libpcf/src/pin_constraints.cpp b/libopenfpga/libpcf/src/pin_constraints.cpp index 4f7a701a7..25cd1048d 100644 --- a/libopenfpga/libpcf/src/pin_constraints.cpp +++ b/libopenfpga/libpcf/src/pin_constraints.cpp @@ -38,6 +38,28 @@ std::string PinConstraints::net(const PinConstraintId& pin_constraint_id) const return pin_constraint_nets_[pin_constraint_id]; } +std::string PinConstraints::pin_net(const openfpga::BasicPort& pin) const { + std::string constrained_net_name; + for (const PinConstraintId& pin_constraint : pin_constraints()) { + if (pin == pin_constraint_pins_[pin_constraint]) { + constrained_net_name = net(pin_constraint); + break; + } + } + 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(); } @@ -70,3 +92,11 @@ PinConstraintId PinConstraints::create_pin_constraint(const openfpga::BasicPort& bool PinConstraints::valid_pin_constraint_id(const PinConstraintId& pin_constraint_id) const { return ( size_t(pin_constraint_id) < pin_constraint_ids_.size() ) && ( pin_constraint_id == pin_constraint_ids_[pin_constraint_id] ); } + +bool PinConstraints::unconstrained_net(const std::string& net) const { + return net.empty(); +} + +bool PinConstraints::unmapped_net(const std::string& net) const { + return std::string(PIN_CONSTRAINT_OPEN_NET) == net; +} diff --git a/libopenfpga/libpcf/src/pin_constraints.h b/libopenfpga/libpcf/src/pin_constraints.h index 8b3a977c0..3ea3aad2f 100644 --- a/libopenfpga/libpcf/src/pin_constraints.h +++ b/libopenfpga/libpcf/src/pin_constraints.h @@ -52,11 +52,21 @@ class PinConstraints { /* Get the net to be constrained */ std::string net(const PinConstraintId& pin_constraint_id) const; + /* Find the net that is constrained on a pin + * TODO: this function will only return the first net found in the constraint list + */ + 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; public: /* Public Mutators */ - /* Reserve a number of design constraints to be memory efficent */ void reserve_pin_constraints(const size_t& num_pin_constraints); @@ -65,7 +75,22 @@ class PinConstraints { const std::string& net); public: /* Public invalidators/validators */ + /* Show if the pin constraint id is a valid for data queries */ bool valid_pin_constraint_id(const PinConstraintId& pin_constraint_id) const; + + /* Show if the net has no constraints (free to map to any pin) + * This function is used to identify the net name returned by APIs: + * - pin_net() + * - net() + */ + bool unconstrained_net(const std::string& net) const; + + /* Show if the net is defined specifically not to map to any pin + * This function is used to identify the net name returned by APIs: + * - pin_net() + * - net() + */ + bool unmapped_net(const std::string& net) const; private: /* Internal data */ /* Unique ids for each design constraint */ vtr::vector pin_constraint_ids_; diff --git a/openfpga/src/fpga_verilog/verilog_api.cpp b/openfpga/src/fpga_verilog/verilog_api.cpp index 424f85c42..46a81c96e 100644 --- a/openfpga/src/fpga_verilog/verilog_api.cpp +++ b/openfpga/src/fpga_verilog/verilog_api.cpp @@ -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()); diff --git a/openfpga/src/fpga_verilog/verilog_formal_random_top_testbench.cpp b/openfpga/src/fpga_verilog/verilog_formal_random_top_testbench.cpp index 860cc39a8..848970a30 100644 --- a/openfpga/src/fpga_verilog/verilog_formal_random_top_testbench.cpp +++ b/openfpga/src/fpga_verilog/verilog_formal_random_top_testbench.cpp @@ -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& 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 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); diff --git a/openfpga/src/fpga_verilog/verilog_formal_random_top_testbench.h b/openfpga/src/fpga_verilog/verilog_formal_random_top_testbench.h index d89652df9..6dd4f0310 100644 --- a/openfpga/src/fpga_verilog/verilog_formal_random_top_testbench.h +++ b/openfpga/src/fpga_verilog/verilog_formal_random_top_testbench.h @@ -7,6 +7,8 @@ #include #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); diff --git a/openfpga/src/fpga_verilog/verilog_preconfig_top_module.cpp b/openfpga/src/fpga_verilog/verilog_preconfig_top_module.cpp index 542eadc2e..ece6df67a 100644 --- a/openfpga/src/fpga_verilog/verilog_preconfig_top_module.cpp +++ b/openfpga/src/fpga_verilog/verilog_preconfig_top_module.cpp @@ -135,16 +135,10 @@ int print_verilog_preconfig_top_module_connect_global_ports(std::fstream &fp, BasicPort module_clock_pin(module_global_port.get_name(), module_global_port.pins()[pin_id], module_global_port.pins()[pin_id]); /* If the clock port name is in the pin constraints, we should wire it to the constrained pin */ - std::string constrained_net_name; - for (const PinConstraintId& pin_constraint : pin_constraints.pin_constraints()) { - if (module_clock_pin == pin_constraints.pin(pin_constraint)) { - constrained_net_name = pin_constraints.net(pin_constraint); - break; - } - } + std::string constrained_net_name = pin_constraints.pin_net(module_clock_pin); /* If constrained to an open net or there is no clock in the benchmark, we assign it to a default value */ - if ( (std::string(PIN_CONSTRAINT_OPEN_NET) == constrained_net_name) + if ( (true == pin_constraints.unmapped_net(constrained_net_name)) || (true == benchmark_clock_port_names.empty())) { std::vector default_values(1, fabric_global_ports.global_port_default_value(global_port_id)); print_verilog_wire_constant_values(fp, module_clock_pin, default_values); @@ -152,7 +146,7 @@ int print_verilog_preconfig_top_module_connect_global_ports(std::fstream &fp, } std::string clock_name_to_connect; - if (!constrained_net_name.empty()) { + if (!pin_constraints.unconstrained_net(constrained_net_name)) { clock_name_to_connect = constrained_net_name; } else { /* Otherwise, we must have a clear one-to-one clock net corresponding!!! */ @@ -173,8 +167,27 @@ int print_verilog_preconfig_top_module_connect_global_ports(std::fstream &fp, } /* For other ports, give an default value */ - std::vector default_values(module_global_port.get_width(), fabric_global_ports.global_port_default_value(global_port_id)); - print_verilog_wire_constant_values(fp, module_global_port, default_values); + for (size_t pin_id = 0; pin_id < module_global_port.pins().size(); ++pin_id) { + BasicPort module_global_pin(module_global_port.get_name(), + module_global_port.pins()[pin_id], + module_global_port.pins()[pin_id]); + + /* If the global port name is in the pin constraints, we should wire it to the constrained pin */ + std::string constrained_net_name = pin_constraints.pin_net(module_global_pin); + + /* - If constrained to a given net in the benchmark, we connect the global pin to the net + * - If constrained to an open net in the benchmark, we assign it to a default value + */ + if ( (false == pin_constraints.unconstrained_net(constrained_net_name)) + && (false == pin_constraints.unmapped_net(constrained_net_name))) { + BasicPort benchmark_pin(constrained_net_name + std::string(FORMAL_VERIFICATION_TOP_MODULE_PORT_POSTFIX), 1); + print_verilog_wire_connection(fp, module_global_pin, benchmark_pin, false); + } else { + VTR_ASSERT_SAFE(std::string(PIN_CONSTRAINT_OPEN_NET) == constrained_net_name); + std::vector default_values(module_global_pin.get_width(), fabric_global_ports.global_port_default_value(global_port_id)); + print_verilog_wire_constant_values(fp, module_global_pin, default_values); + } + } } print_verilog_comment(fp, std::string("----- End Connect Global ports of FPGA top module -----")); diff --git a/openfpga/src/fpga_verilog/verilog_testbench_utils.cpp b/openfpga/src/fpga_verilog/verilog_testbench_utils.cpp index b445e07f9..3329d33cf 100644 --- a/openfpga/src/fpga_verilog/verilog_testbench_utils.cpp +++ b/openfpga/src/fpga_verilog/verilog_testbench_utils.cpp @@ -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& clock_port_names, const std::string& check_flag_port_postfix, const std::vector& 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; diff --git a/openfpga/src/fpga_verilog/verilog_testbench_utils.h b/openfpga/src/fpga_verilog/verilog_testbench_utils.h index a2eca17cd..0eb77bda9 100644 --- a/openfpga/src/fpga_verilog/verilog_testbench_utils.h +++ b/openfpga/src/fpga_verilog/verilog_testbench_utils.h @@ -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& clock_port_names, const std::string& check_flag_port_postfix, const std::vector& clock_ports); diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp index 08b7cd2e8..d58a2c730 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp +++ b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp @@ -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"; @@ -258,21 +257,17 @@ void print_verilog_top_testbench_config_protocol_port(std::fstream& fp, } /******************************************************************** - * Wire the global ports of FPGA fabric to local wires + * Wire the global clock ports of FPGA fabric to local wires *******************************************************************/ static -void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp, - const ModuleManager& module_manager, - const ModuleId& top_module, - const FabricGlobalPortInfo& fabric_global_port_info, - const SimulationSetting& simulation_parameters, - const bool& active_global_prog_reset, - const bool& active_global_prog_set) { +void print_verilog_top_testbench_global_clock_ports_stimuli(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& top_module, + const FabricGlobalPortInfo& fabric_global_port_info, + const SimulationSetting& simulation_parameters) { /* Validate the file stream */ valid_file_stream(fp); - print_verilog_comment(fp, std::string("----- Begin connecting global ports of FPGA fabric to stimuli -----")); - /* Connect global clock ports to operating or programming clock signal */ for (const FabricGlobalPortId& fabric_global_port : fabric_global_port_info.global_ports()) { if (false == fabric_global_port_info.global_port_is_clock(fabric_global_port)) { @@ -317,6 +312,18 @@ void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp, 1 == fabric_global_port_info.global_port_default_value(fabric_global_port)); } } +} + +/******************************************************************** + * Wire the global config done ports of FPGA fabric to local wires + *******************************************************************/ +static +void print_verilog_top_testbench_global_config_done_ports_stimuli(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& top_module, + const FabricGlobalPortInfo& fabric_global_port_info) { + /* Validate the file stream */ + valid_file_stream(fp); /* Connect global configuration done ports to configuration done signal */ for (const FabricGlobalPortId& fabric_global_port : fabric_global_port_info.global_ports()) { @@ -341,6 +348,20 @@ void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp, stimuli_config_done_port, 1 == fabric_global_port_info.global_port_default_value(fabric_global_port)); } +} + +/******************************************************************** + * Wire the global reset ports of FPGA fabric to local wires + *******************************************************************/ +static +void print_verilog_top_testbench_global_reset_ports_stimuli(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& top_module, + const PinConstraints& pin_constraints, + const FabricGlobalPortInfo& fabric_global_port_info, + const bool& active_global_prog_reset) { + /* Validate the file stream */ + valid_file_stream(fp); /* Connect global reset ports to operating or programming reset signal */ for (const FabricGlobalPortId& fabric_global_port : fabric_global_port_info.global_ports()) { @@ -373,20 +394,58 @@ void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp, stimuli_reset_port.set_name(std::string(TOP_TB_RESET_PORT_NAME)); stimuli_reset_port.set_width(1); } - /* Wire the port to the input stimuli: - * The wiring will be inverted if the default value of the global port is 1 - * Otherwise, the wiring will not be inverted! - */ - if (true == activate) { - print_verilog_wire_connection(fp, module_manager.module_port(top_module, module_global_port), - stimuli_reset_port, - 1 == fabric_global_port_info.global_port_default_value(fabric_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, fabric_global_port_info.global_port_default_value(fabric_global_port))); + + BasicPort module_global_port_info = module_manager.module_port(top_module, module_global_port); + + for (size_t pin_id = 0; pin_id < module_global_port_info.pins().size(); ++pin_id) { + BasicPort module_global_pin(module_global_port_info.get_name(), + module_global_port_info.pins()[pin_id], + module_global_port_info.pins()[pin_id]); + + /* Regular reset port can be mapped by a net from user design */ + if (false == fabric_global_port_info.global_port_is_prog(fabric_global_port)) { + /* If the global port name is in the pin constraints, we should wire it to the constrained pin */ + std::string constrained_net_name = pin_constraints.pin_net(module_global_pin); + + /* - If constrained to a given net in the benchmark, we connect the global pin to the net */ + if ( (false == pin_constraints.unconstrained_net(constrained_net_name)) + && (false == pin_constraints.unmapped_net(constrained_net_name))) { + BasicPort benchmark_pin(constrained_net_name, 1); + print_verilog_wire_connection(fp, module_global_pin, + benchmark_pin, + false); + continue; /* Finish the net assignment for this reset pin */ + } + } + + /* Wire the port to the input stimuli: + * The wiring will be inverted if the default value of the global port is 1 + * Otherwise, the wiring will not be inverted! + */ + if (true == activate) { + print_verilog_wire_connection(fp, module_global_pin, + stimuli_reset_port, + 1 == fabric_global_port_info.global_port_default_value(fabric_global_port)); + } else { + VTR_ASSERT_SAFE(false == activate); + print_verilog_wire_constant_values(fp, module_global_pin, + std::vector(1, fabric_global_port_info.global_port_default_value(fabric_global_port))); + } } } +} + +/******************************************************************** + * Wire the global set ports of FPGA fabric to local wires + *******************************************************************/ +static +void print_verilog_top_testbench_global_set_ports_stimuli(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& top_module, + const FabricGlobalPortInfo& fabric_global_port_info, + const bool& active_global_prog_set) { + /* Validate the file stream */ + valid_file_stream(fp); /* Connect global set ports to operating or programming set signal */ for (const FabricGlobalPortId& fabric_global_port : fabric_global_port_info.global_ports()) { @@ -438,6 +497,18 @@ void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp, std::vector(1, fabric_global_port_info.global_port_default_value(fabric_global_port))); } } +} + +/******************************************************************** + * Wire the regular global ports of FPGA fabric to local wires + *******************************************************************/ +static +void print_verilog_top_testbench_regular_global_ports_stimuli(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& top_module, + const FabricGlobalPortInfo& fabric_global_port_info) { + /* Validate the file stream */ + valid_file_stream(fp); /* For the rest of global ports, wire them to constant signals */ for (const FabricGlobalPortId& fabric_global_port : fabric_global_port_info.global_ports()) { @@ -478,6 +549,55 @@ void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp, std::vector default_values(module_port.get_width(), fabric_global_port_info.global_port_default_value(fabric_global_port)); print_verilog_wire_constant_values(fp, module_port, default_values); } +} + +/******************************************************************** + * Wire the global ports of FPGA fabric to local wires + *******************************************************************/ +static +void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& top_module, + const PinConstraints& pin_constraints, + const FabricGlobalPortInfo& fabric_global_port_info, + const SimulationSetting& simulation_parameters, + const bool& active_global_prog_reset, + const bool& active_global_prog_set) { + /* Validate the file stream */ + valid_file_stream(fp); + + print_verilog_comment(fp, std::string("----- Begin connecting global ports of FPGA fabric to stimuli -----")); + + print_verilog_top_testbench_global_clock_ports_stimuli(fp, + module_manager, + top_module, + fabric_global_port_info, + simulation_parameters); + + print_verilog_top_testbench_global_config_done_ports_stimuli(fp, + module_manager, + top_module, + fabric_global_port_info); + + + print_verilog_top_testbench_global_reset_ports_stimuli(fp, + module_manager, + top_module, + pin_constraints, + fabric_global_port_info, + active_global_prog_reset); + + print_verilog_top_testbench_global_set_ports_stimuli(fp, + module_manager, + top_module, + fabric_global_port_info, + active_global_prog_set); + + + print_verilog_top_testbench_regular_global_ports_stimuli(fp, + module_manager, + top_module, + fabric_global_port_info); print_verilog_comment(fp, std::string("----- End connecting global ports of FPGA fabric to stimuli -----")); } @@ -1810,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& 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: @@ -1994,6 +2162,7 @@ void print_verilog_top_testbench(const ModuleManager& module_manager, /* 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, @@ -2042,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(1, BasicPort(std::string(TOP_TB_OP_CLOCK_PORT_NAME), 1))); diff --git a/openfpga/src/utils/fabric_global_port_info_utils.cpp b/openfpga/src/utils/fabric_global_port_info_utils.cpp index 3200a8fbd..9fbd707c5 100644 --- a/openfpga/src/utils/fabric_global_port_info_utils.cpp +++ b/openfpga/src/utils/fabric_global_port_info_utils.cpp @@ -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 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 */ diff --git a/openfpga/src/utils/fabric_global_port_info_utils.h b/openfpga/src/utils/fabric_global_port_info_utils.h index 457c0018e..99611bc8b 100644 --- a/openfpga/src/utils/fabric_global_port_info_utils.h +++ b/openfpga/src/utils/fabric_global_port_info_utils.h @@ -6,6 +6,7 @@ *******************************************************************/ #include #include "fabric_global_port_info.h" +#include "module_manager.h" /******************************************************************** * Function declaration @@ -18,6 +19,14 @@ std::vector find_fabric_global_programming_reset_ports(const std::vector 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 diff --git a/openfpga_flow/openfpga_shell_scripts/example_without_ace_script.openfpga b/openfpga_flow/openfpga_shell_scripts/example_without_ace_script.openfpga index f694b3c03..3c1be9114 100644 --- a/openfpga_flow/openfpga_shell_scripts/example_without_ace_script.openfpga +++ b/openfpga_flow/openfpga_shell_scripts/example_without_ace_script.openfpga @@ -55,7 +55,7 @@ write_fabric_verilog --file ./SRC --explicit_port_mapping --include_timing --pri # - Enable top-level testbench which is a full verification including programming circuit and core logic of FPGA # - Enable pre-configured top-level testbench which is a fast verification skipping programming phase # - Simulation ini file is optional and is needed only when you need to interface different HDL simulators using openfpga flow-run scripts -write_verilog_testbench --file ./SRC --reference_benchmark_file_path ${REFERENCE_VERILOG_TESTBENCH} --print_top_testbench --print_preconfig_top_testbench --print_simulation_ini ./SimulationDeck/simulation_deck.ini --include_signal_init --support_icarus_simulator +write_verilog_testbench --file ./SRC --reference_benchmark_file_path ${REFERENCE_VERILOG_TESTBENCH} --print_top_testbench --print_preconfig_top_testbench --print_simulation_ini ./SimulationDeck/simulation_deck.ini --include_signal_init --support_icarus_simulator --pin_constraints_file ${OPENFPGA_PIN_CONSTRAINTS_FILE} # Write the SDC files for PnR backend # - Turn on every options here diff --git a/openfpga_flow/tasks/basic_tests/k4_series/k4n4_fracff/config/pin_constraints.xml b/openfpga_flow/tasks/basic_tests/k4_series/k4n4_fracff/config/pin_constraints.xml new file mode 100644 index 000000000..abcf209f6 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/k4_series/k4n4_fracff/config/pin_constraints.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/openfpga_flow/tasks/basic_tests/k4_series/k4n4_fracff/config/task.conf b/openfpga_flow/tasks/basic_tests/k4_series/k4n4_fracff/config/task.conf index 58be5a2bb..07e326a1e 100644 --- a/openfpga_flow/tasks/basic_tests/k4_series/k4n4_fracff/config/task.conf +++ b/openfpga_flow/tasks/basic_tests/k4_series/k4n4_fracff/config/task.conf @@ -19,6 +19,7 @@ fpga_flow=yosys_vpr openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/example_without_ace_script.openfpga openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_frac_N4_fracff_40nm_cc_openfpga.xml openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/fixed_sim_openfpga.xml +openfpga_pin_constraints_file=${PATH:OPENFPGA_PATH}/openfpga_flow/tasks/basic_tests/k4_series/k4n4_fracff/config/pin_constraints.xml # Yosys script parameters yosys_cell_sim_verilog=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/openfpga_dff_sim.v yosys_dff_map_verilog=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/openfpga_dff_map.v