Merge pull request #173 from lnis-uofu/dev

Support Multiple Clock Definition in Testbench and SDC Generators
This commit is contained in:
tangxifan 2021-01-15 16:13:46 -07:00 committed by GitHub
commit 4f1d815d7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 432 additions and 74 deletions

View File

@ -49,6 +49,8 @@ Similar to the Switch Boxes and Connection Blocks, the channel wire segments in
- ``circuit_model_name="<string>"`` should match a circuit model whose type is ``chan_wire`` defined in :ref:`circuit_library`.
.. _annotate_vpr_arch_physical_tile_annotation:
Physical Tile Annotation
~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -136,6 +136,8 @@ Pass Gate Logic
.. note:: pass-gate logic are used in building multiplexers and LUTs.
.. _circuit_library_circuit_port:
Circuit Port
^^^^^^^^^^^^

View File

@ -10,7 +10,10 @@ General organization is as follows
<openfpga_simulation_setting>
<clock_setting>
<operating frequency="<int>|<string>" num_cycles="<int>|<string>" slack="<float>"/>
<operating frequency="<int>|<string>" num_cycles="<int>|<string>" slack="<float>">
<clock name="<string>" port="<string>" frequency="<float>"/>
...
</operating>
<programming frequency="<int>"/>
</clock_setting>
<simulator_option>
@ -54,13 +57,17 @@ We should the full syntax in the code block below and then provide details on ea
.. code-block:: xml
<clock_setting>
<operating frequency="<float>|<string>" num_cycles="<int>|<string>" slack="<float>"/>
<operating frequency="<float>|<string>" num_cycles="<int>|<string>" slack="<float>">
<clock name="<string>" port="<string>" frequency="<float>"/>
...
</operating>
<programming frequency="<float>"/>
</clock_setting>
Operating clock setting
^^^^^^^^^^^^^^^^^^^^^^^
Operating clocks are defined under the XML node ``<operating>``
To support FPGA fabrics with multiple clocks, OpenFPGA allows users to define a default operating clock frequency as well as a set of clock ports using different frequencies.
.. option:: <operating frequency="<float>|<string>" num_cycles="<int>|<string>" slack="<float>"/>
@ -70,6 +77,8 @@ Operating clocks are defined under the XML node ``<operating>``
This is very useful to validate the maximum operating frequency for users' implementations
In such case, the value of this attribute should be a reserved word ``auto``.
.. note:: The frequency is considered as a default operating clock frequency, which will be used when a clock pin of a multi-clock FPGA fabric lacks explicit clock definition.
- ``num_cycles="<int>|<string>"``
can be either ``auto`` or an integer. When set to ``auto``, OpenFPGA will infer the number of clock cycles from the average/median of all the signal activities.
When set to an integer, OpenFPGA will use the given number of clock cycles in HDL and SPICE simulations.
@ -86,6 +95,22 @@ Operating clocks are defined under the XML node ``<operating>``
.. warning:: Avoid to use a negative slack! This may cause your simulation to fail!
.. option:: <clock name="<string>" port="<string>" frequency="<float>"/>
- ``name="<string>``
Specify a unique name for a clock signal. The name will be used in generating clock stimulus in testbenches.
- ``port="<string>``
Specify the clock port which the clock signal should be applied to. The clock port must be a valid clock port defined in OpenFPGA architecture description. Explicit index is required, e.g., ``clk[1:1]``. Otherwise, default index ``0`` will be considered, e.g., ``clk`` will be translated as ``clk[0:0]``.
.. note:: You can define clock ports either through the tile annotation in :ref:`annotate_vpr_arch_physical_tile_annotation` or :ref:`circuit_library_circuit_port`.
- ``frequency="<float>``
Specify frequency of a clock signal in the unit of ``[Hz]``
.. warning:: Currently, we only allow operating clocks to be overwritten!!!
Programming clock setting
^^^^^^^^^^^^^^^^^^^^^^^^^
Programming clocks are defined under the XML node ``<programming>``

View File

@ -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"
@ -32,6 +35,33 @@ e_sim_accuracy_type string_to_sim_accuracy_type(const std::string& type_string)
return NUM_SIM_ACCURACY_TYPES;
}
/********************************************************************
* Parse XML codes of a <clock> line to an object of simulation setting
*******************************************************************/
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) {
std::string clock_name = get_attribute(xml_clock_override_setting, "name", loc_data).as_string();
/* 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.));
}
/********************************************************************
* Parse XML codes of a <clock_setting> to an object of simulation setting
*******************************************************************/
@ -42,7 +72,7 @@ void read_xml_clock_setting(pugi::xml_node& xml_clock_setting,
/* Parse operating clock setting */
pugi::xml_node xml_operating_clock_setting = get_single_child(xml_clock_setting, "operating", loc_data);
sim_setting.set_operating_clock_frequency(get_attribute(xml_operating_clock_setting, "frequency", loc_data).as_float(0.));
sim_setting.set_default_operating_clock_frequency(get_attribute(xml_operating_clock_setting, "frequency", loc_data).as_float(0.));
/* Parse number of clock cycles to be used in simulation
* Valid keywords is "auto" or other integer larger than 0
@ -59,6 +89,15 @@ void read_xml_clock_setting(pugi::xml_node& xml_clock_setting,
sim_setting.set_operating_clock_frequency_slack(get_attribute(xml_operating_clock_setting, "slack", loc_data).as_float(0.));
/* Iterate over multiple operating clock settings and parse one by one */
for (pugi::xml_node xml_clock : xml_operating_clock_setting.children()) {
/* Error out if the XML child has an invalid name! */
if (xml_clock.name() != std::string("clock")) {
bad_tag(xml_clock, loc_data, xml_operating_clock_setting, {"clock"});
}
read_xml_operating_clock_override_setting(xml_clock, loc_data, sim_setting);
}
/* Parse programming clock setting */
pugi::xml_node xml_programming_clock_setting = get_single_child(xml_clock_setting, "programming", loc_data);

View File

@ -9,6 +9,13 @@ namespace openfpga {
* Member functions for class SimulationSetting
***********************************************************************/
/************************************************************************
* Public Accessors : aggregates
***********************************************************************/
SimulationSetting::simulation_clock_range SimulationSetting::clocks() const {
return vtr::make_range(clock_ids_.begin(), clock_ids_.end());
}
/************************************************************************
* Constructors
***********************************************************************/
@ -19,12 +26,31 @@ SimulationSetting::SimulationSetting() {
/************************************************************************
* Public Accessors
***********************************************************************/
float SimulationSetting::operating_clock_frequency() const {
return clock_frequencies_.x();
float SimulationSetting::default_operating_clock_frequency() const {
return default_clock_frequencies_.x();
}
float SimulationSetting::programming_clock_frequency() const {
return clock_frequencies_.y();
return default_clock_frequencies_.y();
}
size_t SimulationSetting::num_simulation_clock_cycles() const {
return clock_ids_.size();
}
std::string SimulationSetting::clock_name(const SimulationClockId& clock_id) const {
VTR_ASSERT(valid_clock_id(clock_id));
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];
}
bool SimulationSetting::auto_select_num_clock_cycles() const {
@ -110,12 +136,44 @@ float SimulationSetting::stimuli_input_slew(const e_sim_signal_type& signal_type
/************************************************************************
* Public Mutators
***********************************************************************/
void SimulationSetting::set_operating_clock_frequency(const float& clock_freq) {
clock_frequencies_.set_x(clock_freq);
void SimulationSetting::set_default_operating_clock_frequency(const float& clock_freq) {
default_clock_frequencies_.set_x(clock_freq);
}
void SimulationSetting::set_programming_clock_frequency(const float& clock_freq) {
clock_frequencies_.set_y(clock_freq);
default_clock_frequencies_.set_y(clock_freq);
}
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_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;
}
void SimulationSetting::set_num_clock_cycles(const size_t& num_clk_cycles) {
@ -212,4 +270,9 @@ bool SimulationSetting::valid_signal_threshold(const float& threshold) const {
return (0. < threshold) && (threshold < 1);
}
bool SimulationSetting::valid_clock_id(const SimulationClockId& clock_id) const {
return ( size_t(clock_id) < clock_ids_.size() ) && ( clock_id == clock_ids_[clock_id] );
}
} /* namespace openfpga ends */

View File

@ -7,9 +7,15 @@
*******************************************************************/
#include <string>
#include <array>
#include <map>
#include "vtr_vector.h"
#include "vtr_geometry.h"
#include "openfpga_port.h"
#include "simulation_setting_fwd.h"
/********************************************************************
* Types of signal type in measurement and stimuli
*******************************************************************/
@ -48,11 +54,21 @@ namespace openfpga {
*
*******************************************************************/
class SimulationSetting {
public: /* Types */
typedef vtr::vector<SimulationClockId, SimulationClockId>::const_iterator simulation_clock_iterator;
/* Create range */
typedef vtr::Range<simulation_clock_iterator> simulation_clock_range;
public: /* Constructors */
SimulationSetting();
public: /* Accessors: aggregates */
simulation_clock_range clocks() const;
public: /* Public Accessors */
float operating_clock_frequency() const;
float default_operating_clock_frequency() const;
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;
float operating_clock_frequency_slack() const;
@ -73,8 +89,19 @@ class SimulationSetting {
e_sim_accuracy_type stimuli_input_slew_type(const e_sim_signal_type& signal_type) const;
float stimuli_input_slew(const e_sim_signal_type& signal_type) const;
public: /* Public Mutators */
void set_operating_clock_frequency(const float& clock_freq);
void set_default_operating_clock_frequency(const float& clock_freq);
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_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);
void set_simulation_temperature(const float& sim_temp);
@ -102,13 +129,30 @@ class SimulationSetting {
const float& input_slew);
public: /* Public Validators */
bool valid_signal_threshold(const float& threshold) const;
bool valid_clock_id(const SimulationClockId& clock_id) const;
private: /* Internal data */
/* Operating clock frequency: the clock frequency to be applied to users' implemetation on FPGA
/* Operating clock frequency: the default clock frequency to be applied to users' implemetation on FPGA
* This will be stored in the x() part of vtr::Point
* Programming clock frequency: the clock frequency to be applied to configuration protocol of FPGA
* This will be stored in the y() part of vtr::Point
*/
vtr::Point<float> clock_frequencies_;
vtr::Point<float> default_clock_frequencies_;
/* Multiple simulation clocks with detailed information
* Each clock has
* - a unique id
* - 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

View File

@ -0,0 +1,22 @@
/************************************************************************
* A header file for SimulationSetting class, including critical data declaration
* Please include this file only for using any SimulationSetting data structure
* Refer to simulation_setting.h for more details
***********************************************************************/
/************************************************************************
* Create strong id for Simulation Clock to avoid illegal type casting
***********************************************************************/
#ifndef SIMULATION_SETTING_FWD_H
#define SIMULATION_SETTING_FWD_H
#include "vtr_strong_id.h"
struct simulation_clock_id_tag;
typedef vtr::StrongId<simulation_clock_id_tag> SimulationClockId;
/* Short declaration of class */
class SimulationSetting;
#endif

View File

@ -27,7 +27,7 @@ void write_xml_clock_setting(std::fstream& fp,
fp << "\t" << "<clock_setting>" << "\n";
fp << "\t\t" << "<operating";
write_xml_attribute(fp, "frequency", sim_setting.operating_clock_frequency());
write_xml_attribute(fp, "frequency", sim_setting.default_operating_clock_frequency());
if (true == sim_setting.auto_select_num_clock_cycles()) {
write_xml_attribute(fp, "num_cycles", "auto");
@ -37,8 +37,20 @@ void write_xml_clock_setting(std::fstream& fp,
}
write_xml_attribute(fp, "slack", std::to_string(sim_setting.operating_clock_frequency_slack()).c_str());
fp << ">" << "\n";
fp << "/>" << "\n";
/* Output clock information one by one */
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";
}
fp << "\t\t" << "</operating";
fp << ">" << "\n";
fp << "\t\t" << "<operating";
write_xml_attribute(fp, "frequency", sim_setting.programming_clock_frequency());
@ -219,7 +231,7 @@ void write_xml_simulation_setting(std::fstream& fp,
const openfpga::SimulationSetting& sim_setting) {
/* Validate the file stream */
openfpga::check_file_stream(fname, fp);
/* Write the root node <openfpga_simulation_setting>
*/
fp << "<openfpga_simulation_setting>" << "\n";

View File

@ -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 << "/>";

View File

@ -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;
}

View File

@ -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

View File

@ -191,7 +191,7 @@ int annotate_simulation_setting(const AtomContext& atom_ctx,
SimulationSetting& sim_setting) {
/* Find if the operating frequency is binded to vpr results */
if (0. == sim_setting.operating_clock_frequency()) {
if (0. == sim_setting.default_operating_clock_frequency()) {
VTR_LOG("User specified the operating clock frequency to use VPR results\n");
/* Run timing analysis and collect critical path delay
* This code is copied from function vpr_analysis() in vpr_api.h
@ -212,12 +212,24 @@ int annotate_simulation_setting(const AtomContext& atom_ctx,
/* Get critical path delay. Update simulation settings */
float T_crit = timing_info->least_slack_critical_path().delay() * (1. + sim_setting.operating_clock_frequency_slack());
sim_setting.set_operating_clock_frequency(1 / T_crit);
sim_setting.set_default_operating_clock_frequency(1 / T_crit);
VTR_LOG("Use VPR critical path delay %g [ns] with a %g [%] slack in OpenFPGA.\n",
T_crit / 1e9, sim_setting.operating_clock_frequency_slack() * 100);
}
VTR_LOG("Will apply operating clock frequency %g [MHz] to simulations\n",
sim_setting.operating_clock_frequency() / 1e6);
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

View File

@ -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().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());
}
@ -190,7 +189,7 @@ int write_analysis_sdc(const OpenfpgaContext& openfpga_ctx,
if (true == options.generate_sdc_analysis()) {
print_analysis_sdc(options,
1./openfpga_ctx.simulation_setting().operating_clock_frequency(),
1./openfpga_ctx.simulation_setting().default_operating_clock_frequency(),
g_vpr_ctx,
openfpga_ctx,
openfpga_ctx.flow_manager().compress_routing());

View File

@ -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(),

View File

@ -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);

View File

@ -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 */

View File

@ -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());
}

View File

@ -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 */

View File

@ -226,7 +226,7 @@ void fpga_verilog_testbench(const ModuleManager &module_manager,
bitstream_manager.num_bits(),
simulation_setting.num_clock_cycles(),
simulation_setting.programming_clock_frequency(),
simulation_setting.operating_clock_frequency());
simulation_setting.default_operating_clock_frequency());
}
/* Generate a Verilog file including all the netlists that have been generated */

View File

@ -254,7 +254,7 @@ void print_verilog_random_top_testbench(const std::string& circuit_name,
float simulation_time = find_operating_phase_simulation_time(MAGIC_NUMBER_FOR_SIMULATION_TIME,
simulation_parameters.num_clock_cycles(),
1./simulation_parameters.operating_clock_frequency(),
1./simulation_parameters.default_operating_clock_frequency(),
VERILOG_SIM_TIMESCALE);
/* Add Icarus requirement */

View File

@ -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.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);

View File

@ -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.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);
@ -1968,7 +2035,7 @@ void print_verilog_top_testbench(const ModuleManager& module_manager,
num_config_clock_cycles,
1./simulation_parameters.programming_clock_frequency(),
simulation_parameters.num_clock_cycles(),
1./simulation_parameters.operating_clock_frequency());
1./simulation_parameters.default_operating_clock_frequency());
/* Add Icarus requirement:

View File

@ -0,0 +1,51 @@
<!-- Simulation Setting for OpenFPGA framework
This file will use automatic inference for any settings
including:
- auto select the number of simulation cycles
- auto select the simulation clock frequency from VPR results
-->
<openfpga_simulation_setting>
<clock_setting>
<!-- The frequency defined in the operating line will be
the default operating clock frequency for all the clocks
define specific frequency using <clock> line will overwrite the default value
Note that
- clock name must be unique as it is used in testbench genertion
- the clock port must match clock port definition in OpenFPGA architecture XML!!!
-->
<operating frequency="50e6" num_cycles="20" slack="0.2">
<clock name="clk_10MHz" port="clk[0:0]" frequency="10e6"/>
<clock name="clk_20MHz" port="clk[1:1]" frequency="20e6"/>
<clock name="clk_30MHz" port="clk[2:2]" frequency="30e6"/>
<clock name="clk_40MHz" port="clk[3:3]" frequency="40e6"/>
</operating>
<programming frequency="100e6"/>
</clock_setting>
<simulator_option>
<operating_condition temperature="25"/>
<output_log verbose="false" captab="false"/>
<accuracy type="abs" value="1e-13"/>
<runtime fast_simulation="true"/>
</simulator_option>
<monte_carlo num_simulation_points="2"/>
<measurement_setting>
<slew>
<rise upper_thres_pct="0.95" lower_thres_pct="0.05"/>
<fall upper_thres_pct="0.05" lower_thres_pct="0.95"/>
</slew>
<delay>
<rise input_thres_pct="0.5" output_thres_pct="0.5"/>
<fall input_thres_pct="0.5" output_thres_pct="0.5"/>
</delay>
</measurement_setting>
<stimulus>
<clock>
<rise slew_type="abs" slew_time="20e-12" />
<fall slew_type="abs" slew_time="20e-12" />
</clock>
<input>
<rise slew_type="abs" slew_time="25e-12" />
<fall slew_type="abs" slew_time="25e-12" />
</input>
</stimulus>
</openfpga_simulation_setting>

View File

@ -24,7 +24,7 @@ fpga_flow=vpr_blif
[OpenFPGA_SHELL]
openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/global_tile_clock_example_script.openfpga
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_GlobalTile4Clk_cc_openfpga.xml
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/fixed_4clock_sim_openfpga.xml
[ARCHITECTURES]
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_GlobalTile4Clk_40nm.xml