Merge remote-tracking branch 'origin/master' into github-action-optimizations
This commit is contained in:
commit
cb80a9bbd4
|
@ -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";
|
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_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_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";
|
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
|
python3 openfpga_flow/scripts/run_fpga_task.py quicklogic_tests/flow_test --debug --show_thread_logs
|
||||||
|
|
|
@ -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`.
|
- ``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
|
Physical Tile Annotation
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -136,6 +136,8 @@ Pass Gate Logic
|
||||||
.. note:: pass-gate logic are used in building multiplexers and LUTs.
|
.. note:: pass-gate logic are used in building multiplexers and LUTs.
|
||||||
|
|
||||||
|
|
||||||
|
.. _circuit_library_circuit_port:
|
||||||
|
|
||||||
Circuit Port
|
Circuit Port
|
||||||
^^^^^^^^^^^^
|
^^^^^^^^^^^^
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,10 @@ General organization is as follows
|
||||||
|
|
||||||
<openfpga_simulation_setting>
|
<openfpga_simulation_setting>
|
||||||
<clock_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>"/>
|
<programming frequency="<int>"/>
|
||||||
</clock_setting>
|
</clock_setting>
|
||||||
<simulator_option>
|
<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
|
.. code-block:: xml
|
||||||
|
|
||||||
<clock_setting>
|
<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>"/>
|
<programming frequency="<float>"/>
|
||||||
</clock_setting>
|
</clock_setting>
|
||||||
|
|
||||||
Operating clock setting
|
Operating clock setting
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
Operating clocks are defined under the XML node ``<operating>``
|
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>"/>
|
.. 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
|
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``.
|
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>"``
|
- ``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.
|
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.
|
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!
|
.. 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 clock setting
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
Programming clocks are defined under the XML node ``<programming>``
|
Programming clocks are defined under the XML node ``<programming>``
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
File Formats
|
||||||
|
------------
|
||||||
|
|
||||||
|
OpenFPGA widely uses XML format for interchangable files
|
||||||
|
|
||||||
|
|
||||||
|
.. _file_formats:
|
||||||
|
File formats
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
pin_constraints_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.
|
|
@ -12,3 +12,5 @@ FPGA-Bitstream can generate two types of bitstreams:
|
||||||
generic_bitstream
|
generic_bitstream
|
||||||
|
|
||||||
fabric_dependent_bitstream
|
fabric_dependent_bitstream
|
||||||
|
|
||||||
|
repack_design_constraints
|
||||||
|
|
|
@ -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
|
|
@ -16,3 +16,5 @@
|
||||||
|
|
||||||
fpga_bitstream/index
|
fpga_bitstream/index
|
||||||
|
|
||||||
|
file_formats/index
|
||||||
|
|
||||||
|
|
|
@ -6,11 +6,28 @@ FPGA-Bitstream
|
||||||
repack
|
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
|
build_architecture_bitstream
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
|
@ -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
|
- ``--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.
|
- ``--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.
|
.. 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.
|
||||||
|
|
|
@ -4,4 +4,6 @@ add_subdirectory(libopenfpgashell)
|
||||||
add_subdirectory(libarchopenfpga)
|
add_subdirectory(libarchopenfpga)
|
||||||
add_subdirectory(libopenfpgautil)
|
add_subdirectory(libopenfpgautil)
|
||||||
add_subdirectory(libfabrickey)
|
add_subdirectory(libfabrickey)
|
||||||
|
add_subdirectory(librepackdc)
|
||||||
add_subdirectory(libfpgabitstream)
|
add_subdirectory(libfpgabitstream)
|
||||||
|
add_subdirectory(libpcf)
|
||||||
|
|
|
@ -12,6 +12,9 @@
|
||||||
/* Headers from vtr util library */
|
/* Headers from vtr util library */
|
||||||
#include "vtr_assert.h"
|
#include "vtr_assert.h"
|
||||||
|
|
||||||
|
/* Headers from openfpga util library */
|
||||||
|
#include "openfpga_port_parser.h"
|
||||||
|
|
||||||
/* Headers from libarchfpga */
|
/* Headers from libarchfpga */
|
||||||
#include "arch_error.h"
|
#include "arch_error.h"
|
||||||
#include "read_xml_util.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;
|
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
|
* 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 */
|
/* Parse operating clock setting */
|
||||||
pugi::xml_node xml_operating_clock_setting = get_single_child(xml_clock_setting, "operating", loc_data);
|
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
|
/* Parse number of clock cycles to be used in simulation
|
||||||
* Valid keywords is "auto" or other integer larger than 0
|
* 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.));
|
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 */
|
/* Parse programming clock setting */
|
||||||
pugi::xml_node xml_programming_clock_setting = get_single_child(xml_clock_setting, "programming", loc_data);
|
pugi::xml_node xml_programming_clock_setting = get_single_child(xml_clock_setting, "programming", loc_data);
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,13 @@ namespace openfpga {
|
||||||
* Member functions for class SimulationSetting
|
* 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
|
* Constructors
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
|
@ -19,12 +26,31 @@ SimulationSetting::SimulationSetting() {
|
||||||
/************************************************************************
|
/************************************************************************
|
||||||
* Public Accessors
|
* Public Accessors
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
float SimulationSetting::operating_clock_frequency() const {
|
float SimulationSetting::default_operating_clock_frequency() const {
|
||||||
return clock_frequencies_.x();
|
return default_clock_frequencies_.x();
|
||||||
}
|
}
|
||||||
|
|
||||||
float SimulationSetting::programming_clock_frequency() const {
|
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 {
|
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
|
* Public Mutators
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
void SimulationSetting::set_operating_clock_frequency(const float& clock_freq) {
|
void SimulationSetting::set_default_operating_clock_frequency(const float& clock_freq) {
|
||||||
clock_frequencies_.set_x(clock_freq);
|
default_clock_frequencies_.set_x(clock_freq);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimulationSetting::set_programming_clock_frequency(const float& 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) {
|
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);
|
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 */
|
} /* namespace openfpga ends */
|
||||||
|
|
|
@ -7,9 +7,15 @@
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include "vtr_vector.h"
|
||||||
#include "vtr_geometry.h"
|
#include "vtr_geometry.h"
|
||||||
|
|
||||||
|
#include "openfpga_port.h"
|
||||||
|
|
||||||
|
#include "simulation_setting_fwd.h"
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* Types of signal type in measurement and stimuli
|
* Types of signal type in measurement and stimuli
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
|
@ -48,11 +54,21 @@ namespace openfpga {
|
||||||
*
|
*
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
class SimulationSetting {
|
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 */
|
public: /* Constructors */
|
||||||
SimulationSetting();
|
SimulationSetting();
|
||||||
|
public: /* Accessors: aggregates */
|
||||||
|
simulation_clock_range clocks() const;
|
||||||
public: /* Public Accessors */
|
public: /* Public Accessors */
|
||||||
float operating_clock_frequency() const;
|
float default_operating_clock_frequency() const;
|
||||||
float programming_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;
|
bool auto_select_num_clock_cycles() const;
|
||||||
size_t num_clock_cycles() const;
|
size_t num_clock_cycles() const;
|
||||||
float operating_clock_frequency_slack() 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;
|
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;
|
float stimuli_input_slew(const e_sim_signal_type& signal_type) const;
|
||||||
public: /* Public Mutators */
|
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);
|
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_num_clock_cycles(const size_t& num_clk_cycles);
|
||||||
void set_operating_clock_frequency_slack(const float& op_clk_freq_slack);
|
void set_operating_clock_frequency_slack(const float& op_clk_freq_slack);
|
||||||
void set_simulation_temperature(const float& sim_temp);
|
void set_simulation_temperature(const float& sim_temp);
|
||||||
|
@ -102,13 +129,30 @@ class SimulationSetting {
|
||||||
const float& input_slew);
|
const float& input_slew);
|
||||||
public: /* Public Validators */
|
public: /* Public Validators */
|
||||||
bool valid_signal_threshold(const float& threshold) const;
|
bool valid_signal_threshold(const float& threshold) const;
|
||||||
|
bool valid_clock_id(const SimulationClockId& clock_id) const;
|
||||||
private: /* Internal data */
|
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
|
* 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
|
* 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
|
* 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
|
/* Number of clock cycles to be used in simulation
|
||||||
* If the value is 0, the clock cycles can be automatically
|
* If the value is 0, the clock cycles can be automatically
|
||||||
|
|
|
@ -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
|
|
@ -27,7 +27,7 @@ void write_xml_clock_setting(std::fstream& fp,
|
||||||
fp << "\t" << "<clock_setting>" << "\n";
|
fp << "\t" << "<clock_setting>" << "\n";
|
||||||
|
|
||||||
fp << "\t\t" << "<operating";
|
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()) {
|
if (true == sim_setting.auto_select_num_clock_cycles()) {
|
||||||
write_xml_attribute(fp, "num_cycles", "auto");
|
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());
|
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";
|
fp << "\t\t" << "<operating";
|
||||||
write_xml_attribute(fp, "frequency", sim_setting.programming_clock_frequency());
|
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) {
|
const openfpga::SimulationSetting& sim_setting) {
|
||||||
/* Validate the file stream */
|
/* Validate the file stream */
|
||||||
openfpga::check_file_stream(fname, fp);
|
openfpga::check_file_stream(fname, fp);
|
||||||
|
|
||||||
/* Write the root node <openfpga_simulation_setting>
|
/* Write the root node <openfpga_simulation_setting>
|
||||||
*/
|
*/
|
||||||
fp << "<openfpga_simulation_setting>" << "\n";
|
fp << "<openfpga_simulation_setting>" << "\n";
|
||||||
|
|
|
@ -17,25 +17,6 @@
|
||||||
/* namespace openfpga begins */
|
/* namespace openfpga begins */
|
||||||
namespace openfpga {
|
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
|
* 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) {
|
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 ";
|
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, "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, "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());
|
write_xml_attribute(fp, "y", tile_annotation.global_port_tile_coordinates(global_port_id)[tile_info_id].y());
|
||||||
fp << "/>";
|
fp << "/>";
|
||||||
|
|
|
@ -90,3 +90,21 @@ void write_xml_attribute(std::fstream& fp,
|
||||||
fp << std::scientific << value;
|
fp << std::scientific << value;
|
||||||
fp << "\"";
|
fp << "\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* FIXME: Use a common function to output ports
|
||||||
|
* Generate the full hierarchy name for a operating pb_type
|
||||||
|
*******************************************************************/
|
||||||
|
std::string generate_xml_port_name(const openfpga::BasicPort& pb_port) {
|
||||||
|
std::string port_name;
|
||||||
|
|
||||||
|
/* Output format: <port_name>[<LSB>:<MSB>] */
|
||||||
|
port_name += pb_port.get_name();
|
||||||
|
port_name += std::string("[");
|
||||||
|
port_name += std::to_string(pb_port.get_lsb());
|
||||||
|
port_name += std::string(":");
|
||||||
|
port_name += std::to_string(pb_port.get_msb());
|
||||||
|
port_name += std::string("]");
|
||||||
|
|
||||||
|
return port_name;
|
||||||
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include "circuit_library.h"
|
#include "circuit_library.h"
|
||||||
|
#include "openfpga_port.h"
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* Function declaration
|
* Function declaration
|
||||||
|
@ -30,4 +31,6 @@ void write_xml_attribute(std::fstream& fp,
|
||||||
const char* attr,
|
const char* attr,
|
||||||
const size_t& value);
|
const size_t& value);
|
||||||
|
|
||||||
|
std::string generate_xml_port_name(const openfpga::BasicPort& pb_port);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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})
|
|
@ -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>
|
||||||
|
|
|
@ -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] );
|
||||||
|
}
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
|
@ -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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -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})
|
|
@ -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>
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
|
@ -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] );
|
||||||
|
}
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
|
@ -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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,8 +23,10 @@ target_link_libraries(libopenfpga
|
||||||
libopenfpgashell
|
libopenfpgashell
|
||||||
libopenfpgautil
|
libopenfpgautil
|
||||||
libfabrickey
|
libfabrickey
|
||||||
|
librepackdc
|
||||||
libfpgabitstream
|
libfpgabitstream
|
||||||
libini
|
libini
|
||||||
|
libpcf
|
||||||
libvtrutil
|
libvtrutil
|
||||||
libvpr)
|
libvpr)
|
||||||
|
|
||||||
|
|
|
@ -191,7 +191,7 @@ int annotate_simulation_setting(const AtomContext& atom_ctx,
|
||||||
SimulationSetting& sim_setting) {
|
SimulationSetting& sim_setting) {
|
||||||
|
|
||||||
/* Find if the operating frequency is binded to vpr results */
|
/* 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");
|
VTR_LOG("User specified the operating clock frequency to use VPR results\n");
|
||||||
/* Run timing analysis and collect critical path delay
|
/* Run timing analysis and collect critical path delay
|
||||||
* This code is copied from function vpr_analysis() in vpr_api.h
|
* 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 */
|
/* Get critical path delay. Update simulation settings */
|
||||||
float T_crit = timing_info->least_slack_critical_path().delay() * (1. + sim_setting.operating_clock_frequency_slack());
|
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",
|
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);
|
T_crit / 1e9, sim_setting.operating_clock_frequency_slack() * 100);
|
||||||
}
|
}
|
||||||
VTR_LOG("Will apply operating clock frequency %g [MHz] to simulations\n",
|
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()) {
|
if (0. == sim_setting.num_clock_cycles()) {
|
||||||
/* Find the number of clock cycles to be used in simulation
|
/* Find the number of clock cycles to be used in simulation
|
||||||
|
|
|
@ -21,6 +21,9 @@ ShellCommandId add_openfpga_repack_command(openfpga::Shell<OpenfpgaContext>& she
|
||||||
const ShellCommandClassId& cmd_class_id,
|
const ShellCommandClassId& cmd_class_id,
|
||||||
const std::vector<ShellCommandId>& dependent_cmds) {
|
const std::vector<ShellCommandId>& dependent_cmds) {
|
||||||
Command shell_cmd("repack");
|
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' */
|
/* Add an option '--verbose' */
|
||||||
shell_cmd.add_option("verbose", false, "Enable verbose output");
|
shell_cmd.add_option("verbose", false, "Enable verbose output");
|
||||||
|
|
||||||
|
|
|
@ -8,10 +8,15 @@
|
||||||
/* Headers from openfpgashell library */
|
/* Headers from openfpgashell library */
|
||||||
#include "command_exit_codes.h"
|
#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 "build_physical_truth_table.h"
|
||||||
#include "repack.h"
|
#include "repack.h"
|
||||||
#include "openfpga_repack.h"
|
#include "openfpga_repack.h"
|
||||||
|
|
||||||
|
|
||||||
/* Include global variables of VPR */
|
/* Include global variables of VPR */
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
|
|
||||||
|
@ -24,13 +29,23 @@ namespace openfpga {
|
||||||
int repack(OpenfpgaContext& openfpga_ctx,
|
int repack(OpenfpgaContext& openfpga_ctx,
|
||||||
const Command& cmd, const CommandContext& cmd_context) {
|
const Command& cmd, const CommandContext& cmd_context) {
|
||||||
|
|
||||||
|
CommandOptionId opt_design_constraints = cmd.option("design_constraints");
|
||||||
CommandOptionId opt_verbose = cmd.option("verbose");
|
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(),
|
pack_physical_pbs(g_vpr_ctx.device(),
|
||||||
g_vpr_ctx.atom(),
|
g_vpr_ctx.atom(),
|
||||||
g_vpr_ctx.clustering(),
|
g_vpr_ctx.clustering(),
|
||||||
openfpga_ctx.mutable_vpr_device_annotation(),
|
openfpga_ctx.mutable_vpr_device_annotation(),
|
||||||
openfpga_ctx.mutable_vpr_clustering_annotation(),
|
openfpga_ctx.mutable_vpr_clustering_annotation(),
|
||||||
|
repack_design_constraints,
|
||||||
cmd_context.option_enable(cmd, opt_verbose));
|
cmd_context.option_enable(cmd, opt_verbose));
|
||||||
|
|
||||||
build_physical_lut_truth_tables(openfpga_ctx.mutable_vpr_clustering_annotation(),
|
build_physical_lut_truth_tables(openfpga_ctx.mutable_vpr_clustering_annotation(),
|
||||||
|
|
|
@ -83,8 +83,6 @@ int write_pnr_sdc(const OpenfpgaContext& openfpga_ctx,
|
||||||
/* Execute only when sdc is enabled */
|
/* Execute only when sdc is enabled */
|
||||||
if (true == options.generate_sdc_pnr()) {
|
if (true == options.generate_sdc_pnr()) {
|
||||||
print_pnr_sdc(options,
|
print_pnr_sdc(options,
|
||||||
1./openfpga_ctx.simulation_setting().programming_clock_frequency(),
|
|
||||||
1./openfpga_ctx.simulation_setting().operating_clock_frequency(),
|
|
||||||
g_vpr_ctx.device(),
|
g_vpr_ctx.device(),
|
||||||
openfpga_ctx.vpr_device_annotation(),
|
openfpga_ctx.vpr_device_annotation(),
|
||||||
openfpga_ctx.device_rr_gsb(),
|
openfpga_ctx.device_rr_gsb(),
|
||||||
|
@ -92,6 +90,7 @@ int write_pnr_sdc(const OpenfpgaContext& openfpga_ctx,
|
||||||
openfpga_ctx.mux_lib(),
|
openfpga_ctx.mux_lib(),
|
||||||
openfpga_ctx.arch().circuit_lib,
|
openfpga_ctx.arch().circuit_lib,
|
||||||
openfpga_ctx.fabric_global_port_info(),
|
openfpga_ctx.fabric_global_port_info(),
|
||||||
|
openfpga_ctx.simulation_setting(),
|
||||||
openfpga_ctx.flow_manager().compress_routing());
|
openfpga_ctx.flow_manager().compress_routing());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +189,7 @@ int write_analysis_sdc(const OpenfpgaContext& openfpga_ctx,
|
||||||
|
|
||||||
if (true == options.generate_sdc_analysis()) {
|
if (true == options.generate_sdc_analysis()) {
|
||||||
print_analysis_sdc(options,
|
print_analysis_sdc(options,
|
||||||
1./openfpga_ctx.simulation_setting().operating_clock_frequency(),
|
1./openfpga_ctx.simulation_setting().default_operating_clock_frequency(),
|
||||||
g_vpr_ctx,
|
g_vpr_ctx,
|
||||||
openfpga_ctx,
|
openfpga_ctx,
|
||||||
openfpga_ctx.flow_manager().compress_routing());
|
openfpga_ctx.flow_manager().compress_routing());
|
||||||
|
|
|
@ -11,6 +11,9 @@
|
||||||
#include "verilog_api.h"
|
#include "verilog_api.h"
|
||||||
#include "openfpga_verilog.h"
|
#include "openfpga_verilog.h"
|
||||||
|
|
||||||
|
/* Headers from pcf library */
|
||||||
|
#include "read_xml_pin_constraints.h"
|
||||||
|
|
||||||
/* Include global variables of VPR */
|
/* Include global variables of VPR */
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
|
|
||||||
|
@ -62,6 +65,7 @@ int write_verilog_testbench(OpenfpgaContext& openfpga_ctx,
|
||||||
|
|
||||||
CommandOptionId opt_output_dir = cmd.option("file");
|
CommandOptionId opt_output_dir = cmd.option("file");
|
||||||
CommandOptionId opt_fabric_netlist = cmd.option("fabric_netlist_file_path");
|
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_reference_benchmark = cmd.option("reference_benchmark_file_path");
|
||||||
CommandOptionId opt_print_top_testbench = cmd.option("print_top_testbench");
|
CommandOptionId opt_print_top_testbench = cmd.option("print_top_testbench");
|
||||||
CommandOptionId opt_fast_configuration = cmd.option("fast_configuration");
|
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_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_support_icarus_simulator(cmd_context.option_enable(cmd, opt_support_icarus_simulator));
|
||||||
options.set_verbose_output(cmd_context.option_enable(cmd, opt_verbose));
|
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 */
|
/* If pin constraints are enabled by command options, read the file */
|
||||||
return CMD_EXEC_SUCCESS;
|
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 */
|
} /* end namespace openfpga */
|
||||||
|
|
|
@ -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");
|
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);
|
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'*/
|
/* 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");
|
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);
|
shell_cmd.set_option_require_value(ref_bm_opt, openfpga::OPT_STRING);
|
||||||
|
|
|
@ -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 */
|
/* Find the port of the grid module according to the tile annotation */
|
||||||
int grid_pin_start_index = physical_tile->num_pins;
|
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) {
|
for (const t_physical_tile_port& tile_port : physical_tile->ports) {
|
||||||
if (std::string(tile_port.name) == tile_port_to_connect.get_name()) {
|
if (std::string(tile_port.name) == tile_port_to_connect.get_name()) {
|
||||||
BasicPort ref_tile_port(tile_port.name, tile_port.num_pins);
|
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;
|
return CMD_EXEC_FATAL_ERROR;
|
||||||
}
|
}
|
||||||
grid_pin_start_index = tile_port.absolute_first_pin_index;
|
grid_pin_start_index = tile_port.absolute_first_pin_index;
|
||||||
|
physical_tile_port = tile_port;
|
||||||
break;
|
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());
|
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 */
|
/* A tile may consist of multiple subtile, connect to all the pins from sub tiles */
|
||||||
for (int iz = 0; iz < physical_tile->capacity; ++iz) {
|
for (int iz = 0; iz < physical_tile->capacity; ++iz) {
|
||||||
/* TODO: This should be replaced by using a pin mapping data structure from physical tile! */
|
for (size_t pin_id = 0; pin_id < size_t(physical_tile_port.num_pins); ++pin_id) {
|
||||||
int grid_pin_index = grid_pin_start_index + iz * physical_tile->equivalent_sites[0]->pb_type->num_pins;
|
/* TODO: This should be replaced by using a pin mapping data structure from physical tile! */
|
||||||
/* Find the module pin */
|
int grid_pin_index = grid_pin_start_index + iz * physical_tile->equivalent_sites[0]->pb_type->num_pins + pin_id;
|
||||||
size_t grid_pin_width = physical_tile->pin_width_offset[grid_pin_index];
|
/* Find the module pin */
|
||||||
size_t grid_pin_height = physical_tile->pin_height_offset[grid_pin_index];
|
size_t grid_pin_width = physical_tile->pin_width_offset[grid_pin_index];
|
||||||
std::vector<e_side> pin_sides = find_physical_tile_pin_side(physical_tile, grid_pin_index, border_side);
|
size_t grid_pin_height = physical_tile->pin_height_offset[grid_pin_index];
|
||||||
for (const e_side& pin_side : pin_sides) {
|
std::vector<e_side> pin_sides = find_physical_tile_pin_side(physical_tile, grid_pin_index, border_side);
|
||||||
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));
|
|
||||||
|
|
||||||
/* Build nets */
|
/* Build nets */
|
||||||
BasicPort src_port = module_manager.module_port(top_module, top_module_port);
|
for (const e_side& pin_side : pin_sides) {
|
||||||
for (size_t pin_id = 0; pin_id < tile_port_to_connect.pins().size(); ++pin_id) {
|
std::string grid_port_name = generate_grid_port_name(grid_coordinate,
|
||||||
ModuleNetId net = create_module_source_pin_net(module_manager, top_module,
|
grid_pin_width, grid_pin_height,
|
||||||
top_module, 0,
|
pin_side,
|
||||||
top_module_port, src_port.pins()[pin_id]);
|
grid_pin_index, false);
|
||||||
VTR_ASSERT(ModuleNetId::INVALID() != net);
|
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));
|
||||||
/* 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]);
|
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]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
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));
|
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(),
|
print_analysis_sdc_io_delays(fp, option.time_unit(),
|
||||||
vpr_ctx.atom(), vpr_ctx.placement(),
|
vpr_ctx.atom(), vpr_ctx.placement(),
|
||||||
openfpga_ctx.vpr_netlist_annotation(), openfpga_ctx.io_location_map(),
|
openfpga_ctx.vpr_netlist_annotation(), openfpga_ctx.io_location_map(),
|
||||||
|
|
|
@ -59,11 +59,10 @@ void print_pnr_sdc_clock_port(std::fstream& fp,
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
static
|
static
|
||||||
void print_pnr_sdc_global_clock_ports(std::fstream& fp,
|
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 ModuleManager& module_manager,
|
||||||
const ModuleId& top_module,
|
const ModuleId& top_module,
|
||||||
const FabricGlobalPortInfo& fabric_global_port_info) {
|
const FabricGlobalPortInfo& fabric_global_port_info,
|
||||||
|
const SimulationSetting& sim_setting) {
|
||||||
|
|
||||||
valid_file_stream(fp);
|
valid_file_stream(fp);
|
||||||
|
|
||||||
|
@ -73,11 +72,11 @@ void print_pnr_sdc_global_clock_ports(std::fstream& fp,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* Reach here, it means a clock port and we need print constraints */
|
/* 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 */
|
/* For programming clock, we give a fixed period */
|
||||||
if (true == fabric_global_port_info.global_port_is_prog(global_port)) {
|
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 */
|
/* Print comments */
|
||||||
fp << "##################################################" << std::endl;
|
fp << "##################################################" << std::endl;
|
||||||
fp << "# Create programmable clock " << 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()) {
|
for (const size_t& pin : clock_port.pins()) {
|
||||||
BasicPort port_to_constrain(clock_port.get_name(), pin, pin);
|
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,
|
print_pnr_sdc_clock_port(fp,
|
||||||
port_to_constrain,
|
port_to_constrain,
|
||||||
clock_period);
|
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
|
* In general, we do not recommend to do this
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
void print_pnr_sdc_global_ports(const std::string& sdc_dir,
|
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 ModuleManager& module_manager,
|
||||||
const ModuleId& top_module,
|
const ModuleId& top_module,
|
||||||
const FabricGlobalPortInfo& global_ports,
|
const FabricGlobalPortInfo& global_ports,
|
||||||
|
const SimulationSetting& sim_setting,
|
||||||
const bool& constrain_non_clock_port) {
|
const bool& constrain_non_clock_port) {
|
||||||
|
|
||||||
/* Create the file name for Verilog netlist */
|
/* 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_sdc_file_header(fp, std::string("Clock contraints for PnR"));
|
||||||
|
|
||||||
print_pnr_sdc_global_clock_ports(fp,
|
print_pnr_sdc_global_clock_ports(fp,
|
||||||
programming_critical_path_delay,
|
|
||||||
operating_critical_path_delay,
|
|
||||||
module_manager, top_module,
|
module_manager, top_module,
|
||||||
global_ports);
|
global_ports, sim_setting);
|
||||||
|
|
||||||
if (true == constrain_non_clock_port) {
|
if (true == constrain_non_clock_port) {
|
||||||
print_pnr_sdc_global_non_clock_ports(fp,
|
print_pnr_sdc_global_non_clock_ports(fp,
|
||||||
operating_critical_path_delay,
|
1./sim_setting.default_operating_clock_frequency(),
|
||||||
module_manager, top_module,
|
module_manager, top_module,
|
||||||
global_ports);
|
global_ports);
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "module_manager.h"
|
#include "module_manager.h"
|
||||||
#include "fabric_global_port_info.h"
|
#include "fabric_global_port_info.h"
|
||||||
|
#include "simulation_setting.h"
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* Function declaration
|
* Function declaration
|
||||||
|
@ -17,11 +18,10 @@
|
||||||
namespace openfpga {
|
namespace openfpga {
|
||||||
|
|
||||||
void print_pnr_sdc_global_ports(const std::string& sdc_dir,
|
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 ModuleManager& module_manager,
|
||||||
const ModuleId& top_module,
|
const ModuleId& top_module,
|
||||||
const FabricGlobalPortInfo& global_ports,
|
const FabricGlobalPortInfo& global_ports,
|
||||||
|
const SimulationSetting& sim_setting,
|
||||||
const bool& constrain_non_clock_port);
|
const bool& constrain_non_clock_port);
|
||||||
|
|
||||||
} /* end namespace openfpga */
|
} /* end namespace openfpga */
|
||||||
|
|
|
@ -319,8 +319,6 @@ void print_pnr_sdc_compact_routing_disable_switch_block_outputs(const std::strin
|
||||||
* 4. Design constraints for breaking the combinational loops in FPGA fabric
|
* 4. Design constraints for breaking the combinational loops in FPGA fabric
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
void print_pnr_sdc(const PnrSdcOption& sdc_options,
|
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 DeviceContext& device_ctx,
|
||||||
const VprDeviceAnnotation& device_annotation,
|
const VprDeviceAnnotation& device_annotation,
|
||||||
const DeviceRRGSB& device_rr_gsb,
|
const DeviceRRGSB& device_rr_gsb,
|
||||||
|
@ -328,6 +326,7 @@ void print_pnr_sdc(const PnrSdcOption& sdc_options,
|
||||||
const MuxLibrary& mux_lib,
|
const MuxLibrary& mux_lib,
|
||||||
const CircuitLibrary& circuit_lib,
|
const CircuitLibrary& circuit_lib,
|
||||||
const FabricGlobalPortInfo& global_ports,
|
const FabricGlobalPortInfo& global_ports,
|
||||||
|
const SimulationSetting& sim_setting,
|
||||||
const bool& compact_routing_hierarchy) {
|
const bool& compact_routing_hierarchy) {
|
||||||
|
|
||||||
std::string top_module_name = generate_fpga_top_module_name();
|
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 */
|
/* Constrain global ports */
|
||||||
if (true == sdc_options.constrain_global_port()) {
|
if (true == sdc_options.constrain_global_port()) {
|
||||||
print_pnr_sdc_global_ports(sdc_options.sdc_dir(),
|
print_pnr_sdc_global_ports(sdc_options.sdc_dir(),
|
||||||
programming_critical_path_delay,
|
|
||||||
operating_critical_path_delay,
|
|
||||||
module_manager, top_module, global_ports,
|
module_manager, top_module, global_ports,
|
||||||
|
sim_setting,
|
||||||
sdc_options.constrain_non_clock_global_port());
|
sdc_options.constrain_non_clock_global_port());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "module_manager.h"
|
#include "module_manager.h"
|
||||||
#include "mux_library.h"
|
#include "mux_library.h"
|
||||||
#include "circuit_library.h"
|
#include "circuit_library.h"
|
||||||
|
#include "simulation_setting.h"
|
||||||
#include "fabric_global_port_info.h"
|
#include "fabric_global_port_info.h"
|
||||||
#include "pnr_sdc_option.h"
|
#include "pnr_sdc_option.h"
|
||||||
|
|
||||||
|
@ -23,8 +24,6 @@
|
||||||
namespace openfpga {
|
namespace openfpga {
|
||||||
|
|
||||||
void print_pnr_sdc(const PnrSdcOption& sdc_options,
|
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 DeviceContext& device_ctx,
|
||||||
const VprDeviceAnnotation& device_annotation,
|
const VprDeviceAnnotation& device_annotation,
|
||||||
const DeviceRRGSB& device_rr_gsb,
|
const DeviceRRGSB& device_rr_gsb,
|
||||||
|
@ -32,6 +31,7 @@ void print_pnr_sdc(const PnrSdcOption& sdc_options,
|
||||||
const MuxLibrary& mux_lib,
|
const MuxLibrary& mux_lib,
|
||||||
const CircuitLibrary& circuit_lib,
|
const CircuitLibrary& circuit_lib,
|
||||||
const FabricGlobalPortInfo& global_ports,
|
const FabricGlobalPortInfo& global_ports,
|
||||||
|
const SimulationSetting& sim_setting,
|
||||||
const bool& compact_routing_hierarchy);
|
const bool& compact_routing_hierarchy);
|
||||||
|
|
||||||
} /* end namespace openfpga */
|
} /* end namespace openfpga */
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
#include "vtr_assert.h"
|
#include "vtr_assert.h"
|
||||||
#include "vtr_time.h"
|
#include "vtr_time.h"
|
||||||
|
|
||||||
|
#include "command_exit_codes.h"
|
||||||
|
|
||||||
#include "circuit_library_utils.h"
|
#include "circuit_library_utils.h"
|
||||||
|
|
||||||
/* Headers from openfpgautil library */
|
/* 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.
|
* 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
|
* - Verilog netlist including preprocessing flags and all the Verilog netlists that have been generated
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
void fpga_verilog_testbench(const ModuleManager &module_manager,
|
int fpga_verilog_testbench(const ModuleManager &module_manager,
|
||||||
const BitstreamManager &bitstream_manager,
|
const BitstreamManager &bitstream_manager,
|
||||||
const FabricBitstream &fabric_bitstream,
|
const FabricBitstream &fabric_bitstream,
|
||||||
const AtomContext &atom_ctx,
|
const AtomContext &atom_ctx,
|
||||||
const PlacementContext &place_ctx,
|
const PlacementContext &place_ctx,
|
||||||
const IoLocationMap &io_location_map,
|
const PinConstraints& pin_constraints,
|
||||||
const FabricGlobalPortInfo &fabric_global_port_info,
|
const IoLocationMap &io_location_map,
|
||||||
const VprNetlistAnnotation &netlist_annotation,
|
const FabricGlobalPortInfo &fabric_global_port_info,
|
||||||
const CircuitLibrary &circuit_lib,
|
const VprNetlistAnnotation &netlist_annotation,
|
||||||
const SimulationSetting &simulation_setting,
|
const CircuitLibrary &circuit_lib,
|
||||||
const ConfigProtocol &config_protocol,
|
const SimulationSetting &simulation_setting,
|
||||||
const VerilogTestbenchOption &options) {
|
const ConfigProtocol &config_protocol,
|
||||||
|
const VerilogTestbenchOption &options) {
|
||||||
|
|
||||||
vtr::ScopedStartFinishTimer timer("Write Verilog testbenches for FPGA fabric\n");
|
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();
|
std::string netlist_name = atom_ctx.nlist.netlist_name();
|
||||||
|
|
||||||
|
int status = CMD_EXEC_SUCCESS;
|
||||||
|
|
||||||
/* Create directories */
|
/* Create directories */
|
||||||
create_directory(src_dir_path);
|
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 */
|
/* 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()) {
|
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);
|
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,
|
status = print_verilog_preconfig_top_module(module_manager, bitstream_manager,
|
||||||
config_protocol,
|
config_protocol,
|
||||||
circuit_lib, fabric_global_port_info,
|
circuit_lib, fabric_global_port_info,
|
||||||
atom_ctx, place_ctx, io_location_map,
|
atom_ctx, place_ctx,
|
||||||
netlist_annotation,
|
pin_constraints,
|
||||||
netlist_name,
|
io_location_map,
|
||||||
formal_verification_top_netlist_file_path,
|
netlist_annotation,
|
||||||
options.explicit_port_mapping());
|
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()) {
|
if (true == options.print_preconfig_top_testbench()) {
|
||||||
|
@ -193,6 +203,7 @@ void fpga_verilog_testbench(const ModuleManager &module_manager,
|
||||||
random_top_testbench_file_path,
|
random_top_testbench_file_path,
|
||||||
atom_ctx,
|
atom_ctx,
|
||||||
netlist_annotation,
|
netlist_annotation,
|
||||||
|
pin_constraints,
|
||||||
simulation_setting,
|
simulation_setting,
|
||||||
options.explicit_port_mapping());
|
options.explicit_port_mapping());
|
||||||
}
|
}
|
||||||
|
@ -205,7 +216,9 @@ void fpga_verilog_testbench(const ModuleManager &module_manager,
|
||||||
circuit_lib,
|
circuit_lib,
|
||||||
config_protocol,
|
config_protocol,
|
||||||
fabric_global_port_info,
|
fabric_global_port_info,
|
||||||
atom_ctx, place_ctx, io_location_map,
|
atom_ctx, place_ctx,
|
||||||
|
pin_constraints,
|
||||||
|
io_location_map,
|
||||||
netlist_annotation,
|
netlist_annotation,
|
||||||
netlist_name,
|
netlist_name,
|
||||||
top_testbench_file_path,
|
top_testbench_file_path,
|
||||||
|
@ -226,7 +239,7 @@ void fpga_verilog_testbench(const ModuleManager &module_manager,
|
||||||
bitstream_manager.num_bits(),
|
bitstream_manager.num_bits(),
|
||||||
simulation_setting.num_clock_cycles(),
|
simulation_setting.num_clock_cycles(),
|
||||||
simulation_setting.programming_clock_frequency(),
|
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 */
|
/* 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,
|
netlist_name,
|
||||||
options.fabric_netlist_file_path(),
|
options.fabric_netlist_file_path(),
|
||||||
options.reference_benchmark_file_path());
|
options.reference_benchmark_file_path());
|
||||||
|
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
} /* end namespace openfpga */
|
} /* end namespace openfpga */
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "bitstream_manager.h"
|
#include "bitstream_manager.h"
|
||||||
#include "fabric_bitstream.h"
|
#include "fabric_bitstream.h"
|
||||||
#include "simulation_setting.h"
|
#include "simulation_setting.h"
|
||||||
|
#include "pin_constraints.h"
|
||||||
#include "io_location_map.h"
|
#include "io_location_map.h"
|
||||||
#include "fabric_global_port_info.h"
|
#include "fabric_global_port_info.h"
|
||||||
#include "vpr_netlist_annotation.h"
|
#include "vpr_netlist_annotation.h"
|
||||||
|
@ -42,18 +43,19 @@ void fpga_fabric_verilog(ModuleManager& module_manager,
|
||||||
const DeviceRRGSB& device_rr_gsb,
|
const DeviceRRGSB& device_rr_gsb,
|
||||||
const FabricVerilogOption& options);
|
const FabricVerilogOption& options);
|
||||||
|
|
||||||
void fpga_verilog_testbench(const ModuleManager& module_manager,
|
int fpga_verilog_testbench(const ModuleManager& module_manager,
|
||||||
const BitstreamManager& bitstream_manager,
|
const BitstreamManager& bitstream_manager,
|
||||||
const FabricBitstream& fabric_bitstream,
|
const FabricBitstream& fabric_bitstream,
|
||||||
const AtomContext& atom_ctx,
|
const AtomContext& atom_ctx,
|
||||||
const PlacementContext& place_ctx,
|
const PlacementContext& place_ctx,
|
||||||
const IoLocationMap& io_location_map,
|
const PinConstraints& pin_constraints,
|
||||||
const FabricGlobalPortInfo &fabric_global_port_info,
|
const IoLocationMap& io_location_map,
|
||||||
const VprNetlistAnnotation& netlist_annotation,
|
const FabricGlobalPortInfo &fabric_global_port_info,
|
||||||
const CircuitLibrary& circuit_lib,
|
const VprNetlistAnnotation& netlist_annotation,
|
||||||
const SimulationSetting& simulation_parameters,
|
const CircuitLibrary& circuit_lib,
|
||||||
const ConfigProtocol& config_protocol,
|
const SimulationSetting& simulation_parameters,
|
||||||
const VerilogTestbenchOption& options);
|
const ConfigProtocol& config_protocol,
|
||||||
|
const VerilogTestbenchOption& options);
|
||||||
|
|
||||||
|
|
||||||
} /* end namespace openfpga */
|
} /* end namespace openfpga */
|
||||||
|
|
|
@ -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!
|
/* Create a clock port if the benchmark does not have one!
|
||||||
* The clock is used for counting and synchronizing input stimulus
|
* 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 -------"));
|
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 */
|
/* Add an empty line as splitter */
|
||||||
fp << std::endl;
|
fp << std::endl;
|
||||||
|
@ -192,6 +194,7 @@ void print_verilog_random_top_testbench(const std::string& circuit_name,
|
||||||
const std::string& verilog_fname,
|
const std::string& verilog_fname,
|
||||||
const AtomContext& atom_ctx,
|
const AtomContext& atom_ctx,
|
||||||
const VprNetlistAnnotation& netlist_annotation,
|
const VprNetlistAnnotation& netlist_annotation,
|
||||||
|
const PinConstraints& pin_constraints,
|
||||||
const SimulationSetting& simulation_parameters,
|
const SimulationSetting& simulation_parameters,
|
||||||
const bool& explicit_port_mapping) {
|
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("'");
|
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);
|
explicit_port_mapping);
|
||||||
|
|
||||||
/* Find clock port to be used */
|
/* 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 */
|
/* Add stimuli for reset, set, clock and iopad signals */
|
||||||
print_verilog_testbench_clock_stimuli(fp, simulation_parameters,
|
print_verilog_testbench_clock_stimuli(fp,
|
||||||
clock_port);
|
pin_constraints,
|
||||||
|
simulation_parameters,
|
||||||
|
clock_ports);
|
||||||
print_verilog_testbench_random_stimuli(fp, atom_ctx,
|
print_verilog_testbench_random_stimuli(fp, atom_ctx,
|
||||||
netlist_annotation,
|
netlist_annotation,
|
||||||
clock_port_names,
|
clock_port_names,
|
||||||
std::string(CHECKFLAG_PORT_POSTFIX),
|
std::string(CHECKFLAG_PORT_POSTFIX),
|
||||||
clock_port);
|
clock_ports);
|
||||||
|
|
||||||
print_verilog_testbench_check(fp,
|
print_verilog_testbench_check(fp,
|
||||||
std::string(AUTOCHECKED_SIMULATION_FLAG),
|
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,
|
float simulation_time = find_operating_phase_simulation_time(MAGIC_NUMBER_FOR_SIMULATION_TIME,
|
||||||
simulation_parameters.num_clock_cycles(),
|
simulation_parameters.num_clock_cycles(),
|
||||||
1./simulation_parameters.operating_clock_frequency(),
|
1./simulation_parameters.default_operating_clock_frequency(),
|
||||||
VERILOG_SIM_TIMESCALE);
|
VERILOG_SIM_TIMESCALE);
|
||||||
|
|
||||||
/* Add Icarus requirement */
|
/* Add Icarus requirement */
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "vpr_context.h"
|
#include "vpr_context.h"
|
||||||
|
#include "pin_constraints.h"
|
||||||
#include "simulation_setting.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 std::string& verilog_fname,
|
||||||
const AtomContext& atom_ctx,
|
const AtomContext& atom_ctx,
|
||||||
const VprNetlistAnnotation& netlist_annotation,
|
const VprNetlistAnnotation& netlist_annotation,
|
||||||
|
const PinConstraints& pin_constraints,
|
||||||
const SimulationSetting& simulation_parameters,
|
const SimulationSetting& simulation_parameters,
|
||||||
const bool& explicit_port_mapping);
|
const bool& explicit_port_mapping);
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
#include "vtr_log.h"
|
#include "vtr_log.h"
|
||||||
#include "vtr_time.h"
|
#include "vtr_time.h"
|
||||||
|
|
||||||
|
#include "command_exit_codes.h"
|
||||||
|
|
||||||
/* Headers from openfpgautil library */
|
/* Headers from openfpgautil library */
|
||||||
#include "openfpga_port.h"
|
#include "openfpga_port.h"
|
||||||
#include "openfpga_digest.h"
|
#include "openfpga_digest.h"
|
||||||
|
@ -24,254 +26,218 @@
|
||||||
#include "verilog_preconfig_top_module.h"
|
#include "verilog_preconfig_top_module.h"
|
||||||
|
|
||||||
/* begin namespace openfpga */
|
/* begin namespace openfpga */
|
||||||
namespace openfpga
|
namespace openfpga {
|
||||||
{
|
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* Print module declaration and ports for the pre-configured
|
* Print module declaration and ports for the pre-configured
|
||||||
* FPGA top module
|
* FPGA top module
|
||||||
* The module ports do exactly match the input benchmark
|
* The module ports do exactly match the input benchmark
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
static void print_verilog_preconfig_top_module_ports(std::fstream &fp,
|
static
|
||||||
const std::string &circuit_name,
|
void print_verilog_preconfig_top_module_ports(std::fstream &fp,
|
||||||
const AtomContext &atom_ctx,
|
const std::string &circuit_name,
|
||||||
const VprNetlistAnnotation &netlist_annotation)
|
const AtomContext &atom_ctx,
|
||||||
{
|
const VprNetlistAnnotation &netlist_annotation) {
|
||||||
|
|
||||||
/* Validate the file stream */
|
/* Validate the file stream */
|
||||||
valid_file_stream(fp);
|
valid_file_stream(fp);
|
||||||
|
|
||||||
/* Module declaration */
|
/* Module declaration */
|
||||||
fp << "module " << circuit_name << std::string(FORMAL_VERIFICATION_TOP_MODULE_POSTFIX);
|
fp << "module " << circuit_name << std::string(FORMAL_VERIFICATION_TOP_MODULE_POSTFIX);
|
||||||
fp << " (" << std::endl;
|
fp << " (" << std::endl;
|
||||||
|
|
||||||
/* Add module ports */
|
/* Add module ports */
|
||||||
size_t port_counter = 0;
|
size_t port_counter = 0;
|
||||||
|
|
||||||
/* Port type-to-type mapping */
|
/* Port type-to-type mapping */
|
||||||
std::map<AtomBlockType, enum e_dump_verilog_port_type> port_type2type_map;
|
std::map<AtomBlockType, enum e_dump_verilog_port_type> port_type2type_map;
|
||||||
port_type2type_map[AtomBlockType::INPAD] = VERILOG_PORT_INPUT;
|
port_type2type_map[AtomBlockType::INPAD] = VERILOG_PORT_INPUT;
|
||||||
port_type2type_map[AtomBlockType::OUTPAD] = VERILOG_PORT_OUTPUT;
|
port_type2type_map[AtomBlockType::OUTPAD] = VERILOG_PORT_OUTPUT;
|
||||||
|
|
||||||
/* Print all the I/Os of the circuit implementation to be tested*/
|
/* Print all the I/Os of the circuit implementation to be tested*/
|
||||||
for (const AtomBlockId &atom_blk : atom_ctx.nlist.blocks())
|
for (const AtomBlockId &atom_blk : atom_ctx.nlist.blocks()) {
|
||||||
{
|
/* We only care I/O logical 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))) {
|
||||||
if ((AtomBlockType::INPAD != atom_ctx.nlist.block_type(atom_blk)) && (AtomBlockType::OUTPAD != atom_ctx.nlist.block_type(atom_blk)))
|
continue;
|
||||||
{
|
|
||||||
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++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 */
|
if (0 < port_counter) {
|
||||||
fp << std::endl;
|
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
|
* Print internal wires for the pre-configured FPGA top module
|
||||||
* The internal wires are tailored for the ports of FPGA top module
|
* The internal wires are tailored for the ports of FPGA top module
|
||||||
* which will be different in various configuration protocols
|
* which will be different in various configuration protocols
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
static void print_verilog_preconfig_top_module_internal_wires(std::fstream &fp,
|
static
|
||||||
const ModuleManager &module_manager,
|
void print_verilog_preconfig_top_module_internal_wires(std::fstream &fp,
|
||||||
const ModuleId &top_module)
|
const ModuleManager &module_manager,
|
||||||
{
|
const ModuleId &top_module) {
|
||||||
/* Validate the file stream */
|
/* Validate the file stream */
|
||||||
valid_file_stream(fp);
|
valid_file_stream(fp);
|
||||||
|
|
||||||
/* Global ports of top-level module */
|
/* Global ports of top-level module */
|
||||||
print_verilog_comment(fp, std::string("----- Local wires for FPGA fabric -----"));
|
print_verilog_comment(fp, std::string("----- Local wires for FPGA fabric -----"));
|
||||||
for (const ModulePortId &module_port_id : module_manager.module_ports(top_module))
|
for (const ModulePortId &module_port_id : module_manager.module_ports(top_module)) {
|
||||||
{
|
BasicPort module_port = module_manager.module_port(top_module, module_port_id);
|
||||||
BasicPort module_port = module_manager.module_port(top_module, module_port_id);
|
fp << generate_verilog_port(VERILOG_PORT_WIRE, module_port) << ";" << std::endl;
|
||||||
fp << generate_verilog_port(VERILOG_PORT_WIRE, module_port) << ";" << std::endl;
|
|
||||||
}
|
|
||||||
/* Add an empty line as a splitter */
|
|
||||||
fp << std::endl;
|
|
||||||
}
|
}
|
||||||
|
/* Add an empty line as a splitter */
|
||||||
|
fp << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* Connect global ports of FPGA top module to constants except:
|
* Connect global ports of FPGA top module to constants except:
|
||||||
* 1. operating clock, which should be wired to the clock port of
|
* 1. operating clock, which should be wired to the clock port of
|
||||||
* this pre-configured FPGA top module
|
* this pre-configured FPGA top module
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
static void print_verilog_preconfig_top_module_connect_global_ports(std::fstream &fp,
|
static
|
||||||
const ModuleManager &module_manager,
|
int print_verilog_preconfig_top_module_connect_global_ports(std::fstream &fp,
|
||||||
const ModuleId &top_module,
|
const ModuleManager &module_manager,
|
||||||
const FabricGlobalPortInfo &fabric_global_ports,
|
const ModuleId &top_module,
|
||||||
const std::vector<std::string> &benchmark_clock_port_names)
|
const PinConstraints& pin_constraints,
|
||||||
{
|
const FabricGlobalPortInfo &fabric_global_ports,
|
||||||
/* Validate the file stream */
|
const std::vector<std::string> &benchmark_clock_port_names) {
|
||||||
valid_file_stream(fp);
|
/* 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()) {
|
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);
|
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));
|
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);
|
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! */
|
/* 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))
|
if ((true == fabric_global_ports.global_port_is_clock(global_port_id))
|
||||||
&& (false == fabric_global_ports.global_port_is_prog(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 */
|
/* Wiring to each pin of the global port: benchmark clock is always 1-bit */
|
||||||
for (const size_t &pin : module_global_port.pins()) {
|
for (size_t pin_id = 0; pin_id < module_global_port.pins().size(); ++pin_id) {
|
||||||
for (const std::string &clock_port_name : benchmark_clock_port_names) {
|
BasicPort module_clock_pin(module_global_port.get_name(), module_global_port.pins()[pin_id], module_global_port.pins()[pin_id]);
|
||||||
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);
|
/* If the clock port name is in the pin constraints, we should wire it to the constrained pin */
|
||||||
print_verilog_wire_connection(fp, module_clock_pin, benchmark_clock_pin, false);
|
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 */
|
/* If constrained to an open net or there is no clock in the benchmark, we assign it to a default value */
|
||||||
std::vector<size_t> default_values(module_global_port.get_width(), fabric_global_ports.global_port_default_value(global_port_id));
|
if ( (std::string(PIN_CONSTRAINT_OPEN_NET) == constrained_net_name)
|
||||||
print_verilog_wire_constant_values(fp, module_global_port, default_values);
|
|| (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 -----"));
|
/* 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));
|
||||||
/* Add an empty line as a splitter */
|
print_verilog_wire_constant_values(fp, module_global_port, default_values);
|
||||||
fp << std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************
|
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
|
* Impose the bitstream on the configuration memories
|
||||||
* This function uses 'assign' syntax to impost the bitstream at mem port
|
* This function uses 'assign' syntax to impost the bitstream at mem port
|
||||||
* while uses 'force' syntax to impost the bitstream at mem_inv 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,
|
static
|
||||||
const ModuleManager &module_manager,
|
void print_verilog_preconfig_top_module_assign_bitstream(std::fstream &fp,
|
||||||
const ModuleId &top_module,
|
const ModuleManager &module_manager,
|
||||||
const BitstreamManager &bitstream_manager,
|
const ModuleId &top_module,
|
||||||
const bool& output_datab_bits)
|
const BitstreamManager &bitstream_manager,
|
||||||
{
|
const bool& output_datab_bits) {
|
||||||
/* Validate the file stream */
|
/* Validate the file stream */
|
||||||
valid_file_stream(fp);
|
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())
|
for (const ConfigBlockId &config_block_id : bitstream_manager.blocks()) {
|
||||||
{
|
/* We only cares blocks with configuration bits */
|
||||||
/* 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;
|
||||||
{
|
}
|
||||||
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);
|
||||||
/* Build the hierarchical path of the configuration bit in modules */
|
/* Drop the first block, which is the top module, it should be replaced by the instance name here */
|
||||||
std::vector<ConfigBlockId> block_hierarchy = find_bitstream_manager_block_hierarchy(bitstream_manager, config_block_id);
|
/* Ensure that this is the module we want to drop! */
|
||||||
/* Drop the first block, which is the top module, it should be replaced by the instance name here */
|
VTR_ASSERT(0 == module_manager.module_name(top_module).compare(bitstream_manager.block_name(block_hierarchy[0])));
|
||||||
/* Ensure that this is the module we want to drop! */
|
block_hierarchy.erase(block_hierarchy.begin());
|
||||||
VTR_ASSERT(0 == module_manager.module_name(top_module).compare(bitstream_manager.block_name(block_hierarchy[0])));
|
/* Build the full hierarchy path */
|
||||||
block_hierarchy.erase(block_hierarchy.begin());
|
std::string bit_hierarchy_path(FORMAL_VERIFICATION_TOP_MODULE_UUT_NAME);
|
||||||
/* Build the full hierarchy path */
|
for (const ConfigBlockId &temp_block : block_hierarchy) {
|
||||||
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(".");
|
bit_hierarchy_path += std::string(".");
|
||||||
|
bit_hierarchy_path += bitstream_manager.block_name(temp_block);
|
||||||
/* 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 += std::string(".");
|
||||||
|
|
||||||
if (true == output_datab_bits) {
|
/* Find the bit index in the parent block */
|
||||||
fp << "initial begin" << std::endl;
|
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())
|
/* Wire it to the configuration bit: access both data out and data outb ports */
|
||||||
{
|
std::vector<size_t> config_data_values;
|
||||||
/* We only cares blocks with configuration bits */
|
for (const ConfigBitId config_bit : bitstream_manager.block_bits(config_block_id)) {
|
||||||
if (0 == bitstream_manager.block_bits(config_block_id).size())
|
config_data_values.push_back(bitstream_manager.bit_value(config_bit));
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
print_verilog_wire_constant_values(fp, config_data_port, config_data_values);
|
||||||
print_verilog_comment(fp, std::string("----- End assign bitstream to configuration memories -----"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************
|
if (true == output_datab_bits) {
|
||||||
* 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;
|
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 */
|
/* 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;
|
continue;
|
||||||
}
|
}
|
||||||
/* Build the hierarchical path of the configuration bit in modules */
|
/* Build the hierarchical path of the configuration bit in modules */
|
||||||
|
@ -282,94 +248,144 @@ namespace openfpga
|
||||||
block_hierarchy.erase(block_hierarchy.begin());
|
block_hierarchy.erase(block_hierarchy.begin());
|
||||||
/* Build the full hierarchy path */
|
/* Build the full hierarchy path */
|
||||||
std::string bit_hierarchy_path(FORMAL_VERIFICATION_TOP_MODULE_UUT_NAME);
|
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 += std::string(".");
|
||||||
bit_hierarchy_path += bitstream_manager.block_name(temp_block);
|
bit_hierarchy_path += bitstream_manager.block_name(temp_block);
|
||||||
}
|
}
|
||||||
bit_hierarchy_path += std::string(".");
|
bit_hierarchy_path += std::string(".");
|
||||||
|
|
||||||
/* Find the bit index in the parent block */
|
/* 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(),
|
BasicPort config_datab_port(bit_hierarchy_path + generate_configurable_memory_inverted_data_out_name(),
|
||||||
bitstream_manager.block_bits(config_block_id).size());
|
bitstream_manager.block_bits(config_block_id).size());
|
||||||
|
|
||||||
|
|
||||||
std::vector<size_t> config_datab_values;
|
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));
|
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;
|
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
|
* Impose the bitstream on the configuration memories
|
||||||
* We branch here for different simulators:
|
* We branch here for different simulators:
|
||||||
* 1. iVerilog Icarus prefers using 'assign' syntax to force the values
|
* 1. iVerilog Icarus prefers using 'assign' syntax to force the values
|
||||||
* 2. Mentor Modelsim prefers using '$deposit' syntax to do so
|
* 2. Mentor Modelsim prefers using '$deposit' syntax to do so
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
static void print_verilog_preconfig_top_module_load_bitstream(std::fstream &fp,
|
static
|
||||||
const ModuleManager &module_manager,
|
void print_verilog_preconfig_top_module_load_bitstream(std::fstream &fp,
|
||||||
const ModuleId &top_module,
|
const ModuleManager &module_manager,
|
||||||
const CircuitLibrary& circuit_lib,
|
const ModuleId &top_module,
|
||||||
const CircuitModelId& mem_model,
|
const CircuitLibrary& circuit_lib,
|
||||||
const BitstreamManager &bitstream_manager)
|
const CircuitModelId& mem_model,
|
||||||
{
|
const BitstreamManager &bitstream_manager) {
|
||||||
|
|
||||||
/* Skip the datab port if there is only 1 output port in memory model
|
/* 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
|
* 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.
|
* 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
|
* TODO: this switch could be smarter: it should identify if only data or datab
|
||||||
* ports are defined.
|
* ports are defined.
|
||||||
*/
|
*/
|
||||||
bool output_datab_bits = true;
|
bool output_datab_bits = true;
|
||||||
if (1 == circuit_lib.model_ports_by_type(mem_model, CIRCUIT_MODEL_PORT_OUTPUT).size()) {
|
if (1 == circuit_lib.model_ports_by_type(mem_model, CIRCUIT_MODEL_PORT_OUTPUT).size()) {
|
||||||
output_datab_bits = false;
|
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 -----"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************
|
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
|
* Top-level function to generate a Verilog module of
|
||||||
* a pre-configured FPGA fabric.
|
* 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
|
* 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
|
* All these are hard to implement as a module in module manager
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
void print_verilog_preconfig_top_module(const ModuleManager &module_manager,
|
int print_verilog_preconfig_top_module(const ModuleManager &module_manager,
|
||||||
const BitstreamManager &bitstream_manager,
|
const BitstreamManager &bitstream_manager,
|
||||||
const ConfigProtocol &config_protocol,
|
const ConfigProtocol &config_protocol,
|
||||||
const CircuitLibrary &circuit_lib,
|
const CircuitLibrary &circuit_lib,
|
||||||
const FabricGlobalPortInfo &global_ports,
|
const FabricGlobalPortInfo &global_ports,
|
||||||
const AtomContext &atom_ctx,
|
const AtomContext &atom_ctx,
|
||||||
const PlacementContext &place_ctx,
|
const PlacementContext &place_ctx,
|
||||||
const IoLocationMap &io_location_map,
|
const PinConstraints& pin_constraints,
|
||||||
const VprNetlistAnnotation &netlist_annotation,
|
const IoLocationMap &io_location_map,
|
||||||
const std::string &circuit_name,
|
const VprNetlistAnnotation &netlist_annotation,
|
||||||
const std::string &verilog_fname,
|
const std::string &circuit_name,
|
||||||
const bool &explicit_port_mapping)
|
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("'");
|
std::string timer_message = std::string("Write pre-configured FPGA top-level Verilog netlist for design '") + circuit_name + std::string("'");
|
||||||
|
|
||||||
/* Start time count */
|
int status = CMD_EXEC_SUCCESS;
|
||||||
vtr::ScopedStartFinishTimer timer(timer_message);
|
|
||||||
|
|
||||||
/* Create the file stream */
|
/* Start time count */
|
||||||
std::fstream fp;
|
vtr::ScopedStartFinishTimer timer(timer_message);
|
||||||
fp.open(verilog_fname, std::fstream::out | std::fstream::trunc);
|
|
||||||
|
|
||||||
/* Validate the file stream */
|
/* Create the file stream */
|
||||||
check_file_stream(verilog_fname.c_str(), fp);
|
std::fstream fp;
|
||||||
|
fp.open(verilog_fname, std::fstream::out | std::fstream::trunc);
|
||||||
|
|
||||||
/* Generate a brief description on the Verilog file*/
|
/* Validate the file stream */
|
||||||
std::string title = std::string("Verilog netlist for pre-configured FPGA fabric by design: ") + circuit_name;
|
check_file_stream(verilog_fname.c_str(), fp);
|
||||||
print_verilog_file_header(fp, title);
|
|
||||||
|
|
||||||
/* Print module declaration and ports */
|
/* Generate a brief description on the Verilog file*/
|
||||||
print_verilog_preconfig_top_module_ports(fp, circuit_name, atom_ctx, netlist_annotation);
|
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 */
|
/* Print module declaration and ports */
|
||||||
ModuleId top_module = module_manager.find_module(generate_fpga_top_module_name());
|
print_verilog_preconfig_top_module_ports(fp, circuit_name, atom_ctx, netlist_annotation);
|
||||||
VTR_ASSERT(true == module_manager.valid_module_id(top_module));
|
|
||||||
|
|
||||||
/* Print internal wires */
|
/* Find the top_module */
|
||||||
print_verilog_preconfig_top_module_internal_wires(fp, module_manager, 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 internal wires */
|
||||||
print_verilog_testbench_fpga_instance(fp, module_manager, top_module,
|
print_verilog_preconfig_top_module_internal_wires(fp, module_manager, top_module);
|
||||||
std::string(FORMAL_VERIFICATION_TOP_MODULE_UUT_NAME),
|
|
||||||
explicit_port_mapping);
|
|
||||||
|
|
||||||
/* Find clock ports in benchmark */
|
/* Instanciate FPGA top-level module */
|
||||||
std::vector<std::string> benchmark_clock_port_names = find_atom_netlist_clock_port_names(atom_ctx.nlist, netlist_annotation);
|
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! */
|
/* Find clock ports in benchmark */
|
||||||
print_verilog_preconfig_top_module_connect_global_ports(fp, module_manager, top_module,
|
std::vector<std::string> benchmark_clock_port_names = find_atom_netlist_clock_port_names(atom_ctx.nlist, netlist_annotation);
|
||||||
global_ports,
|
|
||||||
benchmark_clock_port_names);
|
|
||||||
|
|
||||||
/* Connect I/Os to benchmark I/Os or constant driver */
|
/* Connect FPGA top module global ports to constant or benchmark global signals! */
|
||||||
print_verilog_testbench_connect_fpga_ios(fp, module_manager, top_module,
|
status = print_verilog_preconfig_top_module_connect_global_ports(fp, module_manager, top_module,
|
||||||
atom_ctx, place_ctx, io_location_map,
|
pin_constraints, global_ports,
|
||||||
netlist_annotation,
|
benchmark_clock_port_names);
|
||||||
std::string(FORMAL_VERIFICATION_TOP_MODULE_PORT_POSTFIX),
|
if (CMD_EXEC_FATAL_ERROR == status) {
|
||||||
std::string(FORMAL_VERIFICATION_TOP_MODULE_PORT_POSTFIX),
|
return status;
|
||||||
(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 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 */
|
} /* end namespace openfpga */
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "vpr_context.h"
|
#include "vpr_context.h"
|
||||||
#include "module_manager.h"
|
#include "module_manager.h"
|
||||||
#include "bitstream_manager.h"
|
#include "bitstream_manager.h"
|
||||||
|
#include "pin_constraints.h"
|
||||||
#include "io_location_map.h"
|
#include "io_location_map.h"
|
||||||
#include "fabric_global_port_info.h"
|
#include "fabric_global_port_info.h"
|
||||||
#include "config_protocol.h"
|
#include "config_protocol.h"
|
||||||
|
@ -22,18 +23,19 @@
|
||||||
/* begin namespace openfpga */
|
/* begin namespace openfpga */
|
||||||
namespace openfpga {
|
namespace openfpga {
|
||||||
|
|
||||||
void print_verilog_preconfig_top_module(const ModuleManager& module_manager,
|
int print_verilog_preconfig_top_module(const ModuleManager& module_manager,
|
||||||
const BitstreamManager& bitstream_manager,
|
const BitstreamManager& bitstream_manager,
|
||||||
const ConfigProtocol &config_protocol,
|
const ConfigProtocol &config_protocol,
|
||||||
const CircuitLibrary& circuit_lib,
|
const CircuitLibrary& circuit_lib,
|
||||||
const FabricGlobalPortInfo &global_ports,
|
const FabricGlobalPortInfo &global_ports,
|
||||||
const AtomContext& atom_ctx,
|
const AtomContext& atom_ctx,
|
||||||
const PlacementContext& place_ctx,
|
const PlacementContext& place_ctx,
|
||||||
const IoLocationMap& io_location_map,
|
const PinConstraints& pin_constraints,
|
||||||
const VprNetlistAnnotation& netlist_annotation,
|
const IoLocationMap& io_location_map,
|
||||||
const std::string& circuit_name,
|
const VprNetlistAnnotation& netlist_annotation,
|
||||||
const std::string& verilog_fname,
|
const std::string& circuit_name,
|
||||||
const bool& explicit_port_mapping);
|
const std::string& verilog_fname,
|
||||||
|
const bool& explicit_port_mapping);
|
||||||
|
|
||||||
} /* end namespace openfpga */
|
} /* end namespace openfpga */
|
||||||
|
|
||||||
|
|
|
@ -347,14 +347,18 @@ void print_verilog_timeout_and_vcd(std::fstream& fp,
|
||||||
* Restrictions:
|
* Restrictions:
|
||||||
* Assume this is a single clock benchmark
|
* Assume this is a single clock benchmark
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
BasicPort generate_verilog_testbench_clock_port(const std::vector<std::string>& clock_port_names,
|
std::vector<BasicPort> generate_verilog_testbench_clock_port(const std::vector<std::string>& clock_port_names,
|
||||||
const std::string& default_clock_name) {
|
const std::string& default_clock_name) {
|
||||||
|
std::vector<BasicPort> clock_ports;
|
||||||
if (0 == clock_port_names.size()) {
|
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 clock_ports;
|
||||||
return BasicPort(clock_port_names[0], 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
|
@ -382,7 +386,7 @@ void print_verilog_testbench_check(std::fstream& fp,
|
||||||
|
|
||||||
print_verilog_comment(fp, std::string("----- Begin checking output vectors -------"));
|
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 -------"));
|
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 << "\t" << generate_verilog_port(VERILOG_PORT_REG, sim_start_port) << ";" << std::endl;
|
||||||
fp << 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\tif (1'b1 == " << generate_verilog_port(VERILOG_PORT_CONKT, sim_start_port) << ") begin" << std::endl;
|
||||||
fp << "\t\t";
|
fp << "\t\t";
|
||||||
print_verilog_register_connection(fp, sim_start_port, sim_start_port, true);
|
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
|
* but be only used as a synchronizer in verification
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
void print_verilog_testbench_clock_stimuli(std::fstream& fp,
|
void print_verilog_testbench_clock_stimuli(std::fstream& fp,
|
||||||
|
const PinConstraints& pin_constraints,
|
||||||
const SimulationSetting& simulation_parameters,
|
const SimulationSetting& simulation_parameters,
|
||||||
const BasicPort& clock_port) {
|
const std::vector<BasicPort>& clock_ports) {
|
||||||
/* Validate the file stream */
|
/* Validate the file stream */
|
||||||
valid_file_stream(fp);
|
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;
|
/* Find the corresponding clock frequency from the simulation parameters */
|
||||||
/* Create clock stimuli */
|
float clk_freq_to_use = (0.5 / simulation_parameters.default_operating_clock_frequency()) / VERILOG_SIM_TIMESCALE;
|
||||||
fp << "\t\t" << generate_verilog_port(VERILOG_PORT_CONKT, clock_port) << " <= 1'b0;" << std::endl;
|
/* Check pin constraints to see if this clock is constrained to a specific pin
|
||||||
fp << "\t\twhile(1) begin" << std::endl;
|
* If constrained,
|
||||||
fp << "\t\t\t#" << std::setprecision(10) << ((0.5/simulation_parameters.operating_clock_frequency())/VERILOG_SIM_TIMESCALE) << std::endl;
|
* - connect this clock to default values if it is set to be OPEN
|
||||||
fp << "\t\t\t" << generate_verilog_port(VERILOG_PORT_CONKT, clock_port);
|
* - connect this clock to a specific clock source from simulation settings!!!
|
||||||
fp << " <= !";
|
*/
|
||||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, clock_port);
|
VTR_ASSERT(1 == clock_port.get_width());
|
||||||
fp << ";" << std::endl;
|
for (const PinConstraintId& pin_constraint : pin_constraints.pin_constraints()) {
|
||||||
fp << "\t\tend" << std::endl;
|
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 << "\tend" << std::endl;
|
||||||
fp << 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 VprNetlistAnnotation& netlist_annotation,
|
||||||
const std::vector<std::string>& clock_port_names,
|
const std::vector<std::string>& clock_port_names,
|
||||||
const std::string& check_flag_port_postfix,
|
const std::string& check_flag_port_postfix,
|
||||||
const BasicPort& clock_port) {
|
const std::vector<BasicPort>& clock_ports) {
|
||||||
/* Validate the file stream */
|
/* Validate the file stream */
|
||||||
valid_file_stream(fp);
|
valid_file_stream(fp);
|
||||||
|
|
||||||
|
@ -557,25 +593,14 @@ void print_verilog_testbench_random_stimuli(std::fstream& fp,
|
||||||
/* Add an empty line as splitter */
|
/* Add an empty line as splitter */
|
||||||
fp << std::endl;
|
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 -------"));
|
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()) {
|
for (const AtomBlockId& atom_blk : atom_ctx.nlist.blocks()) {
|
||||||
/* Bypass non-I/O atom blocks ! */
|
/* Bypass non-I/O atom blocks ! */
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "vpr_context.h"
|
#include "vpr_context.h"
|
||||||
#include "io_location_map.h"
|
#include "io_location_map.h"
|
||||||
#include "vpr_netlist_annotation.h"
|
#include "vpr_netlist_annotation.h"
|
||||||
|
#include "pin_constraints.h"
|
||||||
#include "simulation_setting.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 std::string& error_counter_name,
|
||||||
const float& simulation_time);
|
const float& simulation_time);
|
||||||
|
|
||||||
BasicPort generate_verilog_testbench_clock_port(const std::vector<std::string>& clock_port_names,
|
std::vector<BasicPort> generate_verilog_testbench_clock_port(const std::vector<std::string>& clock_port_names,
|
||||||
const std::string& default_clock_name);
|
const std::string& default_clock_name);
|
||||||
|
|
||||||
void print_verilog_testbench_check(std::fstream& fp,
|
void print_verilog_testbench_check(std::fstream& fp,
|
||||||
const std::string& autochecked_preprocessing_flag,
|
const std::string& autochecked_preprocessing_flag,
|
||||||
|
@ -76,15 +77,16 @@ void print_verilog_testbench_check(std::fstream& fp,
|
||||||
const std::string& default_clock_name);
|
const std::string& default_clock_name);
|
||||||
|
|
||||||
void print_verilog_testbench_clock_stimuli(std::fstream& fp,
|
void print_verilog_testbench_clock_stimuli(std::fstream& fp,
|
||||||
|
const PinConstraints& pin_constraints,
|
||||||
const SimulationSetting& simulation_parameters,
|
const SimulationSetting& simulation_parameters,
|
||||||
const BasicPort& clock_port);
|
const std::vector<BasicPort>& clock_ports);
|
||||||
|
|
||||||
void print_verilog_testbench_random_stimuli(std::fstream& fp,
|
void print_verilog_testbench_random_stimuli(std::fstream& fp,
|
||||||
const AtomContext& atom_ctx,
|
const AtomContext& atom_ctx,
|
||||||
const VprNetlistAnnotation& netlist_annotation,
|
const VprNetlistAnnotation& netlist_annotation,
|
||||||
const std::vector<std::string>& clock_port_names,
|
const std::vector<std::string>& clock_port_names,
|
||||||
const std::string& check_flag_port_postfix,
|
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,
|
void print_verilog_testbench_shared_ports(std::fstream& fp,
|
||||||
const AtomContext& atom_ctx,
|
const AtomContext& atom_ctx,
|
||||||
|
|
|
@ -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_PROG_SET_PORT_NAME = "prog_set";
|
||||||
constexpr char* TOP_TB_CONFIG_DONE_PORT_NAME = "config_done";
|
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_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_PROG_CLOCK_PORT_NAME = "prog_clock";
|
||||||
constexpr char* TOP_TB_INOUT_REG_POSTFIX = "_reg";
|
constexpr char* TOP_TB_INOUT_REG_POSTFIX = "_reg";
|
||||||
constexpr char* TOP_TB_CLOCK_REG_POSTFIX = "_reg";
|
constexpr char* TOP_TB_CLOCK_REG_POSTFIX = "_reg";
|
||||||
|
|
||||||
constexpr char* AUTOCHECK_TOP_TESTBENCH_VERILOG_MODULE_POSTFIX = "_autocheck_top_tb";
|
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
|
* 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 ModuleManager& module_manager,
|
||||||
const ModuleId& top_module,
|
const ModuleId& top_module,
|
||||||
const FabricGlobalPortInfo& fabric_global_port_info,
|
const FabricGlobalPortInfo& fabric_global_port_info,
|
||||||
|
const SimulationSetting& simulation_parameters,
|
||||||
const bool& active_global_prog_reset,
|
const bool& active_global_prog_reset,
|
||||||
const bool& active_global_prog_set) {
|
const bool& active_global_prog_set) {
|
||||||
/* Validate the file stream */
|
/* 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
|
* The wiring will be inverted if the default value of the global port is 1
|
||||||
* Otherwise, the wiring will not be inverted!
|
* Otherwise, the wiring will not be inverted!
|
||||||
*/
|
*/
|
||||||
print_verilog_wire_connection(fp, module_manager.module_port(top_module, module_global_port),
|
for (const size_t& pin : module_manager.module_port(top_module, module_global_port).pins()) {
|
||||||
stimuli_clock_port,
|
BasicPort global_port_to_connect(module_manager.module_port(top_module, module_global_port).get_name(), pin, pin);
|
||||||
1 == fabric_global_port_info.global_port_default_value(fabric_global_port));
|
/* 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 */
|
/* 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 -----"));
|
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
|
* This function prints the top testbench module declaration
|
||||||
* and internal wires/port declaration
|
* and internal wires/port declaration
|
||||||
|
@ -481,6 +571,8 @@ void print_verilog_top_testbench_ports(std::fstream& fp,
|
||||||
const AtomContext& atom_ctx,
|
const AtomContext& atom_ctx,
|
||||||
const VprNetlistAnnotation& netlist_annotation,
|
const VprNetlistAnnotation& netlist_annotation,
|
||||||
const std::vector<std::string>& clock_port_names,
|
const std::vector<std::string>& clock_port_names,
|
||||||
|
const PinConstraints& pin_constraints,
|
||||||
|
const SimulationSetting& simulation_parameters,
|
||||||
const ConfigProtocol& config_protocol,
|
const ConfigProtocol& config_protocol,
|
||||||
const std::string& circuit_name){
|
const std::string& circuit_name){
|
||||||
/* Validate the file stream */
|
/* 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);
|
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;
|
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);
|
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;
|
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);
|
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,
|
print_verilog_top_testbench_config_protocol_port(fp, config_protocol,
|
||||||
module_manager, top_module);
|
module_manager, top_module);
|
||||||
|
|
||||||
/* Create a clock port if the benchmark have one but not in the default name!
|
/* Print clock ports */
|
||||||
* We will wire the clock directly to the operating clock directly
|
print_verilog_top_testbench_benchmark_clock_ports(fp,
|
||||||
*/
|
module_manager, top_module,
|
||||||
for (const std::string clock_port_name : clock_port_names) {
|
clock_port_names,
|
||||||
if (0 == clock_port_name.compare(op_clock_port.get_name())) {
|
pin_constraints,
|
||||||
continue;
|
simulation_parameters,
|
||||||
}
|
op_clock_port);
|
||||||
/* 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_verilog_testbench_shared_ports(fp, atom_ctx, netlist_annotation,
|
print_verilog_testbench_shared_ports(fp, atom_ctx, netlist_annotation,
|
||||||
clock_port_names,
|
clock_port_names,
|
||||||
|
@ -962,6 +1051,7 @@ void print_verilog_top_testbench_load_bitstream_task(std::fstream& fp,
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
static
|
static
|
||||||
void print_verilog_top_testbench_generic_stimulus(std::fstream& fp,
|
void print_verilog_top_testbench_generic_stimulus(std::fstream& fp,
|
||||||
|
const SimulationSetting& simulation_parameters,
|
||||||
const size_t& num_config_clock_cycles,
|
const size_t& num_config_clock_cycles,
|
||||||
const float& prog_clock_period,
|
const float& prog_clock_period,
|
||||||
const float& op_clock_period,
|
const float& op_clock_period,
|
||||||
|
@ -1014,6 +1104,32 @@ void print_verilog_top_testbench_generic_stimulus(std::fstream& fp,
|
||||||
|
|
||||||
fp << std::endl;
|
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 */
|
/* Generate stimuli waveform for operating clock signals */
|
||||||
print_verilog_comment(fp, "----- Begin raw operating clock signal generation -----");
|
print_verilog_comment(fp, "----- Begin raw operating clock signal generation -----");
|
||||||
print_verilog_clock_stimuli(fp, op_clock_register_port,
|
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 FabricGlobalPortInfo& global_ports,
|
||||||
const AtomContext& atom_ctx,
|
const AtomContext& atom_ctx,
|
||||||
const PlacementContext& place_ctx,
|
const PlacementContext& place_ctx,
|
||||||
|
const PinConstraints& pin_constraints,
|
||||||
const IoLocationMap& io_location_map,
|
const IoLocationMap& io_location_map,
|
||||||
const VprNetlistAnnotation& netlist_annotation,
|
const VprNetlistAnnotation& netlist_annotation,
|
||||||
const std::string& circuit_name,
|
const std::string& circuit_name,
|
||||||
|
@ -1826,13 +1943,20 @@ void print_verilog_top_testbench(const ModuleManager& module_manager,
|
||||||
|
|
||||||
/* Start of testbench */
|
/* Start of testbench */
|
||||||
print_verilog_top_testbench_ports(fp, module_manager, top_module,
|
print_verilog_top_testbench_ports(fp, module_manager, top_module,
|
||||||
atom_ctx, netlist_annotation, clock_port_names,
|
atom_ctx, netlist_annotation,
|
||||||
config_protocol,
|
clock_port_names,
|
||||||
|
pin_constraints,
|
||||||
|
simulation_parameters, config_protocol,
|
||||||
circuit_name);
|
circuit_name);
|
||||||
|
|
||||||
/* Find the clock period */
|
/* Find the clock period */
|
||||||
float prog_clock_period = (1./simulation_parameters.programming_clock_frequency());
|
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 */
|
/* Estimate the number of configuration clock cycles */
|
||||||
size_t num_config_clock_cycles = calculate_num_config_clock_cycles(config_protocol.type(),
|
size_t num_config_clock_cycles = calculate_num_config_clock_cycles(config_protocol.type(),
|
||||||
apply_fast_configuration,
|
apply_fast_configuration,
|
||||||
|
@ -1842,9 +1966,10 @@ void print_verilog_top_testbench(const ModuleManager& module_manager,
|
||||||
|
|
||||||
/* Generate stimuli for general control signals */
|
/* Generate stimuli for general control signals */
|
||||||
print_verilog_top_testbench_generic_stimulus(fp,
|
print_verilog_top_testbench_generic_stimulus(fp,
|
||||||
|
simulation_parameters,
|
||||||
num_config_clock_cycles,
|
num_config_clock_cycles,
|
||||||
prog_clock_period,
|
prog_clock_period,
|
||||||
op_clock_period,
|
default_op_clock_period,
|
||||||
VERILOG_SIM_TIMESCALE);
|
VERILOG_SIM_TIMESCALE);
|
||||||
|
|
||||||
/* Generate stimuli for programming interface */
|
/* 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,
|
print_verilog_top_testbench_global_ports_stimuli(fp,
|
||||||
module_manager, top_module,
|
module_manager, top_module,
|
||||||
global_ports,
|
global_ports,
|
||||||
|
simulation_parameters,
|
||||||
active_global_prog_reset,
|
active_global_prog_reset,
|
||||||
active_global_prog_set);
|
active_global_prog_set);
|
||||||
|
|
||||||
|
@ -1935,7 +2061,7 @@ void print_verilog_top_testbench(const ModuleManager& module_manager,
|
||||||
netlist_annotation,
|
netlist_annotation,
|
||||||
clock_port_names,
|
clock_port_names,
|
||||||
std::string(TOP_TESTBENCH_CHECKFLAG_PORT_POSTFIX),
|
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 */
|
/* Add output autocheck */
|
||||||
print_verilog_testbench_check(fp,
|
print_verilog_testbench_check(fp,
|
||||||
|
@ -1961,7 +2087,7 @@ void print_verilog_top_testbench(const ModuleManager& module_manager,
|
||||||
num_config_clock_cycles,
|
num_config_clock_cycles,
|
||||||
1./simulation_parameters.programming_clock_frequency(),
|
1./simulation_parameters.programming_clock_frequency(),
|
||||||
simulation_parameters.num_clock_cycles(),
|
simulation_parameters.num_clock_cycles(),
|
||||||
1./simulation_parameters.operating_clock_frequency());
|
1./simulation_parameters.default_operating_clock_frequency());
|
||||||
|
|
||||||
|
|
||||||
/* Add Icarus requirement:
|
/* Add Icarus requirement:
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "circuit_library.h"
|
#include "circuit_library.h"
|
||||||
#include "config_protocol.h"
|
#include "config_protocol.h"
|
||||||
#include "vpr_context.h"
|
#include "vpr_context.h"
|
||||||
|
#include "pin_constraints.h"
|
||||||
#include "io_location_map.h"
|
#include "io_location_map.h"
|
||||||
#include "fabric_global_port_info.h"
|
#include "fabric_global_port_info.h"
|
||||||
#include "vpr_netlist_annotation.h"
|
#include "vpr_netlist_annotation.h"
|
||||||
|
@ -33,6 +34,7 @@ void print_verilog_top_testbench(const ModuleManager& module_manager,
|
||||||
const FabricGlobalPortInfo& global_ports,
|
const FabricGlobalPortInfo& global_ports,
|
||||||
const AtomContext& atom_ctx,
|
const AtomContext& atom_ctx,
|
||||||
const PlacementContext& place_ctx,
|
const PlacementContext& place_ctx,
|
||||||
|
const PinConstraints& pin_constraints,
|
||||||
const IoLocationMap& io_location_map,
|
const IoLocationMap& io_location_map,
|
||||||
const VprNetlistAnnotation& netlist_annotation,
|
const VprNetlistAnnotation& netlist_annotation,
|
||||||
const std::string& circuit_name,
|
const std::string& circuit_name,
|
||||||
|
|
|
@ -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
|
* Note: this is ONLY applicable to the pb_pin of top-level pb_graph_node
|
||||||
***************************************************************************************/
|
***************************************************************************************/
|
||||||
static
|
static
|
||||||
int find_pb_route_remapped_source_pb_pin(const t_pb* pb,
|
std::vector<int> find_pb_route_remapped_source_pb_pin(const t_pb* pb,
|
||||||
const t_pb_graph_pin* source_pb_pin,
|
const t_pb_graph_pin* source_pb_pin,
|
||||||
const AtomNetId& atom_net_id) {
|
const AtomNetId& atom_net_id) {
|
||||||
VTR_ASSERT(true == source_pb_pin->parent_node->is_root());
|
VTR_ASSERT(true == source_pb_pin->parent_node->is_root());
|
||||||
|
|
||||||
std::vector<int> pb_route_indices;
|
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;
|
||||||
|
|
||||||
return pb_route_indices[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************************************************
|
/***************************************************************************************
|
||||||
|
@ -339,6 +337,7 @@ void add_lb_router_nets(LbRouter& lb_router,
|
||||||
const VprDeviceAnnotation& device_annotation,
|
const VprDeviceAnnotation& device_annotation,
|
||||||
const ClusteringContext& clustering_ctx,
|
const ClusteringContext& clustering_ctx,
|
||||||
const VprClusteringAnnotation& clustering_annotation,
|
const VprClusteringAnnotation& clustering_annotation,
|
||||||
|
const RepackDesignConstraints& design_constraints,
|
||||||
const ClusterBlockId& block_id,
|
const ClusterBlockId& block_id,
|
||||||
const bool& verbose) {
|
const bool& verbose) {
|
||||||
size_t net_counter = 0;
|
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*/
|
/* Find the net mapped to this pin in clustering results*/
|
||||||
AtomNetId atom_net_id = pb_pin_mapped_nets[source_pb_pin];
|
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;
|
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,
|
/* The outputs of pb_graph_node is INTERMEDIATE node in the routing resource graph,
|
||||||
* they are all connected to a common source node
|
* they are all connected to a common source node
|
||||||
*/
|
*/
|
||||||
LbRRNodeId source_lb_rr_node = lb_rr_graph.find_node(LB_INTERMEDIATE, source_pb_pin);
|
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));
|
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);
|
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);
|
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 */
|
/* 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);
|
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());
|
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,
|
VTR_LOGV(verbose,
|
||||||
"Pb route for Net %s:\n",
|
"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,
|
VTR_LOGV(verbose,
|
||||||
"Source node:\n\t%s -> %s\n",
|
"Source node:\n\t%s -> %s\n",
|
||||||
source_pb_pin->to_string().c_str(),
|
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,
|
add_lb_router_net_to_route(lb_router, lb_rr_graph,
|
||||||
std::vector<LbRRNodeId>(1, source_lb_rr_node),
|
std::vector<LbRRNodeId>(1, source_lb_rr_node),
|
||||||
sink_lb_rr_nodes,
|
sink_lb_rr_nodes,
|
||||||
atom_ctx, atom_net_id);
|
atom_ctx, atom_net_id_to_route);
|
||||||
|
|
||||||
net_counter++;
|
net_counter++;
|
||||||
}
|
}
|
||||||
|
@ -542,6 +611,7 @@ void repack_cluster(const AtomContext& atom_ctx,
|
||||||
const ClusteringContext& clustering_ctx,
|
const ClusteringContext& clustering_ctx,
|
||||||
const VprDeviceAnnotation& device_annotation,
|
const VprDeviceAnnotation& device_annotation,
|
||||||
VprClusteringAnnotation& clustering_annotation,
|
VprClusteringAnnotation& clustering_annotation,
|
||||||
|
const RepackDesignConstraints& design_constraints,
|
||||||
const ClusterBlockId& block_id,
|
const ClusterBlockId& block_id,
|
||||||
const bool& verbose) {
|
const bool& verbose) {
|
||||||
/* Get the pb graph that current clustered block is mapped to */
|
/* 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 nets to be routed with source and terminals */
|
||||||
add_lb_router_nets(lb_router, lb_type, lb_rr_graph, atom_ctx, device_annotation,
|
add_lb_router_nets(lb_router, lb_type, lb_rr_graph, atom_ctx, device_annotation,
|
||||||
clustering_ctx, const_cast<const VprClusteringAnnotation&>(clustering_annotation),
|
clustering_ctx, const_cast<const VprClusteringAnnotation&>(clustering_annotation),
|
||||||
|
design_constraints,
|
||||||
block_id, verbose);
|
block_id, verbose);
|
||||||
|
|
||||||
/* Initialize the modes to expand routing trees with the physical modes in device annotation
|
/* 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 ClusteringContext& clustering_ctx,
|
||||||
const VprDeviceAnnotation& device_annotation,
|
const VprDeviceAnnotation& device_annotation,
|
||||||
VprClusteringAnnotation& clustering_annotation,
|
VprClusteringAnnotation& clustering_annotation,
|
||||||
|
const RepackDesignConstraints& design_constraints,
|
||||||
const bool& verbose) {
|
const bool& verbose) {
|
||||||
vtr::ScopedStartFinishTimer timer("Repack clustered blocks to physical implementation of logical tile");
|
vtr::ScopedStartFinishTimer timer("Repack clustered blocks to physical implementation of logical tile");
|
||||||
|
|
||||||
for (auto blk_id : clustering_ctx.clb_nlist.blocks()) {
|
for (auto blk_id : clustering_ctx.clb_nlist.blocks()) {
|
||||||
repack_cluster(atom_ctx, clustering_ctx,
|
repack_cluster(atom_ctx, clustering_ctx,
|
||||||
device_annotation, clustering_annotation,
|
device_annotation,
|
||||||
|
clustering_annotation,
|
||||||
|
design_constraints,
|
||||||
blk_id, verbose);
|
blk_id, verbose);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -632,6 +706,7 @@ void pack_physical_pbs(const DeviceContext& device_ctx,
|
||||||
const ClusteringContext& clustering_ctx,
|
const ClusteringContext& clustering_ctx,
|
||||||
VprDeviceAnnotation& device_annotation,
|
VprDeviceAnnotation& device_annotation,
|
||||||
VprClusteringAnnotation& clustering_annotation,
|
VprClusteringAnnotation& clustering_annotation,
|
||||||
|
const RepackDesignConstraints& design_constraints,
|
||||||
const bool& verbose) {
|
const bool& verbose) {
|
||||||
|
|
||||||
/* build the routing resource graph for each logical tile */
|
/* 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 */
|
/* Call the LbRouter to re-pack each clustered block to physical implementation */
|
||||||
repack_clusters(atom_ctx, clustering_ctx,
|
repack_clusters(atom_ctx, clustering_ctx,
|
||||||
const_cast<const VprDeviceAnnotation&>(device_annotation), clustering_annotation,
|
const_cast<const VprDeviceAnnotation&>(device_annotation), clustering_annotation,
|
||||||
|
design_constraints,
|
||||||
verbose);
|
verbose);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "vpr_device_annotation.h"
|
#include "vpr_device_annotation.h"
|
||||||
#include "vpr_clustering_annotation.h"
|
#include "vpr_clustering_annotation.h"
|
||||||
#include "vpr_routing_annotation.h"
|
#include "vpr_routing_annotation.h"
|
||||||
|
#include "repack_design_constraints.h"
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* Function declaration
|
* Function declaration
|
||||||
|
@ -21,6 +22,7 @@ void pack_physical_pbs(const DeviceContext& device_ctx,
|
||||||
const ClusteringContext& clustering_ctx,
|
const ClusteringContext& clustering_ctx,
|
||||||
VprDeviceAnnotation& device_annotation,
|
VprDeviceAnnotation& device_annotation,
|
||||||
VprClusteringAnnotation& clustering_annotation,
|
VprClusteringAnnotation& clustering_annotation,
|
||||||
|
const RepackDesignConstraints& design_constraints,
|
||||||
const bool& verbose);
|
const bool& verbose);
|
||||||
|
|
||||||
} /* end namespace openfpga */
|
} /* end namespace openfpga */
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
- tree\_mux: If routing multiplexers are built with a tree-like structure
|
||||||
- <feature_size>: The technology node which the delay numbers are extracted from.
|
- <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.
|
- 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.
|
Other features are used in naming should be listed here.
|
||||||
|
|
|
@ -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>
|
|
@ -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 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
|
# - 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
|
# - 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
|
# Write the SDC files for PnR backend
|
||||||
# - Turn on every options here
|
# - Turn on every options here
|
||||||
|
|
|
@ -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
|
|
@ -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>
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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=
|
|
@ -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-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
|
* 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
|
* 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.
|
Other features are used in naming should be listed here.
|
||||||
|
|
|
@ -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
2
yosys
|
@ -1 +1 @@
|
||||||
Subproject commit a0606e09f57df456ba9bcfc6a7cf7b64d814b8e4
|
Subproject commit 14b993449d5b6e37d69ff523356d05941a78b66e
|
Loading…
Reference in New Issue