Merge remote-tracking branch 'origin/master' into github-action-optimizations

This commit is contained in:
Ashton Snelgrove 2021-01-22 10:12:12 -07:00
commit cb80a9bbd4
81 changed files with 3111 additions and 581 deletions

View File

@ -109,6 +109,7 @@ python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/tile_organization/til
echo -e "Testing global port definition from tiles";
python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/global_tile_ports/global_tile_clock --debug --show_thread_logs
python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/global_tile_ports/global_tile_reset --debug --show_thread_logs
python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/global_tile_ports/global_tile_4clock --debug --show_thread_logs
echo -e "Testing yosys flow using custom ys script for running quicklogic device";
python3 openfpga_flow/scripts/run_fpga_task.py quicklogic_tests/flow_test --debug --show_thread_logs

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

@ -0,0 +1,14 @@
File Formats
------------
OpenFPGA widely uses XML format for interchangable files
.. _file_formats:
File formats
.. toctree::
:maxdepth: 2
pin_constraints_file

View File

@ -0,0 +1,25 @@
.. _file_format_pin_constraints_file:
Pin Constraints File
--------------------
The *Pin Constraints File* (PCF) aims to create pin binding between an implementation and an FPGA fabric
An example of design constraints is shown as follows.
.. code-block:: xml
<pin_constraints>
<set_io pin="clk[0]" net="clk0"/>
<set_io pin="clk[1]" net="clk1"/>
<set_io pin="clk[2]" net="OPEN"/>
<set_io pin="clk[3]" net="OPEN"/>
</pin_constraints>
.. option:: pin="<string>"
The pin name of the FPGA fabric to be constrained, which should be a valid pin 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]``.
.. option:: net="<string>"
The net name of the pin to be mapped, which should be consistent with net definition in your ``.blif`` file. The reserved word ``OPEN`` means that no net should be mapped to a given pin. Please ensure that it is not conflicted with any net names in your ``.blif`` file.

View File

@ -12,3 +12,5 @@ FPGA-Bitstream can generate two types of bitstreams:
generic_bitstream
fabric_dependent_bitstream
repack_design_constraints

View File

@ -0,0 +1,29 @@
.. _fpga_bitstream_repack_design_constraints:
Repack Design Constraints
-------------------------
An example of design constraints is shown as follows.
.. code-block:: xml
<repack_design_constraints>
<pin_constraint pb_type="clb" pin="clk[0]" net="clk0"/>
<pin_constraint pb_type="clb" pin="clk[1]" net="clk1"/>
<pin_constraint pb_type="clb" pin="clk[2]" net="OPEN"/>
<pin_constraint pb_type="clb" pin="clk[3]" net="OPEN"/>
</repack_design_constraints>
.. option:: pb_type="<string>"
The pb_type name to be constrained, which should be consistent with VPR's architecture description.
.. option:: pin="<string>"
The pin name of the ``pb_type`` to be constrained, which should be consistent with VPR's architecture description.
.. option:: net="<string>"
The net name of the pin to be mapped, which should be consistent with net definition in your ``.blif`` file. The reserved word ``OPEN`` means that no net should be mapped to a given pin. Please ensure that it is not conflicted with any net names in your ``.blif`` file.
.. warning:: Design constraints is a feature for power-users. It may cause repack to fail. It is users's responsibility to ensure proper design constraints

View File

@ -16,3 +16,5 @@
fpga_bitstream/index
file_formats/index

View File

@ -6,11 +6,28 @@ FPGA-Bitstream
repack
~~~~~~
Repack the netlist to physical pbs
Repack the netlist to physical pbs
Repack is an essential procedure before building a bitstream, which aims to packing each programmable blocks by considering **only** the physical modes.
Repack's functionality are in the following aspects:
.. note:: This must be done before bitstream generator and testbench generation. Strongly recommend it is done after all the fix-up have been applied
- It annotates the net mapping results from operating modes (considered by VPR) to the physical modes (considered by OpenFPGA)
- It re-routes all the nets by considering the programmable interconnects in physical modes **only**.
.. note:: This must be done before bitstream generator and testbench generation. Strongly recommend it is done after all the fix-up have been applied
.. option:: --design_constraints
Apply design constraints from an external file.
Normally, repack takes the net mapping from VPR packing and routing results.
Alternatively, repack can accept the design constraints, in particular, net remapping, from an XML-based design constraint description.
See details in :ref:`fpga_bitstream_repack_design_constraints`.
.. warning:: Design constraints are designed to help repacker to identify which clock net to be mapped to which pin, so that multi-clock benchmarks can be correctly implemented, in the case that VPR may not have sufficient vision on clock net mapping. **Try not to use design constraints to remap any other types of nets!!!**
- ``--verbose`` Show verbose log
.. option:: --verbose
Show verbose log
build_architecture_bitstream
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -33,6 +33,8 @@ write_verilog_testbench
- ``--reference_benchmark_file_path`` Must specify the reference benchmark Verilog file if you want to output any testbenches
- ``--pin_constraints_file`` specify the *Pin Constraints File* (PCF) if you want to custom stimulus in testbenches. Strongly recommend for multi-clock simulations. See detailed file format about :ref:`file_format_pin_constraints_file`.
- ``--fast_configuration`` Enable fast configuration phase for the top-level testbench in order to reduce runtime of simulations. It is applicable to configuration chain, memory bank and frame-based configuration protocols. For configuration chain, when enabled, the zeros at the head of the bitstream will be skipped. For memory bank and frame-based, when enabled, all the zero configuration bits will be skipped. So ensure that your memory cells can be correctly reset to zero with a reset signal.
.. note:: If both reset and set ports are defined in the circuit modeling for programming, OpenFPGA will pick the one that will bring largest benefit in speeding up configuration.

View File

@ -4,4 +4,6 @@ add_subdirectory(libopenfpgashell)
add_subdirectory(libarchopenfpga)
add_subdirectory(libopenfpgautil)
add_subdirectory(libfabrickey)
add_subdirectory(librepackdc)
add_subdirectory(libfpgabitstream)
add_subdirectory(libpcf)

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

@ -0,0 +1,35 @@
cmake_minimum_required(VERSION 3.9)
project("libpcf")
file(GLOB_RECURSE EXEC_SOURCES test/*.cpp)
file(GLOB_RECURSE LIB_SOURCES src/*.cpp)
file(GLOB_RECURSE LIB_HEADERS src/*.h)
files_to_dirs(LIB_HEADERS LIB_INCLUDE_DIRS)
#Remove test executable from library
list(REMOVE_ITEM LIB_SOURCES ${EXEC_SOURCES})
#Create the library
add_library(libpcf STATIC
${LIB_HEADERS}
${LIB_SOURCES})
target_include_directories(libpcf PUBLIC ${LIB_INCLUDE_DIRS})
set_target_properties(libpcf PROPERTIES PREFIX "") #Avoid extra 'lib' prefix
#Specify link-time dependancies
target_link_libraries(libpcf
libopenfpgautil
libarchopenfpga
libvtrutil
libpugixml
libpugiutil)
#Create the test executable
foreach(testsourcefile ${EXEC_SOURCES})
# Use a simple string replace, to cut off .cpp.
get_filename_component(testname ${testsourcefile} NAME_WE)
add_executable(${testname} ${testsourcefile})
# Make sure the library is linked to each test executable
target_link_libraries(${testname} libpcf)
endforeach(testsourcefile ${EXEC_SOURCES})

View File

@ -0,0 +1,9 @@
<pin_constraints>
<!-- For a given .blif file, we want to assign
- the clk0 signal to the clk[0] port of the FPGA fabric
- the clk1 signal to the clk[1] port of the FPGA fabric
-->
<set_io pin="clk[0]" net="clk0"/>
<set_io pin="clk[1]" net="clk1"/>
</pin_constraints>

View File

@ -0,0 +1,72 @@
#include <algorithm>
#include "vtr_assert.h"
#include "vtr_log.h"
#include "pin_constraints.h"
/************************************************************************
* Member functions for class PinConstraints
***********************************************************************/
/************************************************************************
* Constructors
***********************************************************************/
PinConstraints::PinConstraints() {
return;
}
/************************************************************************
* Public Accessors : aggregates
***********************************************************************/
PinConstraints::pin_constraint_range PinConstraints::pin_constraints() const {
return vtr::make_range(pin_constraint_ids_.begin(), pin_constraint_ids_.end());
}
/************************************************************************
* Public Accessors : Basic data query
***********************************************************************/
openfpga::BasicPort PinConstraints::pin(const PinConstraintId& pin_constraint_id) const {
/* validate the pin_constraint_id */
VTR_ASSERT(valid_pin_constraint_id(pin_constraint_id));
return pin_constraint_pins_[pin_constraint_id];
}
std::string PinConstraints::net(const PinConstraintId& pin_constraint_id) const {
/* validate the pin_constraint_id */
VTR_ASSERT(valid_pin_constraint_id(pin_constraint_id));
return pin_constraint_nets_[pin_constraint_id];
}
bool PinConstraints::empty() const {
return 0 == pin_constraint_ids_.size();
}
/************************************************************************
* Public Mutators
***********************************************************************/
void PinConstraints::reserve_pin_constraints(const size_t& num_pin_constraints) {
pin_constraint_ids_.reserve(num_pin_constraints);
pin_constraint_pins_.reserve(num_pin_constraints);
pin_constraint_nets_.reserve(num_pin_constraints);
}
PinConstraintId PinConstraints::create_pin_constraint(const openfpga::BasicPort& pin,
const std::string& net) {
/* Create a new id */
PinConstraintId pin_constraint_id = PinConstraintId(pin_constraint_ids_.size());
pin_constraint_ids_.push_back(pin_constraint_id);
pin_constraint_pins_.push_back(pin);
pin_constraint_nets_.push_back(net);
return pin_constraint_id;
}
/************************************************************************
* Internal invalidators/validators
***********************************************************************/
/* Validators */
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] );
}

View File

@ -0,0 +1,80 @@
#ifndef PIN_CONSTRAINTS_H
#define PIN_CONSTRAINTS_H
/********************************************************************
* This file include the declaration of pin constraints
*******************************************************************/
#include <string>
#include <map>
#include <array>
/* Headers from vtrutil library */
#include "vtr_vector.h"
#include "vtr_geometry.h"
/* Headers from openfpgautil library */
#include "openfpga_port.h"
#include "pin_constraints_fwd.h"
/* Constants */
constexpr char* PIN_CONSTRAINT_OPEN_NET = "OPEN";
/********************************************************************
* A data structure to describe the pin constraints for FPGA fabrics
* This data structure may include a number of pin constraints
* each of which may constrain:
* - pin assignment, for instance, force a net to be mapped to specific pin
*
* Typical usage:
* --------------
* // Create an object of pin constraints
* PinConstraints pin_constraints;
* // Add a pin assignment
* openfpga::BasicPort pin_info(clk, 1);
* std::string net_info("top_clock");
* PinConstraintId pin_constraint_id = pin_constraints.create_pin_constraint(pin_info, net_info);
*
*******************************************************************/
class PinConstraints {
public: /* Types */
typedef vtr::vector<PinConstraintId, PinConstraintId>::const_iterator pin_constraint_iterator;
/* Create range */
typedef vtr::Range<pin_constraint_iterator> pin_constraint_range;
public: /* Constructors */
PinConstraints();
public: /* Accessors: aggregates */
pin_constraint_range pin_constraints() const;
public: /* Public Accessors: Basic data query */
/* Get the pin to be constrained */
openfpga::BasicPort pin(const PinConstraintId& pin_constraint_id) const;
/* Get the net to be constrained */
std::string net(const PinConstraintId& pin_constraint_id) 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);
/* Add a pin constraint to storage */
PinConstraintId create_pin_constraint(const openfpga::BasicPort& pin,
const std::string& net);
public: /* Public invalidators/validators */
bool valid_pin_constraint_id(const PinConstraintId& pin_constraint_id) const;
private: /* Internal data */
/* Unique ids for each design constraint */
vtr::vector<PinConstraintId, PinConstraintId> pin_constraint_ids_;
/* Pins to constraint */
vtr::vector<PinConstraintId, openfpga::BasicPort> pin_constraint_pins_;
/* Nets to constraint */
vtr::vector<PinConstraintId, std::string> pin_constraint_nets_;
};
#endif

View File

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

View File

@ -0,0 +1,82 @@
/********************************************************************
* This file includes the top-level function of this library
* which reads an XML of pin constraints to the associated
* data structures
*******************************************************************/
#include <string>
/* Headers from pugi XML library */
#include "pugixml.hpp"
#include "pugixml_util.hpp"
/* Headers from vtr util library */
#include "vtr_assert.h"
#include "vtr_time.h"
/* Headers from libopenfpga util library */
#include "openfpga_port_parser.h"
/* Headers from libarchfpga */
#include "arch_error.h"
#include "read_xml_util.h"
#include "read_xml_pin_constraints.h"
/********************************************************************
* Parse XML codes of a <set_io> to an object of PinConstraint
*******************************************************************/
static
void read_xml_pin_constraint(pugi::xml_node& xml_pin_constraint,
const pugiutil::loc_data& loc_data,
PinConstraints& pin_constraints) {
openfpga::PortParser port_parser(get_attribute(xml_pin_constraint, "pin", loc_data).as_string());
std::string net_name = get_attribute(xml_pin_constraint, "net", loc_data).as_string();
/* Create a new pin constraint in the storage */
PinConstraintId pin_constraint_id = pin_constraints.create_pin_constraint(port_parser.port(), net_name);
if (false == pin_constraints.valid_pin_constraint_id(pin_constraint_id)) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_pin_constraint),
"Fail to create pin constraint!\n");
}
}
/********************************************************************
* Parse XML codes about <pin_constraints> to an object of PinConstraints
*******************************************************************/
PinConstraints read_xml_pin_constraints(const char* pin_constraint_fname) {
vtr::ScopedStartFinishTimer timer("Read Pin Constraints");
PinConstraints pin_constraints;
/* Parse the file */
pugi::xml_document doc;
pugiutil::loc_data loc_data;
try {
loc_data = pugiutil::load_xml(doc, pin_constraint_fname);
pugi::xml_node xml_root = get_single_child(doc, "pin_constraints", loc_data);
size_t num_pin_constraints = std::distance(xml_root.children().begin(), xml_root.children().end());
/* Reserve memory space for the region */
pin_constraints.reserve_pin_constraints(num_pin_constraints);
for (pugi::xml_node xml_pin_constraint : xml_root.children()) {
/* Error out if the XML child has an invalid name! */
if (xml_pin_constraint.name() != std::string("set_io")) {
bad_tag(xml_pin_constraint, loc_data, xml_root, {"set_io"});
}
read_xml_pin_constraint(xml_pin_constraint, loc_data, pin_constraints);
}
} catch (pugiutil::XmlError& e) {
archfpga_throw(pin_constraint_fname, e.line(),
"%s", e.what());
}
return pin_constraints;
}

View File

@ -0,0 +1,16 @@
#ifndef READ_XML_PIN_CONSTRAINTS_H
#define READ_XML_PIN_CONSTRAINTS_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include "pugixml_util.hpp"
#include "pugixml.hpp"
#include "pin_constraints.h"
/********************************************************************
* Function declaration
*******************************************************************/
PinConstraints read_xml_pin_constraints(const char* pin_constraint_fname);
#endif

View File

@ -0,0 +1,94 @@
/********************************************************************
* This file includes functions that outputs a pin constraint object to XML format
*******************************************************************/
/* Headers from system goes first */
#include <string>
#include <algorithm>
/* Headers from vtr util library */
#include "vtr_assert.h"
#include "vtr_log.h"
#include "vtr_time.h"
/* Headers from openfpga util library */
#include "openfpga_digest.h"
/* Headers from arch openfpga library */
#include "write_xml_utils.h"
/* Headers from pin constraint library */
#include "write_xml_pin_constraints.h"
/********************************************************************
* A writer to output a pin constraint to XML format
*
* Return 0 if successful
* Return 1 if there are more serious bugs in the architecture
* Return 2 if fail when creating files
*******************************************************************/
static
int write_xml_pin_constraint(std::fstream& fp,
const PinConstraints& pin_constraints,
const PinConstraintId& pin_constraint) {
/* Validate the file stream */
if (false == openfpga::valid_file_stream(fp)) {
return 2;
}
openfpga::write_tab_to_file(fp, 1);
fp << "<set_io";
if (false == pin_constraints.valid_pin_constraint_id(pin_constraint)) {
return 1;
}
write_xml_attribute(fp, "pin", generate_xml_port_name(pin_constraints.pin(pin_constraint)).c_str());
write_xml_attribute(fp, "net", pin_constraints.net(pin_constraint).c_str());
fp << "/>" << "\n";
return 0;
}
/********************************************************************
* A writer to output a repack pin constraint object to XML format
*
* Return 0 if successful
* Return 1 if there are more serious bugs in the architecture
* Return 2 if fail when creating files
*******************************************************************/
int write_xml_pin_constraints(const char* fname,
const PinConstraints& pin_constraints) {
vtr::ScopedStartFinishTimer timer("Write Pin Constraints");
/* Create a file handler */
std::fstream fp;
/* Open the file stream */
fp.open(std::string(fname), std::fstream::out | std::fstream::trunc);
/* Validate the file stream */
openfpga::check_file_stream(fname, fp);
/* Write the root node */
fp << "<pin_constraints>" << "\n";
int err_code = 0;
/* Write region by region */
for (const PinConstraintId& pin_constraint : pin_constraints.pin_constraints()) {
/* Write constraint by constraint */
err_code = write_xml_pin_constraint(fp, pin_constraints, pin_constraint);
if (0 != err_code) {
return err_code;
}
}
/* Finish writing the root node */
fp << "</pin_constraints>" << "\n";
/* Close the file stream */
fp.close();
return err_code;
}

View File

@ -0,0 +1,16 @@
#ifndef WRITE_XML_PIN_CONSTRAINTS_H
#define WRITE_XML_PIN_CONSTRAINTS_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include <fstream>
#include "pin_constraints.h"
/********************************************************************
* Function declaration
*******************************************************************/
int write_xml_pin_constraints(const char* fname,
const PinConstraints& pin_constraints);
#endif

View File

@ -0,0 +1,33 @@
/********************************************************************
* Unit test functions to validate the correctness of
* 1. parser of data structures
* 2. writer of data structures
*******************************************************************/
/* Headers from vtrutils */
#include "vtr_assert.h"
#include "vtr_log.h"
/* Headers from fabric key */
#include "read_xml_pin_constraints.h"
#include "write_xml_pin_constraints.h"
int main(int argc, const char** argv) {
/* Ensure we have only one or two argument */
VTR_ASSERT((2 == argc) || (3 == argc));
/* Parse the fabric key from an XML file */
PinConstraints pin_constraints = read_xml_pin_constraints(argv[1]);
VTR_LOG("Read the pin constraints from an XML file: %s.\n",
argv[1]);
/* Output pin constraints to an XML file
* This is optional only used when there is a second argument
*/
if (3 <= argc) {
write_xml_pin_constraints(argv[2], pin_constraints);
VTR_LOG("Echo the pin constraints to an XML file: %s.\n",
argv[2]);
}
}

View File

@ -0,0 +1,35 @@
cmake_minimum_required(VERSION 3.9)
project("librepackdc")
file(GLOB_RECURSE EXEC_SOURCES test/*.cpp)
file(GLOB_RECURSE LIB_SOURCES src/*.cpp)
file(GLOB_RECURSE LIB_HEADERS src/*.h)
files_to_dirs(LIB_HEADERS LIB_INCLUDE_DIRS)
#Remove test executable from library
list(REMOVE_ITEM LIB_SOURCES ${EXEC_SOURCES})
#Create the library
add_library(librepackdc STATIC
${LIB_HEADERS}
${LIB_SOURCES})
target_include_directories(librepackdc PUBLIC ${LIB_INCLUDE_DIRS})
set_target_properties(librepackdc PROPERTIES PREFIX "") #Avoid extra 'lib' prefix
#Specify link-time dependancies
target_link_libraries(librepackdc
libopenfpgautil
libarchopenfpga
libvtrutil
libpugixml
libpugiutil)
#Create the test executable
foreach(testsourcefile ${EXEC_SOURCES})
# Use a simple string replace, to cut off .cpp.
get_filename_component(testname ${testsourcefile} NAME_WE)
add_executable(${testname} ${testsourcefile})
# Make sure the library is linked to each test executable
target_link_libraries(${testname} librepackdc)
endforeach(testsourcefile ${EXEC_SOURCES})

View File

@ -0,0 +1,7 @@
<repack_design_constraints>
<pin_constraint pb_type="clb" pin="clk[0]" net="clk0"/>
<pin_constraint pb_type="clb" pin="clk[1]" net="clk1"/>
<pin_constraint pb_type="clb" pin="clk[2]" net="OPEN"/>
<pin_constraint pb_type="clb" pin="clk[3]" net="OPEN"/>
</repack_design_constraints>

View File

@ -0,0 +1,89 @@
/********************************************************************
* This file includes the top-level function of this library
* which reads an XML of a fabric key to the associated
* data structures
*******************************************************************/
#include <string>
/* Headers from pugi XML library */
#include "pugixml.hpp"
#include "pugixml_util.hpp"
/* Headers from vtr util library */
#include "vtr_assert.h"
#include "vtr_time.h"
/* Headers from libopenfpga util library */
#include "openfpga_port_parser.h"
/* Headers from libarchfpga */
#include "arch_error.h"
#include "read_xml_util.h"
#include "read_xml_repack_design_constraints.h"
/********************************************************************
* Parse XML codes of a <key> to an object of FabricKey
*******************************************************************/
static
void read_xml_pin_constraint(pugi::xml_node& xml_pin_constraint,
const pugiutil::loc_data& loc_data,
RepackDesignConstraints& repack_design_constraints) {
/* Create a new design constraint in the storage */
RepackDesignConstraintId design_constraint_id = repack_design_constraints.create_design_constraint(RepackDesignConstraints::PIN_ASSIGNMENT);
if (false == repack_design_constraints.valid_design_constraint_id(design_constraint_id)) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_pin_constraint),
"Fail to create design constraint!\n");
}
repack_design_constraints.set_pb_type(design_constraint_id,
get_attribute(xml_pin_constraint, "pb_type", loc_data).as_string());
openfpga::PortParser port_parser(get_attribute(xml_pin_constraint, "pin", loc_data).as_string());
repack_design_constraints.set_pin(design_constraint_id,
port_parser.port());
repack_design_constraints.set_net(design_constraint_id,
get_attribute(xml_pin_constraint, "net", loc_data).as_string());
}
/********************************************************************
* Parse XML codes about <repack_design_constraints> to an object of RepackDesignConstraints
*******************************************************************/
RepackDesignConstraints read_xml_repack_design_constraints(const char* design_constraint_fname) {
vtr::ScopedStartFinishTimer timer("Read Repack Design Constraints");
RepackDesignConstraints repack_design_constraints;
/* Parse the file */
pugi::xml_document doc;
pugiutil::loc_data loc_data;
try {
loc_data = pugiutil::load_xml(doc, design_constraint_fname);
pugi::xml_node xml_root = get_single_child(doc, "repack_design_constraints", loc_data);
size_t num_design_constraints = std::distance(xml_root.children().begin(), xml_root.children().end());
/* Reserve memory space for the region */
repack_design_constraints.reserve_design_constraints(num_design_constraints);
for (pugi::xml_node xml_design_constraint : xml_root.children()) {
/* Error out if the XML child has an invalid name! */
if (xml_design_constraint.name() != std::string("pin_constraint")) {
bad_tag(xml_design_constraint, loc_data, xml_root, {"pin_constraint"});
}
read_xml_pin_constraint(xml_design_constraint, loc_data, repack_design_constraints);
}
} catch (pugiutil::XmlError& e) {
archfpga_throw(design_constraint_fname, e.line(),
"%s", e.what());
}
return repack_design_constraints;
}

View File

@ -0,0 +1,16 @@
#ifndef READ_XML_REPACK_DESIGN_CONSTRAINTS_H
#define READ_XML_REPACK_DESIGN_CONSTRAINTS_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include "pugixml_util.hpp"
#include "pugixml.hpp"
#include "repack_design_constraints.h"
/********************************************************************
* Function declaration
*******************************************************************/
RepackDesignConstraints read_xml_repack_design_constraints(const char* design_constraint_fname);
#endif

View File

@ -0,0 +1,108 @@
#include <algorithm>
#include "vtr_assert.h"
#include "vtr_log.h"
#include "repack_design_constraints.h"
/************************************************************************
* Member functions for class RepackDesignConstraints
***********************************************************************/
/************************************************************************
* Constructors
***********************************************************************/
RepackDesignConstraints::RepackDesignConstraints() {
return;
}
/************************************************************************
* Public Accessors : aggregates
***********************************************************************/
RepackDesignConstraints::repack_design_constraint_range RepackDesignConstraints::design_constraints() const {
return vtr::make_range(repack_design_constraint_ids_.begin(), repack_design_constraint_ids_.end());
}
/************************************************************************
* Public Accessors : Basic data query
***********************************************************************/
RepackDesignConstraints::e_design_constraint_type RepackDesignConstraints::type(const RepackDesignConstraintId& repack_design_constraint_id) const {
/* validate the design_constraint_id */
VTR_ASSERT(valid_design_constraint_id(repack_design_constraint_id));
return repack_design_constraint_types_[repack_design_constraint_id];
}
std::string RepackDesignConstraints::pb_type(const RepackDesignConstraintId& repack_design_constraint_id) const {
/* validate the design_constraint_id */
VTR_ASSERT(valid_design_constraint_id(repack_design_constraint_id));
return repack_design_constraint_pb_types_[repack_design_constraint_id];
}
openfpga::BasicPort RepackDesignConstraints::pin(const RepackDesignConstraintId& repack_design_constraint_id) const {
/* validate the design_constraint_id */
VTR_ASSERT(valid_design_constraint_id(repack_design_constraint_id));
return repack_design_constraint_pins_[repack_design_constraint_id];
}
std::string RepackDesignConstraints::net(const RepackDesignConstraintId& repack_design_constraint_id) const {
/* validate the design_constraint_id */
VTR_ASSERT(valid_design_constraint_id(repack_design_constraint_id));
return repack_design_constraint_nets_[repack_design_constraint_id];
}
bool RepackDesignConstraints::empty() const {
return 0 == repack_design_constraint_ids_.size();
}
/************************************************************************
* Public Mutators
***********************************************************************/
void RepackDesignConstraints::reserve_design_constraints(const size_t& num_design_constraints) {
repack_design_constraint_ids_.reserve(num_design_constraints);
repack_design_constraint_types_.reserve(num_design_constraints);
repack_design_constraint_pb_types_.reserve(num_design_constraints);
repack_design_constraint_pins_.reserve(num_design_constraints);
repack_design_constraint_nets_.reserve(num_design_constraints);
}
RepackDesignConstraintId RepackDesignConstraints::create_design_constraint(const RepackDesignConstraints::e_design_constraint_type& repack_design_constraint_type) {
/* Create a new id */
RepackDesignConstraintId repack_design_constraint_id = RepackDesignConstraintId(repack_design_constraint_ids_.size());
repack_design_constraint_ids_.push_back(repack_design_constraint_id);
repack_design_constraint_types_.push_back(repack_design_constraint_type);
repack_design_constraint_pb_types_.emplace_back();
repack_design_constraint_pins_.emplace_back();
repack_design_constraint_nets_.emplace_back();
return repack_design_constraint_id;
}
void RepackDesignConstraints::set_pb_type(const RepackDesignConstraintId& repack_design_constraint_id,
const std::string& pb_type) {
/* validate the design_constraint_id */
VTR_ASSERT(valid_design_constraint_id(repack_design_constraint_id));
repack_design_constraint_pb_types_[repack_design_constraint_id] = pb_type;
}
void RepackDesignConstraints::set_pin(const RepackDesignConstraintId& repack_design_constraint_id,
const openfpga::BasicPort& pin) {
/* validate the design_constraint_id */
VTR_ASSERT(valid_design_constraint_id(repack_design_constraint_id));
repack_design_constraint_pins_[repack_design_constraint_id] = pin;
}
void RepackDesignConstraints::set_net(const RepackDesignConstraintId& repack_design_constraint_id,
const std::string& net) {
/* validate the design_constraint_id */
VTR_ASSERT(valid_design_constraint_id(repack_design_constraint_id));
repack_design_constraint_nets_[repack_design_constraint_id] = net;
}
/************************************************************************
* Internal invalidators/validators
***********************************************************************/
/* Validators */
bool RepackDesignConstraints::valid_design_constraint_id(const RepackDesignConstraintId& design_constraint_id) const {
return ( size_t(design_constraint_id) < repack_design_constraint_ids_.size() ) && ( design_constraint_id == repack_design_constraint_ids_[design_constraint_id] );
}

View File

@ -0,0 +1,106 @@
#ifndef REPACK_DESIGN_CONSTRAINTS_H
#define REPACK_DESIGN_CONSTRAINTS_H
/********************************************************************
* This file include the declaration of repack design constraints
*******************************************************************/
#include <string>
#include <map>
#include <array>
/* Headers from vtrutil library */
#include "vtr_vector.h"
#include "vtr_geometry.h"
/* Headers from openfpgautil library */
#include "openfpga_port.h"
#include "repack_design_constraints_fwd.h"
/* Constants */
constexpr char* REPACK_DESIGN_CONSTRAINT_OPEN_NET = "OPEN";
/********************************************************************
* A data structure to describe the design constraints for repacking tools
* This data structure may include a number of design constraints
* each of which may constrain:
* - pin assignment, for instance, force a net to be mapped to specific pin
*
* Typical usage:
* --------------
* // Create an object of design constraints
* RepackDesignConstraints repack_design_constraints;
* // Add a pin assignment
* RepackDesignConstraintId repack_dc_id = fabric_key.create_design_constraint(RepackDesignConstraints::PIN_ASSIGNMENT);
*
*******************************************************************/
class RepackDesignConstraints {
public: /* Type of design constraints */
enum e_design_constraint_type {
PIN_ASSIGNMENT,
NUM_DESIGN_CONSTRAINT_TYPES
};
public: /* Types */
typedef vtr::vector<RepackDesignConstraintId, RepackDesignConstraintId>::const_iterator repack_design_constraint_iterator;
/* Create range */
typedef vtr::Range<repack_design_constraint_iterator> repack_design_constraint_range;
public: /* Constructors */
RepackDesignConstraints();
public: /* Accessors: aggregates */
repack_design_constraint_range design_constraints() const;
public: /* Public Accessors: Basic data query */
/* Get the type of constraint */
e_design_constraint_type type(const RepackDesignConstraintId& repack_design_constraint_id) const;
/* Get the pb_type name to be constrained */
std::string pb_type(const RepackDesignConstraintId& repack_design_constraint_id) const;
/* Get the pin to be constrained */
openfpga::BasicPort pin(const RepackDesignConstraintId& repack_design_constraint_id) const;
/* Get the net to be constrained */
std::string net(const RepackDesignConstraintId& repack_design_constraint_id) const;
/* Check if there are any design constraints */
bool empty() const;
public: /* Public Mutators */
/* Reserve a number of design constraints to be memory efficent */
void reserve_design_constraints(const size_t& num_design_constraints);
/* Add a design constraint to storage */
RepackDesignConstraintId create_design_constraint(const e_design_constraint_type& repack_design_constraint_type);
/* Set the pb_type name to be constrained */
void set_pb_type(const RepackDesignConstraintId& repack_design_constraint_id,
const std::string& pb_type);
/* Set the pin to be constrained */
void set_pin(const RepackDesignConstraintId& repack_design_constraint_id,
const openfpga::BasicPort& pin);
/* Set the net to be constrained */
void set_net(const RepackDesignConstraintId& repack_design_constraint_id,
const std::string& net);
public: /* Public invalidators/validators */
bool valid_design_constraint_id(const RepackDesignConstraintId& repack_design_constraint_id) const;
private: /* Internal data */
/* Unique ids for each design constraint */
vtr::vector<RepackDesignConstraintId, RepackDesignConstraintId> repack_design_constraint_ids_;
/* Type for each design constraint */
vtr::vector<RepackDesignConstraintId, e_design_constraint_type> repack_design_constraint_types_;
/* Tiles to constraint */
vtr::vector<RepackDesignConstraintId, std::string> repack_design_constraint_pb_types_;
/* Pins to constraint */
vtr::vector<RepackDesignConstraintId, openfpga::BasicPort> repack_design_constraint_pins_;
/* Nets to constraint */
vtr::vector<RepackDesignConstraintId, std::string> repack_design_constraint_nets_;
};
#endif

View File

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

View File

@ -0,0 +1,97 @@
/********************************************************************
* This file includes functions that outputs a repack design constraint object to XML format
*******************************************************************/
/* Headers from system goes first */
#include <string>
#include <algorithm>
/* Headers from vtr util library */
#include "vtr_assert.h"
#include "vtr_log.h"
#include "vtr_time.h"
/* Headers from openfpga util library */
#include "openfpga_digest.h"
/* Headers from arch openfpga library */
#include "write_xml_utils.h"
/* Headers from fabrickey library */
#include "write_xml_repack_design_constraints.h"
/********************************************************************
* A writer to output a pin constraint to XML format
*
* Return 0 if successful
* Return 1 if there are more serious bugs in the architecture
* Return 2 if fail when creating files
*******************************************************************/
static
int write_xml_pin_constraint(std::fstream& fp,
const RepackDesignConstraints& repack_design_constraints,
const RepackDesignConstraintId& design_constraint) {
/* Validate the file stream */
if (false == openfpga::valid_file_stream(fp)) {
return 2;
}
openfpga::write_tab_to_file(fp, 1);
fp << "<pin_constraint";
if (false == repack_design_constraints.valid_design_constraint_id(design_constraint)) {
return 1;
}
write_xml_attribute(fp, "pb_type", repack_design_constraints.pb_type(design_constraint).c_str());
write_xml_attribute(fp, "pin", generate_xml_port_name(repack_design_constraints.pin(design_constraint)).c_str());
write_xml_attribute(fp, "net", repack_design_constraints.net(design_constraint).c_str());
fp << "/>" << "\n";
return 0;
}
/********************************************************************
* A writer to output a repack design constraint object to XML format
*
* Return 0 if successful
* Return 1 if there are more serious bugs in the architecture
* Return 2 if fail when creating files
*******************************************************************/
int write_xml_repack_design_constraints(const char* fname,
const RepackDesignConstraints& repack_design_constraints) {
vtr::ScopedStartFinishTimer timer("Write Repack Design Constraints");
/* Create a file handler */
std::fstream fp;
/* Open the file stream */
fp.open(std::string(fname), std::fstream::out | std::fstream::trunc);
/* Validate the file stream */
openfpga::check_file_stream(fname, fp);
/* Write the root node */
fp << "<repack_design_constraints>" << "\n";
int err_code = 0;
/* Write region by region */
for (const RepackDesignConstraintId& design_constraint : repack_design_constraints.design_constraints()) {
/* Write constraint by constraint */
if (RepackDesignConstraints::PIN_ASSIGNMENT == repack_design_constraints.type(design_constraint)) {
err_code = write_xml_pin_constraint(fp, repack_design_constraints, design_constraint);
if (0 != err_code) {
return err_code;
}
}
}
/* Finish writing the root node */
fp << "</repack_design_constraints>" << "\n";
/* Close the file stream */
fp.close();
return err_code;
}

View File

@ -0,0 +1,16 @@
#ifndef WRITE_XML_REPACK_DESIGN_CONSTRAINTS_H
#define WRITE_XML_REPACK_DESIGN_CONSTRAINTS_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include <fstream>
#include "repack_design_constraints.h"
/********************************************************************
* Function declaration
*******************************************************************/
int write_xml_repack_design_constraints(const char* fname,
const RepackDesignConstraints& repack_design_constraints);
#endif

View File

@ -0,0 +1,34 @@
/********************************************************************
* Unit test functions to validate the correctness of
* 1. parser of data structures
* 2. writer of data structures
*******************************************************************/
/* Headers from vtrutils */
#include "vtr_assert.h"
#include "vtr_log.h"
/* Headers from fabric key */
#include "read_xml_repack_design_constraints.h"
#include "write_xml_repack_design_constraints.h"
int main(int argc, const char** argv) {
/* Ensure we have only one or two argument */
VTR_ASSERT((2 == argc) || (3 == argc));
/* Parse the fabric key from an XML file */
RepackDesignConstraints design_constraints = read_xml_repack_design_constraints(argv[1]);
VTR_LOG("Read the repack design constraints from an XML file: %s.\n",
argv[1]);
/* Output the circuit library to an XML file
* This is optional only used when there is a second argument
*/
if (3 <= argc) {
write_xml_repack_design_constraints(argv[2], design_constraints);
VTR_LOG("Echo the repack design constraints to an XML file: %s.\n",
argv[2]);
}
}

View File

@ -23,8 +23,10 @@ target_link_libraries(libopenfpga
libopenfpgashell
libopenfpgautil
libfabrickey
librepackdc
libfpgabitstream
libini
libpcf
libvtrutil
libvpr)

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

@ -21,6 +21,9 @@ ShellCommandId add_openfpga_repack_command(openfpga::Shell<OpenfpgaContext>& she
const ShellCommandClassId& cmd_class_id,
const std::vector<ShellCommandId>& dependent_cmds) {
Command shell_cmd("repack");
/* Add an option '--design_constraints' */
CommandOptionId opt_design_constraints = shell_cmd.add_option("design_constraints", false, "file path to the design constraints");
shell_cmd.set_option_require_value(opt_design_constraints, openfpga::OPT_STRING);
/* Add an option '--verbose' */
shell_cmd.add_option("verbose", false, "Enable verbose output");

View File

@ -8,10 +8,15 @@
/* Headers from openfpgashell library */
#include "command_exit_codes.h"
/* Headers from librepackdc library */
#include "repack_design_constraints.h"
#include "read_xml_repack_design_constraints.h"
#include "build_physical_truth_table.h"
#include "repack.h"
#include "openfpga_repack.h"
/* Include global variables of VPR */
#include "globals.h"
@ -24,13 +29,23 @@ namespace openfpga {
int repack(OpenfpgaContext& openfpga_ctx,
const Command& cmd, const CommandContext& cmd_context) {
CommandOptionId opt_design_constraints = cmd.option("design_constraints");
CommandOptionId opt_verbose = cmd.option("verbose");
/* Load design constraints from file */
RepackDesignConstraints repack_design_constraints;
if (true == cmd_context.option_enable(cmd, opt_design_constraints)) {
std::string dc_fname = cmd_context.option_value(cmd, opt_design_constraints);
VTR_ASSERT(false == dc_fname.empty());
repack_design_constraints = read_xml_repack_design_constraints(dc_fname.c_str());
}
pack_physical_pbs(g_vpr_ctx.device(),
g_vpr_ctx.atom(),
g_vpr_ctx.clustering(),
openfpga_ctx.mutable_vpr_device_annotation(),
openfpga_ctx.mutable_vpr_clustering_annotation(),
repack_design_constraints,
cmd_context.option_enable(cmd, opt_verbose));
build_physical_lut_truth_tables(openfpga_ctx.mutable_vpr_clustering_annotation(),

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

@ -11,6 +11,9 @@
#include "verilog_api.h"
#include "openfpga_verilog.h"
/* Headers from pcf library */
#include "read_xml_pin_constraints.h"
/* Include global variables of VPR */
#include "globals.h"
@ -62,6 +65,7 @@ int write_verilog_testbench(OpenfpgaContext& openfpga_ctx,
CommandOptionId opt_output_dir = cmd.option("file");
CommandOptionId opt_fabric_netlist = cmd.option("fabric_netlist_file_path");
CommandOptionId opt_pcf = cmd.option("pin_constraints_file");
CommandOptionId opt_reference_benchmark = cmd.option("reference_benchmark_file_path");
CommandOptionId opt_print_top_testbench = cmd.option("print_top_testbench");
CommandOptionId opt_fast_configuration = cmd.option("fast_configuration");
@ -89,22 +93,26 @@ int write_verilog_testbench(OpenfpgaContext& openfpga_ctx,
options.set_include_signal_init(cmd_context.option_enable(cmd, opt_include_signal_init));
options.set_support_icarus_simulator(cmd_context.option_enable(cmd, opt_support_icarus_simulator));
options.set_verbose_output(cmd_context.option_enable(cmd, opt_verbose));
fpga_verilog_testbench(openfpga_ctx.module_graph(),
openfpga_ctx.bitstream_manager(),
openfpga_ctx.fabric_bitstream(),
g_vpr_ctx.atom(),
g_vpr_ctx.placement(),
openfpga_ctx.io_location_map(),
openfpga_ctx.fabric_global_port_info(),
openfpga_ctx.vpr_netlist_annotation(),
openfpga_ctx.arch().circuit_lib,
openfpga_ctx.simulation_setting(),
openfpga_ctx.arch().config_protocol,
options);
/* TODO: should identify the error code from internal function execution */
return CMD_EXEC_SUCCESS;
/* If pin constraints are enabled by command options, read the file */
PinConstraints pin_constraints;
if (true == cmd_context.option_enable(cmd, opt_pcf)) {
pin_constraints = read_xml_pin_constraints(cmd_context.option_value(cmd, opt_pcf).c_str());
}
return fpga_verilog_testbench(openfpga_ctx.module_graph(),
openfpga_ctx.bitstream_manager(),
openfpga_ctx.fabric_bitstream(),
g_vpr_ctx.atom(),
g_vpr_ctx.placement(),
pin_constraints,
openfpga_ctx.io_location_map(),
openfpga_ctx.fabric_global_port_info(),
openfpga_ctx.vpr_netlist_annotation(),
openfpga_ctx.arch().circuit_lib,
openfpga_ctx.simulation_setting(),
openfpga_ctx.arch().config_protocol,
options);
}
} /* end namespace openfpga */

View File

@ -70,6 +70,11 @@ ShellCommandId add_openfpga_write_verilog_testbench_command(openfpga::Shell<Open
CommandOptionId fabric_netlist_opt = shell_cmd.add_option("fabric_netlist_file_path", false, "Specify the file path to the fabric Verilog netlist");
shell_cmd.set_option_require_value(fabric_netlist_opt, openfpga::OPT_STRING);
/* Add an option '--pin_constraints_file in short '-pcf' */
CommandOptionId pcf_opt = shell_cmd.add_option("pin_constraints_file", false, "Specify the file path to the pin constraints");
shell_cmd.set_option_short_name(pcf_opt, "pcf");
shell_cmd.set_option_require_value(pcf_opt, openfpga::OPT_STRING);
/* Add an option '--reference_benchmark_file_path'*/
CommandOptionId ref_bm_opt = shell_cmd.add_option("reference_benchmark_file_path", true, "Specify the file path to the reference Verilog netlist");
shell_cmd.set_option_require_value(ref_bm_opt, openfpga::OPT_STRING);

View File

@ -710,6 +710,7 @@ int build_top_module_global_net_for_given_grid_module(ModuleManager& module_mana
/* Find the port of the grid module according to the tile annotation */
int grid_pin_start_index = physical_tile->num_pins;
t_physical_tile_port physical_tile_port;
for (const t_physical_tile_port& tile_port : physical_tile->ports) {
if (std::string(tile_port.name) == tile_port_to_connect.get_name()) {
BasicPort ref_tile_port(tile_port.name, tile_port.num_pins);
@ -726,6 +727,7 @@ int build_top_module_global_net_for_given_grid_module(ModuleManager& module_mana
return CMD_EXEC_FATAL_ERROR;
}
grid_pin_start_index = tile_port.absolute_first_pin_index;
physical_tile_port = tile_port;
break;
}
}
@ -741,32 +743,39 @@ int build_top_module_global_net_for_given_grid_module(ModuleManager& module_mana
VTR_ASSERT(1 == physical_tile->equivalent_sites.size());
/* Ensure port width is in range */
BasicPort src_port = module_manager.module_port(top_module, top_module_port);
VTR_ASSERT(src_port.get_width() >= size_t(physical_tile_port.num_pins));
/* A tile may consist of multiple subtile, connect to all the pins from sub tiles */
for (int iz = 0; iz < physical_tile->capacity; ++iz) {
/* TODO: This should be replaced by using a pin mapping data structure from physical tile! */
int grid_pin_index = grid_pin_start_index + iz * physical_tile->equivalent_sites[0]->pb_type->num_pins;
/* Find the module pin */
size_t grid_pin_width = physical_tile->pin_width_offset[grid_pin_index];
size_t grid_pin_height = physical_tile->pin_height_offset[grid_pin_index];
std::vector<e_side> pin_sides = find_physical_tile_pin_side(physical_tile, grid_pin_index, border_side);
for (const e_side& pin_side : pin_sides) {
std::string grid_port_name = generate_grid_port_name(grid_coordinate,
grid_pin_width, grid_pin_height,
pin_side,
grid_pin_index, false);
ModulePortId grid_port_id = module_manager.find_module_port(grid_module, grid_port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(grid_module, grid_port_id));
for (size_t pin_id = 0; pin_id < size_t(physical_tile_port.num_pins); ++pin_id) {
/* TODO: This should be replaced by using a pin mapping data structure from physical tile! */
int grid_pin_index = grid_pin_start_index + iz * physical_tile->equivalent_sites[0]->pb_type->num_pins + pin_id;
/* Find the module pin */
size_t grid_pin_width = physical_tile->pin_width_offset[grid_pin_index];
size_t grid_pin_height = physical_tile->pin_height_offset[grid_pin_index];
std::vector<e_side> pin_sides = find_physical_tile_pin_side(physical_tile, grid_pin_index, border_side);
/* Build nets */
BasicPort src_port = module_manager.module_port(top_module, top_module_port);
for (size_t pin_id = 0; pin_id < tile_port_to_connect.pins().size(); ++pin_id) {
ModuleNetId net = create_module_source_pin_net(module_manager, top_module,
top_module, 0,
top_module_port, src_port.pins()[pin_id]);
VTR_ASSERT(ModuleNetId::INVALID() != net);
/* Configure the net sink */
module_manager.add_module_net_sink(top_module, net, grid_module, grid_instance, grid_port_id, tile_port_to_connect.pins()[pin_id]);
for (const e_side& pin_side : pin_sides) {
std::string grid_port_name = generate_grid_port_name(grid_coordinate,
grid_pin_width, grid_pin_height,
pin_side,
grid_pin_index, false);
ModulePortId grid_port_id = module_manager.find_module_port(grid_module, grid_port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(grid_module, grid_port_id));
VTR_ASSERT(1 == module_manager.module_port(grid_module, grid_port_id).get_width());
ModuleNetId net = create_module_source_pin_net(module_manager, top_module,
top_module, 0,
top_module_port, src_port.pins()[pin_id]);
VTR_ASSERT(ModuleNetId::INVALID() != net);
/* Configure the net sink */
BasicPort sink_port = module_manager.module_port(grid_module, grid_port_id);
module_manager.add_module_net_sink(top_module, net, grid_module, grid_instance, grid_port_id, sink_port.pins()[0]);
}
}
}

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

@ -7,6 +7,8 @@
#include "vtr_assert.h"
#include "vtr_time.h"
#include "command_exit_codes.h"
#include "circuit_library_utils.h"
/* Headers from openfpgautil library */
@ -147,18 +149,19 @@ void fpga_fabric_verilog(ModuleManager &module_manager,
* This testbench is created for quick verification and formal verification purpose.
* - Verilog netlist including preprocessing flags and all the Verilog netlists that have been generated
********************************************************************/
void fpga_verilog_testbench(const ModuleManager &module_manager,
const BitstreamManager &bitstream_manager,
const FabricBitstream &fabric_bitstream,
const AtomContext &atom_ctx,
const PlacementContext &place_ctx,
const IoLocationMap &io_location_map,
const FabricGlobalPortInfo &fabric_global_port_info,
const VprNetlistAnnotation &netlist_annotation,
const CircuitLibrary &circuit_lib,
const SimulationSetting &simulation_setting,
const ConfigProtocol &config_protocol,
const VerilogTestbenchOption &options) {
int fpga_verilog_testbench(const ModuleManager &module_manager,
const BitstreamManager &bitstream_manager,
const FabricBitstream &fabric_bitstream,
const AtomContext &atom_ctx,
const PlacementContext &place_ctx,
const PinConstraints& pin_constraints,
const IoLocationMap &io_location_map,
const FabricGlobalPortInfo &fabric_global_port_info,
const VprNetlistAnnotation &netlist_annotation,
const CircuitLibrary &circuit_lib,
const SimulationSetting &simulation_setting,
const ConfigProtocol &config_protocol,
const VerilogTestbenchOption &options) {
vtr::ScopedStartFinishTimer timer("Write Verilog testbenches for FPGA fabric\n");
@ -166,6 +169,8 @@ void fpga_verilog_testbench(const ModuleManager &module_manager,
std::string netlist_name = atom_ctx.nlist.netlist_name();
int status = CMD_EXEC_SUCCESS;
/* Create directories */
create_directory(src_dir_path);
@ -176,14 +181,19 @@ void fpga_verilog_testbench(const ModuleManager &module_manager,
/* Generate wrapper module for FPGA fabric (mapped by the input benchmark and pre-configured testbench for verification */
if (true == options.print_formal_verification_top_netlist()) {
std::string formal_verification_top_netlist_file_path = src_dir_path + netlist_name + std::string(FORMAL_VERIFICATION_VERILOG_FILE_POSTFIX);
print_verilog_preconfig_top_module(module_manager, bitstream_manager,
config_protocol,
circuit_lib, fabric_global_port_info,
atom_ctx, place_ctx, io_location_map,
netlist_annotation,
netlist_name,
formal_verification_top_netlist_file_path,
options.explicit_port_mapping());
status = print_verilog_preconfig_top_module(module_manager, bitstream_manager,
config_protocol,
circuit_lib, fabric_global_port_info,
atom_ctx, place_ctx,
pin_constraints,
io_location_map,
netlist_annotation,
netlist_name,
formal_verification_top_netlist_file_path,
options.explicit_port_mapping());
if (status == CMD_EXEC_FATAL_ERROR) {
return status;
}
}
if (true == options.print_preconfig_top_testbench()) {
@ -193,6 +203,7 @@ void fpga_verilog_testbench(const ModuleManager &module_manager,
random_top_testbench_file_path,
atom_ctx,
netlist_annotation,
pin_constraints,
simulation_setting,
options.explicit_port_mapping());
}
@ -205,7 +216,9 @@ void fpga_verilog_testbench(const ModuleManager &module_manager,
circuit_lib,
config_protocol,
fabric_global_port_info,
atom_ctx, place_ctx, io_location_map,
atom_ctx, place_ctx,
pin_constraints,
io_location_map,
netlist_annotation,
netlist_name,
top_testbench_file_path,
@ -226,7 +239,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 */
@ -234,6 +247,8 @@ void fpga_verilog_testbench(const ModuleManager &module_manager,
netlist_name,
options.fabric_netlist_file_path(),
options.reference_benchmark_file_path());
return status;
}
} /* end namespace openfpga */

View File

@ -19,6 +19,7 @@
#include "bitstream_manager.h"
#include "fabric_bitstream.h"
#include "simulation_setting.h"
#include "pin_constraints.h"
#include "io_location_map.h"
#include "fabric_global_port_info.h"
#include "vpr_netlist_annotation.h"
@ -42,18 +43,19 @@ void fpga_fabric_verilog(ModuleManager& module_manager,
const DeviceRRGSB& device_rr_gsb,
const FabricVerilogOption& options);
void fpga_verilog_testbench(const ModuleManager& module_manager,
const BitstreamManager& bitstream_manager,
const FabricBitstream& fabric_bitstream,
const AtomContext& atom_ctx,
const PlacementContext& place_ctx,
const IoLocationMap& io_location_map,
const FabricGlobalPortInfo &fabric_global_port_info,
const VprNetlistAnnotation& netlist_annotation,
const CircuitLibrary& circuit_lib,
const SimulationSetting& simulation_parameters,
const ConfigProtocol& config_protocol,
const VerilogTestbenchOption& options);
int fpga_verilog_testbench(const ModuleManager& module_manager,
const BitstreamManager& bitstream_manager,
const FabricBitstream& fabric_bitstream,
const AtomContext& atom_ctx,
const PlacementContext& place_ctx,
const PinConstraints& pin_constraints,
const IoLocationMap& io_location_map,
const FabricGlobalPortInfo &fabric_global_port_info,
const VprNetlistAnnotation& netlist_annotation,
const CircuitLibrary& circuit_lib,
const SimulationSetting& simulation_parameters,
const ConfigProtocol& config_protocol,
const VerilogTestbenchOption& options);
} /* end namespace openfpga */

View File

@ -65,9 +65,11 @@ void print_verilog_top_random_testbench_ports(std::fstream& fp,
/* Create a clock port if the benchmark does not have one!
* The clock is used for counting and synchronizing input stimulus
*/
BasicPort clock_port = generate_verilog_testbench_clock_port(clock_port_names, std::string(DEFAULT_CLOCK_NAME));
std::vector<BasicPort> clock_ports = generate_verilog_testbench_clock_port(clock_port_names, std::string(DEFAULT_CLOCK_NAME));
print_verilog_comment(fp, std::string("----- Default clock port is added here since benchmark does not contain one -------"));
fp << "\t" << generate_verilog_port(VERILOG_PORT_REG, clock_port) << ";" << std::endl;
for (const BasicPort& clock_port : clock_ports) {
fp << "\t" << generate_verilog_port(VERILOG_PORT_REG, clock_port) << ";" << std::endl;
}
/* Add an empty line as splitter */
fp << std::endl;
@ -192,6 +194,7 @@ 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 PinConstraints& pin_constraints,
const SimulationSetting& simulation_parameters,
const bool& explicit_port_mapping) {
std::string timer_message = std::string("Write configuration-skip testbench for FPGA top-level Verilog netlist implemented by '") + circuit_name.c_str() + std::string("'");
@ -227,16 +230,18 @@ void print_verilog_random_top_testbench(const std::string& circuit_name,
explicit_port_mapping);
/* Find clock port to be used */
BasicPort clock_port = generate_verilog_testbench_clock_port(clock_port_names, std::string(DEFAULT_CLOCK_NAME));
std::vector<BasicPort> clock_ports = generate_verilog_testbench_clock_port(clock_port_names, std::string(DEFAULT_CLOCK_NAME));
/* Add stimuli for reset, set, clock and iopad signals */
print_verilog_testbench_clock_stimuli(fp, simulation_parameters,
clock_port);
print_verilog_testbench_clock_stimuli(fp,
pin_constraints,
simulation_parameters,
clock_ports);
print_verilog_testbench_random_stimuli(fp, atom_ctx,
netlist_annotation,
clock_port_names,
std::string(CHECKFLAG_PORT_POSTFIX),
clock_port);
clock_ports);
print_verilog_testbench_check(fp,
std::string(AUTOCHECKED_SIMULATION_FLAG),
@ -252,7 +257,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

@ -6,6 +6,7 @@
*******************************************************************/
#include <string>
#include "vpr_context.h"
#include "pin_constraints.h"
#include "simulation_setting.h"
/********************************************************************
@ -19,6 +20,7 @@ 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 PinConstraints& pin_constraints,
const SimulationSetting& simulation_parameters,
const bool& explicit_port_mapping);

View File

@ -9,6 +9,8 @@
#include "vtr_log.h"
#include "vtr_time.h"
#include "command_exit_codes.h"
/* Headers from openfpgautil library */
#include "openfpga_port.h"
#include "openfpga_digest.h"
@ -24,254 +26,218 @@
#include "verilog_preconfig_top_module.h"
/* begin namespace openfpga */
namespace openfpga
{
namespace openfpga {
/********************************************************************
/********************************************************************
* Print module declaration and ports for the pre-configured
* FPGA top module
* The module ports do exactly match the input benchmark
*******************************************************************/
static void print_verilog_preconfig_top_module_ports(std::fstream &fp,
const std::string &circuit_name,
const AtomContext &atom_ctx,
const VprNetlistAnnotation &netlist_annotation)
{
static
void print_verilog_preconfig_top_module_ports(std::fstream &fp,
const std::string &circuit_name,
const AtomContext &atom_ctx,
const VprNetlistAnnotation &netlist_annotation) {
/* Validate the file stream */
valid_file_stream(fp);
/* Validate the file stream */
valid_file_stream(fp);
/* Module declaration */
fp << "module " << circuit_name << std::string(FORMAL_VERIFICATION_TOP_MODULE_POSTFIX);
fp << " (" << std::endl;
/* Module declaration */
fp << "module " << circuit_name << std::string(FORMAL_VERIFICATION_TOP_MODULE_POSTFIX);
fp << " (" << std::endl;
/* Add module ports */
size_t port_counter = 0;
/* Add module ports */
size_t port_counter = 0;
/* Port type-to-type mapping */
std::map<AtomBlockType, enum e_dump_verilog_port_type> port_type2type_map;
port_type2type_map[AtomBlockType::INPAD] = VERILOG_PORT_INPUT;
port_type2type_map[AtomBlockType::OUTPAD] = VERILOG_PORT_OUTPUT;
/* Port type-to-type mapping */
std::map<AtomBlockType, enum e_dump_verilog_port_type> port_type2type_map;
port_type2type_map[AtomBlockType::INPAD] = VERILOG_PORT_INPUT;
port_type2type_map[AtomBlockType::OUTPAD] = VERILOG_PORT_OUTPUT;
/* Print all the I/Os of the circuit implementation to be tested*/
for (const AtomBlockId &atom_blk : atom_ctx.nlist.blocks())
{
/* We only care I/O logical blocks !*/
if ((AtomBlockType::INPAD != atom_ctx.nlist.block_type(atom_blk)) && (AtomBlockType::OUTPAD != 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);
}
if (0 < port_counter)
{
fp << "," << std::endl;
}
/* Both input and output ports have only size of 1 */
BasicPort module_port(std::string(block_name + std::string(FORMAL_VERIFICATION_TOP_MODULE_PORT_POSTFIX)), 1);
fp << generate_verilog_port(port_type2type_map[atom_ctx.nlist.block_type(atom_blk)], module_port);
/* Update port counter */
port_counter++;
/* Print all the I/Os of the circuit implementation to be tested*/
for (const AtomBlockId &atom_blk : atom_ctx.nlist.blocks()) {
/* We only care I/O logical blocks !*/
if ((AtomBlockType::INPAD != atom_ctx.nlist.block_type(atom_blk)) && (AtomBlockType::OUTPAD != atom_ctx.nlist.block_type(atom_blk))) {
continue;
}
fp << ");" << std::endl;
/* 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);
}
/* Add an empty line as a splitter */
fp << std::endl;
if (0 < port_counter) {
fp << "," << std::endl;
}
/* Both input and output ports have only size of 1 */
BasicPort module_port(std::string(block_name + std::string(FORMAL_VERIFICATION_TOP_MODULE_PORT_POSTFIX)), 1);
fp << generate_verilog_port(port_type2type_map[atom_ctx.nlist.block_type(atom_blk)], module_port);
/* Update port counter */
port_counter++;
}
/********************************************************************
fp << ");" << std::endl;
/* Add an empty line as a splitter */
fp << std::endl;
}
/********************************************************************
* Print internal wires for the pre-configured FPGA top module
* The internal wires are tailored for the ports of FPGA top module
* which will be different in various configuration protocols
*******************************************************************/
static void print_verilog_preconfig_top_module_internal_wires(std::fstream &fp,
const ModuleManager &module_manager,
const ModuleId &top_module)
{
/* Validate the file stream */
valid_file_stream(fp);
static
void print_verilog_preconfig_top_module_internal_wires(std::fstream &fp,
const ModuleManager &module_manager,
const ModuleId &top_module) {
/* Validate the file stream */
valid_file_stream(fp);
/* Global ports of top-level module */
print_verilog_comment(fp, std::string("----- Local wires for FPGA fabric -----"));
for (const ModulePortId &module_port_id : module_manager.module_ports(top_module))
{
BasicPort module_port = module_manager.module_port(top_module, module_port_id);
fp << generate_verilog_port(VERILOG_PORT_WIRE, module_port) << ";" << std::endl;
}
/* Add an empty line as a splitter */
fp << std::endl;
/* Global ports of top-level module */
print_verilog_comment(fp, std::string("----- Local wires for FPGA fabric -----"));
for (const ModulePortId &module_port_id : module_manager.module_ports(top_module)) {
BasicPort module_port = module_manager.module_port(top_module, module_port_id);
fp << generate_verilog_port(VERILOG_PORT_WIRE, module_port) << ";" << std::endl;
}
/* Add an empty line as a splitter */
fp << std::endl;
}
/********************************************************************
/********************************************************************
* Connect global ports of FPGA top module to constants except:
* 1. operating clock, which should be wired to the clock port of
* this pre-configured FPGA top module
*******************************************************************/
static void print_verilog_preconfig_top_module_connect_global_ports(std::fstream &fp,
const ModuleManager &module_manager,
const ModuleId &top_module,
const FabricGlobalPortInfo &fabric_global_ports,
const std::vector<std::string> &benchmark_clock_port_names)
{
/* Validate the file stream */
valid_file_stream(fp);
static
int print_verilog_preconfig_top_module_connect_global_ports(std::fstream &fp,
const ModuleManager &module_manager,
const ModuleId &top_module,
const PinConstraints& pin_constraints,
const FabricGlobalPortInfo &fabric_global_ports,
const std::vector<std::string> &benchmark_clock_port_names) {
/* Validate the file stream */
valid_file_stream(fp);
print_verilog_comment(fp, std::string("----- Begin Connect Global ports of FPGA top module -----"));
print_verilog_comment(fp, std::string("----- Begin Connect Global ports of FPGA top module -----"));
for (const FabricGlobalPortId& global_port_id : fabric_global_ports.global_ports()) {
ModulePortId module_global_port_id = fabric_global_ports.global_module_port(global_port_id);
VTR_ASSERT(ModuleManager::MODULE_GLOBAL_PORT == module_manager.port_type(top_module, module_global_port_id));
BasicPort module_global_port = module_manager.module_port(top_module, module_global_port_id);
/* Now, for operating clock port, we should wire it to the clock of benchmark! */
if ((true == fabric_global_ports.global_port_is_clock(global_port_id))
&& (false == fabric_global_ports.global_port_is_prog(global_port_id))) {
/* Wiring to each pin of the global port: benchmark clock is always 1-bit */
for (const size_t &pin : module_global_port.pins()) {
for (const std::string &clock_port_name : benchmark_clock_port_names) {
BasicPort module_clock_pin(module_global_port.get_name(), pin, pin);
BasicPort benchmark_clock_pin(clock_port_name + std::string(FORMAL_VERIFICATION_TOP_MODULE_PORT_POSTFIX), 1);
print_verilog_wire_connection(fp, module_clock_pin, benchmark_clock_pin, false);
for (const FabricGlobalPortId& global_port_id : fabric_global_ports.global_ports()) {
ModulePortId module_global_port_id = fabric_global_ports.global_module_port(global_port_id);
VTR_ASSERT(ModuleManager::MODULE_GLOBAL_PORT == module_manager.port_type(top_module, module_global_port_id));
BasicPort module_global_port = module_manager.module_port(top_module, module_global_port_id);
/* Now, for operating clock port, we should wire it to the clock of benchmark! */
if ((true == fabric_global_ports.global_port_is_clock(global_port_id))
&& (false == fabric_global_ports.global_port_is_prog(global_port_id))) {
/* Wiring to each pin of the global port: benchmark clock is always 1-bit */
for (size_t pin_id = 0; pin_id < module_global_port.pins().size(); ++pin_id) {
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;
}
}
/* Finish, go to the next */
continue;
}
/* For other ports, give an default value */
std::vector<size_t> 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);
/* 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)
|| (true == benchmark_clock_port_names.empty())) {
std::vector<size_t> default_values(1, fabric_global_ports.global_port_default_value(global_port_id));
print_verilog_wire_constant_values(fp, module_clock_pin, default_values);
continue;
}
std::string clock_name_to_connect;
if (!constrained_net_name.empty()) {
clock_name_to_connect = constrained_net_name;
} else {
/* Otherwise, we must have a clear one-to-one clock net corresponding!!! */
if (benchmark_clock_port_names.size() != module_global_port.get_width()) {
VTR_LOG_ERROR("Unable to map %lu benchmark clocks to %lu clock pins of FPGA!\nRequire clear pin constraints!\n",
benchmark_clock_port_names.size(),
module_global_port.get_width());
return CMD_EXEC_FATAL_ERROR;
}
clock_name_to_connect = benchmark_clock_port_names[pin_id];
}
BasicPort benchmark_clock_pin(clock_name_to_connect + std::string(FORMAL_VERIFICATION_TOP_MODULE_PORT_POSTFIX), 1);
print_verilog_wire_connection(fp, module_clock_pin, benchmark_clock_pin, false);
}
/* Finish, go to the next */
continue;
}
print_verilog_comment(fp, std::string("----- End Connect Global ports of FPGA top module -----"));
/* Add an empty line as a splitter */
fp << std::endl;
/* For other ports, give an default value */
std::vector<size_t> 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);
}
/********************************************************************
print_verilog_comment(fp, std::string("----- End Connect Global ports of FPGA top module -----"));
/* Add an empty line as a splitter */
fp << std::endl;
return CMD_EXEC_SUCCESS;
}
/********************************************************************
* Impose the bitstream on the configuration memories
* This function uses 'assign' syntax to impost the bitstream at mem port
* while uses 'force' syntax to impost the bitstream at mem_inv port
*******************************************************************/
static void print_verilog_preconfig_top_module_assign_bitstream(std::fstream &fp,
const ModuleManager &module_manager,
const ModuleId &top_module,
const BitstreamManager &bitstream_manager,
const bool& output_datab_bits)
{
/* Validate the file stream */
valid_file_stream(fp);
static
void print_verilog_preconfig_top_module_assign_bitstream(std::fstream &fp,
const ModuleManager &module_manager,
const ModuleId &top_module,
const BitstreamManager &bitstream_manager,
const bool& output_datab_bits) {
/* Validate the file stream */
valid_file_stream(fp);
print_verilog_comment(fp, std::string("----- Begin assign bitstream to configuration memories -----"));
print_verilog_comment(fp, std::string("----- Begin assign bitstream to configuration memories -----"));
for (const ConfigBlockId &config_block_id : bitstream_manager.blocks())
{
/* We only cares blocks with configuration bits */
if (0 == bitstream_manager.block_bits(config_block_id).size())
{
continue;
}
/* Build the hierarchical path of the configuration bit in modules */
std::vector<ConfigBlockId> block_hierarchy = find_bitstream_manager_block_hierarchy(bitstream_manager, config_block_id);
/* Drop the first block, which is the top module, it should be replaced by the instance name here */
/* Ensure that this is the module we want to drop! */
VTR_ASSERT(0 == module_manager.module_name(top_module).compare(bitstream_manager.block_name(block_hierarchy[0])));
block_hierarchy.erase(block_hierarchy.begin());
/* Build the full hierarchy path */
std::string bit_hierarchy_path(FORMAL_VERIFICATION_TOP_MODULE_UUT_NAME);
for (const ConfigBlockId &temp_block : block_hierarchy)
{
bit_hierarchy_path += std::string(".");
bit_hierarchy_path += bitstream_manager.block_name(temp_block);
}
for (const ConfigBlockId &config_block_id : bitstream_manager.blocks()) {
/* We only cares blocks with configuration bits */
if (0 == bitstream_manager.block_bits(config_block_id).size()) {
continue;
}
/* Build the hierarchical path of the configuration bit in modules */
std::vector<ConfigBlockId> block_hierarchy = find_bitstream_manager_block_hierarchy(bitstream_manager, config_block_id);
/* Drop the first block, which is the top module, it should be replaced by the instance name here */
/* Ensure that this is the module we want to drop! */
VTR_ASSERT(0 == module_manager.module_name(top_module).compare(bitstream_manager.block_name(block_hierarchy[0])));
block_hierarchy.erase(block_hierarchy.begin());
/* Build the full hierarchy path */
std::string bit_hierarchy_path(FORMAL_VERIFICATION_TOP_MODULE_UUT_NAME);
for (const ConfigBlockId &temp_block : block_hierarchy) {
bit_hierarchy_path += std::string(".");
/* Find the bit index in the parent block */
BasicPort config_data_port(bit_hierarchy_path + generate_configurable_memory_data_out_name(),
bitstream_manager.block_bits(config_block_id).size());
/* Wire it to the configuration bit: access both data out and data outb ports */
std::vector<size_t> config_data_values;
for (const ConfigBitId config_bit : bitstream_manager.block_bits(config_block_id))
{
config_data_values.push_back(bitstream_manager.bit_value(config_bit));
}
print_verilog_wire_constant_values(fp, config_data_port, config_data_values);
bit_hierarchy_path += bitstream_manager.block_name(temp_block);
}
bit_hierarchy_path += std::string(".");
if (true == output_datab_bits) {
fp << "initial begin" << std::endl;
/* Find the bit index in the parent block */
BasicPort config_data_port(bit_hierarchy_path + generate_configurable_memory_data_out_name(),
bitstream_manager.block_bits(config_block_id).size());
for (const ConfigBlockId &config_block_id : bitstream_manager.blocks())
{
/* We only cares blocks with configuration bits */
if (0 == bitstream_manager.block_bits(config_block_id).size())
{
continue;
}
/* Build the hierarchical path of the configuration bit in modules */
std::vector<ConfigBlockId> block_hierarchy = find_bitstream_manager_block_hierarchy(bitstream_manager, config_block_id);
/* Drop the first block, which is the top module, it should be replaced by the instance name here */
/* Ensure that this is the module we want to drop! */
VTR_ASSERT(0 == module_manager.module_name(top_module).compare(bitstream_manager.block_name(block_hierarchy[0])));
block_hierarchy.erase(block_hierarchy.begin());
/* Build the full hierarchy path */
std::string bit_hierarchy_path(FORMAL_VERIFICATION_TOP_MODULE_UUT_NAME);
for (const ConfigBlockId &temp_block : block_hierarchy)
{
bit_hierarchy_path += std::string(".");
bit_hierarchy_path += bitstream_manager.block_name(temp_block);
}
bit_hierarchy_path += std::string(".");
/* Find the bit index in the parent block */
BasicPort config_datab_port(bit_hierarchy_path + generate_configurable_memory_inverted_data_out_name(),
bitstream_manager.block_bits(config_block_id).size());
std::vector<size_t> config_datab_values;
for (const ConfigBitId config_bit : bitstream_manager.block_bits(config_block_id))
{
config_datab_values.push_back(!bitstream_manager.bit_value(config_bit));
}
print_verilog_force_wire_constant_values(fp, config_datab_port, config_datab_values);
}
fp << "end" << std::endl;
/* Wire it to the configuration bit: access both data out and data outb ports */
std::vector<size_t> config_data_values;
for (const ConfigBitId config_bit : bitstream_manager.block_bits(config_block_id)) {
config_data_values.push_back(bitstream_manager.bit_value(config_bit));
}
print_verilog_comment(fp, std::string("----- End assign bitstream to configuration memories -----"));
print_verilog_wire_constant_values(fp, config_data_port, config_data_values);
}
/********************************************************************
* Impose the bitstream on the configuration memories
* This function uses '$deposit' syntax to do so
*******************************************************************/
static void print_verilog_preconfig_top_module_deposit_bitstream(std::fstream &fp,
const ModuleManager &module_manager,
const ModuleId &top_module,
const BitstreamManager &bitstream_manager,
const bool& output_datab_bits)
{
/* Validate the file stream */
valid_file_stream(fp);
print_verilog_comment(fp, std::string("----- Begin deposit bitstream to configuration memories -----"));
if (true == output_datab_bits) {
fp << "initial begin" << std::endl;
for (const ConfigBlockId &config_block_id : bitstream_manager.blocks())
{
for (const ConfigBlockId &config_block_id : bitstream_manager.blocks()) {
/* We only cares blocks with configuration bits */
if (0 == bitstream_manager.block_bits(config_block_id).size())
{
if (0 == bitstream_manager.block_bits(config_block_id).size()) {
continue;
}
/* Build the hierarchical path of the configuration bit in modules */
@ -282,94 +248,144 @@ namespace openfpga
block_hierarchy.erase(block_hierarchy.begin());
/* Build the full hierarchy path */
std::string bit_hierarchy_path(FORMAL_VERIFICATION_TOP_MODULE_UUT_NAME);
for (const ConfigBlockId &temp_block : block_hierarchy)
{
for (const ConfigBlockId &temp_block : block_hierarchy) {
bit_hierarchy_path += std::string(".");
bit_hierarchy_path += bitstream_manager.block_name(temp_block);
}
bit_hierarchy_path += std::string(".");
/* Find the bit index in the parent block */
BasicPort config_data_port(bit_hierarchy_path + generate_configurable_memory_data_out_name(),
bitstream_manager.block_bits(config_block_id).size());
/* Wire it to the configuration bit: access both data out and data outb ports */
std::vector<size_t> config_data_values;
for (const ConfigBitId config_bit : bitstream_manager.block_bits(config_block_id))
{
config_data_values.push_back(bitstream_manager.bit_value(config_bit));
}
print_verilog_deposit_wire_constant_values(fp, config_data_port, config_data_values);
/* Skip datab ports if specified */
if (false == output_datab_bits) {
continue;
}
BasicPort config_datab_port(bit_hierarchy_path + generate_configurable_memory_inverted_data_out_name(),
bitstream_manager.block_bits(config_block_id).size());
std::vector<size_t> config_datab_values;
for (const ConfigBitId config_bit : bitstream_manager.block_bits(config_block_id))
{
for (const ConfigBitId config_bit : bitstream_manager.block_bits(config_block_id)) {
config_datab_values.push_back(!bitstream_manager.bit_value(config_bit));
}
print_verilog_deposit_wire_constant_values(fp, config_datab_port, config_datab_values);
print_verilog_force_wire_constant_values(fp, config_datab_port, config_datab_values);
}
fp << "end" << std::endl;
print_verilog_comment(fp, std::string("----- End deposit bitstream to configuration memories -----"));
}
/********************************************************************
print_verilog_comment(fp, std::string("----- End assign bitstream to configuration memories -----"));
}
/********************************************************************
* Impose the bitstream on the configuration memories
* This function uses '$deposit' syntax to do so
*******************************************************************/
static
void print_verilog_preconfig_top_module_deposit_bitstream(std::fstream &fp,
const ModuleManager &module_manager,
const ModuleId &top_module,
const BitstreamManager &bitstream_manager,
const bool& output_datab_bits) {
/* Validate the file stream */
valid_file_stream(fp);
print_verilog_comment(fp, std::string("----- Begin deposit bitstream to configuration memories -----"));
fp << "initial begin" << std::endl;
for (const ConfigBlockId &config_block_id : bitstream_manager.blocks()) {
/* We only cares blocks with configuration bits */
if (0 == bitstream_manager.block_bits(config_block_id).size()) {
continue;
}
/* Build the hierarchical path of the configuration bit in modules */
std::vector<ConfigBlockId> block_hierarchy = find_bitstream_manager_block_hierarchy(bitstream_manager, config_block_id);
/* Drop the first block, which is the top module, it should be replaced by the instance name here */
/* Ensure that this is the module we want to drop! */
VTR_ASSERT(0 == module_manager.module_name(top_module).compare(bitstream_manager.block_name(block_hierarchy[0])));
block_hierarchy.erase(block_hierarchy.begin());
/* Build the full hierarchy path */
std::string bit_hierarchy_path(FORMAL_VERIFICATION_TOP_MODULE_UUT_NAME);
for (const ConfigBlockId &temp_block : block_hierarchy) {
bit_hierarchy_path += std::string(".");
bit_hierarchy_path += bitstream_manager.block_name(temp_block);
}
bit_hierarchy_path += std::string(".");
/* Find the bit index in the parent block */
BasicPort config_data_port(bit_hierarchy_path + generate_configurable_memory_data_out_name(),
bitstream_manager.block_bits(config_block_id).size());
/* Wire it to the configuration bit: access both data out and data outb ports */
std::vector<size_t> config_data_values;
for (const ConfigBitId config_bit : bitstream_manager.block_bits(config_block_id)) {
config_data_values.push_back(bitstream_manager.bit_value(config_bit));
}
print_verilog_deposit_wire_constant_values(fp, config_data_port, config_data_values);
/* Skip datab ports if specified */
if (false == output_datab_bits) {
continue;
}
BasicPort config_datab_port(bit_hierarchy_path + generate_configurable_memory_inverted_data_out_name(),
bitstream_manager.block_bits(config_block_id).size());
std::vector<size_t> config_datab_values;
for (const ConfigBitId config_bit : bitstream_manager.block_bits(config_block_id)) {
config_datab_values.push_back(!bitstream_manager.bit_value(config_bit));
}
print_verilog_deposit_wire_constant_values(fp, config_datab_port, config_datab_values);
}
fp << "end" << std::endl;
print_verilog_comment(fp, std::string("----- End deposit bitstream to configuration memories -----"));
}
/********************************************************************
* Impose the bitstream on the configuration memories
* We branch here for different simulators:
* 1. iVerilog Icarus prefers using 'assign' syntax to force the values
* 2. Mentor Modelsim prefers using '$deposit' syntax to do so
*******************************************************************/
static void print_verilog_preconfig_top_module_load_bitstream(std::fstream &fp,
const ModuleManager &module_manager,
const ModuleId &top_module,
const CircuitLibrary& circuit_lib,
const CircuitModelId& mem_model,
const BitstreamManager &bitstream_manager)
{
static
void print_verilog_preconfig_top_module_load_bitstream(std::fstream &fp,
const ModuleManager &module_manager,
const ModuleId &top_module,
const CircuitLibrary& circuit_lib,
const CircuitModelId& mem_model,
const BitstreamManager &bitstream_manager) {
/* Skip the datab port if there is only 1 output port in memory model
* Currently, it assumes that the data output port is always defined while datab is optional
* If we see only 1 port, we assume datab is not defined by default.
* TODO: this switch could be smarter: it should identify if only data or datab
* ports are defined.
*/
bool output_datab_bits = true;
if (1 == circuit_lib.model_ports_by_type(mem_model, CIRCUIT_MODEL_PORT_OUTPUT).size()) {
output_datab_bits = false;
}
print_verilog_comment(fp, std::string("----- Begin load bitstream to configuration memories -----"));
print_verilog_preprocessing_flag(fp, std::string(ICARUS_SIMULATOR_FLAG));
/* Use assign syntax for Icarus simulator */
print_verilog_preconfig_top_module_assign_bitstream(fp, module_manager, top_module,
bitstream_manager,
output_datab_bits);
fp << "`else" << std::endl;
/* Use assign syntax for Icarus simulator */
print_verilog_preconfig_top_module_deposit_bitstream(fp, module_manager, top_module,
bitstream_manager,
output_datab_bits);
print_verilog_endif(fp);
print_verilog_comment(fp, std::string("----- End load bitstream to configuration memories -----"));
/* Skip the datab port if there is only 1 output port in memory model
* Currently, it assumes that the data output port is always defined while datab is optional
* If we see only 1 port, we assume datab is not defined by default.
* TODO: this switch could be smarter: it should identify if only data or datab
* ports are defined.
*/
bool output_datab_bits = true;
if (1 == circuit_lib.model_ports_by_type(mem_model, CIRCUIT_MODEL_PORT_OUTPUT).size()) {
output_datab_bits = false;
}
/********************************************************************
print_verilog_comment(fp, std::string("----- Begin load bitstream to configuration memories -----"));
print_verilog_preprocessing_flag(fp, std::string(ICARUS_SIMULATOR_FLAG));
/* Use assign syntax for Icarus simulator */
print_verilog_preconfig_top_module_assign_bitstream(fp, module_manager, top_module,
bitstream_manager,
output_datab_bits);
fp << "`else" << std::endl;
/* Use assign syntax for Icarus simulator */
print_verilog_preconfig_top_module_deposit_bitstream(fp, module_manager, top_module,
bitstream_manager,
output_datab_bits);
print_verilog_endif(fp);
print_verilog_comment(fp, std::string("----- End load bitstream to configuration memories -----"));
}
/********************************************************************
* Top-level function to generate a Verilog module of
* a pre-configured FPGA fabric.
*
@ -401,87 +417,94 @@ namespace openfpga
* It includes wires to force constant values to part of FPGA datapath I/Os
* All these are hard to implement as a module in module manager
*******************************************************************/
void print_verilog_preconfig_top_module(const ModuleManager &module_manager,
const BitstreamManager &bitstream_manager,
const ConfigProtocol &config_protocol,
const CircuitLibrary &circuit_lib,
const FabricGlobalPortInfo &global_ports,
const AtomContext &atom_ctx,
const PlacementContext &place_ctx,
const IoLocationMap &io_location_map,
const VprNetlistAnnotation &netlist_annotation,
const std::string &circuit_name,
const std::string &verilog_fname,
const bool &explicit_port_mapping)
{
std::string timer_message = std::string("Write pre-configured FPGA top-level Verilog netlist for design '") + circuit_name + std::string("'");
int print_verilog_preconfig_top_module(const ModuleManager &module_manager,
const BitstreamManager &bitstream_manager,
const ConfigProtocol &config_protocol,
const CircuitLibrary &circuit_lib,
const FabricGlobalPortInfo &global_ports,
const AtomContext &atom_ctx,
const PlacementContext &place_ctx,
const PinConstraints& pin_constraints,
const IoLocationMap &io_location_map,
const VprNetlistAnnotation &netlist_annotation,
const std::string &circuit_name,
const std::string &verilog_fname,
const bool &explicit_port_mapping) {
std::string timer_message = std::string("Write pre-configured FPGA top-level Verilog netlist for design '") + circuit_name + std::string("'");
/* Start time count */
vtr::ScopedStartFinishTimer timer(timer_message);
int status = CMD_EXEC_SUCCESS;
/* Create the file stream */
std::fstream fp;
fp.open(verilog_fname, std::fstream::out | std::fstream::trunc);
/* Start time count */
vtr::ScopedStartFinishTimer timer(timer_message);
/* Validate the file stream */
check_file_stream(verilog_fname.c_str(), fp);
/* Create the file stream */
std::fstream fp;
fp.open(verilog_fname, std::fstream::out | std::fstream::trunc);
/* Generate a brief description on the Verilog file*/
std::string title = std::string("Verilog netlist for pre-configured FPGA fabric by design: ") + circuit_name;
print_verilog_file_header(fp, title);
/* Validate the file stream */
check_file_stream(verilog_fname.c_str(), fp);
/* Print module declaration and ports */
print_verilog_preconfig_top_module_ports(fp, circuit_name, atom_ctx, netlist_annotation);
/* Generate a brief description on the Verilog file*/
std::string title = std::string("Verilog netlist for pre-configured FPGA fabric by design: ") + circuit_name;
print_verilog_file_header(fp, title);
/* Find 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));
/* Print module declaration and ports */
print_verilog_preconfig_top_module_ports(fp, circuit_name, atom_ctx, netlist_annotation);
/* Print internal wires */
print_verilog_preconfig_top_module_internal_wires(fp, module_manager, top_module);
/* Find 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));
/* Instanciate FPGA top-level module */
print_verilog_testbench_fpga_instance(fp, module_manager, top_module,
std::string(FORMAL_VERIFICATION_TOP_MODULE_UUT_NAME),
explicit_port_mapping);
/* Print internal wires */
print_verilog_preconfig_top_module_internal_wires(fp, module_manager, top_module);
/* Find clock ports in benchmark */
std::vector<std::string> benchmark_clock_port_names = find_atom_netlist_clock_port_names(atom_ctx.nlist, netlist_annotation);
/* Instanciate FPGA top-level module */
print_verilog_testbench_fpga_instance(fp, module_manager, top_module,
std::string(FORMAL_VERIFICATION_TOP_MODULE_UUT_NAME),
explicit_port_mapping);
/* Connect FPGA top module global ports to constant or benchmark global signals! */
print_verilog_preconfig_top_module_connect_global_ports(fp, module_manager, top_module,
global_ports,
benchmark_clock_port_names);
/* Find clock ports in benchmark */
std::vector<std::string> benchmark_clock_port_names = find_atom_netlist_clock_port_names(atom_ctx.nlist, netlist_annotation);
/* Connect I/Os to benchmark I/Os or constant driver */
print_verilog_testbench_connect_fpga_ios(fp, module_manager, top_module,
atom_ctx, place_ctx, io_location_map,
netlist_annotation,
std::string(FORMAL_VERIFICATION_TOP_MODULE_PORT_POSTFIX),
std::string(FORMAL_VERIFICATION_TOP_MODULE_PORT_POSTFIX),
(size_t)VERILOG_DEFAULT_SIGNAL_INIT_VALUE);
/* Assign the SRAM model applied to the FPGA fabric */
CircuitModelId sram_model = config_protocol.memory_model();
VTR_ASSERT(true == circuit_lib.valid_model_id(sram_model));
/* Assign FPGA internal SRAM/Memory ports to bitstream values */
print_verilog_preconfig_top_module_load_bitstream(fp, module_manager, top_module,
circuit_lib, sram_model,
bitstream_manager);
/* Add signal initialization */
print_verilog_testbench_signal_initialization(fp,
std::string(FORMAL_VERIFICATION_TOP_MODULE_UUT_NAME),
circuit_lib,
module_manager,
top_module);
/* Testbench ends*/
print_verilog_module_end(fp, std::string(circuit_name) + std::string(FORMAL_VERIFICATION_TOP_MODULE_POSTFIX));
/* Close the file stream */
fp.close();
/* Connect FPGA top module global ports to constant or benchmark global signals! */
status = print_verilog_preconfig_top_module_connect_global_ports(fp, module_manager, top_module,
pin_constraints, global_ports,
benchmark_clock_port_names);
if (CMD_EXEC_FATAL_ERROR == status) {
return status;
}
/* Connect I/Os to benchmark I/Os or constant driver */
print_verilog_testbench_connect_fpga_ios(fp, module_manager, top_module,
atom_ctx, place_ctx, io_location_map,
netlist_annotation,
std::string(FORMAL_VERIFICATION_TOP_MODULE_PORT_POSTFIX),
std::string(FORMAL_VERIFICATION_TOP_MODULE_PORT_POSTFIX),
(size_t)VERILOG_DEFAULT_SIGNAL_INIT_VALUE);
/* Assign the SRAM model applied to the FPGA fabric */
CircuitModelId sram_model = config_protocol.memory_model();
VTR_ASSERT(true == circuit_lib.valid_model_id(sram_model));
/* Assign FPGA internal SRAM/Memory ports to bitstream values */
print_verilog_preconfig_top_module_load_bitstream(fp, module_manager, top_module,
circuit_lib, sram_model,
bitstream_manager);
/* Add signal initialization */
print_verilog_testbench_signal_initialization(fp,
std::string(FORMAL_VERIFICATION_TOP_MODULE_UUT_NAME),
circuit_lib,
module_manager,
top_module);
/* Testbench ends*/
print_verilog_module_end(fp, std::string(circuit_name) + std::string(FORMAL_VERIFICATION_TOP_MODULE_POSTFIX));
/* Close the file stream */
fp.close();
return status;
}
} /* end namespace openfpga */

View File

@ -10,6 +10,7 @@
#include "vpr_context.h"
#include "module_manager.h"
#include "bitstream_manager.h"
#include "pin_constraints.h"
#include "io_location_map.h"
#include "fabric_global_port_info.h"
#include "config_protocol.h"
@ -22,18 +23,19 @@
/* begin namespace openfpga */
namespace openfpga {
void print_verilog_preconfig_top_module(const ModuleManager& module_manager,
const BitstreamManager& bitstream_manager,
const ConfigProtocol &config_protocol,
const CircuitLibrary& circuit_lib,
const FabricGlobalPortInfo &global_ports,
const AtomContext& atom_ctx,
const PlacementContext& place_ctx,
const IoLocationMap& io_location_map,
const VprNetlistAnnotation& netlist_annotation,
const std::string& circuit_name,
const std::string& verilog_fname,
const bool& explicit_port_mapping);
int print_verilog_preconfig_top_module(const ModuleManager& module_manager,
const BitstreamManager& bitstream_manager,
const ConfigProtocol &config_protocol,
const CircuitLibrary& circuit_lib,
const FabricGlobalPortInfo &global_ports,
const AtomContext& atom_ctx,
const PlacementContext& place_ctx,
const PinConstraints& pin_constraints,
const IoLocationMap& io_location_map,
const VprNetlistAnnotation& netlist_annotation,
const std::string& circuit_name,
const std::string& verilog_fname,
const bool& explicit_port_mapping);
} /* end namespace openfpga */

View File

@ -347,14 +347,18 @@ void print_verilog_timeout_and_vcd(std::fstream& fp,
* Restrictions:
* Assume this is a single clock benchmark
*******************************************************************/
BasicPort generate_verilog_testbench_clock_port(const std::vector<std::string>& clock_port_names,
const std::string& default_clock_name) {
std::vector<BasicPort> generate_verilog_testbench_clock_port(const std::vector<std::string>& clock_port_names,
const std::string& default_clock_name) {
std::vector<BasicPort> clock_ports;
if (0 == clock_port_names.size()) {
return BasicPort(default_clock_name, 1);
clock_ports.push_back(BasicPort(default_clock_name, 1));
} else {
for (const std::string& clock_port_name : clock_port_names) {
clock_ports.push_back(BasicPort(clock_port_name, 1));
}
}
VTR_ASSERT(1 == clock_port_names.size());
return BasicPort(clock_port_names[0], 1);
return clock_ports;
}
/********************************************************************
@ -382,7 +386,7 @@ void print_verilog_testbench_check(std::fstream& fp,
print_verilog_comment(fp, std::string("----- Begin checking output vectors -------"));
BasicPort clock_port = generate_verilog_testbench_clock_port(clock_port_names, default_clock_name);
std::vector<BasicPort> clock_ports = generate_verilog_testbench_clock_port(clock_port_names, default_clock_name);
print_verilog_comment(fp, std::string("----- Skip the first falling edge of clock, it is for initialization -------"));
@ -391,7 +395,14 @@ void print_verilog_testbench_check(std::fstream& fp,
fp << "\t" << generate_verilog_port(VERILOG_PORT_REG, sim_start_port) << ";" << std::endl;
fp << std::endl;
fp << "\talways@(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, clock_port) << ") begin" << std::endl;
/* TODO: This is limitation when multiple clock signals exist
* Ideally, all the input signals are generated by different clock edges,
* depending which clock domain the signals belong to
* Currently, as we lack the information, we only use the first clock signal
*/
VTR_ASSERT(1 <= clock_ports.size());
fp << "\talways@(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, clock_ports[0]) << ") begin" << std::endl;
fp << "\t\tif (1'b1 == " << generate_verilog_port(VERILOG_PORT_CONKT, sim_start_port) << ") begin" << std::endl;
fp << "\t\t";
print_verilog_register_connection(fp, sim_start_port, sim_start_port, true);
@ -465,28 +476,53 @@ void print_verilog_testbench_check(std::fstream& fp,
* but be only used as a synchronizer in verification
*******************************************************************/
void print_verilog_testbench_clock_stimuli(std::fstream& fp,
const PinConstraints& pin_constraints,
const SimulationSetting& simulation_parameters,
const BasicPort& clock_port) {
const std::vector<BasicPort>& clock_ports) {
/* Validate the file stream */
valid_file_stream(fp);
print_verilog_comment(fp, std::string("----- Clock Initialization -------"));
for (const BasicPort& clock_port : clock_ports) {
print_verilog_comment(fp, std::string("----- Clock '") + clock_port.get_name() + std::string("' Initialization -------"));
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" << generate_verilog_port(VERILOG_PORT_CONKT, clock_port);
fp << " <= !";
fp << generate_verilog_port(VERILOG_PORT_CONKT, clock_port);
fp << ";" << std::endl;
fp << "\t\tend" << std::endl;
/* 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;
/* Check pin constraints to see if this clock is constrained to a specific pin
* If constrained,
* - connect this clock to default values if it is set to be OPEN
* - connect this clock to a specific clock source from simulation settings!!!
*/
VTR_ASSERT(1 == clock_port.get_width());
for (const PinConstraintId& pin_constraint : pin_constraints.pin_constraints()) {
if (clock_port.get_name() != pin_constraints.net(pin_constraint)) {
continue;
}
/* Skip all the unrelated pin constraints */
VTR_ASSERT(clock_port.get_name() == pin_constraints.net(pin_constraint));
/* Try to find which clock source is considered in simulation settings for this pin */
for (const SimulationClockId& sim_clock_id : simulation_parameters.clocks()) {
if (pin_constraints.pin(pin_constraint) == simulation_parameters.clock_port(sim_clock_id)) {
clk_freq_to_use = (0.5 / simulation_parameters.clock_frequency(sim_clock_id)) / VERILOG_SIM_TIMESCALE;
}
}
}
fp << "\tend" << std::endl;
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) << 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);
fp << ";" << std::endl;
fp << "\t\tend" << std::endl;
/* Add an empty line as splitter */
fp << std::endl;
fp << "\tend" << std::endl;
/* Add an empty line as splitter */
fp << std::endl;
}
}
/********************************************************************
@ -498,7 +534,7 @@ void print_verilog_testbench_random_stimuli(std::fstream& fp,
const VprNetlistAnnotation& netlist_annotation,
const std::vector<std::string>& clock_port_names,
const std::string& check_flag_port_postfix,
const BasicPort& clock_port) {
const std::vector<BasicPort>& clock_ports) {
/* Validate the file stream */
valid_file_stream(fp);
@ -557,25 +593,14 @@ void print_verilog_testbench_random_stimuli(std::fstream& fp,
/* Add an empty line as splitter */
fp << std::endl;
// Not ready yet to determine if input is reset
/*
fprintf(fp, "//----- Reset Stimulis\n");
fprintf(fp, " initial begin\n");
fprintf(fp, " #%.3f\n",(rand() % 10) + 0.001);
fprintf(fp, " %s <= !%s;\n", reset_input_name, reset_input_name);
fprintf(fp, " #%.3f\n",(rand() % 10) + 0.001);
fprintf(fp, " %s <= !%s;\n", reset_input_name, reset_input_name);
fprintf(fp, " while(1) begin\n");
fprintf(fp, " #%.3f\n", (rand() % 15) + 0.5);
fprintf(fp, " %s <= !%s;\n", reset_input_name, reset_input_name);
fprintf(fp, " #%.3f\n", (rand() % 10000) + 200);
fprintf(fp, " %s <= !%s;\n", reset_input_name, reset_input_name);
fprintf(fp, " end\n");
fprintf(fp, " end\n\n");
*/
print_verilog_comment(fp, std::string("----- Input Stimulus -------"));
fp << "\talways@(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, clock_port) << ") begin" << std::endl;
/* TODO: This is limitation when multiple clock signals exist
* Ideally, all the input signals are generated by different clock edges,
* depending which clock domain the signals belong to
* Currently, as we lack the information, we only use the first clock signal
*/
VTR_ASSERT(1 <= clock_ports.size());
fp << "\talways@(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, clock_ports[0]) << ") begin" << std::endl;
for (const AtomBlockId& atom_blk : atom_ctx.nlist.blocks()) {
/* Bypass non-I/O atom blocks ! */

View File

@ -12,6 +12,7 @@
#include "vpr_context.h"
#include "io_location_map.h"
#include "vpr_netlist_annotation.h"
#include "pin_constraints.h"
#include "simulation_setting.h"
/********************************************************************
@ -60,8 +61,8 @@ void print_verilog_timeout_and_vcd(std::fstream& fp,
const std::string& error_counter_name,
const float& simulation_time);
BasicPort generate_verilog_testbench_clock_port(const std::vector<std::string>& clock_port_names,
const std::string& default_clock_name);
std::vector<BasicPort> generate_verilog_testbench_clock_port(const std::vector<std::string>& clock_port_names,
const std::string& default_clock_name);
void print_verilog_testbench_check(std::fstream& fp,
const std::string& autochecked_preprocessing_flag,
@ -76,15 +77,16 @@ void print_verilog_testbench_check(std::fstream& fp,
const std::string& default_clock_name);
void print_verilog_testbench_clock_stimuli(std::fstream& fp,
const PinConstraints& pin_constraints,
const SimulationSetting& simulation_parameters,
const BasicPort& clock_port);
const std::vector<BasicPort>& clock_ports);
void print_verilog_testbench_random_stimuli(std::fstream& fp,
const AtomContext& atom_ctx,
const VprNetlistAnnotation& netlist_annotation,
const std::vector<std::string>& clock_port_names,
const std::string& check_flag_port_postfix,
const BasicPort& clock_port);
const std::vector<BasicPort>& clock_ports);
void print_verilog_testbench_shared_ports(std::fstream& fp,
const AtomContext& atom_ctx,

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 */
@ -288,9 +301,21 @@ void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp,
* The wiring will be inverted if the default value of the global port is 1
* Otherwise, the wiring will not be inverted!
*/
print_verilog_wire_connection(fp, module_manager.module_port(top_module, module_global_port),
stimuli_clock_port,
1 == fabric_global_port_info.global_port_default_value(fabric_global_port));
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);
/* 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));
}
}
/* Connect global configuration done ports to configuration done signal */
@ -457,6 +482,71 @@ void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp,
print_verilog_comment(fp, std::string("----- End connecting global ports of FPGA fabric to stimuli -----"));
}
/********************************************************************
* This function prints the clock ports for all the benchmark clock nets
* It will search the pin constraints to see if a clock is constrained to a specific pin
* If constrained,
* - connect this clock to default values if it is set to be OPEN
* - connect this clock to a specific clock source from simulation settings!!!
* Otherwise,
* - connect this clock to the default clock port
*******************************************************************/
static
void print_verilog_top_testbench_benchmark_clock_ports(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& top_module,
const std::vector<std::string>& clock_port_names,
const PinConstraints& pin_constraints,
const SimulationSetting& simulation_parameters,
const BasicPort& default_clock_port) {
/* Create a clock port if the benchmark have one but not in the default name!
* We will wire the clock directly to the operating clock directly
*/
for (const std::string clock_port_name : clock_port_names) {
if (0 == clock_port_name.compare(default_clock_port.get_name())) {
continue;
}
/* Ensure the clock port name is not a duplication of global ports of the FPGA module */
bool print_clock_port = true;
for (const BasicPort& module_port : module_manager.module_ports_by_type(top_module, ModuleManager::MODULE_GLOBAL_PORT)) {
if (0 == clock_port_name.compare(module_port.get_name())) {
print_clock_port = false;
}
}
if (false == print_clock_port) {
continue;
}
BasicPort clock_source_to_connect = default_clock_port;
/* Check pin constraints to see if this clock is constrained to a specific pin
* If constrained,
* - connect this clock to default values if it is set to be OPEN
* - connect this clock to a specific clock source from simulation settings!!!
*/
for (const PinConstraintId& pin_constraint : pin_constraints.pin_constraints()) {
if (clock_port_name != pin_constraints.net(pin_constraint)) {
continue;
}
/* Skip all the unrelated pin constraints */
VTR_ASSERT(clock_port_name == pin_constraints.net(pin_constraint));
/* Try to find which clock source is considered in simulation settings for this pin */
for (const SimulationClockId& sim_clock_id : simulation_parameters.clocks()) {
if (pin_constraints.pin(pin_constraint) == simulation_parameters.clock_port(sim_clock_id)) {
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_id));
clock_source_to_connect = BasicPort(sim_clock_port_name, 1);
}
}
}
/* Print the clock and wire it to the clock source */
print_verilog_comment(fp, std::string("----- Create a clock for benchmark and wire it to " + clock_source_to_connect.get_name() + " -------"));
BasicPort clock_port(clock_port_name, 1);
fp << "\t" << generate_verilog_port(VERILOG_PORT_WIRE, clock_port) << ";" << std::endl;
print_verilog_wire_connection(fp, clock_port, clock_source_to_connect, false);
}
}
/********************************************************************
* This function prints the top testbench module declaration
* and internal wires/port declaration
@ -481,6 +571,8 @@ 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 PinConstraints& pin_constraints,
const SimulationSetting& simulation_parameters,
const ConfigProtocol& config_protocol,
const std::string& circuit_name){
/* Validate the file stream */
@ -536,7 +628,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);
@ -558,30 +664,13 @@ void print_verilog_top_testbench_ports(std::fstream& fp,
print_verilog_top_testbench_config_protocol_port(fp, config_protocol,
module_manager, top_module);
/* Create a clock port if the benchmark have one but not in the default name!
* We will wire the clock directly to the operating clock directly
*/
for (const std::string clock_port_name : clock_port_names) {
if (0 == clock_port_name.compare(op_clock_port.get_name())) {
continue;
}
/* Ensure the clock port name is not a duplication of global ports of the FPGA module */
bool print_clock_port = true;
for (const BasicPort& module_port : module_manager.module_ports_by_type(top_module, ModuleManager::MODULE_GLOBAL_PORT)) {
if (0 == clock_port_name.compare(module_port.get_name())) {
print_clock_port = false;
}
}
if (false == print_clock_port) {
continue;
}
/* Print the clock and wire it to op_clock */
print_verilog_comment(fp, std::string("----- Create a clock for benchmark and wire it to op_clock -------"));
BasicPort clock_port(clock_port_name, 1);
fp << "\t" << generate_verilog_port(VERILOG_PORT_WIRE, clock_port) << ";" << std::endl;
print_verilog_wire_connection(fp, clock_port, op_clock_port, false);
}
/* Print clock ports */
print_verilog_top_testbench_benchmark_clock_ports(fp,
module_manager, top_module,
clock_port_names,
pin_constraints,
simulation_parameters,
op_clock_port);
print_verilog_testbench_shared_ports(fp, atom_ctx, netlist_annotation,
clock_port_names,
@ -962,6 +1051,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,
@ -1014,6 +1104,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,
@ -1774,6 +1890,7 @@ void print_verilog_top_testbench(const ModuleManager& module_manager,
const FabricGlobalPortInfo& global_ports,
const AtomContext& atom_ctx,
const PlacementContext& place_ctx,
const PinConstraints& pin_constraints,
const IoLocationMap& io_location_map,
const VprNetlistAnnotation& netlist_annotation,
const std::string& circuit_name,
@ -1826,13 +1943,20 @@ 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,
atom_ctx, netlist_annotation,
clock_port_names,
pin_constraints,
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,
@ -1842,9 +1966,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 */
@ -1884,6 +2009,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);
@ -1935,7 +2061,7 @@ void print_verilog_top_testbench(const ModuleManager& module_manager,
netlist_annotation,
clock_port_names,
std::string(TOP_TESTBENCH_CHECKFLAG_PORT_POSTFIX),
BasicPort(std::string(TOP_TB_OP_CLOCK_PORT_NAME), 1));
std::vector<BasicPort>(1, BasicPort(std::string(TOP_TB_OP_CLOCK_PORT_NAME), 1)));
/* Add output autocheck */
print_verilog_testbench_check(fp,
@ -1961,7 +2087,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

@ -12,6 +12,7 @@
#include "circuit_library.h"
#include "config_protocol.h"
#include "vpr_context.h"
#include "pin_constraints.h"
#include "io_location_map.h"
#include "fabric_global_port_info.h"
#include "vpr_netlist_annotation.h"
@ -33,6 +34,7 @@ void print_verilog_top_testbench(const ModuleManager& module_manager,
const FabricGlobalPortInfo& global_ports,
const AtomContext& atom_ctx,
const PlacementContext& place_ctx,
const PinConstraints& pin_constraints,
const IoLocationMap& io_location_map,
const VprNetlistAnnotation& netlist_annotation,
const std::string& circuit_name,

View File

@ -240,9 +240,9 @@ std::vector<t_pb_graph_pin*> find_routed_pb_graph_pins_atom_net(const t_pb* pb,
* Note: this is ONLY applicable to the pb_pin of top-level pb_graph_node
***************************************************************************************/
static
int find_pb_route_remapped_source_pb_pin(const t_pb* pb,
const t_pb_graph_pin* source_pb_pin,
const AtomNetId& atom_net_id) {
std::vector<int> find_pb_route_remapped_source_pb_pin(const t_pb* pb,
const t_pb_graph_pin* source_pb_pin,
const AtomNetId& atom_net_id) {
VTR_ASSERT(true == source_pb_pin->parent_node->is_root());
std::vector<int> pb_route_indices;
@ -268,9 +268,7 @@ int find_pb_route_remapped_source_pb_pin(const t_pb* pb,
}
}
VTR_ASSERT(1 == pb_route_indices.size());
return pb_route_indices[0];
return pb_route_indices;
}
/***************************************************************************************
@ -339,6 +337,7 @@ void add_lb_router_nets(LbRouter& lb_router,
const VprDeviceAnnotation& device_annotation,
const ClusteringContext& clustering_ctx,
const VprClusteringAnnotation& clustering_annotation,
const RepackDesignConstraints& design_constraints,
const ClusterBlockId& block_id,
const bool& verbose) {
size_t net_counter = 0;
@ -409,31 +408,101 @@ void add_lb_router_nets(LbRouter& lb_router,
/* Find the net mapped to this pin in clustering results*/
AtomNetId atom_net_id = pb_pin_mapped_nets[source_pb_pin];
/* Bypass unmapped pins */
if (AtomNetId::INVALID() == atom_net_id) {
/* Check if the net information is constrained or not */
std::string constrained_net_name;
for (const RepackDesignConstraintId& design_constraint : design_constraints.design_constraints()) {
/* All the pin must have only 1 bit */
VTR_ASSERT_SAFE(1 == design_constraints.pin(design_constraint).get_width());
/* If found a constraint, record the net name */
if ( (std::string(lb_type->pb_type->name) == design_constraints.pb_type(design_constraint))
&& (std::string(source_pb_pin->port->name) == design_constraints.pin(design_constraint).get_name())
&& (size_t(source_pb_pin->pin_number) == design_constraints.pin(design_constraint).get_lsb())) {
constrained_net_name = design_constraints.net(design_constraint);
break;
}
}
/* Find the constrained net mapped to this pin in clustering results */
AtomNetId constrained_atom_net_id = AtomNetId::INVALID();
/* If the pin is constrained, we need to
* - if this is an open net, for invalid net then
* - if this is valid net name, find the net id from atom_netlist
* and overwrite the atom net id to mapped
*/
if (!constrained_net_name.empty()) {
if (std::string(REPACK_DESIGN_CONSTRAINT_OPEN_NET) != constrained_net_name) {
constrained_atom_net_id = atom_ctx.nlist.find_net(constrained_net_name);
if (false == atom_ctx.nlist.valid_net_id(constrained_atom_net_id)) {
VTR_LOG_WARN("Invalid net '%s' to be constrained! Will drop the constraint in repacking\n",
constrained_net_name.c_str());
}
}
} else {
VTR_ASSERT_SAFE(constrained_net_name.empty());
constrained_atom_net_id = atom_net_id;
}
/* Bypass unmapped pins. There are 4 conditions to consider
* +======+=================+=============+================================+
* | Case | Packing results | Constraints | Decision to route |
* +======+=================+=============+================================+
* | 0 | Unmapped | Unmapped | No routing needed |
* +======+=================+=============+================================+
* | 1 | Unmapped | Mapped | Find the pb source pin that |
* | | | | drives the constrained net and |
* | | | | use it to find sink nodes |
* +======+=================+=============+================================+
* | 2 | Mapped | Unmapped | No routing needed |
* +======+=================+=============+================================+
* | 3 | Mapped | Mapped | Route with the constrained net |
* | | | | but use the packing net id to |
* | | | | find the sink nodes to route |
* +======+=================+=============+================================+
*/
if (AtomNetId::INVALID() == constrained_atom_net_id) {
continue;
}
/* If we have a net to route, it must be the constrained net */
AtomNetId atom_net_id_to_route = constrained_atom_net_id;
/* The outputs of pb_graph_node is INTERMEDIATE node in the routing resource graph,
* they are all connected to a common source node
*/
LbRRNodeId source_lb_rr_node = lb_rr_graph.find_node(LB_INTERMEDIATE, source_pb_pin);
VTR_ASSERT(true == lb_rr_graph.valid_node_id(source_lb_rr_node));
int pb_route_index = find_pb_route_remapped_source_pb_pin(pb, source_pb_pin, atom_net_id);
/* As the pin remapping is allowed during routing, we should
* - Find the routing traces from packing results which is mapped to the net
* from the same port (as remapping is allowed for pins in the same port only)
* - Find the source pb_graph_pin that drives the routing traces during packing
* - Then we can find the sink nodes
*/
std::vector<int> pb_route_indices = find_pb_route_remapped_source_pb_pin(pb, source_pb_pin, atom_net_id_to_route);
/* It could happen that the constrained net is NOT used in this clb, we just skip it for routing
* For example, a clkB net is never mapped to any ports in the pb that is clocked by clkA net
* */
int pb_route_index;
if (0 == pb_route_indices.size()) {
continue;
} else {
VTR_ASSERT(1 == pb_route_indices.size());
pb_route_index = pb_route_indices[0];
}
t_pb_graph_pin* packing_source_pb_pin = get_pb_graph_node_pin_from_block_pin(block_id, pb_route_index);
VTR_ASSERT(nullptr != packing_source_pb_pin);
/* Find all the sink pins in the pb_route, we walk through the input pins and find the pin */
std::vector<t_pb_graph_pin*> sink_pb_graph_pins = find_routed_pb_graph_pins_atom_net(pb, source_pb_pin, packing_source_pb_pin, atom_net_id, device_annotation, pb_pin_mapped_nets, pb_graph_pin_lookup_from_index);
std::vector<t_pb_graph_pin*> sink_pb_graph_pins = find_routed_pb_graph_pins_atom_net(pb, source_pb_pin, packing_source_pb_pin, atom_net_id_to_route, device_annotation, pb_pin_mapped_nets, pb_graph_pin_lookup_from_index);
std::vector<LbRRNodeId> sink_lb_rr_nodes = find_lb_net_physical_sink_lb_rr_nodes(lb_rr_graph, sink_pb_graph_pins, device_annotation);
VTR_ASSERT(sink_lb_rr_nodes.size() == sink_pb_graph_pins.size());
/* Printf for debugging only, may be enabled if verbose is enabled
*/
/* Output verbose messages for debugging only */
VTR_LOGV(verbose,
"Pb route for Net %s:\n",
atom_ctx.nlist.net_name(atom_net_id).c_str());
atom_ctx.nlist.net_name(atom_net_id_to_route).c_str());
VTR_LOGV(verbose,
"Source node:\n\t%s -> %s\n",
source_pb_pin->to_string().c_str(),
@ -449,7 +518,7 @@ void add_lb_router_nets(LbRouter& lb_router,
add_lb_router_net_to_route(lb_router, lb_rr_graph,
std::vector<LbRRNodeId>(1, source_lb_rr_node),
sink_lb_rr_nodes,
atom_ctx, atom_net_id);
atom_ctx, atom_net_id_to_route);
net_counter++;
}
@ -542,6 +611,7 @@ void repack_cluster(const AtomContext& atom_ctx,
const ClusteringContext& clustering_ctx,
const VprDeviceAnnotation& device_annotation,
VprClusteringAnnotation& clustering_annotation,
const RepackDesignConstraints& design_constraints,
const ClusterBlockId& block_id,
const bool& verbose) {
/* Get the pb graph that current clustered block is mapped to */
@ -563,6 +633,7 @@ void repack_cluster(const AtomContext& atom_ctx,
/* Add nets to be routed with source and terminals */
add_lb_router_nets(lb_router, lb_type, lb_rr_graph, atom_ctx, device_annotation,
clustering_ctx, const_cast<const VprClusteringAnnotation&>(clustering_annotation),
design_constraints,
block_id, verbose);
/* Initialize the modes to expand routing trees with the physical modes in device annotation
@ -607,12 +678,15 @@ void repack_clusters(const AtomContext& atom_ctx,
const ClusteringContext& clustering_ctx,
const VprDeviceAnnotation& device_annotation,
VprClusteringAnnotation& clustering_annotation,
const RepackDesignConstraints& design_constraints,
const bool& verbose) {
vtr::ScopedStartFinishTimer timer("Repack clustered blocks to physical implementation of logical tile");
for (auto blk_id : clustering_ctx.clb_nlist.blocks()) {
repack_cluster(atom_ctx, clustering_ctx,
device_annotation, clustering_annotation,
device_annotation,
clustering_annotation,
design_constraints,
blk_id, verbose);
}
}
@ -632,6 +706,7 @@ void pack_physical_pbs(const DeviceContext& device_ctx,
const ClusteringContext& clustering_ctx,
VprDeviceAnnotation& device_annotation,
VprClusteringAnnotation& clustering_annotation,
const RepackDesignConstraints& design_constraints,
const bool& verbose) {
/* build the routing resource graph for each logical tile */
@ -642,6 +717,7 @@ void pack_physical_pbs(const DeviceContext& device_ctx,
/* Call the LbRouter to re-pack each clustered block to physical implementation */
repack_clusters(atom_ctx, clustering_ctx,
const_cast<const VprDeviceAnnotation&>(device_annotation), clustering_annotation,
design_constraints,
verbose);
}

View File

@ -8,6 +8,7 @@
#include "vpr_device_annotation.h"
#include "vpr_clustering_annotation.h"
#include "vpr_routing_annotation.h"
#include "repack_design_constraints.h"
/********************************************************************
* Function declaration
@ -21,6 +22,7 @@ void pack_physical_pbs(const DeviceContext& device_ctx,
const ClusteringContext& clustering_ctx,
VprDeviceAnnotation& device_annotation,
VprClusteringAnnotation& clustering_annotation,
const RepackDesignConstraints& design_constraints,
const bool& verbose);
} /* end namespace openfpga */

View File

@ -0,0 +1,22 @@
clk0 0.505000 0.204400
rst0 0.491000 0.206000
clk1 0.472000 0.204400
rst1 0.501400 0.204600
q1[0] 0.278800 0.557400
q1[1] 0.240600 0.268800
q1[2] 0.178200 0.120000
q1[3] 0.098400 0.041600
q0[0] 0.283400 0.566600
q0[1] 0.246800 0.272000
q0[2] 0.181000 0.122200
q0[3] 0.093200 0.048800
n34 0.178200 0.068356
n38 0.098400 0.002698
$abc$226$new_n22_ 0.880800 0.004943
n42 0.283400 0.129291
n46 0.246800 0.084119
n50 0.181000 0.067113
n54 0.093200 0.002644
$abc$226$new_n27_ 0.883200 0.005398
n26 0.278800 0.038636
n30 0.240600 0.082416

View File

@ -0,0 +1,48 @@
# Benchmark "counter4bit_2clock" written by ABC on Wed Jan 13 13:27:00 2021
.model counter4bit_2clock
.inputs clk0 rst0 clk1 rst1
.outputs q0[0] q0[1] q0[2] q0[3] q1[0] q1[1] \
q1[2] q1[3]
.latch n26 q1[0] re clk1 2
.latch n30 q1[1] re clk1 2
.latch n34 q1[2] re clk1 2
.latch n38 q1[3] re clk1 2
.latch n42 q0[0] re clk0 2
.latch n46 q0[1] re clk0 2
.latch n50 q0[2] re clk0 2
.latch n54 q0[3] re clk0 2
.names q1[0] q1[1] rst1 q1[2] n34
-001 1
0-01 1
1100 1
.names rst1 $abc$226$new_n22_ n38
00 1
.names q1[2] q1[0] q1[1] q1[3] $abc$226$new_n22_
--00 1
-0-0 1
0--0 1
1111 1
.names rst0 q0[0] n42
00 1
.names rst0 q0[1] q0[0] n46
001 1
010 1
.names q0[1] q0[0] rst0 q0[2] n50
-001 1
0-01 1
1100 1
.names rst0 $abc$226$new_n27_ n54
00 1
.names q0[2] q0[1] q0[0] q0[3] $abc$226$new_n27_
--00 1
-0-0 1
0--0 1
1111 1
.names q1[0] rst1 n26
00 1
.names rst1 q1[0] q1[1] n30
001 1
010 1
.end

View File

@ -0,0 +1,29 @@
module counter4bit_2clock(clk0, rst0, clk1, rst1, q0, q1);
input clk0;
input rst0;
output [3:0] q0;
reg [3:0] q0;
input clk1;
input rst1;
output [3:0] q1;
reg [3:0] q1;
always @ (posedge clk0)
begin
if(rst0)
q0 <= 4'b0000;
else
q0 <= q0 + 1;
end
always @ (posedge clk1)
begin
if(rst1)
q1 <= 4'b0000;
else
q1 <= q1 + 1;
end
endmodule

View File

@ -0,0 +1,60 @@
/* Generated by Yosys 0.9+2406 (git sha1 a0606e09, gcc 8.4.0 -fPIC -Os) */
module counter4bit_2clock(clk0, rst0, clk1, rst1, \q0[0] , \q0[1] , \q0[2] , \q0[3] , \q1[0] , \q1[1] , \q1[2] , \q1[3] );
wire _00_;
wire _01_;
input clk0;
input clk1;
wire n26;
wire n30;
wire n34;
wire n38;
wire n42;
wire n46;
wire n50;
wire n54;
output \q0[0] ;
reg \q0[0] ;
output \q0[1] ;
reg \q0[1] ;
output \q0[2] ;
reg \q0[2] ;
output \q0[3] ;
reg \q0[3] ;
output \q1[0] ;
reg \q1[0] ;
output \q1[1] ;
reg \q1[1] ;
output \q1[2] ;
reg \q1[2] ;
output \q1[3] ;
reg \q1[3] ;
input rst0;
input rst1;
always @(posedge clk1)
\q1[0] <= n26;
always @(posedge clk1)
\q1[1] <= n30;
always @(posedge clk1)
\q1[2] <= n34;
always @(posedge clk1)
\q1[3] <= n38;
always @(posedge clk1)
\q0[0] <= n42;
always @(posedge clk1)
\q0[1] <= n46;
always @(posedge clk1)
\q0[2] <= n50;
always @(posedge clk1)
\q0[3] <= n54;
assign n38 = 4'h1 >> { _00_, rst1 };
assign _00_ = 16'h807f >> { \q1[3] , \q1[1] , \q1[0] , \q1[2] };
assign n42 = 4'h1 >> { \q0[0] , rst0 };
assign n46 = 8'h14 >> { \q0[0] , \q0[1] , rst0 };
assign n50 = 16'h0708 >> { \q0[2] , rst0, \q0[0] , \q0[1] };
assign n54 = 4'h1 >> { _01_, rst0 };
assign _01_ = 16'h807f >> { \q0[3] , \q0[0] , \q0[1] , \q0[2] };
assign n26 = 4'h1 >> { rst1, \q1[0] };
assign n30 = 8'h14 >> { \q1[1] , \q1[0] , rst1 };
assign n34 = 16'h0708 >> { \q1[2] , rst1, \q1[1] , \q1[0] };
endmodule

View File

@ -0,0 +1,42 @@
module counter4bit_2clock_tb;
reg clk0, rst0;
wire [3:0] q0;
reg clk1, rst1;
wire [3:0] q1;
counter_2clock C_1(
clk0,
q0,
rst0);
counter_2clock C_1(
clk1,
q1,
rst1);
initial begin
#0 rst0 = 1'b1; clk0 = 1'b0;
#100 rst0 = 1'b0;
end
always begin
#10 clk0 = ~clk0;
end
initial begin
#0 rst1 = 1'b1; clk1 = 1'b0;
#100 rst1 = 1'b0;
end
always begin
#20 clk1 = ~clk1;
end
initial begin
#5000 $stop;
end
endmodule

View File

@ -26,5 +26,6 @@ Note that an OpenFPGA architecture can be applied to multiple VPR architecture f
- tree\_mux: If routing multiplexers are built with a tree-like structure
- <feature_size>: The technology node which the delay numbers are extracted from.
- powergate : The FPGA has power-gating techniques applied. If not defined, there is no power-gating.
- GlobalTile<Int>Clk: How many clocks are defined through global ports from physical tiles. <Int> is the number of clocks
Other features are used in naming should be listed here.

View File

@ -0,0 +1,198 @@
<!-- Architecture annotation for OpenFPGA framework
This annotation supports the k6_N10_40nm.xml
- General purpose logic block
- K = 6, N = 10, I = 40
- Single mode
- Routing architecture
- L = 4, fc_in = 0.15, fc_out = 0.1
- 4 operating clocks
-->
<openfpga_architecture>
<technology_library>
<device_library>
<device_model name="logic" type="transistor">
<lib type="industry" corner="TOP_TT" ref="M" path="${OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.pm"/>
<design vdd="0.9" pn_ratio="2"/>
<pmos name="pch" chan_length="40e-9" min_width="140e-9" variation="logic_transistor_var"/>
<nmos name="nch" chan_length="40e-9" min_width="140e-9" variation="logic_transistor_var"/>
</device_model>
<device_model name="io" type="transistor">
<lib type="academia" ref="M" path="${OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.pm"/>
<design vdd="2.5" pn_ratio="3"/>
<pmos name="pch_25" chan_length="270e-9" min_width="320e-9" variation="io_transistor_var"/>
<nmos name="nch_25" chan_length="270e-9" min_width="320e-9" variation="io_transistor_var"/>
</device_model>
</device_library>
<variation_library>
<variation name="logic_transistor_var" abs_deviation="0.1" num_sigma="3"/>
<variation name="io_transistor_var" abs_deviation="0.1" num_sigma="3"/>
</variation_library>
</technology_library>
<circuit_library>
<circuit_model type="inv_buf" name="INVTX1" prefix="INVTX1" is_default="true">
<design_technology type="cmos" topology="inverter" size="1"/>
<device_technology device_model_name="logic"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<delay_matrix type="rise" in_port="in" out_port="out">
10e-12
</delay_matrix>
<delay_matrix type="fall" in_port="in" out_port="out">
10e-12
</delay_matrix>
</circuit_model>
<circuit_model type="inv_buf" name="buf4" prefix="buf4" is_default="false">
<design_technology type="cmos" topology="buffer" size="1" num_level="2" f_per_stage="4"/>
<device_technology device_model_name="logic"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<delay_matrix type="rise" in_port="in" out_port="out">
10e-12
</delay_matrix>
<delay_matrix type="fall" in_port="in" out_port="out">
10e-12
</delay_matrix>
</circuit_model>
<circuit_model type="inv_buf" name="tap_buf4" prefix="tap_buf4" is_default="false">
<design_technology type="cmos" topology="buffer" size="1" num_level="3" f_per_stage="4"/>
<device_technology device_model_name="logic"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<delay_matrix type="rise" in_port="in" out_port="out">
10e-12
</delay_matrix>
<delay_matrix type="fall" in_port="in" out_port="out">
10e-12
</delay_matrix>
</circuit_model>
<circuit_model type="pass_gate" name="TGATE" prefix="TGATE" is_default="true">
<design_technology type="cmos" topology="transmission_gate" nmos_size="1" pmos_size="2"/>
<device_technology device_model_name="logic"/>
<input_buffer exist="false"/>
<output_buffer exist="false"/>
<port type="input" prefix="in" size="1"/>
<port type="input" prefix="sel" size="1"/>
<port type="input" prefix="selb" size="1"/>
<port type="output" prefix="out" size="1"/>
<delay_matrix type="rise" in_port="in sel selb" out_port="out">
10e-12 5e-12 5e-12
</delay_matrix>
<delay_matrix type="fall" in_port="in sel selb" out_port="out">
10e-12 5e-12 5e-12
</delay_matrix>
</circuit_model>
<circuit_model type="chan_wire" name="chan_segment" prefix="track_seg" is_default="true">
<design_technology type="cmos"/>
<input_buffer exist="false"/>
<output_buffer exist="false"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<wire_param model_type="pi" R="101" C="22.5e-15" num_level="1"/> <!-- model_type could be T, res_val and cap_val DON'T CARE -->
</circuit_model>
<circuit_model type="wire" name="direct_interc" prefix="direct_interc" is_default="true">
<design_technology type="cmos"/>
<input_buffer exist="false"/>
<output_buffer exist="false"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<wire_param model_type="pi" R="0" C="0" num_level="1"/> <!-- model_type could be T, res_val cap_val should be defined -->
</circuit_model>
<circuit_model type="mux" name="mux_tree" prefix="mux_tree" dump_structural_verilog="true">
<design_technology type="cmos" structure="tree" add_const_input="true" const_input_val="1"/>
<input_buffer exist="true" circuit_model_name="INVTX1"/>
<output_buffer exist="true" circuit_model_name="INVTX1"/>
<pass_gate_logic circuit_model_name="TGATE"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<port type="sram" prefix="sram" size="1"/>
</circuit_model>
<circuit_model type="mux" name="mux_tree_tapbuf" prefix="mux_tree_tapbuf" is_default="true" dump_structural_verilog="true">
<design_technology type="cmos" structure="tree" add_const_input="true" const_input_val="1"/>
<input_buffer exist="true" circuit_model_name="INVTX1"/>
<output_buffer exist="true" circuit_model_name="tap_buf4"/>
<pass_gate_logic circuit_model_name="TGATE"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<port type="sram" prefix="sram" size="1"/>
</circuit_model>
<!--DFF subckt ports should be defined as <D> <Q> <CLK> <RESET> <SET> -->
<circuit_model type="ff" name="DFFSRQ" prefix="DFFSRQ" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/spice/dff.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/verilog/dff.v">
<design_technology type="cmos"/>
<input_buffer exist="true" circuit_model_name="INVTX1"/>
<output_buffer exist="true" circuit_model_name="INVTX1"/>
<port type="input" prefix="D" size="1"/>
<port type="input" prefix="set" lib_name="SET" size="1" is_global="true" default_val="0" is_set="true"/>
<port type="input" prefix="reset" lib_name="RST" size="1" is_global="true" default_val="0" is_reset="true"/>
<port type="output" prefix="Q" size="1"/>
<port type="clock" prefix="clk" lib_name="CK" size="1" is_global="false" default_val="0"/>
</circuit_model>
<circuit_model type="lut" name="lut4" prefix="lut4" dump_structural_verilog="true">
<design_technology type="cmos"/>
<input_buffer exist="true" circuit_model_name="INVTX1"/>
<output_buffer exist="true" circuit_model_name="INVTX1"/>
<lut_input_inverter exist="true" circuit_model_name="INVTX1"/>
<lut_input_buffer exist="true" circuit_model_name="buf4"/>
<pass_gate_logic circuit_model_name="TGATE"/>
<port type="input" prefix="in" size="4"/>
<port type="output" prefix="out" size="1"/>
<port type="sram" prefix="sram" size="16"/>
</circuit_model>
<!--Scan-chain DFF subckt ports should be defined as <D> <Q> <Qb> <CLK> <RESET> <SET> -->
<circuit_model type="ccff" name="DFF" prefix="DFF" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/spice/dff.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/verilog/dff.v">
<design_technology type="cmos"/>
<input_buffer exist="true" circuit_model_name="INVTX1"/>
<output_buffer exist="true" circuit_model_name="INVTX1"/>
<port type="input" prefix="D" size="1"/>
<port type="output" prefix="Q" size="1"/>
<port type="output" prefix="QN" size="1"/>
<port type="clock" prefix="prog_clk" lib_name="CK" size="1" is_global="true" default_val="0" is_prog="true"/>
</circuit_model>
<circuit_model type="iopad" name="GPIO" prefix="GPIO" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/spice/gpio.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/verilog/gpio.v">
<design_technology type="cmos"/>
<input_buffer exist="true" circuit_model_name="INVTX1"/>
<output_buffer exist="true" circuit_model_name="INVTX1"/>
<port type="inout" prefix="PAD" size="1" is_global="true" is_io="true" is_data_io="true"/>
<port type="sram" prefix="DIR" size="1" mode_select="true" circuit_model_name="DFF" default_val="1"/>
<port type="input" prefix="outpad" lib_name="A" size="1"/>
<port type="output" prefix="inpad" lib_name="Y" size="1"/>
</circuit_model>
</circuit_library>
<configuration_protocol>
<organization type="scan_chain" circuit_model_name="DFF"/>
</configuration_protocol>
<connection_block>
<switch name="ipin_cblock" circuit_model_name="mux_tree_tapbuf"/>
</connection_block>
<switch_block>
<switch name="0" circuit_model_name="mux_tree_tapbuf"/>
</switch_block>
<routing_segment>
<segment name="L4" circuit_model_name="chan_segment"/>
</routing_segment>
<tile_annotations>
<global_port name="clk" is_clock="true" default_val="0">
<!-- MUST explicitly define the number of clock bits
being consistent with physical tile port definition
-->
<tile name="clb" port="clk[0:3]" x="-1" y="-1"/>
</global_port>
</tile_annotations>
<pb_type_annotations>
<!-- physical pb_type binding in complex block IO -->
<pb_type name="io" physical_mode_name="physical" idle_mode_name="inpad"/>
<pb_type name="io[physical].iopad" circuit_model_name="GPIO" mode_bits="1"/>
<pb_type name="io[inpad].inpad" physical_pb_type_name="io[physical].iopad" mode_bits="1"/>
<pb_type name="io[outpad].outpad" physical_pb_type_name="io[physical].iopad" mode_bits="0"/>
<!-- End physical pb_type binding in complex block IO -->
<!-- physical pb_type binding in complex block CLB -->
<!-- physical mode will be the default mode if not specified -->
<pb_type name="clb">
<!-- Binding interconnect to circuit models as their physical implementation, if not defined, we use the default model -->
<interconnect name="crossbar" circuit_model_name="mux_tree"/>
</pb_type>
<pb_type name="clb.fle[n1_lut4].ble4.lut4" circuit_model_name="lut4"/>
<pb_type name="clb.fle[n1_lut4].ble4.ff" circuit_model_name="DFFSRQ"/>
<!-- End physical pb_type binding in complex block IO -->
</pb_type_annotations>
</openfpga_architecture>

View File

@ -57,7 +57,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 --explicit_port_mapping
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 #--explicit_port_mapping
# Write the SDC files for PnR backend
# - Turn on every options here

View File

@ -0,0 +1,76 @@
# Run VPR for the 'and' design
# When the global clock is defined as a port of a tile, clock routing in VPR should be skipped
# This is due to the Fc_in of clock port is set to 0 for global wiring
#--write_rr_graph example_rr_graph.xml
vpr ${VPR_ARCH_FILE} ${VPR_TESTBENCH_BLIF}
# Read OpenFPGA architecture definition
read_openfpga_arch -f ${OPENFPGA_ARCH_FILE}
# Read OpenFPGA simulation settings
read_openfpga_simulation_setting -f ${OPENFPGA_SIM_SETTING_FILE}
# Annotate the OpenFPGA architecture to VPR data base
# to debug use --verbose options
link_openfpga_arch --activity_file ${ACTIVITY_FILE} --sort_gsb_chan_node_in_edges
# Check and correct any naming conflicts in the BLIF netlist
check_netlist_naming_conflict --fix --report ./netlist_renaming.xml
# Apply fix-up to clustering nets based on routing results
pb_pin_fixup --verbose
# Apply fix-up to Look-Up Table truth tables based on packing results
lut_truth_table_fixup
# Build the module graph
# - Enabled compression on routing architecture modules
# - Enable pin duplication on grid modules
build_fabric --compress_routing #--verbose
# Write the fabric hierarchy of module graph to a file
# This is used by hierarchical PnR flows
write_fabric_hierarchy --file ./fabric_hierarchy.txt
# Repack the netlist to physical pbs
# This must be done before bitstream generator and testbench generation
# Strongly recommend it is done after all the fix-up have been applied
repack --design_constraints ${OPENFPGA_REPACK_DESIGN_CONSTRAINTS_FILE} #--verbose
# Build the bitstream
# - Output the fabric-independent bitstream to a file
build_architecture_bitstream --verbose --write_file fabric_independent_bitstream.xml
# Build fabric-dependent bitstream
build_fabric_bitstream --verbose
# Write fabric-dependent bitstream
write_fabric_bitstream --file fabric_bitstream.xml --format xml
# Write the Verilog netlist for FPGA fabric
# - Enable the use of explicit port mapping in Verilog netlist
write_fabric_verilog --file ./SRC --explicit_port_mapping --include_timing --print_user_defined_template --verbose
# Write the Verilog testbench for FPGA fabric
# - We suggest the use of same output directory as fabric Verilog netlists
# - Must specify the reference benchmark file if you want to output any testbenches
# - 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 --pin_constraints_file ${OPENFPGA_PIN_CONSTRAINTS_FILE} #--explicit_port_mapping
# Write the SDC files for PnR backend
# - Turn on every options here
write_pnr_sdc --file ./SDC
# Write SDC to disable timing for configure ports
write_sdc_disable_timing_configure_ports --file ./SDC/disable_configure_ports.sdc
# Write the SDC to run timing analysis for a mapped FPGA fabric
write_analysis_sdc --file ./SDC_analysis
# Finish and exit OpenFPGA
exit
# Note :
# To run verification at the end of the flow maintain source in ./SRC directory

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

@ -0,0 +1,11 @@
<pin_constraints>
<!-- For a given .blif file, we want to assign
- the clk0 signal to the clk[0] port of the FPGA fabric
- the clk1 signal to the clk[1] port of the FPGA fabric
-->
<set_io pin="clk[0]" net="clk0"/>
<set_io pin="clk[1]" net="clk1"/>
<set_io pin="clk[2]" net="OPEN"/>
<set_io pin="clk[3]" net="OPEN"/>
</pin_constraints>

View File

@ -0,0 +1,14 @@
<repack_design_constraints>
<!-- For a given .blif file, we want to assign
- the clk0 signal to the clk[0] port of all the clb tiles available in the FPGA fabric
- the clk1 signal to the clk[1] port of all the clb tiles available in the FPGA fabric
and ensure no signals could be mapped to
- the clk[2] port of all the clb tiles available in the FPGA fabric
- the clk[3] port of all the clb tiles available in the FPGA fabric
-->
<pin_constraint pb_type="clb" pin="clk[0]" net="clk0"/>
<pin_constraint pb_type="clb" pin="clk[1]" net="clk1"/>
<pin_constraint pb_type="clb" pin="clk[2]" net="OPEN"/>
<pin_constraint pb_type="clb" pin="clk[3]" net="OPEN"/>
</repack_design_constraints>

View File

@ -0,0 +1,46 @@
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# Configuration file for running experiments
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs
# Each job execute fpga_flow script on combination of architecture & benchmark
# timeout_each_job is timeout for each job
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
[GENERAL]
run_engine=openfpga_shell
power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml
power_analysis = true
spice_output=false
verilog_output=true
timeout_each_job = 20*60
# Due to the limitation in ACE2 which cannot output .blif files
# with correct multi-clock assignments to .latch lines
# We have to use the vpr_blif flow where the .blif is modified
# based on yosys outputs with correct clock assignment!
# TODO: This limitation should be removed and we should use yosys_vpr flow!!!
fpga_flow=vpr_blif
#fpga_flow=yosys_vpr
[OpenFPGA_SHELL]
openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/global_tile_multiclock_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/fixed_4clock_sim_openfpga.xml
openfpga_repack_design_constraints_file=${PATH:OPENFPGA_PATH}/openfpga_flow/tasks/basic_tests/global_tile_ports/global_tile_4clock/config/repack_pin_constraints.xml
openfpga_pin_constraints_file=${PATH:OPENFPGA_PATH}/openfpga_flow/tasks/basic_tests/global_tile_ports/global_tile_4clock/config/pin_constraints.xml
[ARCHITECTURES]
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_GlobalTile4Clk_40nm.xml
[BENCHMARKS]
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/counter4bit_2clock/counter4bit_2clock.blif
#bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/counter4bit_2clock/counter4bit_2clock.v
[SYNTHESIS_PARAM]
bench0_top = counter4bit_2clock
bench0_act=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/counter4bit_2clock/counter4bit_2clock.act
bench0_verilog=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/counter4bit_2clock/counter4bit_2clock_post_yosys.v
bench0_chan_width = 300
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
end_flow_with_test=
vpr_fpga_verilog_formal_verification_top_netlist=

View File

@ -21,5 +21,6 @@ Please reveal the following architecture features in the names to help quickly s
* Top-left (Tl): the pins of a tile are placed on the top side and left side only
* Top-right (Tr): the pins of a tile are placed on the top side and right side only
* Bottom-right (Br): the pins of a tile are placed on the bottom side and right side only
- GlobalTile<Int>Clk: How many clocks are defined through global ports from physical tiles. <Int> is the number of clocks
Other features are used in naming should be listed here.

View File

@ -0,0 +1,296 @@
<!--
Architecture with no fracturable LUTs
- 40 nm technology
- General purpose logic block:
K = 4, N = 4
- Routing architecture: L = 4, fc_in = 0.15, Fc_out = 0.1
- 4 operating clocks which can be selected for each logic element
Details on Modelling:
Based on flagship k6_frac_N10_mem32K_40nm.xml architecture. This architecture has no fracturable LUTs nor any heterogeneous blocks.
Authors: Jason Luu, Jeff Goeders, Vaughn Betz
-->
<architecture>
<!--
ODIN II specific config begins
Describes the types of user-specified netlist blocks (in blif, this corresponds to
".model [type_of_block]") that this architecture supports.
Note: Basic LUTs, I/Os, and flip-flops are not included here as there are
already special structures in blif (.names, .input, .output, and .latch)
that describe them.
-->
<models>
<!-- A virtual model for I/O to be used in the physical mode of io block -->
<model name="io">
<input_ports>
<port name="outpad"/>
</input_ports>
<output_ports>
<port name="inpad"/>
</output_ports>
</model>
</models>
<tiles>
<tile name="io" capacity="8" area="0">
<equivalent_sites>
<site pb_type="io"/>
</equivalent_sites>
<input name="outpad" num_pins="1"/>
<output name="inpad" num_pins="1"/>
<fc in_type="frac" in_val="0.15" out_type="frac" out_val="0.10"/>
<pinlocations pattern="custom">
<loc side="left">io.outpad io.inpad</loc>
<loc side="top">io.outpad io.inpad</loc>
<loc side="right">io.outpad io.inpad</loc>
<loc side="bottom">io.outpad io.inpad</loc>
</pinlocations>
</tile>
<tile name="clb" area="53894">
<equivalent_sites>
<site pb_type="clb"/>
</equivalent_sites>
<input name="I" num_pins="10" equivalent="full"/>
<output name="O" num_pins="4" equivalent="none"/>
<clock name="clk" num_pins="4"/>
<fc in_type="frac" in_val="0.15" out_type="frac" out_val="0.10">
<fc_override port_name="clk" fc_type="frac" fc_val="0"/>
</fc>
<pinlocations pattern="spread"/>
</tile>
</tiles>
<!-- ODIN II specific config ends -->
<!-- Physical descriptions begin -->
<layout tileable="true">
<auto_layout aspect_ratio="1.0">
<!--Perimeter of 'io' blocks with 'EMPTY' blocks at corners-->
<perimeter type="io" priority="100"/>
<corners type="EMPTY" priority="101"/>
<!--Fill with 'clb'-->
<fill type="clb" priority="10"/>
</auto_layout>
<fixed_layout name="2x2" width="4" height="4">
<!--Perimeter of 'io' blocks with 'EMPTY' blocks at corners-->
<perimeter type="io" priority="100"/>
<corners type="EMPTY" priority="101"/>
<!--Fill with 'clb'-->
<fill type="clb" priority="10"/>
</fixed_layout>
</layout>
<device>
<!-- VB & JL: Using Ian Kuon's transistor sizing and drive strength data for routing, at 40 nm. Ian used BPTM
models. We are modifying the delay values however, to include metal C and R, which allows more architecture
experimentation. We are also modifying the relative resistance of PMOS to be 1.8x that of NMOS
(vs. Ian's 3x) as 1.8x lines up with Jeff G's data from a 45 nm process (and is more typical of
45 nm in general). I'm upping the Rmin_nmos from Ian's just over 6k to nearly 9k, and dropping
RminW_pmos from 18k to 16k to hit this 1.8x ratio, while keeping the delays of buffers approximately
lined up with Stratix IV.
We are using Jeff G.'s capacitance data for 45 nm (in tech/ptm_45nm).
Jeff's tables list C in for transistors with widths in multiples of the minimum feature size (45 nm).
The minimum contactable transistor is 2.5 * 45 nm, so I need to multiply drive strength sizes in this file
by 2.5x when looking up in Jeff's tables.
The delay values are lined up with Stratix IV, which has an architecture similar to this
proposed FPGA, and which is also 40 nm
C_ipin_cblock: input capacitance of a track buffer, which VPR assumes is a single-stage
4x minimum drive strength buffer. -->
<sizing R_minW_nmos="8926" R_minW_pmos="16067"/>
<!-- The grid_logic_tile_area below will be used for all blocks that do not explicitly set their own (non-routing)
area; set to 0 since we explicitly set the area of all blocks currently in this architecture file.
-->
<area grid_logic_tile_area="0"/>
<chan_width_distr>
<x distr="uniform" peak="1.000000"/>
<y distr="uniform" peak="1.000000"/>
</chan_width_distr>
<switch_block type="wilton" fs="3"/>
<connection_block input_switch_name="ipin_cblock"/>
</device>
<switchlist>
<!-- VB: the mux_trans_size and buf_size data below is in minimum width transistor *areas*, assuming the purple
book area formula. This means the mux transistors are about 5x minimum drive strength.
We assume the first stage of the buffer is 3x min drive strength to be reasonable given the large
mux transistors, and this gives a reasonable stage ratio of a bit over 5x to the second stage. We assume
the n and p transistors in the first stage are equal-sized to lower the buffer trip point, since it's fed
by a pass transistor mux. We can then reverse engineer the buffer second stage to hit the specified
buf_size (really buffer area) - 16.2x minimum drive nmos and 1.8*16.2 = 29.2x minimum drive.
I then took the data from Jeff G.'s PTM modeling of 45 nm to get the Cin (gate of first stage) and Cout
(diff of second stage) listed below. Jeff's models are in tech/ptm_45nm, and are in min feature multiples.
The minimum contactable transistor is 2.5 * 45 nm, so I need to multiply the drive strength sizes above by
2.5x when looking up in Jeff's tables.
Finally, we choose a switch delay (58 ps) that leads to length 4 wires having a delay equal to that of SIV of 126 ps.
This also leads to the switch being 46% of the total wire delay, which is reasonable. -->
<switch type="mux" name="0" R="551" Cin=".77e-15" Cout="4e-15" Tdel="58e-12" mux_trans_size="2.630740" buf_size="27.645901"/>
<!--switch ipin_cblock resistance set to yeild for 4x minimum drive strength buffer-->
<switch type="mux" name="ipin_cblock" R="2231.5" Cout="0." Cin="1.47e-15" Tdel="7.247000e-11" mux_trans_size="1.222260" buf_size="auto"/>
</switchlist>
<segmentlist>
<!--- VB & JL: using ITRS metal stack data, 96 nm half pitch wires, which are intermediate metal width/space.
With the 96 nm half pitch, such wires would take 60 um of height, vs. a 90 nm high (approximated as square) Stratix IV tile so this seems
reasonable. Using a tile length of 90 nm, corresponding to the length of a Stratix IV tile if it were square. -->
<segment name="L4" freq="1.000000" length="4" type="unidir" Rmetal="101" Cmetal="22.5e-15">
<mux name="0"/>
<sb type="pattern">1 1 1 1 1</sb>
<cb type="pattern">1 1 1 1</cb>
</segment>
</segmentlist>
<complexblocklist>
<!-- Define I/O pads begin -->
<!-- Capacity is a unique property of I/Os, it is the maximum number of I/Os that can be placed at the same (X,Y) location on the FPGA -->
<!-- Not sure of the area of an I/O (varies widely), and it's not relevant to the design of the FPGA core, so we're setting it to 0. -->
<pb_type name="io">
<input name="outpad" num_pins="1"/>
<output name="inpad" num_pins="1"/>
<!-- A mode denotes the physical implementation of an I/O
This mode will be not packable but is mainly used for fabric verilog generation
-->
<mode name="physical" packable="false">
<pb_type name="iopad" blif_model=".subckt io" num_pb="1">
<input name="outpad" num_pins="1"/>
<output name="inpad" num_pins="1"/>
</pb_type>
<interconnect>
<direct name="outpad" input="io.outpad" output="iopad.outpad">
<delay_constant max="1.394e-11" in_port="io.outpad" out_port="iopad.outpad"/>
</direct>
<direct name="inpad" input="iopad.inpad" output="io.inpad">
<delay_constant max="4.243e-11" in_port="iopad.inpad" out_port="io.inpad"/>
</direct>
</interconnect>
</mode>
<!-- IOs can operate as either inputs or outputs.
Delays below come from Ian Kuon. They are small, so they should be interpreted as
the delays to and from registers in the I/O (and generally I/Os are registered
today and that is when you timing analyze them.
-->
<mode name="inpad">
<pb_type name="inpad" blif_model=".input" num_pb="1">
<output name="inpad" num_pins="1"/>
</pb_type>
<interconnect>
<direct name="inpad" input="inpad.inpad" output="io.inpad">
<delay_constant max="4.243e-11" in_port="inpad.inpad" out_port="io.inpad"/>
</direct>
</interconnect>
</mode>
<mode name="outpad">
<pb_type name="outpad" blif_model=".output" num_pb="1">
<input name="outpad" num_pins="1"/>
</pb_type>
<interconnect>
<direct name="outpad" input="io.outpad" output="outpad.outpad">
<delay_constant max="1.394e-11" in_port="io.outpad" out_port="outpad.outpad"/>
</direct>
</interconnect>
</mode>
<!-- Every input pin is driven by 15% of the tracks in a channel, every output pin is driven by 10% of the tracks in a channel -->
<!-- IOs go on the periphery of the FPGA, for consistency,
make it physically equivalent on all sides so that only one definition of I/Os is needed.
If I do not make a physically equivalent definition, then I need to define 4 different I/Os, one for each side of the FPGA
-->
<!-- Place I/Os on the sides of the FPGA -->
<power method="ignore"/>
</pb_type>
<!-- Define I/O pads ends -->
<!-- Define general purpose logic block (CLB) begin -->
<!--- Area calculation: Total Stratix IV tile area is about 8100 um^2, and a minimum width transistor
area is 60 L^2 yields a tile area of 84375 MWTAs.
Routing at W=300 is 30481 MWTAs, leaving us with a total of 53000 MWTAs for logic block area
This means that only 37% of our area is in the general routing, and 63% is inside the logic
block. Note that the crossbar / local interconnect is considered part of the logic block
area in this analysis. That is a lower proportion of of routing area than most academics
assume, but note that the total routing area really includes the crossbar, which would push
routing area up significantly, we estimate into the ~70% range.
-->
<pb_type name="clb">
<input name="I" num_pins="10" equivalent="full"/>
<output name="O" num_pins="4" equivalent="none"/>
<clock name="clk" num_pins="4"/>
<!-- Describe basic logic element.
Each basic logic element has a 4-LUT that can be optionally registered
-->
<pb_type name="fle" num_pb="4">
<input name="in" num_pins="4"/>
<output name="out" num_pins="1"/>
<clock name="clk" num_pins="1"/>
<!-- 4-LUT mode definition begin -->
<mode name="n1_lut4">
<!-- Define 4-LUT mode -->
<pb_type name="ble4" num_pb="1">
<input name="in" num_pins="4"/>
<output name="out" num_pins="1"/>
<clock name="clk" num_pins="1"/>
<!-- Define LUT -->
<pb_type name="lut4" blif_model=".names" num_pb="1" class="lut">
<input name="in" num_pins="4" port_class="lut_in"/>
<output name="out" num_pins="1" port_class="lut_out"/>
<!-- LUT timing using delay matrix -->
<delay_matrix type="max" in_port="lut4.in" out_port="lut4.out">
261e-12
261e-12
261e-12
261e-12
</delay_matrix>
</pb_type>
<!-- Define flip-flop -->
<pb_type name="ff" blif_model=".latch" num_pb="1" class="flipflop">
<input name="D" num_pins="1" port_class="D"/>
<output name="Q" num_pins="1" port_class="Q"/>
<clock name="clk" num_pins="1" port_class="clock"/>
<T_setup value="66e-12" port="ff.D" clock="clk"/>
<T_clock_to_Q max="124e-12" port="ff.Q" clock="clk"/>
</pb_type>
<interconnect>
<direct name="direct1" input="ble4.in" output="lut4[0:0].in"/>
<direct name="direct2" input="lut4.out" output="ff.D">
<!-- Advanced user option that tells CAD tool to find LUT+FF pairs in netlist -->
<pack_pattern name="ble4" in_port="lut4.out" out_port="ff.D"/>
</direct>
<direct name="direct3" input="ble4.clk" output="ff.clk"/>
<mux name="mux1" input="ff.Q lut4.out" output="ble4.out">
<!-- LUT to output is faster than FF to output on a Stratix IV -->
<delay_constant max="25e-12" in_port="lut4.out" out_port="ble4.out"/>
<delay_constant max="45e-12" in_port="ff.Q" out_port="ble4.out"/>
</mux>
</interconnect>
</pb_type>
<interconnect>
<direct name="direct1" input="fle.in" output="ble4.in"/>
<direct name="direct2" input="ble4.out" output="fle.out[0:0]"/>
<direct name="direct3" input="fle.clk" output="ble4.clk"/>
</interconnect>
</mode>
<!-- 6-LUT mode definition end -->
</pb_type>
<interconnect>
<!-- We use a full crossbar to get logical equivalence at inputs of CLB
The delays below come from Stratix IV. the delay through a connection block
input mux + the crossbar in Stratix IV is 167 ps. We already have a 72 ps
delay on the connection block input mux (modeled by Ian Kuon), so the remaining
delay within the crossbar is 95 ps.
The delays of cluster feedbacks in Stratix IV is 100 ps, when driven by a LUT.
Since all our outputs LUT outputs go to a BLE output, and have a delay of
25 ps to do so, we subtract 25 ps from the 100 ps delay of a feedback
to get the part that should be marked on the crossbar. -->
<complete name="crossbar" input="clb.I fle[3:0].out" output="fle[3:0].in">
<delay_constant max="95e-12" in_port="clb.I" out_port="fle[3:0].in"/>
<delay_constant max="75e-12" in_port="fle[3:0].out" out_port="fle[3:0].in"/>
</complete>
<complete name="clks" input="clb.clk" output="fle[3:0].clk">
</complete>
<!-- This way of specifying direct connection to clb outputs is important because this architecture uses automatic spreading of opins.
By grouping to output pins in this fashion, if a logic block is completely filled by 6-LUTs,
then the outputs those 6-LUTs take get evenly distributed across all four sides of the CLB instead of clumped on two sides (which is what happens with a more
naive specification).
-->
<direct name="clbouts1" input="fle[3:0].out" output="clb.O"/>
</interconnect>
<!-- Every input pin is driven by 15% of the tracks in a channel, every output pin is driven by 10% of the tracks in a channel -->
<!-- Place this general purpose logic block in any unspecified column -->
</pb_type>
<!-- Define general purpose logic block (CLB) ends -->
</complexblocklist>
</architecture>

2
yosys

@ -1 +1 @@
Subproject commit a0606e09f57df456ba9bcfc6a7cf7b64d814b8e4
Subproject commit 14b993449d5b6e37d69ff523356d05941a78b66e