Merge pull request #98 from LNIS-Projects/dev
Support of multiple regions for configuration chain
|
@ -1,3 +0,0 @@
|
|||
[submodule "OpenSTA"]
|
||||
path = OpenSTA
|
||||
url = https://github.com/abk-openroad/OpenSTA
|
|
@ -17,9 +17,11 @@ python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/full_testbench/config
|
|||
python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/full_testbench/configuration_chain_use_set --debug --show_thread_logs
|
||||
python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/full_testbench/configuration_chain_use_setb --debug --show_thread_logs
|
||||
python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/full_testbench/configuration_chain_use_set_reset --debug --show_thread_logs
|
||||
python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/full_testbench/multi_region_configuration_chain --debug --show_thread_logs
|
||||
python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/full_testbench/fast_configuration_chain --debug --show_thread_logs
|
||||
python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/full_testbench/fast_configuration_chain_use_set --debug --show_thread_logs
|
||||
python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/full_testbench/smart_fast_configuration_chain --debug --show_thread_logs
|
||||
python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/full_testbench/smart_fast_multi_region_configuration_chain --debug --show_thread_logs
|
||||
python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/preconfig_testbench/configuration_chain --debug --show_thread_logs
|
||||
|
||||
echo -e "Testing fram-based configuration protocol of a K4N4 FPGA";
|
||||
|
@ -64,6 +66,15 @@ python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/generate_testbench --
|
|||
echo -e "Testing user-defined simulation settings: clock frequency and number of cycles";
|
||||
python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/fixed_simulation_settings --debug --show_thread_logs
|
||||
|
||||
echo -e "Testing Secured FPGA fabrics";
|
||||
python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/fabric_key/generate_vanilla_key --debug --show_thread_logs
|
||||
python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/fabric_key/generate_multi_region_vanilla_key --debug --show_thread_logs
|
||||
python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/fabric_key/generate_random_key --debug --show_thread_logs
|
||||
python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/fabric_key/load_external_key --debug --show_thread_logs
|
||||
python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/fabric_key/load_external_key_cc_fpga --debug --show_thread_logs
|
||||
python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/fabric_key/load_external_key_multi_region_cc_fpga --debug --show_thread_logs
|
||||
|
||||
|
||||
echo -e "Testing K4 series FPGA";
|
||||
echo -e "Testing K4N4 with facturable LUTs";
|
||||
python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/k4_series/k4n4_frac_lut --debug --show_thread_logs
|
||||
|
|
|
@ -82,10 +82,6 @@ python3 openfpga_flow/scripts/run_fpga_task.py fpga_verilog/duplicated_grid_pin
|
|||
echo -e "Testing Verilog generation with spy output pads";
|
||||
python3 openfpga_flow/scripts/run_fpga_task.py fpga_verilog/spypad --debug --show_thread_logs
|
||||
|
||||
echo -e "Testing Secured FPGA fabrics";
|
||||
python3 openfpga_flow/scripts/run_fpga_task.py fpga_verilog/fabric_key/generate_vanilla_key --debug --show_thread_logs
|
||||
python3 openfpga_flow/scripts/run_fpga_task.py fpga_verilog/fabric_key/generate_random_key --debug --show_thread_logs
|
||||
python3 openfpga_flow/scripts/run_fpga_task.py fpga_verilog/fabric_key/load_external_key --debug --show_thread_logs
|
||||
|
||||
echo -e "Testing Power-gating designs";
|
||||
python3 openfpga_flow/scripts/run_fpga_task.py fpga_verilog/power_gated_design/power_gated_inverter --show_thread_logs --debug
|
||||
|
|
After Width: | Height: | Size: 274 KiB |
After Width: | Height: | Size: 200 KiB |
After Width: | Height: | Size: 1.3 MiB |
|
@ -49,7 +49,7 @@ It will use the circuit model defined in :numref:`fig_ccff`.
|
|||
.. code-block:: xml
|
||||
|
||||
<configuration_protocol>
|
||||
<organization type="scan_chain" circuit_model_name="ccff"/>
|
||||
<organization type="scan_chain" circuit_model_name="ccff" num_regions="<int>"/>
|
||||
</configuration_protocol>
|
||||
|
||||
.. _fig_ccff_fpga:
|
||||
|
@ -60,6 +60,17 @@ It will use the circuit model defined in :numref:`fig_ccff`.
|
|||
|
||||
Example of a configuration chain to program core logic of a FPGA
|
||||
|
||||
.. option:: num_regions="<int>"
|
||||
|
||||
Specify the number of configuration chains to be used across the fabrics. By default, it will be only 1 configuration chain. The more configuration chain to be used, the fast configuration runtime will be, but at the cost of more I/Os in the FPGA fabrics. The organization of each configurable region can be customized through the fabric key (see details in :ref:`fabric_key`).
|
||||
|
||||
.. figure:: figures/multi_region_config_chains.png
|
||||
:scale: 100%
|
||||
:alt: map to buried treasure
|
||||
|
||||
Examples of single- and multiple- region configuration chains
|
||||
|
||||
|
||||
Frame-based Example
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
The following XML code describes frame-based memory banks to configure the core logic of FPGA.
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
.. _fabric_key:
|
||||
|
||||
Fabric Key
|
||||
~~~~~~~~~~
|
||||
|
||||
|
@ -6,6 +8,12 @@ With this key, OpenFPGA can generate correct bitstreams for the FPGA.
|
|||
Using a wrong key, OpenFPGA may error out or generate wrong bitstreams.
|
||||
The fabric key support allows users to build secured/classified FPGA chips even with an open-source tool.
|
||||
|
||||
.. figure:: figures/fabric_key_motivation.png
|
||||
:scale: 60%
|
||||
:alt: map to buried treasure
|
||||
|
||||
The use of fabric key to secure the FPGA chip design
|
||||
|
||||
.. note:: Users are the only owner of the key. OpenFPGA will not store or replicate the key.
|
||||
|
||||
Key Generation
|
||||
|
@ -19,7 +27,56 @@ A fabric key can be achieved in the following ways:
|
|||
File Format
|
||||
```````````
|
||||
|
||||
A fabric key follows an XML format. As shown in the following XML code, the key file includes the organization of configurable memory blocks in the top-level FPGA fabric:
|
||||
A fabric key follows an XML format. As shown in the following XML code, the key file includes the organization of configurable blocks in the top-level FPGA fabric.
|
||||
|
||||
Configurable Region
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The top-level FPGA fabric can consist of several configurable regions, where a region may contain one or multiple configurable blocks. Each configurable region can be configured independently and in parrallel.
|
||||
|
||||
.. option:: <region id="<int>"/>
|
||||
|
||||
- ``id`` indicates the unique id of a configurable region in the fabric.
|
||||
|
||||
.. warning:: The id must start from zero!
|
||||
|
||||
.. note:: The number of regions defined in the fabric key must be consistent with the number of regions defined in the configuration protocol of architecture description. (See details in :ref:`config_protocol`).
|
||||
|
||||
The following example shows how to define multiple configuration regions in the fabric key.
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<fabric_key>
|
||||
<region id="0">
|
||||
<key id="0" name="grid_io_bottom" value="0" alias="grid_io_bottom_1__0_"/>
|
||||
<key id="1" name="grid_io_right" value="0" alias="grid_io_right_2__1_"/>
|
||||
<key id="2" name="sb_1__1_" value="0" alias="sb_1__1_"/>
|
||||
</region>
|
||||
<region id="1">
|
||||
<key id="3" name="cbx_1__1_" value="0" alias="cbx_1__1_"/>
|
||||
<key id="4" name="grid_io_top" value="0" alias="grid_io_top_1__2_"/>
|
||||
<key id="5" name="sb_0__1_" value="0" alias="sb_0__1_"/>
|
||||
</region>
|
||||
<region id="2">
|
||||
<key id="6" name="sb_0__0_" value="0" alias="sb_0__0_"/>
|
||||
<key id="7" name="cby_0__1_" value="0" alias="cby_0__1_"/>
|
||||
<key id="8" name="grid_io_left" value="0" alias="grid_io_left_0__1_"/>
|
||||
</region>
|
||||
<region id="3">
|
||||
<key id="9" name="sb_1__0_" value="0" alias="sb_1__0_"/>
|
||||
<key id="10" name="cbx_1__0_" value="0" alias="cbx_1__0_"/>
|
||||
<key id="11" name="cby_1__1_" value="0" alias="cby_1__1_"/>
|
||||
<key id="12" name="grid_clb" value="0" alias="grid_clb_1__1_"/>
|
||||
</region>
|
||||
</fabric_key>
|
||||
|
||||
|
||||
Configurable Block
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Each configurable block is defined as a key. There are two ways to define a key, either with alias or with name and value.
|
||||
|
||||
.. option:: <key id="<int>" alias="<string>" name="<string>" value="<int>"/>
|
||||
|
||||
- ``id`` indicates the sequence of the configurable memory block in the top-level FPGA fabric.
|
||||
|
||||
|
@ -29,86 +86,92 @@ A fabric key follows an XML format. As shown in the following XML code, the key
|
|||
|
||||
- ``alias`` indicates the instance name of the configurable memory block in the top-level FPGA fabric. If a valid alias is specified, the ``name`` and ``value`` are not required.
|
||||
|
||||
.. note:: For fast loading of fabric key, strongly recommend to use pairs ``name`` and ``alias`` or ``name`` and ``value`` in the fabric key file. Using only ``alias`` may cause long parsing time for fabric key.
|
||||
.. warning:: For fast loading of fabric key, strongly recommend to use pairs ``name`` and ``alias`` or ``name`` and ``value`` in the fabric key file. Using only ``alias`` may cause long parsing time for fabric key.
|
||||
|
||||
The following is an example of a fabric key generate by OpenFPGA for a 2 :math:`\times` 2 FPGA.
|
||||
This key contains only ``alias`` which is easy to craft.
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<fabric_key>
|
||||
<key id="0" alias="sb_2__2_"/>
|
||||
<key id="1" alias="grid_clb_2_2"/>
|
||||
<key id="2" alias="sb_0__1_"/>
|
||||
<key id="3" alias="cby_0__1_"/>
|
||||
<key id="4" alias="grid_clb_2_1"/>
|
||||
<key id="5" alias="grid_io_left_0_1"/>
|
||||
<key id="6" alias="sb_1__0_"/>
|
||||
<key id="7" alias="sb_1__1_"/>
|
||||
<key id="8" alias="cbx_2__1_"/>
|
||||
<key id="9" alias="cby_1__2_"/>
|
||||
<key id="10" alias="grid_io_right_3_2"/>
|
||||
<key id="11" alias="cbx_2__0_"/>
|
||||
<key id="12" alias="cby_1__1_"/>
|
||||
<key id="13" alias="grid_io_right_3_1"/>
|
||||
<key id="14" alias="grid_io_bottom_1_0"/>
|
||||
<key id="15" alias="cby_2__1_"/>
|
||||
<key id="16" alias="sb_2__1_"/>
|
||||
<key id="17" alias="cbx_1__0_"/>
|
||||
<key id="18" alias="grid_clb_1_2"/>
|
||||
<key id="19" alias="cbx_1__2_"/>
|
||||
<key id="20" alias="cbx_2__2_"/>
|
||||
<key id="21" alias="sb_2__0_"/>
|
||||
<key id="22" alias="sb_1__2_"/>
|
||||
<key id="23" alias="cby_0__2_"/>
|
||||
<key id="24" alias="sb_0__0_"/>
|
||||
<key id="25" alias="grid_clb_1_1"/>
|
||||
<key id="26" alias="cby_2__2_"/>
|
||||
<key id="27" alias="grid_io_top_2_3"/>
|
||||
<key id="28" alias="sb_0__2_"/>
|
||||
<key id="29" alias="grid_io_bottom_2_0"/>
|
||||
<key id="30" alias="cbx_1__1_"/>
|
||||
<key id="31" alias="grid_io_top_1_3"/>
|
||||
<key id="32" alias="grid_io_left_0_2"/>
|
||||
</fabric_key>
|
||||
<fabric_key>
|
||||
<region id="0">
|
||||
<key id="0" alias="sb_2__2_"/>
|
||||
<key id="1" alias="grid_clb_2_2"/>
|
||||
<key id="2" alias="sb_0__1_"/>
|
||||
<key id="3" alias="cby_0__1_"/>
|
||||
<key id="4" alias="grid_clb_2_1"/>
|
||||
<key id="5" alias="grid_io_left_0_1"/>
|
||||
<key id="6" alias="sb_1__0_"/>
|
||||
<key id="7" alias="sb_1__1_"/>
|
||||
<key id="8" alias="cbx_2__1_"/>
|
||||
<key id="9" alias="cby_1__2_"/>
|
||||
<key id="10" alias="grid_io_right_3_2"/>
|
||||
<key id="11" alias="cbx_2__0_"/>
|
||||
<key id="12" alias="cby_1__1_"/>
|
||||
<key id="13" alias="grid_io_right_3_1"/>
|
||||
<key id="14" alias="grid_io_bottom_1_0"/>
|
||||
<key id="15" alias="cby_2__1_"/>
|
||||
<key id="16" alias="sb_2__1_"/>
|
||||
<key id="17" alias="cbx_1__0_"/>
|
||||
<key id="18" alias="grid_clb_1_2"/>
|
||||
<key id="19" alias="cbx_1__2_"/>
|
||||
<key id="20" alias="cbx_2__2_"/>
|
||||
<key id="21" alias="sb_2__0_"/>
|
||||
<key id="22" alias="sb_1__2_"/>
|
||||
<key id="23" alias="cby_0__2_"/>
|
||||
<key id="24" alias="sb_0__0_"/>
|
||||
<key id="25" alias="grid_clb_1_1"/>
|
||||
<key id="26" alias="cby_2__2_"/>
|
||||
<key id="27" alias="grid_io_top_2_3"/>
|
||||
<key id="28" alias="sb_0__2_"/>
|
||||
<key id="29" alias="grid_io_bottom_2_0"/>
|
||||
<key id="30" alias="cbx_1__1_"/>
|
||||
<key id="31" alias="grid_io_top_1_3"/>
|
||||
<key id="32" alias="grid_io_left_0_2"/>
|
||||
</region>
|
||||
</fabric_key>
|
||||
|
||||
The following shows another example of a fabric key generate by OpenFPGA for a 2 :math:`\times` 2 FPGA.
|
||||
This key contains only ``name`` and ``value`` which is fast to parse.
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<fabric_key>
|
||||
<key id="0" name="sb_2__2_" value="0"/>
|
||||
<key id="1" name="grid_clb" value="3"/>
|
||||
<key id="2" name="sb_0__1_" value="0"/>
|
||||
<key id="3" name="cby_0__1_" value="0"/>
|
||||
<key id="4" name="grid_clb" value="2"/>
|
||||
<key id="5" name="grid_io_left" value="0"/>
|
||||
<key id="6" name="sb_1__0_" value="0"/>
|
||||
<key id="7" name="sb_1__1_" value="0"/>
|
||||
<key id="8" name="cbx_1__1_" value="1"/>
|
||||
<key id="9" name="cby_1__1_" value="1"/>
|
||||
<key id="10" name="grid_io_right" value="1"/>
|
||||
<key id="11" name="cbx_1__0_" value="1"/>
|
||||
<key id="12" name="cby_1__1_" value="0"/>
|
||||
<key id="13" name="grid_io_right" value="0"/>
|
||||
<key id="14" name="grid_io_bottom" value="0"/>
|
||||
<key id="15" name="cby_2__1_" value="0"/>
|
||||
<key id="16" name="sb_2__1_" value="0"/>
|
||||
<key id="17" name="cbx_1__0_" value="0"/>
|
||||
<key id="18" name="grid_clb" value="1"/>
|
||||
<key id="19" name="cbx_1__2_" value="0"/>
|
||||
<key id="20" name="cbx_1__2_" value="1"/>
|
||||
<key id="21" name="sb_2__0_" value="0"/>
|
||||
<key id="22" name="sb_1__2_" value="0"/>
|
||||
<key id="23" name="cby_0__1_" value="1"/>
|
||||
<key id="24" name="sb_0__0_" value="0"/>
|
||||
<key id="25" name="grid_clb" value="0"/>
|
||||
<key id="26" name="cby_2__1_" value="1"/>
|
||||
<key id="27" name="grid_io_top" value="1"/>
|
||||
<key id="28" name="sb_0__2_" value="0"/>
|
||||
<key id="29" name="grid_io_bottom" value="1"/>
|
||||
<key id="30" name="cbx_1__1_" value="0"/>
|
||||
<key id="31" name="grid_io_top" value="0"/>
|
||||
<key id="32" name="grid_io_left" value="1"/>
|
||||
</fabric_key>
|
||||
<fabric_key>
|
||||
<region id="0">
|
||||
<key id="0" name="sb_2__2_" value="0"/>
|
||||
<key id="1" name="grid_clb" value="3"/>
|
||||
<key id="2" name="sb_0__1_" value="0"/>
|
||||
<key id="3" name="cby_0__1_" value="0"/>
|
||||
<key id="4" name="grid_clb" value="2"/>
|
||||
<key id="5" name="grid_io_left" value="0"/>
|
||||
<key id="6" name="sb_1__0_" value="0"/>
|
||||
<key id="7" name="sb_1__1_" value="0"/>
|
||||
<key id="8" name="cbx_1__1_" value="1"/>
|
||||
<key id="9" name="cby_1__1_" value="1"/>
|
||||
<key id="10" name="grid_io_right" value="1"/>
|
||||
<key id="11" name="cbx_1__0_" value="1"/>
|
||||
<key id="12" name="cby_1__1_" value="0"/>
|
||||
<key id="13" name="grid_io_right" value="0"/>
|
||||
<key id="14" name="grid_io_bottom" value="0"/>
|
||||
<key id="15" name="cby_2__1_" value="0"/>
|
||||
<key id="16" name="sb_2__1_" value="0"/>
|
||||
<key id="17" name="cbx_1__0_" value="0"/>
|
||||
<key id="18" name="grid_clb" value="1"/>
|
||||
<key id="19" name="cbx_1__2_" value="0"/>
|
||||
<key id="20" name="cbx_1__2_" value="1"/>
|
||||
<key id="21" name="sb_2__0_" value="0"/>
|
||||
<key id="22" name="sb_1__2_" value="0"/>
|
||||
<key id="23" name="cby_0__1_" value="1"/>
|
||||
<key id="24" name="sb_0__0_" value="0"/>
|
||||
<key id="25" name="grid_clb" value="0"/>
|
||||
<key id="26" name="cby_2__1_" value="1"/>
|
||||
<key id="27" name="grid_io_top" value="1"/>
|
||||
<key id="28" name="sb_0__2_" value="0"/>
|
||||
<key id="29" name="grid_io_bottom" value="1"/>
|
||||
<key id="30" name="cbx_1__1_" value="0"/>
|
||||
<key id="31" name="grid_io_top" value="0"/>
|
||||
<key id="32" name="grid_io_left" value="1"/>
|
||||
</region>
|
||||
</fabric_key>
|
||||
|
||||
|
||||
|
|
After Width: | Height: | Size: 167 KiB |
After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 299 KiB |
|
@ -88,7 +88,7 @@ Inside the directory, the Verilog testbenches are organized as illustrated in :n
|
|||
.. _fig_preconfig_module:
|
||||
|
||||
.. figure:: ./figures/preconfig_module.png
|
||||
:scale: 100%
|
||||
:scale: 25%
|
||||
|
||||
Internal structure of a pre-configured FPGA module
|
||||
|
||||
|
|
|
@ -27,12 +27,43 @@ The rest of this section will focus on detailed motivation on each of them, as d
|
|||
|
||||
Design flows in different purposes using OpenFPGA
|
||||
|
||||
Fully Customizable Architecture
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
OpenFPGA supports VPR's architecture description language, which allows
|
||||
users to define versatile programmable fabrics down to point-to-point
|
||||
interconnection.
|
||||
OpenFPGA leverage VPR's architecture description by introducing an XML-based
|
||||
architecture annotation, enabling fully customizable FPGA fabric down to
|
||||
circuit elements.
|
||||
As illustrated in :ref:`fig_openfpga_arch_lang_coverage`, OpenFPGA's
|
||||
architecture annotation covers a complete FPGA fabric, including both the
|
||||
programmable fabric and the configuration peripheral.
|
||||
|
||||
.. _fig_openfpga_arch_lang_coverage:
|
||||
|
||||
.. figure:: ./figures/openfpga_arch_lang_coverage.png
|
||||
:scale: 15%
|
||||
:alt: OpenFPGA architecture description language enabling fully customizable FPGA architecture and circuit-level implementation
|
||||
|
||||
OpenFPGA architecture description language enabling fully customizable FPGA architecture and circuit-level implementation
|
||||
|
||||
The technical details can be found in our TVLSI'19 paper :cite:`XTang_TVLSI_2019` and FPL'19 paper :cite:`XTang_FPL_2019`.
|
||||
|
||||
FPGA-Verilog
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Driven by the strong need in data processing applications, Field Programmable Gate Arrays (FPGAs) are playing an ever-increasing role as programmable accelerators in modern
|
||||
computing systems. To fully unlock processing capabilities for domain-specific applications, FPGA architectures have to be tailored for seamless cooperation with other computing resources. However, prototyping and bringing to production a customized FPGA is a costly and complex endeavor even for industrial vendors. OpenFPGA, an opensource framework, aims to rapid prototype of customizable FPGA architectures through a semi-custom design approach. We propose an XML-to-Prototype design flow, where the Verilog netlists of a full FPGA fabric can be autogenerated using an extension of the XML language from the VTR framework and then fed into a back-end flow to generate production-ready layouts.
|
||||
FPGA-Verilog is designed to output flexible and standard Verilog netlists, enabling various backend choices, as illustrated in :ref:`fig_fpga_verilog_motivation`.
|
||||
|
||||
.. _fig_fpga_verilog_motivation:
|
||||
|
||||
.. figure:: ./figures/fpga_verilog_motivation.png
|
||||
:scale: 25%
|
||||
:alt: Flexible netlist format support by FPGA-Verilog to enable various backend choices
|
||||
|
||||
FPGA-Verilog enabling flexible backend flows
|
||||
|
||||
The technical details can be found in our TVLSI'19 paper :cite:`XTang_TVLSI_2019` and FPL'19 paper :cite:`XTang_FPL_2019`.
|
||||
|
||||
|
@ -41,7 +72,18 @@ FPGA-SDC
|
|||
|
||||
Design constraints are indepensible in modern ASIC design flows to guarantee the performance level.
|
||||
OpenFPGA includes a rich SDC generator in the OpenFPGA framework to deal with both PnR constraints and sign-off timing analysis.
|
||||
Our flow automatically generates two sets of SDC files. The first set of SDC is designed for the P&R flow, where all the combinational loops are broken to enable wellcontrolled timing-driven P&R. In addition, there are SDC files devoted to constrain pin-to-pin timing for all the resources in FPGAs, in order to obtain nicely constrained and homogeneous delays across the fabric. The second set of SDC is designed for the timing analysis of a benchmark at the post P&R stage.
|
||||
Our flow automatically generates two sets of SDC files.
|
||||
- The first set of SDC is designed for the P&R flow, where all the combinational loops are broken to enable wellcontrolled timing-driven P&R. In addition, there are SDC files devoted to constrain pin-to-pin timing for all the resources in FPGAs, in order to obtain nicely constrained and homogeneous delays across the fabric. OpenFPGA allows users to define timing constraints in the architecture description and outputs timing constraints in standard format, enabling fully timing constrained backend flow (see :ref:`fig_fpga_sdc_motivation`).
|
||||
- The second set of SDC is designed for the timing analysis of a benchmark at the post P&R stage.
|
||||
|
||||
.. _fig_fpga_sdc_motivation:
|
||||
|
||||
.. figure:: ./figures/fpga_sdc_motivation.png
|
||||
:scale: 25%
|
||||
:alt: FPGA-SDC enabling iterative timing constrained backend flow
|
||||
|
||||
FPGA-SDC enabling iterative timing constrained backend flow
|
||||
|
||||
|
||||
The technical details can be found in our FPL'19 paper :cite:`XTang_FPL_2019`.
|
||||
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
.. _eda_flow:
|
||||
|
||||
Supported EDA flows in OpenFPGA
|
||||
-------------------------------
|
||||
|
||||
As illustrated in :numref:`fig_eda_flow`, FPGA-SPICE creates a modified VTR flow. All the input files for VPR do not need modifications except the architecture description XML. As simulation-based power analysis requires the transistor-level netlists, we extend the architecture description language to support transistor-level modeling (See details in "Tools Guide>Extended Architecture Description Language"). FPGA-SPICE, embedded in VPR, outputs the SPICE netlists and testbenches according to placement and routing results when enabled by command-line options. (See each "FPGA-*Branch*" about command-line options available) Besides automatically generating all the SPICE netlists, FPGA-SPICE supports user-defined SPICE netlists for modules. We believe the support on user-defined SPICE netlists allows FPGA-SPICE to be general enough to support novel circuit designs and even technologies. (See "FPGA-SPICE... > Create Customized SPICE Modules" for guidelines in customizing your FPGA-SPICE compatible SPICE netlists.) With the dumped SPICE netlists and testbenches, a SPICE simulator, i.e., HSPICE, can be called to conduct a power analysis. FPGA-SPICE automatically generates a shell script, which brings convenience for users to run all the simulations (See "FPGA-SPICE... > Run SPICE simulation").
|
||||
|
||||
.. _fig_eda_flow:
|
||||
|
||||
.. figure:: ./figures/eda_flow.png
|
||||
:scale: 50%
|
||||
:alt: map to buried treasure
|
||||
|
||||
Detailed EDA flows based on FPGA-SPICE/Verilog/Bitstream in the purpose of (a) architecture of the output of FPGA-SPICE (b) functionality verification; (c) prototyping and area analysis and (d) power analysis. *TBD: change for Yosys*
|
||||
|
||||
FPGA-Verilog is the part of the flow in charge of the Verilog and the semi-custom design flow. In our case, we use Cadence Innovus. The goal is to get the full-FPGA layout to complete the analysis provided by FPGA-SPICE. By having the layout, we can get an area analysis on the one hand and have new information concerning the power analysis. For instance, having the layout allows the user to have new information on the circuit such as the parasitics.
|
||||
|
||||
FPGA-Bitstream is the part of the flow in charge of the functional verification of the produced FPGA. Testbenches are generated by FPGA-Verilog and are combined with the full FPGA fabric in Modelsim. A bitstream is generated at the same time as the testbenches. This bitstream configures the FPGA with the functionality given by the user to VPR at the beginning of the flow. First, we configure the FPGA with the bitstream, and then waveforms are sent onto the I/O pads to check the functionality.
|
Before Width: | Height: | Size: 268 KiB |
After Width: | Height: | Size: 818 KiB |
|
@ -6,7 +6,7 @@
|
|||
|
||||
compile
|
||||
|
||||
eda_flow
|
||||
tools
|
||||
|
||||
design_flow/index
|
||||
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
.. _openfpga_tools:
|
||||
|
||||
Supported Tools
|
||||
---------------
|
||||
|
||||
Internal Tools
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
To enable various design purposes, OpenFPGA integrates several tools to i.e., FPGA-Verilog, FPGA-SDC and FPGA-bitstream (highlighted green in :ref:`fig_openfpga_tools`, with other popular open-source EDA tools, i.e., VPR and Yosys.
|
||||
|
||||
.. _fig_openfpga_tools:
|
||||
|
||||
.. figure:: figures/openfpga_tools.png
|
||||
:scale: 25%
|
||||
:alt: map to buried treasure
|
||||
|
||||
OpenFPGA tool suites and design flows
|
||||
|
||||
Third-Party Tools
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
OpenFPGA accepts and outputs in standard file formats, and therefore can
|
||||
interface a wide range of commercial and open-source tools.
|
||||
|
||||
+--------------+-------------------------+
|
||||
| Usage | Tools |
|
||||
+==============+=========================+
|
||||
| Backend | Synopsys IC Compiler II |
|
||||
| | |
|
||||
| | Cadence Innovus |
|
||||
+--------------+-------------------------+
|
||||
| Timing | Synopsys PrimeTime |
|
||||
| Analyzer | |
|
||||
| | Cadence Tempus |
|
||||
+--------------+-------------------------+
|
||||
| Verification | Synopsys VCS |
|
||||
| | |
|
||||
| | Synopsys Formality |
|
||||
| | |
|
||||
| | Mentor ModelSim |
|
||||
| | |
|
||||
| | Mentor QuestaSim |
|
||||
| | |
|
||||
| | Cadence NCSim |
|
||||
| | |
|
||||
| | Icarus iVerilog |
|
||||
+--------------+-------------------------+
|
|
@ -28,6 +28,10 @@ CircuitModelId ConfigProtocol::memory_model() const {
|
|||
return memory_model_;
|
||||
}
|
||||
|
||||
int ConfigProtocol::num_regions() const {
|
||||
return num_regions_;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Public Mutators
|
||||
***********************************************************************/
|
||||
|
@ -42,3 +46,7 @@ void ConfigProtocol::set_memory_model_name(const std::string& memory_model_name)
|
|||
void ConfigProtocol::set_memory_model(const CircuitModelId& memory_model) {
|
||||
memory_model_ = memory_model;
|
||||
}
|
||||
|
||||
void ConfigProtocol::set_num_regions(const int& num_regions) {
|
||||
num_regions_ = num_regions;
|
||||
}
|
||||
|
|
|
@ -15,10 +15,12 @@ class ConfigProtocol {
|
|||
e_config_protocol_type type() const;
|
||||
std::string memory_model_name() const;
|
||||
CircuitModelId memory_model() const;
|
||||
int num_regions() const;
|
||||
public: /* Public Mutators */
|
||||
void set_type(const e_config_protocol_type& type);
|
||||
void set_memory_model_name(const std::string& memory_model_name);
|
||||
void set_memory_model(const CircuitModelId& memory_model);
|
||||
void set_num_regions(const int& num_regions);
|
||||
private: /* Internal data */
|
||||
/* The type of configuration protocol.
|
||||
* In other words, it is about how to organize and access each configurable memory
|
||||
|
@ -28,6 +30,9 @@ class ConfigProtocol {
|
|||
/* The circuit model of configuration memory to be used in the protocol */
|
||||
std::string memory_model_name_;
|
||||
CircuitModelId memory_model_;
|
||||
|
||||
/* Number of configurable regions */
|
||||
int num_regions_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -53,8 +53,18 @@ void read_xml_config_organization(pugi::xml_node& xml_config_orgz,
|
|||
|
||||
config_protocol.set_type(config_orgz_type);
|
||||
|
||||
/* Find the circuit model used by the configuration protocol */
|
||||
config_protocol.set_memory_model_name(get_attribute(xml_config_orgz, "circuit_model_name", loc_data).as_string());
|
||||
|
||||
/* Parse the number of configurable regions
|
||||
* At least 1 region should be defined, otherwise error out
|
||||
*/
|
||||
config_protocol.set_num_regions(get_attribute(xml_config_orgz, "num_regions", loc_data, pugiutil::ReqOpt::OPTIONAL).as_int(1));
|
||||
if (1 > config_protocol.num_regions()) {
|
||||
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_config_orgz),
|
||||
"Invalid 'num_region=%d' definition. At least 1 region should be defined!\n",
|
||||
config_protocol.num_regions());
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
<fabric_key>
|
||||
<key id="0" name="sb" value="0"/>
|
||||
<key id="2" name="cb" value="10"/>
|
||||
<key id="1" name="sb" value="7"/>
|
||||
<key id="3" name="clb" value="53"/>
|
||||
<key id="4" name="bram" value="32"/>
|
||||
<region id="0">
|
||||
<key id="0" name="sb" value="0"/>
|
||||
<key id="2" name="cb" value="10"/>
|
||||
<key id="1" name="sb" value="7"/>
|
||||
<key id="3" name="clb" value="53"/>
|
||||
<key id="4" name="bram" value="32"/>
|
||||
</region>
|
||||
</fabric_key>
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
#include <algorithm>
|
||||
|
||||
#include "vtr_assert.h"
|
||||
#include "vtr_log.h"
|
||||
|
||||
#include "fabric_key.h"
|
||||
|
||||
|
@ -20,24 +23,31 @@ FabricKey::fabric_key_range FabricKey::keys() const {
|
|||
return vtr::make_range(key_ids_.begin(), key_ids_.end());
|
||||
}
|
||||
|
||||
FabricKey::fabric_region_range FabricKey::regions() const {
|
||||
return vtr::make_range(region_ids_.begin(), region_ids_.end());
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Public Accessors : Basic data query
|
||||
***********************************************************************/
|
||||
/* Access the name of a key */
|
||||
std::vector<FabricKeyId> FabricKey::region_keys(const FabricRegionId& region_id) const {
|
||||
/* validate the region_id */
|
||||
VTR_ASSERT(valid_region_id(region_id));
|
||||
return region_key_ids_[region_id];
|
||||
}
|
||||
|
||||
std::string FabricKey::key_name(const FabricKeyId& key_id) const {
|
||||
/* validate the key_id */
|
||||
VTR_ASSERT(valid_key_id(key_id));
|
||||
return key_names_[key_id];
|
||||
}
|
||||
|
||||
/* Access the value of a key */
|
||||
size_t FabricKey::key_value(const FabricKeyId& key_id) const {
|
||||
/* validate the key_id */
|
||||
VTR_ASSERT(valid_key_id(key_id));
|
||||
return key_values_[key_id];
|
||||
}
|
||||
|
||||
/* Access the alias of a key */
|
||||
std::string FabricKey::key_alias(const FabricKeyId& key_id) const {
|
||||
/* validate the key_id */
|
||||
VTR_ASSERT(valid_key_id(key_id));
|
||||
|
@ -51,20 +61,78 @@ bool FabricKey::empty() const {
|
|||
/************************************************************************
|
||||
* Public Mutators
|
||||
***********************************************************************/
|
||||
|
||||
void FabricKey::reserve_regions(const size_t& num_regions) {
|
||||
region_ids_.reserve(num_regions);
|
||||
region_key_ids_.reserve(num_regions);
|
||||
}
|
||||
|
||||
FabricRegionId FabricKey::create_region() {
|
||||
/* Create a new id */
|
||||
FabricRegionId region = FabricRegionId(region_ids_.size());
|
||||
region_ids_.push_back(region);
|
||||
region_key_ids_.emplace_back();
|
||||
|
||||
return region;
|
||||
}
|
||||
|
||||
void FabricKey::reserve_region_keys(const FabricRegionId& region_id,
|
||||
const size_t& num_keys) {
|
||||
/* validate the region_id */
|
||||
VTR_ASSERT(valid_region_id(region_id));
|
||||
|
||||
region_key_ids_[region_id].reserve(num_keys);
|
||||
}
|
||||
|
||||
void FabricKey::add_key_to_region(const FabricRegionId& region_id,
|
||||
const FabricKeyId& key_id) {
|
||||
/* validate the key_id */
|
||||
VTR_ASSERT(valid_key_id(key_id));
|
||||
/* validate the region_id */
|
||||
VTR_ASSERT(valid_region_id(region_id));
|
||||
|
||||
/* Check if the key is already in the region */
|
||||
if (region_key_ids_[region_id].end() != std::find(region_key_ids_[region_id].begin(),
|
||||
region_key_ids_[region_id].end(),
|
||||
key_id)) {
|
||||
VTR_LOG_WARN("Try to add a key '%s' which is already in the region '%lu'!\n",
|
||||
key_name(key_id).c_str(),
|
||||
size_t(region_id));
|
||||
VTR_ASSERT(region_id == key_regions_[key_id]);
|
||||
return; /* Nothing to do but leave a warning! */
|
||||
}
|
||||
|
||||
/* Register the key in the region */
|
||||
region_key_ids_[region_id].push_back(key_id);
|
||||
|
||||
/* If the key is already in another region, we will error out */
|
||||
if ( (true == valid_region_id(key_regions_[key_id]))
|
||||
&& (region_id != key_regions_[key_id])) {
|
||||
VTR_LOG_ERROR("Try to add a key '%s' to region '%lu' but it is already in another region '%lu'!\n",
|
||||
key_name(key_id).c_str(),
|
||||
size_t(key_regions_[key_id]),
|
||||
size_t(region_id));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
key_regions_[key_id] = region_id;
|
||||
}
|
||||
|
||||
void FabricKey::reserve_keys(const size_t& num_keys) {
|
||||
key_ids_.reserve(num_keys);
|
||||
key_names_.reserve(num_keys);
|
||||
key_values_.reserve(num_keys);
|
||||
key_regions_.reserve(num_keys);
|
||||
key_alias_.reserve(num_keys);
|
||||
}
|
||||
|
||||
/* Create a new key and add it to the library, return an id */
|
||||
FabricKeyId FabricKey::create_key() {
|
||||
/* Create a new id */
|
||||
FabricKeyId key = FabricKeyId(key_ids_.size());
|
||||
key_ids_.push_back(key);
|
||||
key_names_.emplace_back();
|
||||
key_values_.emplace_back();
|
||||
key_regions_.emplace_back(FabricRegionId::INVALID());
|
||||
key_alias_.emplace_back();
|
||||
|
||||
return key;
|
||||
|
@ -98,6 +166,10 @@ void FabricKey::set_key_alias(const FabricKeyId& key_id,
|
|||
* Internal invalidators/validators
|
||||
***********************************************************************/
|
||||
/* Validators */
|
||||
bool FabricKey::valid_region_id(const FabricRegionId& region_id) const {
|
||||
return ( size_t(region_id) < region_ids_.size() ) && ( region_id == region_ids_[region_id] );
|
||||
}
|
||||
|
||||
bool FabricKey::valid_key_id(const FabricKeyId& key_id) const {
|
||||
return ( size_t(key_id) < key_ids_.size() ) && ( key_id == key_ids_[key_id] );
|
||||
}
|
||||
|
|
|
@ -15,41 +15,94 @@
|
|||
|
||||
/********************************************************************
|
||||
* A data structure to describe a secure key for fabric organization
|
||||
* A fabric may consist of multiple regions
|
||||
* Each region contains a number of keys
|
||||
*
|
||||
* Note that:
|
||||
* - each key can only be defined in one unique region
|
||||
*
|
||||
* Typical usage:
|
||||
* --------------
|
||||
* // Create an empty fabric key
|
||||
* FabricKey fabric_key;
|
||||
* // Create a region
|
||||
* FabricRegionId region = fabric_key.create_region();
|
||||
* // Add a key with name and value
|
||||
* FabricKeyId key = fabic_key.create_key(key_name, key_value);
|
||||
* FabricKeyId key = fabric_key.create_key(key_name, key_value);
|
||||
* // Affilate a key to a region
|
||||
* fabric_key.add_key_to_region(region, key);
|
||||
*
|
||||
*******************************************************************/
|
||||
class FabricKey {
|
||||
public: /* Types */
|
||||
typedef vtr::vector<FabricKeyId, FabricKeyId>::const_iterator fabric_key_iterator;
|
||||
typedef vtr::vector<FabricRegionId, FabricRegionId>::const_iterator fabric_region_iterator;
|
||||
/* Create range */
|
||||
typedef vtr::Range<fabric_region_iterator> fabric_region_range;
|
||||
typedef vtr::Range<fabric_key_iterator> fabric_key_range;
|
||||
public: /* Constructors */
|
||||
FabricKey();
|
||||
public: /* Accessors: aggregates */
|
||||
fabric_key_range keys() const;
|
||||
fabric_region_range regions() const;
|
||||
public: /* Public Accessors: Basic data query */
|
||||
/* Access all the keys of a region */
|
||||
std::vector<FabricKeyId> region_keys(const FabricRegionId& region_id) const;
|
||||
|
||||
/* Access the name of a key */
|
||||
std::string key_name(const FabricKeyId& key_id) const;
|
||||
|
||||
/* Access the value of a key */
|
||||
size_t key_value(const FabricKeyId& key_id) const;
|
||||
|
||||
/* Access the alias of a key */
|
||||
std::string key_alias(const FabricKeyId& key_id) const;
|
||||
|
||||
/* Check if there are any keys */
|
||||
bool empty() const;
|
||||
|
||||
public: /* Public Mutators: model-related */
|
||||
|
||||
/* Reserve a number of regions to be memory efficent */
|
||||
void reserve_regions(const size_t& num_regions);
|
||||
|
||||
/* Create a new region and add it to the library, return an id */
|
||||
FabricRegionId create_region();
|
||||
|
||||
/* Reserve the memory space for keys under a region, to be memory efficient */
|
||||
void reserve_region_keys(const FabricRegionId& region_id,
|
||||
const size_t& num_keys);
|
||||
|
||||
/* Add a key to a region */
|
||||
void add_key_to_region(const FabricRegionId& region_id,
|
||||
const FabricKeyId& key_id);
|
||||
|
||||
/* Reserve a number of keys to be memory efficent */
|
||||
void reserve_keys(const size_t& num_keys);
|
||||
|
||||
/* Create a new key and add it to the library, return an id */
|
||||
FabricKeyId create_key();
|
||||
|
||||
/* Configure attributes of a key */
|
||||
void set_key_name(const FabricKeyId& key_id,
|
||||
const std::string& name);
|
||||
|
||||
void set_key_value(const FabricKeyId& key_id,
|
||||
const size_t& value);
|
||||
|
||||
void set_key_alias(const FabricKeyId& key_id,
|
||||
const std::string& alias);
|
||||
|
||||
public: /* Public invalidators/validators */
|
||||
bool valid_region_id(const FabricRegionId& region_id) const;
|
||||
bool valid_key_id(const FabricKeyId& key_id) const;
|
||||
private: /* Internal data */
|
||||
/* Unique ids for each region */
|
||||
vtr::vector<FabricRegionId, FabricRegionId> region_ids_;
|
||||
|
||||
/* Key ids for each region */
|
||||
vtr::vector<FabricRegionId, std::vector<FabricKeyId>> region_key_ids_;
|
||||
|
||||
/* Unique ids for each key */
|
||||
vtr::vector<FabricKeyId, FabricKeyId> key_ids_;
|
||||
|
||||
|
@ -59,6 +112,9 @@ class FabricKey {
|
|||
/* Values for each key */
|
||||
vtr::vector<FabricKeyId, size_t> key_values_;
|
||||
|
||||
/* Region for each key */
|
||||
vtr::vector<FabricKeyId, FabricRegionId> key_regions_;
|
||||
|
||||
/* Optional alias for each key, with which a key can also be represented */
|
||||
vtr::vector<FabricKeyId, std::string> key_alias_;
|
||||
};
|
||||
|
|
|
@ -12,8 +12,10 @@
|
|||
|
||||
#include "vtr_strong_id.h"
|
||||
|
||||
struct fabric_region_id_tag;
|
||||
struct fabric_key_id_tag;
|
||||
|
||||
typedef vtr::StrongId<fabric_region_id_tag> FabricRegionId;
|
||||
typedef vtr::StrongId<fabric_key_id_tag> FabricKeyId;
|
||||
|
||||
/* Short declaration of class */
|
||||
|
|
|
@ -23,17 +23,19 @@
|
|||
* Parse XML codes of a <key> to an object of FabricKey
|
||||
*******************************************************************/
|
||||
static
|
||||
void read_xml_component_key(pugi::xml_node& xml_component_key,
|
||||
const pugiutil::loc_data& loc_data,
|
||||
FabricKey& fabric_key) {
|
||||
void read_xml_region_key(pugi::xml_node& xml_component_key,
|
||||
const pugiutil::loc_data& loc_data,
|
||||
FabricKey& fabric_key,
|
||||
const FabricRegionId& fabric_region) {
|
||||
|
||||
/* Find the id of component key */
|
||||
const size_t& id = get_attribute(xml_component_key, "id", loc_data).as_int();
|
||||
|
||||
if (false == fabric_key.valid_key_id(FabricKeyId(id))) {
|
||||
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_component_key),
|
||||
"Invalid 'id' attribute '%d'\n",
|
||||
id);
|
||||
"Invalid 'id' attribute '%d' (in total %lu keys)!\n",
|
||||
id,
|
||||
fabric_key.keys().size());
|
||||
}
|
||||
|
||||
VTR_ASSERT_SAFE(true == fabric_key.valid_key_id(FabricKeyId(id)));
|
||||
|
@ -57,6 +59,41 @@ void read_xml_component_key(pugi::xml_node& xml_component_key,
|
|||
|
||||
fabric_key.set_key_name(FabricKeyId(id), name);
|
||||
fabric_key.set_key_value(FabricKeyId(id), value);
|
||||
fabric_key.add_key_to_region(fabric_region, FabricKeyId(id));
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Parse XML codes of a <key> to an object of FabricKey
|
||||
*******************************************************************/
|
||||
static
|
||||
void read_xml_fabric_region(pugi::xml_node& xml_region,
|
||||
const pugiutil::loc_data& loc_data,
|
||||
FabricKey& fabric_key) {
|
||||
/* Find the unique id for the region */
|
||||
const FabricRegionId& region_id = FabricRegionId(get_attribute(xml_region, "id", loc_data).as_int());
|
||||
if (false == fabric_key.valid_region_id(region_id)) {
|
||||
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_region),
|
||||
"Invalid region id '%lu' (in total %lu regions)!\n",
|
||||
size_t(region_id),
|
||||
fabric_key.regions().size());
|
||||
}
|
||||
VTR_ASSERT_SAFE(true == fabric_key.valid_region_id(region_id));
|
||||
|
||||
/* Reserve memory space for the keys in the region */
|
||||
size_t num_keys = std::distance(xml_region.children().begin(), xml_region.children().end());
|
||||
fabric_key.reserve_region_keys(region_id, num_keys);
|
||||
|
||||
for (pugi::xml_node xml_key : xml_region.children()) {
|
||||
/* Error out if the XML child has an invalid name! */
|
||||
if (xml_key.name() != std::string("key")) {
|
||||
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_region),
|
||||
"Unexpected child '%s' in region '%lu', Region XML node can only contain keys!\n",
|
||||
xml_key.name(),
|
||||
size_t(region_id));
|
||||
}
|
||||
/* Parse the key for this region */
|
||||
read_xml_region_key(xml_key, loc_data, fabric_key, region_id);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
|
@ -77,7 +114,24 @@ FabricKey read_xml_fabric_key(const char* key_fname) {
|
|||
|
||||
pugi::xml_node xml_root = get_single_child(doc, "fabric_key", loc_data);
|
||||
|
||||
size_t num_keys = std::distance(xml_root.children().begin(), xml_root.children().end());
|
||||
size_t num_regions = std::distance(xml_root.children().begin(), xml_root.children().end());
|
||||
/* Reserve memory space for the region */
|
||||
fabric_key.reserve_regions(num_regions);
|
||||
for (size_t iregion = 0; iregion < num_regions; ++iregion) {
|
||||
fabric_key.create_region();
|
||||
}
|
||||
|
||||
/* Reserve memory space for the keys */
|
||||
size_t num_keys = 0;
|
||||
|
||||
for (pugi::xml_node xml_region : xml_root.children()) {
|
||||
/* Error out if the XML child has an invalid name! */
|
||||
if (xml_region.name() != std::string("region")) {
|
||||
bad_tag(xml_region, loc_data, xml_root, {"region"});
|
||||
}
|
||||
num_keys += std::distance(xml_region.children().begin(), xml_region.children().end());
|
||||
}
|
||||
|
||||
fabric_key.reserve_keys(num_keys);
|
||||
for (size_t ikey = 0; ikey < num_keys; ++ikey) {
|
||||
fabric_key.create_key();
|
||||
|
@ -86,12 +140,12 @@ FabricKey read_xml_fabric_key(const char* key_fname) {
|
|||
/* Iterate over the children under this node,
|
||||
* each child should be named after circuit_model
|
||||
*/
|
||||
for (pugi::xml_node xml_key : xml_root.children()) {
|
||||
for (pugi::xml_node xml_region : xml_root.children()) {
|
||||
/* Error out if the XML child has an invalid name! */
|
||||
if (xml_key.name() != std::string("key")) {
|
||||
bad_tag(xml_key, loc_data, xml_root, {"key"});
|
||||
if (xml_region.name() != std::string("region")) {
|
||||
bad_tag(xml_region, loc_data, xml_root, {"region"});
|
||||
}
|
||||
read_xml_component_key(xml_key, loc_data, fabric_key);
|
||||
read_xml_fabric_region(xml_region, loc_data, fabric_key);
|
||||
}
|
||||
} catch (pugiutil::XmlError& e) {
|
||||
archfpga_throw(key_fname, e.line(),
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#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 */
|
||||
|
@ -33,7 +35,8 @@ int write_xml_fabric_component_key(std::fstream& fp,
|
|||
return 2;
|
||||
}
|
||||
|
||||
fp << "\t" << "<key";
|
||||
openfpga::write_tab_to_file(fp, 2);
|
||||
fp << "<key";
|
||||
|
||||
if (false == fabric_key.valid_key_id(component_key)) {
|
||||
return 1;
|
||||
|
@ -79,12 +82,21 @@ int write_xml_fabric_key(const char* fname,
|
|||
|
||||
int err_code = 0;
|
||||
|
||||
/* Write component by component */
|
||||
for (const FabricKeyId& key : fabric_key.keys()) {
|
||||
err_code = write_xml_fabric_component_key(fp, fabric_key, key);
|
||||
if (0 != err_code) {
|
||||
return err_code;
|
||||
/* Write region by region */
|
||||
for (const FabricRegionId& region : fabric_key.regions()) {
|
||||
openfpga::write_tab_to_file(fp, 1);
|
||||
fp << "<region id=\"" << size_t(region) << "\"" << ">\n";
|
||||
|
||||
/* Write component by component */
|
||||
for (const FabricKeyId& key : fabric_key.region_keys(region)) {
|
||||
err_code = write_xml_fabric_component_key(fp, fabric_key, key);
|
||||
if (0 != err_code) {
|
||||
return err_code;
|
||||
}
|
||||
}
|
||||
|
||||
openfpga::write_tab_to_file(fp, 1);
|
||||
fp << "</region>" << "\n";
|
||||
}
|
||||
|
||||
/* Finish writing the root node */
|
||||
|
|
|
@ -122,7 +122,6 @@ int build_fabric(OpenfpgaContext& openfpga_ctx,
|
|||
VTR_ASSERT(false == fkey_fname.empty());
|
||||
curr_status = write_fabric_key_to_xml_file(openfpga_ctx.module_graph(),
|
||||
fkey_fname,
|
||||
openfpga_ctx.arch().config_protocol.type(),
|
||||
cmd_context.option_enable(cmd, opt_verbose));
|
||||
/* If there is any error, final status cannot be overwritten by a success flag */
|
||||
if (CMD_EXEC_SUCCESS != curr_status) {
|
||||
|
|
|
@ -120,7 +120,7 @@ int build_device_module_graph(ModuleManager& module_manager,
|
|||
openfpga_ctx.device_rr_gsb(),
|
||||
openfpga_ctx.tile_direct(),
|
||||
openfpga_ctx.arch().arch_direct,
|
||||
openfpga_ctx.arch().config_protocol.type(),
|
||||
openfpga_ctx.arch().config_protocol,
|
||||
sram_model,
|
||||
frame_view, compress_routing, duplicate_grid_pin,
|
||||
fabric_key, generate_random_fabric_key);
|
||||
|
|
|
@ -330,7 +330,7 @@ int build_top_module(ModuleManager& module_manager,
|
|||
const DeviceRRGSB& device_rr_gsb,
|
||||
const TileDirect& tile_direct,
|
||||
const ArchDirect& arch_direct,
|
||||
const e_config_protocol_type& sram_orgz_type,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const CircuitModelId& sram_model,
|
||||
const bool& frame_view,
|
||||
const bool& compact_routing_hierarchy,
|
||||
|
@ -396,7 +396,7 @@ int build_top_module(ModuleManager& module_manager,
|
|||
*/
|
||||
if (true == fabric_key.empty()) {
|
||||
organize_top_module_memory_modules(module_manager, top_module,
|
||||
circuit_lib, sram_orgz_type, sram_model,
|
||||
circuit_lib, config_protocol, sram_model,
|
||||
grids, grid_instance_ids,
|
||||
device_rr_gsb, sb_instance_ids, cb_instance_ids,
|
||||
compact_routing_hierarchy);
|
||||
|
@ -411,7 +411,7 @@ int build_top_module(ModuleManager& module_manager,
|
|||
|
||||
/* Shuffle the configurable children in a random sequence */
|
||||
if (true == generate_random_fabric_key) {
|
||||
shuffle_top_module_configurable_children(module_manager, top_module);
|
||||
shuffle_top_module_configurable_children(module_manager, top_module, config_protocol);
|
||||
}
|
||||
|
||||
/* Add shared SRAM ports from the sub-modules under this Verilog module
|
||||
|
@ -427,11 +427,11 @@ int build_top_module(ModuleManager& module_manager,
|
|||
* This is a much easier job after adding sub modules (instances),
|
||||
* we just need to find all the I/O ports from the child modules and build a list of it
|
||||
*/
|
||||
size_t module_num_config_bits = find_module_num_config_bits_from_child_modules(module_manager, top_module, circuit_lib, sram_model, sram_orgz_type);
|
||||
size_t module_num_config_bits = find_module_num_config_bits_from_child_modules(module_manager, top_module, circuit_lib, sram_model, config_protocol.type());
|
||||
if (0 < module_num_config_bits) {
|
||||
add_top_module_sram_ports(module_manager, top_module,
|
||||
circuit_lib, sram_model,
|
||||
sram_orgz_type, module_num_config_bits);
|
||||
config_protocol, module_num_config_bits);
|
||||
}
|
||||
|
||||
/* Add module nets to connect memory cells inside
|
||||
|
@ -440,7 +440,7 @@ int build_top_module(ModuleManager& module_manager,
|
|||
if (0 < module_manager.configurable_children(top_module).size()) {
|
||||
add_top_module_nets_memory_config_bus(module_manager, decoder_lib,
|
||||
top_module,
|
||||
sram_orgz_type, circuit_lib.design_tech_type(sram_model),
|
||||
config_protocol, circuit_lib.design_tech_type(sram_model),
|
||||
module_num_config_bits);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "decoder_library.h"
|
||||
#include "tile_direct.h"
|
||||
#include "arch_direct.h"
|
||||
#include "config_protocol.h"
|
||||
#include "module_manager.h"
|
||||
#include "io_location_map.h"
|
||||
#include "fabric_key.h"
|
||||
|
@ -34,7 +35,7 @@ int build_top_module(ModuleManager& module_manager,
|
|||
const DeviceRRGSB& device_rr_gsb,
|
||||
const TileDirect& tile_direct,
|
||||
const ArchDirect& arch_direct,
|
||||
const e_config_protocol_type& sram_orgz_type,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const CircuitModelId& sram_model,
|
||||
const bool& frame_view,
|
||||
const bool& compact_routing_hierarchy,
|
||||
|
|
|
@ -176,6 +176,100 @@ void organize_top_module_tile_memory_modules(ModuleManager& module_manager,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Split memory modules into different configurable regions
|
||||
* This function will create regions based on the definition
|
||||
* in the configuration protocols, to accommodate each configurable
|
||||
* child under the top-level module
|
||||
*
|
||||
* For example:
|
||||
* FPGA Top-level module
|
||||
* +----------------------+
|
||||
* | | |
|
||||
* | Region 0 | Region 1 |
|
||||
* | | |
|
||||
* +----------------------+
|
||||
* | | |
|
||||
* | Region 2 | Region 3 |
|
||||
* | | |
|
||||
* +----------------------+
|
||||
*
|
||||
* A typical organization of a Region X
|
||||
* +-----------------------+
|
||||
* | |
|
||||
* | +------+ +------+ |
|
||||
* | | | | | |
|
||||
* | | Tile | | Tile | ... |
|
||||
* | | | | | |
|
||||
* | +------+ +------+ |
|
||||
* | ... ... |
|
||||
* | |
|
||||
* | +------+ +------+ |
|
||||
* | | | | | |
|
||||
* | | Tile | | Tile | ... |
|
||||
* | | | | | |
|
||||
* | +------+ +------+ |
|
||||
* +-----------------------+
|
||||
*
|
||||
* Note:
|
||||
* - This function should NOT modify configurable children
|
||||
*
|
||||
*******************************************************************/
|
||||
static
|
||||
void build_top_module_configurable_regions(ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const ConfigProtocol& config_protocol) {
|
||||
|
||||
vtr::ScopedStartFinishTimer timer("Build configurable regions for the top module");
|
||||
|
||||
/* Ensure we have valid configurable children */
|
||||
VTR_ASSERT(false == module_manager.configurable_children(top_module).empty());
|
||||
|
||||
/* Ensure that our region definition is valid */
|
||||
VTR_ASSERT(1 <= config_protocol.num_regions());
|
||||
|
||||
/* Exclude decoders from the list */
|
||||
size_t num_configurable_children = module_manager.configurable_children(top_module).size();
|
||||
if (CONFIG_MEM_MEMORY_BANK == config_protocol.type()) {
|
||||
num_configurable_children -= 2;
|
||||
} else if (CONFIG_MEM_FRAME_BASED == config_protocol.type()) {
|
||||
num_configurable_children -= 1;
|
||||
}
|
||||
|
||||
/* Evenly place each configurable child to each region */
|
||||
size_t num_children_per_region = num_configurable_children / config_protocol.num_regions();
|
||||
size_t region_child_counter = 0;
|
||||
bool create_region = true;
|
||||
ConfigRegionId curr_region = ConfigRegionId::INVALID();
|
||||
for (size_t ichild = 0; ichild < module_manager.configurable_children(top_module).size(); ++ichild) {
|
||||
if (true == create_region) {
|
||||
curr_region = module_manager.add_config_region(top_module);
|
||||
}
|
||||
|
||||
/* Add the child to a region */
|
||||
module_manager.add_configurable_child_to_region(top_module,
|
||||
curr_region,
|
||||
module_manager.configurable_children(top_module)[ichild],
|
||||
module_manager.configurable_child_instances(top_module)[ichild],
|
||||
ichild);
|
||||
|
||||
/* See if the current region is full or not:
|
||||
* For the last region, we will keep adding until we finish all the children
|
||||
*/
|
||||
region_child_counter++;
|
||||
if (region_child_counter < num_children_per_region) {
|
||||
create_region = false;
|
||||
} else if (size_t(curr_region) < (size_t)config_protocol.num_regions() - 1) {
|
||||
create_region = true;
|
||||
region_child_counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ensure that the number of configurable regions created matches the definition */
|
||||
VTR_ASSERT((size_t)config_protocol.num_regions() == module_manager.regions(top_module).size());
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Organize the list of memory modules and instances
|
||||
* This function will record all the sub modules of the top-level module
|
||||
|
@ -273,7 +367,7 @@ void organize_top_module_tile_memory_modules(ModuleManager& module_manager,
|
|||
void organize_top_module_memory_modules(ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const e_config_protocol_type& sram_orgz_type,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const CircuitModelId& sram_model,
|
||||
const DeviceGrid& grids,
|
||||
const vtr::Matrix<size_t>& grid_instance_ids,
|
||||
|
@ -332,7 +426,7 @@ void organize_top_module_memory_modules(ModuleManager& module_manager,
|
|||
for (const vtr::Point<size_t>& io_coord : io_coords[io_side]) {
|
||||
/* Identify the GSB that surrounds the grid */
|
||||
organize_top_module_tile_memory_modules(module_manager, top_module,
|
||||
circuit_lib, sram_orgz_type, sram_model,
|
||||
circuit_lib, config_protocol.type(), sram_model,
|
||||
grids, grid_instance_ids,
|
||||
device_rr_gsb, sb_instance_ids, cb_instance_ids,
|
||||
compact_routing_hierarchy,
|
||||
|
@ -362,12 +456,15 @@ void organize_top_module_memory_modules(ModuleManager& module_manager,
|
|||
|
||||
for (const vtr::Point<size_t>& core_coord : core_coords) {
|
||||
organize_top_module_tile_memory_modules(module_manager, top_module,
|
||||
circuit_lib, sram_orgz_type, sram_model,
|
||||
circuit_lib, config_protocol.type(), sram_model,
|
||||
grids, grid_instance_ids,
|
||||
device_rr_gsb, sb_instance_ids, cb_instance_ids,
|
||||
compact_routing_hierarchy,
|
||||
core_coord, NUM_SIDES);
|
||||
}
|
||||
|
||||
/* Split memory modules into different regions */
|
||||
build_top_module_configurable_regions(module_manager, top_module, config_protocol);
|
||||
}
|
||||
|
||||
|
||||
|
@ -375,13 +472,18 @@ void organize_top_module_memory_modules(ModuleManager& module_manager,
|
|||
* Shuffle the configurable children in a random sequence
|
||||
*
|
||||
* TODO: May use a more customized shuffle mechanism
|
||||
* TODO: Apply region-based shuffling
|
||||
* The shuffling will be applied to each separated regions
|
||||
* Configurable children will not shuffled from a region
|
||||
* to another, instead they should stay in the same region
|
||||
*
|
||||
* Note:
|
||||
* - This function should NOT be called
|
||||
* before allocating any configurable child
|
||||
********************************************************************/
|
||||
void shuffle_top_module_configurable_children(ModuleManager& module_manager,
|
||||
const ModuleId& top_module) {
|
||||
const ModuleId& top_module,
|
||||
const ConfigProtocol& config_protocol) {
|
||||
size_t num_keys = module_manager.configurable_children(top_module).size();
|
||||
std::vector<size_t> shuffled_keys;
|
||||
shuffled_keys.reserve(num_keys);
|
||||
|
@ -403,6 +505,10 @@ void shuffle_top_module_configurable_children(ModuleManager& module_manager,
|
|||
orig_configurable_children[shuffled_keys[ikey]],
|
||||
orig_configurable_child_instances[shuffled_keys[ikey]]);
|
||||
}
|
||||
|
||||
/* Reset configurable regions */
|
||||
module_manager.clear_config_region(top_module);
|
||||
build_top_module_configurable_regions(module_manager, top_module, config_protocol);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
|
@ -421,57 +527,104 @@ int load_top_module_memory_modules_from_fabric_key(ModuleManager& module_manager
|
|||
/* Ensure a clean start */
|
||||
module_manager.clear_configurable_children(top_module);
|
||||
|
||||
for (const FabricKeyId& key : fabric_key.keys()) {
|
||||
/* Find if instance id is valid */
|
||||
std::pair<ModuleId, size_t> instance_info(ModuleId::INVALID(), 0);
|
||||
/* If we have an alias, we try to find a instance in this name */
|
||||
if (!fabric_key.key_alias(key).empty()) {
|
||||
/* If we have the key, we can quickly spot instance id.
|
||||
* Otherwise, we have to exhaustively find the module id and instance id
|
||||
*/
|
||||
if (!fabric_key.key_name(key).empty()) {
|
||||
size_t curr_configurable_child_id = 0;
|
||||
|
||||
for (const FabricRegionId& region : fabric_key.regions()) {
|
||||
/* Create a configurable region in the top module */
|
||||
ConfigRegionId top_module_config_region = module_manager.add_config_region(top_module);
|
||||
for (const FabricKeyId& key : fabric_key.region_keys(region)) {
|
||||
/* Find if instance id is valid */
|
||||
std::pair<ModuleId, size_t> instance_info(ModuleId::INVALID(), 0);
|
||||
/* If we have an alias, we try to find a instance in this name */
|
||||
if (!fabric_key.key_alias(key).empty()) {
|
||||
/* If we have the key, we can quickly spot instance id.
|
||||
* Otherwise, we have to exhaustively find the module id and instance id
|
||||
*/
|
||||
if (!fabric_key.key_name(key).empty()) {
|
||||
instance_info.first = module_manager.find_module(fabric_key.key_name(key));
|
||||
instance_info.second = module_manager.instance_id(top_module, instance_info.first, fabric_key.key_alias(key));
|
||||
} else {
|
||||
instance_info = find_module_manager_instance_module_info(module_manager, top_module, fabric_key.key_alias(key));
|
||||
}
|
||||
} else {
|
||||
/* If we do not have an alias, we use the name and value to build the info deck */
|
||||
instance_info.first = module_manager.find_module(fabric_key.key_name(key));
|
||||
instance_info.second = module_manager.instance_id(top_module, instance_info.first, fabric_key.key_alias(key));
|
||||
} else {
|
||||
instance_info = find_module_manager_instance_module_info(module_manager, top_module, fabric_key.key_alias(key));
|
||||
instance_info.second = fabric_key.key_value(key);
|
||||
}
|
||||
} else {
|
||||
/* If we do not have an alias, we use the name and value to build the info deck */
|
||||
instance_info.first = module_manager.find_module(fabric_key.key_name(key));
|
||||
instance_info.second = fabric_key.key_value(key);
|
||||
}
|
||||
|
||||
if (false == module_manager.valid_module_id(instance_info.first)) {
|
||||
if (!fabric_key.key_alias(key).empty()) {
|
||||
VTR_LOG_ERROR("Invalid key alias '%s'!\n",
|
||||
fabric_key.key_alias(key).c_str());
|
||||
} else {
|
||||
VTR_LOG_ERROR("Invalid key name '%s'!\n",
|
||||
fabric_key.key_name(key).c_str());
|
||||
if (false == module_manager.valid_module_id(instance_info.first)) {
|
||||
if (!fabric_key.key_alias(key).empty()) {
|
||||
VTR_LOG_ERROR("Invalid key alias '%s'!\n",
|
||||
fabric_key.key_alias(key).c_str());
|
||||
} else {
|
||||
VTR_LOG_ERROR("Invalid key name '%s'!\n",
|
||||
fabric_key.key_name(key).c_str());
|
||||
}
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
|
||||
if (false == module_manager.valid_module_instance_id(top_module, instance_info.first, instance_info.second)) {
|
||||
if (!fabric_key.key_alias(key).empty()) {
|
||||
VTR_LOG_ERROR("Invalid key alias '%s'!\n",
|
||||
fabric_key.key_alias(key).c_str());
|
||||
} else {
|
||||
VTR_LOG_ERROR("Invalid key value '%ld'!\n",
|
||||
instance_info.second);
|
||||
if (false == module_manager.valid_module_instance_id(top_module, instance_info.first, instance_info.second)) {
|
||||
if (!fabric_key.key_alias(key).empty()) {
|
||||
VTR_LOG_ERROR("Invalid key alias '%s'!\n",
|
||||
fabric_key.key_alias(key).c_str());
|
||||
} else {
|
||||
VTR_LOG_ERROR("Invalid key value '%ld'!\n",
|
||||
instance_info.second);
|
||||
}
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
|
||||
/* Now we can add the child to configurable children of the top module */
|
||||
module_manager.add_configurable_child(top_module,
|
||||
instance_info.first,
|
||||
instance_info.second);
|
||||
/* Now we can add the child to configurable children of the top module */
|
||||
module_manager.add_configurable_child(top_module,
|
||||
instance_info.first,
|
||||
instance_info.second);
|
||||
module_manager.add_configurable_child_to_region(top_module,
|
||||
top_module_config_region,
|
||||
instance_info.first,
|
||||
instance_info.second,
|
||||
curr_configurable_child_id);
|
||||
curr_configurable_child_id++;
|
||||
}
|
||||
}
|
||||
|
||||
return CMD_EXEC_SUCCESS;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Generate a list of ports that are used for SRAM configuration
|
||||
* to the top-level module
|
||||
* 1. Standalone SRAMs:
|
||||
* use the suggested port_size
|
||||
* 2. Scan-chain Flip-flops:
|
||||
* IMPORTANT: the port size will be limited by the number of configurable regions
|
||||
* 3. Memory decoders:
|
||||
* use the suggested port_size
|
||||
********************************************************************/
|
||||
static
|
||||
size_t generate_top_module_sram_port_size(const ConfigProtocol& config_protocol,
|
||||
const size_t& num_config_bits) {
|
||||
size_t sram_port_size = num_config_bits;
|
||||
|
||||
switch (config_protocol.type()) {
|
||||
case CONFIG_MEM_STANDALONE:
|
||||
break;
|
||||
case CONFIG_MEM_SCAN_CHAIN:
|
||||
/* CCFF head/tail are single-bit ports */
|
||||
sram_port_size = config_protocol.num_regions();
|
||||
break;
|
||||
case CONFIG_MEM_MEMORY_BANK:
|
||||
break;
|
||||
case CONFIG_MEM_FRAME_BASED:
|
||||
break;
|
||||
default:
|
||||
VTR_LOGF_ERROR(__FILE__, __LINE__,
|
||||
"Invalid type of SRAM organization!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return sram_port_size;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Add a list of ports that are used for SRAM configuration to the FPGA
|
||||
* top-level module
|
||||
|
@ -499,13 +652,13 @@ void add_top_module_sram_ports(ModuleManager& module_manager,
|
|||
const ModuleId& module_id,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& sram_model,
|
||||
const e_config_protocol_type sram_orgz_type,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const size_t& num_config_bits) {
|
||||
std::vector<std::string> sram_port_names = generate_sram_port_names(circuit_lib, sram_model, sram_orgz_type);
|
||||
size_t sram_port_size = generate_sram_port_size(sram_orgz_type, num_config_bits);
|
||||
std::vector<std::string> sram_port_names = generate_sram_port_names(circuit_lib, sram_model, config_protocol.type());
|
||||
size_t sram_port_size = generate_top_module_sram_port_size(config_protocol, num_config_bits);
|
||||
|
||||
/* Add ports to the module manager */
|
||||
switch (sram_orgz_type) {
|
||||
switch (config_protocol.type()) {
|
||||
case CONFIG_MEM_STANDALONE: {
|
||||
for (const std::string& sram_port_name : sram_port_names) {
|
||||
/* Add generated ports to the ModuleManager */
|
||||
|
@ -821,6 +974,124 @@ void add_top_module_nets_cmos_memory_bank_config_bus(ModuleManager& module_manag
|
|||
module_manager.add_configurable_child(top_module, wl_decoder_module, 0);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Connect all the memory modules under the parent module in a chain
|
||||
*
|
||||
* Region 0:
|
||||
* +--------+ +--------+ +--------+
|
||||
* ccff_head[0] --->| Memory |--->| Memory |--->... --->| Memory |----> ccff_tail[0]
|
||||
* | Module | | Module | | Module |
|
||||
* | [0] | | [1] | | [N-1] |
|
||||
* +--------+ +--------+ +--------+
|
||||
*
|
||||
* Region 1:
|
||||
* +--------+ +--------+ +--------+
|
||||
* ccff_head[1] --->| Memory |--->| Memory |--->... --->| Memory |----> ccff_tail[1]
|
||||
* | Module | | Module | | Module |
|
||||
* | [0] | | [1] | | [N-1] |
|
||||
* +--------+ +--------+ +--------+
|
||||
*
|
||||
* For the 1st memory module:
|
||||
* net source is the configuration chain head of the primitive module
|
||||
* net sink is the configuration chain head of the next memory module
|
||||
*
|
||||
* For the rest of memory modules:
|
||||
* net source is the configuration chain tail of the previous memory module
|
||||
* net sink is the configuration chain head of the next memory module
|
||||
*********************************************************************/
|
||||
static
|
||||
void add_top_module_nets_cmos_memory_chain_config_bus(ModuleManager& module_manager,
|
||||
const ModuleId& parent_module,
|
||||
const ConfigProtocol& config_protocol) {
|
||||
for (const ConfigRegionId& config_region : module_manager.regions(parent_module)) {
|
||||
for (size_t mem_index = 0; mem_index < module_manager.region_configurable_children(parent_module, config_region).size(); ++mem_index) {
|
||||
ModuleId net_src_module_id;
|
||||
size_t net_src_instance_id;
|
||||
ModulePortId net_src_port_id;
|
||||
size_t net_src_pin_id;
|
||||
|
||||
ModuleId net_sink_module_id;
|
||||
size_t net_sink_instance_id;
|
||||
ModulePortId net_sink_port_id;
|
||||
size_t net_sink_pin_id;
|
||||
|
||||
if (0 == mem_index) {
|
||||
/* Find the port name of configuration chain head */
|
||||
std::string src_port_name = generate_sram_port_name(config_protocol.type(), CIRCUIT_MODEL_PORT_INPUT);
|
||||
net_src_module_id = parent_module;
|
||||
net_src_instance_id = 0;
|
||||
net_src_port_id = module_manager.find_module_port(net_src_module_id, src_port_name);
|
||||
net_src_pin_id = size_t(config_region);
|
||||
|
||||
/* Find the port name of next memory module */
|
||||
std::string sink_port_name = generate_configuration_chain_head_name();
|
||||
net_sink_module_id = module_manager.region_configurable_children(parent_module, config_region)[mem_index];
|
||||
net_sink_instance_id = module_manager.region_configurable_child_instances(parent_module, config_region)[mem_index];
|
||||
net_sink_port_id = module_manager.find_module_port(net_sink_module_id, sink_port_name);
|
||||
net_sink_pin_id = 0;
|
||||
} else {
|
||||
/* Find the port name of previous memory module */
|
||||
std::string src_port_name = generate_configuration_chain_tail_name();
|
||||
net_src_module_id = module_manager.region_configurable_children(parent_module, config_region)[mem_index - 1];
|
||||
net_src_instance_id = module_manager.region_configurable_child_instances(parent_module, config_region)[mem_index - 1];
|
||||
net_src_port_id = module_manager.find_module_port(net_src_module_id, src_port_name);
|
||||
net_src_pin_id = 0;
|
||||
|
||||
/* Find the port name of next memory module */
|
||||
std::string sink_port_name = generate_configuration_chain_head_name();
|
||||
net_sink_module_id = module_manager.region_configurable_children(parent_module, config_region)[mem_index];
|
||||
net_sink_instance_id = module_manager.region_configurable_child_instances(parent_module, config_region)[mem_index];
|
||||
net_sink_port_id = module_manager.find_module_port(net_sink_module_id, sink_port_name);
|
||||
net_sink_pin_id = 0;
|
||||
}
|
||||
|
||||
/* Get the pin id for source port */
|
||||
BasicPort net_src_port = module_manager.module_port(net_src_module_id, net_src_port_id);
|
||||
/* Get the pin id for sink port */
|
||||
BasicPort net_sink_port = module_manager.module_port(net_sink_module_id, net_sink_port_id);
|
||||
|
||||
VTR_ASSERT(net_src_pin_id < net_src_port.get_width());
|
||||
VTR_ASSERT(net_sink_pin_id < net_sink_port.get_width());
|
||||
|
||||
/* Create a net and add source and sink to it */
|
||||
ModuleNetId net = create_module_source_pin_net(module_manager, parent_module, net_src_module_id, net_src_instance_id, net_src_port_id, net_src_port.pins()[net_src_pin_id]);
|
||||
/* Add net sink */
|
||||
module_manager.add_module_net_sink(parent_module, net, net_sink_module_id, net_sink_instance_id, net_sink_port_id, net_sink_port.pins()[net_sink_pin_id]);
|
||||
}
|
||||
|
||||
/* For the last memory module:
|
||||
* net source is the configuration chain tail of the previous memory module
|
||||
* net sink is the configuration chain tail of the primitive module
|
||||
*/
|
||||
/* Find the port name of previous memory module */
|
||||
std::string src_port_name = generate_configuration_chain_tail_name();
|
||||
ModuleId net_src_module_id = module_manager.region_configurable_children(parent_module, config_region).back();
|
||||
size_t net_src_instance_id = module_manager.region_configurable_child_instances(parent_module, config_region).back();
|
||||
ModulePortId net_src_port_id = module_manager.find_module_port(net_src_module_id, src_port_name);
|
||||
size_t net_src_pin_id = 0;
|
||||
|
||||
/* Find the port name of next memory module */
|
||||
std::string sink_port_name = generate_sram_port_name(config_protocol.type(), CIRCUIT_MODEL_PORT_OUTPUT);
|
||||
ModuleId net_sink_module_id = parent_module;
|
||||
size_t net_sink_instance_id = 0;
|
||||
ModulePortId net_sink_port_id = module_manager.find_module_port(net_sink_module_id, sink_port_name);
|
||||
size_t net_sink_pin_id = size_t(config_region);
|
||||
|
||||
/* Get the pin id for source port */
|
||||
BasicPort net_src_port = module_manager.module_port(net_src_module_id, net_src_port_id);
|
||||
/* Get the pin id for sink port */
|
||||
BasicPort net_sink_port = module_manager.module_port(net_sink_module_id, net_sink_port_id);
|
||||
|
||||
VTR_ASSERT(net_src_pin_id < net_src_port.get_width());
|
||||
VTR_ASSERT(net_sink_pin_id < net_sink_port.get_width());
|
||||
|
||||
/* Create a net and add source and sink to it */
|
||||
ModuleNetId net = create_module_source_pin_net(module_manager, parent_module, net_src_module_id, net_src_instance_id, net_src_port_id, net_src_port.pins()[net_src_pin_id]);
|
||||
/* Add net sink */
|
||||
module_manager.add_module_net_sink(parent_module, net, net_sink_module_id, net_sink_instance_id, net_sink_port_id, net_sink_port.pins()[net_sink_pin_id]);
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Add the port-to-port connection between all the memory modules
|
||||
* and their parent module
|
||||
|
@ -869,17 +1140,17 @@ static
|
|||
void add_top_module_nets_cmos_memory_config_bus(ModuleManager& module_manager,
|
||||
DecoderLibrary& decoder_lib,
|
||||
const ModuleId& parent_module,
|
||||
const e_config_protocol_type& sram_orgz_type,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const size_t& num_config_bits) {
|
||||
switch (sram_orgz_type) {
|
||||
switch (config_protocol.type()) {
|
||||
case CONFIG_MEM_STANDALONE:
|
||||
add_module_nets_cmos_flatten_memory_config_bus(module_manager, parent_module,
|
||||
sram_orgz_type, CIRCUIT_MODEL_PORT_BL);
|
||||
config_protocol.type(), CIRCUIT_MODEL_PORT_BL);
|
||||
add_module_nets_cmos_flatten_memory_config_bus(module_manager, parent_module,
|
||||
sram_orgz_type, CIRCUIT_MODEL_PORT_WL);
|
||||
config_protocol.type(), CIRCUIT_MODEL_PORT_WL);
|
||||
break;
|
||||
case CONFIG_MEM_SCAN_CHAIN: {
|
||||
add_module_nets_cmos_memory_chain_config_bus(module_manager, parent_module, CONFIG_MEM_SCAN_CHAIN);
|
||||
add_top_module_nets_cmos_memory_chain_config_bus(module_manager, parent_module, config_protocol);
|
||||
break;
|
||||
}
|
||||
case CONFIG_MEM_MEMORY_BANK:
|
||||
|
@ -930,7 +1201,7 @@ void add_top_module_nets_cmos_memory_config_bus(ModuleManager& module_manager,
|
|||
void add_top_module_nets_memory_config_bus(ModuleManager& module_manager,
|
||||
DecoderLibrary& decoder_lib,
|
||||
const ModuleId& parent_module,
|
||||
const e_config_protocol_type& sram_orgz_type,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const e_circuit_model_design_tech& mem_tech,
|
||||
const size_t& num_config_bits) {
|
||||
|
||||
|
@ -940,7 +1211,7 @@ void add_top_module_nets_memory_config_bus(ModuleManager& module_manager,
|
|||
case CIRCUIT_MODEL_DESIGN_CMOS:
|
||||
add_top_module_nets_cmos_memory_config_bus(module_manager, decoder_lib,
|
||||
parent_module,
|
||||
sram_orgz_type,
|
||||
config_protocol,
|
||||
num_config_bits);
|
||||
break;
|
||||
case CIRCUIT_MODEL_DESIGN_RRAM:
|
||||
|
|
|
@ -11,10 +11,12 @@
|
|||
#include "module_manager.h"
|
||||
#include "circuit_types.h"
|
||||
#include "circuit_library.h"
|
||||
#include "config_protocol.h"
|
||||
#include "decoder_library.h"
|
||||
#include "device_grid.h"
|
||||
#include "device_rr_gsb.h"
|
||||
#include "fabric_key.h"
|
||||
#include "config_protocol.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
|
@ -26,7 +28,7 @@ namespace openfpga {
|
|||
void organize_top_module_memory_modules(ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const e_config_protocol_type& sram_orgz_type,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const CircuitModelId& sram_model,
|
||||
const DeviceGrid& grids,
|
||||
const vtr::Matrix<size_t>& grid_instance_ids,
|
||||
|
@ -36,7 +38,8 @@ void organize_top_module_memory_modules(ModuleManager& module_manager,
|
|||
const bool& compact_routing_hierarchy);
|
||||
|
||||
void shuffle_top_module_configurable_children(ModuleManager& module_manager,
|
||||
const ModuleId& top_module);
|
||||
const ModuleId& top_module,
|
||||
const ConfigProtocol& config_protocol);
|
||||
|
||||
int load_top_module_memory_modules_from_fabric_key(ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
|
@ -46,13 +49,13 @@ void add_top_module_sram_ports(ModuleManager& module_manager,
|
|||
const ModuleId& module_id,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& sram_model,
|
||||
const e_config_protocol_type sram_orgz_type,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const size_t& num_config_bits);
|
||||
|
||||
void add_top_module_nets_memory_config_bus(ModuleManager& module_manager,
|
||||
DecoderLibrary& decoder_lib,
|
||||
const ModuleId& parent_module,
|
||||
const e_config_protocol_type& sram_orgz_type,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const e_circuit_model_design_tech& mem_tech,
|
||||
const size_t& num_config_bits);
|
||||
|
||||
|
|
|
@ -29,7 +29,6 @@ namespace openfpga {
|
|||
***************************************************************************************/
|
||||
int write_fabric_key_to_xml_file(const ModuleManager& module_manager,
|
||||
const std::string& fname,
|
||||
const e_config_protocol_type& config_protocol_type,
|
||||
const bool& verbose) {
|
||||
std::string timer_message = std::string("Write fabric key to XML file '") + fname + std::string("'");
|
||||
|
||||
|
@ -58,31 +57,36 @@ int write_fabric_key_to_xml_file(const ModuleManager& module_manager,
|
|||
FabricKey fabric_key;
|
||||
size_t num_keys = module_manager.configurable_children(top_module).size();
|
||||
|
||||
/* Exclude configuration-related modules in the keys */
|
||||
if (CONFIG_MEM_MEMORY_BANK == config_protocol_type) {
|
||||
num_keys -= 2;
|
||||
} else if (CONFIG_MEM_FRAME_BASED == config_protocol_type) {
|
||||
num_keys -= 1;
|
||||
}
|
||||
|
||||
fabric_key.reserve_keys(num_keys);
|
||||
|
||||
for (size_t ichild = 0; ichild < num_keys; ++ichild) {
|
||||
ModuleId child_module = module_manager.configurable_children(top_module)[ichild];
|
||||
size_t child_instance = module_manager.configurable_child_instances(top_module)[ichild];
|
||||
size_t num_regions = module_manager.regions(top_module).size();
|
||||
fabric_key.reserve_regions(num_regions);
|
||||
|
||||
FabricKeyId key = fabric_key.create_key();
|
||||
fabric_key.set_key_name(key, module_manager.module_name(child_module));
|
||||
fabric_key.set_key_value(key, child_instance);
|
||||
/* Create regions for the keys and load keys by region */
|
||||
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
|
||||
FabricRegionId fabric_region = fabric_key.create_region();
|
||||
fabric_key.reserve_region_keys(fabric_region, module_manager.region_configurable_children(top_module, config_region).size());
|
||||
|
||||
if (false == module_manager.instance_name(top_module, child_module, child_instance).empty()) {
|
||||
fabric_key.set_key_alias(key, module_manager.instance_name(top_module, child_module, child_instance));
|
||||
for (size_t ichild = 0; ichild < module_manager.region_configurable_children(top_module, config_region).size(); ++ichild) {
|
||||
ModuleId child_module = module_manager.region_configurable_children(top_module, config_region)[ichild];
|
||||
size_t child_instance = module_manager.region_configurable_child_instances(top_module, config_region)[ichild];
|
||||
|
||||
FabricKeyId key = fabric_key.create_key();
|
||||
fabric_key.set_key_name(key, module_manager.module_name(child_module));
|
||||
fabric_key.set_key_value(key, child_instance);
|
||||
|
||||
if (false == module_manager.instance_name(top_module, child_module, child_instance).empty()) {
|
||||
fabric_key.set_key_alias(key, module_manager.instance_name(top_module, child_module, child_instance));
|
||||
}
|
||||
|
||||
/* Add keys to the region */
|
||||
fabric_key.add_key_to_region(fabric_region, key);
|
||||
}
|
||||
}
|
||||
|
||||
VTR_LOGV(verbose,
|
||||
"Created %lu keys for the top module %s.\n",
|
||||
num_keys, top_module_name.c_str());
|
||||
"Created %lu regions and %lu keys for the top module %s.\n",
|
||||
num_regions, num_keys, top_module_name.c_str());
|
||||
|
||||
/* Call the XML writer for fabric key */
|
||||
int err_code = write_xml_fabric_key(fname.c_str(), fabric_key);
|
||||
|
|
|
@ -16,7 +16,6 @@ namespace openfpga {
|
|||
|
||||
int write_fabric_key_to_xml_file(const ModuleManager& module_manager,
|
||||
const std::string& fname,
|
||||
const e_config_protocol_type& config_protocol_type,
|
||||
const bool& verbose);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <numeric>
|
||||
#include <algorithm>
|
||||
#include "vtr_assert.h"
|
||||
#include "vtr_log.h"
|
||||
|
||||
#include "circuit_library.h"
|
||||
#include "module_manager.h"
|
||||
|
@ -97,6 +98,43 @@ ModuleManager::module_net_sink_range ModuleManager::module_net_sinks(const Modul
|
|||
return vtr::make_range(net_sink_ids_[module][net].begin(), net_sink_ids_[module][net].end());
|
||||
}
|
||||
|
||||
ModuleManager::region_range ModuleManager::regions(const ModuleId& module) const {
|
||||
VTR_ASSERT(valid_module_id(module));
|
||||
return vtr::make_range(config_region_ids_[module].begin(), config_region_ids_[module].end());
|
||||
}
|
||||
|
||||
std::vector<ModuleId> ModuleManager::region_configurable_children(const ModuleId& parent_module,
|
||||
const ConfigRegionId& region) const {
|
||||
/* Validate the module_id */
|
||||
VTR_ASSERT(valid_module_id(parent_module));
|
||||
VTR_ASSERT(valid_region_id(parent_module, region));
|
||||
|
||||
std::vector<ModuleId> region_config_children;
|
||||
region_config_children.reserve(config_region_children_[parent_module][region].size());
|
||||
|
||||
for (const size_t& child_id : config_region_children_[parent_module][region]) {
|
||||
region_config_children.push_back(configurable_children_[parent_module][child_id]);
|
||||
}
|
||||
|
||||
return region_config_children;
|
||||
}
|
||||
|
||||
std::vector<size_t> ModuleManager::region_configurable_child_instances(const ModuleId& parent_module,
|
||||
const ConfigRegionId& region) const {
|
||||
/* Validate the module_id */
|
||||
VTR_ASSERT(valid_module_id(parent_module));
|
||||
VTR_ASSERT(valid_region_id(parent_module, region));
|
||||
|
||||
std::vector<size_t> region_config_child_instances;
|
||||
region_config_child_instances.reserve(config_region_children_[parent_module][region].size());
|
||||
|
||||
for (const size_t& child_id : config_region_children_[parent_module][region]) {
|
||||
region_config_child_instances.push_back(configurable_child_instances_[parent_module][child_id]);
|
||||
}
|
||||
|
||||
return region_config_child_instances;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Public Accessors
|
||||
******************************************************************************/
|
||||
|
@ -482,6 +520,10 @@ ModuleId ModuleManager::add_module(const std::string& name) {
|
|||
child_instance_names_.emplace_back();
|
||||
configurable_children_.emplace_back();
|
||||
configurable_child_instances_.emplace_back();
|
||||
configurable_child_regions_.emplace_back();
|
||||
|
||||
config_region_ids_.emplace_back();
|
||||
config_region_children_.emplace_back();
|
||||
|
||||
port_ids_.emplace_back();
|
||||
ports_.emplace_back();
|
||||
|
@ -661,6 +703,7 @@ void ModuleManager::add_configurable_child(const ModuleId& parent_module,
|
|||
|
||||
configurable_children_[parent_module].push_back(child_module);
|
||||
configurable_child_instances_[parent_module].push_back(child_instance);
|
||||
configurable_child_regions_[parent_module].push_back(ConfigRegionId::INVALID());
|
||||
}
|
||||
|
||||
void ModuleManager::reserve_configurable_child(const ModuleId& parent_module,
|
||||
|
@ -673,6 +716,52 @@ void ModuleManager::reserve_configurable_child(const ModuleId& parent_module,
|
|||
if (num_children > configurable_child_instances_[parent_module].size()) {
|
||||
configurable_child_instances_[parent_module].reserve(num_children);
|
||||
}
|
||||
if (num_children > configurable_child_instances_[parent_module].size()) {
|
||||
configurable_child_regions_[parent_module].reserve(num_children);
|
||||
}
|
||||
}
|
||||
|
||||
ConfigRegionId ModuleManager::add_config_region(const ModuleId& module) {
|
||||
/* Validate the module id */
|
||||
VTR_ASSERT ( valid_module_id(module) );
|
||||
|
||||
/* Create an new id */
|
||||
ConfigRegionId config_region_id = ConfigRegionId(config_region_ids_[module].size());
|
||||
config_region_ids_[module].push_back(config_region_id);
|
||||
|
||||
config_region_children_[module].emplace_back();
|
||||
|
||||
return config_region_id;
|
||||
}
|
||||
|
||||
void ModuleManager::add_configurable_child_to_region(const ModuleId& parent_module,
|
||||
const ConfigRegionId& config_region,
|
||||
const ModuleId& child_module,
|
||||
const size_t& child_instance,
|
||||
const size_t& config_child_id) {
|
||||
/* Validate the module id */
|
||||
VTR_ASSERT ( valid_module_id(parent_module) );
|
||||
VTR_ASSERT ( valid_module_id(child_module) );
|
||||
VTR_ASSERT ( valid_region_id(parent_module, config_region) );
|
||||
|
||||
/* Ensure that the child module is in the configurable children list */
|
||||
VTR_ASSERT(child_module == configurable_children(parent_module)[config_child_id]);
|
||||
VTR_ASSERT(child_instance == configurable_child_instances(parent_module)[config_child_id]);
|
||||
|
||||
/* If the child is already in another region, error out */
|
||||
if ( (true == valid_region_id(parent_module, configurable_child_regions_[parent_module][config_child_id]))
|
||||
&& (config_region != configurable_child_regions_[parent_module][config_child_id]) ) {
|
||||
VTR_LOGF_ERROR(__FILE__, __LINE__,
|
||||
"Try to add a configurable child '%s[%lu]' to region '%lu' which is already added to another region '%lu'!\n",
|
||||
module_name(child_module).c_str(),
|
||||
child_instance,
|
||||
size_t(config_region),
|
||||
size_t(configurable_child_regions_[parent_module][config_child_id]));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Passed all the checks, add the child to the region */
|
||||
config_region_children_[parent_module][config_region].push_back(config_child_id);
|
||||
}
|
||||
|
||||
void ModuleManager::reserve_module_nets(const ModuleId& module,
|
||||
|
@ -869,6 +958,14 @@ void ModuleManager::clear_configurable_children(const ModuleId& parent_module) {
|
|||
|
||||
configurable_children_[parent_module].clear();
|
||||
configurable_child_instances_[parent_module].clear();
|
||||
configurable_child_regions_[parent_module].clear();
|
||||
}
|
||||
|
||||
void ModuleManager::clear_config_region(const ModuleId& parent_module) {
|
||||
VTR_ASSERT(valid_module_id(parent_module));
|
||||
|
||||
config_region_ids_[parent_module].clear();
|
||||
config_region_children_[parent_module].clear();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
@ -902,6 +999,14 @@ bool ModuleManager::valid_module_instance_id(const ModuleId& parent_module,
|
|||
return ( instance_id < num_instance(parent_module, child_module) );
|
||||
}
|
||||
|
||||
bool ModuleManager::valid_region_id(const ModuleId& module,
|
||||
const ConfigRegionId& region) const {
|
||||
if (false == valid_module_id(module)) {
|
||||
return false;
|
||||
}
|
||||
return ( size_t(region) < config_region_ids_[module].size() ) && ( region == config_region_ids_[module][region] );
|
||||
}
|
||||
|
||||
void ModuleManager::invalidate_name2id_map() {
|
||||
name_id_map_.clear();
|
||||
}
|
||||
|
|
|
@ -124,12 +124,14 @@ class ModuleManager {
|
|||
typedef lazy_id_iterator<ModuleNetId> module_net_iterator;
|
||||
typedef vtr::vector<ModuleNetSrcId, ModuleNetSrcId>::const_iterator module_net_src_iterator;
|
||||
typedef vtr::vector<ModuleNetSinkId, ModuleNetSinkId>::const_iterator module_net_sink_iterator;
|
||||
typedef vtr::vector<ConfigRegionId, ConfigRegionId>::const_iterator region_iterator;
|
||||
|
||||
typedef vtr::Range<module_iterator> module_range;
|
||||
typedef vtr::Range<module_port_iterator> module_port_range;
|
||||
typedef vtr::Range<module_net_iterator> module_net_range;
|
||||
typedef vtr::Range<module_net_src_iterator> module_net_src_range;
|
||||
typedef vtr::Range<module_net_sink_iterator> module_net_sink_range;
|
||||
typedef vtr::Range<region_iterator> region_range;
|
||||
|
||||
public: /* Public aggregators */
|
||||
/* Find all the modules */
|
||||
|
@ -151,6 +153,15 @@ class ModuleManager {
|
|||
/* Find the sink ids of modules */
|
||||
module_net_sink_range module_net_sinks(const ModuleId& module, const ModuleNetId& net) const;
|
||||
|
||||
/* Find all the regions */
|
||||
region_range regions(const ModuleId& module) const;
|
||||
/* Find all the configurable child modules under a region of a parent module */
|
||||
std::vector<ModuleId> region_configurable_children(const ModuleId& parent_module,
|
||||
const ConfigRegionId& region) const;
|
||||
/* Find all the instances of configurable child modules under a region of a parent module */
|
||||
std::vector<size_t> region_configurable_child_instances(const ModuleId& parent_module,
|
||||
const ConfigRegionId& region) const;
|
||||
|
||||
public: /* Public accessors */
|
||||
size_t num_modules() const;
|
||||
size_t num_nets(const ModuleId& module) const;
|
||||
|
@ -242,6 +253,19 @@ class ModuleManager {
|
|||
*/
|
||||
void reserve_configurable_child(const ModuleId& module, const size_t& num_children);
|
||||
|
||||
/* Create a new configurable region under a module */
|
||||
ConfigRegionId add_config_region(const ModuleId& module);
|
||||
/* Add a configurable child module to a region
|
||||
* Note:
|
||||
* - The child module must be added as a configurable child to the parent module
|
||||
* before calling this function!
|
||||
*/
|
||||
void add_configurable_child_to_region(const ModuleId& parent_module,
|
||||
const ConfigRegionId& config_region,
|
||||
const ModuleId& child_module,
|
||||
const size_t& child_instance,
|
||||
const size_t& config_child_id);
|
||||
|
||||
/* Reserved a number of module nets for a given module
|
||||
* for memory efficiency
|
||||
*/
|
||||
|
@ -281,6 +305,13 @@ class ModuleManager {
|
|||
* Do NOT use unless you know what you are doing!!!
|
||||
*/
|
||||
void clear_configurable_children(const ModuleId& parent_module);
|
||||
|
||||
/* This is a strong function which will remove all the configurable regions
|
||||
* under a given parent module
|
||||
* It is mainly used by loading fabric keys
|
||||
* Do NOT use unless you know what you are doing!!!
|
||||
*/
|
||||
void clear_config_region(const ModuleId& parent_module);
|
||||
public: /* Public validators/invalidators */
|
||||
bool valid_module_id(const ModuleId& module) const;
|
||||
bool valid_module_port_id(const ModuleId& module, const ModulePortId& port) const;
|
||||
|
@ -288,6 +319,8 @@ class ModuleManager {
|
|||
bool valid_module_instance_id(const ModuleId& parent_module,
|
||||
const ModuleId& child_module,
|
||||
const size_t& instance_id) const;
|
||||
bool valid_region_id(const ModuleId& module,
|
||||
const ConfigRegionId& region) const;
|
||||
private: /* Private validators/invalidators */
|
||||
void invalidate_name2id_map();
|
||||
void invalidate_port_lookup();
|
||||
|
@ -310,6 +343,14 @@ class ModuleManager {
|
|||
*/
|
||||
vtr::vector<ModuleId, std::vector<ModuleId>> configurable_children_; /* Child modules with configurable memory bits that this module contain */
|
||||
vtr::vector<ModuleId, std::vector<size_t>> configurable_child_instances_; /* Instances of child modules with configurable memory bits that this module contain */
|
||||
vtr::vector<ModuleId, std::vector<ConfigRegionId>> configurable_child_regions_; /* Instances of child modules with configurable memory bits that this module contain */
|
||||
|
||||
/* Configurable regions to group the configurable children
|
||||
* Note:
|
||||
* - Each child can only be added a group
|
||||
*/
|
||||
vtr::vector<ModuleId, vtr::vector<ConfigRegionId, ConfigRegionId>> config_region_ids_;
|
||||
vtr::vector<ModuleId, vtr::vector<ConfigRegionId, std::vector<size_t>>> config_region_children_;
|
||||
|
||||
/* Port-level data */
|
||||
vtr::vector<ModuleId, vtr::vector<ModulePortId, ModulePortId>> port_ids_; /* List of ports for each Module */
|
||||
|
|
|
@ -19,6 +19,7 @@ struct module_pin_id_tag;
|
|||
struct module_net_id_tag;
|
||||
struct module_net_src_id_tag;
|
||||
struct module_net_sink_id_tag;
|
||||
struct config_region_id_tag;
|
||||
|
||||
typedef vtr::StrongId<module_id_tag> ModuleId;
|
||||
typedef vtr::StrongId<instance_id_tag> InstanceId;
|
||||
|
@ -27,6 +28,7 @@ typedef vtr::StrongId<module_pin_id_tag> ModulePinId;
|
|||
typedef vtr::StrongId<module_net_id_tag> ModuleNetId;
|
||||
typedef vtr::StrongId<module_net_src_id_tag> ModuleNetSrcId;
|
||||
typedef vtr::StrongId<module_net_sink_id_tag> ModuleNetSinkId;
|
||||
typedef vtr::StrongId<config_region_id_tag> ConfigRegionId;
|
||||
|
||||
class ModuleManager;
|
||||
|
||||
|
|
|
@ -38,29 +38,58 @@ static
|
|||
void rec_build_module_fabric_dependent_chain_bitstream(const BitstreamManager& bitstream_manager,
|
||||
const ConfigBlockId& parent_block,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const ModuleId& parent_module,
|
||||
FabricBitstream& fabric_bitstream) {
|
||||
const ConfigRegionId& config_region,
|
||||
FabricBitstream& fabric_bitstream,
|
||||
const FabricBitRegionId& fabric_bitstream_region) {
|
||||
|
||||
/* Depth-first search: if we have any children in the parent_block,
|
||||
* we dive to the next level first!
|
||||
*/
|
||||
if (0 < bitstream_manager.block_children(parent_block).size()) {
|
||||
for (size_t child_id = 0; child_id < module_manager.configurable_children(parent_module).size(); ++child_id) {
|
||||
ModuleId child_module = module_manager.configurable_children(parent_module)[child_id];
|
||||
size_t child_instance = module_manager.configurable_child_instances(parent_module)[child_id];
|
||||
/* Get the instance name and ensure it is not empty */
|
||||
std::string instance_name = module_manager.instance_name(parent_module, child_module, child_instance);
|
||||
|
||||
/* Find the child block that matches the instance name! */
|
||||
ConfigBlockId child_block = bitstream_manager.find_child_block(parent_block, instance_name);
|
||||
/* We must have one valid block id! */
|
||||
if (true != bitstream_manager.valid_block_id(child_block))
|
||||
VTR_ASSERT(true == bitstream_manager.valid_block_id(child_block));
|
||||
if (parent_module == top_module) {
|
||||
for (size_t child_id = 0; child_id < module_manager.region_configurable_children(parent_module, config_region).size(); ++child_id) {
|
||||
ModuleId child_module = module_manager.region_configurable_children(parent_module, config_region)[child_id];
|
||||
size_t child_instance = module_manager.region_configurable_child_instances(parent_module, config_region)[child_id];
|
||||
/* Get the instance name and ensure it is not empty */
|
||||
std::string instance_name = module_manager.instance_name(parent_module, child_module, child_instance);
|
||||
|
||||
/* Find the child block that matches the instance name! */
|
||||
ConfigBlockId child_block = bitstream_manager.find_child_block(parent_block, instance_name);
|
||||
/* We must have one valid block id! */
|
||||
if (true != bitstream_manager.valid_block_id(child_block))
|
||||
VTR_ASSERT(true == bitstream_manager.valid_block_id(child_block));
|
||||
|
||||
/* Go recursively */
|
||||
rec_build_module_fabric_dependent_chain_bitstream(bitstream_manager, child_block,
|
||||
module_manager, child_module,
|
||||
fabric_bitstream);
|
||||
/* Go recursively */
|
||||
rec_build_module_fabric_dependent_chain_bitstream(bitstream_manager, child_block,
|
||||
module_manager, top_module,
|
||||
child_module,
|
||||
config_region,
|
||||
fabric_bitstream,
|
||||
fabric_bitstream_region);
|
||||
}
|
||||
} else {
|
||||
for (size_t child_id = 0; child_id < module_manager.configurable_children(parent_module).size(); ++child_id) {
|
||||
ModuleId child_module = module_manager.configurable_children(parent_module)[child_id];
|
||||
size_t child_instance = module_manager.configurable_child_instances(parent_module)[child_id];
|
||||
/* Get the instance name and ensure it is not empty */
|
||||
std::string instance_name = module_manager.instance_name(parent_module, child_module, child_instance);
|
||||
|
||||
/* Find the child block that matches the instance name! */
|
||||
ConfigBlockId child_block = bitstream_manager.find_child_block(parent_block, instance_name);
|
||||
/* We must have one valid block id! */
|
||||
if (true != bitstream_manager.valid_block_id(child_block))
|
||||
VTR_ASSERT(true == bitstream_manager.valid_block_id(child_block));
|
||||
|
||||
/* Go recursively */
|
||||
rec_build_module_fabric_dependent_chain_bitstream(bitstream_manager, child_block,
|
||||
module_manager, top_module,
|
||||
child_module,
|
||||
config_region,
|
||||
fabric_bitstream,
|
||||
fabric_bitstream_region);
|
||||
}
|
||||
}
|
||||
/* Ensure that there should be no configuration bits in the parent block */
|
||||
VTR_ASSERT(0 == bitstream_manager.block_bits(parent_block).size());
|
||||
|
@ -71,7 +100,8 @@ void rec_build_module_fabric_dependent_chain_bitstream(const BitstreamManager& b
|
|||
* And then, we can return
|
||||
*/
|
||||
for (const ConfigBitId& config_bit : bitstream_manager.block_bits(parent_block)) {
|
||||
fabric_bitstream.add_bit(config_bit);
|
||||
FabricBitId fabric_bit = fabric_bitstream.add_bit(config_bit);
|
||||
fabric_bitstream.add_bit_to_region(fabric_bitstream_region, fabric_bit);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,7 +131,8 @@ void rec_build_module_fabric_dependent_memory_bank_bitstream(const BitstreamMana
|
|||
const size_t& num_bls,
|
||||
const size_t& num_wls,
|
||||
size_t& cur_mem_index,
|
||||
FabricBitstream& fabric_bitstream) {
|
||||
FabricBitstream& fabric_bitstream,
|
||||
const FabricBitRegionId& fabric_bitstream_region) {
|
||||
|
||||
/* Depth-first search: if we have any children in the parent_block,
|
||||
* we dive to the next level first!
|
||||
|
@ -141,7 +172,8 @@ void rec_build_module_fabric_dependent_memory_bank_bitstream(const BitstreamMana
|
|||
bl_addr_size, wl_addr_size,
|
||||
num_bls, num_wls,
|
||||
cur_mem_index,
|
||||
fabric_bitstream);
|
||||
fabric_bitstream,
|
||||
fabric_bitstream_region);
|
||||
}
|
||||
/* Ensure that there should be no configuration bits in the parent block */
|
||||
VTR_ASSERT(0 == bitstream_manager.block_bits(parent_block).size());
|
||||
|
@ -173,6 +205,9 @@ void rec_build_module_fabric_dependent_memory_bank_bitstream(const BitstreamMana
|
|||
/* Set data input */
|
||||
fabric_bitstream.set_bit_din(fabric_bit, bitstream_manager.bit_value(config_bit));
|
||||
|
||||
/* Add the bit to the region */
|
||||
fabric_bitstream.add_bit_to_region(fabric_bitstream_region, fabric_bit);
|
||||
|
||||
/* Increase the memory index */
|
||||
cur_mem_index++;
|
||||
}
|
||||
|
@ -207,7 +242,8 @@ void rec_build_module_fabric_dependent_frame_bitstream(const BitstreamManager& b
|
|||
const ModuleManager& module_manager,
|
||||
const std::vector<ModuleId>& parent_modules,
|
||||
const std::vector<char>& addr_code,
|
||||
FabricBitstream& fabric_bitstream) {
|
||||
FabricBitstream& fabric_bitstream,
|
||||
FabricBitRegionId& fabric_bitstream_region) {
|
||||
|
||||
/* Depth-first search: if we have any children in the parent_block,
|
||||
* we dive to the next level first!
|
||||
|
@ -325,7 +361,8 @@ void rec_build_module_fabric_dependent_frame_bitstream(const BitstreamManager& b
|
|||
rec_build_module_fabric_dependent_frame_bitstream(bitstream_manager, child_blocks,
|
||||
module_manager, child_modules,
|
||||
child_addr_code,
|
||||
fabric_bitstream);
|
||||
fabric_bitstream,
|
||||
fabric_bitstream_region);
|
||||
}
|
||||
/* Ensure that there should be no configuration bits in the parent block */
|
||||
VTR_ASSERT(0 == bitstream_manager.block_bits(parent_block).size());
|
||||
|
@ -362,6 +399,9 @@ void rec_build_module_fabric_dependent_frame_bitstream(const BitstreamManager& b
|
|||
|
||||
/* Set data input */
|
||||
fabric_bitstream.set_bit_din(fabric_bit, bitstream_manager.bit_value(config_bit));
|
||||
|
||||
/* Add the bit to the region */
|
||||
fabric_bitstream.add_bit_to_region(fabric_bitstream_region, fabric_bit);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -382,19 +422,32 @@ void build_module_fabric_dependent_bitstream(const ConfigProtocol& config_protoc
|
|||
/* Reserve bits before build-up */
|
||||
fabric_bitstream.reserve_bits(bitstream_manager.num_bits());
|
||||
|
||||
rec_build_module_fabric_dependent_chain_bitstream(bitstream_manager, top_block,
|
||||
module_manager, top_module,
|
||||
fabric_bitstream);
|
||||
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
|
||||
FabricBitRegionId fabric_bitstream_region = fabric_bitstream.add_region();
|
||||
rec_build_module_fabric_dependent_chain_bitstream(bitstream_manager, top_block,
|
||||
module_manager, top_module,
|
||||
top_module,
|
||||
config_region,
|
||||
fabric_bitstream,
|
||||
fabric_bitstream_region);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case CONFIG_MEM_SCAN_CHAIN: {
|
||||
/* Reserve bits before build-up */
|
||||
fabric_bitstream.reserve_bits(bitstream_manager.num_bits());
|
||||
|
||||
rec_build_module_fabric_dependent_chain_bitstream(bitstream_manager, top_block,
|
||||
module_manager, top_module,
|
||||
fabric_bitstream);
|
||||
fabric_bitstream.reverse();
|
||||
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
|
||||
FabricBitRegionId fabric_bitstream_region = fabric_bitstream.add_region();
|
||||
rec_build_module_fabric_dependent_chain_bitstream(bitstream_manager, top_block,
|
||||
module_manager, top_module,
|
||||
top_module,
|
||||
config_region,
|
||||
fabric_bitstream,
|
||||
fabric_bitstream_region);
|
||||
fabric_bitstream.reverse_region_bits(fabric_bitstream_region);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CONFIG_MEM_MEMORY_BANK: {
|
||||
|
@ -429,13 +482,21 @@ void build_module_fabric_dependent_bitstream(const ConfigProtocol& config_protoc
|
|||
fabric_bitstream.set_wl_address_length(wl_addr_port_info.get_width());
|
||||
fabric_bitstream.reserve_bits(bitstream_manager.num_bits());
|
||||
|
||||
rec_build_module_fabric_dependent_memory_bank_bitstream(bitstream_manager, top_block,
|
||||
module_manager, top_module, top_module,
|
||||
bl_addr_port_info.get_width(),
|
||||
wl_addr_port_info.get_width(),
|
||||
bl_port_info.get_width(),
|
||||
wl_port_info.get_width(),
|
||||
cur_mem_index, fabric_bitstream);
|
||||
/* TODO: Currently only support 1 region. Will expand later! */
|
||||
VTR_ASSERT(1 == module_manager.regions(top_module).size());
|
||||
|
||||
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
|
||||
FabricBitRegionId fabric_bitstream_region = fabric_bitstream.add_region();
|
||||
rec_build_module_fabric_dependent_memory_bank_bitstream(bitstream_manager, top_block,
|
||||
module_manager, top_module, top_module,
|
||||
bl_addr_port_info.get_width(),
|
||||
wl_addr_port_info.get_width(),
|
||||
bl_port_info.get_width(),
|
||||
wl_port_info.get_width(),
|
||||
cur_mem_index,
|
||||
fabric_bitstream,
|
||||
fabric_bitstream_region);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CONFIG_MEM_FRAME_BASED: {
|
||||
|
@ -449,12 +510,19 @@ void build_module_fabric_dependent_bitstream(const ConfigProtocol& config_protoc
|
|||
fabric_bitstream.reserve_bits(bitstream_manager.num_bits());
|
||||
fabric_bitstream.set_address_length(addr_port_info.get_width());
|
||||
|
||||
rec_build_module_fabric_dependent_frame_bitstream(bitstream_manager,
|
||||
std::vector<ConfigBlockId>(1, top_block),
|
||||
module_manager,
|
||||
std::vector<ModuleId>(1, top_module),
|
||||
std::vector<char>(),
|
||||
fabric_bitstream);
|
||||
/* TODO: Currently only support 1 region. Will expand later! */
|
||||
VTR_ASSERT(1 == module_manager.regions(top_module).size());
|
||||
|
||||
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
|
||||
FabricBitRegionId fabric_bitstream_region = fabric_bitstream.add_region();
|
||||
rec_build_module_fabric_dependent_frame_bitstream(bitstream_manager,
|
||||
std::vector<ConfigBlockId>(1, top_block),
|
||||
module_manager,
|
||||
std::vector<ModuleId>(1, top_module),
|
||||
std::vector<char>(),
|
||||
fabric_bitstream,
|
||||
fabric_bitstream_region);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
|
@ -18,6 +18,9 @@ FabricBitstream::FabricBitstream() {
|
|||
invalid_bit_ids_.clear();
|
||||
address_length_ = 0;
|
||||
wl_address_length_ = 0;
|
||||
|
||||
num_regions_ = 0;
|
||||
invalid_region_ids_.clear();
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
|
@ -33,6 +36,23 @@ FabricBitstream::fabric_bit_range FabricBitstream::bits() const {
|
|||
fabric_bit_iterator(FabricBitId(num_bits_), invalid_bit_ids_));
|
||||
}
|
||||
|
||||
size_t FabricBitstream::num_regions() const {
|
||||
return num_regions_;
|
||||
}
|
||||
|
||||
/* Find all the configuration bits */
|
||||
FabricBitstream::fabric_bit_region_range FabricBitstream::regions() const {
|
||||
return vtr::make_range(fabric_bit_region_iterator(FabricBitRegionId(0), invalid_region_ids_),
|
||||
fabric_bit_region_iterator(FabricBitRegionId(num_regions_), invalid_region_ids_));
|
||||
}
|
||||
|
||||
std::vector<FabricBitId> FabricBitstream::region_bits(const FabricBitRegionId& region_id) const {
|
||||
/* Ensure a valid id */
|
||||
VTR_ASSERT(true == valid_region_id(region_id));
|
||||
|
||||
return region_bit_ids_[region_id];
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Public Accessors
|
||||
******************************************************************************/
|
||||
|
@ -134,19 +154,6 @@ void FabricBitstream::set_bit_din(const FabricBitId& bit_id,
|
|||
bit_dins_[bit_id] = din;
|
||||
}
|
||||
|
||||
void FabricBitstream::reverse() {
|
||||
std::reverse(config_bit_ids_.begin(), config_bit_ids_.end());
|
||||
|
||||
if (true == use_address_) {
|
||||
std::reverse(bit_addresses_.begin(), bit_addresses_.end());
|
||||
std::reverse(bit_dins_.begin(), bit_dins_.end());
|
||||
|
||||
if (true == use_wl_address_) {
|
||||
std::reverse(bit_wl_addresses_.begin(), bit_wl_addresses_.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FabricBitstream::set_use_address(const bool& enable) {
|
||||
/* Add a lock, only can be modified when num bits are zero*/
|
||||
if (0 == num_bits_) {
|
||||
|
@ -177,11 +184,55 @@ void FabricBitstream::set_wl_address_length(const size_t& length) {
|
|||
}
|
||||
}
|
||||
|
||||
void FabricBitstream::reserve_regions(const size_t& num_regions) {
|
||||
region_bit_ids_.reserve(num_regions);
|
||||
}
|
||||
|
||||
FabricBitRegionId FabricBitstream::add_region() {
|
||||
FabricBitRegionId region = FabricBitRegionId(num_regions_);
|
||||
/* Add a new bit, and allocate associated data structures */
|
||||
num_regions_++;
|
||||
region_bit_ids_.emplace_back();
|
||||
|
||||
return region;
|
||||
}
|
||||
|
||||
void FabricBitstream::add_bit_to_region(const FabricBitRegionId& region_id,
|
||||
const FabricBitId& bit_id) {
|
||||
VTR_ASSERT(true == valid_region_id(region_id));
|
||||
VTR_ASSERT(true == valid_bit_id(bit_id));
|
||||
|
||||
region_bit_ids_[region_id].push_back(bit_id);
|
||||
}
|
||||
|
||||
void FabricBitstream::reverse() {
|
||||
std::reverse(config_bit_ids_.begin(), config_bit_ids_.end());
|
||||
|
||||
if (true == use_address_) {
|
||||
std::reverse(bit_addresses_.begin(), bit_addresses_.end());
|
||||
std::reverse(bit_dins_.begin(), bit_dins_.end());
|
||||
|
||||
if (true == use_wl_address_) {
|
||||
std::reverse(bit_wl_addresses_.begin(), bit_wl_addresses_.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FabricBitstream::reverse_region_bits(const FabricBitRegionId& region_id) {
|
||||
VTR_ASSERT(true == valid_region_id(region_id));
|
||||
|
||||
std::reverse(region_bit_ids_[region_id].begin(), region_bit_ids_[region_id].end());
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Public Validators
|
||||
******************************************************************************/
|
||||
char FabricBitstream::valid_bit_id(const FabricBitId& bit_id) const {
|
||||
bool FabricBitstream::valid_bit_id(const FabricBitId& bit_id) const {
|
||||
return (size_t(bit_id) < num_bits_);
|
||||
}
|
||||
|
||||
bool FabricBitstream::valid_region_id(const FabricBitRegionId& region_id) const {
|
||||
return (size_t(region_id) < num_regions_);
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
|
|
@ -93,8 +93,10 @@ class FabricBitstream {
|
|||
class lazy_id_iterator;
|
||||
|
||||
typedef lazy_id_iterator<FabricBitId> fabric_bit_iterator;
|
||||
typedef lazy_id_iterator<FabricBitRegionId> fabric_bit_region_iterator;
|
||||
|
||||
typedef vtr::Range<fabric_bit_iterator> fabric_bit_range;
|
||||
typedef vtr::Range<fabric_bit_region_iterator> fabric_bit_region_range;
|
||||
|
||||
public: /* Public constructor */
|
||||
FabricBitstream();
|
||||
|
@ -104,6 +106,11 @@ class FabricBitstream {
|
|||
size_t num_bits() const;
|
||||
fabric_bit_range bits() const;
|
||||
|
||||
/* Find all the configuration regions */
|
||||
size_t num_regions() const;
|
||||
fabric_bit_region_range regions() const;
|
||||
std::vector<FabricBitId> region_bits(const FabricBitRegionId& region_id) const;
|
||||
|
||||
public: /* Public Accessors */
|
||||
/* Find the configuration bit id in architecture bitstream database */
|
||||
ConfigBitId config_bit(const FabricBitId& bit_id) const;
|
||||
|
@ -139,6 +146,18 @@ class FabricBitstream {
|
|||
void set_bit_din(const FabricBitId& bit_id,
|
||||
const char& din);
|
||||
|
||||
/* Reserve regions */
|
||||
void reserve_regions(const size_t& num_regions);
|
||||
|
||||
/* Add a new configuration region */
|
||||
FabricBitRegionId add_region();
|
||||
|
||||
void add_bit_to_region(const FabricBitRegionId& region_id,
|
||||
const FabricBitId& bit_id);
|
||||
|
||||
/* Reserve bits by region */
|
||||
void reverse_region_bits(const FabricBitRegionId& region_id);
|
||||
|
||||
/* Reverse bit sequence of the fabric bitstream
|
||||
* This is required by configuration chain protocol
|
||||
*/
|
||||
|
@ -162,9 +181,15 @@ class FabricBitstream {
|
|||
void set_wl_address_length(const size_t& length);
|
||||
|
||||
public: /* Public Validators */
|
||||
char valid_bit_id(const FabricBitId& bit_id) const;
|
||||
bool valid_bit_id(const FabricBitId& bit_id) const;
|
||||
bool valid_region_id(const FabricBitRegionId& bit_id) const;
|
||||
|
||||
private: /* Internal data */
|
||||
/* Unique id of a region in the Bitstream */
|
||||
size_t num_regions_;
|
||||
std::unordered_set<FabricBitRegionId> invalid_region_ids_;
|
||||
vtr::vector<FabricBitRegionId, std::vector<FabricBitId>> region_bit_ids_;
|
||||
|
||||
/* Unique id of a bit in the Bitstream */
|
||||
size_t num_bits_;
|
||||
std::unordered_set<FabricBitId> invalid_bit_ids_;
|
||||
|
|
|
@ -13,8 +13,10 @@ namespace openfpga {
|
|||
|
||||
/* Strong Ids for BitstreamContext */
|
||||
struct fabric_bit_id_tag;
|
||||
struct fabric_bit_region_id_tag;
|
||||
|
||||
typedef vtr::StrongId<fabric_bit_id_tag> FabricBitId;
|
||||
typedef vtr::StrongId<fabric_bit_region_id_tag> FabricBitRegionId;
|
||||
|
||||
class FabricBitstream;
|
||||
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
#include "simulation_utils.h"
|
||||
#include "openfpga_atom_netlist_utils.h"
|
||||
|
||||
#include "fabric_bitstream_utils.h"
|
||||
|
||||
#include "verilog_constants.h"
|
||||
#include "verilog_writer_utils.h"
|
||||
#include "verilog_testbench_utils.h"
|
||||
|
@ -136,18 +138,22 @@ void print_verilog_top_testbench_flatten_memory_port(std::fstream& fp,
|
|||
* Print local wires for configuration chain protocols
|
||||
*******************************************************************/
|
||||
static
|
||||
void print_verilog_top_testbench_config_chain_port(std::fstream& fp) {
|
||||
void print_verilog_top_testbench_config_chain_port(std::fstream& fp,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module) {
|
||||
/* Validate the file stream */
|
||||
valid_file_stream(fp);
|
||||
|
||||
/* Print the head of configuraion-chains here */
|
||||
print_verilog_comment(fp, std::string("---- Configuration-chain head -----"));
|
||||
BasicPort config_chain_head_port(generate_configuration_chain_head_name(), 1);
|
||||
ModulePortId cc_head_port_id = module_manager.find_module_port(top_module, generate_configuration_chain_head_name());
|
||||
BasicPort config_chain_head_port = module_manager.module_port(top_module, cc_head_port_id);
|
||||
fp << generate_verilog_port(VERILOG_PORT_REG, config_chain_head_port) << ";" << std::endl;
|
||||
|
||||
/* Print the tail of configuration-chains here */
|
||||
print_verilog_comment(fp, std::string("---- Configuration-chain tail -----"));
|
||||
BasicPort config_chain_tail_port(generate_configuration_chain_tail_name(), 1);
|
||||
ModulePortId cc_tail_port_id = module_manager.find_module_port(top_module, generate_configuration_chain_tail_name());
|
||||
BasicPort config_chain_tail_port = module_manager.module_port(top_module, cc_tail_port_id);
|
||||
fp << generate_verilog_port(VERILOG_PORT_WIRE, config_chain_tail_port) << ";" << std::endl;
|
||||
}
|
||||
|
||||
|
@ -271,7 +277,7 @@ void print_verilog_top_testbench_config_protocol_port(std::fstream& fp,
|
|||
print_verilog_top_testbench_flatten_memory_port(fp, module_manager, top_module);
|
||||
break;
|
||||
case CONFIG_MEM_SCAN_CHAIN:
|
||||
print_verilog_top_testbench_config_chain_port(fp);
|
||||
print_verilog_top_testbench_config_chain_port(fp, module_manager, top_module);
|
||||
break;
|
||||
case CONFIG_MEM_MEMORY_BANK:
|
||||
print_verilog_top_testbench_memory_bank_port(fp, module_manager, top_module);
|
||||
|
@ -659,7 +665,10 @@ size_t calculate_num_config_clock_cycles(const e_config_protocol_type& sram_orgz
|
|||
const bool& bit_value_to_skip,
|
||||
const BitstreamManager& bitstream_manager,
|
||||
const FabricBitstream& fabric_bitstream) {
|
||||
size_t num_config_clock_cycles = 1 + fabric_bitstream.num_bits();
|
||||
/* Find the longest regional bitstream */
|
||||
size_t regional_bitstream_max_size = find_fabric_regional_bitstream_max_size(fabric_bitstream);
|
||||
|
||||
size_t num_config_clock_cycles = 1 + regional_bitstream_max_size;
|
||||
|
||||
/* Branch on the type of configuration protocol */
|
||||
switch (sram_orgz_type) {
|
||||
|
@ -670,23 +679,24 @@ size_t calculate_num_config_clock_cycles(const e_config_protocol_type& sram_orgz
|
|||
num_config_clock_cycles = 2;
|
||||
break;
|
||||
case CONFIG_MEM_SCAN_CHAIN:
|
||||
/* For fast configuraiton, the bitstream size counts from the first bit '1' */
|
||||
/* For fast configuration, the bitstream size counts from the first bit '1' */
|
||||
if (true == fast_configuration) {
|
||||
size_t full_num_config_clock_cycles = num_config_clock_cycles;
|
||||
size_t num_bits_to_skip = 0;
|
||||
for (const FabricBitId& bit_id : fabric_bitstream.bits()) {
|
||||
if (bit_value_to_skip != bitstream_manager.bit_value(fabric_bitstream.config_bit(bit_id))) {
|
||||
break;
|
||||
}
|
||||
num_bits_to_skip++;
|
||||
}
|
||||
/* For fast configuration, the number of bits to be skipped
|
||||
* depends on each regional bitstream
|
||||
* For example:
|
||||
* Region 0: 000000001111101010
|
||||
* Region 1: 00000011010101
|
||||
* Region 2: 0010101111000110
|
||||
* The number of bits that can be skipped is limited by Region 2
|
||||
*/
|
||||
size_t num_bits_to_skip = find_configuration_chain_fabric_bitstream_size_to_be_skipped(fabric_bitstream, bitstream_manager, bit_value_to_skip);
|
||||
|
||||
num_config_clock_cycles = full_num_config_clock_cycles - num_bits_to_skip;
|
||||
num_config_clock_cycles = 1 + regional_bitstream_max_size - num_bits_to_skip;
|
||||
|
||||
VTR_LOG("Fast configuration reduces number of configuration clock cycles from %lu to %lu (compression_rate = %f%)\n",
|
||||
full_num_config_clock_cycles,
|
||||
1 + regional_bitstream_max_size,
|
||||
num_config_clock_cycles,
|
||||
100. * ((float)num_config_clock_cycles / (float)full_num_config_clock_cycles - 1.));
|
||||
100. * ((float)num_config_clock_cycles / (float)(1 + regional_bitstream_max_size) - 1.));
|
||||
}
|
||||
break;
|
||||
case CONFIG_MEM_MEMORY_BANK:
|
||||
|
@ -770,14 +780,17 @@ void print_verilog_top_testbench_benchmark_instance(std::fstream& fp,
|
|||
* During each programming cycle, we feed the input of scan chain with a memory bit
|
||||
*******************************************************************/
|
||||
static
|
||||
void print_verilog_top_testbench_load_bitstream_task_configuration_chain(std::fstream& fp) {
|
||||
void print_verilog_top_testbench_load_bitstream_task_configuration_chain(std::fstream& fp,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module) {
|
||||
|
||||
/* Validate the file stream */
|
||||
valid_file_stream(fp);
|
||||
|
||||
BasicPort prog_clock_port(std::string(TOP_TB_PROG_CLOCK_PORT_NAME), 1);
|
||||
BasicPort cc_head_port(generate_configuration_chain_head_name(), 1);
|
||||
BasicPort cc_head_value(generate_configuration_chain_head_name() + std::string("_val"), 1);
|
||||
ModulePortId cc_head_port_id = module_manager.find_module_port(top_module, generate_configuration_chain_head_name());
|
||||
BasicPort cc_head_port = module_manager.module_port(top_module, cc_head_port_id);
|
||||
BasicPort cc_head_value(generate_configuration_chain_head_name() + std::string("_val"), cc_head_port.get_width());
|
||||
|
||||
/* Add an empty line as splitter */
|
||||
fp << std::endl;
|
||||
|
@ -962,7 +975,9 @@ void print_verilog_top_testbench_load_bitstream_task(std::fstream& fp,
|
|||
/* No need to have a specific task. Loading is done in 1 clock cycle */
|
||||
break;
|
||||
case CONFIG_MEM_SCAN_CHAIN:
|
||||
print_verilog_top_testbench_load_bitstream_task_configuration_chain(fp);
|
||||
print_verilog_top_testbench_load_bitstream_task_configuration_chain(fp,
|
||||
module_manager,
|
||||
top_module);
|
||||
break;
|
||||
case CONFIG_MEM_MEMORY_BANK:
|
||||
print_verilog_top_testbench_load_bitstream_task_memory_bank(fp,
|
||||
|
@ -1359,6 +1374,8 @@ static
|
|||
void print_verilog_top_testbench_configuration_chain_bitstream(std::fstream& fp,
|
||||
const bool& fast_configuration,
|
||||
const bool& bit_value_to_skip,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const BitstreamManager& bitstream_manager,
|
||||
const FabricBitstream& fabric_bitstream) {
|
||||
/* Validate the file stream */
|
||||
|
@ -1370,7 +1387,8 @@ void print_verilog_top_testbench_configuration_chain_bitstream(std::fstream& fp,
|
|||
* We do not care the value of scan_chain head during the first programming cycle
|
||||
* It is reset anyway
|
||||
*/
|
||||
BasicPort config_chain_head_port(generate_configuration_chain_head_name(), 1);
|
||||
ModulePortId cc_head_port_id = module_manager.find_module_port(top_module, generate_configuration_chain_head_name());
|
||||
BasicPort config_chain_head_port = module_manager.module_port(top_module, cc_head_port_id);
|
||||
std::vector<size_t> initial_values(config_chain_head_port.get_width(), 0);
|
||||
|
||||
print_verilog_comment(fp, "----- Begin bitstream loading during configuration phase -----");
|
||||
|
@ -1383,27 +1401,60 @@ void print_verilog_top_testbench_configuration_chain_bitstream(std::fstream& fp,
|
|||
|
||||
fp << std::endl;
|
||||
|
||||
/* Find the longest bitstream */
|
||||
size_t regional_bitstream_max_size = find_fabric_regional_bitstream_max_size(fabric_bitstream);
|
||||
|
||||
/* For fast configuration, the bitstream size counts from the first bit '1' */
|
||||
size_t num_bits_to_skip = 0;
|
||||
if (true == fast_configuration) {
|
||||
num_bits_to_skip = find_configuration_chain_fabric_bitstream_size_to_be_skipped(fabric_bitstream, bitstream_manager, bit_value_to_skip);
|
||||
}
|
||||
VTR_ASSERT(num_bits_to_skip < regional_bitstream_max_size);
|
||||
|
||||
/* Reorganize the regional bitstreams to be the same size */
|
||||
std::vector<std::vector<bool>> regional_bitstreams;
|
||||
regional_bitstreams.reserve(fabric_bitstream.regions().size());
|
||||
for (const FabricBitRegionId& region : fabric_bitstream.regions()) {
|
||||
std::vector<bool> curr_regional_bitstream;
|
||||
curr_regional_bitstream.resize(regional_bitstream_max_size, false);
|
||||
/* Starting index should consider the offset between the current bitstream size and
|
||||
* the maximum size of regional bitstream
|
||||
*/
|
||||
size_t offset = regional_bitstream_max_size - fabric_bitstream.region_bits(region).size();
|
||||
for (const FabricBitId& bit_id : fabric_bitstream.region_bits(region)) {
|
||||
curr_regional_bitstream[offset] = bitstream_manager.bit_value(fabric_bitstream.config_bit(bit_id));
|
||||
offset++;
|
||||
}
|
||||
VTR_ASSERT(offset == regional_bitstream_max_size);
|
||||
|
||||
/* Add the adapt sub-bitstream */
|
||||
regional_bitstreams.push_back(curr_regional_bitstream);
|
||||
}
|
||||
|
||||
/* Attention: when the fast configuration is enabled, we will start from the first bit '1'
|
||||
* This requires a reset signal (as we forced in the first clock cycle)
|
||||
*
|
||||
* Note that bitstream may come from different regions
|
||||
* The bitstream value to be loaded should be organized as follows
|
||||
*
|
||||
* cycleA
|
||||
* |
|
||||
* Region 0: 0|00000001111101010
|
||||
* Region 1: | 00000011010101
|
||||
* Region 2: | 0010101111000110
|
||||
*
|
||||
* Zero bits will be added to the head of those bitstreams are shorter
|
||||
* than the longest bitstream
|
||||
*/
|
||||
bool start_config = false;
|
||||
for (const FabricBitId& bit_id : fabric_bitstream.bits()) {
|
||||
if ( (false == start_config)
|
||||
&& (bit_value_to_skip != bitstream_manager.bit_value(fabric_bitstream.config_bit(bit_id)))) {
|
||||
start_config = true;
|
||||
}
|
||||
|
||||
/* In fast configuration mode, we do not output anything
|
||||
* until we have to (the first bit '1' detected)
|
||||
*/
|
||||
if ( (true == fast_configuration)
|
||||
&& (false == start_config)) {
|
||||
continue;
|
||||
for (size_t ibit = num_bits_to_skip; ibit < regional_bitstream_max_size; ++ibit) {
|
||||
std::vector<size_t> curr_cc_head_val;
|
||||
curr_cc_head_val.reserve(fabric_bitstream.regions().size());
|
||||
for (const auto& region_bitstream : regional_bitstreams) {
|
||||
curr_cc_head_val.push_back((size_t)region_bitstream[ibit]);
|
||||
}
|
||||
|
||||
fp << "\t\t" << std::string(TOP_TESTBENCH_PROG_TASK_NAME);
|
||||
fp << "(1'b" << (size_t)bitstream_manager.bit_value(fabric_bitstream.config_bit(bit_id)) << ");" << std::endl;
|
||||
fp << "(" << generate_verilog_constant_values(curr_cc_head_val) << ");" << std::endl;
|
||||
}
|
||||
|
||||
/* Raise the flag of configuration done when bitstream loading is complete */
|
||||
|
@ -1654,6 +1705,7 @@ void print_verilog_top_testbench_bitstream(std::fstream& fp,
|
|||
case CONFIG_MEM_SCAN_CHAIN:
|
||||
print_verilog_top_testbench_configuration_chain_bitstream(fp, fast_configuration,
|
||||
bit_value_to_skip,
|
||||
module_manager, top_module,
|
||||
bitstream_manager, fabric_bitstream);
|
||||
break;
|
||||
case CONFIG_MEM_MEMORY_BANK:
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/************************************************************************
|
||||
* Function to perform fundamental operation for fabric bitstream class
|
||||
* These functions are not universal methods for the FabricBitstream class
|
||||
* They are made to ease the development in some specific purposes
|
||||
* Please classify such functions in this file
|
||||
***********************************************************************/
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
/* Headers from vtrutil library */
|
||||
#include "vtr_assert.h"
|
||||
#include "vtr_log.h"
|
||||
|
||||
#include "fabric_bitstream_utils.h"
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
/********************************************************************
|
||||
* Find the longest bitstream size of a fabric bitstream
|
||||
*******************************************************************/
|
||||
size_t find_fabric_regional_bitstream_max_size(const FabricBitstream& fabric_bitstream) {
|
||||
size_t regional_bitstream_max_size = 0;
|
||||
/* Find the longest regional bitstream */
|
||||
for (const auto& region : fabric_bitstream.regions()) {
|
||||
if (regional_bitstream_max_size < fabric_bitstream.region_bits(region).size()) {
|
||||
regional_bitstream_max_size = fabric_bitstream.region_bits(region).size();
|
||||
}
|
||||
}
|
||||
return regional_bitstream_max_size;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* For fast configuration, the number of bits to be skipped
|
||||
* depends on each regional bitstream
|
||||
* For example:
|
||||
* Region 0: 000000001111101010
|
||||
* Region 1: 00000011010101
|
||||
* Region 2: 0010101111000110
|
||||
* The number of bits that can be skipped is limited by Region 2
|
||||
* Find the longest bitstream size of a fabric bitstream
|
||||
*******************************************************************/
|
||||
size_t find_configuration_chain_fabric_bitstream_size_to_be_skipped(const FabricBitstream& fabric_bitstream,
|
||||
const BitstreamManager& bitstream_manager,
|
||||
const bool& bit_value_to_skip) {
|
||||
size_t regional_bitstream_max_size = find_fabric_regional_bitstream_max_size(fabric_bitstream);
|
||||
|
||||
size_t num_bits_to_skip = size_t(-1);
|
||||
for (const auto& region : fabric_bitstream.regions()) {
|
||||
size_t curr_region_num_bits_to_skip = 0;
|
||||
for (const FabricBitId& bit_id : fabric_bitstream.region_bits(region)) {
|
||||
if (bit_value_to_skip != bitstream_manager.bit_value(fabric_bitstream.config_bit(bit_id))) {
|
||||
break;
|
||||
}
|
||||
curr_region_num_bits_to_skip++;
|
||||
}
|
||||
/* For regional bitstream which is short than the longest region bitstream,
|
||||
* The number of bits to skip
|
||||
*/
|
||||
curr_region_num_bits_to_skip += regional_bitstream_max_size - fabric_bitstream.region_bits(region).size();
|
||||
num_bits_to_skip = std::min(curr_region_num_bits_to_skip, num_bits_to_skip);
|
||||
}
|
||||
|
||||
return num_bits_to_skip;
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
|
@ -0,0 +1,29 @@
|
|||
/********************************************************************
|
||||
* Header file for fabric_bitstream_utils.cpp
|
||||
*******************************************************************/
|
||||
#ifndef FABRIC_BITSTREAM_UTILS_H
|
||||
#define FABRIC_BITSTREAM_UTILS_H
|
||||
|
||||
/********************************************************************
|
||||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
#include <vector>
|
||||
#include "bitstream_manager.h"
|
||||
#include "fabric_bitstream.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
*******************************************************************/
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
size_t find_fabric_regional_bitstream_max_size(const FabricBitstream& fabric_bitstream);
|
||||
|
||||
size_t find_configuration_chain_fabric_bitstream_size_to_be_skipped(const FabricBitstream& fabric_bitstream,
|
||||
const BitstreamManager& bitstream_manager,
|
||||
const bool& bit_value_to_skip);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
#endif
|
|
@ -0,0 +1,23 @@
|
|||
<fabric_key>
|
||||
<region id="0">
|
||||
<key id="0" name="grid_io_bottom" value="0" alias="grid_io_bottom_1__0_"/>
|
||||
<key id="1" name="grid_io_right" value="0" alias="grid_io_right_2__1_"/>
|
||||
<key id="2" name="sb_1__1_" value="0" alias="sb_1__1_"/>
|
||||
</region>
|
||||
<region id="1">
|
||||
<key id="3" name="cbx_1__1_" value="0" alias="cbx_1__1_"/>
|
||||
<key id="4" name="grid_io_top" value="0" alias="grid_io_top_1__2_"/>
|
||||
<key id="5" name="sb_0__1_" value="0" alias="sb_0__1_"/>
|
||||
</region>
|
||||
<region id="2">
|
||||
<key id="6" name="sb_0__0_" value="0" alias="sb_0__0_"/>
|
||||
<key id="7" name="cby_0__1_" value="0" alias="cby_0__1_"/>
|
||||
<key id="8" name="grid_io_left" value="0" alias="grid_io_left_0__1_"/>
|
||||
</region>
|
||||
<region id="3">
|
||||
<key id="9" name="sb_1__0_" value="0" alias="sb_1__0_"/>
|
||||
<key id="10" name="cbx_1__0_" value="0" alias="cbx_1__0_"/>
|
||||
<key id="11" name="cby_1__1_" value="0" alias="cby_1__1_"/>
|
||||
<key id="12" name="grid_clb" value="0" alias="grid_clb_1__1_"/>
|
||||
</region>
|
||||
</fabric_key>
|
|
@ -1,35 +1,37 @@
|
|||
<fabric_key>
|
||||
<key id="0" name="sb_2__2_" value="0" alias="sb_2__2_"/>
|
||||
<key id="1" name="grid_clb" value="3" alias="grid_clb_2__2_"/>
|
||||
<key id="2" name="sb_0__1_" value="0" alias="sb_0__1_"/>
|
||||
<key id="3" name="cby_0__1_" value="0" alias="cby_0__1_"/>
|
||||
<key id="4" name="grid_clb" value="2" alias="grid_clb_2__1_"/>
|
||||
<key id="5" name="grid_io_left" value="0" alias="grid_io_left_0__1_"/>
|
||||
<key id="6" name="sb_1__0_" value="0" alias="sb_1__0_"/>
|
||||
<key id="7" name="sb_1__1_" value="0" alias="sb_1__1_"/>
|
||||
<key id="8" name="cbx_1__1_" value="1" alias="cbx_2__1_"/>
|
||||
<key id="9" name="cby_1__1_" value="1" alias="cby_1__2_"/>
|
||||
<key id="10" name="grid_io_right" value="1" alias="grid_io_right_3__2_"/>
|
||||
<key id="11" name="cbx_1__0_" value="1" alias="cbx_2__0_"/>
|
||||
<key id="12" name="cby_1__1_" value="0" alias="cby_1__1_"/>
|
||||
<key id="13" name="grid_io_right" value="0" alias="grid_io_right_3__1_"/>
|
||||
<key id="14" name="grid_io_bottom" value="0" alias="grid_io_bottom_1__0_"/>
|
||||
<key id="15" name="cby_2__1_" value="0" alias="cby_2__1_"/>
|
||||
<key id="16" name="sb_2__1_" value="0" alias="sb_2__1_"/>
|
||||
<key id="17" name="cbx_1__0_" value="0" alias="cbx_1__0_"/>
|
||||
<key id="18" name="grid_clb" value="1" alias="grid_clb_1__2_"/>
|
||||
<key id="19" name="cbx_1__2_" value="0" alias="cbx_1__2_"/>
|
||||
<key id="20" name="cbx_1__2_" value="1" alias="cbx_2__2_"/>
|
||||
<key id="21" name="sb_2__0_" value="0" alias="sb_2__0_"/>
|
||||
<key id="22" name="sb_1__2_" value="0" alias="sb_1__2_"/>
|
||||
<key id="23" name="cby_0__1_" value="1" alias="cby_0__2_"/>
|
||||
<key id="24" name="sb_0__0_" value="0" alias="sb_0__0_"/>
|
||||
<key id="25" name="grid_clb" value="0" alias="grid_clb_1__1_"/>
|
||||
<key id="26" name="cby_2__1_" value="1" alias="cby_2__2_"/>
|
||||
<key id="27" name="grid_io_top" value="1" alias="grid_io_top_2__3_"/>
|
||||
<key id="28" name="sb_0__2_" value="0" alias="sb_0__2_"/>
|
||||
<key id="29" name="grid_io_bottom" value="1" alias="grid_io_bottom_2__0_"/>
|
||||
<key id="30" name="cbx_1__1_" value="0" alias="cbx_1__1_"/>
|
||||
<key id="31" name="grid_io_top" value="0" alias="grid_io_top_1__3_"/>
|
||||
<key id="32" name="grid_io_left" value="1" alias="grid_io_left_0__2_"/>
|
||||
<region id="0">
|
||||
<key id="0" name="sb_2__2_" value="0" alias="sb_2__2_"/>
|
||||
<key id="1" name="grid_clb" value="3" alias="grid_clb_2__2_"/>
|
||||
<key id="2" name="sb_0__1_" value="0" alias="sb_0__1_"/>
|
||||
<key id="3" name="cby_0__1_" value="0" alias="cby_0__1_"/>
|
||||
<key id="4" name="grid_clb" value="2" alias="grid_clb_2__1_"/>
|
||||
<key id="5" name="grid_io_left" value="0" alias="grid_io_left_0__1_"/>
|
||||
<key id="6" name="sb_1__0_" value="0" alias="sb_1__0_"/>
|
||||
<key id="7" name="sb_1__1_" value="0" alias="sb_1__1_"/>
|
||||
<key id="8" name="cbx_1__1_" value="1" alias="cbx_2__1_"/>
|
||||
<key id="9" name="cby_1__1_" value="1" alias="cby_1__2_"/>
|
||||
<key id="10" name="grid_io_right" value="1" alias="grid_io_right_3__2_"/>
|
||||
<key id="11" name="cbx_1__0_" value="1" alias="cbx_2__0_"/>
|
||||
<key id="12" name="cby_1__1_" value="0" alias="cby_1__1_"/>
|
||||
<key id="13" name="grid_io_right" value="0" alias="grid_io_right_3__1_"/>
|
||||
<key id="14" name="grid_io_bottom" value="0" alias="grid_io_bottom_1__0_"/>
|
||||
<key id="15" name="cby_2__1_" value="0" alias="cby_2__1_"/>
|
||||
<key id="16" name="sb_2__1_" value="0" alias="sb_2__1_"/>
|
||||
<key id="17" name="cbx_1__0_" value="0" alias="cbx_1__0_"/>
|
||||
<key id="18" name="grid_clb" value="1" alias="grid_clb_1__2_"/>
|
||||
<key id="19" name="cbx_1__2_" value="0" alias="cbx_1__2_"/>
|
||||
<key id="20" name="cbx_1__2_" value="1" alias="cbx_2__2_"/>
|
||||
<key id="21" name="sb_2__0_" value="0" alias="sb_2__0_"/>
|
||||
<key id="22" name="sb_1__2_" value="0" alias="sb_1__2_"/>
|
||||
<key id="23" name="cby_0__1_" value="1" alias="cby_0__2_"/>
|
||||
<key id="24" name="sb_0__0_" value="0" alias="sb_0__0_"/>
|
||||
<key id="25" name="grid_clb" value="0" alias="grid_clb_1__1_"/>
|
||||
<key id="26" name="cby_2__1_" value="1" alias="cby_2__2_"/>
|
||||
<key id="27" name="grid_io_top" value="1" alias="grid_io_top_2__3_"/>
|
||||
<key id="28" name="sb_0__2_" value="0" alias="sb_0__2_"/>
|
||||
<key id="29" name="grid_io_bottom" value="1" alias="grid_io_bottom_2__0_"/>
|
||||
<key id="30" name="cbx_1__1_" value="0" alias="cbx_1__1_"/>
|
||||
<key id="31" name="grid_io_top" value="0" alias="grid_io_top_1__3_"/>
|
||||
<key id="32" name="grid_io_left" value="1" alias="grid_io_left_0__2_"/>
|
||||
</region>
|
||||
</fabric_key>
|
||||
|
|
|
@ -0,0 +1,189 @@
|
|||
<!-- 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
|
||||
-->
|
||||
<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="true" 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"/>
|
||||
<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" num_regions="4"/>
|
||||
</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>
|
||||
<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>
|
|
@ -0,0 +1,191 @@
|
|||
<!-- 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
|
||||
-->
|
||||
<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" lib_name="SET" size="1" is_global="true" default_val="0" is_set="true"/>
|
||||
<port type="input" prefix="reset" lib_name="RST" 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" lib_name="CK" size="1" is_global="true" 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="DFFSR" prefix="DFFSR" 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="pReset" lib_name="RST" size="1" is_global="true" default_val="0" is_reset="true" is_prog="true"/>
|
||||
<port type="input" prefix="pSet" lib_name="SET" size="1" is_global="true" default_val="0" is_set="true" is_prog="true"/>
|
||||
<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"/>
|
||||
<port type="sram" prefix="DIR" size="1" mode_select="true" circuit_model_name="DFFSR" 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="DFFSR" num_regions="4"/>
|
||||
</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>
|
||||
<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>
|
|
@ -0,0 +1,34 @@
|
|||
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||
# 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
|
||||
fpga_flow=vpr_blif
|
||||
|
||||
[OpenFPGA_SHELL]
|
||||
openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/OpenFPGAShellScripts/generate_fabric_key_example_script.openfpga
|
||||
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_multi_region_cc_openfpga.xml
|
||||
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
|
||||
|
||||
[ARCHITECTURES]
|
||||
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_40nm.xml
|
||||
|
||||
[BENCHMARKS]
|
||||
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.blif
|
||||
|
||||
[SYNTHESIS_PARAM]
|
||||
bench0_top = and2
|
||||
bench0_act = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.act
|
||||
bench0_verilog = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.v
|
||||
|
||||
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
|
|
@ -0,0 +1,39 @@
|
|||
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||
# 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
|
||||
fpga_flow=vpr_blif
|
||||
|
||||
[OpenFPGA_SHELL]
|
||||
openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/OpenFPGAShellScripts/generate_secure_fabric_from_key_example_script.openfpga
|
||||
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_multi_region_cc_openfpga.xml
|
||||
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
|
||||
external_fabric_key_file=${PATH:OPENFPGA_PATH}/openfpga_flow/fabric_keys/k4_N4_2x2_multi_region_sample_key.xml
|
||||
openfpga_vpr_device_layout=auto
|
||||
|
||||
[ARCHITECTURES]
|
||||
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_40nm.xml
|
||||
|
||||
[BENCHMARKS]
|
||||
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.blif
|
||||
|
||||
[SYNTHESIS_PARAM]
|
||||
bench0_top = and2
|
||||
bench0_act = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.act
|
||||
bench0_verilog = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.v
|
||||
bench0_chan_width = 300
|
||||
|
||||
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
|
||||
end_flow_with_test=
|
||||
#vpr_fpga_verilog_formal_verification_top_netlist=
|
|
@ -0,0 +1,43 @@
|
|||
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||
# 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
|
||||
fpga_flow=yosys_vpr
|
||||
|
||||
[OpenFPGA_SHELL]
|
||||
openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/OpenFPGAShellScripts/fix_device_example_script.openfpga
|
||||
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_multi_region_cc_openfpga.xml
|
||||
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
|
||||
openfpga_vpr_device_layout=2x2
|
||||
|
||||
[ARCHITECTURES]
|
||||
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_40nm.xml
|
||||
|
||||
[BENCHMARKS]
|
||||
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.v
|
||||
bench1=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/or2/or2.v
|
||||
bench2=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2_latch/and2_latch.v
|
||||
|
||||
[SYNTHESIS_PARAM]
|
||||
bench0_top = and2
|
||||
bench0_chan_width = 300
|
||||
|
||||
bench1_top = or2
|
||||
bench1_chan_width = 300
|
||||
|
||||
bench2_top = and2_latch
|
||||
bench2_chan_width = 300
|
||||
|
||||
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
|
||||
end_flow_with_test=
|
|
@ -0,0 +1,34 @@
|
|||
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||
# 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
|
||||
fpga_flow=yosys_vpr
|
||||
|
||||
[OpenFPGA_SHELL]
|
||||
openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/OpenFPGAShellScripts/fast_configuration_example_script.openfpga
|
||||
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_multi_region_cc_use_both_set_reset_openfpga.xml
|
||||
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
|
||||
|
||||
[ARCHITECTURES]
|
||||
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_40nm.xml
|
||||
|
||||
[BENCHMARKS]
|
||||
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.v
|
||||
|
||||
[SYNTHESIS_PARAM]
|
||||
bench0_top = and2
|
||||
bench0_chan_width = 300
|
||||
|
||||
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
|
||||
end_flow_with_test=
|