[Tool] Upgrade openfpga engine to support multi-clock frequency definiton and their usage in testbench/SDC generation
This commit is contained in:
parent
89f9d24d32
commit
87b2c1f3b8
|
@ -12,6 +12,9 @@
|
|||
/* Headers from vtr util library */
|
||||
#include "vtr_assert.h"
|
||||
|
||||
/* Headers from openfpga util library */
|
||||
#include "openfpga_port_parser.h"
|
||||
|
||||
/* Headers from libarchfpga */
|
||||
#include "arch_error.h"
|
||||
#include "read_xml_util.h"
|
||||
|
@ -39,11 +42,24 @@ static
|
|||
void read_xml_operating_clock_override_setting(pugi::xml_node& xml_clock_override_setting,
|
||||
const pugiutil::loc_data& loc_data,
|
||||
openfpga::SimulationSetting& sim_setting) {
|
||||
/* Create a new clock override object in the sim_setting object with the given name */
|
||||
SimulationClockId clock_id = sim_setting.create_simulation_clock(get_attribute(xml_clock_override_setting, "name", loc_data).as_string());
|
||||
VTR_ASSERT(sim_setting.valid_clock_id(clock_id));
|
||||
std::string clock_name = get_attribute(xml_clock_override_setting, "name", loc_data).as_string();
|
||||
|
||||
sim_setting.set_simulation_clock_frequency(clock_id, get_attribute(xml_clock_override_setting, "frequency", loc_data).as_float(0.));
|
||||
/* Create a new clock override object in the sim_setting object with the given name */
|
||||
SimulationClockId clock_id = sim_setting.create_clock(clock_name);
|
||||
|
||||
/* Report if the clock creation failed, this is due to a conflicts in naming*/
|
||||
if (false == sim_setting.valid_clock_id(clock_id)) {
|
||||
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_clock_override_setting),
|
||||
"Fail to create simulation clock '%s', it may share the same name as other simulation clock definition!\n",
|
||||
clock_name.c_str());
|
||||
}
|
||||
|
||||
/* Parse port information */
|
||||
openfpga::PortParser clock_port_parser(get_attribute(xml_clock_override_setting, "port", loc_data).as_string());
|
||||
sim_setting.set_clock_port(clock_id, clock_port_parser.port());
|
||||
|
||||
/* Parse frequency information */
|
||||
sim_setting.set_clock_frequency(clock_id, get_attribute(xml_clock_override_setting, "frequency", loc_data).as_float(0.));
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
|
|
|
@ -43,6 +43,11 @@ std::string SimulationSetting::clock_name(const SimulationClockId& clock_id) con
|
|||
return clock_names_[clock_id];
|
||||
}
|
||||
|
||||
BasicPort SimulationSetting::clock_port(const SimulationClockId& clock_id) const {
|
||||
VTR_ASSERT(valid_clock_id(clock_id));
|
||||
return clock_ports_[clock_id];
|
||||
}
|
||||
|
||||
float SimulationSetting::clock_frequency(const SimulationClockId& clock_id) const {
|
||||
VTR_ASSERT(valid_clock_id(clock_id));
|
||||
return clock_frequencies_[clock_id];
|
||||
|
@ -139,16 +144,33 @@ void SimulationSetting::set_programming_clock_frequency(const float& clock_freq)
|
|||
default_clock_frequencies_.set_y(clock_freq);
|
||||
}
|
||||
|
||||
SimulationClockId SimulationSetting::create_simulation_clock(const std::string& name) {
|
||||
SimulationClockId SimulationSetting::create_clock(const std::string& name) {
|
||||
/* Ensure a unique name for the clock definition */
|
||||
std::map<std::string, SimulationClockId>::iterator it = clock_name2ids_.find(name);
|
||||
if (it != clock_name2ids_.end()) {
|
||||
return SimulationClockId::INVALID();
|
||||
}
|
||||
|
||||
/* This is a legal name. we can create a new id */
|
||||
SimulationClockId clock_id = SimulationClockId(clock_ids_.size());
|
||||
clock_ids_.push_back(clock_id);
|
||||
clock_names_.push_back(name);
|
||||
clock_ports_.emplace_back();
|
||||
clock_frequencies_.push_back(0.);
|
||||
|
||||
/* Register in the name-to-id map */
|
||||
clock_name2ids_[name] = clock_id;
|
||||
|
||||
return clock_id;
|
||||
}
|
||||
|
||||
void SimulationSetting::set_simulation_clock_frequency(const SimulationClockId& clock_id,
|
||||
void SimulationSetting::set_clock_port(const SimulationClockId& clock_id,
|
||||
const BasicPort& port) {
|
||||
VTR_ASSERT(valid_clock_id(clock_id));
|
||||
clock_ports_[clock_id] = port;
|
||||
}
|
||||
|
||||
void SimulationSetting::set_clock_frequency(const SimulationClockId& clock_id,
|
||||
const float& frequency) {
|
||||
VTR_ASSERT(valid_clock_id(clock_id));
|
||||
clock_frequencies_[clock_id] = frequency;
|
||||
|
|
|
@ -7,10 +7,13 @@
|
|||
*******************************************************************/
|
||||
#include <string>
|
||||
#include <array>
|
||||
#include <map>
|
||||
|
||||
#include "vtr_vector.h"
|
||||
#include "vtr_geometry.h"
|
||||
|
||||
#include "openfpga_port.h"
|
||||
|
||||
#include "simulation_setting_fwd.h"
|
||||
|
||||
/********************************************************************
|
||||
|
@ -64,6 +67,7 @@ class SimulationSetting {
|
|||
float programming_clock_frequency() const;
|
||||
size_t num_simulation_clock_cycles() const;
|
||||
std::string clock_name(const SimulationClockId& clock_id) const;
|
||||
BasicPort clock_port(const SimulationClockId& clock_id) const;
|
||||
float clock_frequency(const SimulationClockId& clock_id) const;
|
||||
bool auto_select_num_clock_cycles() const;
|
||||
size_t num_clock_cycles() const;
|
||||
|
@ -89,11 +93,14 @@ class SimulationSetting {
|
|||
void set_programming_clock_frequency(const float& clock_freq);
|
||||
/* Add a new simulation clock with
|
||||
* - a given name
|
||||
* - a given port description
|
||||
* - a default zero frequency which can be overwritten by
|
||||
* the operating_clock_frequency()
|
||||
*/
|
||||
SimulationClockId create_simulation_clock(const std::string& name);
|
||||
void set_simulation_clock_frequency(const SimulationClockId& clock_id,
|
||||
SimulationClockId create_clock(const std::string& name);
|
||||
void set_clock_port(const SimulationClockId& clock_id,
|
||||
const BasicPort& port);
|
||||
void set_clock_frequency(const SimulationClockId& clock_id,
|
||||
const float& frequency);
|
||||
void set_num_clock_cycles(const size_t& num_clk_cycles);
|
||||
void set_operating_clock_frequency_slack(const float& op_clk_freq_slack);
|
||||
|
@ -134,14 +141,19 @@ class SimulationSetting {
|
|||
/* Multiple simulation clocks with detailed information
|
||||
* Each clock has
|
||||
* - a unique id
|
||||
* - a unique name which is supposed
|
||||
* - a unique name
|
||||
* - a unique port definition which is supposed
|
||||
* to match the clock port definition in OpenFPGA documentation
|
||||
* - a frequency which is only applicable to this clock name
|
||||
*/
|
||||
vtr::vector<SimulationClockId, SimulationClockId> clock_ids_;
|
||||
vtr::vector<SimulationClockId, std::string> clock_names_;
|
||||
vtr::vector<SimulationClockId, BasicPort> clock_ports_;
|
||||
vtr::vector<SimulationClockId, float> clock_frequencies_;
|
||||
|
||||
/* Fast name-to-id lookup */
|
||||
std::map<std::string, SimulationClockId> clock_name2ids_;
|
||||
|
||||
/* Number of clock cycles to be used in simulation
|
||||
* If the value is 0, the clock cycles can be automatically
|
||||
* inferred from the signal activities of users' implementation
|
||||
|
|
|
@ -44,6 +44,7 @@ void write_xml_clock_setting(std::fstream& fp,
|
|||
for (const SimulationClockId& clock_id : sim_setting.clocks()) {
|
||||
fp << "\t\t\t" << "<clock";
|
||||
write_xml_attribute(fp, "name", sim_setting.clock_name(clock_id).c_str());
|
||||
write_xml_attribute(fp, "port", generate_xml_port_name(sim_setting.clock_port(clock_id)).c_str());
|
||||
write_xml_attribute(fp, "frequency", std::to_string(sim_setting.clock_frequency(clock_id)).c_str());
|
||||
fp << ">" << "\n";
|
||||
}
|
||||
|
|
|
@ -17,25 +17,6 @@
|
|||
/* namespace openfpga begins */
|
||||
namespace openfpga {
|
||||
|
||||
/********************************************************************
|
||||
* FIXME: Use a common function to output ports
|
||||
* Generate the full hierarchy name for a operating pb_type
|
||||
*******************************************************************/
|
||||
static
|
||||
std::string generate_tile_port_name(const BasicPort& pb_port) {
|
||||
std::string port_name;
|
||||
|
||||
/* Output format: <port_name>[<LSB>:<MSB>] */
|
||||
port_name += pb_port.get_name();
|
||||
port_name += std::string("[");
|
||||
port_name += std::to_string(pb_port.get_lsb());
|
||||
port_name += std::string(":");
|
||||
port_name += std::to_string(pb_port.get_msb());
|
||||
port_name += std::string("]");
|
||||
|
||||
return port_name;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* A writer to output a device variation in a technology library to XML format
|
||||
*******************************************************************/
|
||||
|
@ -64,7 +45,7 @@ void write_xml_tile_annotation_global_port(std::fstream& fp,
|
|||
for (size_t tile_info_id = 0; tile_info_id < tile_annotation.global_port_tile_names(global_port_id).size(); ++tile_info_id) {
|
||||
fp << "\t\t\t" << "<tile ";
|
||||
write_xml_attribute(fp, "name", tile_annotation.global_port_tile_names(global_port_id)[tile_info_id].c_str());
|
||||
write_xml_attribute(fp, "port", generate_tile_port_name(tile_annotation.global_port_tile_ports(global_port_id)[tile_info_id]).c_str());
|
||||
write_xml_attribute(fp, "port", generate_xml_port_name(tile_annotation.global_port_tile_ports(global_port_id)[tile_info_id]).c_str());
|
||||
write_xml_attribute(fp, "x", tile_annotation.global_port_tile_coordinates(global_port_id)[tile_info_id].x());
|
||||
write_xml_attribute(fp, "y", tile_annotation.global_port_tile_coordinates(global_port_id)[tile_info_id].y());
|
||||
fp << "/>";
|
||||
|
|
|
@ -90,3 +90,21 @@ void write_xml_attribute(std::fstream& fp,
|
|||
fp << std::scientific << value;
|
||||
fp << "\"";
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* FIXME: Use a common function to output ports
|
||||
* Generate the full hierarchy name for a operating pb_type
|
||||
*******************************************************************/
|
||||
std::string generate_xml_port_name(const openfpga::BasicPort& pb_port) {
|
||||
std::string port_name;
|
||||
|
||||
/* Output format: <port_name>[<LSB>:<MSB>] */
|
||||
port_name += pb_port.get_name();
|
||||
port_name += std::string("[");
|
||||
port_name += std::to_string(pb_port.get_lsb());
|
||||
port_name += std::string(":");
|
||||
port_name += std::to_string(pb_port.get_msb());
|
||||
port_name += std::string("]");
|
||||
|
||||
return port_name;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*******************************************************************/
|
||||
#include <fstream>
|
||||
#include "circuit_library.h"
|
||||
#include "openfpga_port.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
|
@ -30,4 +31,6 @@ void write_xml_attribute(std::fstream& fp,
|
|||
const char* attr,
|
||||
const size_t& value);
|
||||
|
||||
std::string generate_xml_port_name(const openfpga::BasicPort& pb_port);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -219,6 +219,18 @@ int annotate_simulation_setting(const AtomContext& atom_ctx,
|
|||
VTR_LOG("Will apply operating clock frequency %g [MHz] to simulations\n",
|
||||
sim_setting.default_operating_clock_frequency() / 1e6);
|
||||
|
||||
/* Walk through all the clock information */
|
||||
for (const SimulationClockId& clock_id : sim_setting.clocks()) {
|
||||
if (0. == sim_setting.clock_frequency(clock_id)) {
|
||||
sim_setting.set_clock_frequency(clock_id, sim_setting.default_operating_clock_frequency());
|
||||
}
|
||||
VTR_LOG("Will apply clock frequency %g [MHz] to clock '%s[%d:%d]' in simulations\n",
|
||||
sim_setting.clock_frequency(clock_id) / 1e6,
|
||||
sim_setting.clock_port(clock_id).get_name().c_str(),
|
||||
sim_setting.clock_port(clock_id).get_lsb(),
|
||||
sim_setting.clock_port(clock_id).get_msb());
|
||||
}
|
||||
|
||||
if (0. == sim_setting.num_clock_cycles()) {
|
||||
/* Find the number of clock cycles to be used in simulation
|
||||
* by average over the signal activity
|
||||
|
|
|
@ -83,8 +83,6 @@ int write_pnr_sdc(const OpenfpgaContext& openfpga_ctx,
|
|||
/* Execute only when sdc is enabled */
|
||||
if (true == options.generate_sdc_pnr()) {
|
||||
print_pnr_sdc(options,
|
||||
1./openfpga_ctx.simulation_setting().programming_clock_frequency(),
|
||||
1./openfpga_ctx.simulation_setting().default_operating_clock_frequency(),
|
||||
g_vpr_ctx.device(),
|
||||
openfpga_ctx.vpr_device_annotation(),
|
||||
openfpga_ctx.device_rr_gsb(),
|
||||
|
@ -92,6 +90,7 @@ int write_pnr_sdc(const OpenfpgaContext& openfpga_ctx,
|
|||
openfpga_ctx.mux_lib(),
|
||||
openfpga_ctx.arch().circuit_lib,
|
||||
openfpga_ctx.fabric_global_port_info(),
|
||||
openfpga_ctx.simulation_setting(),
|
||||
openfpga_ctx.flow_manager().compress_routing());
|
||||
}
|
||||
|
||||
|
|
|
@ -241,7 +241,10 @@ void print_analysis_sdc(const AnalysisSdcOption& option,
|
|||
ModuleId top_module = openfpga_ctx.module_graph().find_module(generate_fpga_top_module_name());
|
||||
VTR_ASSERT(true == openfpga_ctx.module_graph().valid_module_id(top_module));
|
||||
|
||||
/* Create clock and set I/O ports with input/output delays */
|
||||
/* Create clock and set I/O ports with input/output delays
|
||||
* FIXME: Now different I/Os have different delays due to multiple clock frequency
|
||||
* We need to consider these impacts and constrain different I/Os with different delays!!!
|
||||
*/
|
||||
print_analysis_sdc_io_delays(fp, option.time_unit(),
|
||||
vpr_ctx.atom(), vpr_ctx.placement(),
|
||||
openfpga_ctx.vpr_netlist_annotation(), openfpga_ctx.io_location_map(),
|
||||
|
|
|
@ -59,11 +59,10 @@ void print_pnr_sdc_clock_port(std::fstream& fp,
|
|||
*******************************************************************/
|
||||
static
|
||||
void print_pnr_sdc_global_clock_ports(std::fstream& fp,
|
||||
const float& programming_critical_path_delay,
|
||||
const float& operating_critical_path_delay,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const FabricGlobalPortInfo& fabric_global_port_info) {
|
||||
const FabricGlobalPortInfo& fabric_global_port_info,
|
||||
const SimulationSetting& sim_setting) {
|
||||
|
||||
valid_file_stream(fp);
|
||||
|
||||
|
@ -73,11 +72,11 @@ void print_pnr_sdc_global_clock_ports(std::fstream& fp,
|
|||
continue;
|
||||
}
|
||||
/* Reach here, it means a clock port and we need print constraints */
|
||||
float clock_period = operating_critical_path_delay;
|
||||
float clock_period = 1./sim_setting.default_operating_clock_frequency();
|
||||
|
||||
/* For programming clock, we give a fixed period */
|
||||
if (true == fabric_global_port_info.global_port_is_prog(global_port)) {
|
||||
clock_period = programming_critical_path_delay;
|
||||
clock_period = 1./sim_setting.programming_clock_frequency();
|
||||
/* Print comments */
|
||||
fp << "##################################################" << std::endl;
|
||||
fp << "# Create programmable clock " << std::endl;
|
||||
|
@ -93,6 +92,15 @@ void print_pnr_sdc_global_clock_ports(std::fstream& fp,
|
|||
for (const size_t& pin : clock_port.pins()) {
|
||||
BasicPort port_to_constrain(clock_port.get_name(), pin, pin);
|
||||
|
||||
/* Should try to find a port defintion from simulation parameters
|
||||
* If found, it means that we need to use special clock name!
|
||||
*/
|
||||
for (const SimulationClockId& sim_clock : sim_setting.clocks()) {
|
||||
if (port_to_constrain == sim_setting.clock_port(sim_clock)) {
|
||||
clock_period = 1./sim_setting.clock_frequency(sim_clock);
|
||||
}
|
||||
}
|
||||
|
||||
print_pnr_sdc_clock_port(fp,
|
||||
port_to_constrain,
|
||||
clock_period);
|
||||
|
@ -153,11 +161,10 @@ void print_pnr_sdc_global_non_clock_ports(std::fstream& fp,
|
|||
* In general, we do not recommend to do this
|
||||
*******************************************************************/
|
||||
void print_pnr_sdc_global_ports(const std::string& sdc_dir,
|
||||
const float& programming_critical_path_delay,
|
||||
const float& operating_critical_path_delay,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const FabricGlobalPortInfo& global_ports,
|
||||
const SimulationSetting& sim_setting,
|
||||
const bool& constrain_non_clock_port) {
|
||||
|
||||
/* Create the file name for Verilog netlist */
|
||||
|
@ -177,14 +184,12 @@ void print_pnr_sdc_global_ports(const std::string& sdc_dir,
|
|||
print_sdc_file_header(fp, std::string("Clock contraints for PnR"));
|
||||
|
||||
print_pnr_sdc_global_clock_ports(fp,
|
||||
programming_critical_path_delay,
|
||||
operating_critical_path_delay,
|
||||
module_manager, top_module,
|
||||
global_ports);
|
||||
global_ports, sim_setting);
|
||||
|
||||
if (true == constrain_non_clock_port) {
|
||||
print_pnr_sdc_global_non_clock_ports(fp,
|
||||
operating_critical_path_delay,
|
||||
1./sim_setting.default_operating_clock_frequency(),
|
||||
module_manager, top_module,
|
||||
global_ports);
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <vector>
|
||||
#include "module_manager.h"
|
||||
#include "fabric_global_port_info.h"
|
||||
#include "simulation_setting.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
|
@ -17,11 +18,10 @@
|
|||
namespace openfpga {
|
||||
|
||||
void print_pnr_sdc_global_ports(const std::string& sdc_dir,
|
||||
const float& programming_critical_path_delay,
|
||||
const float& operating_critical_path_delay,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const FabricGlobalPortInfo& global_ports,
|
||||
const SimulationSetting& sim_setting,
|
||||
const bool& constrain_non_clock_port);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
|
|
@ -319,8 +319,6 @@ void print_pnr_sdc_compact_routing_disable_switch_block_outputs(const std::strin
|
|||
* 4. Design constraints for breaking the combinational loops in FPGA fabric
|
||||
*******************************************************************/
|
||||
void print_pnr_sdc(const PnrSdcOption& sdc_options,
|
||||
const float& programming_critical_path_delay,
|
||||
const float& operating_critical_path_delay,
|
||||
const DeviceContext& device_ctx,
|
||||
const VprDeviceAnnotation& device_annotation,
|
||||
const DeviceRRGSB& device_rr_gsb,
|
||||
|
@ -328,6 +326,7 @@ void print_pnr_sdc(const PnrSdcOption& sdc_options,
|
|||
const MuxLibrary& mux_lib,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const FabricGlobalPortInfo& global_ports,
|
||||
const SimulationSetting& sim_setting,
|
||||
const bool& compact_routing_hierarchy) {
|
||||
|
||||
std::string top_module_name = generate_fpga_top_module_name();
|
||||
|
@ -337,9 +336,8 @@ void print_pnr_sdc(const PnrSdcOption& sdc_options,
|
|||
/* Constrain global ports */
|
||||
if (true == sdc_options.constrain_global_port()) {
|
||||
print_pnr_sdc_global_ports(sdc_options.sdc_dir(),
|
||||
programming_critical_path_delay,
|
||||
operating_critical_path_delay,
|
||||
module_manager, top_module, global_ports,
|
||||
sim_setting,
|
||||
sdc_options.constrain_non_clock_global_port());
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "module_manager.h"
|
||||
#include "mux_library.h"
|
||||
#include "circuit_library.h"
|
||||
#include "simulation_setting.h"
|
||||
#include "fabric_global_port_info.h"
|
||||
#include "pnr_sdc_option.h"
|
||||
|
||||
|
@ -23,8 +24,6 @@
|
|||
namespace openfpga {
|
||||
|
||||
void print_pnr_sdc(const PnrSdcOption& sdc_options,
|
||||
const float& programming_critical_path_delay,
|
||||
const float& operating_critical_path_delay,
|
||||
const DeviceContext& device_ctx,
|
||||
const VprDeviceAnnotation& device_annotation,
|
||||
const DeviceRRGSB& device_rr_gsb,
|
||||
|
@ -32,6 +31,7 @@ void print_pnr_sdc(const PnrSdcOption& sdc_options,
|
|||
const MuxLibrary& mux_lib,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const FabricGlobalPortInfo& global_ports,
|
||||
const SimulationSetting& sim_setting,
|
||||
const bool& compact_routing_hierarchy);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
|
|
@ -484,11 +484,23 @@ void print_verilog_testbench_clock_stimuli(std::fstream& fp,
|
|||
for (const BasicPort& clock_port : clock_ports) {
|
||||
print_verilog_comment(fp, std::string("----- Clock '") + clock_port.get_name() + std::string("' Initialization -------"));
|
||||
|
||||
/* Find the corresponding clock frequency from the simulation parameters */
|
||||
float clk_freq_to_use = (0.5 / simulation_parameters.default_operating_clock_frequency()) / VERILOG_SIM_TIMESCALE;
|
||||
/* FIXME: This could be buggy because the implementation clock names do NOT have to
|
||||
* be the same as the clock definition in simulation settings!!!
|
||||
*/
|
||||
for (const SimulationClockId& sim_clock_id : simulation_parameters.clocks()) {
|
||||
/* If the clock name matches, we can use the clock frequency */
|
||||
if (simulation_parameters.clock_port(sim_clock_id) == clock_port) {
|
||||
clk_freq_to_use = (0.5 / simulation_parameters.clock_frequency(sim_clock_id)) / VERILOG_SIM_TIMESCALE;
|
||||
}
|
||||
}
|
||||
|
||||
fp << "\tinitial begin" << std::endl;
|
||||
/* Create clock stimuli */
|
||||
fp << "\t\t" << generate_verilog_port(VERILOG_PORT_CONKT, clock_port) << " <= 1'b0;" << std::endl;
|
||||
fp << "\t\twhile(1) begin" << std::endl;
|
||||
fp << "\t\t\t#" << std::setprecision(10) << ((0.5/simulation_parameters.default_operating_clock_frequency())/VERILOG_SIM_TIMESCALE) << std::endl;
|
||||
fp << "\t\t\t#" << std::setprecision(10) << clk_freq_to_use << std::endl;
|
||||
fp << "\t\t\t" << generate_verilog_port(VERILOG_PORT_CONKT, clock_port);
|
||||
fp << " <= !";
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, clock_port);
|
||||
|
|
|
@ -56,12 +56,24 @@ constexpr char* TOP_TB_PROG_RESET_PORT_NAME = "prog_reset";
|
|||
constexpr char* TOP_TB_PROG_SET_PORT_NAME = "prog_set";
|
||||
constexpr char* TOP_TB_CONFIG_DONE_PORT_NAME = "config_done";
|
||||
constexpr char* TOP_TB_OP_CLOCK_PORT_NAME = "op_clock";
|
||||
constexpr char* TOP_TB_OP_CLOCK_PORT_PREFIX = "operating_clk_";
|
||||
constexpr char* TOP_TB_PROG_CLOCK_PORT_NAME = "prog_clock";
|
||||
constexpr char* TOP_TB_INOUT_REG_POSTFIX = "_reg";
|
||||
constexpr char* TOP_TB_CLOCK_REG_POSTFIX = "_reg";
|
||||
|
||||
constexpr char* AUTOCHECK_TOP_TESTBENCH_VERILOG_MODULE_POSTFIX = "_autocheck_top_tb";
|
||||
|
||||
/********************************************************************
|
||||
* Generate a simulation clock port name
|
||||
* This function is designed to produce a uniform clock naming for these ports
|
||||
*******************************************************************/
|
||||
static
|
||||
std::string generate_top_testbench_clock_name(const std::string& prefix,
|
||||
const std::string& port_name) {
|
||||
return prefix + port_name;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Print local wires for flatten memory (standalone) configuration protocols
|
||||
*******************************************************************/
|
||||
|
@ -253,6 +265,7 @@ 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) {
|
||||
/* Validate the file stream */
|
||||
|
@ -290,10 +303,15 @@ void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp,
|
|||
*/
|
||||
for (const size_t& pin : module_manager.module_port(top_module, module_global_port).pins()) {
|
||||
BasicPort global_port_to_connect(module_manager.module_port(top_module, module_global_port).get_name(), pin, pin);
|
||||
/* TODO: This is a temporary fix to make the testbench generator run in multi-clock scenario
|
||||
* Need to consider multiple clock sources to connect
|
||||
* each of which may operate in different ferquency!!!
|
||||
/* Should try to find a port defintion from simulation parameters
|
||||
* If found, it means that we need to use special clock name!
|
||||
*/
|
||||
for (const SimulationClockId& sim_clock : simulation_parameters.clocks()) {
|
||||
if (global_port_to_connect == simulation_parameters.clock_port(sim_clock)) {
|
||||
stimuli_clock_port.set_name(generate_top_testbench_clock_name(std::string(TOP_TB_OP_CLOCK_PORT_PREFIX), simulation_parameters.clock_name(sim_clock)));
|
||||
}
|
||||
}
|
||||
|
||||
print_verilog_wire_connection(fp, global_port_to_connect,
|
||||
stimuli_clock_port,
|
||||
1 == fabric_global_port_info.global_port_default_value(fabric_global_port));
|
||||
|
@ -488,6 +506,7 @@ void print_verilog_top_testbench_ports(std::fstream& fp,
|
|||
const AtomContext& atom_ctx,
|
||||
const VprNetlistAnnotation& netlist_annotation,
|
||||
const std::vector<std::string>& clock_port_names,
|
||||
const SimulationSetting& simulation_parameters,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const std::string& circuit_name){
|
||||
/* Validate the file stream */
|
||||
|
@ -543,7 +562,21 @@ void print_verilog_top_testbench_ports(std::fstream& fp,
|
|||
BasicPort prog_clock_register_port(std::string(std::string(TOP_TB_PROG_CLOCK_PORT_NAME) + std::string(TOP_TB_CLOCK_REG_POSTFIX)), 1);
|
||||
fp << generate_verilog_port(VERILOG_PORT_REG, prog_clock_register_port) << ";" << std::endl;
|
||||
|
||||
/* Operating clock */
|
||||
/* Multiple operating clocks based on the simulation settings */
|
||||
for (const SimulationClockId& sim_clock : simulation_parameters.clocks()) {
|
||||
std::string sim_clock_port_name = generate_top_testbench_clock_name(std::string(TOP_TB_OP_CLOCK_PORT_PREFIX), simulation_parameters.clock_name(sim_clock));
|
||||
BasicPort sim_clock_port(sim_clock_port_name, 1);
|
||||
fp << generate_verilog_port(VERILOG_PORT_WIRE, sim_clock_port) << ";" << std::endl;
|
||||
BasicPort sim_clock_register_port(std::string(sim_clock_port_name + std::string(TOP_TB_CLOCK_REG_POSTFIX)), 1);
|
||||
fp << generate_verilog_port(VERILOG_PORT_REG, sim_clock_register_port) << ";" << std::endl;
|
||||
}
|
||||
|
||||
/* FIXME: Actually, for multi-clock implementations, input and output ports
|
||||
* should be synchronized by different clocks. Currently, we lack the information
|
||||
* about what inputs are driven by which clock. Therefore, we use a unified clock
|
||||
* signal to do the job. However, this has to be fixed later!!!
|
||||
* Create an operating clock_port to synchronize checkers stimulus generator
|
||||
*/
|
||||
BasicPort op_clock_port(std::string(TOP_TB_OP_CLOCK_PORT_NAME), 1);
|
||||
fp << generate_verilog_port(VERILOG_PORT_WIRE, op_clock_port) << ";" << std::endl;
|
||||
BasicPort op_clock_register_port(std::string(std::string(TOP_TB_OP_CLOCK_PORT_NAME) + std::string(TOP_TB_CLOCK_REG_POSTFIX)), 1);
|
||||
|
@ -969,6 +1002,7 @@ void print_verilog_top_testbench_load_bitstream_task(std::fstream& fp,
|
|||
*******************************************************************/
|
||||
static
|
||||
void print_verilog_top_testbench_generic_stimulus(std::fstream& fp,
|
||||
const SimulationSetting& simulation_parameters,
|
||||
const size_t& num_config_clock_cycles,
|
||||
const float& prog_clock_period,
|
||||
const float& op_clock_period,
|
||||
|
@ -1021,6 +1055,32 @@ void print_verilog_top_testbench_generic_stimulus(std::fstream& fp,
|
|||
|
||||
fp << std::endl;
|
||||
|
||||
/* Generate stimuli waveform for multiple user-defined operating clock signals */
|
||||
for (const SimulationClockId& sim_clock : simulation_parameters.clocks()) {
|
||||
print_verilog_comment(fp, "----- Begin raw operating clock signal '" + simulation_parameters.clock_name(sim_clock) + "' generation -----");
|
||||
std::string sim_clock_port_name = generate_top_testbench_clock_name(std::string(TOP_TB_OP_CLOCK_PORT_PREFIX), simulation_parameters.clock_name(sim_clock));
|
||||
BasicPort sim_clock_port(sim_clock_port_name, 1);
|
||||
BasicPort sim_clock_register_port(std::string(sim_clock_port_name + std::string(TOP_TB_CLOCK_REG_POSTFIX)), 1);
|
||||
|
||||
float sim_clock_period = 1. / simulation_parameters.clock_frequency(sim_clock);
|
||||
print_verilog_clock_stimuli(fp, sim_clock_register_port,
|
||||
0, /* Initial value */
|
||||
0.5 * sim_clock_period / timescale,
|
||||
std::string("~" + reset_port.get_name()));
|
||||
print_verilog_comment(fp, "----- End raw operating clock signal generation -----");
|
||||
|
||||
/* Operation clock should be enabled after programming phase finishes.
|
||||
* Before configuration is done (config_done is enabled), operation clock should be always zero.
|
||||
*/
|
||||
print_verilog_comment(fp, std::string("----- Actual operating clock is triggered only when " + config_done_port.get_name() + " is enabled -----"));
|
||||
fp << "\tassign " << generate_verilog_port(VERILOG_PORT_CONKT, sim_clock_port);
|
||||
fp << " = " << generate_verilog_port(VERILOG_PORT_CONKT, sim_clock_register_port);
|
||||
fp << " & " << generate_verilog_port(VERILOG_PORT_CONKT, config_done_port);
|
||||
fp << ";" << std::endl;
|
||||
|
||||
fp << std::endl;
|
||||
}
|
||||
|
||||
/* Generate stimuli waveform for operating clock signals */
|
||||
print_verilog_comment(fp, "----- Begin raw operating clock signal generation -----");
|
||||
print_verilog_clock_stimuli(fp, op_clock_register_port,
|
||||
|
@ -1834,12 +1894,17 @@ 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,
|
||||
simulation_parameters, config_protocol,
|
||||
circuit_name);
|
||||
|
||||
/* Find the clock period */
|
||||
float prog_clock_period = (1./simulation_parameters.programming_clock_frequency());
|
||||
float op_clock_period = (1./simulation_parameters.default_operating_clock_frequency());
|
||||
float default_op_clock_period = (1./simulation_parameters.default_operating_clock_frequency());
|
||||
float max_op_clock_period = 0.;
|
||||
for (const SimulationClockId& clock_id : simulation_parameters.clocks()) {
|
||||
max_op_clock_period = std::max(max_op_clock_period, (float)(1./simulation_parameters.clock_frequency(clock_id)));
|
||||
}
|
||||
|
||||
/* Estimate the number of configuration clock cycles */
|
||||
size_t num_config_clock_cycles = calculate_num_config_clock_cycles(config_protocol.type(),
|
||||
apply_fast_configuration,
|
||||
|
@ -1849,9 +1914,10 @@ void print_verilog_top_testbench(const ModuleManager& module_manager,
|
|||
|
||||
/* Generate stimuli for general control signals */
|
||||
print_verilog_top_testbench_generic_stimulus(fp,
|
||||
simulation_parameters,
|
||||
num_config_clock_cycles,
|
||||
prog_clock_period,
|
||||
op_clock_period,
|
||||
default_op_clock_period,
|
||||
VERILOG_SIM_TIMESCALE);
|
||||
|
||||
/* Generate stimuli for programming interface */
|
||||
|
@ -1891,6 +1957,7 @@ void print_verilog_top_testbench(const ModuleManager& module_manager,
|
|||
print_verilog_top_testbench_global_ports_stimuli(fp,
|
||||
module_manager, top_module,
|
||||
global_ports,
|
||||
simulation_parameters,
|
||||
active_global_prog_reset,
|
||||
active_global_prog_set);
|
||||
|
||||
|
|
Loading…
Reference in New Issue