Merge pull request #56 from LNIS-Projects/dev

Dev
This commit is contained in:
Laboratory for Nano Integrated Systems (LNIS) 2020-06-24 11:46:35 -06:00 committed by GitHub
commit 2c3eb71d00
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
129 changed files with 11226 additions and 1058 deletions

View File

@ -102,6 +102,11 @@ python3 openfpga_flow/scripts/run_fpga_task.py openfpga_shell/generate_testbench
echo -e "Testing SDC generation with time units";
python3 openfpga_flow/scripts/run_fpga_task.py openfpga_shell/sdc_time_unit --debug --show_thread_logs
echo -e "Testing Secured FPGA fabrics";
python3 openfpga_flow/scripts/run_fpga_task.py openfpga_shell/fabric_key/generate_vanilla_key --debug --show_thread_logs
python3 openfpga_flow/scripts/run_fpga_task.py openfpga_shell/fabric_key/generate_random_key --debug --show_thread_logs
python3 openfpga_flow/scripts/run_fpga_task.py openfpga_shell/fabric_key/load_external_key --debug --show_thread_logs
# Verify MCNC big20 benchmark suite with ModelSim
# Please make sure you have ModelSim installed in the environment
# Otherwise, it will fail

View File

@ -0,0 +1,69 @@
Fabric Key
~~~~~~~~~~
Fabric key is a secure key for users to generate bitstream for a specific FPGA fabric.
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.
.. note:: Users are the only owner of the key. OpenFPGA will not store or replicate the key.
Key Generation
``````````````
A fabric key can be achieved in the following ways:
- OpenFPGA can auto-generate a fabric key using random algorithms (see detail in :ref:`cmd_build_fabric`)
- Users can craft a fabric key based on auto-generated file by following the file format description.
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:
- ``id`` indicates the sequence of the configurable memory block in the top-level FPGA fabric.
- ``name`` indicates the module name of the configurable memory block.
- ``value`` indicates the instance id of the configurable memory block in the top-level FPGA fabric.
The following is an example of a fabric key generate by OpenFPGA for a 2 :math:`\times` 2 FPGA.
.. 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"/>
<key id="33" name="decoder6to33" value="0"/>
</fabric_key>

View File

@ -25,4 +25,4 @@ OpenFPGA Architecture Description
annotate_vpr_arch
fabric_key

View File

@ -6,46 +6,109 @@ Usage
Generic bitstream is a fabric-independent bitstream where configuration bits are organized out-of-order in a database.
This can be regarded as a raw bitstream used for
- ``debugging``: Hardware engineers can validate if their configuration memories across the FPGA fabric are assigned to expected values
- ``an exchangeable file format for bitstream assembler``: Software engineers can use the raw bitstream to build a bitstream assembler which organize the bitstream in the loadable formate to FPGA chips.
- ``creation of artificial bitstream``: Test engineers can craft artificial bitstreams to test each element of the FPGA fabric, which is typically not synthesizable by VPR.
.. note:: The fabric-independent bitstream cannot be directly loaded to FPGA fabrics
- ``debugging``: Hardware engineers can validate if their configuration memories across the FPGA fabric are assigned to expected values
- ``an exchangeable file format for bitstream assembler``: Software engineers can use the raw bitstream to build a bitstream assembler which organize the bitstream in the loadable formate to FPGA chips.
- ``creation of artificial bitstream``: Test engineers can craft artificial bitstreams to test each element of the FPGA fabric, which is typically not synthesizable by VPR. Use the ``--read_file`` option to load the artifical bitsteam to OpenFPGA (see details in :ref:`openfpga_bitstream_commands`).
.. warning:: The fabric-independent bitstream cannot be directly loaded to FPGA fabrics
File Format
```````````
OpenFPGA can output the generic bitstream to an XML format, which is easy to debug. As shown in the following XML code, configuration bits are organized block by block, where each block could be a LUT, a routing multiplexer `etc`. Each ``bitstream_block`` includes two sets of information:
OpenFPGA can output the generic bitstream to an XML format, which is easy to debug. As shown in the following XML code, configuration bits are organized block by block, where each block could be a LUT, a routing multiplexer `etc`. Each ``bitstream_block`` includes the following information:
- ``name`` represents the instance name which you can find in the fabric netlists
- ``hierarchy_level`` represents the depth of this block in the hierarchy of the FPGA fabric. It always starts from 0 as the root.
- ``hierarchy`` represents the location of this block in FPGA fabric.
The hierachy includes the full hierarchy of this block
- ``instance`` denotes the instance name which you can find in the fabric netlists
- ``level`` denotes the depth of the block in the hierarchy
- ``input_nets`` represents the path ids and net names that are mapped to the inputs of block. Unused inputs will be tagged as ``unmapped`` which is a reserved word of OpenFPGA. Path id corresponds the selected ``path_id`` in the ``<bitstream>`` node.
- ``output_nets`` represents the path ids and net names that are mapped to the outputs of block. Unused outputs will be tagged as ``unmapped`` which is a reserved word OpenFPGA.
- ``bitstream`` represents the configuration bits affiliated to this block.
- ``path_id`` denotes the index of inputs which is propagated to the output. Note that smallest valid index starts from zero. Only routing multiplexers have the path index. Unused routing multiplexer will not have a ``path_id`` of ``-1``, which allows bitstream assembler to freely find the best path in terms of Quality of Results (QoR). A used routing multiplexer should have a zero or positive ``path_id``.
- ``bit`` denotes a single configuration bit under this block. It contains \
- ``memory_port`` the memory port name which you can find in the fabric netlists by following the hierarchy.
- ``value`` a binary value which is the configuration bit assigned to the memory port.
.. code-block:: xml
<bitstream_block index="0">
<hierarchy>
<bitstream_block name="fpga_top" hierarchy_level="0">
<!-- Bitstream block of a 4-input Look-Up Table in a Configurable Logic Block (CLB) -->
<bitstream_block name="grid_clb_1_1" hierarchy_level="1">
<bitstream_block name="logical_tile_clb_mode_clb__0" hierarchy_level="2">
<bitstream_block name="logical_tile_clb_mode_default__fle_0" hierarchy_level="3">
<bitstream_block name="logical_tile_clb_mode_default__fle_mode_n1_lut4__ble4_0" hierarchy_level="4">
<bitstream_block name="logical_tile_clb_mode_default__fle_mode_n1_lut4__ble4_mode_default__lut4_0" hierarchy_level="5">
<bitstream_block name="lut4_config_latch_mem" hierarchy_level="6">
<hierarchy>
<instance level="0" name="fpga_top"/>
<instance level="1" name="grid_clb_1_1"/>
<instance level="2" name="logical_tile_clb_mode_clb__0"/>
<instance level="3" name="logical_tile_clb_mode_default__fle_0"/>
<instance level="4" name="logical_tile_clb_mode_default__fle_mode_n1_lut4__ble4_0"/>
<instance level="5" name="logical_tile_clb_mode_default__fle_mode_n1_lut4__ble4_mode_default__lut4_0"/>
<instance level="6" name="lut4_config_latch_mem"/>
</hierarchy>
<bitstream>
<bit memory_port="mem_out[0]" value="0"/>
<bit memory_port="mem_out[1]" value="0"/>
<bit memory_port="mem_out[2]" value="0"/>
<bit memory_port="mem_out[3]" value="0"/>
<bit memory_port="mem_out[4]" value="0"/>
<bit memory_port="mem_out[5]" value="0"/>
<bit memory_port="mem_out[6]" value="0"/>
<bit memory_port="mem_out[7]" value="0"/>
<bit memory_port="mem_out[8]" value="0"/>
<bit memory_port="mem_out[9]" value="0"/>
<bit memory_port="mem_out[10]" value="0"/>
<bit memory_port="mem_out[11]" value="0"/>
<bit memory_port="mem_out[12]" value="0"/>
<bit memory_port="mem_out[13]" value="0"/>
<bit memory_port="mem_out[14]" value="0"/>
<bit memory_port="mem_out[15]" value="0"/>
</bitstream>
</bitstream_block>
</bitstream_block>
</bitstream_block>
</bitstream_block>
</bitstream_block>
</bitstream_block>
<!-- More bitstream blocks -->
<!-- Bitstream block of a 2-input routing multiplexer in a Switch Block (SB) -->
<bitstream_block name="sb_0__2_" hierarchy_level="1">
<bitstream_block name="mem_right_track_0" hierarchy_level="2">
<hierarchy>
<instance level="0" name="fpga_top"/>
<instance level="1" name="grid_clb_1_1"/>
<instance level="2" name="fle_0"/>
<instance level="3" name="lut4_0"/>
</hierarchy>
<bitstream>
<bit memory_port="mem_out[0]" value="1"/>
<instance level="1" name="sb_0__2_"/>
<instance level="2" name="mem_right_track_0"/>
</hierarchy>
<input_nets>
<path id="0" net_name="unmapped"/>
<path id="1" net_name="unmapped"/>
</input_nets>
<output_nets>
<path id="0" net_name="unmapped"/>
</output_nets>
<bitstream path_id="-1">
<bit memory_port="mem_out[0]" value="0"/>
<bit memory_port="mem_out[1]" value="0"/>
<bit memory_port="mem_out[2]" value="1"/>
<bit memory_port="mem_out[3]" value="0"/>
<bit memory_port="mem_out[4]" value="1"/>
<bit memory_port="mem_out[5]" value="0"/>
<bit memory_port="mem_out[6]" value="1"/>
<bit memory_port="mem_out[7]" value="0"/>
<bit memory_port="mem_out[8]" value="1"/>
<bit memory_port="mem_out[9]" value="0"/>
<bit memory_port="mem_out[10]" value="1"/>
<bit memory_port="mem_out[11]" value="0"/>
<bit memory_port="mem_out[12]" value="1"/>
<bit memory_port="mem_out[13]" value="0"/>
<bit memory_port="mem_out[14]" value="1"/>
<bit memory_port="mem_out[15]" value="0"/>
</bitstream>
</bitstream>
</bitstream_block>
</bitstream_block>
</bitstream_block>

View File

@ -11,4 +11,4 @@ OpenFPGA Shell
openfpga_script
openfpga_commands
openfpga_commands/index

View File

@ -1,280 +0,0 @@
.. _openfpga_commands:
Commands
--------
As OpenFPGA integrates various tools, the commands are categorized into different classes:
Basic Commands
~~~~~~~~~~~~~~
.. option:: help
Show help desk to list all the available commands
.. option:: exit
Exit OpenFPGA shell
VPR
~~~
.. option:: vpr
OpenFPGA allows users to call ``vpr`` in the standard way as documented in vtr project.
Setup OpenFPGA
~~~~~~~~~~~~~~
.. option:: read_openfpga_arch
Read the XML file about architecture description (see details in :ref:`arch_generality`)
- ``--file`` or ``-f`` Specify the file name
- ``--verbose`` Show verbose log
.. option:: write_openfpga_arch
Write the OpenFPGA XML architecture file to a file
- ``--file`` or ``-f`` Specify the file name
- ``--verbose`` Show verbose log
.. option:: read_openfpga_simulation_setting
Read the XML file about simulation settings (see details in :ref:`simulation_setting`)
- ``--file`` or ``-f`` Specify the file name
- ``--verbose`` Show verbose log
.. option:: write_openfpga_simulation_setting
Write the OpenFPGA XML simulation settings to a file
- ``--file`` or ``-f`` Specify the file name
- ``--verbose`` Show verbose log
.. option:: link_openfpga_arch
Annotate the OpenFPGA architecture to VPR data base
- ``--activity_file`` Specify the signal activity file
- ``--sort_gsb_chan_node_in_edges`` Sort the edges for the routing tracks in General Switch Blocks (GSBs). Strongly recommand to turn this on for uniquifying the routing modules
- ``--verbose`` Show verbose log
.. option:: write_gsb_to_xml
Write the internal structure of General Switch Blocks (GSBs) across a FPGA fabric, including the interconnection between the nodes and node-level details, to XML files
- ``--file`` or ``-f`` Specify the output directory of the XML files. Each GSB will be written to an indepedent XML file
- ``--verbose`` Show verbose log
.. note:: This command is used to help users to study the difference between GSBs
.. option:: check_netlist_naming_conflict
Check and correct any naming conflicts in the BLIF netlist
This is strongly recommended. Otherwise, the outputted Verilog netlists may not be compiled successfully.
.. warning:: This command may be deprecated in future when it is merged to VPR upstream
- ``--fix`` Apply fix-up to the names that violate the syntax
- ``--report <.xml>`` Report the naming fix-up to a log file
.. option:: pb_pin_fixup
Apply fix-up to clustering nets based on routing results
This is strongly recommended. Otherwise, the bitstream generation may be wrong
.. warning:: This command may be deprecated in future when it is merged to VPR upstream
- ``--verbose`` Show verbose log
.. option:: lut_truth_table_fixup
Apply fix-up to Look-Up Table truth tables based on packing results
.. warning:: This command may be deprecated in future when it is merged to VPR upstream
- ``--verbose`` Show verbose log
.. option:: build_fabric
Build the module graph.
- ``--compress_routing`` Enable compression on routing architecture modules. Strongly recommend this as it will minimize the number of routing modules to be outputted. It can reduce the netlist size significantly.
- ``--duplicate_grid_pin`` Enable pin duplication on grid modules. This is optional unless ultra-dense layout generation is needed
- ``--verbose`` Show verbose log
.. note:: This is a must-run command before launching FPGA-Verilog, FPGA-Bitstream, FPGA-SDC and FPGA-SPICE
.. option:: write_fabric_hierarchy
Write the hierarchy of FPGA fabric graph to a plain-text file
- ``--file`` or ``-f`` Specify the file name to write the hierarchy.
- ``--depth`` Specify at which depth of the fabric module graph should the writer stop outputting. The root module start from depth 0. For example, if you want a two-level hierarchy, you should specify depth as 1.
- ``--verbose`` Show verbose log
.. note:: This file is designed for hierarchical PnR flow, which requires the tree of Multiple-Instanced-Blocks (MIBs).
FPGA-Bitstream
~~~~~~~~~~~~~~
.. option:: repack
Repack the netlist to physical pbs
This must be done before bitstream generator and testbench generation
Strongly recommend it is done after all the fix-up have been applied
- ``--verbose`` Show verbose log
.. option:: build_architecture_bitstream
Decode VPR implementing results to an fabric-independent bitstream database
- ``--file`` or ``-f`` Output the fabric-independent bitstream to an XML file
- ``--verbose`` Show verbose log
.. option:: build_fabric_bitstream
Build a sequence for every configuration bits in the bitstream database for a specific FPGA fabric
- ``--file`` or ``-f`` Output the fabric bitstream to an plain text file (only 0 or 1)
- ``--verbose`` Show verbose log
.. _openfpga_verilog_commands:
FPGA-Verilog
~~~~~~~~~~~~
.. option:: write_fabric_verilog
Write the Verilog netlist for FPGA fabric based on module graph
- ``--file`` or ``-f`` Specify the output directory for the Verilog netlists
- ``--explicit_port_mapping`` Use explicit port mapping when writing the Verilog netlists
- ``--include_timing`` Output timing information to Verilog netlists for primitive modules
- ``--include_signal_init`` Output signal initialization to Verilog netlists for primitive modules
- ``--support_icarus_simulator`` Output Verilog netlists with syntax that iVerilog simulatorcan accept
- ``--print_user_defined_template`` Output a template Verilog netlist for all the user-defined ``circuit models`` in :ref:`circuit_library`. This aims to help engineers to check what is the port sequence required by top-level Verilog netlists
- ``--verbose`` Show verbose log
.. option:: write_verilog_testbench
Write the Verilog testbench for FPGA fabric
- ``--file`` or ``-f`` The output directory for all the testbench netlists. We suggest the use of same output directory as fabric Verilog netlists
- ``--reference_benchmark_file_path`` Must specify the reference benchmark Verilog file if you want to output any testbenches
- ``--fast_configuration`` Enable fast configuration phase for the top-level testbench in order to reduce runtime of simulations. It is applicable to memory bank and frame-based configuration protocols. When enabled, all the zero configuration bits will be skipped. So ensure that your memory cells can be correctly reset to zero with a reset signal.
- ``--print_top_testbench`` Enable top-level testbench which is a full verification including programming circuit and core logic of FPGA
- ``--print_formal_verification_top_netlist`` Generate a top-level module which can be used in formal verification
- ``--print_preconfig_top_testbench`` Enable pre-configured top-level testbench which is a fast verification skipping programming phase
- ``--print_simulation_ini`` Output an exchangeable simulation ini file, which is needed only when you need to interface different HDL simulators using openfpga flow-run scripts
- ``--explicit_port_mapping`` Use explicit port mapping when writing the Verilog netlists
FPGA-SDC
~~~~~~~~
.. option:: write_pnr_sdc
Write the SDC files for PnR backend
- ``--file`` or ``-f`` Specify the output directory for SDC files
- ``--hierarchical`` Output SDC files without full path in hierarchy
- ``--flatten_names`` Use flatten names (no wildcards) in SDC files
- ``--time_unit`` Specify a time unit to be used in SDC files. Acceptable values are string: ``as`` | ``fs`` | ``ps`` | ``ns`` | ``us`` | ``ms`` | ``ks`` | ``Ms``. By default, we will consider second (``s``).
- ``--output_hierarchy`` Output hierarchy of Multiple-Instance-Blocks(MIBs) to plain text file. This is applied to constrain timing for grids, Switch Blocks and Connection Blocks.
.. note:: Valid only when ``compress_routing`` is enabled in ``build_fabric``
- ``--constrain_global_port`` Constrain all the global ports of FPGA fabric.
- ``--constrain_non_clock_global_port`` Constrain all the non-clock global ports as clocks ports of FPGA fabric
.. note:: ``constrain_global_port`` will treat these global ports in Clock Tree Synthesis (CTS), in purpose of balancing the delay to each sink. Be carefull to enable ``constrain_non_clock_global_port``, this may significanly increase the runtime of CTS as it is supposed to be routed before any other nets. This may cause routing congestion as well.
- ``--constrain_grid`` Constrain all the grids of FPGA fabric
- ``--constrain_sb`` Constrain all the switch blocks of FPGA fabric
- ``--constrain_cb`` Constrain all the connection blocks of FPGA fabric
- ``--constrain_configurable_memory_outputs`` Constrain all the outputs of configurable memories of FPGA fabric
- ``--constrain_routing_multiplexer_outputs`` Constrain all the outputs of routing multiplexer of FPGA fabric
- ``--constrain_switch_block_outputs`` Constrain all the outputs of switch blocks of FPGA fabric
- ``--constrain_zero_delay_paths`` Constrain all the zero-delay paths in FPGA fabric
.. note:: Zero-delay path may cause errors in some PnR tools as it is considered illegal
- ``--verbose`` Enable verbose output
.. option:: write_configuration_chain_sdc
Write the SDC file to constrain the timing for configuration chain. The timing constraints will always start from the first output (Q) of a Configuration Chain Flip-flop (CCFF) and ends at the inputs of the next CCFF in the chain. Note that Qb of CCFF will not be constrained!
- ``--file`` or ``-f`` Specify the output SDC file
- ``--time_unit`` Specify a time unit to be used in SDC files. Acceptable values are string: ``as`` | ``fs`` | ``ps`` | ``ns`` | ``us`` | ``ms`` | ``ks`` | ``Ms``. By default, we will consider second (``s``).
- ``--max_delay`` Specify the maximum delay to be used. The timing value should follow the time unit defined in this command.
- ``--min_delay`` Specify the minimum delay to be used. The timing value should follow the time unit defined in this command.
.. note::
Only applicable when configuration chain is used as configuration protocol
.. option:: write_sdc_disable_timing_configure_ports
Write the SDC file to disable timing for configure ports of programmable modules. The SDC aims to break the combinational loops across FPGAs and avoid false path timing to be visible to timing analyzers
- ``--file`` or ``-f`` Specify the output SDC file
- ``--flatten_names`` Use flatten names (no wildcards) in SDC files
- ``--verbose`` Show verbose log
.. option:: write_analysis_sdc
Write the SDC to run timing analysis for a mapped FPGA fabric
- ``--file`` or ``-f`` Specify the output directory for SDC files
- ``--flatten_names`` Use flatten names (no wildcards) in SDC files
- ``--time_unit`` Specify a time unit to be used in SDC files. Acceptable values are string: ``as`` | ``fs`` | ``ps`` | ``ns`` | ``us`` | ``ms`` | ``ks`` | ``Ms``. By default, we will consider second (``s``).

View File

@ -0,0 +1,15 @@
.. _openfpga_basic_commands:
Basic Commands
--------------
help
~~~~
Show help desk to list all the available commands
exit
~~~~
Exit OpenFPGA shell

View File

@ -0,0 +1,33 @@
.. _openfpga_bitstream_commands:
FPGA-Bitstream
--------------
repack
~~~~~~
Repack the netlist to physical pbs
This must be done before bitstream generator and testbench generation
Strongly recommend it is done after all the fix-up have been applied
- ``--verbose`` Show verbose log
build_architecture_bitstream
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Decode VPR implementing results to an fabric-independent bitstream database
- ``--read_file`` Read the fabric-independent bitstream from an XML file. When this is enabled, bitstream generation will NOT consider VPR results.
- ``--write_file`` Output the fabric-independent bitstream to an XML file
- ``--verbose`` Show verbose log
build_fabric_bitstream
~~~~~~~~~~~~~~~~~~~~~~
Build a sequence for every configuration bits in the bitstream database for a specific FPGA fabric
- ``--file`` or ``-f`` Output the fabric bitstream to an plain text file (only 0 or 1)
- ``--verbose`` Show verbose log

View File

@ -0,0 +1,84 @@
.. _openfpga_sdc_commands:
FPGA-SDC
--------
write_pnr_sdc
~~~~~~~~~~~~~
Write the SDC files for PnR backend
- ``--file`` or ``-f`` Specify the output directory for SDC files
- ``--hierarchical`` Output SDC files without full path in hierarchy
- ``--flatten_names`` Use flatten names (no wildcards) in SDC files
- ``--time_unit`` Specify a time unit to be used in SDC files. Acceptable values are string: ``as`` | ``fs`` | ``ps`` | ``ns`` | ``us`` | ``ms`` | ``ks`` | ``Ms``. By default, we will consider second (``s``).
- ``--output_hierarchy`` Output hierarchy of Multiple-Instance-Blocks(MIBs) to plain text file. This is applied to constrain timing for grids, Switch Blocks and Connection Blocks.
.. note:: Valid only when ``compress_routing`` is enabled in ``build_fabric``
- ``--constrain_global_port`` Constrain all the global ports of FPGA fabric.
- ``--constrain_non_clock_global_port`` Constrain all the non-clock global ports as clocks ports of FPGA fabric
.. note:: ``constrain_global_port`` will treat these global ports in Clock Tree Synthesis (CTS), in purpose of balancing the delay to each sink. Be carefull to enable ``constrain_non_clock_global_port``, this may significanly increase the runtime of CTS as it is supposed to be routed before any other nets. This may cause routing congestion as well.
- ``--constrain_grid`` Constrain all the grids of FPGA fabric
- ``--constrain_sb`` Constrain all the switch blocks of FPGA fabric
- ``--constrain_cb`` Constrain all the connection blocks of FPGA fabric
- ``--constrain_configurable_memory_outputs`` Constrain all the outputs of configurable memories of FPGA fabric
- ``--constrain_routing_multiplexer_outputs`` Constrain all the outputs of routing multiplexer of FPGA fabric
- ``--constrain_switch_block_outputs`` Constrain all the outputs of switch blocks of FPGA fabric
- ``--constrain_zero_delay_paths`` Constrain all the zero-delay paths in FPGA fabric
.. note:: Zero-delay path may cause errors in some PnR tools as it is considered illegal
- ``--verbose`` Enable verbose output
write_configuration_chain_sdc
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Write the SDC file to constrain the timing for configuration chain. The timing constraints will always start from the first output (Q) of a Configuration Chain Flip-flop (CCFF) and ends at the inputs of the next CCFF in the chain. Note that Qb of CCFF will not be constrained!
- ``--file`` or ``-f`` Specify the output SDC file
- ``--time_unit`` Specify a time unit to be used in SDC files. Acceptable values are string: ``as`` | ``fs`` | ``ps`` | ``ns`` | ``us`` | ``ms`` | ``ks`` | ``Ms``. By default, we will consider second (``s``).
- ``--max_delay`` Specify the maximum delay to be used. The timing value should follow the time unit defined in this command.
- ``--min_delay`` Specify the minimum delay to be used. The timing value should follow the time unit defined in this command.
.. note::
Only applicable when configuration chain is used as configuration protocol
write_sdc_disable_timing_configure_ports
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Write the SDC file to disable timing for configure ports of programmable modules. The SDC aims to break the combinational loops across FPGAs and avoid false path timing to be visible to timing analyzers
- ``--file`` or ``-f`` Specify the output SDC file
- ``--flatten_names`` Use flatten names (no wildcards) in SDC files
- ``--verbose`` Show verbose log
write_analysis_sdc
~~~~~~~~~~~~~~~~~~
Write the SDC to run timing analysis for a mapped FPGA fabric
- ``--file`` or ``-f`` Specify the output directory for SDC files
- ``--flatten_names`` Use flatten names (no wildcards) in SDC files
- ``--time_unit`` Specify a time unit to be used in SDC files. Acceptable values are string: ``as`` | ``fs`` | ``ps`` | ``ns`` | ``us`` | ``ms`` | ``ks`` | ``Ms``. By default, we will consider second (``s``).

View File

@ -0,0 +1,44 @@
.. _openfpga_verilog_commands:
FPGA-Verilog
------------
write_fabric_verilog
~~~~~~~~~~~~~~~~~~~~
Write the Verilog netlist for FPGA fabric based on module graph
- ``--file`` or ``-f`` Specify the output directory for the Verilog netlists
- ``--explicit_port_mapping`` Use explicit port mapping when writing the Verilog netlists
- ``--include_timing`` Output timing information to Verilog netlists for primitive modules
- ``--include_signal_init`` Output signal initialization to Verilog netlists for primitive modules
- ``--support_icarus_simulator`` Output Verilog netlists with syntax that iVerilog simulatorcan accept
- ``--print_user_defined_template`` Output a template Verilog netlist for all the user-defined ``circuit models`` in :ref:`circuit_library`. This aims to help engineers to check what is the port sequence required by top-level Verilog netlists
- ``--verbose`` Show verbose log
write_verilog_testbench
~~~~~~~~~~~~~~~~~~~~~~~
Write the Verilog testbench for FPGA fabric
- ``--file`` or ``-f`` The output directory for all the testbench netlists. We suggest the use of same output directory as fabric Verilog netlists
- ``--reference_benchmark_file_path`` Must specify the reference benchmark Verilog file if you want to output any testbenches
- ``--fast_configuration`` Enable fast configuration phase for the top-level testbench in order to reduce runtime of simulations. It is applicable to memory bank and frame-based configuration protocols. When enabled, all the zero configuration bits will be skipped. So ensure that your memory cells can be correctly reset to zero with a reset signal.
- ``--print_top_testbench`` Enable top-level testbench which is a full verification including programming circuit and core logic of FPGA
- ``--print_formal_verification_top_netlist`` Generate a top-level module which can be used in formal verification
- ``--print_preconfig_top_testbench`` Enable pre-configured top-level testbench which is a fast verification skipping programming phase
- ``--print_simulation_ini`` Output an exchangeable simulation ini file, which is needed only when you need to interface different HDL simulators using openfpga flow-run scripts
- ``--explicit_port_mapping`` Use explicit port mapping when writing the Verilog netlists

View File

@ -0,0 +1,21 @@
Commands
--------
As OpenFPGA integrates various tools, the commands are categorized into different classes:
.. _openfpga_commands:
.. toctree::
:maxdepth: 2
basic_commands
vpr_commands
setup_commands
fpga_bitstream_commands
fpga_verilog_commands
fpga_sdc_commands

View File

@ -0,0 +1,127 @@
.. _openfpga_setup_commands:
Setup OpenFPGA
--------------
read_openfpga_arch
~~~~~~~~~~~~~~~~~~
Read the XML file about architecture description (see details in :ref:`arch_generality`)
- ``--file`` or ``-f`` Specify the file name
- ``--verbose`` Show verbose log
write_openfpga_arch
~~~~~~~~~~~~~~~~~~~
Write the OpenFPGA XML architecture file to a file
- ``--file`` or ``-f`` Specify the file name
- ``--verbose`` Show verbose log
read_openfpga_simulation_setting
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Read the XML file about simulation settings (see details in :ref:`simulation_setting`)
- ``--file`` or ``-f`` Specify the file name
- ``--verbose`` Show verbose log
write_openfpga_simulation_setting
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Write the OpenFPGA XML simulation settings to a file
- ``--file`` or ``-f`` Specify the file name
- ``--verbose`` Show verbose log
link_openfpga_arch
~~~~~~~~~~~~~~~~~~
Annotate the OpenFPGA architecture to VPR data base
- ``--activity_file`` Specify the signal activity file
- ``--sort_gsb_chan_node_in_edges`` Sort the edges for the routing tracks in General Switch Blocks (GSBs). Strongly recommand to turn this on for uniquifying the routing modules
- ``--verbose`` Show verbose log
write_gsb_to_xml
~~~~~~~~~~~~~~~~
Write the internal structure of General Switch Blocks (GSBs) across a FPGA fabric, including the interconnection between the nodes and node-level details, to XML files
- ``--file`` or ``-f`` Specify the output directory of the XML files. Each GSB will be written to an indepedent XML file
- ``--verbose`` Show verbose log
.. note:: This command is used to help users to study the difference between GSBs
check_netlist_naming_conflict
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Check and correct any naming conflicts in the BLIF netlist
This is strongly recommended. Otherwise, the outputted Verilog netlists may not be compiled successfully.
.. warning:: This command may be deprecated in future when it is merged to VPR upstream
- ``--fix`` Apply fix-up to the names that violate the syntax
- ``--report <.xml>`` Report the naming fix-up to a log file
pb_pin_fixup
~~~~~~~~~~~~
Apply fix-up to clustering nets based on routing results
This is strongly recommended. Otherwise, the bitstream generation may be wrong
.. warning:: This command may be deprecated in future when it is merged to VPR upstream
- ``--verbose`` Show verbose log
lut_truth_table_fixup
~~~~~~~~~~~~~~~~~~~~~
Apply fix-up to Look-Up Table truth tables based on packing results
.. warning:: This command may be deprecated in future when it is merged to VPR upstream
- ``--verbose`` Show verbose log
.. _cmd_build_fabric:
build_fabric
~~~~~~~~~~~~
Build the module graph.
- ``--compress_routing`` Enable compression on routing architecture modules. Strongly recommend this as it will minimize the number of routing modules to be outputted. It can reduce the netlist size significantly.
- ``--duplicate_grid_pin`` Enable pin duplication on grid modules. This is optional unless ultra-dense layout generation is needed
- ``--load_fabric_key <xml_file>`` Load an external fabric key from an XML file.
- ``--generate_fabric_key`` Generate a fabric key in a random way
- ``--write_fabric_key <xml_file>`` Output current fabric key to an XML file
- ``--verbose`` Show verbose log
.. note:: This is a must-run command before launching FPGA-Verilog, FPGA-Bitstream, FPGA-SDC and FPGA-SPICE
write_fabric_hierarchy
~~~~~~~~~~~~~~~~~~~~~~
Write the hierarchy of FPGA fabric graph to a plain-text file
- ``--file`` or ``-f`` Specify the file name to write the hierarchy.
- ``--depth`` Specify at which depth of the fabric module graph should the writer stop outputting. The root module start from depth 0. For example, if you want a two-level hierarchy, you should specify depth as 1.
- ``--verbose`` Show verbose log
.. note:: This file is designed for hierarchical PnR flow, which requires the tree of Multiple-Instanced-Blocks (MIBs).

View File

@ -0,0 +1,11 @@
.. _openfpga_vpr_commands:
VPR Commands
------------
vpr
~~~
OpenFPGA allows users to call ``vpr`` in the standard way as documented in the vtr_project_.
.. _vtr_project: https://github.com/verilog-to-routing/vtr-verilog-to-routing

View File

@ -4,8 +4,9 @@ A Quick Start
-------------
In this tutorial, we will consider a simple but representative FPGA architecture to show you how to
- Adapt the VPR architecture XML file to OpenFPGA acceptable format
- Create the OpenFPGA architecture XMl file to customize the primitive circuits
- Adapt a VPR architecture XML file to OpenFPGA acceptable format
- Create an OpenFPGA architecture XML file to customize the primitive circuits
- Create a simulation setting XML file to specify the simulation settings
Through this quick example, we will introduce the key steps to build your own FPGA based on a VPR architecture template.
@ -128,6 +129,7 @@ Craft OpenFPGA Architecture
OpenFPGA needs another XML file which contains detailed modeling on the physical design of FPGA architecture.
This is designed to minimize the modification on the original VPR architecture file, so that it can be reused.
You may create an XML file `k4_n4_openfpga_arch.xml` and then add contents shown as follows.
Overview on the Structure
^^^^^^^^^^^^^^^^^^^^^^^^^
@ -136,7 +138,6 @@ An OpenFPGA architecture including the following parts.
- Architecture modeling with a focus on circuit-level description
- Configuration protocol definition
- Annotation on the VPR architecture modules
- Simulation settings
These parts are organized as follows in the XML file.
@ -173,10 +174,6 @@ These parts are organized as follows in the XML file.
</pb_type_annotations>
</openfpga_architecture>
<openfpga_simulation_setting>
...
</openfpga_simulation_setting>
Technology Library Definition
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Technology information are all stored under the ``<technology_library>`` node, which contains transistor-level information to build the FPGA.
@ -474,10 +471,13 @@ The complete annotation is shown as follows:
See details in :ref:`annotate_vpr_arch`.
Simulation Settings
^^^^^^^^^^^^^^^^^^^
~~~~~~~~~~~~~~~~~~~
OpenFPGA needs an XML file where detailed simulation settings are defined.
The simulation settings contain critical parameters to build testbenches for verify the FPGA fabric.
You may create an XML file `k4_n4_openfpga_simulation.xml` and then add contents shown as follows.
The complete annotation is shown as follows:
.. code-block:: xml

View File

@ -18,9 +18,9 @@ We will simply execute the following openfpga task-run by
.. code-block:: shell
python3 openfpga_flow/scripts/run_fpga_task.py openfpga_shell/configuration_chain
python3 openfpga_flow/scripts/run_fpga_task.py openfpga_shell/full_testbench/configuration_chain
Detailed settings, such as architecture XML files and RTL designs, can be found at ``${OPENFPGA_PATH}/openfpga_flow/tasks/openfpga_shell/configuration_chain/config/task.conf``.
Detailed settings, such as architecture XML files and RTL designs, can be found at ``${OPENFPGA_PATH}/openfpga_flow/tasks/openfpga_shell/full_testbench/configuration_chain/config/task.conf``.
.. note:: ``${OPENFPGA_PATH}`` is the root directory of OpenFPGA
@ -28,7 +28,7 @@ After this task-run, you can find all the generated netlists and testbenches at
.. code-block:: shell
${OPENFPGA_PATH}/openfpga_flow/tasks/openfpga_shell/configuration_chain/latest/k4_N4_tileable_40nm/and2/MIN_ROUTE_CHAN_WIDTH/SRC/
${OPENFPGA_PATH}/openfpga_flow/tasks/openfpga_shell/full_testbench/configuration_chain/latest/k4_N4_tileable_40nm/and2/MIN_ROUTE_CHAN_WIDTH/SRC/
.. note:: See :ref:`fabric_netlists` and :ref:`fpga_verilog_testbench` for the netlist details.
@ -43,7 +43,7 @@ The simulation results are logged in
.. code-block:: shell
${OPENFPGA_PATH}/openfpga_flow/tasks/openfpga_shell/configuration_chain/latest/k4_N4_tileable_40nm/and2/MIN_ROUTE_CHAN_WIDTH/vvp_sim_output.txt
${OPENFPGA_PATH}/openfpga_flow/tasks/openfpga_shell/full_testbench/configuration_chain/latest/k4_N4_tileable_40nm/and2/MIN_ROUTE_CHAN_WIDTH/vvp_sim_output.txt
If the verification passed, you should be able to see ``Simulation Succeed`` in the log file.
@ -53,7 +53,7 @@ To visualize the waveforms, you can use the `GTKWave
.. code-block:: shell
gtkwave ${OPENFPGA_PATH}/openfpga_flow/tasks/openfpga_shell/configuration_chain/latest/k4_N4_tileable_40nm/and2/MIN_ROUTE_CHAN_WIDTH/and2_formal.vcd &
gtkwave ${OPENFPGA_PATH}/openfpga_flow/tasks/openfpga_shell/full_testbench/configuration_chain/latest/k4_N4_tileable_40nm/and2/MIN_ROUTE_CHAN_WIDTH/and2_formal.vcd &
Manual Method
^^^^^^^^^^^^^
@ -62,7 +62,7 @@ If you want to run iVerilog simulation manually, you can follow these steps:
.. code-block:: shell
cd ${OPENFPGA_PATH}/openfpga_flow/tasks/openfpga_shell/configuration_chain/latest/k4_N4_tileable_40nm/and2/MIN_ROUTE_CHAN_WIDTH
cd ${OPENFPGA_PATH}/openfpga_flow/tasks/openfpga_shell/full_testbench/configuration_chain/latest/k4_N4_tileable_40nm/and2/MIN_ROUTE_CHAN_WIDTH
source iverilog_output.txt
@ -73,9 +73,9 @@ Debugging Tips
If you want to apply full visibility to the signals, you need to change the following line in
.. code-block:: shell
.. code-block:: shell
${OPENFPGA_PATH}/openfpga_flow/tasks/openfpga_shell/configuration_chain/latest/k4_N4_tileable_40nm/and2/MIN_ROUTE_CHAN_WIDTH/SRC/and2_autocheck_top_tb.v
${OPENFPGA_PATH}/openfpga_flow/tasks/openfpga_shell/full_testbench/configuration_chain/latest/k4_N4_tileable_40nm/and2/MIN_ROUTE_CHAN_WIDTH/SRC/and2_autocheck_top_tb.v
from
@ -100,13 +100,13 @@ You can simply call the python script in the following line:
.. code-block:: shell
python3 openfpga_flow/scripts/run_modelsim.py openfpga_shell/configuration_chain --run_sim
python3 openfpga_flow/scripts/run_modelsim.py openfpga_shell/full_testbench/configuration_chain --run_sim
The script will automatically create a Modelsim project at
.. code-block:: shell
${OPENFPGA_PATH}/openfpga_flow/tasks/openfpga_shell/configuration_chain/latest/k4_N4_tileable_40nm/and2/MIN_ROUTE_CHAN_WIDTH/MSIM2/
${OPENFPGA_PATH}/openfpga_flow/tasks/openfpga_shell/full_testbench/configuration_chain/latest/k4_N4_tileable_40nm/and2/MIN_ROUTE_CHAN_WIDTH/MSIM2/
and run the simulation.
@ -119,7 +119,7 @@ Modify the ``fpga_defines.v`` (see details in :ref:`fabric_netlists`) at
.. code-block:: shell
${OPENFPGA_PATH}/openfpga_flow/tasks/openfpga_shell/configuration_chain/latest/k4_N4_tileable_40nm/and2/MIN_ROUTE_CHAN_WIDTH/SRC/
${OPENFPGA_PATH}/openfpga_flow/tasks/openfpga_shellfull_testbench//configuration_chain/latest/k4_N4_tileable_40nm/and2/MIN_ROUTE_CHAN_WIDTH/SRC/
by **deleting** the line
@ -131,7 +131,7 @@ Create a folder ``MSIM`` under
.. code-block:: shell
${OPENFPGA_PATH}/openfpga_flow/tasks/openfpga_shell/configuration_chain/latest/k4_N4_tileable_40nm/and2/MIN_ROUTE_CHAN_WIDTH/
${OPENFPGA_PATH}/openfpga_flow/tasks/openfpga_shell/full_testbench/configuration_chain/latest/k4_N4_tileable_40nm/and2/MIN_ROUTE_CHAN_WIDTH/
Under the ``MSIM`` folder, create symbolic links to ``SRC`` folder and reference benchmarks by
@ -149,7 +149,7 @@ Add the following file to your project:
.. code-block:: shell
${OPENFPGA_PATH}/openfpga_flow/tasks/openfpga_shell/configuration_chain/latest/k4_N4_tileable_40nm/and2/MIN_ROUTE_CHAN_WIDTH/SRC/and2_include_netlists.v
${OPENFPGA_PATH}/openfpga_flow/tasks/openfpga_shell/full_testbench/configuration_chain/latest/k4_N4_tileable_40nm/and2/MIN_ROUTE_CHAN_WIDTH/SRC/and2_include_netlists.v
Compile the netlists, create a simulation configuration and specify ``and2_autocheck_top_tb`` at the top unit.

View File

@ -3,3 +3,5 @@ add_subdirectory(libini)
add_subdirectory(libopenfpgashell)
add_subdirectory(libarchopenfpga)
add_subdirectory(libopenfpgautil)
add_subdirectory(libfabrickey)
add_subdirectory(libfpgabitstream)

View File

@ -61,6 +61,21 @@ void write_xml_attribute(std::fstream& fp,
fp << "\"";
}
/********************************************************************
* A most utilized function to write an XML attribute to file
* This accepts the value as a size_t
*******************************************************************/
void write_xml_attribute(std::fstream& fp,
const char* attr,
const size_t& value) {
/* Validate the file stream */
openfpga::valid_file_stream(fp);
fp << " " << attr << "=\"";
fp << value;
fp << "\"";
}
/********************************************************************
* A most utilized function to write an XML attribute to file
* This accepts the value as a float

View File

@ -26,4 +26,8 @@ void write_xml_attribute(std::fstream& fp,
const char* attr,
const float& value);
void write_xml_attribute(std::fstream& fp,
const char* attr,
const size_t& value);
#endif

View File

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

View File

@ -0,0 +1,7 @@
<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"/>
</fabric_key>

View File

@ -0,0 +1,86 @@
#include "vtr_assert.h"
#include "fabric_key.h"
/************************************************************************
* Member functions for class FabricKey
***********************************************************************/
/************************************************************************
* Constructors
***********************************************************************/
FabricKey::FabricKey() {
return;
}
/************************************************************************
* Public Accessors : aggregates
***********************************************************************/
FabricKey::fabric_key_range FabricKey::keys() const {
return vtr::make_range(key_ids_.begin(), key_ids_.end());
}
/************************************************************************
* Public Accessors : Basic data query
***********************************************************************/
/* Access the name of a key */
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];
}
bool FabricKey::empty() const {
return 0 == key_ids_.size();
}
/************************************************************************
* Public Mutators
***********************************************************************/
void FabricKey::reserve_keys(const size_t& num_keys) {
key_ids_.reserve(num_keys);
key_names_.reserve(num_keys);
key_values_.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();
return key;
}
void FabricKey::set_key_name(const FabricKeyId& key_id,
const std::string& name) {
/* validate the key_id */
VTR_ASSERT(valid_key_id(key_id));
key_names_[key_id] = name;
}
void FabricKey::set_key_value(const FabricKeyId& key_id,
const size_t& value) {
/* validate the key_id */
VTR_ASSERT(valid_key_id(key_id));
key_values_[key_id] = value;
}
/************************************************************************
* Internal invalidators/validators
***********************************************************************/
/* Validators */
bool FabricKey::valid_key_id(const FabricKeyId& key_id) const {
return ( size_t(key_id) < key_ids_.size() ) && ( key_id == key_ids_[key_id] );
}

View File

@ -0,0 +1,60 @@
#ifndef FABRIC_KEY_H
#define FABRIC_KEY_H
/********************************************************************
* This file include the declaration of fabric key
*******************************************************************/
#include <string>
#include <map>
#include <array>
/* Headers from vtrutil library */
#include "vtr_vector.h"
#include "fabric_key_fwd.h"
/********************************************************************
* A data structure to describe a secure key for fabric organization
*
* Typical usage:
* --------------
* // Create an empty fabric key
* FabricKey fabric_key;
* // Add a key with name and value
* FabricKeyId key = fabic_key.create_key(key_name, key_value);
*
*******************************************************************/
class FabricKey {
public: /* Types */
typedef vtr::vector<FabricKeyId, FabricKeyId>::const_iterator fabric_key_iterator;
/* Create range */
typedef vtr::Range<fabric_key_iterator> fabric_key_range;
public: /* Constructors */
FabricKey();
public: /* Accessors: aggregates */
fabric_key_range keys() const;
public: /* Public Accessors: Basic data query */
std::string key_name(const FabricKeyId& key_id) const;
size_t key_value(const FabricKeyId& key_id) const;
bool empty() const;
public: /* Public Mutators: model-related */
void reserve_keys(const size_t& num_keys);
FabricKeyId create_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);
public: /* Public invalidators/validators */
bool valid_key_id(const FabricKeyId& key_id) const;
private: /* Internal data */
/* Unique ids for each key */
vtr::vector<FabricKeyId, FabricKeyId> key_ids_;
/* Names for each key */
vtr::vector<FabricKeyId, std::string> key_names_;
/* Values for each key */
vtr::vector<FabricKeyId, size_t> key_values_;
};
#endif

View File

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

View File

@ -0,0 +1,88 @@
/********************************************************************
* This file includes the top-level function of this library
* which reads an XML of a fabric key to the associated
* data structures
*******************************************************************/
#include <string>
/* Headers from pugi XML library */
#include "pugixml.hpp"
#include "pugixml_util.hpp"
/* Headers from vtr util library */
#include "vtr_assert.h"
#include "vtr_time.h"
/* Headers from libarchfpga */
#include "arch_error.h"
#include "read_xml_util.h"
#include "read_xml_fabric_key.h"
/********************************************************************
* 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) {
/* Find the id of component key */
const size_t& id = get_attribute(xml_component_key, "id", loc_data).as_int();
const std::string& name = get_attribute(xml_component_key, "name", loc_data).as_string();
const size_t& value = get_attribute(xml_component_key, "value", 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);
}
VTR_ASSERT_SAFE(true == fabric_key.valid_key_id(FabricKeyId(id)));
fabric_key.set_key_name(FabricKeyId(id), name);
fabric_key.set_key_value(FabricKeyId(id), value);
}
/********************************************************************
* Parse XML codes about <fabric> to an object of FabricKey
*******************************************************************/
FabricKey read_xml_fabric_key(const char* key_fname) {
vtr::ScopedStartFinishTimer timer("Read Fabric Key");
FabricKey fabric_key;
/* Parse the file */
pugi::xml_document doc;
pugiutil::loc_data loc_data;
try {
loc_data = pugiutil::load_xml(doc, 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());
fabric_key.reserve_keys(num_keys);
for (size_t ikey = 0; ikey < num_keys; ++ikey) {
fabric_key.create_key();
}
/* Iterate over the children under this node,
* each child should be named after circuit_model
*/
for (pugi::xml_node xml_key : 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"});
}
read_xml_component_key(xml_key, loc_data, fabric_key);
}
} catch (pugiutil::XmlError& e) {
archfpga_throw(key_fname, e.line(),
"%s", e.what());
}
return fabric_key;
}

View File

@ -0,0 +1,16 @@
#ifndef READ_XML_FABRIC_KEY_H
#define READ_XML_FABRIC_KEY_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include "pugixml_util.hpp"
#include "pugixml.hpp"
#include "fabric_key.h"
/********************************************************************
* Function declaration
*******************************************************************/
FabricKey read_xml_fabric_key(const char* key_fname);
#endif

View File

@ -0,0 +1,91 @@
/********************************************************************
* This file includes functions that outputs a configuration protocol to XML format
*******************************************************************/
/* Headers from system goes first */
#include <string>
#include <algorithm>
/* Headers from vtr util library */
#include "vtr_assert.h"
#include "vtr_log.h"
#include "vtr_time.h"
#include "openfpga_digest.h"
/* Headers from arch openfpga library */
#include "write_xml_utils.h"
/* Headers from fabrickey library */
#include "write_xml_fabric_key.h"
/********************************************************************
* A writer to output a component key to XML format
*
* Return 0 if successful
* Return 1 if there are more serious bugs in the architecture
* Return 2 if fail when creating files
*******************************************************************/
static
int write_xml_fabric_component_key(std::fstream& fp,
const FabricKey& fabric_key,
const FabricKeyId& component_key) {
/* Validate the file stream */
if (false == openfpga::valid_file_stream(fp)) {
return 2;
}
fp << "\t" << "<key";
if (false == fabric_key.valid_key_id(component_key)) {
return 1;
}
write_xml_attribute(fp, "id", size_t(component_key));
write_xml_attribute(fp, "name", fabric_key.key_name(component_key).c_str());
write_xml_attribute(fp, "value", fabric_key.key_value(component_key));
fp << "/>" << "\n";
return 0;
}
/********************************************************************
* A writer to output a fabric key to XML format
*
* Return 0 if successful
* Return 1 if there are more serious bugs in the architecture
* Return 2 if fail when creating files
*******************************************************************/
int write_xml_fabric_key(const char* fname,
const FabricKey& fabric_key) {
vtr::ScopedStartFinishTimer timer("Write Fabric Key");
/* Create a file handler */
std::fstream fp;
/* Open the file stream */
fp.open(std::string(fname), std::fstream::out | std::fstream::trunc);
/* Validate the file stream */
openfpga::check_file_stream(fname, fp);
/* Write the root node */
fp << "<fabric_key>" << "\n";
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;
}
}
/* Finish writing the root node */
fp << "</fabric_key>" << "\n";
/* Close the file stream */
fp.close();
return err_code;
}

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -108,6 +108,27 @@ ConfigBlockId BitstreamManager::find_child_block(const ConfigBlockId& block_id,
return candidates[0];
}
int BitstreamManager::block_path_id(const ConfigBlockId& block_id) const {
/* Ensure the input ids are valid */
VTR_ASSERT(true == valid_block_id(block_id));
return block_path_ids_[block_id];
}
std::vector<std::string> BitstreamManager::block_input_net_ids(const ConfigBlockId& block_id) const {
/* Ensure the input ids are valid */
VTR_ASSERT(true == valid_block_id(block_id));
return block_input_net_ids_[block_id];
}
std::vector<std::string> BitstreamManager::block_output_net_ids(const ConfigBlockId& block_id) const {
/* Ensure the input ids are valid */
VTR_ASSERT(true == valid_block_id(block_id));
return block_output_net_ids_[block_id];
}
/******************************************************************************
* Public Mutators
******************************************************************************/
@ -122,18 +143,46 @@ ConfigBitId BitstreamManager::add_bit(const bool& bit_value) {
return bit;
}
ConfigBlockId BitstreamManager::add_block(const std::string& block_name) {
void BitstreamManager::reserve_blocks(const size_t& num_blocks) {
block_ids_.reserve(num_blocks);
block_names_.reserve(num_blocks);
block_bit_ids_.reserve(num_blocks);
block_path_ids_.reserve(num_blocks);
block_input_net_ids_.reserve(num_blocks);
block_output_net_ids_.reserve(num_blocks);
parent_block_ids_.reserve(num_blocks);
child_block_ids_.reserve(num_blocks);
}
ConfigBlockId BitstreamManager::create_block() {
ConfigBlockId block = ConfigBlockId(block_ids_.size());
/* Add a new bit, and allocate associated data structures */
block_ids_.push_back(block);
block_names_.push_back(block_name);
block_names_.emplace_back();
block_bit_ids_.emplace_back();
block_path_ids_.push_back(-2);
block_input_net_ids_.emplace_back();
block_output_net_ids_.emplace_back();
parent_block_ids_.push_back(ConfigBlockId::INVALID());
child_block_ids_.emplace_back();
return block;
}
ConfigBlockId BitstreamManager::add_block(const std::string& block_name) {
ConfigBlockId block = create_block();
set_block_name(block, block_name);
return block;
}
void BitstreamManager::set_block_name(const ConfigBlockId& block_id,
const std::string& block_name) {
/* Ensure the input ids are valid */
VTR_ASSERT(true == valid_block_id(block_id));
block_names_[block_id] = block_name;
}
void BitstreamManager::add_child_block(const ConfigBlockId& parent_block, const ConfigBlockId& child_block) {
/* Ensure the input ids are valid */
VTR_ASSERT(true == valid_block_id(parent_block));
@ -166,6 +215,32 @@ void BitstreamManager::add_bit_to_block(const ConfigBlockId& block, const Config
bit_parent_block_ids_[bit] = block;
}
void BitstreamManager::add_path_id_to_block(const ConfigBlockId& block, const int& path_id) {
/* Ensure the input ids are valid */
VTR_ASSERT(true == valid_block_id(block));
/* Add the bit to the block */
block_path_ids_[block] = path_id;
}
void BitstreamManager::add_input_net_id_to_block(const ConfigBlockId& block,
const std::string& input_net_id) {
/* Ensure the input ids are valid */
VTR_ASSERT(true == valid_block_id(block));
/* Add the bit to the block */
block_input_net_ids_[block].push_back(input_net_id);
}
void BitstreamManager::add_output_net_id_to_block(const ConfigBlockId& block,
const std::string& output_net_id) {
/* Ensure the input ids are valid */
VTR_ASSERT(true == valid_block_id(block));
/* Add the bit to the block */
block_output_net_ids_[block].push_back(output_net_id);
}
void BitstreamManager::add_shared_config_bit_values(const ConfigBitId& bit, const std::vector<bool>& shared_config_bits) {
/* Ensure the input ids are valid */
VTR_ASSERT(true == valid_bit_id(bit));
@ -184,4 +259,8 @@ bool BitstreamManager::valid_block_id(const ConfigBlockId& block_id) const {
return (size_t(block_id) < block_ids_.size()) && (block_id == block_ids_[block_id]);
}
bool BitstreamManager::valid_block_path_id(const ConfigBlockId& block_id) const {
return (true == valid_block_id(block_id)) && (-2 != block_path_id(block_id));
}
} /* end namespace openfpga */

View File

@ -82,19 +82,47 @@ class BitstreamManager {
/* Find the child block in a bitstream manager with a given name */
ConfigBlockId find_child_block(const ConfigBlockId& block_id, const std::string& child_block_name) const;
/* Find path id of a block */
int block_path_id(const ConfigBlockId& block_id) const;
/* Find input net ids of a block */
std::vector<std::string> block_input_net_ids(const ConfigBlockId& block_id) const;
/* Find input net ids of a block */
std::vector<std::string> block_output_net_ids(const ConfigBlockId& block_id) const;
public: /* Public Mutators */
/* Add a new configuration bit to the bitstream manager */
ConfigBitId add_bit(const bool& bit_value);
/* Reserve memory for a number of clocks */
void reserve_blocks(const size_t& num_blocks);
/* Create a new block of configuration bits */
ConfigBlockId create_block();
/* Add a new block of configuration bits to the bitstream manager */
ConfigBlockId add_block(const std::string& block_name);
/* Set a name for a block */
void set_block_name(const ConfigBlockId& block_id,
const std::string& block_name);
/* Set a block as a child block of another */
void add_child_block(const ConfigBlockId& parent_block, const ConfigBlockId& child_block);
/* Add a configuration bit to a block */
void add_bit_to_block(const ConfigBlockId& block, const ConfigBitId& bit);
/* Add a path id to a block */
void add_path_id_to_block(const ConfigBlockId& block, const int& path_id);
/* Add an input net id to a block */
void add_input_net_id_to_block(const ConfigBlockId& block, const std::string& input_net_id);
/* Add an output net id to a block */
void add_output_net_id_to_block(const ConfigBlockId& block, const std::string& output_net_id);
/* Add share configuration bits to a configuration bit */
void add_shared_config_bit_values(const ConfigBitId& bit, const std::vector<bool>& shared_config_bits);
@ -103,6 +131,8 @@ class BitstreamManager {
bool valid_block_id(const ConfigBlockId& block_id) const;
bool valid_block_path_id(const ConfigBlockId& block_id) const;
private: /* Internal data */
/* Unique id of a block of bits in the Bitstream */
vtr::vector<ConfigBlockId, ConfigBlockId> block_ids_;
@ -119,6 +149,28 @@ class BitstreamManager {
vtr::vector<ConfigBlockId, ConfigBlockId> parent_block_ids_;
vtr::vector<ConfigBlockId, std::vector<ConfigBlockId>> child_block_ids_;
/* The ids of the inputs of routing multiplexer blocks which is propagated to outputs
* By default, it will be -2 (which is invalid)
* A valid id starts from -1
* -1 indicates an unused routing multiplexer.
* It will be converted to a valid id by bitstream builders)
* For used routing multiplexers, the path id will be >= 0
*
* Note:
* -Bitstream manager will NOT check if the id is good for bitstream builders
* It just store the results
*/
vtr::vector<ConfigBlockId, int> block_path_ids_;
/* Net ids that are mapped to inputs and outputs of this block
*
* Note:
* -Bitstream manager will NOT check if the id is good for bitstream builders
* It just store the results
*/
vtr::vector<ConfigBlockId, std::vector<std::string>> block_input_net_ids_;
vtr::vector<ConfigBlockId, std::vector<std::string>> block_output_net_ids_;
/* Unique id of a bit in the Bitstream */
vtr::vector<ConfigBitId, ConfigBitId> bit_ids_;
vtr::vector<ConfigBitId, ConfigBlockId> bit_parent_block_ids_;

View File

@ -0,0 +1,181 @@
/********************************************************************
* This file includes the top-level function of this library
* which reads an XML of a fabric key to the associated
* data structures
*******************************************************************/
#include <string>
/* Headers from pugi XML library */
#include "pugixml.hpp"
#include "pugixml_util.hpp"
/* Headers from vtr util library */
#include "vtr_assert.h"
#include "vtr_time.h"
/* Headers from libarchfpga */
#include "arch_error.h"
#include "read_xml_util.h"
#include "openfpga_reserved_words.h"
#include "read_xml_arch_bitstream.h"
/* begin namespace openfpga */
namespace openfpga {
/********************************************************************
* Parse XML codes of a <bitstream_block> to an object of BitstreamManager
* This function goes recursively until we reach the leaf node
*******************************************************************/
static
void rec_read_xml_bitstream_block(pugi::xml_node& xml_bitstream_block,
const pugiutil::loc_data& loc_data,
BitstreamManager& bitstream_manager,
const ConfigBlockId& parent_block) {
/* Find the name of this bitstream block */
const std::string& block_name = get_attribute(xml_bitstream_block, "name", loc_data).as_string();
/* Create the bitstream block */
ConfigBlockId curr_block = bitstream_manager.add_block(block_name);
/* Add it to parent block */
bitstream_manager.add_child_block(parent_block, curr_block);
/* Parse input nets if defined */
pugi::xml_node xml_input_nets = get_single_child(xml_bitstream_block, "input_nets", loc_data, pugiutil::ReqOpt::OPTIONAL);
if (xml_input_nets) {
std::vector<std::string> input_nets;
size_t num_input_nets = count_children(xml_input_nets, "path", loc_data, pugiutil::ReqOpt::OPTIONAL);
input_nets.resize(num_input_nets);
/* Find the child paths/nets */
for (pugi::xml_node xml_input_net : xml_input_nets.children()) {
/* We only care child bitstream blocks here */
if (xml_input_net.name() != std::string("path")) {
bad_tag(xml_input_net, loc_data, xml_input_nets, {"path"});
}
const int& id = get_attribute(xml_input_net, "id", loc_data).as_int();
const std::string& net_name = get_attribute(xml_input_net, "net_name", loc_data).as_string();
VTR_ASSERT((size_t)id < input_nets.size());
input_nets[id] = net_name;
}
for (const std::string& input_net : input_nets) {
bitstream_manager.add_input_net_id_to_block(curr_block, input_net);
}
}
/* Parse output nets if defined */
pugi::xml_node xml_output_nets = get_single_child(xml_bitstream_block, "output_nets", loc_data, pugiutil::ReqOpt::OPTIONAL);
if (xml_output_nets) {
std::vector<std::string> output_nets;
size_t num_output_nets = count_children(xml_output_nets, "path", loc_data, pugiutil::ReqOpt::OPTIONAL);
output_nets.resize(num_output_nets);
/* Find the child paths/nets */
for (pugi::xml_node xml_output_net : xml_output_nets.children()) {
/* We only care child bitstream blocks here */
if (xml_output_net.name() != std::string("path")) {
bad_tag(xml_output_net, loc_data, xml_output_nets, {"path"});
}
const int& id = get_attribute(xml_output_net, "id", loc_data).as_int();
const std::string& net_name = get_attribute(xml_output_net, "net_name", loc_data).as_string();
VTR_ASSERT((size_t)id < output_nets.size());
output_nets[id] = net_name;
}
for (const std::string& output_net : output_nets) {
bitstream_manager.add_output_net_id_to_block(curr_block, output_net);
}
}
/* Parse configuration bits */
pugi::xml_node xml_bitstream = get_single_child(xml_bitstream_block, "bitstream", loc_data, pugiutil::ReqOpt::OPTIONAL);
if (xml_bitstream) {
/* Parse path_id: -2 is an invalid value defined in the bitstream manager internally */
const int& path_id = get_attribute(xml_bitstream, "path_id", loc_data, pugiutil::ReqOpt::OPTIONAL).as_int(-2);
if (-2 < path_id) {
bitstream_manager.add_path_id_to_block(curr_block, path_id);
}
/* Find the child paths/nets */
for (pugi::xml_node xml_bit : xml_bitstream.children()) {
/* We only care child bitstream blocks here */
if (xml_bit.name() != std::string("bit")) {
bad_tag(xml_bit, loc_data, xml_bitstream, {"bit"});
}
const int& bit_value = get_attribute(xml_bit, "value", loc_data).as_int();
ConfigBitId bit = bitstream_manager.add_bit(1 == bit_value);
/* Link the bit to parent block */
bitstream_manager.add_bit_to_block(curr_block, bit);
}
}
/* Go recursively: find all the child blocks and parse */
for (pugi::xml_node xml_child : xml_bitstream_block.children()) {
/* We only care child bitstream blocks here */
if (xml_child.name() == std::string("bitstream_block")) {
rec_read_xml_bitstream_block(xml_child, loc_data, bitstream_manager, curr_block);
}
}
}
/********************************************************************
* Parse XML codes about <bitstream> to an object of Bitstream
*******************************************************************/
BitstreamManager read_xml_architecture_bitstream(const char* fname) {
vtr::ScopedStartFinishTimer timer("Read Architecture Bitstream file");
BitstreamManager bitstream_manager;
/* Parse the file */
pugi::xml_document doc;
pugiutil::loc_data loc_data;
try {
loc_data = pugiutil::load_xml(doc, fname);
/* Count the child <bitstream_block> */
pugi::xml_node xml_root = get_single_child(doc, "bitstream_block", loc_data);
/* Find the name of the top block*/
const std::string& top_block_name = get_attribute(xml_root, "name", loc_data).as_string();
if (top_block_name != std::string(FPGA_TOP_MODULE_NAME)) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_root),
"Top-level block must be named as '%s'!\n",
FPGA_TOP_MODULE_NAME);
}
/* Create the top-level block */
ConfigBlockId top_block = bitstream_manager.add_block(top_block_name);
size_t num_blks = count_children(xml_root, "bitstream_block", loc_data, pugiutil::ReqOpt::OPTIONAL);
/* Reserve bitstream blocks in the data base */
bitstream_manager.reserve_blocks(num_blks);
/* Iterate over the children under this node,
* each child should be named after circuit_model
*/
for (pugi::xml_node xml_blk : xml_root.children()) {
/* Error out if the XML child has an invalid name! */
if (xml_blk.name() != std::string("bitstream_block")) {
bad_tag(xml_blk, loc_data, xml_root, {"bitstream_block"});
}
rec_read_xml_bitstream_block(xml_blk, loc_data, bitstream_manager, top_block);
}
} catch (pugiutil::XmlError& e) {
archfpga_throw(fname, e.line(),
"%s", e.what());
}
return bitstream_manager;
}
} /* end namespace openfpga */

View File

@ -0,0 +1,21 @@
#ifndef READ_XML_ARCH_BITSTREAM_H
#define READ_XML_ARCH_BITSTREAM_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include "pugixml_util.hpp"
#include "pugixml.hpp"
#include "bitstream_manager.h"
/********************************************************************
* Function declaration
*******************************************************************/
/* begin namespace openfpga */
namespace openfpga {
BitstreamManager read_xml_architecture_bitstream(const char* fname);
} /* end namespace openfpga */
#endif

View File

@ -14,10 +14,10 @@
/* Headers from openfpgautil library */
#include "openfpga_digest.h"
#include "openfpga_naming.h"
#include "openfpga_reserved_words.h"
#include "bitstream_manager_utils.h"
#include "arch_bitstream_writer.h"
#include "write_xml_arch_bitstream.h"
/* begin namespace openfpga */
namespace openfpga {
@ -52,46 +52,103 @@ void write_bitstream_xml_file_head(std::fstream& fp) {
static
void rec_write_block_bitstream_to_xml_file(std::fstream& fp,
const BitstreamManager& bitstream_manager,
const ConfigBlockId& block) {
const ConfigBlockId& block,
const size_t& hierarchy_level) {
valid_file_stream(fp);
/* Write the bits of this block */
write_tab_to_file(fp, hierarchy_level);
fp << "<bitstream_block";
fp << " name=\"" << bitstream_manager.block_name(block)<< "\"";
fp << " hierarchy_level=\"" << hierarchy_level << "\"";
fp << ">" << std::endl;
/* Dive to child blocks if this block has any */
for (const ConfigBlockId& child_block : bitstream_manager.block_children(block)) {
rec_write_block_bitstream_to_xml_file(fp, bitstream_manager, child_block);
rec_write_block_bitstream_to_xml_file(fp, bitstream_manager, child_block, hierarchy_level + 1);
}
if (0 == bitstream_manager.block_bits(block).size()) {
write_tab_to_file(fp, hierarchy_level);
fp << "</bitstream_block>" <<std::endl;
return;
}
/* Write the bits of this block */
fp << "<bitstream_block index=\"" << size_t(block) << "\">" << std::endl;
std::vector<ConfigBlockId> block_hierarchy = find_bitstream_manager_block_hierarchy(bitstream_manager, block);
/* Output hierarchy of this parent*/
fp << "\t<hierarchy>" << std::endl;
write_tab_to_file(fp, hierarchy_level + 1);
fp << "<hierarchy>" << std::endl;
size_t hierarchy_counter = 0;
for (const ConfigBlockId& temp_block : block_hierarchy) {
fp << "\t\t<instance level=\"" << hierarchy_counter << "\"";
write_tab_to_file(fp, hierarchy_level + 2);
fp << "<instance level=\"" << hierarchy_counter << "\"";
fp << " name=\"" << bitstream_manager.block_name(temp_block) << "\"";
fp << "/>" << std::endl;
hierarchy_counter++;
}
fp << "\t</hierarchy>" << std::endl;
write_tab_to_file(fp, hierarchy_level + 1);
fp << "</hierarchy>" << std::endl;
/* Output input/output nets if there are any */
if (false == bitstream_manager.block_input_net_ids(block).empty()) {
write_tab_to_file(fp, hierarchy_level + 1);
fp << "<input_nets>\n";
size_t path_counter = 0;
for (const std::string& net : bitstream_manager.block_input_net_ids(block)) {
write_tab_to_file(fp, hierarchy_level + 2);
fp << "<path id=\"" << path_counter << "\"";
fp << " net_name=\"";
fp << net;
fp << "\"/>";
fp << "\n";
path_counter++;
}
write_tab_to_file(fp, hierarchy_level + 1);
fp << "</input_nets>\n";
}
if (false == bitstream_manager.block_output_net_ids(block).empty()) {
write_tab_to_file(fp, hierarchy_level + 1);
fp << "<output_nets>\n";
size_t path_counter = 0;
for (const std::string& net : bitstream_manager.block_output_net_ids(block)) {
write_tab_to_file(fp, hierarchy_level + 2);
fp << "<path id=\"" << path_counter << "\"";
fp << " net_name=\"";
fp << net;
fp << "\"/>";
fp << "\n";
path_counter++;
}
write_tab_to_file(fp, hierarchy_level + 1);
fp << "</output_nets>\n";
}
/* Output child bits under this block */
size_t bit_counter = 0;
fp << "\t<bitstream>" << std::endl;
write_tab_to_file(fp, hierarchy_level + 1);
fp << "<bitstream";
/* Output path id only when it is valid */
if (true == bitstream_manager.valid_block_path_id(block)) {
fp << " path_id=\"" << bitstream_manager.block_path_id(block) << "\"";
}
fp << ">" << std::endl;
for (const ConfigBitId& child_bit : bitstream_manager.block_bits(block)) {
fp << "\t\t<bit";
fp << " memory_port=\"" << generate_configurable_memory_data_out_name() << "[" << bit_counter << "]" << "\"";
write_tab_to_file(fp, hierarchy_level + 2);
fp << "<bit";
fp << " memory_port=\"" << CONFIGURABLE_MEMORY_DATA_OUT_NAME << "[" << bit_counter << "]" << "\"";
fp << " value=\"" << bitstream_manager.bit_value(child_bit) << "\"";
fp << "/>" << std::endl;
bit_counter++;
}
fp << "\t</bitstream>" << std::endl;
write_tab_to_file(fp, hierarchy_level + 1);
fp << "</bitstream>" << std::endl;
write_tab_to_file(fp, hierarchy_level);
fp << "</bitstream_block>" <<std::endl;
}
@ -109,8 +166,8 @@ void rec_write_block_bitstream_to_xml_file(std::fstream& fp,
* specific FPGAs
* 3. TODO: support FASM format
*******************************************************************/
void write_arch_independent_bitstream_to_xml_file(const BitstreamManager& bitstream_manager,
const std::string& fname) {
void write_xml_architecture_bitstream(const BitstreamManager& bitstream_manager,
const std::string& fname) {
/* Ensure that we have a valid file name */
if (true == fname.empty()) {
VTR_LOG_ERROR("Received empty file name to output bitstream!\n\tPlease specify a valid file name.\n");
@ -128,15 +185,13 @@ void write_arch_independent_bitstream_to_xml_file(const BitstreamManager& bitstr
/* Put down a brief introduction */
write_bitstream_xml_file_head(fp);
std::string top_block_name = generate_fpga_top_module_name();
/* Find the top block, which has not parents */
std::vector<ConfigBlockId> top_block = find_bitstream_manager_top_blocks(bitstream_manager);
/* Make sure we have only 1 top block and its name matches the top module */
/* Make sure we have only 1 top block */
VTR_ASSERT(1 == top_block.size());
VTR_ASSERT(0 == top_block_name.compare(bitstream_manager.block_name(top_block[0])));
/* Write bitstream, block by block, in a recursive way */
rec_write_block_bitstream_to_xml_file(fp, bitstream_manager, top_block[0]);
rec_write_block_bitstream_to_xml_file(fp, bitstream_manager, top_block[0], 0);
/* Close file handler */
fp.close();

View File

@ -1,5 +1,5 @@
#ifndef ARCH_BITSTREAM_WRITER_H
#define ARCH_BITSTREAM_WRITER_H
#ifndef WRITE_XML_ARCH_BITSTREAM_H
#define WRITE_XML_ARCH_BITSTREAM_H
/********************************************************************
* Include header files that are required by function declaration
@ -14,8 +14,8 @@
/* begin namespace openfpga */
namespace openfpga {
void write_arch_independent_bitstream_to_xml_file(const BitstreamManager& bitstream_manager,
const std::string& fname);
void write_xml_architecture_bitstream(const BitstreamManager& bitstream_manager,
const std::string& fname);
} /* end namespace openfpga */

View File

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

View File

@ -251,4 +251,20 @@ bool write_space_to_file(std::fstream& fp,
return true;
}
/********************************************************************
* Write a number of tab to a file
********************************************************************/
bool write_tab_to_file(std::fstream& fp,
const size_t& num_tab) {
if (false == valid_file_stream(fp)) {
return false;
}
for (size_t i = 0; i < num_tab; ++i) {
fp << "\t";
}
return true;
}
} /* namespace openfpga ends */

View File

@ -28,6 +28,9 @@ void create_directory(const std::string& dir_path, const bool& recursive = true)
bool write_space_to_file(std::fstream& fp,
const size_t& num_space);
bool write_tab_to_file(std::fstream& fp,
const size_t& num_tab);
} /* namespace openfpga ends */
#endif

View File

@ -10,6 +10,11 @@
/* begin namespace openfpga */
namespace openfpga {
/* Top-level module name */
constexpr char* FPGA_TOP_MODULE_NAME = "fpga_top";
constexpr char* CONFIGURABLE_MEMORY_DATA_OUT_NAME = "mem_out";
/* IO PORT */
/* Prefix of global input, output and inout ports of FPGA fabric */
constexpr char* GIO_INOUT_PREFIX = "gfpga_pad_";

View File

@ -22,6 +22,8 @@ target_link_libraries(libopenfpga
libarchopenfpga
libopenfpgashell
libopenfpgautil
libfabrickey
libfpgabitstream
libini
libvtrutil
libvpr8)

View File

@ -50,5 +50,134 @@ void annotate_rr_node_nets(const DeviceContext& device_ctx,
VTR_LOG("Done with %d nodes mapping\n", counter);
}
/********************************************************************
* This function will find a previous node for a given rr_node
* from the routing traces
*
* It requires a candidate which provided by upstream functions
* Try to validate a candidate by searching it from driving node list
* If not validated, try to find a right one in the routing traces
*******************************************************************/
static
RRNodeId find_previous_node_from_routing_traces(const RRGraph& rr_graph,
t_trace* routing_trace_head,
const RRNodeId& prev_node_candidate,
const RRNodeId& cur_rr_node) {
RRNodeId prev_node = prev_node_candidate;
/* For a valid prev_node, ensure prev node is one of the driving nodes for this rr_node! */
if (prev_node) {
/* Try to spot the previous node in the incoming node list of this rr_node */
bool valid_prev_node = false;
for (const RREdgeId& in_edge : rr_graph.node_in_edges(cur_rr_node)) {
if (prev_node == rr_graph.edge_src_node(in_edge)) {
valid_prev_node = true;
break;
}
}
/* Early exit if we already validate the node */
if (true == valid_prev_node) {
return prev_node;
}
/* If we cannot find one, it could be possible that this rr_node branches
* from an earlier point in the routing tree
*
* +----- ... --->prev_node
* |
* src_node->+
* |
* +-----+ rr_node
*
* Our job now is to start from the head of the traces and find the prev_node
* that drives this rr_node
*
* This search will find the first-fit and finish.
* This is reasonable because if there is a second-fit, it should be a longer path
* which should be considered in routing optimization
*/
if (false == valid_prev_node) {
t_trace* tptr = routing_trace_head;
while (tptr != nullptr) {
RRNodeId cand_prev_node = tptr->index;
bool is_good_cand = false;
for (const RREdgeId& in_edge : rr_graph.node_in_edges(cur_rr_node)) {
if (cand_prev_node == rr_graph.edge_src_node(in_edge)) {
is_good_cand = true;
break;
}
}
if (true == is_good_cand) {
/* Update prev_node */
prev_node = cand_prev_node;
break;
}
/* Move on to the next */
tptr = tptr->next;
}
}
}
return prev_node;
}
/********************************************************************
* Create a mapping between each rr_node and its previous node
* based on VPR routing results
* - Unmapped rr_node will have an invalid id of previous rr_node
*******************************************************************/
void annotate_rr_node_previous_nodes(const DeviceContext& device_ctx,
const ClusteringContext& clustering_ctx,
const RoutingContext& routing_ctx,
VprRoutingAnnotation& vpr_routing_annotation,
const bool& verbose) {
size_t counter = 0;
VTR_LOG("Annotating previous nodes for rr_node...");
VTR_LOGV(verbose, "\n");
for (auto net_id : clustering_ctx.clb_nlist.nets()) {
/* Ignore nets that are not routed */
if (true == clustering_ctx.clb_nlist.net_is_ignored(net_id)) {
continue;
}
/* Ignore used in local cluster only, reserved one CLB pin */
if (false == clustering_ctx.clb_nlist.net_sinks(net_id).size()) {
continue;
}
/* Cache Previous nodes */
RRNodeId prev_node = RRNodeId::INVALID();
t_trace* tptr = routing_ctx.trace[net_id].head;
while (tptr != nullptr) {
RRNodeId rr_node = tptr->index;
/* Find the right previous node */
prev_node = find_previous_node_from_routing_traces(device_ctx.rr_graph,
routing_ctx.trace[net_id].head,
prev_node,
rr_node);
/* Only update mapped nodes */
if (prev_node) {
vpr_routing_annotation.set_rr_node_prev_node(rr_node, prev_node);
counter++;
}
/* Update prev_node */
prev_node = rr_node;
/* Move on to the next */
tptr = tptr->next;
}
}
VTR_LOG("Done with %d nodes mapping\n", counter);
}
} /* end namespace openfpga */

View File

@ -21,6 +21,12 @@ void annotate_rr_node_nets(const DeviceContext& device_ctx,
VprRoutingAnnotation& vpr_routing_annotation,
const bool& verbose);
void annotate_rr_node_previous_nodes(const DeviceContext& device_ctx,
const ClusteringContext& clustering_ctx,
const RoutingContext& routing_ctx,
VprRoutingAnnotation& vpr_routing_annotation,
const bool& verbose);
} /* end namespace openfpga */
#endif

View File

@ -24,11 +24,18 @@ ClusterNetId VprRoutingAnnotation::rr_node_net(const RRNodeId& rr_node) const {
return rr_node_nets_[rr_node];
}
RRNodeId VprRoutingAnnotation::rr_node_prev_node(const RRNodeId& rr_node) const {
/* Ensure that the node_id is in the list */
VTR_ASSERT(size_t(rr_node) < rr_node_nets_.size());
return rr_node_prev_nodes_[rr_node];
}
/************************************************************************
* Public mutators
***********************************************************************/
void VprRoutingAnnotation::init(const RRGraph& rr_graph) {
rr_node_nets_.resize(rr_graph.nodes().size(), ClusterNetId::INVALID());
rr_node_prev_nodes_.resize(rr_graph.nodes().size(), RRNodeId::INVALID());
}
void VprRoutingAnnotation::set_rr_node_net(const RRNodeId& rr_node,
@ -45,4 +52,18 @@ void VprRoutingAnnotation::set_rr_node_net(const RRNodeId& rr_node,
rr_node_nets_[rr_node] = net_id;
}
void VprRoutingAnnotation::set_rr_node_prev_node(const RRNodeId& rr_node,
const RRNodeId& prev_node) {
/* Ensure that the node_id is in the list */
VTR_ASSERT(size_t(rr_node) < rr_node_nets_.size());
/* Warn any override attempt */
if ( (RRNodeId::INVALID() != rr_node_prev_nodes_[rr_node])
&& (prev_node != rr_node_prev_nodes_[rr_node])) {
VTR_LOG_WARN("Override the previous node '%ld' by previous node '%ld' for node '%ld' with in routing context annotation!\n",
size_t(rr_node_prev_nodes_[rr_node]), size_t(prev_node), size_t(rr_node));
}
rr_node_prev_nodes_[rr_node] = prev_node;
}
} /* End namespace openfpga*/

View File

@ -26,13 +26,19 @@ class VprRoutingAnnotation {
VprRoutingAnnotation();
public: /* Public accessors */
ClusterNetId rr_node_net(const RRNodeId& rr_node) const;
RRNodeId rr_node_prev_node(const RRNodeId& rr_node) const;
public: /* Public mutators */
void init(const RRGraph& rr_graph);
void set_rr_node_net(const RRNodeId& rr_node,
const ClusterNetId& net_id);
void set_rr_node_prev_node(const RRNodeId& rr_node,
const RRNodeId& prev_node);
private: /* Internal data */
/* Pair a regular pb_type to its physical pb_type */
/* Clustered net ids mapped to each rr_node */
vtr::vector<RRNodeId, ClusterNetId> rr_node_nets_;
/* Previous rr_node driving each rr_node */
vtr::vector<RRNodeId, RRNodeId> rr_node_prev_nodes_;
};
} /* End namespace openfpga*/

View File

@ -11,8 +11,11 @@
/* Headers from openfpgautil library */
#include "openfpga_digest.h"
/* Headers from fpgabitstream library */
#include "read_xml_arch_bitstream.h"
#include "write_xml_arch_bitstream.h"
#include "build_device_bitstream.h"
#include "arch_bitstream_writer.h"
#include "fabric_bitstream_writer.h"
#include "build_fabric_bitstream.h"
#include "openfpga_bitstream.h"
@ -30,20 +33,25 @@ int fpga_bitstream(OpenfpgaContext& openfpga_ctx,
const Command& cmd, const CommandContext& cmd_context) {
CommandOptionId opt_verbose = cmd.option("verbose");
CommandOptionId opt_file = cmd.option("file");
CommandOptionId opt_write_file = cmd.option("write_file");
CommandOptionId opt_read_file = cmd.option("read_file");
openfpga_ctx.mutable_bitstream_manager() = build_device_bitstream(g_vpr_ctx,
openfpga_ctx,
cmd_context.option_enable(cmd, opt_verbose));
if (true == cmd_context.option_enable(cmd, opt_read_file)) {
openfpga_ctx.mutable_bitstream_manager() = read_xml_architecture_bitstream(cmd_context.option_value(cmd, opt_write_file).c_str());
} else {
openfpga_ctx.mutable_bitstream_manager() = build_device_bitstream(g_vpr_ctx,
openfpga_ctx,
cmd_context.option_enable(cmd, opt_verbose));
}
if (true == cmd_context.option_enable(cmd, opt_file)) {
std::string src_dir_path = find_path_dir_name(cmd_context.option_value(cmd, opt_file));
if (true == cmd_context.option_enable(cmd, opt_write_file)) {
std::string src_dir_path = find_path_dir_name(cmd_context.option_value(cmd, opt_write_file));
/* Create directories */
create_directory(src_dir_path);
write_arch_independent_bitstream_to_xml_file(openfpga_ctx.bitstream_manager(),
cmd_context.option_value(cmd, opt_file));
write_xml_architecture_bitstream(openfpga_ctx.bitstream_manager(),
cmd_context.option_value(cmd, opt_write_file));
}
/* TODO: should identify the error code from internal function execution */

View File

@ -46,10 +46,14 @@ ShellCommandId add_openfpga_arch_bitstream_command(openfpga::Shell<OpenfpgaConte
const std::vector<ShellCommandId>& dependent_cmds) {
Command shell_cmd("build_architecture_bitstream");
/* Add an option '--file' in short '-f'*/
CommandOptionId opt_file = shell_cmd.add_option("file", true, "file path to output the bitstream database");
shell_cmd.set_option_short_name(opt_file, "f");
shell_cmd.set_option_require_value(opt_file, openfpga::OPT_STRING);
/* Add an option '--write_file' */
CommandOptionId opt_write_file = shell_cmd.add_option("write_file", false, "file path to output the bitstream database");
shell_cmd.set_option_require_value(opt_write_file, openfpga::OPT_STRING);
/* Add an option '--read_file' */
CommandOptionId opt_read_file = shell_cmd.add_option("read_file", false, "file path to read the bitstream database");
shell_cmd.set_option_require_value(opt_read_file, openfpga::OPT_STRING);
/* Add an option '--verbose' */
shell_cmd.add_option("verbose", false, "Enable verbose output");

View File

@ -8,10 +8,14 @@
/* Headers from openfpgashell library */
#include "command_exit_codes.h"
/* Headers from fabrickey library */
#include "read_xml_fabric_key.h"
#include "device_rr_gsb.h"
#include "device_rr_gsb_utils.h"
#include "build_device_module.h"
#include "fabric_hierarchy_writer.h"
#include "fabric_key_writer.h"
#include "openfpga_build_fabric.h"
/* Include global variables of VPR */
@ -65,6 +69,9 @@ int build_fabric(OpenfpgaContext& openfpga_ctx,
CommandOptionId opt_compress_routing = cmd.option("compress_routing");
CommandOptionId opt_duplicate_grid_pin = cmd.option("duplicate_grid_pin");
CommandOptionId opt_gen_random_fabric_key = cmd.option("generate_random_fabric_key");
CommandOptionId opt_write_fabric_key = cmd.option("write_fabric_key");
CommandOptionId opt_load_fabric_key = cmd.option("load_fabric_key");
CommandOptionId opt_verbose = cmd.option("verbose");
if (true == cmd_context.option_enable(cmd, opt_compress_routing)) {
@ -75,14 +82,36 @@ int build_fabric(OpenfpgaContext& openfpga_ctx,
VTR_LOG("\n");
/* Load fabric key from file */
FabricKey predefined_fabric_key;
if (true == cmd_context.option_enable(cmd, opt_load_fabric_key)) {
std::string fkey_fname = cmd_context.option_value(cmd, opt_load_fabric_key);
VTR_ASSERT(false == fkey_fname.empty());
predefined_fabric_key = read_xml_fabric_key(fkey_fname.c_str());
}
VTR_LOG("\n");
openfpga_ctx.mutable_module_graph() = build_device_module_graph(openfpga_ctx.mutable_io_location_map(),
openfpga_ctx.mutable_decoder_lib(),
const_cast<const OpenfpgaContext&>(openfpga_ctx),
g_vpr_ctx.device(),
cmd_context.option_enable(cmd, opt_compress_routing),
cmd_context.option_enable(cmd, opt_duplicate_grid_pin),
predefined_fabric_key,
cmd_context.option_enable(cmd, opt_gen_random_fabric_key),
cmd_context.option_enable(cmd, opt_verbose));
/* Output fabric key if user requested */
if (true == cmd_context.option_enable(cmd, opt_write_fabric_key)) {
std::string fkey_fname = cmd_context.option_value(cmd, opt_write_fabric_key);
VTR_ASSERT(false == fkey_fname.empty());
write_fabric_key_to_xml_file(openfpga_ctx.module_graph(),
fkey_fname,
cmd_context.option_enable(cmd, opt_verbose));
}
/* TODO: should identify the error code from internal function execution */
return CMD_EXEC_SUCCESS;
}

View File

@ -95,7 +95,9 @@ int link_arch(OpenfpgaContext& openfpga_ctx,
openfpga_ctx.mutable_vpr_device_annotation(),
cmd_context.option_enable(cmd, opt_verbose));
/* Annotate net mapping to each rr_node
/* Annotate routing results:
* - net mapping to each rr_node
* - previous nodes driving each rr_node
*/
openfpga_ctx.mutable_vpr_routing_annotation().init(g_vpr_ctx.device().rr_graph);
@ -103,6 +105,11 @@ int link_arch(OpenfpgaContext& openfpga_ctx,
openfpga_ctx.mutable_vpr_routing_annotation(),
cmd_context.option_enable(cmd, opt_verbose));
annotate_rr_node_previous_nodes(g_vpr_ctx.device(), g_vpr_ctx.clustering(), g_vpr_ctx.routing(),
openfpga_ctx.mutable_vpr_routing_annotation(),
cmd_context.option_enable(cmd, opt_verbose));
/* Build the routing graph annotation
* - RRGSB
* - DeviceRRGSB

View File

@ -705,7 +705,7 @@ std::string generate_configuration_chain_tail_name() {
* TODO: This could be replaced as a constexpr string
*********************************************************************/
std::string generate_configurable_memory_data_out_name() {
return std::string("mem_out");
return std::string(CONFIGURABLE_MEMORY_DATA_OUT_NAME);
}
/*********************************************************************
@ -1409,7 +1409,7 @@ std::string generate_fpga_global_io_port_name(const std::string& prefix,
* We give a fixed name here, because it is independent from benchmark file
********************************************************************/
std::string generate_fpga_top_module_name() {
return std::string("fpga_top");
return std::string(FPGA_TOP_MODULE_NAME);
}
/*********************************************************************
@ -1418,7 +1418,7 @@ std::string generate_fpga_top_module_name() {
* We give a fixed name here, because it is independent from benchmark file
********************************************************************/
std::string generate_fpga_top_netlist_name(const std::string& postfix) {
return std::string("fpga_top" + postfix);
return std::string(FPGA_TOP_MODULE_NAME + postfix);
}
/*********************************************************************

View File

@ -273,6 +273,17 @@ ShellCommandId add_openfpga_build_fabric_command(openfpga::Shell<OpenfpgaContext
/* Add an option '--duplicate_grid_pin' */
shell_cmd.add_option("duplicate_grid_pin", false, "Duplicate the pins on the same side of a grid");
/* Add an option '--load_fabric_key' */
CommandOptionId opt_load_fkey = shell_cmd.add_option("load_fabric_key", false, "load the fabric key from the given file");
shell_cmd.set_option_require_value(opt_load_fkey, openfpga::OPT_STRING);
/* Add an option '--write_fabric_key' */
CommandOptionId opt_write_fkey = shell_cmd.add_option("write_fabric_key", false, "output current fabric key to a file");
shell_cmd.set_option_require_value(opt_write_fkey, openfpga::OPT_STRING);
/* Add an option '--generate_random_fabric_key' */
shell_cmd.add_option("generate_random_fabric_key", false, "Create a random fabric key which will shuffle the memory address for encryption purpose");
/* Add an option '--verbose' */
shell_cmd.add_option("verbose", false, "Show verbose outputs");

View File

@ -32,6 +32,8 @@ ModuleManager build_device_module_graph(IoLocationMap& io_location_map,
const DeviceContext& vpr_device_ctx,
const bool& compress_routing,
const bool& duplicate_grid_pin,
const FabricKey& fabric_key,
const bool& generate_random_fabric_key,
const bool& verbose) {
vtr::ScopedStartFinishTimer timer("Build fabric module graph");
@ -116,7 +118,8 @@ ModuleManager build_device_module_graph(IoLocationMap& io_location_map,
openfpga_ctx.arch().arch_direct,
openfpga_ctx.arch().config_protocol.type(),
sram_model,
compress_routing, duplicate_grid_pin);
compress_routing, duplicate_grid_pin,
fabric_key, generate_random_fabric_key);
/* Now a critical correction has to be done!
* In the module construction, we always use prefix of ports because they are binded

View File

@ -6,6 +6,7 @@
*******************************************************************/
#include "vpr_context.h"
#include "openfpga_context.h"
#include "fabric_key.h"
/********************************************************************
* Function declaration
@ -20,6 +21,8 @@ ModuleManager build_device_module_graph(IoLocationMap& io_location_map,
const DeviceContext& vpr_device_ctx,
const bool& compress_routing,
const bool& duplicate_grid_pin,
const FabricKey& fabric_key,
const bool& generate_random_fabric_key,
const bool& verbose);
} /* end namespace openfpga */

View File

@ -321,7 +321,9 @@ void build_top_module(ModuleManager& module_manager,
const e_config_protocol_type& sram_orgz_type,
const CircuitModelId& sram_model,
const bool& compact_routing_hierarchy,
const bool& duplicate_grid_pin) {
const bool& duplicate_grid_pin,
const FabricKey& fabric_key,
const bool& generate_random_fabric_key) {
vtr::ScopedStartFinishTimer timer("Build FPGA fabric module");
@ -362,12 +364,26 @@ void build_top_module(ModuleManager& module_manager,
*/
add_module_gpio_ports_from_child_modules(module_manager, top_module);
/* Organize the list of memory modules and instances */
organize_top_module_memory_modules(module_manager, top_module,
circuit_lib, sram_orgz_type, sram_model,
grids, grid_instance_ids,
device_rr_gsb, sb_instance_ids, cb_instance_ids,
compact_routing_hierarchy);
/* Organize the list of memory modules and instances
* If we have an empty fabric key, we organize the memory modules as routine
* Otherwise, we will load the fabric key directly
*/
if (true == fabric_key.empty()) {
organize_top_module_memory_modules(module_manager, top_module,
circuit_lib, sram_orgz_type, sram_model,
grids, grid_instance_ids,
device_rr_gsb, sb_instance_ids, cb_instance_ids,
compact_routing_hierarchy);
} else {
VTR_ASSERT_SAFE(false == fabric_key.empty());
load_top_module_memory_modules_from_fabric_key(module_manager, top_module,
fabric_key);
}
/* Shuffle the configurable children in a random sequence */
if (true == generate_random_fabric_key) {
shuffle_top_module_configurable_children(module_manager, top_module);
}
/* Add shared SRAM ports from the sub-modules under this Verilog module
* This is a much easier job after adding sub modules (instances),

View File

@ -16,6 +16,7 @@
#include "arch_direct.h"
#include "module_manager.h"
#include "io_location_map.h"
#include "fabric_key.h"
/********************************************************************
* Function declaration
@ -36,7 +37,9 @@ void build_top_module(ModuleManager& module_manager,
const e_config_protocol_type& sram_orgz_type,
const CircuitModelId& sram_model,
const bool& compact_routing_hierarchy,
const bool& duplicate_grid_pin);
const bool& duplicate_grid_pin,
const FabricKey& fabric_key,
const bool& generate_random_fabric_key);
} /* end namespace openfpga */

View File

@ -366,6 +366,85 @@ 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
*
* 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) {
size_t num_keys = module_manager.configurable_children(top_module).size();
std::vector<size_t> shuffled_keys;
shuffled_keys.reserve(num_keys);
for (size_t ikey = 0; ikey < num_keys; ++ikey) {
shuffled_keys.push_back(ikey);
}
std::random_shuffle(shuffled_keys.begin(), shuffled_keys.end());
/* Cache the configurable children and their instances */
std::vector<ModuleId> orig_configurable_children = module_manager.configurable_children(top_module);
std::vector<size_t> orig_configurable_child_instances = module_manager.configurable_child_instances(top_module);
/* Reorganize the configurable children */
module_manager.clear_configurable_children(top_module);
for (size_t ikey = 0; ikey < num_keys; ++ikey) {
module_manager.add_configurable_child(top_module,
orig_configurable_children[shuffled_keys[ikey]],
orig_configurable_child_instances[shuffled_keys[ikey]]);
}
}
/********************************************************************
* Load configurable children from a fabric key to top-level module
*
* Note:
* - This function will overwrite any exisiting configurable children
* under the top module
*
* Return 0 - Success
* Return 1 - Fatal errors
********************************************************************/
int load_top_module_memory_modules_from_fabric_key(ModuleManager& module_manager,
const ModuleId& top_module,
const FabricKey& fabric_key) {
/* Ensure a clean start */
module_manager.clear_configurable_children(top_module);
for (const FabricKeyId& key : fabric_key.keys()) {
/* Find if the module name exist */
ModuleId child_module = module_manager.find_module(fabric_key.key_name(key));
if (false == module_manager.valid_module_id(child_module)) {
VTR_LOGF_ERROR(__FILE__, __LINE__,
"Invalid key name '%s'!\n",
fabric_key.key_name(key).c_str());
return 1;
}
/* Find if instance id is valid */
size_t child_instance = fabric_key.key_value(key);
if (child_instance >= module_manager.num_instance(top_module, child_module)) {
VTR_LOGF_ERROR(__FILE__, __LINE__,
"Invalid key value '%ld'!\n",
child_instance);
return 1;
}
/* Now we can add the child to configurable children of the top module */
module_manager.add_configurable_child(top_module,
child_module,
child_instance);
}
return 0;
}
/********************************************************************
* Add a list of ports that are used for SRAM configuration to the FPGA
* top-level module

View File

@ -14,6 +14,7 @@
#include "decoder_library.h"
#include "device_grid.h"
#include "device_rr_gsb.h"
#include "fabric_key.h"
/********************************************************************
* Function declaration
@ -34,6 +35,13 @@ void organize_top_module_memory_modules(ModuleManager& module_manager,
const std::map<t_rr_type, vtr::Matrix<size_t>>& cb_instance_ids,
const bool& compact_routing_hierarchy);
void shuffle_top_module_configurable_children(ModuleManager& module_manager,
const ModuleId& top_module);
int load_top_module_memory_modules_from_fabric_key(ModuleManager& module_manager,
const ModuleId& top_module,
const FabricKey& fabric_key);
void add_top_module_sram_ports(ModuleManager& module_manager,
const ModuleId& module_id,
const CircuitLibrary& circuit_lib,

View File

@ -0,0 +1,80 @@
/***************************************************************************************
* Output fabric key of Module Graph to file formats
***************************************************************************************/
/* Headers from vtrutil library */
#include "vtr_log.h"
#include "vtr_assert.h"
#include "vtr_time.h"
/* Headers from openfpgautil library */
#include "openfpga_digest.h"
/* Headers from archopenfpga library */
#include "write_xml_fabric_key.h"
#include "openfpga_naming.h"
#include "fabric_key_writer.h"
/* begin namespace openfpga */
namespace openfpga {
/***************************************************************************************
* Write the fabric key of top module to an XML file
* We will use the writer API in libfabrickey
*
* Return 0 if successful
* Return 1 if there are more serious bugs in the architecture
* Return 2 if fail when creating files
***************************************************************************************/
int write_fabric_key_to_xml_file(const ModuleManager& module_manager,
const std::string& fname,
const bool& verbose) {
std::string timer_message = std::string("Write fabric key to XML file '") + fname + std::string("'");
std::string dir_path = format_dir_path(find_path_dir_name(fname));
/* Create directories */
create_directory(dir_path);
/* Start time count */
vtr::ScopedStartFinishTimer timer(timer_message);
/* Use default name if user does not provide one */
VTR_ASSERT(true != fname.empty());
/* Find top-level module */
std::string top_module_name = generate_fpga_top_module_name();
ModuleId top_module = module_manager.find_module(top_module_name);
if (true != module_manager.valid_module_id(top_module)) {
VTR_LOGV_ERROR(verbose,
"Unable to find the top-level module '%s'!\n",
top_module_name.c_str());
return 1;
}
/* Build a fabric key database by visiting all the configurable children */
FabricKey fabric_key;
size_t num_keys = module_manager.configurable_children(top_module).size();
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];
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);
}
VTR_LOGV(verbose,
"Created %lu keys for the top module %s.\n",
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);
return err_code;
}
} /* end namespace openfpga */

View File

@ -0,0 +1,23 @@
#ifndef FABRIC_KEY_WRITER_H
#define FABRIC_KEY_WRITER_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include "vpr_context.h"
#include "openfpga_context.h"
/********************************************************************
* Function declaration
*******************************************************************/
/* begin namespace openfpga */
namespace openfpga {
int write_fabric_key_to_xml_file(const ModuleManager& module_manager,
const std::string& fname,
const bool& verbose);
} /* end namespace openfpga */
#endif

View File

@ -626,6 +626,18 @@ void ModuleManager::add_configurable_child(const ModuleId& parent_module,
configurable_child_instances_[parent_module].push_back(child_instance);
}
void ModuleManager::reserve_configurable_child(const ModuleId& parent_module,
const size_t& num_children) {
VTR_ASSERT ( valid_module_id(parent_module) );
/* Do reserve when the number of children is larger than current size of lists */
if (num_children > configurable_children_[parent_module].size()) {
configurable_children_[parent_module].reserve(num_children);
}
if (num_children > configurable_child_instances_[parent_module].size()) {
configurable_child_instances_[parent_module].reserve(num_children);
}
}
/* Add a net to the connection graph of the module */
ModuleNetId ModuleManager::create_module_net(const ModuleId& module) {
/* Validate the module id */
@ -741,6 +753,16 @@ ModuleNetSinkId ModuleManager::add_module_net_sink(const ModuleId& module, const
return net_sink;
}
/******************************************************************************
* Public Deconstructor
******************************************************************************/
void ModuleManager::clear_configurable_children(const ModuleId& parent_module) {
VTR_ASSERT(valid_module_id(parent_module));
configurable_children_[parent_module].clear();
configurable_child_instances_[parent_module].clear();
}
/******************************************************************************
* Private validators/invalidators
******************************************************************************/

View File

@ -156,6 +156,11 @@ class ModuleManager {
void set_child_instance_name(const ModuleId& parent_module, const ModuleId& child_module, const size_t& instance_id, const std::string& instance_name);
/* Add a configurable child module to module */
void add_configurable_child(const ModuleId& module, const ModuleId& child_module, const size_t& child_instance);
/* Reserved a number of configurable children
* for memory efficiency
*/
void reserve_configurable_child(const ModuleId& module, const size_t& num_children);
/* Add a net to the connection graph of the module */
ModuleNetId create_module_net(const ModuleId& module);
/* Set the name of net */
@ -169,6 +174,13 @@ class ModuleManager {
ModuleNetSinkId add_module_net_sink(const ModuleId& module, const ModuleNetId& net,
const ModuleId& sink_module, const size_t& instance_id,
const ModulePortId& sink_port, const size_t& sink_pin);
public: /* Public deconstructors */
/* This is a strong function which will remove all the configurable children
* 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_configurable_children(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;

View File

@ -60,6 +60,7 @@ BitstreamManager build_device_bitstream(const VprContext& vpr_ctx,
openfpga_ctx.arch().circuit_lib,
openfpga_ctx.mux_lib(),
vpr_ctx.device().grid,
vpr_ctx.atom(),
openfpga_ctx.vpr_device_annotation(),
openfpga_ctx.vpr_clustering_annotation(),
openfpga_ctx.vpr_placement_annotation(),
@ -72,6 +73,7 @@ BitstreamManager build_device_bitstream(const VprContext& vpr_ctx,
openfpga_ctx.module_graph(),
openfpga_ctx.arch().circuit_lib,
openfpga_ctx.mux_lib(),
vpr_ctx.atom(),
openfpga_ctx.vpr_device_annotation(),
openfpga_ctx.vpr_routing_annotation(),
vpr_ctx.device().rr_graph,

View File

@ -128,6 +128,7 @@ void build_physical_block_pin_interc_bitstream(BitstreamManager& bitstream_manag
const ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
const MuxLibrary& mux_lib,
const AtomContext& atom_ctx,
const VprDeviceAnnotation& device_annotation,
const PhysicalPb& physical_pb,
t_pb_graph_pin* des_pb_graph_pin,
@ -157,20 +158,35 @@ void build_physical_block_pin_interc_bitstream(BitstreamManager& bitstream_manag
size_t datapath_mux_size = fan_in;
VTR_ASSERT(true == valid_mux_implementation_num_inputs(datapath_mux_size));
/* Cache input and output nets */
std::vector<AtomNetId> input_nets;
AtomNetId output_net = AtomNetId::INVALID();
/* Find the path id:
* - if des pb is not valid, this is an unmapped pb, we can set a default path_id
* - There is no net mapped to des_pb_graph_pin we use default path id
* - There is a net mapped to des_pin_graph_pin: we find the path id
*/
const PhysicalPbId& des_pb_id = physical_pb.find_pb(des_pb_graph_pin->parent_node);
size_t mux_input_pin_id = 0;
if (true != physical_pb.valid_pb_id(des_pb_id)) {
mux_input_pin_id = DEFAULT_PATH_ID;
} else if (AtomNetId::INVALID() == physical_pb.pb_graph_pin_atom_net(des_pb_id, des_pb_graph_pin)) {
mux_input_pin_id = DEFAULT_PATH_ID;
} else {
output_net = physical_pb.pb_graph_pin_atom_net(des_pb_id, des_pb_graph_pin);
for (t_pb_graph_pin* src_pb_graph_pin : pb_graph_pin_inputs(des_pb_graph_pin, cur_interc)) {
const PhysicalPbId& src_pb_id = physical_pb.find_pb(src_pb_graph_pin->parent_node);
input_nets.push_back(physical_pb.pb_graph_pin_atom_net(src_pb_id, src_pb_graph_pin));
}
for (t_pb_graph_pin* src_pb_graph_pin : pb_graph_pin_inputs(des_pb_graph_pin, cur_interc)) {
const PhysicalPbId& src_pb_id = physical_pb.find_pb(src_pb_graph_pin->parent_node);
/* If the src pb id is not valid, we bypass it */
if ( (true == physical_pb.valid_pb_id(src_pb_id))
&& (AtomNetId::INVALID() != physical_pb.pb_graph_pin_atom_net(des_pb_id, des_pb_graph_pin))
&& (physical_pb.pb_graph_pin_atom_net(src_pb_id, src_pb_graph_pin) == physical_pb.pb_graph_pin_atom_net(des_pb_id, des_pb_graph_pin))) {
&& (AtomNetId::INVALID() != output_net)
&& (physical_pb.pb_graph_pin_atom_net(src_pb_id, src_pb_graph_pin) == output_net)) {
break;
}
mux_input_pin_id++;
@ -203,6 +219,21 @@ void build_physical_block_pin_interc_bitstream(BitstreamManager& bitstream_manag
/* Link the memory bits to the mux mem block */
bitstream_manager.add_bit_to_block(mux_mem_block, config_bit);
}
/* Record path ids, input and output nets */
bitstream_manager.add_path_id_to_block(mux_mem_block, mux_input_pin_id);
for (const AtomNetId& input_net : input_nets) {
if (true == atom_ctx.nlist.valid_net_id(input_net)) {
bitstream_manager.add_input_net_id_to_block(mux_mem_block, atom_ctx.nlist.net_name(input_net));
} else {
bitstream_manager.add_input_net_id_to_block(mux_mem_block, std::string("unmapped"));
}
}
if (true == atom_ctx.nlist.valid_net_id(output_net)) {
bitstream_manager.add_output_net_id_to_block(mux_mem_block, atom_ctx.nlist.net_name(output_net));
} else {
bitstream_manager.add_output_net_id_to_block(mux_mem_block, std::string("unmapped"));
}
break;
}
default:
@ -223,6 +254,7 @@ void build_physical_block_interc_port_bitstream(BitstreamManager& bitstream_mana
const ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
const MuxLibrary& mux_lib,
const AtomContext& atom_ctx,
const VprDeviceAnnotation& device_annotation,
t_pb_graph_node* physical_pb_graph_node,
const PhysicalPb& physical_pb,
@ -234,7 +266,7 @@ void build_physical_block_interc_port_bitstream(BitstreamManager& bitstream_mana
for (int ipin = 0; ipin < physical_pb_graph_node->num_input_pins[iport]; ++ipin) {
build_physical_block_pin_interc_bitstream(bitstream_manager, parent_configurable_block,
module_manager, circuit_lib, mux_lib,
device_annotation,
atom_ctx, device_annotation,
physical_pb,
&(physical_pb_graph_node->input_pins[iport][ipin]),
physical_mode);
@ -246,7 +278,7 @@ void build_physical_block_interc_port_bitstream(BitstreamManager& bitstream_mana
for (int ipin = 0; ipin < physical_pb_graph_node->num_output_pins[iport]; ++ipin) {
build_physical_block_pin_interc_bitstream(bitstream_manager, parent_configurable_block,
module_manager, circuit_lib, mux_lib,
device_annotation,
atom_ctx, device_annotation,
physical_pb,
&(physical_pb_graph_node->output_pins[iport][ipin]),
physical_mode);
@ -258,7 +290,7 @@ void build_physical_block_interc_port_bitstream(BitstreamManager& bitstream_mana
for (int ipin = 0; ipin < physical_pb_graph_node->num_clock_pins[iport]; ++ipin) {
build_physical_block_pin_interc_bitstream(bitstream_manager, parent_configurable_block,
module_manager, circuit_lib, mux_lib,
device_annotation,
atom_ctx, device_annotation,
physical_pb,
&(physical_pb_graph_node->clock_pins[iport][ipin]),
physical_mode);
@ -283,6 +315,7 @@ void build_physical_block_interc_bitstream(BitstreamManager& bitstream_manager,
const ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
const MuxLibrary& mux_lib,
const AtomContext& atom_ctx,
const VprDeviceAnnotation& device_annotation,
t_pb_graph_node* physical_pb_graph_node,
const PhysicalPb& physical_pb,
@ -305,7 +338,7 @@ void build_physical_block_interc_bitstream(BitstreamManager& bitstream_manager,
*/
build_physical_block_interc_port_bitstream(bitstream_manager, parent_configurable_block,
module_manager, circuit_lib, mux_lib,
device_annotation,
atom_ctx, device_annotation,
physical_pb_graph_node, physical_pb,
CIRCUIT_PB_PORT_OUTPUT, physical_mode);
@ -324,13 +357,13 @@ void build_physical_block_interc_bitstream(BitstreamManager& bitstream_manager,
/* For each child_pb_graph_node input pins*/
build_physical_block_interc_port_bitstream(bitstream_manager, parent_configurable_block,
module_manager, circuit_lib, mux_lib,
device_annotation,
atom_ctx, device_annotation,
child_pb_graph_node, physical_pb,
CIRCUIT_PB_PORT_INPUT, physical_mode);
/* For clock pins, we should do the same work */
build_physical_block_interc_port_bitstream(bitstream_manager, parent_configurable_block,
module_manager, circuit_lib, mux_lib,
device_annotation,
atom_ctx, device_annotation,
child_pb_graph_node, physical_pb,
CIRCUIT_PB_PORT_CLOCK, physical_mode);
}
@ -456,6 +489,7 @@ void rec_build_physical_block_bitstream(BitstreamManager& bitstream_manager,
const ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
const MuxLibrary& mux_lib,
const AtomContext& atom_ctx,
const VprDeviceAnnotation& device_annotation,
const e_side& border_side,
const PhysicalPb& physical_pb,
@ -486,6 +520,7 @@ void rec_build_physical_block_bitstream(BitstreamManager& bitstream_manager,
/* Go recursively */
rec_build_physical_block_bitstream(bitstream_manager, pb_configurable_block,
module_manager, circuit_lib, mux_lib,
atom_ctx,
device_annotation,
border_side,
physical_pb, child_pb,
@ -530,6 +565,7 @@ void rec_build_physical_block_bitstream(BitstreamManager& bitstream_manager,
/* Generate the bitstream for the interconnection in this physical block */
build_physical_block_interc_bitstream(bitstream_manager, pb_configurable_block,
module_manager, circuit_lib, mux_lib,
atom_ctx,
device_annotation,
physical_pb_graph_node, physical_pb,
physical_mode);
@ -547,6 +583,7 @@ void build_physical_block_bitstream(BitstreamManager& bitstream_manager,
const ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
const MuxLibrary& mux_lib,
const AtomContext& atom_ctx,
const VprDeviceAnnotation& device_annotation,
const VprClusteringAnnotation& cluster_annotation,
const VprPlacementAnnotation& place_annotation,
@ -581,6 +618,7 @@ void build_physical_block_bitstream(BitstreamManager& bitstream_manager,
/* Recursively traverse the pb_graph and generate bitstream */
rec_build_physical_block_bitstream(bitstream_manager, grid_configurable_block,
module_manager, circuit_lib, mux_lib,
atom_ctx,
device_annotation, border_side,
PhysicalPb(), PhysicalPbId::INVALID(),
lb_type->pb_graph_head, z);
@ -595,6 +633,7 @@ void build_physical_block_bitstream(BitstreamManager& bitstream_manager,
/* Recursively traverse the pb_graph and generate bitstream */
rec_build_physical_block_bitstream(bitstream_manager, grid_configurable_block,
module_manager, circuit_lib, mux_lib,
atom_ctx,
device_annotation, border_side,
phy_pb, top_pb_id, pb_graph_head, z);
}
@ -615,6 +654,7 @@ void build_grid_bitstream(BitstreamManager& bitstream_manager,
const CircuitLibrary& circuit_lib,
const MuxLibrary& mux_lib,
const DeviceGrid& grids,
const AtomContext& atom_ctx,
const VprDeviceAnnotation& device_annotation,
const VprClusteringAnnotation& cluster_annotation,
const VprPlacementAnnotation& place_annotation,
@ -640,6 +680,7 @@ void build_grid_bitstream(BitstreamManager& bitstream_manager,
vtr::Point<size_t> grid_coord(ix, iy);
build_physical_block_bitstream(bitstream_manager, top_block, module_manager,
circuit_lib, mux_lib,
atom_ctx,
device_annotation, cluster_annotation,
place_annotation,
grids, grid_coord, NUM_SIDES);
@ -687,6 +728,7 @@ void build_grid_bitstream(BitstreamManager& bitstream_manager,
}
build_physical_block_bitstream(bitstream_manager, top_block, module_manager,
circuit_lib, mux_lib,
atom_ctx,
device_annotation, cluster_annotation,
place_annotation,
grids, io_coordinate, io_side);

View File

@ -5,6 +5,7 @@
* Include header files that are required by function declaration
*******************************************************************/
#include <vector>
#include "vpr_context.h"
#include "device_grid.h"
#include "bitstream_manager.h"
#include "module_manager.h"
@ -27,6 +28,7 @@ void build_grid_bitstream(BitstreamManager& bitstream_manager,
const CircuitLibrary& circuit_lib,
const MuxLibrary& mux_lib,
const DeviceGrid& grids,
const AtomContext& atom_ctx,
const VprDeviceAnnotation& device_annotation,
const VprClusteringAnnotation& cluster_annotation,
const VprPlacementAnnotation& place_annotation,

View File

@ -41,6 +41,7 @@ void build_switch_block_mux_bitstream(BitstreamManager& bitstream_manager,
const RRGraph& rr_graph,
const RRNodeId& cur_rr_node,
const std::vector<RRNodeId>& drive_rr_nodes,
const AtomContext& atom_ctx,
const VprDeviceAnnotation& device_annotation,
const VprRoutingAnnotation& routing_annotation) {
/* Check current rr_node is CHANX or CHANY*/
@ -50,12 +51,29 @@ void build_switch_block_mux_bitstream(BitstreamManager& bitstream_manager,
/* Find the input size of the implementation of a routing multiplexer */
size_t datapath_mux_size = drive_rr_nodes.size();
/* Find out which routing path is used in this MUX */
int path_id = DEFAULT_PATH_ID;
/* Cache input and output nets */
std::vector<ClusterNetId> input_nets;
ClusterNetId output_net = routing_annotation.rr_node_net(cur_rr_node);
for (size_t inode = 0; inode < drive_rr_nodes.size(); ++inode) {
if (routing_annotation.rr_node_net(drive_rr_nodes[inode]) == routing_annotation.rr_node_net(cur_rr_node)) {
path_id = (int)inode;
break;
input_nets.push_back(routing_annotation.rr_node_net(drive_rr_nodes[inode]));
}
VTR_ASSERT(input_nets.size() == drive_rr_nodes.size());
/* Find out which routing path is used in this MUX
* Two conditions to be considered:
* - There is no net mapped to cur_rr_node: we use default path id
* - There is a net mapped to cur_rr_node: we find the path id
*/
int path_id = DEFAULT_PATH_ID;
if (ClusterNetId::INVALID() != output_net) {
/* We must have a valid previous node that is supposed to drive the source node! */
VTR_ASSERT(routing_annotation.rr_node_prev_node(cur_rr_node));
for (size_t inode = 0; inode < drive_rr_nodes.size(); ++inode) {
if ( (input_nets[inode] == output_net)
&& (drive_rr_nodes[inode] == routing_annotation.rr_node_prev_node(cur_rr_node)) ) {
path_id = (int)inode;
break;
}
}
}
@ -85,6 +103,22 @@ void build_switch_block_mux_bitstream(BitstreamManager& bitstream_manager,
/* Link the memory bits to the mux mem block */
bitstream_manager.add_bit_to_block(mux_mem_block, config_bit);
}
/* Record path ids, input and output nets */
bitstream_manager.add_path_id_to_block(mux_mem_block, path_id);
for (const ClusterNetId& input_net : input_nets) {
AtomNetId input_atom_net = atom_ctx.lookup.atom_net(input_net);
if (true == atom_ctx.nlist.valid_net_id(input_atom_net)) {
bitstream_manager.add_input_net_id_to_block(mux_mem_block, atom_ctx.nlist.net_name(input_atom_net));
} else {
bitstream_manager.add_input_net_id_to_block(mux_mem_block, std::string("unmapped"));
}
}
AtomNetId output_atom_net = atom_ctx.lookup.atom_net(output_net);
if (true == atom_ctx.nlist.valid_net_id(output_atom_net)) {
bitstream_manager.add_output_net_id_to_block(mux_mem_block, atom_ctx.nlist.net_name(output_atom_net));
} else {
bitstream_manager.add_output_net_id_to_block(mux_mem_block, std::string("unmapped"));
}
}
/********************************************************************
@ -101,6 +135,7 @@ void build_switch_block_interc_bitstream(BitstreamManager& bitstream_manager,
const CircuitLibrary& circuit_lib,
const MuxLibrary& mux_lib,
const RRGraph& rr_graph,
const AtomContext& atom_ctx,
const VprDeviceAnnotation& device_annotation,
const VprRoutingAnnotation& routing_annotation,
const RRGSB& rr_gsb,
@ -134,7 +169,7 @@ void build_switch_block_interc_bitstream(BitstreamManager& bitstream_manager,
build_switch_block_mux_bitstream(bitstream_manager, mux_mem_block, module_manager,
circuit_lib, mux_lib, rr_graph,
cur_rr_node, driver_rr_nodes,
device_annotation, routing_annotation);
atom_ctx, device_annotation, routing_annotation);
} /*Nothing should be done else*/
}
@ -155,6 +190,7 @@ void build_switch_block_bitstream(BitstreamManager& bitstream_manager,
const ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
const MuxLibrary& mux_lib,
const AtomContext& atom_ctx,
const VprDeviceAnnotation& device_annotation,
const VprRoutingAnnotation& routing_annotation,
const RRGraph& rr_graph,
@ -173,7 +209,7 @@ void build_switch_block_bitstream(BitstreamManager& bitstream_manager,
build_switch_block_interc_bitstream(bitstream_manager, sb_config_block,
module_manager,
circuit_lib, mux_lib, rr_graph,
device_annotation, routing_annotation,
atom_ctx, device_annotation, routing_annotation,
rr_gsb, side_manager.get_side(), itrack);
}
}
@ -192,6 +228,7 @@ void build_connection_block_mux_bitstream(BitstreamManager& bitstream_manager,
const ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
const MuxLibrary& mux_lib,
const AtomContext& atom_ctx,
const VprDeviceAnnotation& device_annotation,
const VprRoutingAnnotation& routing_annotation,
const RRGraph& rr_graph,
@ -200,16 +237,35 @@ void build_connection_block_mux_bitstream(BitstreamManager& bitstream_manager,
/* Find drive_rr_nodes*/
size_t datapath_mux_size = rr_graph.node_fan_in(src_rr_node);
/* Cache input and output nets */
std::vector<ClusterNetId> input_nets;
ClusterNetId output_net = routing_annotation.rr_node_net(src_rr_node);
for (const RREdgeId& edge : rr_graph.node_in_edges(src_rr_node)) {
RRNodeId driver_node = rr_graph.edge_src_node(edge);
input_nets.push_back(routing_annotation.rr_node_net(driver_node));
}
/* Configuration bits for MUX*/
int path_id = DEFAULT_PATH_ID;
int edge_index = 0;
for (const RREdgeId& edge : rr_graph.node_in_edges(src_rr_node)) {
RRNodeId driver_node = rr_graph.edge_src_node(edge);
if (routing_annotation.rr_node_net(driver_node) == routing_annotation.rr_node_net(src_rr_node)) {
path_id = edge_index;
break;
/* Find which path is connected to the output of this routing multiplexer
* Two conditions to be considered:
* - There is no net mapped to src_rr_node: we use default path id
* - There is a net mapped to src_rr_node: we find the path id
*/
if (ClusterNetId::INVALID() != output_net) {
for (const RREdgeId& edge : rr_graph.node_in_edges(src_rr_node)) {
RRNodeId driver_node = rr_graph.edge_src_node(edge);
/* We must have a valid previous node that is supposed to drive the source node! */
VTR_ASSERT(routing_annotation.rr_node_prev_node(src_rr_node));
if ( (routing_annotation.rr_node_net(driver_node) == output_net)
&& (driver_node == routing_annotation.rr_node_prev_node(src_rr_node)) ) {
path_id = edge_index;
break;
}
edge_index++;
}
edge_index++;
}
/* Ensure that our path id makes sense! */
@ -217,7 +273,6 @@ void build_connection_block_mux_bitstream(BitstreamManager& bitstream_manager,
|| ( (DEFAULT_PATH_ID < path_id) && (path_id < (int)datapath_mux_size) )
);
/* Find the circuit model id of the mux, we need its design technology which matters the bitstream generation */
std::vector<RRSwitchId> driver_switches = get_rr_graph_driver_switches(rr_graph, src_rr_node);
VTR_ASSERT(1 == driver_switches.size());
@ -239,9 +294,24 @@ void build_connection_block_mux_bitstream(BitstreamManager& bitstream_manager,
/* Link the memory bits to the mux mem block */
bitstream_manager.add_bit_to_block(mux_mem_block, config_bit);
}
/* Record path ids, input and output nets */
bitstream_manager.add_path_id_to_block(mux_mem_block, path_id);
for (const ClusterNetId& input_net : input_nets) {
AtomNetId input_atom_net = atom_ctx.lookup.atom_net(input_net);
if (true == atom_ctx.nlist.valid_net_id(input_atom_net)) {
bitstream_manager.add_input_net_id_to_block(mux_mem_block, atom_ctx.nlist.net_name(input_atom_net));
} else {
bitstream_manager.add_input_net_id_to_block(mux_mem_block, std::string("unmapped"));
}
}
AtomNetId output_atom_net = atom_ctx.lookup.atom_net(output_net);
if (true == atom_ctx.nlist.valid_net_id(output_atom_net)) {
bitstream_manager.add_output_net_id_to_block(mux_mem_block, atom_ctx.nlist.net_name(output_atom_net));
} else {
bitstream_manager.add_output_net_id_to_block(mux_mem_block, std::string("unmapped"));
}
}
/********************************************************************
* This function generates bitstream for an interconnection,
* i.e., a routing multiplexer, in a Connection Block
@ -255,6 +325,7 @@ void build_connection_block_interc_bitstream(BitstreamManager& bitstream_manager
const ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
const MuxLibrary& mux_lib,
const AtomContext& atom_ctx,
const VprDeviceAnnotation& device_annotation,
const VprRoutingAnnotation& routing_annotation,
const RRGraph& rr_graph,
@ -277,7 +348,7 @@ void build_connection_block_interc_bitstream(BitstreamManager& bitstream_manager
/* This is a routing multiplexer! Generate bitstream */
build_connection_block_mux_bitstream(bitstream_manager, mux_mem_block,
module_manager, circuit_lib, mux_lib,
device_annotation, routing_annotation,
atom_ctx, device_annotation, routing_annotation,
rr_graph, src_rr_node);
} /*Nothing should be done else*/
}
@ -299,6 +370,7 @@ void build_connection_block_bitstream(BitstreamManager& bitstream_manager,
const ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
const MuxLibrary& mux_lib,
const AtomContext& atom_ctx,
const VprDeviceAnnotation& device_annotation,
const VprRoutingAnnotation& routing_annotation,
const RRGraph& rr_graph,
@ -314,7 +386,7 @@ void build_connection_block_bitstream(BitstreamManager& bitstream_manager,
for (size_t inode = 0; inode < rr_gsb.get_num_ipin_nodes(cb_ipin_side); ++inode) {
build_connection_block_interc_bitstream(bitstream_manager, cb_configurable_block,
module_manager, circuit_lib, mux_lib,
device_annotation, routing_annotation,
atom_ctx, device_annotation, routing_annotation,
rr_graph, rr_gsb,
cb_ipin_side, inode);
}
@ -330,6 +402,7 @@ void build_connection_block_bitstreams(BitstreamManager& bitstream_manager,
const ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
const MuxLibrary& mux_lib,
const AtomContext& atom_ctx,
const VprDeviceAnnotation& device_annotation,
const VprRoutingAnnotation& routing_annotation,
const RRGraph& rr_graph,
@ -360,7 +433,7 @@ void build_connection_block_bitstreams(BitstreamManager& bitstream_manager,
build_connection_block_bitstream(bitstream_manager, cb_configurable_block, module_manager,
circuit_lib, mux_lib,
device_annotation, routing_annotation,
atom_ctx, device_annotation, routing_annotation,
rr_graph,
rr_gsb, cb_type);
}
@ -378,6 +451,7 @@ void build_routing_bitstream(BitstreamManager& bitstream_manager,
const ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
const MuxLibrary& mux_lib,
const AtomContext& atom_ctx,
const VprDeviceAnnotation& device_annotation,
const VprRoutingAnnotation& routing_annotation,
const RRGraph& rr_graph,
@ -408,7 +482,7 @@ void build_routing_bitstream(BitstreamManager& bitstream_manager,
build_switch_block_bitstream(bitstream_manager, sb_configurable_block, module_manager,
circuit_lib, mux_lib,
device_annotation, routing_annotation,
atom_ctx, device_annotation, routing_annotation,
rr_graph,
rr_gsb);
}
@ -423,7 +497,7 @@ void build_routing_bitstream(BitstreamManager& bitstream_manager,
build_connection_block_bitstreams(bitstream_manager, top_configurable_block, module_manager,
circuit_lib, mux_lib,
device_annotation, routing_annotation,
atom_ctx, device_annotation, routing_annotation,
rr_graph,
device_rr_gsb, CHANX);
VTR_LOG("Done\n");
@ -432,7 +506,7 @@ void build_routing_bitstream(BitstreamManager& bitstream_manager,
build_connection_block_bitstreams(bitstream_manager, top_configurable_block, module_manager,
circuit_lib, mux_lib,
device_annotation, routing_annotation,
atom_ctx, device_annotation, routing_annotation,
rr_graph,
device_rr_gsb, CHANY);
VTR_LOG("Done\n");

View File

@ -29,6 +29,7 @@ void build_routing_bitstream(BitstreamManager& bitstream_manager,
const ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
const MuxLibrary& mux_lib,
const AtomContext& atom_ctx,
const VprDeviceAnnotation& device_annotation,
const VprRoutingAnnotation& routing_annotation,
const RRGraph& rr_graph,

View File

@ -29,9 +29,10 @@
#include "verilog_api.h"
/* begin namespace openfpga */
namespace openfpga {
namespace openfpga
{
/********************************************************************
/********************************************************************
* A top-level function of FPGA-Verilog which focuses on fabric Verilog generation
* This function will generate
* - primitive modules required by the full fabric
@ -40,201 +41,206 @@ namespace openfpga {
* - Logic block modules, which are Configuration Logic Blocks (CLBs)
* - FPGA module, which are the full FPGA fabric with configuration protocol
*
* Note:
* Note:
* - Please do NOT include ANY testbench generation in this function!!!
* It is about the fabric itself, independent from any implementation
* All the testbench generation should be in the function fpga_testbench_verilog()
*
* TODO: We should use module manager as a constant here.
* TODO: We should use module manager as a constant here.
* All the modification should be done before this writer!
* The only exception now is the user-defined modules.
* We should think clearly about how to handle them for both Verilog and SPICE generators!
********************************************************************/
void fpga_fabric_verilog(ModuleManager& module_manager,
NetlistManager& netlist_manager,
const CircuitLibrary& circuit_lib,
const MuxLibrary& mux_lib,
const DecoderLibrary& decoder_lib,
const DeviceContext& device_ctx,
const VprDeviceAnnotation& device_annotation,
const DeviceRRGSB& device_rr_gsb,
const FabricVerilogOption& options) {
void fpga_fabric_verilog(ModuleManager &module_manager,
NetlistManager &netlist_manager,
const CircuitLibrary &circuit_lib,
const MuxLibrary &mux_lib,
const DecoderLibrary &decoder_lib,
const DeviceContext &device_ctx,
const VprDeviceAnnotation &device_annotation,
const DeviceRRGSB &device_rr_gsb,
const FabricVerilogOption &options)
{
vtr::ScopedStartFinishTimer timer("Write Verilog netlists for FPGA fabric\n");
vtr::ScopedStartFinishTimer timer("Write Verilog netlists for FPGA fabric\n");
std::string src_dir_path = format_dir_path(options.output_directory());
std::string src_dir_path = format_dir_path(options.output_directory());
/* Create directories */
create_directory(src_dir_path);
/* Create directories */
create_directory(src_dir_path);
/* Sub directory under SRC directory to contain all the primitive block netlists */
std::string submodule_dir_path = src_dir_path + std::string(DEFAULT_SUBMODULE_DIR_NAME);
create_directory(submodule_dir_path);
/* Sub directory under SRC directory to contain all the primitive block netlists */
std::string submodule_dir_path = src_dir_path + std::string(DEFAULT_SUBMODULE_DIR_NAME);
create_directory(submodule_dir_path);
/* Sub directory under SRC directory to contain all the logic block netlists */
std::string lb_dir_path = src_dir_path + std::string(DEFAULT_LB_DIR_NAME);
create_directory(lb_dir_path);
/* Sub directory under SRC directory to contain all the logic block netlists */
std::string lb_dir_path = src_dir_path + std::string(DEFAULT_LB_DIR_NAME);
create_directory(lb_dir_path);
/* Sub directory under SRC directory to contain all the routing block netlists */
std::string rr_dir_path = src_dir_path + std::string(DEFAULT_RR_DIR_NAME);
create_directory(rr_dir_path);
/* Sub directory under SRC directory to contain all the routing block netlists */
std::string rr_dir_path = src_dir_path + std::string(DEFAULT_RR_DIR_NAME);
create_directory(rr_dir_path);
/* Print Verilog files containing preprocessing flags */
print_verilog_preprocessing_flags_netlist(std::string(src_dir_path),
options);
/* Print Verilog files containing preprocessing flags */
print_verilog_preprocessing_flags_netlist(std::string(src_dir_path),
options);
/* Generate primitive Verilog modules, which are corner stones of FPGA fabric
/* Generate primitive Verilog modules, which are corner stones of FPGA fabric
* Note that this function MUST be called before Verilog generation of
* core logic (i.e., logic blocks and routing resources) !!!
* This is because that this function will add the primitive Verilog modules to
* This is because that this function will add the primitive Verilog modules to
* the module manager.
* Without the modules in the module manager, core logic generation is not possible!!!
*/
print_verilog_submodule(module_manager, netlist_manager,
mux_lib, decoder_lib, circuit_lib,
submodule_dir_path,
options);
print_verilog_submodule(module_manager, netlist_manager,
mux_lib, decoder_lib, circuit_lib,
submodule_dir_path,
options);
/* Generate routing blocks */
if (true == options.compress_routing()) {
print_verilog_unique_routing_modules(netlist_manager,
const_cast<const ModuleManager&>(module_manager),
device_rr_gsb,
rr_dir_path,
options.explicit_port_mapping());
} else {
VTR_ASSERT(false == options.compress_routing());
print_verilog_flatten_routing_modules(netlist_manager,
const_cast<const ModuleManager&>(module_manager),
device_rr_gsb,
rr_dir_path,
options.explicit_port_mapping());
/* Generate routing blocks */
if (true == options.compress_routing())
{
print_verilog_unique_routing_modules(netlist_manager,
const_cast<const ModuleManager &>(module_manager),
device_rr_gsb,
rr_dir_path,
options.explicit_port_mapping());
}
else
{
VTR_ASSERT(false == options.compress_routing());
print_verilog_flatten_routing_modules(netlist_manager,
const_cast<const ModuleManager &>(module_manager),
device_rr_gsb,
rr_dir_path,
options.explicit_port_mapping());
}
/* Generate grids */
print_verilog_grids(netlist_manager,
const_cast<const ModuleManager &>(module_manager),
device_ctx, device_annotation,
lb_dir_path,
options.explicit_port_mapping(),
options.verbose_output());
/* Generate FPGA fabric */
print_verilog_top_module(netlist_manager,
const_cast<const ModuleManager &>(module_manager),
src_dir_path,
options.explicit_port_mapping());
/* Generate an netlist including all the fabric-related netlists */
print_fabric_include_netlist(const_cast<const NetlistManager &>(netlist_manager),
src_dir_path,
circuit_lib);
/* Given a brief stats on how many Verilog modules have been written to files */
VTR_LOGV(options.verbose_output(),
"Written %lu Verilog modules in total\n",
module_manager.num_modules());
}
/* Generate grids */
print_verilog_grids(netlist_manager,
const_cast<const ModuleManager&>(module_manager),
device_ctx, device_annotation,
lb_dir_path,
options.explicit_port_mapping(),
options.verbose_output());
/* Generate FPGA fabric */
print_verilog_top_module(netlist_manager,
const_cast<const ModuleManager&>(module_manager),
src_dir_path,
options.explicit_port_mapping());
/* Generate an netlist including all the fabric-related netlists */
print_fabric_include_netlist(const_cast<const NetlistManager&>(netlist_manager),
src_dir_path,
circuit_lib);
/* Given a brief stats on how many Verilog modules have been written to files */
VTR_LOGV(options.verbose_output(),
"Written %lu Verilog modules in total\n",
module_manager.num_modules());
}
/********************************************************************
/********************************************************************
* A top-level function of FPGA-Verilog which focuses on fabric Verilog generation
* This function will generate
* - A wrapper module, which encapsulate the FPGA module in a Verilog module which have the same port as the input benchmark
* - A wrapper module, which encapsulate the FPGA module in a Verilog module which have the same port as the input benchmark
* - Testbench, where a FPGA module is configured with a bitstream and then driven by input vectors
* - Pre-configured testbench, which can skip the configuration phase and pre-configure the FPGA module.
* This testbench is created for quick verification and formal verification purpose.
* - Verilog netlist including preprocessing flags and all the Verilog netlists that have been generated
********************************************************************/
void fpga_verilog_testbench(const ModuleManager& module_manager,
const BitstreamManager& bitstream_manager,
const FabricBitstream& fabric_bitstream,
const AtomContext& atom_ctx,
const PlacementContext& place_ctx,
const IoLocationMap& io_location_map,
const VprNetlistAnnotation& netlist_annotation,
const CircuitLibrary& circuit_lib,
const SimulationSetting& simulation_setting,
const e_config_protocol_type& config_protocol_type,
const VerilogTestbenchOption& options) {
void fpga_verilog_testbench(const ModuleManager &module_manager,
const BitstreamManager &bitstream_manager,
const FabricBitstream &fabric_bitstream,
const AtomContext &atom_ctx,
const PlacementContext &place_ctx,
const IoLocationMap &io_location_map,
const VprNetlistAnnotation &netlist_annotation,
const CircuitLibrary &circuit_lib,
const SimulationSetting &simulation_setting,
const e_config_protocol_type &config_protocol_type,
const VerilogTestbenchOption &options)
{
vtr::ScopedStartFinishTimer timer("Write Verilog testbenches for FPGA fabric\n");
vtr::ScopedStartFinishTimer timer("Write Verilog testbenches for FPGA fabric\n");
std::string src_dir_path = format_dir_path(options.output_directory());
std::string src_dir_path = format_dir_path(options.output_directory());
std::string netlist_name = atom_ctx.nlist.netlist_name();
std::string netlist_name = atom_ctx.nlist.netlist_name();
/* Create directories */
create_directory(src_dir_path);
/* Create directories */
create_directory(src_dir_path);
/* TODO: check if this works here. This function was in fabric generator */
print_verilog_simulation_preprocessing_flags(std::string(src_dir_path),
options);
/* TODO: check if this works here. This function was in fabric generator */
print_verilog_simulation_preprocessing_flags(std::string(src_dir_path),
options);
/* Collect global ports from the circuit library:
/* Collect global ports from the circuit library:
* TODO: should we place this in the OpenFPGA context?
*/
std::vector<CircuitPortId> global_ports = find_circuit_library_global_ports(circuit_lib);
std::vector<CircuitPortId> global_ports = find_circuit_library_global_ports(circuit_lib);
/* Generate wrapper module for FPGA fabric (mapped by the input benchmark and pre-configured testbench for verification */
if (true == options.print_formal_verification_top_netlist()) {
std::string formal_verification_top_netlist_file_path = src_dir_path + netlist_name
+ std::string(FORMAL_VERIFICATION_VERILOG_FILE_POSTFIX);
print_verilog_preconfig_top_module(module_manager, bitstream_manager,
circuit_lib, global_ports,
atom_ctx, place_ctx, io_location_map,
netlist_annotation,
netlist_name,
formal_verification_top_netlist_file_path,
options.explicit_port_mapping());
}
/* Generate wrapper module for FPGA fabric (mapped by the input benchmark and pre-configured testbench for verification */
if (true == options.print_formal_verification_top_netlist())
{
std::string formal_verification_top_netlist_file_path = src_dir_path + netlist_name + std::string(FORMAL_VERIFICATION_VERILOG_FILE_POSTFIX);
print_verilog_preconfig_top_module(module_manager, bitstream_manager,
circuit_lib, global_ports,
atom_ctx, place_ctx, io_location_map,
netlist_annotation,
netlist_name,
formal_verification_top_netlist_file_path,
options.explicit_port_mapping());
}
if (true == options.print_preconfig_top_testbench()) {
/* Generate top-level testbench using random vectors */
std::string random_top_testbench_file_path = src_dir_path + netlist_name
+ std::string(RANDOM_TOP_TESTBENCH_VERILOG_FILE_POSTFIX);
print_verilog_random_top_testbench(netlist_name,
random_top_testbench_file_path,
atom_ctx,
netlist_annotation,
simulation_setting,
options.explicit_port_mapping());
}
if (true == options.print_preconfig_top_testbench())
{
/* Generate top-level testbench using random vectors */
std::string random_top_testbench_file_path = src_dir_path + netlist_name + std::string(RANDOM_TOP_TESTBENCH_VERILOG_FILE_POSTFIX);
print_verilog_random_top_testbench(netlist_name,
random_top_testbench_file_path,
atom_ctx,
netlist_annotation,
simulation_setting,
options.explicit_port_mapping());
}
/* Generate full testbench for verification, including configuration phase and operating phase */
if (true == options.print_top_testbench()) {
std::string top_testbench_file_path = src_dir_path + netlist_name
+ std::string(AUTOCHECK_TOP_TESTBENCH_VERILOG_FILE_POSTFIX);
print_verilog_top_testbench(module_manager,
bitstream_manager, fabric_bitstream,
config_protocol_type,
circuit_lib, global_ports,
atom_ctx, place_ctx, io_location_map,
netlist_annotation,
netlist_name,
top_testbench_file_path,
simulation_setting,
options.fast_configuration(),
options.explicit_port_mapping());
}
/* Generate exchangeable files which contains simulation settings */
if (true == options.print_simulation_ini()) {
std::string simulation_ini_file_name = options.simulation_ini_path();
VTR_ASSERT(true != options.simulation_ini_path().empty());
print_verilog_simulation_info(simulation_ini_file_name,
/* Generate full testbench for verification, including configuration phase and operating phase */
if (true == options.print_top_testbench())
{
std::string top_testbench_file_path = src_dir_path + netlist_name + std::string(AUTOCHECK_TOP_TESTBENCH_VERILOG_FILE_POSTFIX);
print_verilog_top_testbench(module_manager,
bitstream_manager, fabric_bitstream,
config_protocol_type,
circuit_lib, global_ports,
atom_ctx, place_ctx, io_location_map,
netlist_annotation,
netlist_name,
src_dir_path,
bitstream_manager.bits().size(),
simulation_setting.num_clock_cycles(),
simulation_setting.programming_clock_frequency(),
simulation_setting.operating_clock_frequency());
top_testbench_file_path,
simulation_setting,
options.fast_configuration(),
options.explicit_port_mapping());
}
/* Generate exchangeable files which contains simulation settings */
if (true == options.print_simulation_ini())
{
std::string simulation_ini_file_name = options.simulation_ini_path();
VTR_ASSERT(true != options.simulation_ini_path().empty());
print_verilog_simulation_info(simulation_ini_file_name,
netlist_name,
src_dir_path,
bitstream_manager.bits().size(),
simulation_setting.num_clock_cycles(),
simulation_setting.programming_clock_frequency(),
simulation_setting.operating_clock_frequency());
}
/* Generate a Verilog file including all the netlists that have been generated */
print_include_netlists(src_dir_path,
netlist_name,
options.reference_benchmark_file_path());
}
/* Generate a Verilog file including all the netlists that have been generated */
print_include_netlists(src_dir_path,
netlist_name,
options.reference_benchmark_file_path());
}
} /* end namespace openfpga */

View File

@ -1,6 +1,6 @@
/********************************************************************
* This file includes functions that are used to generate
* a Verilog module of a pre-configured FPGA fabric
* This file includes functions that are used to generate
* a Verilog module of a pre-configured FPGA fabric
*******************************************************************/
#include <fstream>
@ -24,106 +24,111 @@
#include "verilog_preconfig_top_module.h"
/* begin namespace openfpga */
namespace openfpga {
namespace openfpga
{
/********************************************************************
/********************************************************************
* Print module declaration and ports for the pre-configured
* FPGA top module
* The module ports do exactly match the input benchmark
* The module ports do exactly match the input benchmark
*******************************************************************/
static
void print_verilog_preconfig_top_module_ports(std::fstream& fp,
const std::string& circuit_name,
const AtomContext& atom_ctx,
const VprNetlistAnnotation& netlist_annotation) {
static void print_verilog_preconfig_top_module_ports(std::fstream &fp,
const std::string &circuit_name,
const AtomContext &atom_ctx,
const VprNetlistAnnotation &netlist_annotation)
{
/* Validate the file stream */
valid_file_stream(fp);
/* Validate the file stream */
valid_file_stream(fp);
/* Module declaration */
fp << "module " << circuit_name << std::string(FORMAL_VERIFICATION_TOP_MODULE_POSTFIX);
fp << " (" << std::endl;
/* Add module ports */
size_t port_counter = 0;
/* Module declaration */
fp << "module " << circuit_name << std::string(FORMAL_VERIFICATION_TOP_MODULE_POSTFIX);
fp << " (" << std::endl;
/* Port type-to-type mapping */
std::map<AtomBlockType, enum e_dump_verilog_port_type> port_type2type_map;
port_type2type_map[AtomBlockType::INPAD] = VERILOG_PORT_INPUT;
port_type2type_map[AtomBlockType::OUTPAD] = VERILOG_PORT_OUTPUT;
/* Print all the I/Os of the circuit implementation to be tested*/
for (const AtomBlockId& atom_blk : atom_ctx.nlist.blocks()) {
/* We only care I/O logical blocks !*/
if ( (AtomBlockType::INPAD != atom_ctx.nlist.block_type(atom_blk))
&& (AtomBlockType::OUTPAD != atom_ctx.nlist.block_type(atom_blk)) ) {
continue;
/* Add module ports */
size_t port_counter = 0;
/* Port type-to-type mapping */
std::map<AtomBlockType, enum e_dump_verilog_port_type> port_type2type_map;
port_type2type_map[AtomBlockType::INPAD] = VERILOG_PORT_INPUT;
port_type2type_map[AtomBlockType::OUTPAD] = VERILOG_PORT_OUTPUT;
/* Print all the I/Os of the circuit implementation to be tested*/
for (const AtomBlockId &atom_blk : atom_ctx.nlist.blocks())
{
/* We only care I/O logical blocks !*/
if ((AtomBlockType::INPAD != atom_ctx.nlist.block_type(atom_blk)) && (AtomBlockType::OUTPAD != atom_ctx.nlist.block_type(atom_blk)))
{
continue;
}
/* The block may be renamed as it contains special characters which violate Verilog syntax */
std::string block_name = atom_ctx.nlist.block_name(atom_blk);
if (true == netlist_annotation.is_block_renamed(atom_blk))
{
block_name = netlist_annotation.block_name(atom_blk);
}
if (0 < port_counter)
{
fp << "," << std::endl;
}
/* Both input and output ports have only size of 1 */
BasicPort module_port(std::string(block_name + std::string(FORMAL_VERIFICATION_TOP_MODULE_PORT_POSTFIX)), 1);
fp << generate_verilog_port(port_type2type_map[atom_ctx.nlist.block_type(atom_blk)], module_port);
/* Update port counter */
port_counter++;
}
/* The block may be renamed as it contains special characters which violate Verilog syntax */
std::string block_name = atom_ctx.nlist.block_name(atom_blk);
if (true == netlist_annotation.is_block_renamed(atom_blk)) {
block_name = netlist_annotation.block_name(atom_blk);
}
fp << ");" << std::endl;
if (0 < port_counter) {
fp << "," << std::endl;
}
/* Both input and output ports have only size of 1 */
BasicPort module_port(std::string(block_name + std::string(FORMAL_VERIFICATION_TOP_MODULE_PORT_POSTFIX)), 1);
fp << generate_verilog_port(port_type2type_map[atom_ctx.nlist.block_type(atom_blk)], module_port);
/* Update port counter */
port_counter++;
/* Add an empty line as a splitter */
fp << std::endl;
}
fp << ");" << std::endl;
/* Add an empty line as a splitter */
fp << std::endl;
}
/********************************************************************
/********************************************************************
* Print internal wires for the pre-configured FPGA top module
* The internal wires are tailored for the ports of FPGA top module
* which will be different in various configuration protocols
*******************************************************************/
static
void print_verilog_preconfig_top_module_internal_wires(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& top_module) {
/* Validate the file stream */
valid_file_stream(fp);
static void print_verilog_preconfig_top_module_internal_wires(std::fstream &fp,
const ModuleManager &module_manager,
const ModuleId &top_module)
{
/* Validate the file stream */
valid_file_stream(fp);
/* Global ports of top-level module */
print_verilog_comment(fp, std::string("----- Local wires for FPGA fabric -----"));
for (const ModulePortId& module_port_id : module_manager.module_ports(top_module)) {
BasicPort module_port = module_manager.module_port(top_module, module_port_id);
fp << generate_verilog_port(VERILOG_PORT_WIRE, module_port) << ";" << std::endl;
/* Global ports of top-level module */
print_verilog_comment(fp, std::string("----- Local wires for FPGA fabric -----"));
for (const ModulePortId &module_port_id : module_manager.module_ports(top_module))
{
BasicPort module_port = module_manager.module_port(top_module, module_port_id);
fp << generate_verilog_port(VERILOG_PORT_WIRE, module_port) << ";" << std::endl;
}
/* Add an empty line as a splitter */
fp << std::endl;
}
/* Add an empty line as a splitter */
fp << std::endl;
}
/********************************************************************
/********************************************************************
* Connect global ports of FPGA top module to constants except:
* 1. operating clock, which should be wired to the clock port of
* 1. operating clock, which should be wired to the clock port of
* this pre-configured FPGA top module
*******************************************************************/
static
void print_verilog_preconfig_top_module_connect_global_ports(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& top_module,
const CircuitLibrary& circuit_lib,
const std::vector<CircuitPortId>& global_ports,
const std::vector<std::string>& benchmark_clock_port_names) {
/* Validate the file stream */
valid_file_stream(fp);
static void print_verilog_preconfig_top_module_connect_global_ports(std::fstream &fp,
const ModuleManager &module_manager,
const ModuleId &top_module,
const CircuitLibrary &circuit_lib,
const std::vector<CircuitPortId> &global_ports,
const std::vector<std::string> &benchmark_clock_port_names)
{
/* Validate the file stream */
valid_file_stream(fp);
print_verilog_comment(fp, std::string("----- Begin Connect Global ports of FPGA top module -----"));
print_verilog_comment(fp, std::string("----- Begin Connect Global ports of FPGA top module -----"));
/* Global ports of the top module in module manager do not carry any attributes,
* such as is_clock, is_set, etc.
/* Global ports of the top module in module manager do not carry any attributes,
* such as is_clock, is_set, etc.
* Therefore, for each global port in the top module, we find the circuit port in the circuit library
* which share the same name. We can access to the attributes.
* To gurantee the correct link between global ports in module manager and those in circuit library
@ -131,221 +136,238 @@ void print_verilog_preconfig_top_module_connect_global_ports(std::fstream& fp,
* where we guarantee all the global ports share the same name must have the same attributes.
* So that each global port with the same name is unique!
*/
for (const BasicPort& module_global_port : module_manager.module_ports_by_type(top_module, ModuleManager::MODULE_GLOBAL_PORT)) {
CircuitPortId linked_circuit_port_id = CircuitPortId::INVALID();
/* Find the circuit port with the same name */
for (const CircuitPortId& circuit_port_id : global_ports) {
if (0 != module_global_port.get_name().compare(circuit_lib.port_prefix(circuit_port_id))) {
for (const BasicPort &module_global_port : module_manager.module_ports_by_type(top_module, ModuleManager::MODULE_GLOBAL_PORT))
{
CircuitPortId linked_circuit_port_id = CircuitPortId::INVALID();
/* Find the circuit port with the same name */
for (const CircuitPortId &circuit_port_id : global_ports)
{
if (0 != module_global_port.get_name().compare(circuit_lib.port_prefix(circuit_port_id)))
{
continue;
}
linked_circuit_port_id = circuit_port_id;
break;
}
/* Must find one valid circuit port */
VTR_ASSERT(CircuitPortId::INVALID() != linked_circuit_port_id);
/* Port size should match! */
VTR_ASSERT(module_global_port.get_width() == circuit_lib.port_size(linked_circuit_port_id));
/* Now, for operating clock port, we should wire it to the clock of benchmark! */
if ((CIRCUIT_MODEL_PORT_CLOCK == circuit_lib.port_type(linked_circuit_port_id)) && (false == circuit_lib.port_is_prog(linked_circuit_port_id)))
{
/* Wiring to each pin of the global port: benchmark clock is always 1-bit */
for (const size_t &pin : module_global_port.pins())
{
for (const std::string &clock_port_name : benchmark_clock_port_names)
{
BasicPort module_clock_pin(module_global_port.get_name(), pin, pin);
BasicPort benchmark_clock_pin(clock_port_name + std::string(FORMAL_VERIFICATION_TOP_MODULE_PORT_POSTFIX), 1);
print_verilog_wire_connection(fp, module_clock_pin, benchmark_clock_pin, false);
}
}
/* Finish, go to the next */
continue;
}
linked_circuit_port_id = circuit_port_id;
break;
}
/* Must find one valid circuit port */
VTR_ASSERT(CircuitPortId::INVALID() != linked_circuit_port_id);
/* Port size should match! */
VTR_ASSERT(module_global_port.get_width() == circuit_lib.port_size(linked_circuit_port_id));
/* Now, for operating clock port, we should wire it to the clock of benchmark! */
if ( (CIRCUIT_MODEL_PORT_CLOCK == circuit_lib.port_type(linked_circuit_port_id))
&& (false == circuit_lib.port_is_prog(linked_circuit_port_id)) ) {
/* Wiring to each pin of the global port: benchmark clock is always 1-bit */
for (const size_t& pin : module_global_port.pins()) {
for (const std::string& clock_port_name : benchmark_clock_port_names) {
BasicPort module_clock_pin(module_global_port.get_name(), pin, pin);
BasicPort benchmark_clock_pin(clock_port_name + std::string(FORMAL_VERIFICATION_TOP_MODULE_PORT_POSTFIX), 1);
print_verilog_wire_connection(fp, module_clock_pin, benchmark_clock_pin, false);
}
}
/* Finish, go to the next */
continue;
}
/* For other ports, give an default value */
std::vector<size_t> default_values(module_global_port.get_width(), circuit_lib.port_default_value(linked_circuit_port_id));
print_verilog_wire_constant_values(fp, module_global_port, default_values);
/* For other ports, give an default value */
std::vector<size_t> default_values(module_global_port.get_width(), circuit_lib.port_default_value(linked_circuit_port_id));
print_verilog_wire_constant_values(fp, module_global_port, default_values);
}
print_verilog_comment(fp, std::string("----- End Connect Global ports of FPGA top module -----"));
/* Add an empty line as a splitter */
fp << std::endl;
}
print_verilog_comment(fp, std::string("----- End Connect Global ports of FPGA top module -----"));
/* Add an empty line as a splitter */
fp << std::endl;
}
/********************************************************************
/********************************************************************
* Impose the bitstream on the configuration memories
* This function uses 'assign' syntax to impost the bitstream at mem port
* while uses 'force' syntax to impost the bitstream at mem_inv port
*******************************************************************/
static
void print_verilog_preconfig_top_module_assign_bitstream(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& top_module,
const BitstreamManager& bitstream_manager) {
/* Validate the file stream */
valid_file_stream(fp);
static void print_verilog_preconfig_top_module_assign_bitstream(std::fstream &fp,
const ModuleManager &module_manager,
const ModuleId &top_module,
const BitstreamManager &bitstream_manager)
{
/* Validate the file stream */
valid_file_stream(fp);
print_verilog_comment(fp, std::string("----- Begin assign bitstream to configuration memories -----"));
print_verilog_comment(fp, std::string("----- Begin assign bitstream to configuration memories -----"));
for (const ConfigBlockId& config_block_id : bitstream_manager.blocks()) {
/* We only cares blocks with configuration bits */
if (0 == bitstream_manager.block_bits(config_block_id).size()) {
continue;
}
/* Build the hierarchical path of the configuration bit in modules */
std::vector<ConfigBlockId> block_hierarchy = find_bitstream_manager_block_hierarchy(bitstream_manager, config_block_id);
/* Drop the first block, which is the top module, it should be replaced by the instance name here */
/* Ensure that this is the module we want to drop! */
VTR_ASSERT(0 == module_manager.module_name(top_module).compare(bitstream_manager.block_name(block_hierarchy[0])));
block_hierarchy.erase(block_hierarchy.begin());
/* Build the full hierarchy path */
std::string bit_hierarchy_path(FORMAL_VERIFICATION_TOP_MODULE_UUT_NAME);
for (const ConfigBlockId& temp_block : block_hierarchy) {
for (const ConfigBlockId &config_block_id : bitstream_manager.blocks())
{
/* We only cares blocks with configuration bits */
if (0 == bitstream_manager.block_bits(config_block_id).size())
{
continue;
}
/* Build the hierarchical path of the configuration bit in modules */
std::vector<ConfigBlockId> block_hierarchy = find_bitstream_manager_block_hierarchy(bitstream_manager, config_block_id);
/* Drop the first block, which is the top module, it should be replaced by the instance name here */
/* Ensure that this is the module we want to drop! */
VTR_ASSERT(0 == module_manager.module_name(top_module).compare(bitstream_manager.block_name(block_hierarchy[0])));
block_hierarchy.erase(block_hierarchy.begin());
/* Build the full hierarchy path */
std::string bit_hierarchy_path(FORMAL_VERIFICATION_TOP_MODULE_UUT_NAME);
for (const ConfigBlockId &temp_block : block_hierarchy)
{
bit_hierarchy_path += std::string(".");
bit_hierarchy_path += bitstream_manager.block_name(temp_block);
}
bit_hierarchy_path += std::string(".");
bit_hierarchy_path += bitstream_manager.block_name(temp_block);
}
bit_hierarchy_path += std::string(".");
/* Find the bit index in the parent block */
BasicPort config_data_port(bit_hierarchy_path + generate_configurable_memory_data_out_name(),
bitstream_manager.block_bits(config_block_id).size());
/* Find the bit index in the parent block */
BasicPort config_data_port(bit_hierarchy_path + generate_configurable_memory_data_out_name(),
bitstream_manager.block_bits(config_block_id).size());
/* Wire it to the configuration bit: access both data out and data outb ports */
std::vector<size_t> config_data_values;
for (const ConfigBitId config_bit : bitstream_manager.block_bits(config_block_id)) {
config_data_values.push_back(bitstream_manager.bit_value(config_bit));
/* Wire it to the configuration bit: access both data out and data outb ports */
std::vector<size_t> config_data_values;
for (const ConfigBitId config_bit : bitstream_manager.block_bits(config_block_id))
{
config_data_values.push_back(bitstream_manager.bit_value(config_bit));
}
print_verilog_wire_constant_values(fp, config_data_port, config_data_values);
}
print_verilog_wire_constant_values(fp, config_data_port, config_data_values);
fp << "initial begin" << std::endl;
for (const ConfigBlockId &config_block_id : bitstream_manager.blocks())
{
/* We only cares blocks with configuration bits */
if (0 == bitstream_manager.block_bits(config_block_id).size())
{
continue;
}
/* Build the hierarchical path of the configuration bit in modules */
std::vector<ConfigBlockId> block_hierarchy = find_bitstream_manager_block_hierarchy(bitstream_manager, config_block_id);
/* Drop the first block, which is the top module, it should be replaced by the instance name here */
/* Ensure that this is the module we want to drop! */
VTR_ASSERT(0 == module_manager.module_name(top_module).compare(bitstream_manager.block_name(block_hierarchy[0])));
block_hierarchy.erase(block_hierarchy.begin());
/* Build the full hierarchy path */
std::string bit_hierarchy_path(FORMAL_VERIFICATION_TOP_MODULE_UUT_NAME);
for (const ConfigBlockId &temp_block : block_hierarchy)
{
bit_hierarchy_path += std::string(".");
bit_hierarchy_path += bitstream_manager.block_name(temp_block);
}
bit_hierarchy_path += std::string(".");
/* Find the bit index in the parent block */
BasicPort config_datab_port(bit_hierarchy_path + generate_configurable_memory_inverted_data_out_name(),
bitstream_manager.block_bits(config_block_id).size());
std::vector<size_t> config_datab_values;
for (const ConfigBitId config_bit : bitstream_manager.block_bits(config_block_id))
{
config_datab_values.push_back(!bitstream_manager.bit_value(config_bit));
}
print_verilog_force_wire_constant_values(fp, config_datab_port, config_datab_values);
}
fp << "end" << std::endl;
print_verilog_comment(fp, std::string("----- End assign bitstream to configuration memories -----"));
}
fp << "initial begin" << std::endl;
for (const ConfigBlockId& config_block_id : bitstream_manager.blocks()) {
/* We only cares blocks with configuration bits */
if (0 == bitstream_manager.block_bits(config_block_id).size()) {
continue;
}
/* Build the hierarchical path of the configuration bit in modules */
std::vector<ConfigBlockId> block_hierarchy = find_bitstream_manager_block_hierarchy(bitstream_manager, config_block_id);
/* Drop the first block, which is the top module, it should be replaced by the instance name here */
/* Ensure that this is the module we want to drop! */
VTR_ASSERT(0 == module_manager.module_name(top_module).compare(bitstream_manager.block_name(block_hierarchy[0])));
block_hierarchy.erase(block_hierarchy.begin());
/* Build the full hierarchy path */
std::string bit_hierarchy_path(FORMAL_VERIFICATION_TOP_MODULE_UUT_NAME);
for (const ConfigBlockId& temp_block : block_hierarchy) {
bit_hierarchy_path += std::string(".");
bit_hierarchy_path += bitstream_manager.block_name(temp_block);
}
bit_hierarchy_path += std::string(".");
/* Find the bit index in the parent block */
BasicPort config_datab_port(bit_hierarchy_path + generate_configurable_memory_inverted_data_out_name(),
bitstream_manager.block_bits(config_block_id).size());
std::vector<size_t> config_datab_values;
for (const ConfigBitId config_bit : bitstream_manager.block_bits(config_block_id)) {
config_datab_values.push_back(!bitstream_manager.bit_value(config_bit));
}
print_verilog_force_wire_constant_values(fp, config_datab_port, config_datab_values);
}
fp << "end" << std::endl;
print_verilog_comment(fp, std::string("----- End assign bitstream to configuration memories -----"));
}
/********************************************************************
/********************************************************************
* Impose the bitstream on the configuration memories
* This function uses '$deposit' syntax to do so
*******************************************************************/
static
void print_verilog_preconfig_top_module_deposit_bitstream(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& top_module,
const BitstreamManager& bitstream_manager) {
/* Validate the file stream */
valid_file_stream(fp);
static void print_verilog_preconfig_top_module_deposit_bitstream(std::fstream &fp,
const ModuleManager &module_manager,
const ModuleId &top_module,
const BitstreamManager &bitstream_manager)
{
/* Validate the file stream */
valid_file_stream(fp);
print_verilog_comment(fp, std::string("----- Begin deposit bitstream to configuration memories -----"));
fp << "initial begin" << std::endl;
print_verilog_comment(fp, std::string("----- Begin deposit bitstream to configuration memories -----"));
for (const ConfigBlockId& config_block_id : bitstream_manager.blocks()) {
/* We only cares blocks with configuration bits */
if (0 == bitstream_manager.block_bits(config_block_id).size()) {
continue;
}
/* Build the hierarchical path of the configuration bit in modules */
std::vector<ConfigBlockId> block_hierarchy = find_bitstream_manager_block_hierarchy(bitstream_manager, config_block_id);
/* Drop the first block, which is the top module, it should be replaced by the instance name here */
/* Ensure that this is the module we want to drop! */
VTR_ASSERT(0 == module_manager.module_name(top_module).compare(bitstream_manager.block_name(block_hierarchy[0])));
block_hierarchy.erase(block_hierarchy.begin());
/* Build the full hierarchy path */
std::string bit_hierarchy_path(FORMAL_VERIFICATION_TOP_MODULE_UUT_NAME);
for (const ConfigBlockId& temp_block : block_hierarchy) {
fp << "initial begin" << std::endl;
for (const ConfigBlockId &config_block_id : bitstream_manager.blocks())
{
/* We only cares blocks with configuration bits */
if (0 == bitstream_manager.block_bits(config_block_id).size())
{
continue;
}
/* Build the hierarchical path of the configuration bit in modules */
std::vector<ConfigBlockId> block_hierarchy = find_bitstream_manager_block_hierarchy(bitstream_manager, config_block_id);
/* Drop the first block, which is the top module, it should be replaced by the instance name here */
/* Ensure that this is the module we want to drop! */
VTR_ASSERT(0 == module_manager.module_name(top_module).compare(bitstream_manager.block_name(block_hierarchy[0])));
block_hierarchy.erase(block_hierarchy.begin());
/* Build the full hierarchy path */
std::string bit_hierarchy_path(FORMAL_VERIFICATION_TOP_MODULE_UUT_NAME);
for (const ConfigBlockId &temp_block : block_hierarchy)
{
bit_hierarchy_path += std::string(".");
bit_hierarchy_path += bitstream_manager.block_name(temp_block);
}
bit_hierarchy_path += std::string(".");
bit_hierarchy_path += bitstream_manager.block_name(temp_block);
/* Find the bit index in the parent block */
BasicPort config_data_port(bit_hierarchy_path + generate_configurable_memory_data_out_name(),
bitstream_manager.block_bits(config_block_id).size());
BasicPort config_datab_port(bit_hierarchy_path + generate_configurable_memory_inverted_data_out_name(),
bitstream_manager.block_bits(config_block_id).size());
/* Wire it to the configuration bit: access both data out and data outb ports */
std::vector<size_t> config_data_values;
for (const ConfigBitId config_bit : bitstream_manager.block_bits(config_block_id))
{
config_data_values.push_back(bitstream_manager.bit_value(config_bit));
}
print_verilog_deposit_wire_constant_values(fp, config_data_port, config_data_values);
std::vector<size_t> config_datab_values;
for (const ConfigBitId config_bit : bitstream_manager.block_bits(config_block_id))
{
config_datab_values.push_back(!bitstream_manager.bit_value(config_bit));
}
print_verilog_deposit_wire_constant_values(fp, config_datab_port, config_datab_values);
}
bit_hierarchy_path += std::string(".");
/* Find the bit index in the parent block */
BasicPort config_data_port(bit_hierarchy_path + generate_configurable_memory_data_out_name(),
bitstream_manager.block_bits(config_block_id).size());
fp << "end" << std::endl;
BasicPort config_datab_port(bit_hierarchy_path + generate_configurable_memory_inverted_data_out_name(),
bitstream_manager.block_bits(config_block_id).size());
/* Wire it to the configuration bit: access both data out and data outb ports */
std::vector<size_t> config_data_values;
for (const ConfigBitId config_bit : bitstream_manager.block_bits(config_block_id)) {
config_data_values.push_back(bitstream_manager.bit_value(config_bit));
}
print_verilog_deposit_wire_constant_values(fp, config_data_port, config_data_values);
std::vector<size_t> config_datab_values;
for (const ConfigBitId config_bit : bitstream_manager.block_bits(config_block_id)) {
config_datab_values.push_back(!bitstream_manager.bit_value(config_bit));
}
print_verilog_deposit_wire_constant_values(fp, config_datab_port, config_datab_values);
print_verilog_comment(fp, std::string("----- End deposit bitstream to configuration memories -----"));
}
fp << "end" << std::endl;
print_verilog_comment(fp, std::string("----- End deposit bitstream to configuration memories -----"));
}
/********************************************************************
/********************************************************************
* Impose the bitstream on the configuration memories
* We branch here for different simulators:
* 1. iVerilog Icarus prefers using 'assign' syntax to force the values
* 2. Mentor Modelsim prefers using '$deposit' syntax to do so
*******************************************************************/
static
void print_verilog_preconfig_top_module_load_bitstream(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& top_module,
const BitstreamManager& bitstream_manager) {
print_verilog_comment(fp, std::string("----- Begin load bitstream to configuration memories -----"));
print_verilog_preprocessing_flag(fp, std::string(ICARUS_SIMULATOR_FLAG));
static void print_verilog_preconfig_top_module_load_bitstream(std::fstream &fp,
const ModuleManager &module_manager,
const ModuleId &top_module,
const BitstreamManager &bitstream_manager)
{
print_verilog_comment(fp, std::string("----- Begin load bitstream to configuration memories -----"));
/* Use assign syntax for Icarus simulator */
print_verilog_preconfig_top_module_assign_bitstream(fp, module_manager, top_module, bitstream_manager);
print_verilog_preprocessing_flag(fp, std::string(ICARUS_SIMULATOR_FLAG));
fp << "`else" << std::endl;
/* Use assign syntax for Icarus simulator */
print_verilog_preconfig_top_module_assign_bitstream(fp, module_manager, top_module, bitstream_manager);
/* Use assign syntax for Icarus simulator */
print_verilog_preconfig_top_module_deposit_bitstream(fp, module_manager, top_module, bitstream_manager);
fp << "`else" << std::endl;
print_verilog_endif(fp);
/* Use assign syntax for Icarus simulator */
print_verilog_preconfig_top_module_deposit_bitstream(fp, module_manager, top_module, bitstream_manager);
print_verilog_comment(fp, std::string("----- End load bitstream to configuration memories -----"));
}
print_verilog_endif(fp);
print_verilog_comment(fp, std::string("----- End load bitstream to configuration memories -----"));
}
/********************************************************************
* Top-level function to generate a Verilog module of
/********************************************************************
* Top-level function to generate a Verilog module of
* a pre-configured FPGA fabric.
*
* Pre-configured FPGA fabric
@ -370,79 +392,80 @@ void print_verilog_preconfig_top_module_load_bitstream(std::fstream& fp,
* +-------------------------------------------
*
* Note: we do NOT put this module in the module manager.
* Because, it is not a standard module, where we force configuration signals
* This module is a wrapper for the FPGA fabric to be compatible in
* Because, it is not a standard module, where we force configuration signals
* This module is a wrapper for the FPGA fabric to be compatible in
* the port map of input benchmark.
* It includes wires to force constant values to part of FPGA datapath I/Os
* All these are hard to implement as a module in module manager
*******************************************************************/
void print_verilog_preconfig_top_module(const ModuleManager& module_manager,
const BitstreamManager& bitstream_manager,
const CircuitLibrary& circuit_lib,
const std::vector<CircuitPortId>& global_ports,
const AtomContext& atom_ctx,
const PlacementContext& place_ctx,
const IoLocationMap& io_location_map,
const VprNetlistAnnotation& netlist_annotation,
const std::string& circuit_name,
const std::string& verilog_fname,
const bool& explicit_port_mapping) {
std::string timer_message = std::string("Write pre-configured FPGA top-level Verilog netlist for design '") + circuit_name + std::string("'");
void print_verilog_preconfig_top_module(const ModuleManager &module_manager,
const BitstreamManager &bitstream_manager,
const CircuitLibrary &circuit_lib,
const std::vector<CircuitPortId> &global_ports,
const AtomContext &atom_ctx,
const PlacementContext &place_ctx,
const IoLocationMap &io_location_map,
const VprNetlistAnnotation &netlist_annotation,
const std::string &circuit_name,
const std::string &verilog_fname,
const bool &explicit_port_mapping)
{
std::string timer_message = std::string("Write pre-configured FPGA top-level Verilog netlist for design '") + circuit_name + std::string("'");
/* Start time count */
vtr::ScopedStartFinishTimer timer(timer_message);
/* Start time count */
vtr::ScopedStartFinishTimer timer(timer_message);
/* Create the file stream */
std::fstream fp;
fp.open(verilog_fname, std::fstream::out | std::fstream::trunc);
/* Create the file stream */
std::fstream fp;
fp.open(verilog_fname, std::fstream::out | std::fstream::trunc);
/* Validate the file stream */
check_file_stream(verilog_fname.c_str(), fp);
/* Validate the file stream */
check_file_stream(verilog_fname.c_str(), fp);
/* Generate a brief description on the Verilog file*/
std::string title = std::string("Verilog netlist for pre-configured FPGA fabric by design: ") + circuit_name;
print_verilog_file_header(fp, title);
/* Generate a brief description on the Verilog file*/
std::string title = std::string("Verilog netlist for pre-configured FPGA fabric by design: ") + circuit_name;
print_verilog_file_header(fp, title);
/* Print module declaration and ports */
print_verilog_preconfig_top_module_ports(fp, circuit_name, atom_ctx, netlist_annotation);
/* Print module declaration and ports */
print_verilog_preconfig_top_module_ports(fp, circuit_name, atom_ctx, netlist_annotation);
/* Find the top_module */
ModuleId top_module = module_manager.find_module(generate_fpga_top_module_name());
VTR_ASSERT(true == module_manager.valid_module_id(top_module));
/* Find the top_module */
ModuleId top_module = module_manager.find_module(generate_fpga_top_module_name());
VTR_ASSERT(true == module_manager.valid_module_id(top_module));
/* Print internal wires */
print_verilog_preconfig_top_module_internal_wires(fp, module_manager, top_module);
/* Print internal wires */
print_verilog_preconfig_top_module_internal_wires(fp, module_manager, top_module);
/* Instanciate FPGA top-level module */
print_verilog_testbench_fpga_instance(fp, module_manager, top_module,
std::string(FORMAL_VERIFICATION_TOP_MODULE_UUT_NAME),
explicit_port_mapping);
/* Instanciate FPGA top-level module */
print_verilog_testbench_fpga_instance(fp, module_manager, top_module,
std::string(FORMAL_VERIFICATION_TOP_MODULE_UUT_NAME),
explicit_port_mapping);
/* Find clock ports in benchmark */
std::vector<std::string> benchmark_clock_port_names = find_atom_netlist_clock_port_names(atom_ctx.nlist, netlist_annotation);
/* Find clock ports in benchmark */
std::vector<std::string> benchmark_clock_port_names = find_atom_netlist_clock_port_names(atom_ctx.nlist, netlist_annotation);
/* Connect FPGA top module global ports to constant or benchmark global signals! */
print_verilog_preconfig_top_module_connect_global_ports(fp, module_manager, top_module,
circuit_lib, global_ports,
benchmark_clock_port_names);
/* Connect FPGA top module global ports to constant or benchmark global signals! */
print_verilog_preconfig_top_module_connect_global_ports(fp, module_manager, top_module,
circuit_lib, global_ports,
benchmark_clock_port_names);
/* Connect I/Os to benchmark I/Os or constant driver */
print_verilog_testbench_connect_fpga_ios(fp, module_manager, top_module,
atom_ctx, place_ctx, io_location_map,
netlist_annotation,
std::string(FORMAL_VERIFICATION_TOP_MODULE_PORT_POSTFIX),
std::string(FORMAL_VERIFICATION_TOP_MODULE_PORT_POSTFIX),
(size_t)VERILOG_DEFAULT_SIGNAL_INIT_VALUE);
/* Connect I/Os to benchmark I/Os or constant driver */
print_verilog_testbench_connect_fpga_ios(fp, module_manager, top_module,
atom_ctx, place_ctx, io_location_map,
netlist_annotation,
std::string(FORMAL_VERIFICATION_TOP_MODULE_PORT_POSTFIX),
std::string(FORMAL_VERIFICATION_TOP_MODULE_PORT_POSTFIX),
(size_t)VERILOG_DEFAULT_SIGNAL_INIT_VALUE);
/* Assign FPGA internal SRAM/Memory ports to bitstream values */
print_verilog_preconfig_top_module_load_bitstream(fp, module_manager, top_module,
bitstream_manager);
/* Assign FPGA internal SRAM/Memory ports to bitstream values */
print_verilog_preconfig_top_module_load_bitstream(fp, module_manager, top_module,
bitstream_manager);
/* Testbench ends*/
print_verilog_module_end(fp, std::string(circuit_name) + std::string(FORMAL_VERIFICATION_TOP_MODULE_POSTFIX));
/* Testbench ends*/
print_verilog_module_end(fp, std::string(circuit_name) + std::string(FORMAL_VERIFICATION_TOP_MODULE_POSTFIX));
/* Close the file stream */
fp.close();
}
/* Close the file stream */
fp.close();
}
} /* end namespace openfpga */

View File

@ -6,12 +6,12 @@
*******************************************************************/
#include <vector>
#include <string>
#include "circuit_library.h"
#include "vpr_context.h"
#include "module_manager.h"
#include "bitstream_manager.h"
#include "io_location_map.h"
#include "vpr_netlist_annotation.h"
#include "circuit_library.h"
#include "vpr_context.h"
#include "module_manager.h"
#include "bitstream_manager.h"
#include "io_location_map.h"
#include "vpr_netlist_annotation.h"
/********************************************************************
* Function declaration
@ -27,7 +27,7 @@ void print_verilog_preconfig_top_module(const ModuleManager& module_manager,
const AtomContext& atom_ctx,
const PlacementContext& place_ctx,
const IoLocationMap& io_location_map,
const VprNetlistAnnotation& netlist_annotation,
const VprNetlistAnnotation& netlist_annotation,
const std::string& circuit_name,
const std::string& verilog_fname,
const bool& explicit_port_mapping);

View File

@ -63,7 +63,7 @@ constexpr char* AUTOCHECK_TOP_TESTBENCH_VERILOG_MODULE_POSTFIX = "_autocheck_top
/********************************************************************
* Print local wires for flatten memory (standalone) configuration protocols
*******************************************************************/
static
static
void print_verilog_top_testbench_flatten_memory_port(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& top_module) {
@ -87,7 +87,7 @@ void print_verilog_top_testbench_flatten_memory_port(std::fstream& fp,
/********************************************************************
* Print local wires for configuration chain protocols
*******************************************************************/
static
static
void print_verilog_top_testbench_config_chain_port(std::fstream& fp) {
/* Validate the file stream */
valid_file_stream(fp);
@ -106,7 +106,7 @@ void print_verilog_top_testbench_config_chain_port(std::fstream& fp) {
/********************************************************************
* Print local wires for memory bank configuration protocols
*******************************************************************/
static
static
void print_verilog_top_testbench_memory_bank_port(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& top_module) {
@ -151,7 +151,7 @@ void print_verilog_top_testbench_memory_bank_port(std::fstream& fp,
/********************************************************************
* Print local wires for frame-based decoder protocols
*******************************************************************/
static
static
void print_verilog_top_testbench_frame_decoder_port(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& top_module) {
@ -187,7 +187,7 @@ void print_verilog_top_testbench_frame_decoder_port(std::fstream& fp,
/********************************************************************
* Print local wires for different types of configuration protocols
*******************************************************************/
static
static
void print_verilog_top_testbench_config_protocol_port(std::fstream& fp,
const e_config_protocol_type& sram_orgz_type,
const ModuleManager& module_manager,
@ -215,7 +215,7 @@ void print_verilog_top_testbench_config_protocol_port(std::fstream& fp,
/********************************************************************
* Wire the global ports of FPGA fabric to local wires
*******************************************************************/
static
static
void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& top_module,
@ -232,9 +232,9 @@ void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp,
continue;
}
/* Reach here, it means we have a global clock to deal with:
* 1. if the port is identified as a programming clock,
* 1. if the port is identified as a programming clock,
* connect it to the local wire of programming clock
* 2. if the port is identified as an operating clock
* 2. if the port is identified as an operating clock
* connect it to the local wire of operating clock
*/
/* Find the module port */
@ -254,9 +254,9 @@ void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp,
* The wiring will be inverted if the default value of the global port is 1
* Otherwise, the wiring will not be inverted!
*/
print_verilog_wire_connection(fp, module_manager.module_port(top_module, module_global_port),
stimuli_clock_port,
1 == circuit_lib.port_default_value(model_global_port));
print_verilog_wire_connection(fp, module_manager.module_port(top_module, module_global_port),
stimuli_clock_port,
1 == circuit_lib.port_default_value(model_global_port));
}
/* Connect global configuration done ports to configuration done signal */
@ -278,9 +278,9 @@ void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp,
* The wiring will be inverted if the default value of the global port is 1
* Otherwise, the wiring will not be inverted!
*/
print_verilog_wire_connection(fp, module_manager.module_port(top_module, module_global_port),
stimuli_config_done_port,
1 == circuit_lib.port_default_value(model_global_port));
print_verilog_wire_connection(fp, module_manager.module_port(top_module, module_global_port),
stimuli_config_done_port,
1 == circuit_lib.port_default_value(model_global_port));
}
/* Connect global reset ports to operating or programming reset signal */
@ -315,9 +315,9 @@ void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp,
* The wiring will be inverted if the default value of the global port is 1
* Otherwise, the wiring will not be inverted!
*/
print_verilog_wire_connection(fp, module_manager.module_port(top_module, module_global_port),
stimuli_reset_port,
1 == circuit_lib.port_default_value(model_global_port));
print_verilog_wire_connection(fp, module_manager.module_port(top_module, module_global_port),
stimuli_reset_port,
1 == circuit_lib.port_default_value(model_global_port));
}
/* Connect global set ports to operating or programming set signal */
@ -357,9 +357,9 @@ void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp,
* The wiring will be inverted if the default value of the global port is 1
* Otherwise, the wiring will not be inverted!
*/
print_verilog_wire_connection(fp, module_manager.module_port(top_module, module_global_port),
stimuli_set_port,
1 == circuit_lib.port_default_value(model_global_port));
print_verilog_wire_connection(fp, module_manager.module_port(top_module, module_global_port),
stimuli_set_port,
1 == circuit_lib.port_default_value(model_global_port));
}
/* For the rest of global ports, wire them to constant signals */
@ -411,7 +411,7 @@ void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp,
}
/********************************************************************
* This function prints the top testbench module declaration
* This function prints the top testbench module declaration
* and internal wires/port declaration
* Ports can be classified in two categories:
* 1. General-purpose ports, which are datapath I/Os, clock signals
@ -423,11 +423,11 @@ void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp,
* (a) configuration-chain: we will have two ports,
* a head and a tail for the configuration chain,
* in addition to the regular ports.
* (b) memory-decoders: we will have a few ports to drive
* (b) memory-decoders: we will have a few ports to drive
* address lines for decoders and a bit input port to feed
* configuration bits
*******************************************************************/
static
static
void print_verilog_top_testbench_ports(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& top_module,
@ -477,7 +477,7 @@ void print_verilog_top_testbench_ports(std::fstream& fp,
/* Add local wires/registers that drive stimulus
* We create these general purpose ports here,
* and then wire them to the ports of FPGA fabric depending on their usage
* and then wire them to the ports of FPGA fabric depending on their usage
*/
/* Configuration done port */
BasicPort config_done_port(std::string(TOP_TB_CONFIG_DONE_PORT_NAME), 1);
@ -511,7 +511,7 @@ void print_verilog_top_testbench_ports(std::fstream& fp,
print_verilog_top_testbench_config_protocol_port(fp, sram_orgz_type,
module_manager, top_module);
/* Create a clock port if the benchmark have one but not in the default name!
/* Create a clock port if the benchmark have one but not in the default name!
* We will wire the clock directly to the operating clock directly
*/
for (const std::string clock_port_name : clock_port_names) {
@ -543,7 +543,7 @@ void print_verilog_top_testbench_ports(std::fstream& fp,
std::string(TOP_TESTBENCH_CHECKFLAG_PORT_POSTFIX),
std::string(AUTOCHECKED_SIMULATION_FLAG));
/* Instantiate an integer to count the number of error and
/* Instantiate an integer to count the number of error and
* determine if the simulation succeed or failed
*/
print_verilog_comment(fp, std::string("----- Error counter -----"));
@ -551,14 +551,14 @@ void print_verilog_top_testbench_ports(std::fstream& fp,
}
/********************************************************************
* Estimate the number of configuration clock cycles
* Estimate the number of configuration clock cycles
* by traversing the linked-list and count the number of SRAM=1 or BL=1&WL=1 in it.
* We plus 1 additional config clock cycle here because we need to reset everything during the first clock cycle
* If we consider fast configuration, the number of clock cycles will be
* If we consider fast configuration, the number of clock cycles will be
* the number of non-zero data points in the fabric bitstream
* Note that this will not applicable to configuration chain!!!
*******************************************************************/
static
static
size_t calculate_num_config_clock_cycles(const e_config_protocol_type& sram_orgz_type,
const bool& fast_configuration,
const FabricBitstream& fabric_bitstream) {
@ -567,7 +567,7 @@ size_t calculate_num_config_clock_cycles(const e_config_protocol_type& sram_orgz
/* Branch on the type of configuration protocol */
switch (sram_orgz_type) {
case CONFIG_MEM_STANDALONE:
/* We just need 1 clock cycle to load all the configuration bits
/* We just need 1 clock cycle to load all the configuration bits
* since all the ports are exposed at the top-level
*/
num_config_clock_cycles = 2;
@ -593,7 +593,7 @@ size_t calculate_num_config_clock_cycles(const e_config_protocol_type& sram_orgz
}
break;
}
default:
default:
VTR_LOGF_ERROR(__FILE__, __LINE__,
"Invalid SRAM organization type!\n");
exit(1);
@ -609,7 +609,7 @@ size_t calculate_num_config_clock_cycles(const e_config_protocol_type& sram_orgz
* Instanciate the input benchmark module
*******************************************************************/
static
void print_verilog_top_testbench_benchmark_instance(std::fstream& fp,
void print_verilog_top_testbench_benchmark_instance(std::fstream& fp,
const std::string& reference_verilog_top_name,
const AtomContext& atom_ctx,
const VprNetlistAnnotation& netlist_annotation,
@ -618,11 +618,11 @@ void print_verilog_top_testbench_benchmark_instance(std::fstream& fp,
valid_file_stream(fp);
/* Benchmark is instanciated conditionally: only when a preprocessing flag is enable */
print_verilog_preprocessing_flag(fp, std::string(AUTOCHECKED_SIMULATION_FLAG));
print_verilog_preprocessing_flag(fp, std::string(AUTOCHECKED_SIMULATION_FLAG));
print_verilog_comment(fp, std::string("----- Reference Benchmark Instanication -------"));
/* Do NOT use explicit port mapping here:
/* Do NOT use explicit port mapping here:
* VPR added a prefix of "out_" to the output ports of input benchmark
*/
std::vector<std::string> prefix_to_remove;
@ -650,12 +650,12 @@ void print_verilog_top_testbench_benchmark_instance(std::fstream& fp,
}
/********************************************************************
* Print tasks (processes) in Verilog format,
* which is very useful in generating stimuli for each clock cycle
* This function is tuned for configuration-chain manipulation:
* Print tasks (processes) in Verilog format,
* which is very useful in generating stimuli for each clock cycle
* This function is tuned for configuration-chain manipulation:
* During each programming cycle, we feed the input of scan chain with a memory bit
*******************************************************************/
static
static
void print_verilog_top_testbench_load_bitstream_task_configuration_chain(std::fstream& fp) {
/* Validate the file stream */
@ -668,17 +668,17 @@ void print_verilog_top_testbench_load_bitstream_task_configuration_chain(std::fs
/* Add an empty line as splitter */
fp << std::endl;
/* Feed the scan-chain input at each falling edge of programming clock
* It aims at avoid racing the programming clock (scan-chain data changes at the rising edge).
/* Feed the scan-chain input at each falling edge of programming clock
* It aims at avoid racing the programming clock (scan-chain data changes at the rising edge).
*/
print_verilog_comment(fp, std::string("----- Task: input values during a programming clock cycle -----"));
fp << "task " << std::string(TOP_TESTBENCH_PROG_TASK_NAME) << ";" << std::endl;
fp << generate_verilog_port(VERILOG_PORT_INPUT, cc_head_value) << ";" << std::endl;
fp << "\tbegin" << std::endl;
fp << "\t\t@(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_port) << ");" << std::endl;
fp << "\t\t\t";
fp << "\t\t\t";
fp << generate_verilog_port(VERILOG_PORT_CONKT, cc_head_port);
fp << " = ";
fp << " = ";
fp << generate_verilog_port(VERILOG_PORT_CONKT, cc_head_value);
fp << ";" << std::endl;
@ -690,15 +690,15 @@ void print_verilog_top_testbench_load_bitstream_task_configuration_chain(std::fs
}
/********************************************************************
* Print tasks (processes) in Verilog format,
* which is very useful in generating stimuli for each clock cycle
* This function is tuned for memory bank manipulation:
* Print tasks (processes) in Verilog format,
* which is very useful in generating stimuli for each clock cycle
* This function is tuned for memory bank manipulation:
* During each programming cycle, we feed
* - an address to the BL address port of top module
* - an address to the WL address port of top module
* - a data input to the din port of top module
*******************************************************************/
static
static
void print_verilog_top_testbench_load_bitstream_task_memory_bank(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& top_module) {
@ -731,7 +731,7 @@ void print_verilog_top_testbench_load_bitstream_task_memory_bank(std::fstream& f
/* Add an empty line as splitter */
fp << std::endl;
/* Feed the address and data input at each falling edge of programming clock
/* Feed the address and data input at each falling edge of programming clock
* As the enable signal is wired to the programming clock, we should synchronize
* address and data with the enable signal
*/
@ -743,23 +743,23 @@ void print_verilog_top_testbench_load_bitstream_task_memory_bank(std::fstream& f
fp << "\tbegin" << std::endl;
fp << "\t\t@(posedge " << generate_verilog_port(VERILOG_PORT_CONKT, en_port) << ");" << std::endl;
fp << "\t\t\t";
fp << "\t\t\t";
fp << generate_verilog_port(VERILOG_PORT_CONKT, bl_addr_port);
fp << " = ";
fp << " = ";
fp << generate_verilog_port(VERILOG_PORT_CONKT, bl_addr_value);
fp << ";" << std::endl;
fp << std::endl;
fp << "\t\t\t";
fp << "\t\t\t";
fp << generate_verilog_port(VERILOG_PORT_CONKT, wl_addr_port);
fp << " = ";
fp << " = ";
fp << generate_verilog_port(VERILOG_PORT_CONKT, wl_addr_value);
fp << ";" << std::endl;
fp << std::endl;
fp << "\t\t\t";
fp << "\t\t\t";
fp << generate_verilog_port(VERILOG_PORT_CONKT, din_port);
fp << " = ";
fp << " = ";
fp << generate_verilog_port(VERILOG_PORT_CONKT, din_value);
fp << ";" << std::endl;
fp << std::endl;
@ -773,14 +773,14 @@ void print_verilog_top_testbench_load_bitstream_task_memory_bank(std::fstream& f
/********************************************************************
* Print tasks (processes) in Verilog format,
* which is very useful in generating stimuli for each clock cycle
* This function is tuned for frame-based memory manipulation:
* Print tasks (processes) in Verilog format,
* which is very useful in generating stimuli for each clock cycle
* This function is tuned for frame-based memory manipulation:
* During each programming cycle, we feed
* - an address to the address port of top module
* - a data input to the din port of top module
*******************************************************************/
static
static
void print_verilog_top_testbench_load_bitstream_task_frame_decoder(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& top_module) {
@ -807,7 +807,7 @@ void print_verilog_top_testbench_load_bitstream_task_frame_decoder(std::fstream&
/* Add an empty line as splitter */
fp << std::endl;
/* Feed the address and data input at each falling edge of programming clock
/* Feed the address and data input at each falling edge of programming clock
* As the enable signal is wired to the programming clock, we should synchronize
* address and data with the enable signal
*/
@ -818,16 +818,16 @@ void print_verilog_top_testbench_load_bitstream_task_frame_decoder(std::fstream&
fp << "\tbegin" << std::endl;
fp << "\t\t@(posedge " << generate_verilog_port(VERILOG_PORT_CONKT, en_port) << ");" << std::endl;
fp << "\t\t\t";
fp << "\t\t\t";
fp << generate_verilog_port(VERILOG_PORT_CONKT, addr_port);
fp << " = ";
fp << " = ";
fp << generate_verilog_port(VERILOG_PORT_CONKT, addr_value);
fp << ";" << std::endl;
fp << std::endl;
fp << "\t\t\t";
fp << "\t\t\t";
fp << generate_verilog_port(VERILOG_PORT_CONKT, din_port);
fp << " = ";
fp << " = ";
fp << generate_verilog_port(VERILOG_PORT_CONKT, din_value);
fp << ";" << std::endl;
fp << std::endl;
@ -840,9 +840,9 @@ void print_verilog_top_testbench_load_bitstream_task_frame_decoder(std::fstream&
}
/********************************************************************
* Print tasks, which is very useful in generating stimuli for each clock cycle
* Print tasks, which is very useful in generating stimuli for each clock cycle
*******************************************************************/
static
static
void print_verilog_top_testbench_load_bitstream_task(std::fstream& fp,
const e_config_protocol_type& sram_orgz_type,
const ModuleManager& module_manager,
@ -882,7 +882,7 @@ void print_verilog_top_testbench_load_bitstream_task(std::fstream& fp,
* 6. reset signal
* 7. set signal
*******************************************************************/
static
static
void print_verilog_top_testbench_generic_stimulus(std::fstream& fp,
const size_t& num_config_clock_cycles,
const float& prog_clock_period,
@ -891,7 +891,7 @@ void print_verilog_top_testbench_generic_stimulus(std::fstream& fp,
/* Validate the file stream */
valid_file_stream(fp);
print_verilog_comment(fp, std::string("----- Number of clock cycles in configuration phase: " + std::to_string(num_config_clock_cycles) + " -----"));
print_verilog_comment(fp, std::string("----- Number of clock cycles in configuration phase: " + std::to_string(num_config_clock_cycles) + " -----"));
BasicPort config_done_port(std::string(TOP_TB_CONFIG_DONE_PORT_NAME), 1);
@ -908,26 +908,26 @@ void print_verilog_top_testbench_generic_stimulus(std::fstream& fp,
BasicPort set_port(std::string(TOP_TB_SET_PORT_NAME), 1);
/* Generate stimuli waveform for configuration done signals */
print_verilog_comment(fp, "----- Begin configuration done signal generation -----");
print_verilog_pulse_stimuli(fp, config_done_port,
print_verilog_comment(fp, "----- Begin configuration done signal generation -----");
print_verilog_pulse_stimuli(fp, config_done_port,
0, /* Initial value */
num_config_clock_cycles * prog_clock_period / timescale, 0);
print_verilog_comment(fp, "----- End configuration done signal generation -----");
num_config_clock_cycles * prog_clock_period / timescale, 0);
print_verilog_comment(fp, "----- End configuration done signal generation -----");
fp << std::endl;
/* Generate stimuli waveform for programming clock signals */
print_verilog_comment(fp, "----- Begin raw programming clock signal generation -----");
print_verilog_clock_stimuli(fp, prog_clock_register_port,
print_verilog_comment(fp, "----- Begin raw programming clock signal generation -----");
print_verilog_clock_stimuli(fp, prog_clock_register_port,
0, /* Initial value */
0.5 * prog_clock_period / timescale,
std::string());
print_verilog_comment(fp, "----- End raw programming clock signal generation -----");
std::string());
print_verilog_comment(fp, "----- End raw programming clock signal generation -----");
fp << std::endl;
/* Programming clock should be only enabled during programming phase.
* When configuration is done (config_done is enabled), programming clock should be always zero.
*/
print_verilog_comment(fp, std::string("----- Actual programming clock is triggered only when " + config_done_port.get_name() + " and " + prog_reset_port.get_name() + " are disabled -----"));
print_verilog_comment(fp, std::string("----- Actual programming clock is triggered only when " + config_done_port.get_name() + " and " + prog_reset_port.get_name() + " are disabled -----"));
fp << "\tassign " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_port);
fp << " = " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_register_port);
fp << " & (~" << generate_verilog_port(VERILOG_PORT_CONKT, config_done_port) << ")";
@ -937,17 +937,17 @@ void print_verilog_top_testbench_generic_stimulus(std::fstream& fp,
fp << std::endl;
/* Generate stimuli waveform for operating clock signals */
print_verilog_comment(fp, "----- Begin raw operating clock signal generation -----");
print_verilog_clock_stimuli(fp, op_clock_register_port,
print_verilog_comment(fp, "----- Begin raw operating clock signal generation -----");
print_verilog_clock_stimuli(fp, op_clock_register_port,
0, /* Initial value */
0.5 * op_clock_period / timescale,
std::string("~" + reset_port.get_name()));
print_verilog_comment(fp, "----- End raw operating clock signal generation -----");
std::string("~" + reset_port.get_name()));
print_verilog_comment(fp, "----- End raw operating clock signal generation -----");
/* Operation clock should be enabled after programming phase finishes.
* Before configuration is done (config_done is enabled), operation clock should be always zero.
*/
print_verilog_comment(fp, std::string("----- Actual operating clock is triggered only when " + config_done_port.get_name() + " is enabled -----"));
print_verilog_comment(fp, std::string("----- Actual operating clock is triggered only when " + config_done_port.get_name() + " is enabled -----"));
fp << "\tassign " << generate_verilog_port(VERILOG_PORT_CONKT, op_clock_port);
fp << " = " << generate_verilog_port(VERILOG_PORT_CONKT, op_clock_register_port);
fp << " & " << generate_verilog_port(VERILOG_PORT_CONKT, config_done_port);
@ -955,23 +955,23 @@ void print_verilog_top_testbench_generic_stimulus(std::fstream& fp,
fp << std::endl;
/* Reset signal for configuration circuit:
* only enable during the first clock cycle in programming phase
/* Reset signal for configuration circuit:
* only enable during the first clock cycle in programming phase
*/
print_verilog_comment(fp, "----- Begin programming reset signal generation -----");
print_verilog_pulse_stimuli(fp, prog_reset_port,
print_verilog_comment(fp, "----- Begin programming reset signal generation -----");
print_verilog_pulse_stimuli(fp, prog_reset_port,
1, /* Initial value */
prog_clock_period / timescale, 0);
print_verilog_comment(fp, "----- End programming reset signal generation -----");
prog_clock_period / timescale, 0);
print_verilog_comment(fp, "----- End programming reset signal generation -----");
fp << std::endl;
/* Programming set signal for configuration circuit : always disabled */
print_verilog_comment(fp, "----- Begin programming set signal generation: always disabled -----");
print_verilog_pulse_stimuli(fp, prog_set_port,
print_verilog_comment(fp, "----- Begin programming set signal generation: always disabled -----");
print_verilog_pulse_stimuli(fp, prog_set_port,
0, /* Initial value */
prog_clock_period / timescale, 0);
print_verilog_comment(fp, "----- End programming set signal generation: always disabled -----");
prog_clock_period / timescale, 0);
print_verilog_comment(fp, "----- End programming set signal generation: always disabled -----");
fp << std::endl;
@ -984,30 +984,30 @@ void print_verilog_top_testbench_generic_stimulus(std::fstream& fp,
reset_flip_values.push_back(1);
reset_flip_values.push_back(0);
print_verilog_comment(fp, "----- Begin operating reset signal generation -----");
print_verilog_comment(fp, "----- Begin operating reset signal generation -----");
print_verilog_comment(fp, "----- Reset signal is enabled until the first clock cycle in operation phase -----");
print_verilog_pulse_stimuli(fp, reset_port,
1,
reset_pulse_widths,
reset_flip_values,
config_done_port.get_name());
print_verilog_comment(fp, "----- End operating reset signal generation -----");
print_verilog_comment(fp, "----- End operating reset signal generation -----");
/* Operating set signal for configuration circuit : always disabled */
print_verilog_comment(fp, "----- Begin operating set signal generation: always disabled -----");
print_verilog_pulse_stimuli(fp, set_port,
print_verilog_comment(fp, "----- Begin operating set signal generation: always disabled -----");
print_verilog_pulse_stimuli(fp, set_port,
0, /* Initial value */
op_clock_period / timescale, 0);
print_verilog_comment(fp, "----- End operating set signal generation: always disabled -----");
op_clock_period / timescale, 0);
print_verilog_comment(fp, "----- End operating set signal generation: always disabled -----");
fp << std::endl;
}
/********************************************************************
* Print stimulus for a FPGA fabric with a flatten memory (standalone) configuration protocol
* Print stimulus for a FPGA fabric with a flatten memory (standalone) configuration protocol
* We will load the bitstream in the second clock cycle, right after the first reset cycle
*******************************************************************/
static
static
void print_verilog_top_testbench_vanilla_bitstream(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& top_module,
@ -1027,9 +1027,9 @@ void print_verilog_top_testbench_vanilla_bitstream(std::fstream& fp,
BasicPort wl_port = module_manager.module_port(top_module, wl_port_id);
/* Initial value should be the first configuration bits
* In the rest of programming cycles,
* In the rest of programming cycles,
* configuration bits are fed at the falling edge of programming clock.
* We do not care the value of scan_chain head during the first programming cycle
* We do not care the value of scan_chain head during the first programming cycle
* It is reset anyway
*/
std::vector<size_t> initial_bl_values(bl_port.get_width(), 0);
@ -1052,7 +1052,7 @@ void print_verilog_top_testbench_vanilla_bitstream(std::fstream& fp,
/* Enable all the WLs */
std::vector<size_t> enabled_wl_values(wl_port.get_width(), 1);
fp << "\t\t\t";
fp << "\t\t\t";
fp << generate_verilog_port_constant_values(wl_port, enabled_wl_values);
fp << ";" << std::endl;
@ -1061,9 +1061,9 @@ void print_verilog_top_testbench_vanilla_bitstream(std::fstream& fp,
BasicPort cur_bl_port(bl_port);
cur_bl_port.set_width(ibit, ibit);
fp << "\t\t\t";
fp << "\t\t\t";
fp << generate_verilog_port(VERILOG_PORT_CONKT, cur_bl_port);
fp << " = ";
fp << " = ";
fp << "1'b" << (size_t)bitstream_manager.bit_value(fabric_bitstream.config_bit(bit_id));
fp << ";" << std::endl;
@ -1075,13 +1075,13 @@ void print_verilog_top_testbench_vanilla_bitstream(std::fstream& fp,
/* Disable all the WLs */
fp << "\t\t@(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_port) << ");" << std::endl;
fp << "\t\t\t";
fp << "\t\t\t";
fp << generate_verilog_port_constant_values(wl_port, initial_wl_values);
fp << ";" << std::endl;
/* Raise the flag of configuration done when bitstream loading is complete */
fp << "\t\t@(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_port) << ");" << std::endl;
BasicPort config_done_port(std::string(TOP_TB_CONFIG_DONE_PORT_NAME), 1);
fp << "\t\t\t";
fp << generate_verilog_port(VERILOG_PORT_CONKT, config_done_port);
@ -1095,18 +1095,18 @@ void print_verilog_top_testbench_vanilla_bitstream(std::fstream& fp,
}
/********************************************************************
* Print stimulus for a FPGA fabric with a configuration chain protocol
* Print stimulus for a FPGA fabric with a configuration chain protocol
* where configuration bits are programming in serial (one by one)
* Task list:
* 1. For clock signal, we should create voltage waveforms for two types of clock signals:
* a. operation clock
* b. programming clock
* 2. For Set/Reset, we reset the chip after programming phase ends
* b. programming clock
* 2. For Set/Reset, we reset the chip after programming phase ends
* and before operation phase starts
* 3. For input/output clb nets (mapped to I/O grids),
* we should create voltage waveforms only after programming phase
* 3. For input/output clb nets (mapped to I/O grids),
* we should create voltage waveforms only after programming phase
*******************************************************************/
static
static
void print_verilog_top_testbench_configuration_chain_bitstream(std::fstream& fp,
const BitstreamManager& bitstream_manager,
const FabricBitstream& fabric_bitstream) {
@ -1114,9 +1114,9 @@ void print_verilog_top_testbench_configuration_chain_bitstream(std::fstream& fp,
valid_file_stream(fp);
/* Initial value should be the first configuration bits
* In the rest of programming cycles,
* In the rest of programming cycles,
* configuration bits are fed at the falling edge of programming clock.
* We do not care the value of scan_chain head during the first programming cycle
* 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);
@ -1133,7 +1133,7 @@ void print_verilog_top_testbench_configuration_chain_bitstream(std::fstream& fp,
fp << std::endl;
/* Attention: the configuration chain protcol requires the last configuration bit is fed first
* We will visit the fabric bitstream in a reverse way
* We will visit the fabric bitstream in a reverse way
*/
for (const FabricBitId& bit_id : fabric_bitstream.bits()) {
fp << "\t\t" << std::string(TOP_TESTBENCH_PROG_TASK_NAME);
@ -1143,7 +1143,7 @@ void print_verilog_top_testbench_configuration_chain_bitstream(std::fstream& fp,
/* Raise the flag of configuration done when bitstream loading is complete */
BasicPort prog_clock_port(std::string(TOP_TB_PROG_CLOCK_PORT_NAME), 1);
fp << "\t\t@(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_port) << ");" << std::endl;
BasicPort config_done_port(std::string(TOP_TB_CONFIG_DONE_PORT_NAME), 1);
fp << "\t\t\t";
fp << generate_verilog_port(VERILOG_PORT_CONKT, config_done_port);
@ -1157,12 +1157,12 @@ void print_verilog_top_testbench_configuration_chain_bitstream(std::fstream& fp,
}
/********************************************************************
* Print stimulus for a FPGA fabric with a memory bank configuration protocol
* Print stimulus for a FPGA fabric with a memory bank configuration protocol
* where configuration bits are programming in serial (one by one)
*
* We will use the programming task function created before
*******************************************************************/
static
static
void print_verilog_top_testbench_memory_bank_bitstream(std::fstream& fp,
const bool& fast_configuration,
const ModuleManager& module_manager,
@ -1171,9 +1171,9 @@ void print_verilog_top_testbench_memory_bank_bitstream(std::fstream& fp,
/* Validate the file stream */
valid_file_stream(fp);
/* Feed addresss and data input pair one by one
/* Feed addresss and data input pair one by one
* Note: the first cycle is reserved for programming reset
* We should give dummy values
* We should give dummy values
*/
ModulePortId bl_addr_port_id = module_manager.find_module_port(top_module,
std::string(DECODER_BL_ADDRESS_PORT_NAME));
@ -1211,7 +1211,7 @@ void print_verilog_top_testbench_memory_bank_bitstream(std::fstream& fp,
fp << std::endl;
/* Attention: the configuration chain protcol requires the last configuration bit is fed first
* We will visit the fabric bitstream in a reverse way
* We will visit the fabric bitstream in a reverse way
*/
for (const FabricBitId& bit_id : fabric_bitstream.bits()) {
/* When fast configuration is enabled, we skip zero data_in values */
@ -1224,14 +1224,14 @@ void print_verilog_top_testbench_memory_bank_bitstream(std::fstream& fp,
fp << "(" << bl_addr_port.get_width() << "'b";
VTR_ASSERT(bl_addr_port.get_width() == fabric_bitstream.bit_bl_address(bit_id).size());
for (const size_t& addr_bit : fabric_bitstream.bit_bl_address(bit_id)) {
fp << addr_bit;
fp << addr_bit;
}
fp << ", ";
fp << wl_addr_port.get_width() << "'b";
VTR_ASSERT(wl_addr_port.get_width() == fabric_bitstream.bit_wl_address(bit_id).size());
for (const size_t& addr_bit : fabric_bitstream.bit_wl_address(bit_id)) {
fp << addr_bit;
fp << addr_bit;
}
fp << ", ";
@ -1248,7 +1248,7 @@ void print_verilog_top_testbench_memory_bank_bitstream(std::fstream& fp,
/* Raise the flag of configuration done when bitstream loading is complete */
BasicPort prog_clock_port(std::string(TOP_TB_PROG_CLOCK_PORT_NAME), 1);
fp << "\t\t@(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_port) << ");" << std::endl;
BasicPort config_done_port(std::string(TOP_TB_CONFIG_DONE_PORT_NAME), 1);
fp << "\t\t\t";
fp << generate_verilog_port(VERILOG_PORT_CONKT, config_done_port);
@ -1262,12 +1262,12 @@ void print_verilog_top_testbench_memory_bank_bitstream(std::fstream& fp,
}
/********************************************************************
* Print stimulus for a FPGA fabric with a frame-based configuration protocol
* Print stimulus for a FPGA fabric with a frame-based configuration protocol
* where configuration bits are programming in serial (one by one)
*
* We will use the programming task function created before
*******************************************************************/
static
static
void print_verilog_top_testbench_frame_decoder_bitstream(std::fstream& fp,
const bool& fast_configuration,
const ModuleManager& module_manager,
@ -1276,9 +1276,9 @@ void print_verilog_top_testbench_frame_decoder_bitstream(std::fstream& fp,
/* Validate the file stream */
valid_file_stream(fp);
/* Feed addresss and data input pair one by one
/* Feed addresss and data input pair one by one
* Note: the first cycle is reserved for programming reset
* We should give dummy values
* We should give dummy values
*/
ModulePortId addr_port_id = module_manager.find_module_port(top_module,
std::string(DECODER_ADDRESS_PORT_NAME));
@ -1307,7 +1307,7 @@ void print_verilog_top_testbench_frame_decoder_bitstream(std::fstream& fp,
fp << std::endl;
/* Attention: the configuration chain protcol requires the last configuration bit is fed first
* We will visit the fabric bitstream in a reverse way
* We will visit the fabric bitstream in a reverse way
*/
for (const FabricBitId& bit_id : fabric_bitstream.bits()) {
/* When fast configuration is enabled, we skip zero data_in values */
@ -1320,7 +1320,7 @@ void print_verilog_top_testbench_frame_decoder_bitstream(std::fstream& fp,
fp << "(" << addr_port.get_width() << "'b";
VTR_ASSERT(addr_port.get_width() == fabric_bitstream.bit_address(bit_id).size());
for (const size_t& addr_bit : fabric_bitstream.bit_address(bit_id)) {
fp << addr_bit;
fp << addr_bit;
}
fp << ", ";
fp <<"1'b";
@ -1338,7 +1338,7 @@ void print_verilog_top_testbench_frame_decoder_bitstream(std::fstream& fp,
fp << "(" << addr_port.get_width() << "'b";
std::vector<size_t> all_zero_addr(addr_port.get_width(), 0);
for (const size_t& addr_bit : all_zero_addr) {
fp << addr_bit;
fp << addr_bit;
}
fp << ", ";
fp <<"1'b0";
@ -1347,7 +1347,7 @@ void print_verilog_top_testbench_frame_decoder_bitstream(std::fstream& fp,
/* Raise the flag of configuration done when bitstream loading is complete */
BasicPort prog_clock_port(std::string(TOP_TB_PROG_CLOCK_PORT_NAME), 1);
fp << "\t\t@(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_port) << ");" << std::endl;
BasicPort config_done_port(std::string(TOP_TB_CONFIG_DONE_PORT_NAME), 1);
fp << "\t\t\t";
fp << generate_verilog_port(VERILOG_PORT_CONKT, config_done_port);
@ -1361,12 +1361,12 @@ void print_verilog_top_testbench_frame_decoder_bitstream(std::fstream& fp,
}
/********************************************************************
* Generate the stimuli for the top-level testbench
* Generate the stimuli for the top-level testbench
* The simulation consists of two phases: configuration phase and operation phase
* Configuration bits are loaded serially.
* Configuration bits are loaded serially.
* This is actually what we do for a physical FPGA
*******************************************************************/
static
static
void print_verilog_top_testbench_bitstream(std::fstream& fp,
const e_config_protocol_type& sram_orgz_type,
const bool& fast_configuration,
@ -1377,7 +1377,7 @@ void print_verilog_top_testbench_bitstream(std::fstream& fp,
/* Branch on the type of configuration protocol */
switch (sram_orgz_type) {
case CONFIG_MEM_STANDALONE:
print_verilog_top_testbench_vanilla_bitstream(fp,
print_verilog_top_testbench_vanilla_bitstream(fp,
module_manager, top_module,
bitstream_manager, fabric_bitstream);
break;
@ -1394,7 +1394,7 @@ void print_verilog_top_testbench_bitstream(std::fstream& fp,
module_manager, top_module,
fabric_bitstream);
break;
default:
default:
VTR_LOGF_ERROR(__FILE__, __LINE__,
"Invalid SRAM organization type!\n");
exit(1);
@ -1402,8 +1402,8 @@ void print_verilog_top_testbench_bitstream(std::fstream& fp,
}
/********************************************************************
* The top-level function to generate a testbench, in order to verify:
* 1. Configuration phase of the FPGA fabric, where the bitstream is
* The top-level function to generate a testbench, in order to verify:
* 1. Configuration phase of the FPGA fabric, where the bitstream is
* loaded to the configuration protocol of the FPGA fabric
* 2. Operating phase of the FPGA fabric, where input stimuli are
* fed to the I/Os of the FPGA fabric
@ -1412,9 +1412,9 @@ void print_verilog_top_testbench_bitstream(std::fstream& fp,
* +----->| Fabric |------>| |
* | | | | |
* | +----------+ | |
* | | Output |
* | | Output |
* random_input_vectors -----+ | Vector |---->Functional correct?
* | | Comparator |
* | | Comparator |
* | +-----------+ | |
* | | Input | | |
* +----->| Benchmark |----->| |
@ -1428,7 +1428,7 @@ void print_verilog_top_testbench(const ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
const std::vector<CircuitPortId>& global_ports,
const AtomContext& atom_ctx,
const PlacementContext& place_ctx,
const PlacementContext& place_ctx,
const IoLocationMap& io_location_map,
const VprNetlistAnnotation& netlist_annotation,
const std::string& circuit_name,
@ -1451,7 +1451,7 @@ void print_verilog_top_testbench(const ModuleManager& module_manager,
/* Generate a brief description on the Verilog file*/
std::string title = std::string("FPGA Verilog Testbench for Top-level netlist of Design: ") + circuit_name;
print_verilog_file_header(fp, title);
print_verilog_file_header(fp, title);
/* Find the top_module */
ModuleId top_module = module_manager.find_module(generate_fpga_top_module_name());
@ -1461,14 +1461,14 @@ void print_verilog_top_testbench(const ModuleManager& module_manager,
std::vector<std::string> clock_port_names = find_atom_netlist_clock_port_names(atom_ctx.nlist, netlist_annotation);
/* Start of testbench */
print_verilog_top_testbench_ports(fp, module_manager, top_module,
print_verilog_top_testbench_ports(fp, module_manager, top_module,
atom_ctx, netlist_annotation, clock_port_names,
sram_orgz_type, circuit_name);
/* Find the clock period */
float prog_clock_period = (1./simulation_parameters.programming_clock_frequency());
float op_clock_period = (1./simulation_parameters.operating_clock_frequency());
/* Estimate the number of configuration clock cycles */
/* Estimate the number of configuration clock cycles */
size_t num_config_clock_cycles = calculate_num_config_clock_cycles(sram_orgz_type,
fast_configuration,
fabric_bitstream);
@ -1486,24 +1486,24 @@ void print_verilog_top_testbench(const ModuleManager& module_manager,
circuit_lib, global_ports);
/* Instanciate FPGA top-level module */
print_verilog_testbench_fpga_instance(fp, module_manager, top_module,
print_verilog_testbench_fpga_instance(fp, module_manager, top_module,
std::string(TOP_TESTBENCH_FPGA_INSTANCE_NAME),
explicit_port_mapping);
explicit_port_mapping);
/* Connect I/Os to benchmark I/Os or constant driver */
print_verilog_testbench_connect_fpga_ios(fp, module_manager, top_module,
atom_ctx, place_ctx, io_location_map,
netlist_annotation,
std::string(),
std::string(TOP_TESTBENCH_FPGA_OUTPUT_POSTFIX),
netlist_annotation,
std::string(),
std::string(TOP_TESTBENCH_FPGA_OUTPUT_POSTFIX),
(size_t)VERILOG_DEFAULT_SIGNAL_INIT_VALUE);
/* Instanciate input benchmark */
print_verilog_top_testbench_benchmark_instance(fp,
print_verilog_top_testbench_benchmark_instance(fp,
circuit_name,
atom_ctx,
netlist_annotation,
explicit_port_mapping);
explicit_port_mapping);
/* Print tasks used for loading bitstreams */
print_verilog_top_testbench_load_bitstream_task(fp,
@ -1517,14 +1517,14 @@ void print_verilog_top_testbench(const ModuleManager& module_manager,
bitstream_manager, fabric_bitstream);
/* Add stimuli for reset, set, clock and iopad signals */
print_verilog_testbench_random_stimuli(fp, atom_ctx,
netlist_annotation,
clock_port_names,
print_verilog_testbench_random_stimuli(fp, atom_ctx,
netlist_annotation,
clock_port_names,
std::string(TOP_TESTBENCH_CHECKFLAG_PORT_POSTFIX),
BasicPort(std::string(TOP_TB_OP_CLOCK_PORT_NAME), 1));
/* Add output autocheck */
print_verilog_testbench_check(fp,
print_verilog_testbench_check(fp,
std::string(AUTOCHECKED_SIMULATION_FLAG),
std::string(TOP_TESTBENCH_SIM_START_PORT_NAME),
std::string(TOP_TESTBENCH_REFERENCE_OUTPUT_POSTFIX),
@ -1532,7 +1532,7 @@ void print_verilog_top_testbench(const ModuleManager& module_manager,
std::string(TOP_TESTBENCH_CHECKFLAG_PORT_POSTFIX),
std::string(TOP_TESTBENCH_ERROR_COUNTER),
atom_ctx,
netlist_annotation,
netlist_annotation,
clock_port_names,
std::string(TOP_TB_OP_CLOCK_PORT_NAME));
@ -1545,10 +1545,10 @@ void print_verilog_top_testbench(const ModuleManager& module_manager,
/* Add Icarus requirement */
print_verilog_timeout_and_vcd(fp,
print_verilog_timeout_and_vcd(fp,
std::string(ICARUS_SIMULATOR_FLAG),
std::string(circuit_name + std::string(AUTOCHECK_TOP_TESTBENCH_VERILOG_MODULE_POSTFIX)),
std::string(circuit_name + std::string("_formal.vcd")),
std::string(circuit_name + std::string("_formal.vcd")),
std::string(TOP_TESTBENCH_SIM_START_PORT_NAME),
std::string(TOP_TESTBENCH_ERROR_COUNTER),
(int)simulation_time);

View File

@ -29,9 +29,9 @@ void print_verilog_top_testbench(const ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
const std::vector<CircuitPortId>& global_ports,
const AtomContext& atom_ctx,
const PlacementContext& place_ctx,
const PlacementContext& place_ctx,
const IoLocationMap& io_location_map,
const VprNetlistAnnotation& netlist_annotation,
const VprNetlistAnnotation& netlist_annotation,
const std::string& circuit_name,
const std::string& verilog_fname,
const SimulationSetting& simulation_parameters,

View File

@ -37,7 +37,7 @@ repack #--verbose
# Build the bitstream
# - Output the fabric-independent bitstream to a file
build_architecture_bitstream --verbose --file fabric_indepenent_bitstream.xml
build_architecture_bitstream --verbose --write_file fabric_indepenent_bitstream.xml
# Build fabric-dependent bitstream
build_fabric_bitstream --verbose

View File

@ -37,7 +37,7 @@ repack #--verbose
# Build the bitstream
# - Output the fabric-independent bitstream to a file
build_architecture_bitstream --verbose --file fabric_indepenent_bitstream.xml
build_architecture_bitstream --verbose --write_file fabric_indepenent_bitstream.xml
# Build fabric-dependent bitstream
build_fabric_bitstream --verbose

View File

@ -37,7 +37,7 @@ repack #--verbose
# Build the bitstream
# - Output the fabric-independent bitstream to a file
build_architecture_bitstream --verbose --file fabric_indepenent_bitstream.xml
build_architecture_bitstream --verbose --write_file fabric_indepenent_bitstream.xml
# Build fabric-dependent bitstream
build_fabric_bitstream --verbose

View File

@ -37,7 +37,7 @@ repack #--verbose
# Build the bitstream
# - Output the fabric-independent bitstream to a file
build_architecture_bitstream --verbose --file fabric_indepenent_bitstream.xml
build_architecture_bitstream --verbose --write_file fabric_indepenent_bitstream.xml
# Build fabric-dependent bitstream
build_fabric_bitstream --verbose

View File

@ -37,7 +37,7 @@ repack #--verbose
# Build the bitstream
# - Output the fabric-independent bitstream to a file
build_architecture_bitstream --verbose --file fabric_indepenent_bitstream.xml
build_architecture_bitstream --verbose --write_file fabric_indepenent_bitstream.xml
# Build fabric-dependent bitstream
build_fabric_bitstream --verbose

View File

@ -37,7 +37,7 @@ repack #--verbose
# Build the bitstream
# - Output the fabric-independent bitstream to a file
build_architecture_bitstream --verbose --file fabric_indepenent_bitstream.xml
build_architecture_bitstream --verbose --write_file fabric_indepenent_bitstream.xml
# Build fabric-dependent bitstream
build_fabric_bitstream --verbose

View File

@ -0,0 +1,42 @@
# Run VPR for the 'and' design
#--write_rr_graph example_rr_graph.xml
vpr ${VPR_ARCH_FILE} ${VPR_TESTBENCH_BLIF} --clock_modeling route
# Read OpenFPGA architecture definition
read_openfpga_arch -f ${OPENFPGA_ARCH_FILE}
# Read OpenFPGA simulation settings
read_openfpga_simulation_setting -f ${OPENFPGA_SIM_SETTING_FILE}
# Annotate the OpenFPGA architecture to VPR data base
# to debug use --verbose options
link_openfpga_arch --activity_file ${ACTIVITY_FILE} --sort_gsb_chan_node_in_edges
# Check and correct any naming conflicts in the BLIF netlist
check_netlist_naming_conflict --fix --report ./netlist_renaming.xml
# Build the module graph
# - Enabled compression on routing architecture modules
# - Enable pin duplication on grid modules
build_fabric --compress_routing --write_fabric_key ./fabric_key.xml #--verbose
# Write the fabric hierarchy of module graph to a file
# This is used by hierarchical PnR flows
write_fabric_hierarchy --file ./fabric_hierarchy.txt
# Write the Verilog netlist for FPGA fabric
# - Enable the use of explicit port mapping in Verilog netlist
write_fabric_verilog --file ./SRC --explicit_port_mapping --include_timing --include_signal_init --support_icarus_simulator --print_user_defined_template --verbose
# Write the SDC files for PnR backend
# - Turn on every options here
write_pnr_sdc --file ./SDC
# Write SDC to disable timing for configure ports
write_sdc_disable_timing_configure_ports --file ./SDC/disable_configure_ports.sdc
# Finish and exit OpenFPGA
exit
# Note :
# To run verification at the end of the flow maintain source in ./SRC directory

View File

@ -0,0 +1,74 @@
# Run VPR for the 'and' design
#--write_rr_graph example_rr_graph.xml
vpr ${VPR_ARCH_FILE} ${VPR_TESTBENCH_BLIF} --clock_modeling route
# Read OpenFPGA architecture definition
read_openfpga_arch -f ${OPENFPGA_ARCH_FILE}
# Read OpenFPGA simulation settings
read_openfpga_simulation_setting -f ${OPENFPGA_SIM_SETTING_FILE}
# Annotate the OpenFPGA architecture to VPR data base
# to debug use --verbose options
link_openfpga_arch --activity_file ${ACTIVITY_FILE} --sort_gsb_chan_node_in_edges
# Check and correct any naming conflicts in the BLIF netlist
check_netlist_naming_conflict --fix --report ./netlist_renaming.xml
# Apply fix-up to clustering nets based on routing results
pb_pin_fixup --verbose
# Apply fix-up to Look-Up Table truth tables based on packing results
lut_truth_table_fixup
# Build the module graph
# - Enabled compression on routing architecture modules
# - Enable pin duplication on grid modules
build_fabric --compress_routing \
--write_fabric_key ./fabric_key.xml \
--generate_random_fabric_key
#--verbose
# Write the fabric hierarchy of module graph to a file
# This is used by hierarchical PnR flows
write_fabric_hierarchy --file ./fabric_hierarchy.txt
# Repack the netlist to physical pbs
# This must be done before bitstream generator and testbench generation
# Strongly recommend it is done after all the fix-up have been applied
repack #--verbose
# Build the bitstream
# - Output the fabric-independent bitstream to a file
build_architecture_bitstream --verbose --write_file fabric_indepenent_bitstream.xml
# Build fabric-dependent bitstream
build_fabric_bitstream --verbose
# Write the Verilog netlist for FPGA fabric
# - Enable the use of explicit port mapping in Verilog netlist
write_fabric_verilog --file ./SRC --explicit_port_mapping --include_timing --include_signal_init --support_icarus_simulator --print_user_defined_template --verbose
# Write the Verilog testbench for FPGA fabric
# - We suggest the use of same output directory as fabric Verilog netlists
# - Must specify the reference benchmark file if you want to output any testbenches
# - Enable top-level testbench which is a full verification including programming circuit and core logic of FPGA
# - Enable pre-configured top-level testbench which is a fast verification skipping programming phase
# - Simulation ini file is optional and is needed only when you need to interface different HDL simulators using openfpga flow-run scripts
write_verilog_testbench --file ./SRC --reference_benchmark_file_path ${REFERENCE_VERILOG_TESTBENCH} --print_top_testbench --print_preconfig_top_testbench --print_simulation_ini ./SimulationDeck/simulation_deck.ini --explicit_port_mapping
# Write the SDC files for PnR backend
# - Turn on every options here
write_pnr_sdc --file ./SDC
# Write SDC to disable timing for configure ports
write_sdc_disable_timing_configure_ports --file ./SDC/disable_configure_ports.sdc
# Write the SDC to run timing analysis for a mapped FPGA fabric
write_analysis_sdc --file ./SDC_analysis
# Finish and exit OpenFPGA
exit
# Note :
# To run verification at the end of the flow maintain source in ./SRC directory

View File

@ -0,0 +1,74 @@
# Run VPR for the 'and' design
#--write_rr_graph example_rr_graph.xml
vpr ${VPR_ARCH_FILE} ${VPR_TESTBENCH_BLIF} --clock_modeling route
# Read OpenFPGA architecture definition
read_openfpga_arch -f ${OPENFPGA_ARCH_FILE}
# Read OpenFPGA simulation settings
read_openfpga_simulation_setting -f ${OPENFPGA_SIM_SETTING_FILE}
# Annotate the OpenFPGA architecture to VPR data base
# to debug use --verbose options
link_openfpga_arch --activity_file ${ACTIVITY_FILE} --sort_gsb_chan_node_in_edges
# Check and correct any naming conflicts in the BLIF netlist
check_netlist_naming_conflict --fix --report ./netlist_renaming.xml
# Apply fix-up to clustering nets based on routing results
pb_pin_fixup --verbose
# Apply fix-up to Look-Up Table truth tables based on packing results
lut_truth_table_fixup
# Build the module graph
# - Enabled compression on routing architecture modules
# - Enable pin duplication on grid modules
build_fabric --compress_routing \
--load_fabric_key ${EXTERNAL_FABRIC_KEY_FILE} \
--write_fabric_key ./fabric_key.xml
#--verbose
# Write the fabric hierarchy of module graph to a file
# This is used by hierarchical PnR flows
write_fabric_hierarchy --file ./fabric_hierarchy.txt
# Repack the netlist to physical pbs
# This must be done before bitstream generator and testbench generation
# Strongly recommend it is done after all the fix-up have been applied
repack #--verbose
# Build the bitstream
# - Output the fabric-independent bitstream to a file
build_architecture_bitstream --verbose --write_file fabric_indepenent_bitstream.xml
# Build fabric-dependent bitstream
build_fabric_bitstream --verbose
# Write the Verilog netlist for FPGA fabric
# - Enable the use of explicit port mapping in Verilog netlist
write_fabric_verilog --file ./SRC --explicit_port_mapping --include_timing --include_signal_init --support_icarus_simulator --print_user_defined_template --verbose
# Write the Verilog testbench for FPGA fabric
# - We suggest the use of same output directory as fabric Verilog netlists
# - Must specify the reference benchmark file if you want to output any testbenches
# - Enable top-level testbench which is a full verification including programming circuit and core logic of FPGA
# - Enable pre-configured top-level testbench which is a fast verification skipping programming phase
# - Simulation ini file is optional and is needed only when you need to interface different HDL simulators using openfpga flow-run scripts
write_verilog_testbench --file ./SRC --reference_benchmark_file_path ${REFERENCE_VERILOG_TESTBENCH} --print_top_testbench --print_preconfig_top_testbench --print_simulation_ini ./SimulationDeck/simulation_deck.ini --explicit_port_mapping
# Write the SDC files for PnR backend
# - Turn on every options here
write_pnr_sdc --file ./SDC
# Write SDC to disable timing for configure ports
write_sdc_disable_timing_configure_ports --file ./SDC/disable_configure_ports.sdc
# Write the SDC to run timing analysis for a mapped FPGA fabric
write_analysis_sdc --file ./SDC_analysis
# Finish and exit OpenFPGA
exit
# Note :
# To run verification at the end of the flow maintain source in ./SRC directory

View File

@ -37,7 +37,7 @@ repack #--verbose
# Build the bitstream
# - Output the fabric-independent bitstream to a file
build_architecture_bitstream --verbose --file fabric_indepenent_bitstream.xml
build_architecture_bitstream --verbose --write_file fabric_indepenent_bitstream.xml
# Build fabric-dependent bitstream
build_fabric_bitstream --verbose

View File

@ -37,7 +37,7 @@ repack #--verbose
# Build the bitstream
# - Output the fabric-independent bitstream to a file
build_architecture_bitstream --verbose --file fabric_indepenent_bitstream.xml
build_architecture_bitstream --verbose --write_file fabric_indepenent_bitstream.xml
# Build fabric-dependent bitstream
build_fabric_bitstream --verbose

View File

@ -37,7 +37,7 @@ repack #--verbose
# Build the bitstream
# - Output the fabric-independent bitstream to a file
build_architecture_bitstream --verbose --file fabric_indepenent_bitstream.xml
build_architecture_bitstream --verbose --write_file fabric_indepenent_bitstream.xml
# Build fabric-dependent bitstream
build_fabric_bitstream --verbose
@ -48,7 +48,7 @@ write_fabric_verilog --file ./SRC \
--explicit_port_mapping \
--include_timing \
--include_signal_init
#--support_icarus_simulator
# --support_icarus_simulator
# Write the Verilog testbench for FPGA fabric
# - We suggest the use of same output directory as fabric Verilog netlists

View File

@ -37,7 +37,7 @@ repack #--verbose
# Build the bitstream
# - Output the fabric-independent bitstream to a file
build_architecture_bitstream --verbose --file fabric_indepenent_bitstream.xml
build_architecture_bitstream --verbose --write_file fabric_indepenent_bitstream.xml
# Build fabric-dependent bitstream
build_fabric_bitstream --verbose

View File

@ -0,0 +1,36 @@
<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"/>
<key id="33" name="decoder6to33" value="0"/>
</fabric_key>

View File

@ -85,6 +85,8 @@ parser.add_argument('--openfpga_arch_file', type=str,
help="Openfpga architecture file for shell")
parser.add_argument('--openfpga_sim_setting_file', type=str,
help="Openfpga simulation file for shell")
parser.add_argument('--external_fabric_key_file', type=str,
help="Key file for shell")
parser.add_argument('--yosys_tmpl', type=str,
help="Alternate yosys template, generates top_module.blif")
parser.add_argument('--disp', action="store_true",
@ -686,6 +688,7 @@ def run_openfpga_shell():
path_variables["VPR_ARCH_FILE"] = args.arch_file
path_variables["OPENFPGA_ARCH_FILE"] = args.openfpga_arch_file
path_variables["OPENFPGA_SIM_SETTING_FILE"] = args.openfpga_sim_setting_file
path_variables["EXTERNAL_FABRIC_KEY_FILE"] = args.external_fabric_key_file
path_variables["VPR_TESTBENCH_BLIF"] = args.top_module+".blif"
path_variables["ACTIVITY_FILE"] = args.top_module+"_ace_out.act"
path_variables["REFERENCE_VERILOG_TESTBENCH"] = args.top_module + \

View File

@ -357,6 +357,8 @@ def create_run_command(curr_job_dir, archfile, benchmark_obj, param, task_conf):
task_gc.get("openfpga_arch_file")]
command += ["--openfpga_sim_setting_file",
task_gc.get("openfpga_sim_setting_file")]
command += ["--external_fabric_key_file",
task_gc.get("external_fabric_key_file")]
if benchmark_obj.get("activity_file"):
command += ["--activity_file", benchmark_obj.get("activity_file")]

View File

@ -17,6 +17,7 @@ timeout_each_job = 20*60
fpga_flow=vpr_blif
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k6_frac_N10_behavioral_40nm_openfpga.xml
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
external_fabric_key_file=
[ARCHITECTURES]
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/vpr_only_templates/k6_frac_N10_tileable_40nm.xml

View File

@ -17,6 +17,7 @@ timeout_each_job = 20*60
fpga_flow=vpr_blif
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_mem16K_40nm_openfpga.xml
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
external_fabric_key_file=
[ARCHITECTURES]
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/vpr_only_templates/k6_frac_N10_tileable_adder_chain_mem16K_40nm.xml

View File

@ -17,6 +17,7 @@ timeout_each_job = 20*60
fpga_flow=vpr_blif
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_mem16K_40nm_openfpga.xml
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
external_fabric_key_file=
[ARCHITECTURES]
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/vpr_only_templates/k6_frac_N10_tileable_adder_chain_wide_mem16K_40nm.xml

View File

@ -17,6 +17,7 @@ timeout_each_job = 20*60
fpga_flow=vpr_blif
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k6_frac_N10_40nm_openfpga.xml
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
external_fabric_key_file=
[ARCHITECTURES]
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/vpr_only_templates/k6_frac_N10_tileable_40nm.xml

View File

@ -17,6 +17,7 @@ timeout_each_job = 20*60
fpga_flow=vpr_blif
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k6_frac_N10_adder_column_chain_40nm_openfpga.xml
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
external_fabric_key_file=
[ARCHITECTURES]
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/vpr_only_templates/k6_frac_N10_tileable_adder_chain_40nm.xml

View File

@ -17,6 +17,7 @@ timeout_each_job = 20*60
fpga_flow=vpr_blif
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k6_frac_N10_adder_register_chain_40nm_openfpga.xml
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
external_fabric_key_file=
[ARCHITECTURES]
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/vpr_only_templates/k6_frac_N10_tileable_adder_register_chain_40nm.xml

View File

@ -17,6 +17,7 @@ timeout_each_job = 20*60
fpga_flow=vpr_blif
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k6_frac_N10_adder_register_scan_chain_40nm_openfpga.xml
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
external_fabric_key_file=
[ARCHITECTURES]
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/vpr_only_templates/k6_frac_N10_tileable_adder_register_scan_chain_40nm.xml

View File

@ -0,0 +1,36 @@
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# 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
openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/OpenFPGAShellScripts/generate_secure_fabric_example_script.openfpga
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_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_frame_openfpga.xml
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
external_fabric_key_file=
[ARCHITECTURES]
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/vpr_only_templates/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=

View File

@ -0,0 +1,33 @@
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# 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
openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/OpenFPGAShellScripts/generate_fabric_key_example_script.openfpga
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_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k6_frac_N10_40nm_openfpga.xml
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
external_fabric_key_file=
[ARCHITECTURES]
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/vpr_only_templates/k6_frac_N10_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]

View File

@ -0,0 +1,36 @@
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# 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
openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/OpenFPGAShellScripts/generate_secure_fabric_from_key_example_script.openfpga
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_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_frame_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_sample_key.xml
[ARCHITECTURES]
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/arch/vpr_only_templates/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=

Some files were not shown because too many files have changed in this diff Show More