Merge pull request #466 from lnis-uofu/ql_mem_bank
🏆 A new Configuration Procotol: QuickLogic Memory Bank
This commit is contained in:
commit
2e4c606502
|
@ -201,7 +201,7 @@ A circuit model may consist of a number of ports. The port list is mandatory in
|
|||
|
||||
.. note:: Different types of ``circuit_model`` have different XML syntax, with which users can highly customize their circuit topologies. See refer to examples of :ref:``circuit_model_example`` for more details.
|
||||
|
||||
.. note:: Note that we have a list of reserved port names, which indicate the usage of these ports when building FPGA fabrics. Please do not use ``mem_out``, ``mem_inv``, ``bl``, ``wl``, ``blb``, ``wlb``, ``ccff_head`` and ``ccff_tail``.
|
||||
.. note:: Note that we have a list of reserved port names, which indicate the usage of these ports when building FPGA fabrics. Please do not use ``mem_out``, ``mem_inv``, ``bl``, ``wl``, ``blb``, ``wlb``, ``wlr``, ``ccff_head`` and ``ccff_tail``.
|
||||
|
||||
FPGA I/O Port
|
||||
^^^^^^^^^^^^^
|
||||
|
|
|
@ -333,6 +333,36 @@ The following XML codes describes the SRAM cell shown in :numref:`fig_sram_blwl`
|
|||
|
||||
.. note:: When the ``memory_bank`` type of configuration procotol is specified, SRAM modules should have a BL and a WL.
|
||||
|
||||
.. _circuit_model_sram_blwlr_example:
|
||||
|
||||
SRAM with BL/WL/WLR
|
||||
```````````````````
|
||||
.. _fig_sram_blwlr:
|
||||
|
||||
.. figure:: ./figures/sram_blwlr.svg
|
||||
:scale: 100%
|
||||
|
||||
An example of a SRAM with Bit-Line (BL), Word-Line (WL) and WL read control signals
|
||||
|
||||
The following XML codes describes the SRAM cell shown in :numref:`fig_sram_blwlr`.
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<circuit_model type="sram" name="sram_blwlr" prefix="sram_blwlr" verilog_netlist="sram.v" spice_netlist="sram.sp"/>
|
||||
<design_technology type="cmos"/>
|
||||
<input_buffer exist="false"/>
|
||||
<output_buffer exist="false"/>
|
||||
<port type="bl" prefix="bl" size="1"/>
|
||||
<port type="wl" prefix="wl" size="1"/>
|
||||
<port type="wlr" prefix="wlr" size="1"/>
|
||||
<port type="output" prefix="out" size="1"/>
|
||||
<port type="output" prefix="outb" size="1"/>
|
||||
</circuit_model>
|
||||
|
||||
.. note:: OpenFPGA always assume that a ``WL`` port should be the write enable signal, a ``WLR`` port should be the read enable signal, while a ``BL`` port is the data input.
|
||||
|
||||
.. note:: When the ``memory_bank`` type of configuration procotol is specified, SRAM modules should have a BL and a WL. WLR is optional
|
||||
|
||||
.. _circuit_model_config_latch_example:
|
||||
|
||||
Configurable Latch
|
||||
|
|
|
@ -16,7 +16,7 @@ Template
|
|||
<organization type="<string>" circuit_model_name="<string>" num_regions="<int>"/>
|
||||
</configuration_protocol>
|
||||
|
||||
.. option:: type="scan_chain|memory_bank|standalone"
|
||||
.. option:: type="scan_chain|memory_bank|standalone|frame_based|ql_memory_bank"
|
||||
|
||||
Specify the type of configuration circuits.
|
||||
|
||||
|
@ -24,6 +24,7 @@ Template
|
|||
- ``scan_chain``: configurable memories are connected in a chain. Bitstream is loaded serially to program a FPGA
|
||||
- ``frame_based``: configurable memories are organized by frames. Each module of a FPGA fabric, e.g., Configurable Logic Block (CLB), Switch Block (SB) and Connection Block (CB), is considered as a frame of configurable memories. Inside each frame, all the memory banks are accessed through an address decoder. Users can write each memory cell with a specific address. Note that the frame-based memory organization is applid hierarchically. Each frame may consists of a number of sub frames, each of which follows the similar organization.
|
||||
- ``memory_bank``: configurable memories are organized in an array, where each element can be accessed by an unique address to the BL/WL decoders
|
||||
- ``ql_memory_bank``: configurable memories are organized in an array, where each element can be accessed by an unique address to the BL/WL decoders. This is a physical design friendly memory bank organization, where BL/WLs are efficiently shared by programmable blocks per column and row
|
||||
- ``standalone``: configurable memories are directly accessed through ports of FPGA fabrics. In other words, there are no protocol to control the memories. This allows full customization on the configuration protocol for hardware engineers.
|
||||
|
||||
.. note:: Avoid to use ``standalone`` when designing an FPGA chip. It will causes a huge number of I/Os required, far beyond any package size. It is well applicable to eFPGAs, where designers do need customized protocols between FPGA and processors.
|
||||
|
@ -39,13 +40,19 @@ Template
|
|||
- ``scan_chain`` requires a circuit model type of ``ccff``
|
||||
- ``frame_based`` requires a circuit model type of ``sram``
|
||||
- ``memory_bank`` requires a circuit model type of ``sram``
|
||||
- ``ql_memory_bank`` requires a circuit model type of ``sram``
|
||||
- ``standalone`` requires a circuit model type of ``sram``
|
||||
|
||||
.. option:: num_regions="<int>"
|
||||
|
||||
Specify the number of configuration regions to be used across the fabrics. By default, it will be only 1 configuration region. Each configuration region contains independent configuration protocols, but the whole fabric should employ the same type of configuration protocols. For example, an FPGA fabric consists of 4 configuration regions, each of which includes a configuration chain. The more configuration chain to be used, the fast configuration runtime will be, but at the cost of more I/Os in the FPGA fabrics. The organization of each configurable region can be customized through the fabric key (see details in :ref:`fabric_key`).
|
||||
|
||||
.. warning:: Currently, multiple configuration regions is not applicable to ``standalone`` configuration protocol.
|
||||
.. warning:: Currently, multiple configuration regions is not applicable to
|
||||
|
||||
- ``standalone`` configuration protocol.
|
||||
- ``ql_memory_bank`` configuration protocol when BL/WL protocol ``flatten`` is selected
|
||||
|
||||
.. note:: For ``ql_memory_bank`` configuration protocol when BL/WL protocol ``shift_register`` is selected, different configuration regions **cannot** share any WLs on the same row! In such case, the default fabric key may not work. Strongly recommend to craft your own fabric key based on your configuration region plannning!
|
||||
|
||||
|
||||
Configuration Chain Example
|
||||
|
@ -147,6 +154,75 @@ Users can customized the number of memory banks to be used across the fabrics. B
|
|||
|
||||
.. warning:: Please do NOT add inverted Bit-Line and Word-Line inputs. It is not supported yet!
|
||||
|
||||
QuickLogic Memory bank Example
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
The following XML code describes a physical design friendly memory-bank circuitry to configure the core logic of FPGA, as illustrated in :numref:`fig_memory_bank`.
|
||||
It will use the circuit model defined in :numref:`fig_sram_blwl`.
|
||||
|
||||
The BL and WL protocols can be customized through the XML syntax ``bl`` and ``wl``.
|
||||
|
||||
.. note:: If not specified, the BL/WL protocols will use decoders.
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<configuration_protocol>
|
||||
<organization type="ql_memory_bank" circuit_model_name="sram_blwl">
|
||||
<bl protocol="<string>" num_banks="<int>"/>
|
||||
<wl protocol="<string>" num_banks="<int>"/>
|
||||
</organization>
|
||||
</configuration_protocol>
|
||||
|
||||
.. option:: protocol="decoder|flatten|shift_register"
|
||||
|
||||
- ``decoder``: BLs or WLs are controlled by decoders with address lines. For BLs, the decoder includes an enable signal as well as a data input signal. This is the default option if not specified. See an illustrative example in :numref:`fig_memory_bank_decoder_based`.
|
||||
- ``flatten``: BLs or WLs are directly available at the FPGA fabric. In this way, all the configurable memorys on the same WL can be written through the BL signals in one clock cycle. See an illustrative example in :numref:`fig_memory_bank_flatten`.
|
||||
- ``shift_register``: BLs or WLs are controlled by shift register chains. The BL/WLs are programming each time the shift register chains are fully loaded. See an illustrative example in :numref:`fig_memory_bank_shift_register`.
|
||||
|
||||
.. _fig_memory_bank_decoder_based:
|
||||
|
||||
.. figure:: figures/memory_bank_decoder.svg
|
||||
:scale: 30%
|
||||
:alt: map to buried treasure
|
||||
|
||||
Example of (a) a memory organization using address decoders; (b) single memory bank across the fabric; and (c) multiple memory banks across the fabric.
|
||||
|
||||
|
||||
.. _fig_memory_bank_flatten:
|
||||
|
||||
.. figure:: figures/memory_bank_flatten.svg
|
||||
:scale: 30%
|
||||
:alt: map to buried treasure
|
||||
|
||||
Example of (a) a memory organization with direct access to BL/WL signals; (b) single memory bank across the fabric; and (c) multiple memory banks across the fabric.
|
||||
|
||||
.. _fig_memory_bank_shift_register:
|
||||
|
||||
.. figure:: figures/memory_bank_shift_register.svg
|
||||
:scale: 30%
|
||||
:alt: map to buried treasure
|
||||
|
||||
Example of (a) a memory organization using shift register chains to control BL/WLs; (b) single memory bank across the fabric; and (c) multiple memory banks across the fabric.
|
||||
|
||||
.. option:: num_banks="<int>"
|
||||
|
||||
Specify the number of shift register banks (i.e., independent shift register chains) to be used in each configuration region. When enabled, the length of each shift register chain will be sized by OpenFPGA automatically based on the number of BL/WLs in each configuration region. OpenFPGA will try to create similar sizes for the shift register chains, in order to minimize the number of HDL modules. If not specified, the default number of banks will be ``1``.
|
||||
|
||||
|
||||
.. note:: This is available applicable to shift-register-based BL/WL protocols
|
||||
|
||||
.. note:: More customization on the shift register chains can be enabled through :ref:`fabric_key`
|
||||
|
||||
.. note:: The flip-flop for WL shift register requires an enable signal to gate WL signals when loading WL shift registers
|
||||
|
||||
.. note:: Memory-bank decoders does require a memory cell to have
|
||||
|
||||
- two outputs (one regular and another inverted)
|
||||
- a Bit-Line input to load the data
|
||||
- a Word-Line input to enable data write
|
||||
- (optional) a Word-Line read input to enabe data readback
|
||||
|
||||
.. warning:: Please do NOT add inverted Bit-Line and Word-Line inputs. It is not supported yet!
|
||||
|
||||
Standalone SRAM Example
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
In the standalone configuration protocol, every memory cell of the core logic of a FPGA fabric can be directly accessed at the top-level module, as illustrated in :numref:`fig_vanilla_config_protocol`.
|
||||
|
|
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 158 KiB |
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 157 KiB |
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 177 KiB |
|
@ -0,0 +1,213 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="102.24 198 171.66498 227.98976" width="171.66498" height="227.98976">
|
||||
<defs>
|
||||
<font-face font-family="Times New Roman" font-size="12" panose-1="2 2 5 3 5 4 5 9 3 4" units-per-em="1000" underline-position="-108.88672" underline-thickness="48.828125" slope="-1361.0827" x-height="430.1758" cap-height="662.1094" ascent="891.1133" descent="-216.3086" font-style="italic" font-weight="400">
|
||||
<font-face-src>
|
||||
<font-face-name name="TimesNewRomanPS-ItalicMT"/>
|
||||
</font-face-src>
|
||||
</font-face>
|
||||
<font-face font-family="Times New Roman" font-size="14" panose-1="2 2 5 3 5 4 5 9 3 4" units-per-em="1000" underline-position="-108.88672" underline-thickness="48.828125" slope="-1166.6423" x-height="430.1758" cap-height="662.1094" ascent="891.1133" descent="-216.3086" font-style="italic" font-weight="400">
|
||||
<font-face-src>
|
||||
<font-face-name name="TimesNewRomanPS-ItalicMT"/>
|
||||
</font-face-src>
|
||||
</font-face>
|
||||
<font-face font-family="Times New Roman" font-size="11" panose-1="2 2 5 3 5 4 5 9 3 4" units-per-em="1000" underline-position="-108.88672" underline-thickness="48.828125" slope="-1484.8175" x-height="430.1758" cap-height="662.1094" ascent="891.1133" descent="-216.3086" font-style="italic" font-weight="400">
|
||||
<font-face-src>
|
||||
<font-face-name name="TimesNewRomanPS-ItalicMT"/>
|
||||
</font-face-src>
|
||||
</font-face>
|
||||
</defs>
|
||||
<metadata> Produced by OmniGraffle 7.18.5\n2021-09-21 03:12:41 +0000</metadata>
|
||||
<g id="Canvas_1" stroke="none" stroke-dasharray="none" fill="none" fill-opacity="1" stroke-opacity="1">
|
||||
<title>Canvas 1</title>
|
||||
<g id="Canvas_1_Layer_1">
|
||||
<title>Layer 1</title>
|
||||
<g id="Graphic_8046">
|
||||
<path d="M 127.68 198.72 L 250.92 198.72 L 250.92 312.01722 L 127.68 312.01722 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="4.0,4.0" stroke-width="1"/>
|
||||
</g>
|
||||
<g id="Graphic_34596">
|
||||
<text transform="translate(155.90445 208.44)" fill="black">
|
||||
<tspan font-family="Times New Roman" font-size="12" font-style="italic" font-weight="400" fill="black" x="0" y="11">WL</tspan>
|
||||
</text>
|
||||
</g>
|
||||
<g id="Graphic_35704">
|
||||
<text transform="translate(104.17804 235.33)" fill="black">
|
||||
<tspan font-family="Times New Roman" font-size="12" font-style="italic" font-weight="400" fill="black" x="0" y="11">BL</tspan>
|
||||
</text>
|
||||
</g>
|
||||
<g id="Group_35767">
|
||||
<g id="Line_35770">
|
||||
<path d="M 149.2183 242.6686 L 156.64962 242.6686 L 156.64962 233.84905 L 171.51226 233.84905 L 171.51226 242.6686 L 178.94358 242.6686" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
|
||||
</g>
|
||||
<g id="Line_35769">
|
||||
<line x1="164.08094" y1="230.72207" x2="164.08094" y2="222.9025" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
|
||||
</g>
|
||||
<g id="Line_35768">
|
||||
<line x1="156.64962" y1="230.72207" x2="171.51226" y2="230.72207" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Graphic_35772">
|
||||
<rect x="156.41637" y="339.84" width="68.054996" height="58.68" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
|
||||
<text transform="translate(161.41637 361.38263)" fill="black">
|
||||
<tspan font-family="Times New Roman" font-size="14" font-style="italic" font-weight="400" fill="black" x="11.144686" y="12">SRAM</tspan>
|
||||
</text>
|
||||
</g>
|
||||
<g id="Graphic_35773">
|
||||
<text transform="translate(243.51697 348.48)" fill="black">
|
||||
<tspan font-family="Times New Roman" font-size="11" font-style="italic" font-weight="400" fill="black" x="0" y="10">out</tspan>
|
||||
</text>
|
||||
</g>
|
||||
<g id="Graphic_35774">
|
||||
<text transform="translate(241.45736 372.5285)" fill="black">
|
||||
<tspan font-family="Times New Roman" font-size="11" font-style="italic" font-weight="400" fill="black" x="0" y="10">outb</tspan>
|
||||
</text>
|
||||
</g>
|
||||
<g id="Graphic_35775">
|
||||
<text transform="translate(128.17804 361.68)" fill="black">
|
||||
<tspan font-family="Times New Roman" font-size="12" font-style="italic" font-weight="400" fill="black" x="0" y="11">BL</tspan>
|
||||
</text>
|
||||
</g>
|
||||
<g id="Graphic_35777">
|
||||
<text transform="translate(162.73144 411.48)" fill="black">
|
||||
<tspan font-family="Times New Roman" font-size="12" font-style="italic" font-weight="400" fill="black" x="0" y="11">WL</tspan>
|
||||
</text>
|
||||
</g>
|
||||
<g id="Line_35778">
|
||||
<line x1="156.41637" y1="368.68" x2="144.72758" y2="368.6938" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
|
||||
</g>
|
||||
<g id="Line_35781">
|
||||
<line x1="237.71537" y1="355.48" x2="226.02657" y2="355.4938" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
|
||||
</g>
|
||||
<g id="Line_35780">
|
||||
<line x1="237.71537" y1="378.26216" x2="226.02657" y2="378.27596" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
|
||||
</g>
|
||||
<g id="Line_35782">
|
||||
<line x1="171.0341" y1="411.48" x2="170.97639" y2="398.52" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
|
||||
</g>
|
||||
<g id="Graphic_35783">
|
||||
<path d="M 196.65095 317.8024 L 187.53514 317.8024 L 187.53514 327.1839 L 184.64166 327.1839 L 192.09304 334.05483 L 199.54443 327.1839 L 196.65095 327.1839 Z" fill="#c0ffff"/>
|
||||
<path d="M 196.65095 317.8024 L 187.53514 317.8024 L 187.53514 327.1839 L 184.64166 327.1839 L 192.09304 334.05483 L 199.54443 327.1839 L 196.65095 327.1839 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/>
|
||||
</g>
|
||||
<g id="Graphic_35785">
|
||||
<text transform="translate(195.02518 411.48)" fill="black">
|
||||
<tspan font-family="Times New Roman" font-size="12" font-style="italic" font-weight="400" fill="black" x="0" y="11">WLR</tspan>
|
||||
</text>
|
||||
</g>
|
||||
<g id="Line_35784">
|
||||
<line x1="206.99287" y1="411.48" x2="206.93516" y2="398.52" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
|
||||
</g>
|
||||
<g id="Group_35786">
|
||||
<g id="Graphic_35790">
|
||||
<path d="M 197.45672 215.28 L 212.31937 225.18842 L 197.45672 235.09685 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
|
||||
</g>
|
||||
<g id="Graphic_35789">
|
||||
<circle cx="214.79647" cy="225.18842" r="2.47710469423255" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
|
||||
</g>
|
||||
<g id="Line_35788">
|
||||
<line x1="192.5025" y1="225.18842" x2="196.45672" y2="225.18842" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
|
||||
</g>
|
||||
<g id="Line_35787">
|
||||
<line x1="218.27358" y1="225.18842" x2="222.2278" y2="225.18842" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Group_35791">
|
||||
<g id="Graphic_35795">
|
||||
<path d="M 217.27358 246.93685 L 202.41094 256.84528 L 217.27358 266.7537 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
|
||||
</g>
|
||||
<g id="Graphic_35794">
|
||||
<circle cx="199.93383" cy="256.84528" r="2.47710469423254" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
|
||||
</g>
|
||||
<g id="Line_35793">
|
||||
<line x1="222.2278" y1="256.84528" x2="218.27358" y2="256.84528" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
|
||||
</g>
|
||||
<g id="Line_35792">
|
||||
<line x1="196.45672" y1="256.84528" x2="192.5025" y2="256.84528" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Line_35797">
|
||||
<line x1="192.5025" y1="225.18842" x2="192.5025" y2="256.84528" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
|
||||
</g>
|
||||
<g id="Line_35798">
|
||||
<line x1="222.3825" y1="224.64" x2="222.2278" y2="257.12" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
|
||||
</g>
|
||||
<g id="Line_35803">
|
||||
<line x1="222.3153" y1="238.7479" x2="251.50138" y2="238.495" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
|
||||
</g>
|
||||
<g id="Graphic_35804">
|
||||
<text transform="translate(254.34883 230.20132)" fill="black">
|
||||
<tspan font-family="Times New Roman" font-size="11" font-style="italic" font-weight="400" fill="black" x="0" y="10">outb</tspan>
|
||||
</text>
|
||||
</g>
|
||||
<g id="Line_35805">
|
||||
<path d="M 250.375 204.375 L 192.5025 204.875 L 192.5025 225.18842" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
|
||||
</g>
|
||||
<g id="Line_35806">
|
||||
<line x1="178.94358" y1="242.62" x2="192.5025" y2="242.37" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
|
||||
</g>
|
||||
<g id="Graphic_35807">
|
||||
<text transform="translate(254.34883 198)" fill="black">
|
||||
<tspan font-family="Times New Roman" font-size="11" font-style="italic" font-weight="400" fill="black" x="0" y="10">out</tspan>
|
||||
</text>
|
||||
</g>
|
||||
<g id="Group_35808">
|
||||
<g id="Line_35811">
|
||||
<path d="M 149.14524 267.52314 L 149.14524 274.95446 L 157.9648 274.95446 L 157.9648 289.8171 L 149.14524 289.8171 L 149.14524 297.24842" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
|
||||
</g>
|
||||
<g id="Line_35810">
|
||||
<line x1="161.09179" y1="282.38578" x2="168.91134" y2="282.38578" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
|
||||
</g>
|
||||
<g id="Line_35809">
|
||||
<line x1="161.09179" y1="274.95446" x2="161.09179" y2="289.8171" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
|
||||
</g>
|
||||
</g>
|
||||
<g id="Line_35817">
|
||||
<line x1="127.68" y1="242.875" x2="149.2183" y2="242.6686" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
|
||||
</g>
|
||||
<g id="Graphic_35818">
|
||||
<text transform="translate(102.24 252.04776)" fill="black">
|
||||
<tspan font-family="Times New Roman" font-size="12" font-style="italic" font-weight="400" fill="black" x="0" y="11">WLR</tspan>
|
||||
</text>
|
||||
</g>
|
||||
<g id="Graphic_35819">
|
||||
<text transform="translate(137.36102 295.24314)" fill="black">
|
||||
<tspan font-family="Times New Roman" font-size="11" font-style="italic" font-weight="400" fill="black" x="0" y="10">GND</tspan>
|
||||
</text>
|
||||
</g>
|
||||
<g id="Line_35820">
|
||||
<path d="M 168.91134 282.38578 L 241.12887 281.725 L 241.0367 238.58568" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
|
||||
</g>
|
||||
<g id="Graphic_35821">
|
||||
<ellipse cx="240.89" cy="238.20685" rx="2.52000397038629" ry="2.87686226095125" fill="black"/>
|
||||
<ellipse cx="240.89" cy="238.20685" rx="2.52000397038629" ry="2.87686226095125" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/>
|
||||
</g>
|
||||
<g id="Graphic_35822">
|
||||
<ellipse cx="222.7278" cy="238.2937" rx="2.52000397038632" ry="2.87686226095122" fill="black"/>
|
||||
<ellipse cx="222.7278" cy="238.2937" rx="2.52000397038632" ry="2.87686226095122" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/>
|
||||
</g>
|
||||
<g id="Graphic_35823">
|
||||
<ellipse cx="192.09304" cy="242.83" rx="2.52000397038633" ry="2.87686226095122" fill="black"/>
|
||||
<ellipse cx="192.09304" cy="242.83" rx="2.52000397038633" ry="2.87686226095122" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/>
|
||||
</g>
|
||||
<g id="Graphic_35824">
|
||||
<ellipse cx="192.20189" cy="225.18842" rx="2.52000397038633" ry="2.87686226095122" fill="black"/>
|
||||
<ellipse cx="192.20189" cy="225.18842" rx="2.52000397038633" ry="2.87686226095122" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/>
|
||||
</g>
|
||||
<g id="Graphic_35825">
|
||||
<ellipse cx="149.09" cy="242.83" rx="2.5200039703863" ry="2.87686226095122" fill="black"/>
|
||||
<ellipse cx="149.09" cy="242.83" rx="2.5200039703863" ry="2.87686226095122" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/>
|
||||
</g>
|
||||
<g id="Group_35827">
|
||||
<g id="Line_35830">
|
||||
<path d="M 149.14524 244.44 L 149.14524 251.87132 L 140.32569 251.87132 L 140.32569 266.73396 L 149.14524 266.73396 L 149.14524 274.16528" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
|
||||
</g>
|
||||
<g id="Line_35829">
|
||||
<line x1="137.1987" y1="259.30264" x2="129.37915" y2="259.30264" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
|
||||
</g>
|
||||
<g id="Line_35828">
|
||||
<line x1="137.1987" y1="251.87132" x2="137.1987" y2="266.73396" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 13 KiB |
|
@ -14,7 +14,10 @@ General organization is as follows
|
|||
<clock name="<string>" port="<string>" frequency="<float>"/>
|
||||
...
|
||||
</operating>
|
||||
<programming frequency="<int>"/>
|
||||
<programming frequency="<int>">
|
||||
<clock name="<string>" port="<string>" frequency="auto|<float>" is_shift_register="<bool>"/>
|
||||
...
|
||||
</programming>
|
||||
</clock_setting>
|
||||
<simulator_option>
|
||||
<operating_condition temperature="<int>"/>
|
||||
|
@ -61,7 +64,10 @@ We should the full syntax in the code block below and then provide details on ea
|
|||
<clock name="<string>" port="<string>" frequency="<float>"/>
|
||||
...
|
||||
</operating>
|
||||
<programming frequency="<float>"/>
|
||||
<programming frequency="<float>">
|
||||
<clock name="<string>" port="<string>" frequency="auto|<float>" is_shift_register="<bool>"/>
|
||||
...
|
||||
</programming>
|
||||
</clock_setting>
|
||||
|
||||
Operating clock setting
|
||||
|
@ -121,6 +127,22 @@ Programming clocks are defined under the XML node ``<programming>``
|
|||
Specify the frequency of the programming clock using an absolute value in the unit of ``[Hz]``
|
||||
This frequency is used in testbenches for programming phase simulation.
|
||||
|
||||
.. option:: <clock name="<string>" port="<string>" frequency="auto|<float>" is_shift_register="<bool>"/>
|
||||
|
||||
- ``name="<string>``
|
||||
Specify a unique name for a clock signal. The name should match a reserved word of programming clock, i.e., ``bl_sr_clock`` and ``wl_sr_clock``.
|
||||
|
||||
.. note:: The ``bl_sr_clock`` represents the clock signal driving the BL shift register chains, while the ``wl_sr_clock`` represents the clock signal driving the WL shift register chains
|
||||
|
||||
- ``port="<string>``
|
||||
Specify the clock port which the clock signal should be applied to. The clock port must be a valid clock port defined in OpenFPGA architecture description. Explicit index is required, e.g., ``clk[1:1]``. Otherwise, default index ``0`` will be considered, e.g., ``clk`` will be translated as ``clk[0:0]``.
|
||||
|
||||
- ``frequency="auto|<float>``
|
||||
Specify frequency of a clock signal in the unit of ``[Hz]``. If ``auto`` is used, the programming clock frequency will be inferred by OpenFPGA.
|
||||
|
||||
- ``is_shift_register="<bool>``
|
||||
Specify if this clock signal is used to drive shift register chains in BL/WL protocols
|
||||
|
||||
.. note:: Programming clock frequency is typically much slower than the operating clock and strongly depends on the process technology. Suggest to characterize the speed of your configuration protocols before specifying a value!
|
||||
|
||||
Simulator Option
|
||||
|
|
|
@ -65,6 +65,112 @@ The information depends on the type of configuration procotol.
|
|||
|
||||
.. note:: When there are multiple configuration regions, each ``<bit_value>`` may consist of multiple bits. For example, ``0110`` represents the bits for 4 configuration regions, where the 4 digits correspond to the bits from region ``0, 1, 2, 3`` respectively.
|
||||
|
||||
.. option:: ql_memory_bank using decoders
|
||||
|
||||
Multiple lines will be included, each of which is organized as <bl_address><wl_address><bits>.
|
||||
The size of address line and data input bits are shown as a comment in the bitstream file, which eases the development of bitstream downloader.
|
||||
For example
|
||||
|
||||
.. code-block:: verilog
|
||||
|
||||
// Bitstream width (LSB -> MSB): <bl_address 5 bits><wl_address 5 bits><data input 1 bits>
|
||||
|
||||
The first part represents the Bit-Line address.
|
||||
The second part represents the Word-Line address.
|
||||
The third part represents the configuration bit.
|
||||
For example
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<bitline_address><wordline_address><bit_value>
|
||||
<bitline_address><wordline_address><bit_value>
|
||||
...
|
||||
<bitline_address><wordline_address><bit_value>
|
||||
|
||||
.. note:: When there are multiple configuration regions, each ``<bit_value>`` may consist of multiple bits. For example, ``0110`` represents the bits for 4 configuration regions, where the 4 digits correspond to the bits from region ``0, 1, 2, 3`` respectively.
|
||||
|
||||
.. option:: ql_memory_bank using flatten BL and WLs
|
||||
|
||||
Multiple lines will be included, each of which is organized as <bl_data><wl_data>.
|
||||
The size of data are shown as a comment in the bitstream file, which eases the development of bitstream downloader.
|
||||
For example
|
||||
|
||||
.. code-block:: verilog
|
||||
|
||||
// Bitstream width (LSB -> MSB): <Region 1: bl_data 5 bits><Region 2: bl_data 4 bits><Region 1: wl_data 5 bits><Region 2: wl_data 6 bits>
|
||||
|
||||
The first part represents the Bit-Line data from multiple configuration regions.
|
||||
The second part represents the Word-Line data from multiple configuration regions.
|
||||
For example
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<bitline_data_region1><bitline_data_region2><wordline_data_region1><wordline_data_region2>
|
||||
<bitline_data_region1><bitline_data_region2><wordline_data_region1><wordline_data_region2>
|
||||
...
|
||||
<bitline_data_region1><bitline_data_region2><wordline_data_region1><wordline_data_region2>
|
||||
|
||||
.. note:: The WL data of region is one-hot.
|
||||
|
||||
.. option:: ql_memory_bank using shift registers
|
||||
|
||||
Multiple lines will be included, each of which is organized as <bl_data> or <wl_data>.
|
||||
The size of data are shown as a comment in the bitstream file, which eases the development of bitstream downloader.
|
||||
For example
|
||||
|
||||
.. code-block:: verilog
|
||||
|
||||
// Bitstream word count: 36
|
||||
// Bitstream bl word size: 39
|
||||
// Bitstream wl word size: 37
|
||||
// Bitstream width (LSB -> MSB): <bl shift register heads 1 bits><wl shift register heads 1 bits>
|
||||
|
||||
The bitstream data are organized by words. Each word consists of two parts, BL data to be loaded to BL shift register chains and WL data to be loaded to WL shift register chains
|
||||
For example
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
// Word 0
|
||||
// BL Part
|
||||
<bitline_shift_register_data@clock_0> ----
|
||||
<bitline_shift_register_data@clock_1> ^
|
||||
<bitline_shift_register_data@clock_1> |
|
||||
... BL word size
|
||||
<bitline_shift_register_data@clock_n-2> |
|
||||
<bitline_shift_register_data@clock_n-1> v
|
||||
<bitline_shift_register_data@clock_n> ----
|
||||
// Word 0
|
||||
// WL Part
|
||||
<wordline_shift_register_data@clock_0> ----
|
||||
<wordline_shift_register_data@clock_1> ^
|
||||
<wordline_shift_register_data@clock_1> |
|
||||
... WL word size
|
||||
<wordline_shift_register_data@clock_n-2> |
|
||||
<wordline_shift_register_data@clock_n-1> v
|
||||
<wordline_shift_register_data@clock_n> ----
|
||||
// Word 1
|
||||
// BL Part
|
||||
<bitline_shift_register_data@clock_0> ----
|
||||
<bitline_shift_register_data@clock_1> ^
|
||||
<bitline_shift_register_data@clock_1> |
|
||||
... BL word size
|
||||
<bitline_shift_register_data@clock_n-2> |
|
||||
<bitline_shift_register_data@clock_n-1> v
|
||||
<bitline_shift_register_data@clock_n> ----
|
||||
// Word 1
|
||||
// WL Part
|
||||
<wordline_shift_register_data@clock_0> ----
|
||||
<wordline_shift_register_data@clock_1> ^
|
||||
<wordline_shift_register_data@clock_1> |
|
||||
... WL word size
|
||||
<wordline_shift_register_data@clock_n-2> |
|
||||
<wordline_shift_register_data@clock_n-1> v
|
||||
<wordline_shift_register_data@clock_n> ----
|
||||
... // More words
|
||||
|
||||
.. note:: The BL/WL data may be multi-bit, while each bit corresponds to a configuration region
|
||||
.. note:: The WL data of region is one-hot.
|
||||
|
||||
.. option:: frame_based
|
||||
|
||||
Multiple lines will be included, each of which is organized as ``<address><data_input_bits>``.
|
||||
|
|
|
@ -24,21 +24,54 @@ The following example shows how to define multiple configuration regions in the
|
|||
|
||||
<fabric_key>
|
||||
<region id="0">
|
||||
<bl_shift_register_banks>
|
||||
<bank id="0" range="bl[0:24]"/>
|
||||
<bank id="1" range="bl[25:40]"/>
|
||||
</bl_shift_register_banks>
|
||||
<wl_shift_register_banks>
|
||||
<bank id="0" range="wl[0:19],wl[40:59]"/>
|
||||
<bank id="1" range="wl[21:39],wl[60:69]"/>
|
||||
</wl_shift_register_banks>
|
||||
<key id="0" name="grid_io_bottom" value="0" alias="grid_io_bottom_1__0_"/>
|
||||
<key id="1" name="grid_io_right" value="0" alias="grid_io_right_2__1_"/>
|
||||
<key id="2" name="sb_1__1_" value="0" alias="sb_1__1_"/>
|
||||
</region>
|
||||
<region id="1">
|
||||
<bl_shift_register_banks>
|
||||
<bank id="0" range="bl[0:24]"/>
|
||||
<bank id="1" range="bl[25:40]"/>
|
||||
</bl_shift_register_banks>
|
||||
<wl_shift_register_banks>
|
||||
<bank id="0" range="wl[0:19]"/>
|
||||
</wl_shift_register_banks>
|
||||
<key id="3" name="cbx_1__1_" value="0" alias="cbx_1__1_"/>
|
||||
<key id="4" name="grid_io_top" value="0" alias="grid_io_top_1__2_"/>
|
||||
<key id="5" name="sb_0__1_" value="0" alias="sb_0__1_"/>
|
||||
</region>
|
||||
<region id="2">
|
||||
<bl_shift_register_banks>
|
||||
<bank id="0" range="bl[0:24]"/>
|
||||
<bank id="1" range="bl[25:40]"/>
|
||||
<bank id="2" range="bl[41:59]"/>
|
||||
</bl_shift_register_banks>
|
||||
<wl_shift_register_banks>
|
||||
<bank id="0" range="wl[0:19]"/>
|
||||
<bank id="1" range="wl[21:39]"/>
|
||||
</wl_shift_register_banks>
|
||||
<key id="6" name="sb_0__0_" value="0" alias="sb_0__0_"/>
|
||||
<key id="7" name="cby_0__1_" value="0" alias="cby_0__1_"/>
|
||||
<key id="8" name="grid_io_left" value="0" alias="grid_io_left_0__1_"/>
|
||||
</region>
|
||||
<region id="3">
|
||||
<bl_shift_register_banks>
|
||||
<bank id="0" range="bl[0:24]"/>
|
||||
<bank id="1" range="bl[25:40]"/>
|
||||
</bl_shift_register_banks>
|
||||
<wl_shift_register_banks>
|
||||
<bank id="0" range="wl[0:19]"/>
|
||||
<bank id="1" range="wl[21:39]"/>
|
||||
<bank id="2" range="wl[40:49]"/>
|
||||
</wl_shift_register_banks>
|
||||
<key id="9" name="sb_1__0_" value="0" alias="sb_1__0_"/>
|
||||
<key id="10" name="cbx_1__0_" value="0" alias="cbx_1__0_"/>
|
||||
<key id="11" name="cby_1__1_" value="0" alias="cby_1__1_"/>
|
||||
|
@ -62,6 +95,14 @@ Each configurable block is defined as a key. There are two ways to define a key,
|
|||
|
||||
- ``alias`` indicates the instance name of the configurable memory block in the top-level FPGA fabric. If a valid alias is specified, the ``name`` and ``value`` are not required.
|
||||
|
||||
- ``column`` indicates the relative x coordinate for a configurable memory in a configurable region at the top-level FPGA fabric. This is required when the memory bank protocol is selection.
|
||||
|
||||
.. note:: The configurable memory blocks in the same column will share the same Bit Line (BL) bus
|
||||
|
||||
- ``row`` indicates the relative y coordinate for a configurable memory in a configurable region at the top-level FPGA fabric. This is required when the memory bank protocol is selection.
|
||||
|
||||
.. note:: The configurable memory blocks in the same row will share the same Word Line (WL) bus
|
||||
|
||||
.. warning:: For fast loading of fabric key, strongly recommend to use pairs ``name`` and ``alias`` or ``name`` and ``value`` in the fabric key file. Using only ``alias`` may cause long parsing time for fabric key.
|
||||
|
||||
The following is an example of a fabric key generate by OpenFPGA for a 2 :math:`\times` 2 FPGA.
|
||||
|
@ -149,3 +190,89 @@ This key contains only ``name`` and ``value`` which is fast to parse.
|
|||
<key id="32" name="grid_io_left" value="1"/>
|
||||
</region>
|
||||
</fabric_key>
|
||||
|
||||
The following shows another example of a fabric key generate by OpenFPGA for a 2 :math:`\times` 2 FPGA using memory bank.
|
||||
This key contains only ``name``, ``value``, ``row`` and ``column``.
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<fabric_key>
|
||||
<region id="0">
|
||||
<key id="0" name="sb_2__2_" value="0" alias="sb_2__2_" column="5" row="5"/>
|
||||
<key id="1" name="grid_clb" value="3" alias="grid_clb_2__2_" column="4" row="4"/>
|
||||
<key id="2" name="sb_0__1_" value="0" alias="sb_0__1_" column="1" row="3"/>
|
||||
<key id="3" name="cby_0__1_" value="0" alias="cby_0__1_" column="1" row="2"/>
|
||||
<key id="4" name="grid_clb" value="2" alias="grid_clb_2__1_" column="4" row="2"/>
|
||||
<key id="5" name="grid_io_left" value="0" alias="grid_io_left_0__1_" column="0" row="2"/>
|
||||
<key id="6" name="sb_1__0_" value="0" alias="sb_1__0_" column="3" row="1"/>
|
||||
<key id="7" name="sb_1__1_" value="0" alias="sb_1__1_" column="3" row="3"/>
|
||||
<key id="8" name="cbx_1__1_" value="1" alias="cbx_2__1_" column="4" row="3"/>
|
||||
<key id="9" name="cby_1__1_" value="1" alias="cby_1__2_" column="3" row="4"/>
|
||||
<key id="10" name="grid_io_right" value="0" alias="grid_io_right_3__2_" column="6" row="4"/>
|
||||
<key id="11" name="cbx_1__0_" value="1" alias="cbx_2__0_" column="4" row="1"/>
|
||||
<key id="12" name="cby_1__1_" value="0" alias="cby_1__1_" column="3" row="2"/>
|
||||
<key id="13" name="grid_io_right" value="1" alias="grid_io_right_3__1_" column="6" row="2"/>
|
||||
<key id="14" name="grid_io_bottom" value="1" alias="grid_io_bottom_1__0_" column="2" row="0"/>
|
||||
<key id="15" name="cby_2__1_" value="0" alias="cby_2__1_" column="5" row="2"/>
|
||||
<key id="16" name="sb_2__1_" value="0" alias="sb_2__1_" column="5" row="3"/>
|
||||
<key id="17" name="cbx_1__0_" value="0" alias="cbx_1__0_" column="2" row="1"/>
|
||||
<key id="18" name="grid_clb" value="1" alias="grid_clb_1__2_" column="2" row="4"/>
|
||||
<key id="19" name="cbx_1__2_" value="0" alias="cbx_1__2_" column="2" row="5"/>
|
||||
<key id="20" name="cbx_1__2_" value="1" alias="cbx_2__2_" column="4" row="5"/>
|
||||
<key id="21" name="sb_2__0_" value="0" alias="sb_2__0_" column="5" row="1"/>
|
||||
<key id="22" name="sb_1__2_" value="0" alias="sb_1__2_" column="3" row="5"/>
|
||||
<key id="23" name="cby_0__1_" value="1" alias="cby_0__2_" column="1" row="4"/>
|
||||
<key id="24" name="sb_0__0_" value="0" alias="sb_0__0_" column="1" row="1"/>
|
||||
<key id="25" name="grid_clb" value="0" alias="grid_clb_1__1_" column="2" row="2"/>
|
||||
<key id="26" name="cby_2__1_" value="1" alias="cby_2__2_" column="5" row="4"/>
|
||||
<key id="27" name="grid_io_top" value="1" alias="grid_io_top_2__3_" column="4" row="6"/>
|
||||
<key id="28" name="sb_0__2_" value="0" alias="sb_0__2_" column="1" row="5"/>
|
||||
<key id="29" name="grid_io_bottom" value="0" alias="grid_io_bottom_2__0_" column="4" row="0"/>
|
||||
<key id="30" name="cbx_1__1_" value="0" alias="cbx_1__1_" column="2" row="3"/>
|
||||
<key id="31" name="grid_io_top" value="0" alias="grid_io_top_1__3_" column="2" row="6"/>
|
||||
<key id="32" name="grid_io_left" value="1" alias="grid_io_left_0__2_" column="0" row="4"/>
|
||||
</region>
|
||||
</fabric_key>
|
||||
|
||||
BL Shift Register Banks
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. note:: The customizable is only available when the shift-register-based memory bank is selected in :ref:`config_protocol`
|
||||
|
||||
Each Bit-Line (BL) shift register bank is defined in the code block ``<bl_shift_register_banks>``.
|
||||
A shift register bank may contain multiple shift register chains.
|
||||
- each shift register chain can be defined using the ``bank`` syntax
|
||||
- the BLs controlled by each chain can be customized through the ``range`` syntax.
|
||||
|
||||
.. option:: <bank id="<int>" range="<ports>"/>
|
||||
|
||||
- ``id`` indicates the sequence of the shift register chain in the bank. The id denotes the index in the head or tail bus. For example, ``id="0"`` means the head or tail of the shift register will be in the first bit of a head bus ``head[0:4]``
|
||||
|
||||
- ``range`` indicates ``BL`` port to be controlled by this shift register chain. Multiple BL ports can be defined but the sequence matters. For example, ``bl[0:3], bl[6:10]`` infers a 9-bit shift register chain whose output ports are connected from ``bl[0]`` to ``bl[10]``.
|
||||
|
||||
.. note:: When creating the range, you must know the number of BLs in the configuration region
|
||||
|
||||
.. note:: ports must use ``bl`` as the reserved port name
|
||||
|
||||
|
||||
WL Shift Register Banks
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. note:: The customizable is only available when the shift-register-based memory bank is selected in :ref:`config_protocol`
|
||||
|
||||
Each Word-Line (WL) shift register bank is defined in the code block ``<wl_shift_register_banks>``.
|
||||
A shift register bank may contain multiple shift register chains.
|
||||
- each shift register chain can be defined using the ``bank`` syntax
|
||||
- the BLs controlled by each chain can be customized through the ``range`` syntax.
|
||||
|
||||
|
||||
.. option:: <bank id="<int>" range="<ports>"/>
|
||||
|
||||
- ``id`` indicates the sequence of the shift register chain in the bank. The id denotes the index in the head or tail bus. For example, ``id="0"`` means the head or tail of the shift register will be in the first bit of a head bus ``head[0:4]``
|
||||
|
||||
- ``range`` indicates ``WL`` port to be controlled by this shift register chain. Multiple WL ports can be defined but the sequence matters. For example, ``wl[0:3], wl[6:10]`` infers a 9-bit shift register chain whose output ports are connected from ``wl[0]`` to ``wl[10]``.
|
||||
|
||||
.. note:: When creating the range, you must know the number of BLs in the configuration region
|
||||
|
||||
.. note:: ports must use ``wl`` as the reserved port name
|
||||
|
||||
|
|
|
@ -77,6 +77,9 @@ write_fabric_bitstream
|
|||
|
||||
.. note:: If both reset and set ports are defined in the circuit modeling for programming, OpenFPGA will pick the one that will bring largest benefit in speeding up configuration.
|
||||
|
||||
.. option:: --keep_dont_care_bits
|
||||
|
||||
Keep don't care bits (``x``) in the outputted bitstream file. This is only applicable to plain text file format. If not enabled, the don't care bits are converted to either logic ``0`` or ``1``.
|
||||
|
||||
.. option:: --verbose
|
||||
|
||||
|
|
|
@ -326,6 +326,102 @@ size_t check_ccff_circuit_model_ports(const CircuitLibrary& circuit_lib,
|
|||
return num_err;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* A function to check the port map of CCFF circuit model used to control BLs
|
||||
* - Require 1 clock port
|
||||
* - Require 1 input port as data input (to be driven by other CCFF in a chain)
|
||||
* - Require 1 output port as data output (to drive other CCFF in a chain)
|
||||
* - Require 1 BL port as data output / inout (to drive/driven by BLs)
|
||||
***********************************************************************/
|
||||
size_t check_bl_ccff_circuit_model_ports(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model) {
|
||||
size_t num_err = 0;
|
||||
|
||||
/* Check the type of circuit model */
|
||||
VTR_ASSERT(CIRCUIT_MODEL_CCFF == circuit_lib.model_type(circuit_model));
|
||||
|
||||
/* Check if we have D, Set and Reset */
|
||||
/* We can have either 1 input which is D or 2 inputs which are D and scan input */
|
||||
size_t num_input_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_INPUT, true).size();
|
||||
if (1 != num_input_ports) {
|
||||
VTR_LOG_ERROR("Configuration flip-flop for BL shift register '%s' must have 1 %s port!\n",
|
||||
circuit_lib.model_name(circuit_model).c_str(),
|
||||
CIRCUIT_MODEL_PORT_TYPE_STRING[size_t(CIRCUIT_MODEL_PORT_INPUT)]);
|
||||
num_err++;
|
||||
}
|
||||
|
||||
num_err += check_one_circuit_model_port_type_and_size_required(circuit_lib, circuit_model,
|
||||
CIRCUIT_MODEL_PORT_INPUT,
|
||||
num_input_ports, 1, false);
|
||||
/* Check if we have a clock */
|
||||
num_err += check_one_circuit_model_port_type_and_size_required(circuit_lib, circuit_model,
|
||||
CIRCUIT_MODEL_PORT_CLOCK,
|
||||
1, 1, true);
|
||||
|
||||
|
||||
/* Check if we have 1 output*/
|
||||
num_err += check_one_circuit_model_port_type_and_size_required(circuit_lib, circuit_model,
|
||||
CIRCUIT_MODEL_PORT_OUTPUT,
|
||||
1, 1, false);
|
||||
|
||||
/* Check if we have 1 bl port */
|
||||
num_err += check_one_circuit_model_port_type_and_size_required(circuit_lib, circuit_model,
|
||||
CIRCUIT_MODEL_PORT_BL,
|
||||
1, 1, false);
|
||||
|
||||
return num_err;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* A function to check the port map of CCFF circuit model used to control WLs
|
||||
* - Require 1 clock port
|
||||
* - Require 1 input port as data input (to be driven by other CCFF in a chain)
|
||||
* - Require 1 output port as data output (to drive other CCFF in a chain)
|
||||
* - Require 1 WL port as data output (to drive WLs)
|
||||
* - Optionally require 1 WLR port as data output (to drive WLRs)
|
||||
***********************************************************************/
|
||||
size_t check_wl_ccff_circuit_model_ports(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model) {
|
||||
size_t num_err = 0;
|
||||
|
||||
/* Check the type of circuit model */
|
||||
VTR_ASSERT(CIRCUIT_MODEL_CCFF == circuit_lib.model_type(circuit_model));
|
||||
|
||||
/* Check if we have D, Set and Reset */
|
||||
/* We can have either 1 input which is D or 2 inputs which are D and scan input */
|
||||
size_t num_input_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_INPUT, true).size();
|
||||
if (1 != num_input_ports) {
|
||||
VTR_LOG_ERROR("Configuration flip-flop for WL shift register '%s' must have 1 %s port!\n",
|
||||
circuit_lib.model_name(circuit_model).c_str(),
|
||||
CIRCUIT_MODEL_PORT_TYPE_STRING[size_t(CIRCUIT_MODEL_PORT_INPUT)]);
|
||||
num_err++;
|
||||
}
|
||||
|
||||
num_err += check_one_circuit_model_port_type_and_size_required(circuit_lib, circuit_model,
|
||||
CIRCUIT_MODEL_PORT_INPUT,
|
||||
num_input_ports, 1, false);
|
||||
/* Check if we have two clock: 1 for write-enable, 1 for shift register */
|
||||
num_err += check_one_circuit_model_port_type_and_size_required(circuit_lib, circuit_model,
|
||||
CIRCUIT_MODEL_PORT_CLOCK,
|
||||
2, 1, true);
|
||||
|
||||
|
||||
/* Check if we have 1 output*/
|
||||
num_err += check_one_circuit_model_port_type_and_size_required(circuit_lib, circuit_model,
|
||||
CIRCUIT_MODEL_PORT_OUTPUT,
|
||||
1, 1, false);
|
||||
|
||||
/* Check if we have 1 wl port */
|
||||
if (0 < circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_WLR, true).size()) {
|
||||
num_err += check_one_circuit_model_port_type_and_size_required(circuit_lib, circuit_model,
|
||||
CIRCUIT_MODEL_PORT_WLR,
|
||||
1, 1, false);
|
||||
}
|
||||
|
||||
return num_err;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* A function to check the port map of SRAM circuit model
|
||||
***********************************************************************/
|
||||
|
|
|
@ -39,6 +39,12 @@ size_t check_ff_circuit_model_ports(const CircuitLibrary& circuit_lib,
|
|||
size_t check_ccff_circuit_model_ports(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model);
|
||||
|
||||
size_t check_bl_ccff_circuit_model_ports(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model);
|
||||
|
||||
size_t check_wl_ccff_circuit_model_ports(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model);
|
||||
|
||||
size_t check_sram_circuit_model_ports(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const bool& check_blwl);
|
||||
|
|
|
@ -949,7 +949,6 @@ bool CircuitLibrary::port_is_config_enable(const CircuitPortId& circuit_port_id)
|
|||
return port_is_config_enable_[circuit_port_id];
|
||||
}
|
||||
|
||||
|
||||
/* Return a flag if the port is used during programming a FPGA in a circuit model */
|
||||
bool CircuitLibrary::port_is_prog(const CircuitPortId& circuit_port_id) const {
|
||||
/* validate the circuit_port_id */
|
||||
|
@ -957,6 +956,13 @@ bool CircuitLibrary::port_is_prog(const CircuitPortId& circuit_port_id) const {
|
|||
return port_is_prog_[circuit_port_id];
|
||||
}
|
||||
|
||||
/* Return a flag if the port is used by shift register in a circuit model */
|
||||
bool CircuitLibrary::port_is_shift_register(const CircuitPortId& circuit_port_id) const {
|
||||
/* validate the circuit_port_id */
|
||||
VTR_ASSERT(valid_circuit_port_id(circuit_port_id));
|
||||
return port_is_shift_register_[circuit_port_id];
|
||||
}
|
||||
|
||||
/* Return which level the output port locates at a LUT multiplexing structure */
|
||||
size_t CircuitLibrary::port_lut_frac_level(const CircuitPortId& circuit_port_id) const {
|
||||
/* validate the circuit_port_id */
|
||||
|
@ -1170,7 +1176,7 @@ CircuitModelId CircuitLibrary::add_model(const enum e_circuit_model_type& type)
|
|||
|
||||
/* Pass-gate-related parameters */
|
||||
pass_gate_logic_model_names_.emplace_back();
|
||||
pass_gate_logic_model_ids_.emplace_back();
|
||||
pass_gate_logic_model_ids_.emplace_back(CircuitModelId::INVALID());
|
||||
|
||||
/* Delay information */
|
||||
delay_types_.emplace_back();
|
||||
|
@ -1401,6 +1407,7 @@ CircuitPortId CircuitLibrary::add_model_port(const CircuitModelId& model_id,
|
|||
port_is_set_.push_back(false);
|
||||
port_is_config_enable_.push_back(false);
|
||||
port_is_prog_.push_back(false);
|
||||
port_is_shift_register_.push_back(false);
|
||||
port_tri_state_model_names_.emplace_back();
|
||||
port_tri_state_model_ids_.push_back(CircuitModelId::INVALID());
|
||||
port_inv_model_names_.emplace_back();
|
||||
|
@ -1538,6 +1545,15 @@ void CircuitLibrary::set_port_is_prog(const CircuitPortId& circuit_port_id,
|
|||
return;
|
||||
}
|
||||
|
||||
/* Set the is_prog for a port of a circuit model */
|
||||
void CircuitLibrary::set_port_is_shift_register(const CircuitPortId& circuit_port_id,
|
||||
const bool& is_shift_register) {
|
||||
/* validate the circuit_port_id */
|
||||
VTR_ASSERT(valid_circuit_port_id(circuit_port_id));
|
||||
port_is_shift_register_[circuit_port_id] = is_shift_register;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set the model_name for a port of a circuit model */
|
||||
void CircuitLibrary::set_port_tri_state_model_name(const CircuitPortId& circuit_port_id,
|
||||
const std::string& model_name) {
|
||||
|
|
|
@ -288,6 +288,7 @@ class CircuitLibrary {
|
|||
bool port_is_set(const CircuitPortId& circuit_port_id) const;
|
||||
bool port_is_config_enable(const CircuitPortId& circuit_port_id) const;
|
||||
bool port_is_prog(const CircuitPortId& circuit_port_id) const;
|
||||
bool port_is_shift_register(const CircuitPortId& circuit_port_id) const;
|
||||
size_t port_lut_frac_level(const CircuitPortId& circuit_port_id) const;
|
||||
bool port_is_harden_lut_port(const CircuitPortId& circuit_port_id) const;
|
||||
std::vector<size_t> port_lut_output_mask(const CircuitPortId& circuit_port_id) const;
|
||||
|
@ -372,6 +373,8 @@ class CircuitLibrary {
|
|||
const bool& is_config_enable);
|
||||
void set_port_is_prog(const CircuitPortId& circuit_port_id,
|
||||
const bool& is_prog);
|
||||
void set_port_is_shift_register(const CircuitPortId& circuit_port_id,
|
||||
const bool& is_shift_register);
|
||||
void set_port_tri_state_model_name(const CircuitPortId& circuit_port_id,
|
||||
const std::string& model_name);
|
||||
void set_port_tri_state_model_id(const CircuitPortId& circuit_port_id,
|
||||
|
@ -560,6 +563,7 @@ class CircuitLibrary {
|
|||
vtr::vector<CircuitPortId, bool> port_is_set_;
|
||||
vtr::vector<CircuitPortId, bool> port_is_config_enable_;
|
||||
vtr::vector<CircuitPortId, bool> port_is_prog_;
|
||||
vtr::vector<CircuitPortId, bool> port_is_shift_register_;
|
||||
vtr::vector<CircuitPortId, std::string> port_tri_state_model_names_;
|
||||
vtr::vector<CircuitPortId, CircuitModelId> port_tri_state_model_ids_;
|
||||
vtr::vector<CircuitPortId, std::string> port_inv_model_names_;
|
||||
|
|
|
@ -101,10 +101,11 @@ enum e_circuit_model_port_type {
|
|||
CIRCUIT_MODEL_PORT_BLB,
|
||||
CIRCUIT_MODEL_PORT_WL,
|
||||
CIRCUIT_MODEL_PORT_WLB,
|
||||
CIRCUIT_MODEL_PORT_WLR,
|
||||
NUM_CIRCUIT_MODEL_PORT_TYPES
|
||||
};
|
||||
/* Strings correspond to each port type */
|
||||
constexpr std::array<const char*, NUM_CIRCUIT_MODEL_PORT_TYPES> CIRCUIT_MODEL_PORT_TYPE_STRING = {{"input", "output", "inout", "clock", "sram", "bl", "blb", "wl", "wlb"}};
|
||||
constexpr std::array<const char*, NUM_CIRCUIT_MODEL_PORT_TYPES> CIRCUIT_MODEL_PORT_TYPE_STRING = {{"input", "output", "inout", "clock", "sram", "bl", "blb", "wl", "wlb", "wlr"}};
|
||||
|
||||
enum e_circuit_model_delay_type {
|
||||
CIRCUIT_MODEL_DELAY_RISE,
|
||||
|
@ -125,10 +126,11 @@ enum e_config_protocol_type {
|
|||
CONFIG_MEM_STANDALONE,
|
||||
CONFIG_MEM_SCAN_CHAIN,
|
||||
CONFIG_MEM_MEMORY_BANK,
|
||||
CONFIG_MEM_QL_MEMORY_BANK,
|
||||
CONFIG_MEM_FRAME_BASED,
|
||||
NUM_CONFIG_PROTOCOL_TYPES
|
||||
};
|
||||
|
||||
constexpr std::array<const char*, NUM_CONFIG_PROTOCOL_TYPES> CONFIG_PROTOCOL_TYPE_STRING = {{"standalone", "scan_chain", "memory_bank", "frame_based"}};
|
||||
constexpr std::array<const char*, NUM_CONFIG_PROTOCOL_TYPES> CONFIG_PROTOCOL_TYPE_STRING = {{"standalone", "scan_chain", "memory_bank", "ql_memory_bank", "frame_based"}};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "vtr_assert.h"
|
||||
#include "vtr_log.h"
|
||||
|
||||
#include "config_protocol.h"
|
||||
|
||||
|
@ -32,6 +33,38 @@ int ConfigProtocol::num_regions() const {
|
|||
return num_regions_;
|
||||
}
|
||||
|
||||
e_blwl_protocol_type ConfigProtocol::bl_protocol_type() const {
|
||||
return bl_protocol_type_;
|
||||
}
|
||||
|
||||
std::string ConfigProtocol::bl_memory_model_name() const {
|
||||
return bl_memory_model_name_;
|
||||
}
|
||||
|
||||
CircuitModelId ConfigProtocol::bl_memory_model() const {
|
||||
return bl_memory_model_;
|
||||
}
|
||||
|
||||
size_t ConfigProtocol::bl_num_banks() const {
|
||||
return bl_num_banks_;
|
||||
}
|
||||
|
||||
e_blwl_protocol_type ConfigProtocol::wl_protocol_type() const {
|
||||
return wl_protocol_type_;
|
||||
}
|
||||
|
||||
std::string ConfigProtocol::wl_memory_model_name() const {
|
||||
return wl_memory_model_name_;
|
||||
}
|
||||
|
||||
CircuitModelId ConfigProtocol::wl_memory_model() const {
|
||||
return wl_memory_model_;
|
||||
}
|
||||
|
||||
size_t ConfigProtocol::wl_num_banks() const {
|
||||
return wl_num_banks_;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Public Mutators
|
||||
***********************************************************************/
|
||||
|
@ -50,3 +83,69 @@ void ConfigProtocol::set_memory_model(const CircuitModelId& memory_model) {
|
|||
void ConfigProtocol::set_num_regions(const int& num_regions) {
|
||||
num_regions_ = num_regions;
|
||||
}
|
||||
|
||||
void ConfigProtocol::set_bl_protocol_type(const e_blwl_protocol_type& type) {
|
||||
if (CONFIG_MEM_QL_MEMORY_BANK != type_) {
|
||||
VTR_LOG_ERROR("BL protocol type is only applicable for configuration protocol '%d'", CONFIG_PROTOCOL_TYPE_STRING[type_]);
|
||||
return;
|
||||
}
|
||||
bl_protocol_type_ = type;
|
||||
}
|
||||
|
||||
void ConfigProtocol::set_bl_memory_model_name(const std::string& memory_model_name) {
|
||||
if (BLWL_PROTOCOL_SHIFT_REGISTER != bl_protocol_type_) {
|
||||
VTR_LOG_ERROR("BL protocol memory model is only applicable when '%d' is defined", BLWL_PROTOCOL_TYPE_STRING[bl_protocol_type_]);
|
||||
return;
|
||||
}
|
||||
bl_memory_model_name_ = memory_model_name;
|
||||
}
|
||||
|
||||
void ConfigProtocol::set_bl_memory_model(const CircuitModelId& memory_model) {
|
||||
if (BLWL_PROTOCOL_SHIFT_REGISTER != bl_protocol_type_) {
|
||||
VTR_LOG_ERROR("BL protocol memory model is only applicable when '%d' is defined", BLWL_PROTOCOL_TYPE_STRING[bl_protocol_type_]);
|
||||
return;
|
||||
}
|
||||
bl_memory_model_ = memory_model;
|
||||
}
|
||||
|
||||
void ConfigProtocol::set_bl_num_banks(const size_t& num_banks) {
|
||||
if (BLWL_PROTOCOL_SHIFT_REGISTER != bl_protocol_type_) {
|
||||
VTR_LOG_ERROR("BL protocol memory model is only applicable when '%d' is defined", BLWL_PROTOCOL_TYPE_STRING[bl_protocol_type_]);
|
||||
return;
|
||||
}
|
||||
bl_num_banks_ = num_banks;
|
||||
}
|
||||
|
||||
|
||||
void ConfigProtocol::set_wl_protocol_type(const e_blwl_protocol_type& type) {
|
||||
if (CONFIG_MEM_QL_MEMORY_BANK != type_) {
|
||||
VTR_LOG_ERROR("WL protocol type is only applicable for configuration protocol '%d'", CONFIG_PROTOCOL_TYPE_STRING[type_]);
|
||||
return;
|
||||
}
|
||||
wl_protocol_type_ = type;
|
||||
}
|
||||
|
||||
void ConfigProtocol::set_wl_memory_model_name(const std::string& memory_model_name) {
|
||||
if (BLWL_PROTOCOL_SHIFT_REGISTER != wl_protocol_type_) {
|
||||
VTR_LOG_ERROR("WL protocol memory model is only applicable when '%d' is defined", BLWL_PROTOCOL_TYPE_STRING[wl_protocol_type_]);
|
||||
return;
|
||||
}
|
||||
wl_memory_model_name_ = memory_model_name;
|
||||
}
|
||||
|
||||
void ConfigProtocol::set_wl_memory_model(const CircuitModelId& memory_model) {
|
||||
if (BLWL_PROTOCOL_SHIFT_REGISTER != wl_protocol_type_) {
|
||||
VTR_LOG_ERROR("WL protocol memory model is only applicable when '%d' is defined", BLWL_PROTOCOL_TYPE_STRING[wl_protocol_type_]);
|
||||
return;
|
||||
}
|
||||
wl_memory_model_ = memory_model;
|
||||
}
|
||||
|
||||
void ConfigProtocol::set_wl_num_banks(const size_t& num_banks) {
|
||||
if (BLWL_PROTOCOL_SHIFT_REGISTER != wl_protocol_type_) {
|
||||
VTR_LOG_ERROR("WL protocol memory model is only applicable when '%d' is defined", BLWL_PROTOCOL_TYPE_STRING[wl_protocol_type_]);
|
||||
return;
|
||||
}
|
||||
wl_num_banks_ = num_banks;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,15 @@
|
|||
#include "circuit_types.h"
|
||||
#include "circuit_library_fwd.h"
|
||||
|
||||
/* Data type to define the protocol through which BL/WL can be manipulated */
|
||||
enum e_blwl_protocol_type {
|
||||
BLWL_PROTOCOL_FLATTEN,
|
||||
BLWL_PROTOCOL_DECODER,
|
||||
BLWL_PROTOCOL_SHIFT_REGISTER,
|
||||
NUM_BLWL_PROTOCOL_TYPES
|
||||
};
|
||||
constexpr std::array<const char*, NUM_BLWL_PROTOCOL_TYPES> BLWL_PROTOCOL_TYPE_STRING = {{"flatten", "decoder", "shift_register"}};
|
||||
|
||||
/********************************************************************
|
||||
* A data structure to store configuration protocol information
|
||||
*******************************************************************/
|
||||
|
@ -16,11 +25,29 @@ class ConfigProtocol {
|
|||
std::string memory_model_name() const;
|
||||
CircuitModelId memory_model() const;
|
||||
int num_regions() const;
|
||||
|
||||
e_blwl_protocol_type bl_protocol_type() const;
|
||||
std::string bl_memory_model_name() const;
|
||||
CircuitModelId bl_memory_model() const;
|
||||
size_t bl_num_banks() const;
|
||||
e_blwl_protocol_type wl_protocol_type() const;
|
||||
std::string wl_memory_model_name() const;
|
||||
CircuitModelId wl_memory_model() const;
|
||||
size_t wl_num_banks() const;
|
||||
public: /* Public Mutators */
|
||||
void set_type(const e_config_protocol_type& type);
|
||||
void set_memory_model_name(const std::string& memory_model_name);
|
||||
void set_memory_model(const CircuitModelId& memory_model);
|
||||
void set_num_regions(const int& num_regions);
|
||||
|
||||
void set_bl_protocol_type(const e_blwl_protocol_type& type);
|
||||
void set_bl_memory_model_name(const std::string& memory_model_name);
|
||||
void set_bl_memory_model(const CircuitModelId& memory_model);
|
||||
void set_bl_num_banks(const size_t& num_banks);
|
||||
void set_wl_protocol_type(const e_blwl_protocol_type& type);
|
||||
void set_wl_memory_model_name(const std::string& memory_model_name);
|
||||
void set_wl_memory_model(const CircuitModelId& memory_model);
|
||||
void set_wl_num_banks(const size_t& num_banks);
|
||||
private: /* Internal data */
|
||||
/* The type of configuration protocol.
|
||||
* In other words, it is about how to organize and access each configurable memory
|
||||
|
@ -33,6 +60,23 @@ class ConfigProtocol {
|
|||
|
||||
/* Number of configurable regions */
|
||||
int num_regions_;
|
||||
|
||||
/* BL & WL protocol: This is only applicable to memory-bank configuration protocols
|
||||
* - type: defines which protocol to be used. By default, we consider decoders
|
||||
* - bl/wl_memory_model: defines the circuit model to be used when building shift register chains for BL/WL configuration.
|
||||
* It must be a valid CCFF circuit model. This is only applicable when shift-register protocol is selected
|
||||
* for BL or WL.
|
||||
* - bl/wl_num_banks: defines the number of independent shift register chains (with separated head and tail ports)
|
||||
* for a given BL protocol per configuration region
|
||||
*/
|
||||
e_blwl_protocol_type bl_protocol_type_ = BLWL_PROTOCOL_DECODER;
|
||||
std::string bl_memory_model_name_;
|
||||
CircuitModelId bl_memory_model_;
|
||||
size_t bl_num_banks_;
|
||||
e_blwl_protocol_type wl_protocol_type_ = BLWL_PROTOCOL_DECODER;
|
||||
std::string wl_memory_model_name_;
|
||||
CircuitModelId wl_memory_model_;
|
||||
size_t wl_num_banks_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -22,6 +22,29 @@ void link_config_protocol_to_circuit_library(openfpga::Arch& openfpga_arch) {
|
|||
}
|
||||
|
||||
openfpga_arch.config_protocol.set_memory_model(config_memory_model);
|
||||
|
||||
/* Optional: we need to bind the memory model for BL/WL protocols */
|
||||
if (!openfpga_arch.config_protocol.bl_memory_model_name().empty()) {
|
||||
CircuitModelId bl_memory_model = openfpga_arch.circuit_lib.model(openfpga_arch.config_protocol.bl_memory_model_name());
|
||||
/* Error out if the circuit model id is invalid */
|
||||
if (CircuitModelId::INVALID() == bl_memory_model) {
|
||||
VTR_LOG("Invalid bl memory model name '%s' defined in <configuration_protocol>!",
|
||||
openfpga_arch.config_protocol.bl_memory_model_name().c_str());
|
||||
exit(1);
|
||||
}
|
||||
openfpga_arch.config_protocol.set_bl_memory_model(bl_memory_model);
|
||||
}
|
||||
|
||||
if (!openfpga_arch.config_protocol.wl_memory_model_name().empty()) {
|
||||
CircuitModelId wl_memory_model = openfpga_arch.circuit_lib.model(openfpga_arch.config_protocol.wl_memory_model_name());
|
||||
/* Error out if the circuit model id is invalid */
|
||||
if (CircuitModelId::INVALID() == wl_memory_model) {
|
||||
VTR_LOG("Invalid wl memory model name '%s' defined in <configuration_protocol>!",
|
||||
openfpga_arch.config_protocol.wl_memory_model_name().c_str());
|
||||
exit(1);
|
||||
}
|
||||
openfpga_arch.config_protocol.set_wl_memory_model(wl_memory_model);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
|
|
|
@ -484,6 +484,9 @@ void read_xml_circuit_port(pugi::xml_node& xml_port,
|
|||
/* Identify if the port is in programming purpose, by default it is NOT */
|
||||
circuit_lib.set_port_is_prog(port, get_attribute(xml_port, "is_prog", loc_data, pugiutil::ReqOpt::OPTIONAL).as_bool(false));
|
||||
|
||||
/* Identify if the port is in shift register purpose, by default it is NOT */
|
||||
circuit_lib.set_port_is_shift_register(port, get_attribute(xml_port, "is_shift_register", loc_data, pugiutil::ReqOpt::OPTIONAL).as_bool(false));
|
||||
|
||||
/* Identify if the port is to enable programming for FPGAs, by default it is NOT */
|
||||
circuit_lib.set_port_is_config_enable(port, get_attribute(xml_port, "is_config_enable", loc_data, pugiutil::ReqOpt::OPTIONAL).as_bool(false));
|
||||
|
||||
|
|
|
@ -33,6 +33,81 @@ e_config_protocol_type string_to_config_protocol_type(const std::string& type_st
|
|||
return NUM_CONFIG_PROTOCOL_TYPES;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Convert string to the enumerate of BL/WL protocol type
|
||||
*******************************************************************/
|
||||
static
|
||||
e_blwl_protocol_type string_to_blwl_protocol_type(const std::string& type_string) {
|
||||
|
||||
for (size_t itype = 0; itype < NUM_BLWL_PROTOCOL_TYPES; ++itype) {
|
||||
if (std::string(BLWL_PROTOCOL_TYPE_STRING[itype]) == type_string) {
|
||||
return static_cast<e_blwl_protocol_type>(itype);
|
||||
}
|
||||
}
|
||||
|
||||
return NUM_BLWL_PROTOCOL_TYPES;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Parse XML codes of a <bl> to an object of configuration protocol
|
||||
*******************************************************************/
|
||||
static
|
||||
void read_xml_bl_protocol(pugi::xml_node& xml_bl_protocol,
|
||||
const pugiutil::loc_data& loc_data,
|
||||
ConfigProtocol& config_protocol) {
|
||||
/* Find the type of configuration protocol */
|
||||
const char* type_attr = get_attribute(xml_bl_protocol, "protocol", loc_data).value();
|
||||
/* Translate the type of design technology to enumerate */
|
||||
e_blwl_protocol_type blwl_protocol_type = string_to_blwl_protocol_type(std::string(type_attr));
|
||||
|
||||
if (NUM_BLWL_PROTOCOL_TYPES == blwl_protocol_type) {
|
||||
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_bl_protocol),
|
||||
"Invalid 'protocol' attribute '%s'\n",
|
||||
type_attr);
|
||||
}
|
||||
|
||||
config_protocol.set_bl_protocol_type(blwl_protocol_type);
|
||||
|
||||
/* only applicable to shift-registor protocol
|
||||
* - Find the memory model to build shift register chains
|
||||
* - Find the number of shift register chains for each protocol
|
||||
*/
|
||||
if (BLWL_PROTOCOL_SHIFT_REGISTER == blwl_protocol_type) {
|
||||
config_protocol.set_bl_memory_model_name(get_attribute(xml_bl_protocol, "circuit_model_name", loc_data).as_string());
|
||||
config_protocol.set_bl_num_banks(get_attribute(xml_bl_protocol, "num_banks", loc_data, pugiutil::ReqOpt::OPTIONAL).as_int(1));
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Parse XML codes of a <wl> to an object of configuration protocol
|
||||
*******************************************************************/
|
||||
static
|
||||
void read_xml_wl_protocol(pugi::xml_node& xml_wl_protocol,
|
||||
const pugiutil::loc_data& loc_data,
|
||||
ConfigProtocol& config_protocol) {
|
||||
/* Find the type of configuration protocol */
|
||||
const char* type_attr = get_attribute(xml_wl_protocol, "protocol", loc_data).value();
|
||||
/* Translate the type of design technology to enumerate */
|
||||
e_blwl_protocol_type blwl_protocol_type = string_to_blwl_protocol_type(std::string(type_attr));
|
||||
|
||||
if (NUM_BLWL_PROTOCOL_TYPES == blwl_protocol_type) {
|
||||
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_wl_protocol),
|
||||
"Invalid 'protocol' attribute '%s'\n",
|
||||
type_attr);
|
||||
}
|
||||
|
||||
config_protocol.set_wl_protocol_type(blwl_protocol_type);
|
||||
|
||||
/* only applicable to shift-registor protocol
|
||||
* - Find the memory model to build shift register chains
|
||||
* - Find the number of shift register chains for each protocol
|
||||
*/
|
||||
if (BLWL_PROTOCOL_SHIFT_REGISTER == blwl_protocol_type) {
|
||||
config_protocol.set_wl_memory_model_name(get_attribute(xml_wl_protocol, "circuit_model_name", loc_data).as_string());
|
||||
config_protocol.set_wl_num_banks(get_attribute(xml_wl_protocol, "num_banks", loc_data, pugiutil::ReqOpt::OPTIONAL).as_int(1));
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Parse XML codes of a <organization> to an object of configuration protocol
|
||||
*******************************************************************/
|
||||
|
@ -65,6 +140,25 @@ void read_xml_config_organization(pugi::xml_node& xml_config_orgz,
|
|||
"Invalid 'num_region=%d' definition. At least 1 region should be defined!\n",
|
||||
config_protocol.num_regions());
|
||||
}
|
||||
|
||||
/* Parse BL & WL protocols */
|
||||
if (config_protocol.type() == CONFIG_MEM_QL_MEMORY_BANK) {
|
||||
pugi::xml_node xml_bl_protocol = get_single_child(xml_config_orgz, "bl", loc_data, pugiutil::ReqOpt::OPTIONAL);
|
||||
if (xml_bl_protocol) {
|
||||
read_xml_bl_protocol(xml_bl_protocol, loc_data, config_protocol);
|
||||
}
|
||||
|
||||
pugi::xml_node xml_wl_protocol = get_single_child(xml_config_orgz, "wl", loc_data, pugiutil::ReqOpt::OPTIONAL);
|
||||
if (xml_wl_protocol) {
|
||||
read_xml_wl_protocol(xml_wl_protocol, loc_data, config_protocol);
|
||||
}
|
||||
|
||||
/* Throw an execption if the BL/WL protocols are different. We currently do not support it! */
|
||||
if (config_protocol.bl_protocol_type() != config_protocol.wl_protocol_type()) {
|
||||
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_config_orgz),
|
||||
"Expect same type of protocol for both BL and WL! Other combinations are not supported yet\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
|
|
|
@ -36,7 +36,7 @@ e_sim_accuracy_type string_to_sim_accuracy_type(const std::string& type_string)
|
|||
}
|
||||
|
||||
/********************************************************************
|
||||
* Parse XML codes of a <clock> line to an object of simulation setting
|
||||
* Parse XML codes of a <clock> line under <operating> to an object of simulation setting
|
||||
*******************************************************************/
|
||||
static
|
||||
void read_xml_operating_clock_override_setting(pugi::xml_node& xml_clock_override_setting,
|
||||
|
@ -62,6 +62,40 @@ void read_xml_operating_clock_override_setting(pugi::xml_node& xml_clock_overrid
|
|||
sim_setting.set_clock_frequency(clock_id, get_attribute(xml_clock_override_setting, "frequency", loc_data).as_float(0.));
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Parse XML codes of a <clock> line under <programming> to an object of simulation setting
|
||||
*******************************************************************/
|
||||
static
|
||||
void read_xml_programming_clock_override_setting(pugi::xml_node& xml_clock_override_setting,
|
||||
const pugiutil::loc_data& loc_data,
|
||||
openfpga::SimulationSetting& sim_setting) {
|
||||
std::string clock_name = get_attribute(xml_clock_override_setting, "name", loc_data).as_string();
|
||||
|
||||
/* Create a new clock override object in the sim_setting object with the given name */
|
||||
SimulationClockId clock_id = sim_setting.create_clock(clock_name);
|
||||
|
||||
/* Report if the clock creation failed, this is due to a conflicts in naming*/
|
||||
if (false == sim_setting.valid_clock_id(clock_id)) {
|
||||
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_clock_override_setting),
|
||||
"Fail to create simulation clock '%s', it may share the same name as other simulation clock definition!\n",
|
||||
clock_name.c_str());
|
||||
}
|
||||
|
||||
/* Parse port information */
|
||||
openfpga::PortParser clock_port_parser(get_attribute(xml_clock_override_setting, "port", loc_data).as_string());
|
||||
sim_setting.set_clock_port(clock_id, clock_port_parser.port());
|
||||
|
||||
/* Parse frequency information */
|
||||
std::string clock_freq_str = get_attribute(xml_clock_override_setting, "frequency", loc_data).as_string();
|
||||
if (std::string("auto") != clock_freq_str) {
|
||||
sim_setting.set_clock_frequency(clock_id, get_attribute(xml_clock_override_setting, "frequency", loc_data).as_float(0.));
|
||||
}
|
||||
|
||||
sim_setting.set_clock_is_programming(clock_id, true);
|
||||
|
||||
sim_setting.set_clock_is_shift_register(clock_id, get_attribute(xml_clock_override_setting, "is_shift_register", loc_data).as_bool(false));
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Parse XML codes of a <clock_setting> to an object of simulation setting
|
||||
*******************************************************************/
|
||||
|
@ -102,6 +136,15 @@ void read_xml_clock_setting(pugi::xml_node& xml_clock_setting,
|
|||
pugi::xml_node xml_programming_clock_setting = get_single_child(xml_clock_setting, "programming", loc_data);
|
||||
|
||||
sim_setting.set_programming_clock_frequency(get_attribute(xml_programming_clock_setting, "frequency", loc_data).as_float(0.));
|
||||
|
||||
/* Iterate over multiple operating clock settings and parse one by one */
|
||||
for (pugi::xml_node xml_clock : xml_programming_clock_setting.children()) {
|
||||
/* Error out if the XML child has an invalid name! */
|
||||
if (xml_clock.name() != std::string("clock")) {
|
||||
bad_tag(xml_clock, loc_data, xml_programming_clock_setting, {"clock"});
|
||||
}
|
||||
read_xml_programming_clock_override_setting(xml_clock, loc_data, sim_setting);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
|
|
|
@ -16,6 +16,36 @@ SimulationSetting::simulation_clock_range SimulationSetting::clocks() const {
|
|||
return vtr::make_range(clock_ids_.begin(), clock_ids_.end());
|
||||
}
|
||||
|
||||
std::vector<SimulationClockId> SimulationSetting::operating_clocks() const {
|
||||
std::vector<SimulationClockId> op_clks;
|
||||
for (const SimulationClockId& clk : clocks()) {
|
||||
if (!clock_is_programming(clk)) {
|
||||
op_clks.push_back(clk);
|
||||
}
|
||||
}
|
||||
return op_clks;
|
||||
}
|
||||
|
||||
std::vector<SimulationClockId> SimulationSetting::programming_clocks() const {
|
||||
std::vector<SimulationClockId> prog_clks;
|
||||
for (const SimulationClockId& clk : clocks()) {
|
||||
if (clock_is_programming(clk)) {
|
||||
prog_clks.push_back(clk);
|
||||
}
|
||||
}
|
||||
return prog_clks;
|
||||
}
|
||||
|
||||
std::vector<SimulationClockId> SimulationSetting::programming_shift_register_clocks() const {
|
||||
std::vector<SimulationClockId> prog_clks;
|
||||
for (const SimulationClockId& clk : clocks()) {
|
||||
if (clock_is_programming(clk) && clock_is_shift_register(clk)) {
|
||||
prog_clks.push_back(clk);
|
||||
}
|
||||
}
|
||||
return prog_clks;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Constructors
|
||||
***********************************************************************/
|
||||
|
@ -53,6 +83,16 @@ float SimulationSetting::clock_frequency(const SimulationClockId& clock_id) cons
|
|||
return clock_frequencies_[clock_id];
|
||||
}
|
||||
|
||||
bool SimulationSetting::clock_is_programming(const SimulationClockId& clock_id) const {
|
||||
VTR_ASSERT(valid_clock_id(clock_id));
|
||||
return clock_is_programming_[clock_id];
|
||||
}
|
||||
|
||||
bool SimulationSetting::clock_is_shift_register(const SimulationClockId& clock_id) const {
|
||||
VTR_ASSERT(valid_clock_id(clock_id));
|
||||
return clock_is_shift_register_[clock_id];
|
||||
}
|
||||
|
||||
bool SimulationSetting::auto_select_num_clock_cycles() const {
|
||||
return 0 == num_clock_cycles_;
|
||||
}
|
||||
|
@ -157,6 +197,8 @@ SimulationClockId SimulationSetting::create_clock(const std::string& name) {
|
|||
clock_names_.push_back(name);
|
||||
clock_ports_.emplace_back();
|
||||
clock_frequencies_.push_back(0.);
|
||||
clock_is_programming_.push_back(false);
|
||||
clock_is_shift_register_.push_back(false);
|
||||
|
||||
/* Register in the name-to-id map */
|
||||
clock_name2ids_[name] = clock_id;
|
||||
|
@ -176,6 +218,18 @@ void SimulationSetting::set_clock_frequency(const SimulationClockId& clock_id,
|
|||
clock_frequencies_[clock_id] = frequency;
|
||||
}
|
||||
|
||||
void SimulationSetting::set_clock_is_programming(const SimulationClockId& clock_id,
|
||||
const float& is_prog) {
|
||||
VTR_ASSERT(valid_clock_id(clock_id));
|
||||
clock_is_programming_[clock_id] = is_prog;
|
||||
}
|
||||
|
||||
void SimulationSetting::set_clock_is_shift_register(const SimulationClockId& clock_id,
|
||||
const float& is_sr) {
|
||||
VTR_ASSERT(valid_clock_id(clock_id));
|
||||
clock_is_shift_register_[clock_id] = is_sr;
|
||||
}
|
||||
|
||||
void SimulationSetting::set_num_clock_cycles(const size_t& num_clk_cycles) {
|
||||
num_clock_cycles_ = num_clk_cycles;
|
||||
}
|
||||
|
@ -274,5 +328,9 @@ bool SimulationSetting::valid_clock_id(const SimulationClockId& clock_id) const
|
|||
return ( size_t(clock_id) < clock_ids_.size() ) && ( clock_id == clock_ids_[clock_id] );
|
||||
}
|
||||
|
||||
bool SimulationSetting::constrained_clock(const SimulationClockId& clock_id) const {
|
||||
VTR_ASSERT(valid_clock_id(clock_id));
|
||||
return 0. != clock_frequencies_[clock_id];
|
||||
}
|
||||
|
||||
} /* namespace openfpga ends */
|
||||
|
|
|
@ -62,6 +62,9 @@ class SimulationSetting {
|
|||
SimulationSetting();
|
||||
public: /* Accessors: aggregates */
|
||||
simulation_clock_range clocks() const;
|
||||
std::vector<SimulationClockId> operating_clocks() const;
|
||||
std::vector<SimulationClockId> programming_clocks() const;
|
||||
std::vector<SimulationClockId> programming_shift_register_clocks() const;
|
||||
public: /* Public Accessors */
|
||||
float default_operating_clock_frequency() const;
|
||||
float programming_clock_frequency() const;
|
||||
|
@ -69,6 +72,8 @@ class SimulationSetting {
|
|||
std::string clock_name(const SimulationClockId& clock_id) const;
|
||||
BasicPort clock_port(const SimulationClockId& clock_id) const;
|
||||
float clock_frequency(const SimulationClockId& clock_id) const;
|
||||
bool clock_is_programming(const SimulationClockId& clock_id) const;
|
||||
bool clock_is_shift_register(const SimulationClockId& clock_id) const;
|
||||
bool auto_select_num_clock_cycles() const;
|
||||
size_t num_clock_cycles() const;
|
||||
float operating_clock_frequency_slack() const;
|
||||
|
@ -102,6 +107,10 @@ class SimulationSetting {
|
|||
const BasicPort& port);
|
||||
void set_clock_frequency(const SimulationClockId& clock_id,
|
||||
const float& frequency);
|
||||
void set_clock_is_programming(const SimulationClockId& clock_id,
|
||||
const float& is_prog);
|
||||
void set_clock_is_shift_register(const SimulationClockId& clock_id,
|
||||
const float& is_sr);
|
||||
void set_num_clock_cycles(const size_t& num_clk_cycles);
|
||||
void set_operating_clock_frequency_slack(const float& op_clk_freq_slack);
|
||||
void set_simulation_temperature(const float& sim_temp);
|
||||
|
@ -130,6 +139,8 @@ class SimulationSetting {
|
|||
public: /* Public Validators */
|
||||
bool valid_signal_threshold(const float& threshold) const;
|
||||
bool valid_clock_id(const SimulationClockId& clock_id) const;
|
||||
/** @brief Validate if a given clock is constrained or not */
|
||||
bool constrained_clock(const SimulationClockId& clock_id) const;
|
||||
private: /* Internal data */
|
||||
/* Operating clock frequency: the default clock frequency to be applied to users' implemetation on FPGA
|
||||
* This will be stored in the x() part of vtr::Point
|
||||
|
@ -150,6 +161,8 @@ class SimulationSetting {
|
|||
vtr::vector<SimulationClockId, std::string> clock_names_;
|
||||
vtr::vector<SimulationClockId, BasicPort> clock_ports_;
|
||||
vtr::vector<SimulationClockId, float> clock_frequencies_;
|
||||
vtr::vector<SimulationClockId, bool> clock_is_programming_;
|
||||
vtr::vector<SimulationClockId, bool> clock_is_shift_register_;
|
||||
|
||||
/* Fast name-to-id lookup */
|
||||
std::map<std::string, SimulationClockId> clock_name2ids_;
|
||||
|
|
|
@ -220,6 +220,10 @@ void write_xml_circuit_port(std::fstream& fp,
|
|||
write_xml_attribute(fp, "is_prog", "true");
|
||||
}
|
||||
|
||||
if (true == circuit_lib.port_is_shift_register(port)) {
|
||||
write_xml_attribute(fp, "is_shift_register", "true");
|
||||
}
|
||||
|
||||
if (true == circuit_lib.port_is_config_enable(port)) {
|
||||
write_xml_attribute(fp, "is_config_enable", "true");
|
||||
}
|
||||
|
|
|
@ -26,11 +26,24 @@ void write_xml_config_organization(std::fstream& fp,
|
|||
openfpga::check_file_stream(fname, fp);
|
||||
|
||||
fp << "\t\t" << "<organization";
|
||||
|
||||
write_xml_attribute(fp, "type", CONFIG_PROTOCOL_TYPE_STRING[config_protocol.type()]);
|
||||
write_xml_attribute(fp, "circuit_model_name", circuit_lib.model_name(config_protocol.memory_model()).c_str());
|
||||
|
||||
fp << "/>" << "\n";
|
||||
|
||||
/* Output BL/WL protocols */
|
||||
fp << "\t\t\t" << "<bl";
|
||||
write_xml_attribute(fp, "protocol", BLWL_PROTOCOL_TYPE_STRING[config_protocol.bl_protocol_type()]);
|
||||
write_xml_attribute(fp, "circuit_model_name", circuit_lib.model_name(config_protocol.bl_memory_model()).c_str());
|
||||
write_xml_attribute(fp, "num_banks", config_protocol.bl_num_banks());
|
||||
fp << "/>" << "\n";
|
||||
|
||||
fp << "\t\t\t" << "<wl";
|
||||
write_xml_attribute(fp, "protocol", BLWL_PROTOCOL_TYPE_STRING[config_protocol.wl_protocol_type()]);
|
||||
write_xml_attribute(fp, "circuit_model_name", circuit_lib.model_name(config_protocol.wl_memory_model()).c_str());
|
||||
write_xml_attribute(fp, "num_banks", config_protocol.wl_num_banks());
|
||||
fp << "/>" << "\n";
|
||||
|
||||
fp << "\t" << "</organization>" << "\n";
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
|
|
|
@ -41,7 +41,7 @@ void write_xml_clock_setting(std::fstream& fp,
|
|||
fp << ">" << "\n";
|
||||
|
||||
/* Output clock information one by one */
|
||||
for (const SimulationClockId& clock_id : sim_setting.clocks()) {
|
||||
for (const SimulationClockId& clock_id : sim_setting.operating_clocks()) {
|
||||
fp << "\t\t\t" << "<clock";
|
||||
write_xml_attribute(fp, "name", sim_setting.clock_name(clock_id).c_str());
|
||||
write_xml_attribute(fp, "port", generate_xml_port_name(sim_setting.clock_port(clock_id)).c_str());
|
||||
|
@ -52,9 +52,22 @@ void write_xml_clock_setting(std::fstream& fp,
|
|||
fp << "\t\t" << "</operating";
|
||||
fp << ">" << "\n";
|
||||
|
||||
fp << "\t\t" << "<operating";
|
||||
fp << "\t\t" << "<programming";
|
||||
write_xml_attribute(fp, "frequency", sim_setting.programming_clock_frequency());
|
||||
fp << "/>" << "\n";
|
||||
fp << ">" << "\n";
|
||||
|
||||
/* Output clock information one by one */
|
||||
for (const SimulationClockId& clock_id : sim_setting.programming_clocks()) {
|
||||
fp << "\t\t\t" << "<clock";
|
||||
write_xml_attribute(fp, "name", sim_setting.clock_name(clock_id).c_str());
|
||||
write_xml_attribute(fp, "port", generate_xml_port_name(sim_setting.clock_port(clock_id)).c_str());
|
||||
write_xml_attribute(fp, "frequency", std::to_string(sim_setting.clock_frequency(clock_id)).c_str());
|
||||
write_xml_attribute(fp, "is_shift_register", std::to_string(sim_setting.clock_is_shift_register(clock_id)).c_str());
|
||||
fp << ">" << "\n";
|
||||
}
|
||||
|
||||
fp << "\t\t" << "</programming";
|
||||
fp << ">" << "\n";
|
||||
|
||||
fp << "\t" << "</clock_setting>" << "\n";
|
||||
}
|
||||
|
|
|
@ -27,6 +27,16 @@ FabricKey::fabric_region_range FabricKey::regions() const {
|
|||
return vtr::make_range(region_ids_.begin(), region_ids_.end());
|
||||
}
|
||||
|
||||
FabricKey::fabric_bit_line_bank_range FabricKey::bl_banks(const FabricRegionId& region_id) const {
|
||||
VTR_ASSERT(valid_region_id(region_id));
|
||||
return vtr::make_range(bl_bank_ids_[region_id].begin(), bl_bank_ids_[region_id].end());
|
||||
}
|
||||
|
||||
FabricKey::fabric_word_line_bank_range FabricKey::wl_banks(const FabricRegionId& region_id) const {
|
||||
VTR_ASSERT(valid_region_id(region_id));
|
||||
return vtr::make_range(wl_bank_ids_[region_id].begin(), wl_bank_ids_[region_id].end());
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Public Accessors : Basic data query
|
||||
***********************************************************************/
|
||||
|
@ -54,10 +64,26 @@ std::string FabricKey::key_alias(const FabricKeyId& key_id) const {
|
|||
return key_alias_[key_id];
|
||||
}
|
||||
|
||||
vtr::Point<int> FabricKey::key_coordinate(const FabricKeyId& key_id) const {
|
||||
/* validate the key_id */
|
||||
VTR_ASSERT(valid_key_id(key_id));
|
||||
return key_coordinates_[key_id];
|
||||
}
|
||||
|
||||
bool FabricKey::empty() const {
|
||||
return 0 == key_ids_.size();
|
||||
}
|
||||
|
||||
std::vector<openfpga::BasicPort> FabricKey::bl_bank_data_ports(const FabricRegionId& region_id, const FabricBitLineBankId& bank_id) const {
|
||||
VTR_ASSERT(valid_bl_bank_id(region_id, bank_id));
|
||||
return bl_bank_data_ports_[region_id][bank_id];
|
||||
}
|
||||
|
||||
std::vector<openfpga::BasicPort> FabricKey::wl_bank_data_ports(const FabricRegionId& region_id, const FabricWordLineBankId& bank_id) const {
|
||||
VTR_ASSERT(valid_wl_bank_id(region_id, bank_id));
|
||||
return wl_bank_data_ports_[region_id][bank_id];
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Public Mutators
|
||||
***********************************************************************/
|
||||
|
@ -65,6 +91,10 @@ bool FabricKey::empty() const {
|
|||
void FabricKey::reserve_regions(const size_t& num_regions) {
|
||||
region_ids_.reserve(num_regions);
|
||||
region_key_ids_.reserve(num_regions);
|
||||
bl_bank_ids_.reserve(num_regions);
|
||||
bl_bank_data_ports_.reserve(num_regions);
|
||||
wl_bank_ids_.reserve(num_regions);
|
||||
wl_bank_data_ports_.reserve(num_regions);
|
||||
}
|
||||
|
||||
FabricRegionId FabricKey::create_region() {
|
||||
|
@ -72,6 +102,10 @@ FabricRegionId FabricKey::create_region() {
|
|||
FabricRegionId region = FabricRegionId(region_ids_.size());
|
||||
region_ids_.push_back(region);
|
||||
region_key_ids_.emplace_back();
|
||||
bl_bank_ids_.emplace_back();
|
||||
bl_bank_data_ports_.emplace_back();
|
||||
wl_bank_ids_.emplace_back();
|
||||
wl_bank_data_ports_.emplace_back();
|
||||
|
||||
return region;
|
||||
}
|
||||
|
@ -124,6 +158,7 @@ void FabricKey::reserve_keys(const size_t& num_keys) {
|
|||
key_values_.reserve(num_keys);
|
||||
key_regions_.reserve(num_keys);
|
||||
key_alias_.reserve(num_keys);
|
||||
key_coordinates_.reserve(num_keys);
|
||||
}
|
||||
|
||||
FabricKeyId FabricKey::create_key() {
|
||||
|
@ -134,6 +169,7 @@ FabricKeyId FabricKey::create_key() {
|
|||
key_values_.emplace_back();
|
||||
key_regions_.emplace_back(FabricRegionId::INVALID());
|
||||
key_alias_.emplace_back();
|
||||
key_coordinates_.emplace_back(vtr::Point<int>(-1, -1));
|
||||
|
||||
return key;
|
||||
}
|
||||
|
@ -162,6 +198,62 @@ void FabricKey::set_key_alias(const FabricKeyId& key_id,
|
|||
key_alias_[key_id] = alias;
|
||||
}
|
||||
|
||||
void FabricKey::set_key_coordinate(const FabricKeyId& key_id,
|
||||
const vtr::Point<int>& coord) {
|
||||
/* validate the key_id */
|
||||
VTR_ASSERT(valid_key_id(key_id));
|
||||
|
||||
key_coordinates_[key_id] = coord;
|
||||
}
|
||||
|
||||
void FabricKey::reserve_bl_shift_register_banks(const FabricRegionId& region_id, const size_t& num_banks) {
|
||||
VTR_ASSERT(valid_region_id(region_id));
|
||||
bl_bank_ids_[region_id].reserve(num_banks);
|
||||
bl_bank_data_ports_[region_id].reserve(num_banks);
|
||||
}
|
||||
|
||||
void FabricKey::reserve_wl_shift_register_banks(const FabricRegionId& region_id, const size_t& num_banks) {
|
||||
VTR_ASSERT(valid_region_id(region_id));
|
||||
wl_bank_ids_[region_id].reserve(num_banks);
|
||||
wl_bank_data_ports_[region_id].reserve(num_banks);
|
||||
}
|
||||
|
||||
FabricBitLineBankId FabricKey::create_bl_shift_register_bank(const FabricRegionId& region_id) {
|
||||
VTR_ASSERT(valid_region_id(region_id));
|
||||
|
||||
/* Create a new id */
|
||||
FabricBitLineBankId bank = FabricBitLineBankId(bl_bank_ids_[region_id].size());
|
||||
bl_bank_ids_[region_id].push_back(bank);
|
||||
bl_bank_data_ports_[region_id].emplace_back();
|
||||
|
||||
return bank;
|
||||
}
|
||||
|
||||
void FabricKey::add_data_port_to_bl_shift_register_bank(const FabricRegionId& region_id,
|
||||
const FabricBitLineBankId& bank_id,
|
||||
const openfpga::BasicPort& data_port) {
|
||||
VTR_ASSERT(valid_bl_bank_id(region_id, bank_id));
|
||||
bl_bank_data_ports_[region_id][bank_id].push_back(data_port);
|
||||
}
|
||||
|
||||
FabricWordLineBankId FabricKey::create_wl_shift_register_bank(const FabricRegionId& region_id) {
|
||||
VTR_ASSERT(valid_region_id(region_id));
|
||||
|
||||
/* Create a new id */
|
||||
FabricWordLineBankId bank = FabricWordLineBankId(wl_bank_ids_[region_id].size());
|
||||
wl_bank_ids_[region_id].push_back(bank);
|
||||
wl_bank_data_ports_[region_id].emplace_back();
|
||||
|
||||
return bank;
|
||||
}
|
||||
|
||||
void FabricKey::add_data_port_to_wl_shift_register_bank(const FabricRegionId& region_id,
|
||||
const FabricWordLineBankId& bank_id,
|
||||
const openfpga::BasicPort& data_port) {
|
||||
VTR_ASSERT(valid_wl_bank_id(region_id, bank_id));
|
||||
wl_bank_data_ports_[region_id][bank_id].push_back(data_port);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Internal invalidators/validators
|
||||
***********************************************************************/
|
||||
|
@ -173,3 +265,21 @@ bool FabricKey::valid_region_id(const FabricRegionId& region_id) const {
|
|||
bool FabricKey::valid_key_id(const FabricKeyId& key_id) const {
|
||||
return ( size_t(key_id) < key_ids_.size() ) && ( key_id == key_ids_[key_id] );
|
||||
}
|
||||
|
||||
bool FabricKey::valid_key_coordinate(const vtr::Point<int>& coord) const {
|
||||
return coord.x() > -1 && coord.y() > -1;
|
||||
}
|
||||
|
||||
bool FabricKey::valid_bl_bank_id(const FabricRegionId& region_id, const FabricBitLineBankId& bank_id) const {
|
||||
if (!valid_region_id(region_id)) {
|
||||
return false;
|
||||
}
|
||||
return ( size_t(bank_id) < bl_bank_ids_[region_id].size() ) && ( bank_id == bl_bank_ids_[region_id][bank_id] );
|
||||
}
|
||||
|
||||
bool FabricKey::valid_wl_bank_id(const FabricRegionId& region_id, const FabricWordLineBankId& bank_id) const {
|
||||
if (!valid_region_id(region_id)) {
|
||||
return false;
|
||||
}
|
||||
return ( size_t(bank_id) < wl_bank_ids_[region_id].size() ) && ( bank_id == wl_bank_ids_[region_id][bank_id] );
|
||||
}
|
||||
|
|
|
@ -10,6 +10,10 @@
|
|||
|
||||
/* Headers from vtrutil library */
|
||||
#include "vtr_vector.h"
|
||||
#include "vtr_geometry.h"
|
||||
|
||||
/* Headers from openfpgautil library */
|
||||
#include "openfpga_port.h"
|
||||
|
||||
#include "fabric_key_fwd.h"
|
||||
|
||||
|
@ -37,14 +41,20 @@ class FabricKey {
|
|||
public: /* Types */
|
||||
typedef vtr::vector<FabricKeyId, FabricKeyId>::const_iterator fabric_key_iterator;
|
||||
typedef vtr::vector<FabricRegionId, FabricRegionId>::const_iterator fabric_region_iterator;
|
||||
typedef vtr::vector<FabricBitLineBankId, FabricBitLineBankId>::const_iterator fabric_bit_line_bank_iterator;
|
||||
typedef vtr::vector<FabricWordLineBankId, FabricWordLineBankId>::const_iterator fabric_word_line_bank_iterator;
|
||||
/* Create range */
|
||||
typedef vtr::Range<fabric_region_iterator> fabric_region_range;
|
||||
typedef vtr::Range<fabric_key_iterator> fabric_key_range;
|
||||
typedef vtr::Range<fabric_bit_line_bank_iterator> fabric_bit_line_bank_range;
|
||||
typedef vtr::Range<fabric_word_line_bank_iterator> fabric_word_line_bank_range;
|
||||
public: /* Constructors */
|
||||
FabricKey();
|
||||
public: /* Accessors: aggregates */
|
||||
fabric_key_range keys() const;
|
||||
fabric_region_range regions() const;
|
||||
fabric_bit_line_bank_range bl_banks(const FabricRegionId& region_id) const;
|
||||
fabric_word_line_bank_range wl_banks(const FabricRegionId& region_id) const;
|
||||
public: /* Public Accessors: Basic data query */
|
||||
/* Access all the keys of a region */
|
||||
std::vector<FabricKeyId> region_keys(const FabricRegionId& region_id) const;
|
||||
|
@ -58,9 +68,18 @@ class FabricKey {
|
|||
/* Access the alias of a key */
|
||||
std::string key_alias(const FabricKeyId& key_id) const;
|
||||
|
||||
/* Access the coordinate of a key */
|
||||
vtr::Point<int> key_coordinate(const FabricKeyId& key_id) const;
|
||||
|
||||
/* Check if there are any keys */
|
||||
bool empty() const;
|
||||
|
||||
/* Return a list of data ports which will be driven by a BL shift register bank */
|
||||
std::vector<openfpga::BasicPort> bl_bank_data_ports(const FabricRegionId& region_id, const FabricBitLineBankId& bank_id) const;
|
||||
|
||||
/* Return a list of data ports which will be driven by a WL shift register bank */
|
||||
std::vector<openfpga::BasicPort> wl_bank_data_ports(const FabricRegionId& region_id, const FabricWordLineBankId& bank_id) const;
|
||||
|
||||
public: /* Public Mutators: model-related */
|
||||
|
||||
/* Reserve a number of regions to be memory efficent */
|
||||
|
@ -93,9 +112,36 @@ class FabricKey {
|
|||
void set_key_alias(const FabricKeyId& key_id,
|
||||
const std::string& alias);
|
||||
|
||||
void set_key_coordinate(const FabricKeyId& key_id,
|
||||
const vtr::Point<int>& coord);
|
||||
|
||||
/* Reserve a number of banks to be memory efficent */
|
||||
void reserve_bl_shift_register_banks(const FabricRegionId& region_id, const size_t& num_banks);
|
||||
void reserve_wl_shift_register_banks(const FabricRegionId& region_id, const size_t& num_banks);
|
||||
|
||||
/* Create a new shift register bank for BLs and return an id */
|
||||
FabricBitLineBankId create_bl_shift_register_bank(const FabricRegionId& region_id);
|
||||
|
||||
/* Add a data port to a given BL shift register bank */
|
||||
void add_data_port_to_bl_shift_register_bank(const FabricRegionId& region_id,
|
||||
const FabricBitLineBankId& bank_id,
|
||||
const openfpga::BasicPort& data_port);
|
||||
|
||||
/* Create a new shift register bank for WLs and return an id */
|
||||
FabricWordLineBankId create_wl_shift_register_bank(const FabricRegionId& region_id);
|
||||
|
||||
/* Add a data port to a given WL shift register bank */
|
||||
void add_data_port_to_wl_shift_register_bank(const FabricRegionId& region_id,
|
||||
const FabricWordLineBankId& bank_id,
|
||||
const openfpga::BasicPort& data_port);
|
||||
|
||||
public: /* Public invalidators/validators */
|
||||
bool valid_region_id(const FabricRegionId& region_id) const;
|
||||
bool valid_key_id(const FabricKeyId& key_id) const;
|
||||
/* Identify if key coordinate is acceptable to fabric key convention */
|
||||
bool valid_key_coordinate(const vtr::Point<int>& coord) const;
|
||||
bool valid_bl_bank_id(const FabricRegionId& region_id, const FabricBitLineBankId& bank_id) const;
|
||||
bool valid_wl_bank_id(const FabricRegionId& region_id, const FabricWordLineBankId& bank_id) const;
|
||||
private: /* Internal data */
|
||||
/* Unique ids for each region */
|
||||
vtr::vector<FabricRegionId, FabricRegionId> region_ids_;
|
||||
|
@ -112,11 +158,24 @@ class FabricKey {
|
|||
/* Values for each key */
|
||||
vtr::vector<FabricKeyId, size_t> key_values_;
|
||||
|
||||
/* Values for each key */
|
||||
vtr::vector<FabricKeyId, vtr::Point<int>> key_coordinates_;
|
||||
|
||||
/* Region for each key */
|
||||
vtr::vector<FabricKeyId, FabricRegionId> key_regions_;
|
||||
|
||||
/* Optional alias for each key, with which a key can also be represented */
|
||||
vtr::vector<FabricKeyId, std::string> key_alias_;
|
||||
|
||||
/* Unique ids for each BL shift register bank */
|
||||
vtr::vector<FabricRegionId, vtr::vector<FabricBitLineBankId, FabricBitLineBankId>> bl_bank_ids_;
|
||||
/* Data ports to be connected to each BL shift register bank */
|
||||
vtr::vector<FabricRegionId, vtr::vector<FabricBitLineBankId, std::vector<openfpga::BasicPort>>> bl_bank_data_ports_;
|
||||
|
||||
/* Unique ids for each WL shift register bank */
|
||||
vtr::vector<FabricRegionId, vtr::vector<FabricWordLineBankId, FabricWordLineBankId>> wl_bank_ids_;
|
||||
/* Data ports to be connected to each WL shift register bank */
|
||||
vtr::vector<FabricRegionId, vtr::vector<FabricWordLineBankId, std::vector<openfpga::BasicPort>>> wl_bank_data_ports_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -14,9 +14,13 @@
|
|||
|
||||
struct fabric_region_id_tag;
|
||||
struct fabric_key_id_tag;
|
||||
struct fabric_bit_line_bank_id_tag;
|
||||
struct fabric_word_line_bank_id_tag;
|
||||
|
||||
typedef vtr::StrongId<fabric_region_id_tag> FabricRegionId;
|
||||
typedef vtr::StrongId<fabric_key_id_tag> FabricKeyId;
|
||||
typedef vtr::StrongId<fabric_bit_line_bank_id_tag> FabricBitLineBankId;
|
||||
typedef vtr::StrongId<fabric_word_line_bank_id_tag> FabricWordLineBankId;
|
||||
|
||||
/* Short declaration of class */
|
||||
class FabricKey;
|
||||
|
|
|
@ -13,6 +13,10 @@
|
|||
#include "vtr_assert.h"
|
||||
#include "vtr_time.h"
|
||||
|
||||
/* Headers from openfpga util library */
|
||||
#include "openfpga_tokenizer.h"
|
||||
#include "openfpga_port_parser.h"
|
||||
|
||||
/* Headers from libarchfpga */
|
||||
#include "arch_error.h"
|
||||
#include "read_xml_util.h"
|
||||
|
@ -60,6 +64,122 @@ void read_xml_region_key(pugi::xml_node& xml_component_key,
|
|||
fabric_key.set_key_name(FabricKeyId(id), name);
|
||||
fabric_key.set_key_value(FabricKeyId(id), value);
|
||||
fabric_key.add_key_to_region(fabric_region, FabricKeyId(id));
|
||||
|
||||
/* Parse coordinates */
|
||||
vtr::Point<int> coord;
|
||||
coord.set_x(get_attribute(xml_component_key, "column", loc_data, pugiutil::ReqOpt::OPTIONAL).as_int(-1));
|
||||
coord.set_y(get_attribute(xml_component_key, "row", loc_data, pugiutil::ReqOpt::OPTIONAL).as_int(-1));
|
||||
if (fabric_key.valid_key_coordinate(coord)) {
|
||||
fabric_key.set_key_coordinate(FabricKeyId(id), coord);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Parse XML codes of a <bank> under <bl_shift_register_banks> to an object of FabricKey
|
||||
*******************************************************************/
|
||||
static
|
||||
void read_xml_region_bl_shift_register_bank(pugi::xml_node& xml_bank,
|
||||
const pugiutil::loc_data& loc_data,
|
||||
FabricKey& fabric_key,
|
||||
const FabricRegionId& fabric_region) {
|
||||
/* Find the id of the bank */
|
||||
FabricBitLineBankId bank_id = FabricBitLineBankId(get_attribute(xml_bank, "id", loc_data).as_int());
|
||||
|
||||
if (!fabric_key.valid_bl_bank_id(fabric_region, bank_id)) {
|
||||
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_bank),
|
||||
"Invalid 'id' attribute '%lu' (in total %lu BL banks)!\n",
|
||||
size_t(bank_id),
|
||||
fabric_key.bl_banks(fabric_region).size());
|
||||
}
|
||||
|
||||
VTR_ASSERT_SAFE(true == fabric_key.valid_bl_bank_id(fabric_region, bank_id));
|
||||
|
||||
/* Parse the ports */
|
||||
std::string data_ports = get_attribute(xml_bank, "range", loc_data).as_string();
|
||||
/* Split with ',' if we have multiple ports */
|
||||
openfpga::StringToken tokenizer(data_ports);
|
||||
for (const std::string& data_port : tokenizer.split(',')) {
|
||||
openfpga::PortParser data_port_parser(data_port);
|
||||
fabric_key.add_data_port_to_bl_shift_register_bank(fabric_region, bank_id, data_port_parser.port());
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Parse XML codes of a <bl_shift_register_banks> to an object of FabricKey
|
||||
*******************************************************************/
|
||||
static
|
||||
void read_xml_region_bl_shift_register_banks(pugi::xml_node& xml_bl_bank,
|
||||
const pugiutil::loc_data& loc_data,
|
||||
FabricKey& fabric_key,
|
||||
const FabricRegionId& fabric_region) {
|
||||
size_t num_banks = count_children(xml_bl_bank, "bank", loc_data, pugiutil::ReqOpt::OPTIONAL);
|
||||
fabric_key.reserve_bl_shift_register_banks(fabric_region, num_banks);
|
||||
|
||||
for (size_t ibank = 0; ibank < num_banks; ++ibank) {
|
||||
fabric_key.create_bl_shift_register_bank(fabric_region);
|
||||
}
|
||||
|
||||
for (pugi::xml_node xml_bank : xml_bl_bank.children()) {
|
||||
/* Error out if the XML child has an invalid name! */
|
||||
if (xml_bank.name() != std::string("bank")) {
|
||||
bad_tag(xml_bank, loc_data, xml_bl_bank, {"bank"});
|
||||
}
|
||||
read_xml_region_bl_shift_register_bank(xml_bank, loc_data, fabric_key, fabric_region);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Parse XML codes of a <bank> under <wl_shift_register_banks> to an object of FabricKey
|
||||
*******************************************************************/
|
||||
static
|
||||
void read_xml_region_wl_shift_register_bank(pugi::xml_node& xml_bank,
|
||||
const pugiutil::loc_data& loc_data,
|
||||
FabricKey& fabric_key,
|
||||
const FabricRegionId& fabric_region) {
|
||||
/* Find the id of the bank */
|
||||
FabricWordLineBankId bank_id = FabricWordLineBankId(get_attribute(xml_bank, "id", loc_data).as_int());
|
||||
|
||||
if (!fabric_key.valid_wl_bank_id(fabric_region, bank_id)) {
|
||||
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_bank),
|
||||
"Invalid 'id' attribute '%lu' (in total %lu WL banks)!\n",
|
||||
size_t(bank_id),
|
||||
fabric_key.wl_banks(fabric_region).size());
|
||||
}
|
||||
|
||||
VTR_ASSERT_SAFE(true == fabric_key.valid_wl_bank_id(fabric_region, bank_id));
|
||||
|
||||
/* Parse the ports */
|
||||
std::string data_ports = get_attribute(xml_bank, "range", loc_data).as_string();
|
||||
/* Split with ',' if we have multiple ports */
|
||||
openfpga::StringToken tokenizer(data_ports);
|
||||
for (const std::string& data_port : tokenizer.split(',')) {
|
||||
openfpga::PortParser data_port_parser(data_port);
|
||||
fabric_key.add_data_port_to_wl_shift_register_bank(fabric_region, bank_id, data_port_parser.port());
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Parse XML codes of a <bl_shift_register_banks> to an object of FabricKey
|
||||
*******************************************************************/
|
||||
static
|
||||
void read_xml_region_wl_shift_register_banks(pugi::xml_node& xml_wl_bank,
|
||||
const pugiutil::loc_data& loc_data,
|
||||
FabricKey& fabric_key,
|
||||
const FabricRegionId& fabric_region) {
|
||||
size_t num_banks = count_children(xml_wl_bank, "bank", loc_data, pugiutil::ReqOpt::OPTIONAL);
|
||||
fabric_key.reserve_wl_shift_register_banks(fabric_region, num_banks);
|
||||
|
||||
for (size_t ibank = 0; ibank < num_banks; ++ibank) {
|
||||
fabric_key.create_wl_shift_register_bank(fabric_region);
|
||||
}
|
||||
|
||||
for (pugi::xml_node xml_bank : xml_wl_bank.children()) {
|
||||
/* Error out if the XML child has an invalid name! */
|
||||
if (xml_bank.name() != std::string("bank")) {
|
||||
bad_tag(xml_bank, loc_data, xml_wl_bank, {"bank"});
|
||||
}
|
||||
read_xml_region_wl_shift_register_bank(xml_bank, loc_data, fabric_key, fabric_region);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
|
@ -80,20 +200,25 @@ void read_xml_fabric_region(pugi::xml_node& xml_region,
|
|||
VTR_ASSERT_SAFE(true == fabric_key.valid_region_id(region_id));
|
||||
|
||||
/* Reserve memory space for the keys in the region */
|
||||
size_t num_keys = std::distance(xml_region.children().begin(), xml_region.children().end());
|
||||
size_t num_keys = count_children(xml_region, "key", loc_data, pugiutil::ReqOpt::OPTIONAL);
|
||||
fabric_key.reserve_region_keys(region_id, num_keys);
|
||||
|
||||
for (pugi::xml_node xml_key : xml_region.children()) {
|
||||
/* Error out if the XML child has an invalid name! */
|
||||
if (xml_key.name() != std::string("key")) {
|
||||
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_region),
|
||||
"Unexpected child '%s' in region '%lu', Region XML node can only contain keys!\n",
|
||||
xml_key.name(),
|
||||
size_t(region_id));
|
||||
}
|
||||
/* Parse the key for this region */
|
||||
read_xml_region_key(xml_key, loc_data, fabric_key, region_id);
|
||||
/* Parse the key for this region */
|
||||
if (0 < num_keys) {
|
||||
pugi::xml_node xml_key = get_first_child(xml_region, "key", loc_data);
|
||||
while (xml_key) {
|
||||
read_xml_region_key(xml_key, loc_data, fabric_key, region_id);
|
||||
xml_key = xml_key.next_sibling(xml_key.name());
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse the BL shift register bank for this region */
|
||||
pugi::xml_node xml_bl_bank = get_single_child(xml_region, "bl_shift_register_banks", loc_data, pugiutil::ReqOpt::OPTIONAL);
|
||||
read_xml_region_bl_shift_register_banks(xml_bl_bank, loc_data, fabric_key, region_id);
|
||||
|
||||
/* Parse the WL shift register bank for this region */
|
||||
pugi::xml_node xml_wl_bank = get_single_child(xml_region, "wl_shift_register_banks", loc_data, pugiutil::ReqOpt::OPTIONAL);
|
||||
read_xml_region_wl_shift_register_banks(xml_wl_bank, loc_data, fabric_key, region_id);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
|
|
|
@ -52,11 +52,117 @@ int write_xml_fabric_component_key(std::fstream& fp,
|
|||
write_xml_attribute(fp, "alias", fabric_key.key_alias(component_key).c_str());
|
||||
}
|
||||
|
||||
vtr::Point<int> coord = fabric_key.key_coordinate(component_key);
|
||||
if (fabric_key.valid_key_coordinate(coord)) {
|
||||
write_xml_attribute(fp, "column", coord.x());
|
||||
write_xml_attribute(fp, "row", coord.y());
|
||||
}
|
||||
|
||||
fp << "/>" << "\n";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* A writer to output a BL shift register bank description 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_bl_shift_register_banks(std::fstream& fp,
|
||||
const FabricKey& fabric_key,
|
||||
const FabricRegionId& region) {
|
||||
/* Validate the file stream */
|
||||
if (false == openfpga::valid_file_stream(fp)) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* If we have an empty bank, we just skip it */
|
||||
if (0 == fabric_key.bl_banks(region).size()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Write the root node */
|
||||
openfpga::write_tab_to_file(fp, 2);
|
||||
fp << "<bl_shift_register_banks>" << "\n";
|
||||
|
||||
for (const auto& bank : fabric_key.bl_banks(region)) {
|
||||
openfpga::write_tab_to_file(fp, 3);
|
||||
fp << "<bank";
|
||||
|
||||
write_xml_attribute(fp, "id", size_t(bank));
|
||||
|
||||
std::string port_str;
|
||||
for (const auto& port : fabric_key.bl_bank_data_ports(region, bank)) {
|
||||
port_str += generate_xml_port_name(port) + ",";
|
||||
}
|
||||
/* Chop the last comma */
|
||||
if (!port_str.empty()) {
|
||||
port_str.pop_back();
|
||||
}
|
||||
write_xml_attribute(fp, "range", port_str.c_str());
|
||||
|
||||
fp << "/>" << "\n";
|
||||
}
|
||||
|
||||
openfpga::write_tab_to_file(fp, 2);
|
||||
fp << "</bl_shift_register_banks>" << "\n";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* A writer to output a WL shift register bank description 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_wl_shift_register_banks(std::fstream& fp,
|
||||
const FabricKey& fabric_key,
|
||||
const FabricRegionId& region) {
|
||||
/* Validate the file stream */
|
||||
if (false == openfpga::valid_file_stream(fp)) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* If we have an empty bank, we just skip it */
|
||||
if (0 == fabric_key.wl_banks(region).size()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Write the root node */
|
||||
openfpga::write_tab_to_file(fp, 2);
|
||||
fp << "<wl_shift_register_banks>" << "\n";
|
||||
|
||||
for (const auto& bank : fabric_key.wl_banks(region)) {
|
||||
openfpga::write_tab_to_file(fp, 3);
|
||||
fp << "<bank";
|
||||
|
||||
write_xml_attribute(fp, "id", size_t(bank));
|
||||
|
||||
std::string port_str;
|
||||
for (const auto& port : fabric_key.wl_bank_data_ports(region, bank)) {
|
||||
port_str += generate_xml_port_name(port) + ",";
|
||||
}
|
||||
/* Chop the last comma */
|
||||
if (!port_str.empty()) {
|
||||
port_str.pop_back();
|
||||
}
|
||||
write_xml_attribute(fp, "range", port_str.c_str());
|
||||
|
||||
fp << "/>" << "\n";
|
||||
}
|
||||
|
||||
openfpga::write_tab_to_file(fp, 2);
|
||||
fp << "</wl_shift_register_banks>" << "\n";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* A writer to output a fabric key to XML format
|
||||
*
|
||||
|
@ -87,6 +193,10 @@ int write_xml_fabric_key(const char* fname,
|
|||
openfpga::write_tab_to_file(fp, 1);
|
||||
fp << "<region id=\"" << size_t(region) << "\"" << ">\n";
|
||||
|
||||
/* Write shift register banks */
|
||||
write_xml_fabric_bl_shift_register_banks(fp, fabric_key, region);
|
||||
write_xml_fabric_wl_shift_register_banks(fp, fabric_key, region);
|
||||
|
||||
/* Write component by component */
|
||||
for (const FabricKeyId& key : fabric_key.region_keys(region)) {
|
||||
err_code = write_xml_fabric_component_key(fp, fabric_key, key);
|
||||
|
|
|
@ -46,6 +46,64 @@ std::vector<size_t> ito1hot_vec(const size_t& in_int,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Convert an integer to an one-hot encoding character array
|
||||
* For example:
|
||||
* Input integer: 3
|
||||
* Binary length : 4
|
||||
* Output:
|
||||
* index | 0 | 1 | 2 | 3
|
||||
* ret | 0 | 0 | 0 | 1
|
||||
*
|
||||
* If you need all zero code, set the input integer same as the binary length
|
||||
* For example:
|
||||
* Input integer: 4
|
||||
* Binary length : 4
|
||||
* Output:
|
||||
* index | 0 | 1 | 2 | 3
|
||||
* ret | 0 | 0 | 0 | 0
|
||||
*
|
||||
********************************************************************/
|
||||
std::vector<char> ito1hot_charvec(const size_t& in_int,
|
||||
const size_t& bin_len,
|
||||
const char& default_bit) {
|
||||
/* Make sure we do not have any overflow! */
|
||||
VTR_ASSERT ( (in_int <= bin_len) );
|
||||
|
||||
/* Initialize */
|
||||
std::vector<char> ret(bin_len, default_bit);
|
||||
|
||||
if (bin_len == in_int) {
|
||||
return ret; /* all zero case */
|
||||
}
|
||||
ret[in_int] = '1'; /* Keep a good sequence of bits */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void replace_str_bits(std::string& str_to_convert,
|
||||
const char& bit_in_place,
|
||||
const char& bit_to_replace) {
|
||||
for (char& bit : str_to_convert) {
|
||||
if (bit_in_place == bit) {
|
||||
bit = bit_to_replace;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string combine_two_1hot_str(const std::string& code1,
|
||||
const std::string& code2) {
|
||||
VTR_ASSERT(code1.length() == code2.length());
|
||||
std::string ret = code1;
|
||||
for (size_t ichar = 0; ichar < code2.length(); ichar++) {
|
||||
VTR_ASSERT('0' == code2[ichar] || '1' == code2[ichar] || 'x' == code2[ichar]);
|
||||
if ('1' == code2[ichar] || '0' == code2[ichar]) {
|
||||
ret[ichar] = code2[ichar];
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Converter an integer to a binary vector
|
||||
* For example:
|
||||
|
|
|
@ -22,6 +22,33 @@ constexpr char DONT_CARE_CHAR = 'x';
|
|||
std::vector<size_t> ito1hot_vec(const size_t& in_int,
|
||||
const size_t& bin_len);
|
||||
|
||||
std::vector<char> ito1hot_charvec(const size_t& in_int,
|
||||
const size_t& bin_len,
|
||||
const char& default_bit = '0');
|
||||
|
||||
/** @brief Replace the characters in a string with a given replacement
|
||||
* @param str_to_convert the input and output string
|
||||
* @param bit_in_place the charater to be replaced
|
||||
* @param bit_to_replace the charater to replace the bit_in_place
|
||||
*/
|
||||
void replace_str_bits(std::string& str_to_convert,
|
||||
const char& bit_in_place,
|
||||
const char& bit_to_replace);
|
||||
|
||||
/********************************************************************
|
||||
* @brief Combine to two 1-hot codes which are in string format
|
||||
* Any unique '1' or '0' will be merged
|
||||
* @note Where there are both '0' or '1' in the code1 and code2,
|
||||
* code2 bits will overwrite
|
||||
* For example:
|
||||
* Code 1: xx1x0x110
|
||||
* Code 2: 01xx01xx1
|
||||
* Output: 011x01111
|
||||
* @note This function requires two codes in the same length
|
||||
********************************************************************/
|
||||
std::string combine_two_1hot_str(const std::string& code1,
|
||||
const std::string& code2);
|
||||
|
||||
std::vector<size_t> itobin_vec(const size_t& in_int,
|
||||
const size_t& bin_len);
|
||||
|
||||
|
|
|
@ -51,11 +51,6 @@ BasicPort::BasicPort(const std::string& name, const size_t& width) {
|
|||
set_origin_port_width(-1);
|
||||
}
|
||||
|
||||
/* Copy constructor */
|
||||
BasicPort::BasicPort(const BasicPort& basic_port) {
|
||||
set(basic_port);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Accessors
|
||||
***********************************************************************/
|
||||
|
|
|
@ -18,7 +18,6 @@ class BasicPort {
|
|||
BasicPort(const char* name, const size_t& width);
|
||||
BasicPort(const std::string& name, const size_t& lsb, const size_t& msb);
|
||||
BasicPort(const std::string& name, const size_t& width);
|
||||
BasicPort(const BasicPort& basic_port); /* Copy constructor */
|
||||
public: /* Overloaded operators */
|
||||
bool operator== (const BasicPort& portA) const;
|
||||
bool operator< (const BasicPort& portA) const;
|
||||
|
|
|
@ -13,10 +13,18 @@ namespace openfpga {
|
|||
/* Top-level module name */
|
||||
constexpr char* FPGA_TOP_MODULE_NAME = "fpga_top";
|
||||
|
||||
/* Configuration chain naming constant strings */
|
||||
constexpr char* CONFIGURABLE_MEMORY_CHAIN_IN_NAME = "ccff_head";
|
||||
constexpr char* CONFIGURABLE_MEMORY_CHAIN_OUT_NAME = "ccff_tail";
|
||||
constexpr char* CONFIGURABLE_MEMORY_DATA_OUT_NAME = "mem_out";
|
||||
constexpr char* CONFIGURABLE_MEMORY_INVERTED_DATA_OUT_NAME = "mem_outb";
|
||||
constexpr char* BL_SHIFT_REGISTER_CHAIN_HEAD_NAME = "bl_sr_head";
|
||||
constexpr char* BL_SHIFT_REGISTER_CHAIN_TAIL_NAME = "bl_sr_tail";
|
||||
constexpr char* BL_SHIFT_REGISTER_CHAIN_BL_OUT_NAME = "bl_sr_bl_out";
|
||||
constexpr char* WL_SHIFT_REGISTER_CHAIN_HEAD_NAME = "wl_sr_head";
|
||||
constexpr char* WL_SHIFT_REGISTER_CHAIN_TAIL_NAME = "wl_sr_tail";
|
||||
constexpr char* WL_SHIFT_REGISTER_CHAIN_WL_OUT_NAME = "wl_sr_wl_out";
|
||||
constexpr char* WL_SHIFT_REGISTER_CHAIN_WLR_OUT_NAME = "wl_sr_wlr_out";
|
||||
|
||||
/* IO PORT */
|
||||
/* Prefix of global input, output and inout ports of FPGA fabric */
|
||||
|
@ -33,6 +41,7 @@ constexpr char* CONNECTION_BLOCK_MEM_INSTANCE_PREFIX = "mem_";
|
|||
constexpr char* MEMORY_MODULE_POSTFIX = "_mem";
|
||||
constexpr char* MEMORY_BL_PORT_NAME = "bl";
|
||||
constexpr char* MEMORY_WL_PORT_NAME = "wl";
|
||||
constexpr char* MEMORY_WLR_PORT_NAME = "wlr";
|
||||
|
||||
/* Multiplexer naming constant strings */
|
||||
constexpr char* MUX_BASIS_MODULE_POSTFIX = "_basis";
|
||||
|
@ -48,6 +57,8 @@ constexpr char* DECODER_DATA_OUT_PORT_NAME = "data_out";
|
|||
constexpr char* DECODER_DATA_OUT_INV_PORT_NAME = "data_out_inv";
|
||||
constexpr char* DECODER_BL_ADDRESS_PORT_NAME = "bl_address";
|
||||
constexpr char* DECODER_WL_ADDRESS_PORT_NAME = "wl_address";
|
||||
constexpr char* DECODER_READBACK_PORT_NAME = "readback";
|
||||
constexpr char* DECODER_DATA_READ_ENABLE_PORT_NAME = "data_out_ren";
|
||||
|
||||
/* Inverted port naming */
|
||||
constexpr char* INV_PORT_POSTFIX = "_inv";
|
||||
|
|
|
@ -84,7 +84,7 @@ std::string unit_to_string(const float& unit) {
|
|||
* Convert numeric time unit to string
|
||||
* e.g. 1e-12 -> ps
|
||||
*******************************************************************/
|
||||
std::string time_unit_to_string(const float& unit) {
|
||||
std::string time_unit_to_string(const float& unit, const std::string& postfix) {
|
||||
/* For larger than 1 unit, we do not accept */
|
||||
if (1e6 < unit) {
|
||||
VTR_LOGF_ERROR(__FILE__, __LINE__,
|
||||
|
@ -93,7 +93,7 @@ std::string time_unit_to_string(const float& unit) {
|
|||
exit(1);
|
||||
}
|
||||
|
||||
return unit_to_string(unit) + std::string("s");
|
||||
return unit_to_string(unit) + postfix;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
|
|
|
@ -18,7 +18,7 @@ bool same_float_number(const float& a,
|
|||
|
||||
std::string unit_to_string(const float& unit);
|
||||
|
||||
std::string time_unit_to_string(const float& unit);
|
||||
std::string time_unit_to_string(const float& unit, const std::string& postfix = "s");
|
||||
|
||||
float string_to_unit(const std::string& scale);
|
||||
|
||||
|
|
|
@ -76,6 +76,7 @@ int build_fabric_bitstream(OpenfpgaContext& openfpga_ctx,
|
|||
/* Build fabric bitstream here */
|
||||
openfpga_ctx.mutable_fabric_bitstream() = build_fabric_dependent_bitstream(openfpga_ctx.bitstream_manager(),
|
||||
openfpga_ctx.module_graph(),
|
||||
openfpga_ctx.arch().circuit_lib,
|
||||
openfpga_ctx.arch().config_protocol,
|
||||
cmd_context.option_enable(cmd, opt_verbose));
|
||||
|
||||
|
@ -93,6 +94,7 @@ int write_fabric_bitstream(const OpenfpgaContext& openfpga_ctx,
|
|||
CommandOptionId opt_file = cmd.option("file");
|
||||
CommandOptionId opt_file_format = cmd.option("format");
|
||||
CommandOptionId opt_fast_config = cmd.option("fast_configuration");
|
||||
CommandOptionId opt_keep_dont_care_bits = cmd.option("keep_dont_care_bits");
|
||||
|
||||
/* Write fabric bitstream if required */
|
||||
int status = CMD_EXEC_SUCCESS;
|
||||
|
@ -120,10 +122,12 @@ int write_fabric_bitstream(const OpenfpgaContext& openfpga_ctx,
|
|||
/* By default, output in plain text format */
|
||||
status = write_fabric_bitstream_to_text_file(openfpga_ctx.bitstream_manager(),
|
||||
openfpga_ctx.fabric_bitstream(),
|
||||
openfpga_ctx.blwl_shift_register_banks(),
|
||||
openfpga_ctx.arch().config_protocol,
|
||||
openfpga_ctx.fabric_global_port_info(),
|
||||
cmd_context.option_value(cmd, opt_file),
|
||||
cmd_context.option_enable(cmd, opt_fast_config),
|
||||
cmd_context.option_enable(cmd, opt_keep_dont_care_bits),
|
||||
cmd_context.option_enable(cmd, opt_verbose));
|
||||
}
|
||||
|
||||
|
|
|
@ -154,6 +154,9 @@ ShellCommandId add_openfpga_write_fabric_bitstream_command(openfpga::Shell<Openf
|
|||
/* Add an option '--fast_configuration' */
|
||||
shell_cmd.add_option("fast_configuration", false, "Reduce the size of bitstream to be downloaded");
|
||||
|
||||
/* Add an option '--keep_dont_care_bit' */
|
||||
shell_cmd.add_option("keep_dont_care_bits", false, "Keep don't care bits in bitstream file; If not enabled, don't care bits are converted to logic '0' or '1'");
|
||||
|
||||
/* Add an option '--verbose' */
|
||||
shell_cmd.add_option("verbose", false, "Enable verbose output");
|
||||
|
||||
|
|
|
@ -103,6 +103,7 @@ int build_fabric(OpenfpgaContext& openfpga_ctx,
|
|||
|
||||
curr_status = build_device_module_graph(openfpga_ctx.mutable_module_graph(),
|
||||
openfpga_ctx.mutable_decoder_lib(),
|
||||
openfpga_ctx.mutable_blwl_shift_register_banks(),
|
||||
const_cast<const OpenfpgaContext&>(openfpga_ctx),
|
||||
g_vpr_ctx.device(),
|
||||
cmd_context.option_enable(cmd, opt_frame_view),
|
||||
|
@ -123,6 +124,7 @@ int build_fabric(OpenfpgaContext& openfpga_ctx,
|
|||
|
||||
/* Build fabric global port information */
|
||||
openfpga_ctx.mutable_fabric_global_port_info() = build_fabric_global_port_info(openfpga_ctx.module_graph(),
|
||||
openfpga_ctx.arch().config_protocol,
|
||||
openfpga_ctx.arch().tile_annotations,
|
||||
openfpga_ctx.arch().circuit_lib);
|
||||
|
||||
|
@ -132,6 +134,8 @@ int build_fabric(OpenfpgaContext& openfpga_ctx,
|
|||
VTR_ASSERT(false == fkey_fname.empty());
|
||||
curr_status = write_fabric_key_to_xml_file(openfpga_ctx.module_graph(),
|
||||
fkey_fname,
|
||||
openfpga_ctx.arch().config_protocol,
|
||||
openfpga_ctx.blwl_shift_register_banks(),
|
||||
cmd_context.option_enable(cmd, opt_verbose));
|
||||
/* If there is any error, final status cannot be overwritten by a success flag */
|
||||
if (CMD_EXEC_SUCCESS != curr_status) {
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "device_rr_gsb.h"
|
||||
#include "io_location_map.h"
|
||||
#include "fabric_global_port_info.h"
|
||||
#include "memory_bank_shift_register_banks.h"
|
||||
|
||||
/********************************************************************
|
||||
* This file includes the declaration of the date structure
|
||||
|
@ -65,6 +66,7 @@ class OpenfpgaContext : public Context {
|
|||
const openfpga::DeviceRRGSB& device_rr_gsb() const { return device_rr_gsb_; }
|
||||
const openfpga::MuxLibrary& mux_lib() const { return mux_lib_; }
|
||||
const openfpga::DecoderLibrary& decoder_lib() const { return decoder_lib_; }
|
||||
const openfpga::MemoryBankShiftRegisterBanks& blwl_shift_register_banks() const { return blwl_sr_banks_; }
|
||||
const openfpga::TileDirect& tile_direct() const { return tile_direct_; }
|
||||
const openfpga::ModuleManager& module_graph() const { return module_graph_; }
|
||||
const openfpga::FlowManager& flow_manager() const { return flow_manager_; }
|
||||
|
@ -87,6 +89,7 @@ class OpenfpgaContext : public Context {
|
|||
openfpga::DeviceRRGSB& mutable_device_rr_gsb() { return device_rr_gsb_; }
|
||||
openfpga::MuxLibrary& mutable_mux_lib() { return mux_lib_; }
|
||||
openfpga::DecoderLibrary& mutable_decoder_lib() { return decoder_lib_; }
|
||||
openfpga::MemoryBankShiftRegisterBanks& mutable_blwl_shift_register_banks() { return blwl_sr_banks_; }
|
||||
openfpga::TileDirect& mutable_tile_direct() { return tile_direct_; }
|
||||
openfpga::ModuleManager& mutable_module_graph() { return module_graph_; }
|
||||
openfpga::FlowManager& mutable_flow_manager() { return flow_manager_; }
|
||||
|
@ -132,6 +135,11 @@ class OpenfpgaContext : public Context {
|
|||
/* Inner/inter-column/row tile direct connections */
|
||||
openfpga::TileDirect tile_direct_;
|
||||
|
||||
/* Library of shift register banks that control BLs and WLs
|
||||
* @note Only used when memory bank is used as configuration protocol
|
||||
*/
|
||||
openfpga::MemoryBankShiftRegisterBanks blwl_sr_banks_;
|
||||
|
||||
/* Fabric module graph */
|
||||
openfpga::ModuleManager module_graph_;
|
||||
openfpga::IoLocationMap io_location_map_;
|
||||
|
|
|
@ -703,6 +703,7 @@ std::string generate_sram_port_name(const e_config_protocol_type& sram_orgz_type
|
|||
}
|
||||
break;
|
||||
case CONFIG_MEM_STANDALONE:
|
||||
case CONFIG_MEM_QL_MEMORY_BANK:
|
||||
case CONFIG_MEM_MEMORY_BANK:
|
||||
/* Two types of ports are available:
|
||||
* (1) Bit Lines (BLs) of a SRAM cell, enabled by port type of BL
|
||||
|
@ -718,9 +719,11 @@ std::string generate_sram_port_name(const e_config_protocol_type& sram_orgz_type
|
|||
*/
|
||||
if (CIRCUIT_MODEL_PORT_BL == port_type) {
|
||||
port_name = std::string(MEMORY_BL_PORT_NAME);
|
||||
} else {
|
||||
VTR_ASSERT( CIRCUIT_MODEL_PORT_WL == port_type );
|
||||
} else if (CIRCUIT_MODEL_PORT_WL == port_type) {
|
||||
port_name = std::string(MEMORY_WL_PORT_NAME);
|
||||
} else {
|
||||
VTR_ASSERT( CIRCUIT_MODEL_PORT_WLR == port_type );
|
||||
port_name = std::string(MEMORY_WLR_PORT_NAME);
|
||||
}
|
||||
break;
|
||||
case CONFIG_MEM_FRAME_BASED:
|
||||
|
@ -810,6 +813,32 @@ std::string generate_sram_local_port_name(const CircuitLibrary& circuit_lib,
|
|||
return port_name;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate the BL/WL port names for the top-level module of an FPGA fabric
|
||||
* Each BL/WL bus drive a specific configuration region has an unique name
|
||||
*********************************************************************/
|
||||
std::string generate_regional_blwl_port_name(const std::string& blwl_port_prefix,
|
||||
const ConfigRegionId& region_id) {
|
||||
return blwl_port_prefix + std::string("_config_region_") + std::to_string(size_t(region_id));
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate the module name for a shift register chain which configures BLs
|
||||
*********************************************************************/
|
||||
std::string generate_bl_shift_register_module_name(const std::string& memory_model_name,
|
||||
const size_t& shift_register_size) {
|
||||
return std::string("bl_shift_register_") + memory_model_name + std::string("_size") + std::to_string(shift_register_size);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate the module name for a shift register chain which configures WLs
|
||||
*********************************************************************/
|
||||
std::string generate_wl_shift_register_module_name(const std::string& memory_model_name,
|
||||
const size_t& shift_register_size) {
|
||||
return std::string("wl_shift_register_") + memory_model_name + std::string("_size") + std::to_string(shift_register_size);
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* Generate the port name for the input bus of a routing multiplexer
|
||||
* This is very useful in Verilog code generation where the inputs of
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "circuit_library.h"
|
||||
#include "device_grid.h"
|
||||
#include "openfpga_port.h"
|
||||
#include "module_manager_fwd.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
|
@ -183,6 +184,15 @@ std::string generate_sram_local_port_name(const CircuitLibrary& circuit_lib,
|
|||
const e_config_protocol_type& sram_orgz_type,
|
||||
const e_circuit_model_port_type& port_type);
|
||||
|
||||
std::string generate_regional_blwl_port_name(const std::string& blwl_port_prefix,
|
||||
const ConfigRegionId& region_id);
|
||||
|
||||
std::string generate_bl_shift_register_module_name(const std::string& memory_model_name,
|
||||
const size_t& shift_register_size);
|
||||
|
||||
std::string generate_wl_shift_register_module_name(const std::string& memory_model_name,
|
||||
const size_t& shift_register_size);
|
||||
|
||||
std::string generate_mux_input_bus_port_name(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& mux_model,
|
||||
const size_t& mux_size,
|
||||
|
|
|
@ -56,9 +56,8 @@ int read_arch(OpenfpgaContext& openfpga_context,
|
|||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
|
||||
if (false == check_configurable_memory_circuit_model(openfpga_context.arch().config_protocol.type(),
|
||||
openfpga_context.arch().circuit_lib,
|
||||
openfpga_context.arch().config_protocol.memory_model())) {
|
||||
if (false == check_configurable_memory_circuit_model(openfpga_context.arch().config_protocol,
|
||||
openfpga_context.arch().circuit_lib)) {
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@ int write_fabric_verilog(OpenfpgaContext& openfpga_ctx,
|
|||
|
||||
fpga_fabric_verilog(openfpga_ctx.mutable_module_graph(),
|
||||
openfpga_ctx.mutable_verilog_netlists(),
|
||||
openfpga_ctx.blwl_shift_register_banks(),
|
||||
openfpga_ctx.arch().circuit_lib,
|
||||
openfpga_ctx.mux_lib(),
|
||||
openfpga_ctx.decoder_lib(),
|
||||
|
@ -106,6 +107,7 @@ int write_full_testbench(const OpenfpgaContext& openfpga_ctx,
|
|||
return fpga_verilog_full_testbench(openfpga_ctx.module_graph(),
|
||||
openfpga_ctx.bitstream_manager(),
|
||||
openfpga_ctx.fabric_bitstream(),
|
||||
openfpga_ctx.blwl_shift_register_banks(),
|
||||
g_vpr_ctx.atom(),
|
||||
g_vpr_ctx.placement(),
|
||||
pin_constraints,
|
||||
|
|
|
@ -184,6 +184,19 @@ ModuleId build_wl_memory_decoder_module(ModuleManager& module_manager,
|
|||
module_manager.add_port(module_id, data_inv_port, ModuleManager::MODULE_OUTPUT_PORT);
|
||||
}
|
||||
|
||||
/* Add readback port */
|
||||
if (true == decoder_lib.use_readback(decoder)) {
|
||||
BasicPort readback_port(std::string(DECODER_READBACK_PORT_NAME), 1);
|
||||
module_manager.add_port(module_id, readback_port, ModuleManager::MODULE_INPUT_PORT);
|
||||
}
|
||||
|
||||
/* Add data read-enable port */
|
||||
if (true == decoder_lib.use_readback(decoder)) {
|
||||
BasicPort data_ren_port(std::string(DECODER_DATA_READ_ENABLE_PORT_NAME), data_size);
|
||||
module_manager.add_port(module_id, data_ren_port, ModuleManager::MODULE_OUTPUT_PORT);
|
||||
module_manager.set_port_is_register(module_id, data_ren_port.get_name(), true);
|
||||
}
|
||||
|
||||
return module_id;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ namespace openfpga {
|
|||
*******************************************************************/
|
||||
int build_device_module_graph(ModuleManager& module_manager,
|
||||
DecoderLibrary& decoder_lib,
|
||||
MemoryBankShiftRegisterBanks& blwl_sr_banks,
|
||||
const OpenfpgaContext& openfpga_ctx,
|
||||
const DeviceContext& vpr_device_ctx,
|
||||
const bool& frame_view,
|
||||
|
@ -112,6 +113,7 @@ int build_device_module_graph(ModuleManager& module_manager,
|
|||
/* Build FPGA fabric top-level module */
|
||||
status = build_top_module(module_manager,
|
||||
decoder_lib,
|
||||
blwl_sr_banks,
|
||||
openfpga_ctx.arch().circuit_lib,
|
||||
openfpga_ctx.vpr_device_annotation(),
|
||||
vpr_device_ctx.grid,
|
||||
|
|
|
@ -17,6 +17,7 @@ namespace openfpga {
|
|||
|
||||
int build_device_module_graph(ModuleManager& module_manager,
|
||||
DecoderLibrary& decoder_lib,
|
||||
MemoryBankShiftRegisterBanks& blwl_sr_banks,
|
||||
const OpenfpgaContext& openfpga_ctx,
|
||||
const DeviceContext& vpr_device_ctx,
|
||||
const bool& frame_view,
|
||||
|
|
|
@ -24,6 +24,7 @@ namespace openfpga {
|
|||
* and cache their port/pin index in the top-level module
|
||||
*******************************************************************/
|
||||
FabricGlobalPortInfo build_fabric_global_port_info(const ModuleManager& module_manager,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const TileAnnotation& tile_annotation,
|
||||
const CircuitLibrary& circuit_lib) {
|
||||
vtr::ScopedStartFinishTimer timer("Create global port info for top module");
|
||||
|
@ -53,8 +54,18 @@ FabricGlobalPortInfo build_fabric_global_port_info(const ModuleManager& module_m
|
|||
fabric_global_port_info.set_global_port_is_reset(fabric_port, circuit_lib.port_is_reset(global_port));
|
||||
fabric_global_port_info.set_global_port_is_set(fabric_port, circuit_lib.port_is_set(global_port));
|
||||
fabric_global_port_info.set_global_port_is_prog(fabric_port, circuit_lib.port_is_prog(global_port));
|
||||
fabric_global_port_info.set_global_port_is_shift_register(fabric_port, circuit_lib.port_is_shift_register(global_port));
|
||||
fabric_global_port_info.set_global_port_is_config_enable(fabric_port, circuit_lib.port_is_config_enable(global_port));
|
||||
fabric_global_port_info.set_global_port_default_value(fabric_port, circuit_lib.port_default_value(global_port));
|
||||
|
||||
/* Special for BL/WL shift register models: we should identify which clock belongs to BL and which clock belongs to WL */
|
||||
if (config_protocol.bl_memory_model() == circuit_lib.port_parent_model(global_port)) {
|
||||
fabric_global_port_info.set_global_port_is_bl(fabric_port, true);
|
||||
}
|
||||
|
||||
if (config_protocol.wl_memory_model() == circuit_lib.port_parent_model(global_port)) {
|
||||
fabric_global_port_info.set_global_port_is_wl(fabric_port, true);
|
||||
}
|
||||
}
|
||||
|
||||
/* Add the global ports from tile annotation */
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
namespace openfpga {
|
||||
|
||||
FabricGlobalPortInfo build_fabric_global_port_info(const ModuleManager& module_manager,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const TileAnnotation& tile_annotation,
|
||||
const CircuitLibrary& circuit_lib);
|
||||
|
||||
|
|
|
@ -279,7 +279,7 @@ void build_primitive_block_module(ModuleManager& module_manager,
|
|||
size_t num_shared_config_bits = find_circuit_num_shared_config_bits(circuit_lib, primitive_model, sram_orgz_type);
|
||||
if (0 < num_shared_config_bits) {
|
||||
/* Check: this SRAM organization type must be memory-bank ! */
|
||||
VTR_ASSERT( CONFIG_MEM_MEMORY_BANK == sram_orgz_type );
|
||||
VTR_ASSERT( CONFIG_MEM_MEMORY_BANK == sram_orgz_type || CONFIG_MEM_QL_MEMORY_BANK == sram_orgz_type );
|
||||
/* Generate a list of ports */
|
||||
add_reserved_sram_ports_to_module_manager(module_manager, primitive_module,
|
||||
num_shared_config_bits);
|
||||
|
@ -1114,15 +1114,15 @@ void build_physical_tile_module(ModuleManager& module_manager,
|
|||
*/
|
||||
size_t module_num_config_bits = find_module_num_config_bits_from_child_modules(module_manager, grid_module, circuit_lib, sram_model, sram_orgz_type);
|
||||
if (0 < module_num_config_bits) {
|
||||
add_sram_ports_to_module_manager(module_manager, grid_module, circuit_lib, sram_model, sram_orgz_type, module_num_config_bits);
|
||||
add_pb_sram_ports_to_module_manager(module_manager, grid_module, circuit_lib, sram_model, sram_orgz_type, module_num_config_bits);
|
||||
}
|
||||
|
||||
/* Add module nets to connect memory cells inside
|
||||
* This is a one-shot addition that covers all the memory modules in this pb module!
|
||||
*/
|
||||
if (0 < module_manager.configurable_children(grid_module).size()) {
|
||||
add_module_nets_memory_config_bus(module_manager, decoder_lib, grid_module,
|
||||
sram_orgz_type, circuit_lib.design_tech_type(sram_model));
|
||||
add_pb_module_nets_memory_config_bus(module_manager, decoder_lib, grid_module,
|
||||
sram_orgz_type, circuit_lib.design_tech_type(sram_model));
|
||||
}
|
||||
|
||||
VTR_LOGV(verbose, "Done\n");
|
||||
|
|
|
@ -78,7 +78,6 @@ void add_module_input_nets_to_mem_modules(ModuleManager& module_manager,
|
|||
* pin of output port of the memory module, where W is the size of port
|
||||
* 3. It assumes fixed port name for output ports
|
||||
********************************************************************/
|
||||
static
|
||||
std::vector<ModuleNetId> add_module_output_nets_to_chain_mem_modules(ModuleManager& module_manager,
|
||||
const ModuleId& mem_module,
|
||||
const std::string& mem_module_output_name,
|
||||
|
@ -366,12 +365,15 @@ void build_memory_flatten_module(ModuleManager& module_manager,
|
|||
/* Get the BL/WL ports from the SRAM */
|
||||
std::vector<CircuitPortId> sram_bl_ports = circuit_lib.model_ports_by_type(sram_model, CIRCUIT_MODEL_PORT_BL, true);
|
||||
std::vector<CircuitPortId> sram_wl_ports = circuit_lib.model_ports_by_type(sram_model, CIRCUIT_MODEL_PORT_WL, true);
|
||||
/* Optional: Get the WLR ports from the SRAM */
|
||||
std::vector<CircuitPortId> sram_wlr_ports = circuit_lib.model_ports_by_type(sram_model, CIRCUIT_MODEL_PORT_WLR, true);
|
||||
/* Get the output ports from the SRAM */
|
||||
std::vector<CircuitPortId> sram_output_ports = circuit_lib.model_ports_by_type(sram_model, CIRCUIT_MODEL_PORT_OUTPUT, true);
|
||||
|
||||
/* Ensure that we have only 1 BL, 1 WL and 2 output ports*/
|
||||
/* Ensure that we have only 1 BL, 1 WL and 2 output ports, as well as an optional WLR*/
|
||||
VTR_ASSERT(1 == sram_bl_ports.size());
|
||||
VTR_ASSERT(1 == sram_wl_ports.size());
|
||||
VTR_ASSERT(2 > sram_wlr_ports.size());
|
||||
VTR_ASSERT(2 == sram_output_ports.size());
|
||||
|
||||
/* Create a module and add to the module manager */
|
||||
|
@ -389,6 +391,12 @@ void build_memory_flatten_module(ModuleManager& module_manager,
|
|||
BasicPort wl_port(std::string(MEMORY_WL_PORT_NAME), num_mems);
|
||||
ModulePortId mem_wl_port = module_manager.add_port(mem_module, wl_port, ModuleManager::MODULE_INPUT_PORT);
|
||||
|
||||
BasicPort wlr_port(std::string(MEMORY_WLR_PORT_NAME), num_mems);
|
||||
ModulePortId mem_wlr_port = ModulePortId::INVALID();
|
||||
if (!sram_wlr_ports.empty()) {
|
||||
mem_wlr_port = module_manager.add_port(mem_module, wlr_port, ModuleManager::MODULE_INPUT_PORT);
|
||||
}
|
||||
|
||||
/* Add each output port: port width should match the number of memories */
|
||||
for (size_t iport = 0; iport < sram_output_ports.size(); ++iport) {
|
||||
std::string port_name;
|
||||
|
@ -419,6 +427,9 @@ void build_memory_flatten_module(ModuleManager& module_manager,
|
|||
for (const CircuitPortId& port : sram_wl_ports) {
|
||||
add_module_input_nets_to_mem_modules(module_manager, mem_module, mem_wl_port, circuit_lib, port, sram_mem_module, i, sram_mem_instance);
|
||||
}
|
||||
for (const CircuitPortId& port : sram_wlr_ports) {
|
||||
add_module_input_nets_to_mem_modules(module_manager, mem_module, mem_wlr_port, circuit_lib, port, sram_mem_module, i, sram_mem_instance);
|
||||
}
|
||||
/* Wire outputs of child module to outputs of parent module */
|
||||
add_module_output_nets_to_mem_modules(module_manager, mem_module, circuit_lib, sram_output_ports, sram_mem_module, i, sram_mem_instance);
|
||||
}
|
||||
|
@ -644,9 +655,9 @@ void build_frame_memory_module(ModuleManager& module_manager,
|
|||
* If we find one, we use the module.
|
||||
* Otherwise, we create one and add it to the decoder library
|
||||
*/
|
||||
DecoderId decoder_id = frame_decoder_lib.find_decoder(addr_size, data_size, true, false, use_data_inv);
|
||||
DecoderId decoder_id = frame_decoder_lib.find_decoder(addr_size, data_size, true, false, use_data_inv, false);
|
||||
if (DecoderId::INVALID() == decoder_id) {
|
||||
decoder_id = frame_decoder_lib.add_decoder(addr_size, data_size, true, false, use_data_inv);
|
||||
decoder_id = frame_decoder_lib.add_decoder(addr_size, data_size, true, false, use_data_inv, false);
|
||||
}
|
||||
VTR_ASSERT(DecoderId::INVALID() != decoder_id);
|
||||
|
||||
|
@ -786,6 +797,7 @@ void build_memory_module(ModuleManager& module_manager,
|
|||
const size_t& num_mems) {
|
||||
switch (sram_orgz_type) {
|
||||
case CONFIG_MEM_STANDALONE:
|
||||
case CONFIG_MEM_QL_MEMORY_BANK:
|
||||
case CONFIG_MEM_MEMORY_BANK:
|
||||
build_memory_flatten_module(module_manager, circuit_lib,
|
||||
module_name, sram_model, num_mems);
|
||||
|
|
|
@ -16,6 +16,15 @@
|
|||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
std::vector<ModuleNetId> add_module_output_nets_to_chain_mem_modules(ModuleManager& module_manager,
|
||||
const ModuleId& mem_module,
|
||||
const std::string& mem_module_output_name,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitPortId& circuit_port,
|
||||
const ModuleId& child_module,
|
||||
const size_t& child_index,
|
||||
const size_t& child_instance);
|
||||
|
||||
void build_memory_modules(ModuleManager& module_manager,
|
||||
DecoderLibrary& arch_decoder_lib,
|
||||
const MuxLibrary& mux_lib,
|
||||
|
|
|
@ -462,16 +462,16 @@ void build_switch_block_module(ModuleManager& module_manager,
|
|||
*/
|
||||
size_t module_num_config_bits = find_module_num_config_bits_from_child_modules(module_manager, sb_module, circuit_lib, sram_model, sram_orgz_type);
|
||||
if (0 < module_num_config_bits) {
|
||||
add_sram_ports_to_module_manager(module_manager, sb_module, circuit_lib, sram_model, sram_orgz_type, module_num_config_bits);
|
||||
add_pb_sram_ports_to_module_manager(module_manager, sb_module, circuit_lib, sram_model, sram_orgz_type, module_num_config_bits);
|
||||
}
|
||||
|
||||
/* Add all the nets to connect configuration ports from memory module to primitive modules
|
||||
* This is a one-shot addition that covers all the memory modules in this primitive module!
|
||||
*/
|
||||
if (0 < module_manager.configurable_children(sb_module).size()) {
|
||||
add_module_nets_memory_config_bus(module_manager, decoder_lib,
|
||||
sb_module,
|
||||
sram_orgz_type, circuit_lib.design_tech_type(sram_model));
|
||||
add_pb_module_nets_memory_config_bus(module_manager, decoder_lib,
|
||||
sb_module,
|
||||
sram_orgz_type, circuit_lib.design_tech_type(sram_model));
|
||||
}
|
||||
|
||||
VTR_LOGV(verbose, "Done\n");
|
||||
|
@ -890,16 +890,16 @@ void build_connection_block_module(ModuleManager& module_manager,
|
|||
*/
|
||||
size_t module_num_config_bits = find_module_num_config_bits_from_child_modules(module_manager, cb_module, circuit_lib, sram_model, sram_orgz_type);
|
||||
if (0 < module_num_config_bits) {
|
||||
add_sram_ports_to_module_manager(module_manager, cb_module, circuit_lib, sram_model, sram_orgz_type, module_num_config_bits);
|
||||
add_pb_sram_ports_to_module_manager(module_manager, cb_module, circuit_lib, sram_model, sram_orgz_type, module_num_config_bits);
|
||||
}
|
||||
|
||||
/* Add all the nets to connect configuration ports from memory module to primitive modules
|
||||
* This is a one-shot addition that covers all the memory modules in this primitive module!
|
||||
*/
|
||||
if (0 < module_manager.configurable_children(cb_module).size()) {
|
||||
add_module_nets_memory_config_bus(module_manager, decoder_lib,
|
||||
cb_module,
|
||||
sram_orgz_type, circuit_lib.design_tech_type(sram_model));
|
||||
add_pb_module_nets_memory_config_bus(module_manager, decoder_lib,
|
||||
cb_module,
|
||||
sram_orgz_type, circuit_lib.design_tech_type(sram_model));
|
||||
}
|
||||
|
||||
VTR_LOGV(verbose, "Done\n");
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "build_top_module_utils.h"
|
||||
#include "build_top_module_connection.h"
|
||||
#include "build_top_module_memory.h"
|
||||
#include "build_top_module_memory_bank.h"
|
||||
#include "build_top_module_directs.h"
|
||||
|
||||
#include "build_module_graph_utils.h"
|
||||
|
@ -283,6 +284,7 @@ vtr::Matrix<size_t> add_top_module_connection_block_instances(ModuleManager& mod
|
|||
*******************************************************************/
|
||||
int build_top_module(ModuleManager& module_manager,
|
||||
DecoderLibrary& decoder_lib,
|
||||
MemoryBankShiftRegisterBanks& blwl_sr_banks,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const VprDeviceAnnotation& vpr_device_annotation,
|
||||
const DeviceGrid& grids,
|
||||
|
@ -341,12 +343,6 @@ int build_top_module(ModuleManager& module_manager,
|
|||
tile_direct, arch_direct);
|
||||
}
|
||||
|
||||
/* Add global ports to the pb_module:
|
||||
* This is a much easier job after adding sub modules (instances),
|
||||
* we just need to find all the global ports from the child modules and build a list of it
|
||||
*/
|
||||
add_module_global_ports_from_child_modules(module_manager, top_module);
|
||||
|
||||
/* Add global ports from grid ports that are defined as global in tile annotation */
|
||||
status = add_top_module_global_ports_from_grid_modules(module_manager, top_module, tile_annotation, vpr_device_annotation, grids, grid_instance_ids);
|
||||
if (CMD_EXEC_FATAL_ERROR == status) {
|
||||
|
@ -387,6 +383,11 @@ int build_top_module(ModuleManager& module_manager,
|
|||
if (CMD_EXEC_FATAL_ERROR == status) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = load_top_module_shift_register_banks_from_fabric_key(fabric_key, blwl_sr_banks);
|
||||
if (CMD_EXEC_FATAL_ERROR == status) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
/* Shuffle the configurable children in a random sequence */
|
||||
|
@ -394,6 +395,13 @@ int build_top_module(ModuleManager& module_manager,
|
|||
shuffle_top_module_configurable_children(module_manager, top_module, config_protocol);
|
||||
}
|
||||
|
||||
/* Build shift register bank detailed connections */
|
||||
sync_memory_bank_shift_register_banks_with_config_protocol_settings(module_manager,
|
||||
blwl_sr_banks,
|
||||
config_protocol,
|
||||
top_module,
|
||||
circuit_lib);
|
||||
|
||||
/* Add shared SRAM ports from the sub-modules under this Verilog module
|
||||
* This is a much easier job after adding sub modules (instances),
|
||||
* we just need to find all the I/O ports from the child modules and build a list of it
|
||||
|
@ -407,12 +415,13 @@ int build_top_module(ModuleManager& module_manager,
|
|||
* This is a much easier job after adding sub modules (instances),
|
||||
* we just need to find all the I/O ports from the child modules and build a list of it
|
||||
*/
|
||||
vtr::vector<ConfigRegionId, size_t> top_module_num_config_bits = find_top_module_regional_num_config_bit(module_manager, top_module, circuit_lib, sram_model, config_protocol.type());
|
||||
TopModuleNumConfigBits top_module_num_config_bits = find_top_module_regional_num_config_bit(module_manager, top_module, circuit_lib, sram_model, config_protocol.type());
|
||||
|
||||
if (!top_module_num_config_bits.empty()) {
|
||||
add_top_module_sram_ports(module_manager, top_module,
|
||||
circuit_lib, sram_model,
|
||||
config_protocol,
|
||||
const_cast<const MemoryBankShiftRegisterBanks&>(blwl_sr_banks),
|
||||
top_module_num_config_bits);
|
||||
}
|
||||
|
||||
|
@ -420,12 +429,20 @@ int build_top_module(ModuleManager& module_manager,
|
|||
* This is a one-shot addition that covers all the memory modules in this pb module!
|
||||
*/
|
||||
if (0 < module_manager.configurable_children(top_module).size()) {
|
||||
add_top_module_nets_memory_config_bus(module_manager, decoder_lib,
|
||||
add_top_module_nets_memory_config_bus(module_manager, decoder_lib, blwl_sr_banks,
|
||||
top_module,
|
||||
circuit_lib,
|
||||
config_protocol, circuit_lib.design_tech_type(sram_model),
|
||||
top_module_num_config_bits);
|
||||
}
|
||||
|
||||
/* Add global ports to the top module:
|
||||
* This is a much easier job after adding sub modules (instances),
|
||||
* we just need to find all the global ports from the child modules and build a list of it
|
||||
* @note This function is called after the add_top_module_nets_memory_config_bus() because it may add some sub modules
|
||||
*/
|
||||
add_module_global_ports_from_child_modules(module_manager, top_module);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "config_protocol.h"
|
||||
#include "module_manager.h"
|
||||
#include "fabric_key.h"
|
||||
#include "memory_bank_shift_register_banks.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
|
@ -29,6 +30,7 @@ namespace openfpga {
|
|||
|
||||
int build_top_module(ModuleManager& module_manager,
|
||||
DecoderLibrary& decoder_lib,
|
||||
MemoryBankShiftRegisterBanks& blwl_sr_banks,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const VprDeviceAnnotation& vpr_device_annotation,
|
||||
const DeviceGrid& grids,
|
||||
|
|
|
@ -20,9 +20,11 @@
|
|||
#include "openfpga_naming.h"
|
||||
|
||||
#include "memory_utils.h"
|
||||
#include "memory_bank_utils.h"
|
||||
#include "decoder_library_utils.h"
|
||||
#include "module_manager_utils.h"
|
||||
#include "build_decoder_modules.h"
|
||||
#include "build_top_module_memory_bank.h"
|
||||
#include "build_top_module_memory.h"
|
||||
|
||||
/* begin namespace openfpga */
|
||||
|
@ -74,8 +76,14 @@ void organize_top_module_tile_cb_modules(ModuleManager& module_manager,
|
|||
if (0 < find_module_num_config_bits(module_manager, cb_module,
|
||||
circuit_lib, sram_model,
|
||||
sram_orgz_type)) {
|
||||
/* CBX coordinate conversion calculation: (1,0) -> (2,1) */
|
||||
vtr::Point<int> config_coord(rr_gsb.get_cb_x(cb_type) * 2, rr_gsb.get_cb_y(cb_type) * 2 + 1);
|
||||
if (cb_type == CHANY) {
|
||||
/* CBY has a different coordinate conversion calculation: (0,1) -> (1,2) */
|
||||
config_coord.set(rr_gsb.get_cb_x(cb_type) * 2 + 1, rr_gsb.get_cb_y(cb_type) * 2);
|
||||
}
|
||||
/* Note that use the original CB coodinate for instance id searching ! */
|
||||
module_manager.add_configurable_child(top_module, cb_module, cb_instance_ids[rr_gsb.get_cb_x(cb_type)][rr_gsb.get_cb_y(cb_type)]);
|
||||
module_manager.add_configurable_child(top_module, cb_module, cb_instance_ids[rr_gsb.get_cb_x(cb_type)][rr_gsb.get_cb_y(cb_type)], config_coord);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,6 +92,37 @@ void organize_top_module_tile_cb_modules(ModuleManager& module_manager,
|
|||
* to the memory modules and memory instances
|
||||
* This function is designed for organizing memory modules in top-level
|
||||
* module
|
||||
* This function also adds coordindates for each configurable child under the top-level module
|
||||
* of a FPGA fabric. A configurable child could be a programmable block (grid),
|
||||
* a Connection Block (CBx/y) or a Switch block (SB).
|
||||
* This function, we consider a coordinate system as follows
|
||||
* - Each row may consist of either (1) grid and CBy or (2) CBx and SB
|
||||
* - Each column may consist of either (1) grid and CBx or (2) CBy and SB
|
||||
*
|
||||
* Column 0 Column 1
|
||||
*
|
||||
* +---------------+----------+
|
||||
* | | |
|
||||
* | | |
|
||||
* | Grid | CBY | Row 3
|
||||
* | | |
|
||||
* | | |
|
||||
* +---------------+----------+
|
||||
* | | |
|
||||
* | CBX | SB | Row 2
|
||||
* | | |
|
||||
* +---------------+----------+
|
||||
* | | |
|
||||
* | | |
|
||||
* | Grid | CBY | Row 1
|
||||
* | | |
|
||||
* | | |
|
||||
* +---------------+----------+
|
||||
* | | |
|
||||
* | CBX | SB | Row 0
|
||||
* | | |
|
||||
* +---------------+----------+
|
||||
|
||||
*******************************************************************/
|
||||
static
|
||||
void organize_top_module_tile_memory_modules(ModuleManager& module_manager,
|
||||
|
@ -130,7 +169,8 @@ void organize_top_module_tile_memory_modules(ModuleManager& module_manager,
|
|||
if (0 < find_module_num_config_bits(module_manager, sb_module,
|
||||
circuit_lib, sram_model,
|
||||
sram_orgz_type)) {
|
||||
module_manager.add_configurable_child(top_module, sb_module, sb_instance_ids[rr_gsb.get_sb_x()][rr_gsb.get_sb_y()]);
|
||||
vtr::Point<int> config_coord(rr_gsb.get_sb_x() * 2 + 1, rr_gsb.get_sb_y() * 2 + 1);
|
||||
module_manager.add_configurable_child(top_module, sb_module, sb_instance_ids[rr_gsb.get_sb_x()][rr_gsb.get_sb_y()], config_coord);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -172,11 +212,11 @@ void organize_top_module_tile_memory_modules(ModuleManager& module_manager,
|
|||
if (0 < find_module_num_config_bits(module_manager, grid_module,
|
||||
circuit_lib, sram_model,
|
||||
sram_orgz_type)) {
|
||||
module_manager.add_configurable_child(top_module, grid_module, grid_instance_ids[tile_coord.x()][tile_coord.y()]);
|
||||
vtr::Point<int> config_coord(tile_coord.x() * 2, tile_coord.y() * 2);
|
||||
module_manager.add_configurable_child(top_module, grid_module, grid_instance_ids[tile_coord.x()][tile_coord.y()], config_coord);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Split memory modules into different configurable regions
|
||||
* This function will create regions based on the definition
|
||||
|
@ -231,7 +271,8 @@ void build_top_module_configurable_regions(ModuleManager& module_manager,
|
|||
|
||||
/* Exclude decoders from the list */
|
||||
size_t num_configurable_children = module_manager.configurable_children(top_module).size();
|
||||
if (CONFIG_MEM_MEMORY_BANK == config_protocol.type()) {
|
||||
if (CONFIG_MEM_MEMORY_BANK == config_protocol.type()
|
||||
|| CONFIG_MEM_QL_MEMORY_BANK == config_protocol.type()) {
|
||||
num_configurable_children -= 2;
|
||||
} else if (CONFIG_MEM_FRAME_BASED == config_protocol.type()) {
|
||||
num_configurable_children -= 1;
|
||||
|
@ -496,6 +537,7 @@ void shuffle_top_module_configurable_children(ModuleManager& module_manager,
|
|||
/* 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);
|
||||
std::vector<vtr::Point<int>> orig_configurable_child_coordinates = module_manager.configurable_child_coordinates(top_module);
|
||||
|
||||
/* Reorganize the configurable children */
|
||||
module_manager.clear_configurable_children(top_module);
|
||||
|
@ -503,7 +545,8 @@ void shuffle_top_module_configurable_children(ModuleManager& module_manager,
|
|||
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]]);
|
||||
orig_configurable_child_instances[shuffled_keys[ikey]],
|
||||
orig_configurable_child_coordinates[shuffled_keys[ikey]]);
|
||||
}
|
||||
|
||||
/* Reset configurable regions */
|
||||
|
@ -593,7 +636,8 @@ int load_top_module_memory_modules_from_fabric_key(ModuleManager& module_manager
|
|||
/* Now we can add the child to configurable children of the top module */
|
||||
module_manager.add_configurable_child(top_module,
|
||||
instance_info.first,
|
||||
instance_info.second);
|
||||
instance_info.second,
|
||||
fabric_key.key_coordinate(key));
|
||||
module_manager.add_configurable_child_to_region(top_module,
|
||||
top_module_config_region,
|
||||
instance_info.first,
|
||||
|
@ -614,13 +658,13 @@ int load_top_module_memory_modules_from_fabric_key(ModuleManager& module_manager
|
|||
* - This function should be called after the configurable children
|
||||
* is loaded to the top-level module!
|
||||
********************************************************************/
|
||||
vtr::vector<ConfigRegionId, size_t> find_top_module_regional_num_config_bit(const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& sram_model,
|
||||
const e_config_protocol_type& config_protocol_type) {
|
||||
TopModuleNumConfigBits find_top_module_regional_num_config_bit(const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& sram_model,
|
||||
const e_config_protocol_type& config_protocol_type) {
|
||||
/* Initialize the number of configuration bits for each region */
|
||||
vtr::vector<ConfigRegionId, size_t> num_config_bits(module_manager.regions(top_module).size(), 0);
|
||||
TopModuleNumConfigBits num_config_bits(module_manager.regions(top_module).size(), std::pair<size_t, size_t>(0, 0));
|
||||
|
||||
switch (config_protocol_type) {
|
||||
case CONFIG_MEM_STANDALONE:
|
||||
|
@ -632,7 +676,34 @@ vtr::vector<ConfigRegionId, size_t> find_top_module_regional_num_config_bit(cons
|
|||
*/
|
||||
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
|
||||
for (const ModuleId& child_module : module_manager.region_configurable_children(top_module, config_region)) {
|
||||
num_config_bits[config_region] += find_module_num_config_bits(module_manager, child_module, circuit_lib, sram_model, config_protocol_type);
|
||||
num_config_bits[config_region].first += find_module_num_config_bits(module_manager, child_module, circuit_lib, sram_model, config_protocol_type);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CONFIG_MEM_QL_MEMORY_BANK: {
|
||||
/* For QL memory bank: we will use the row and column information for each configuration child
|
||||
* in order to identify the number of unique BLs and WLs
|
||||
* In this configuration protocol,
|
||||
* - all the configurable child in the same row will share the same WLs
|
||||
* - the number of WLs per row is limited by the configurable child which requires most WLs
|
||||
* - each row has independent WLs
|
||||
* - all the configurable child in the same column will share the same BLs
|
||||
* - the number of BLs per column is limited by the configurable child which requires most BLs
|
||||
* - each column has independent BLs
|
||||
*/
|
||||
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
|
||||
std::map<int, size_t> num_bls_per_tile = compute_memory_bank_regional_bitline_numbers_per_tile(module_manager, top_module,
|
||||
config_region,
|
||||
circuit_lib, sram_model);
|
||||
std::map<int, size_t> num_wls_per_tile = compute_memory_bank_regional_wordline_numbers_per_tile(module_manager, top_module,
|
||||
config_region,
|
||||
circuit_lib, sram_model);
|
||||
for (const auto& kv : num_bls_per_tile) {
|
||||
num_config_bits[config_region].first += kv.second;
|
||||
}
|
||||
for (const auto& kv : num_wls_per_tile) {
|
||||
num_config_bits[config_region].second += kv.second;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -646,14 +717,14 @@ vtr::vector<ConfigRegionId, size_t> find_top_module_regional_num_config_bit(cons
|
|||
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
|
||||
for (const ModuleId& child_module : module_manager.region_configurable_children(top_module, config_region)) {
|
||||
size_t temp_num_config_bits = find_module_num_config_bits(module_manager, child_module, circuit_lib, sram_model, config_protocol_type);
|
||||
num_config_bits[config_region] = std::max((int)temp_num_config_bits, (int)num_config_bits[config_region]);
|
||||
num_config_bits[config_region].first = std::max(temp_num_config_bits, num_config_bits[config_region].first);
|
||||
}
|
||||
|
||||
/* If there are more than 2 configurable children, we need a decoder
|
||||
* Otherwise, we can just short wire the address port to the children
|
||||
*/
|
||||
if (1 < module_manager.region_configurable_children(top_module, config_region).size()) {
|
||||
num_config_bits[config_region] += find_mux_local_decoder_addr_size(module_manager.region_configurable_children(top_module, config_region).size());
|
||||
num_config_bits[config_region].first += find_mux_local_decoder_addr_size(module_manager.region_configurable_children(top_module, config_region).size());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -687,6 +758,7 @@ size_t generate_top_module_sram_port_size(const ConfigProtocol& config_protocol,
|
|||
case CONFIG_MEM_STANDALONE:
|
||||
break;
|
||||
case CONFIG_MEM_SCAN_CHAIN:
|
||||
case CONFIG_MEM_QL_MEMORY_BANK:
|
||||
case CONFIG_MEM_MEMORY_BANK:
|
||||
case CONFIG_MEM_FRAME_BASED:
|
||||
/* CCFF head/tail, data input could be multi-bit ports */
|
||||
|
@ -706,34 +778,41 @@ size_t generate_top_module_sram_port_size(const ConfigProtocol& config_protocol,
|
|||
* top-level module
|
||||
* The type and names of added ports strongly depend on the
|
||||
* organization of SRAMs.
|
||||
* 1. Standalone SRAMs:
|
||||
* two ports will be added, which are BL and WL
|
||||
* 2. Scan-chain Flip-flops:
|
||||
* two ports will be added, which are the head of scan-chain
|
||||
* and the tail of scan-chain
|
||||
* IMPORTANT: the port size will be forced to 1 in this case
|
||||
* because the head and tail are both 1-bit ports!!!
|
||||
* 3. Memory decoders:
|
||||
* - An enable signal
|
||||
* - A BL address port
|
||||
* - A WL address port
|
||||
* - A data-in port for the BL decoder
|
||||
* 4. Frame-based memory:
|
||||
* - An Enable signal
|
||||
* - An address port, whose size depends on the number of config bits
|
||||
* and the maximum size of address ports of configurable children
|
||||
* - An data_in port (single-bit)
|
||||
* - Standalone SRAMs:
|
||||
* two ports will be added, which are BL and WL
|
||||
* - Scan-chain Flip-flops:
|
||||
* two ports will be added, which are the head of scan-chain
|
||||
* and the tail of scan-chain
|
||||
* IMPORTANT: the port size will be forced to 1 in this case
|
||||
* because the head and tail are both 1-bit ports!!!
|
||||
* - Memory decoders:
|
||||
* - An enable signal
|
||||
* - A BL address port
|
||||
* - A WL address port
|
||||
* - A data-in port for the BL decoder
|
||||
* - QL memory decoder:
|
||||
* - An enable signal
|
||||
* - An BL address port
|
||||
* - A WL address port
|
||||
* - A data-in port for the BL decoder
|
||||
* @note In this memory decoders, the address size will be computed in a different way than the regular one
|
||||
* - Frame-based memory:
|
||||
* - An Enable signal
|
||||
* - An address port, whose size depends on the number of config bits
|
||||
* and the maximum size of address ports of configurable children
|
||||
* - An data_in port (single-bit)
|
||||
********************************************************************/
|
||||
void add_top_module_sram_ports(ModuleManager& module_manager,
|
||||
const ModuleId& module_id,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& sram_model,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const vtr::vector<ConfigRegionId, size_t>& num_config_bits) {
|
||||
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
|
||||
const TopModuleNumConfigBits& num_config_bits) {
|
||||
std::vector<std::string> sram_port_names = generate_sram_port_names(circuit_lib, sram_model, config_protocol.type());
|
||||
size_t total_num_config_bits = 0;
|
||||
for (const size_t& curr_num_config_bits : num_config_bits) {
|
||||
total_num_config_bits += curr_num_config_bits;
|
||||
for (const auto& curr_num_config_bits : num_config_bits) {
|
||||
total_num_config_bits += curr_num_config_bits.first;
|
||||
}
|
||||
size_t sram_port_size = generate_top_module_sram_port_size(config_protocol, total_num_config_bits);
|
||||
|
||||
|
@ -754,7 +833,7 @@ void add_top_module_sram_ports(ModuleManager& module_manager,
|
|||
/* BL address size is the largest among all the regions */
|
||||
size_t bl_addr_size = 0;
|
||||
for (const ConfigRegionId& config_region : module_manager.regions(module_id)) {
|
||||
bl_addr_size = std::max(bl_addr_size, find_memory_decoder_addr_size(num_config_bits[config_region]));
|
||||
bl_addr_size = std::max(bl_addr_size, find_memory_decoder_addr_size(num_config_bits[config_region].first));
|
||||
}
|
||||
BasicPort bl_addr_port(std::string(DECODER_BL_ADDRESS_PORT_NAME), bl_addr_size);
|
||||
module_manager.add_port(module_id, bl_addr_port, ModuleManager::MODULE_INPUT_PORT);
|
||||
|
@ -762,7 +841,7 @@ void add_top_module_sram_ports(ModuleManager& module_manager,
|
|||
/* WL address size is the largest among all the regions */
|
||||
size_t wl_addr_size = 0;
|
||||
for (const ConfigRegionId& config_region : module_manager.regions(module_id)) {
|
||||
wl_addr_size = std::max(wl_addr_size, find_memory_decoder_addr_size(num_config_bits[config_region]));
|
||||
wl_addr_size = std::max(wl_addr_size, find_memory_decoder_addr_size(num_config_bits[config_region].first));
|
||||
}
|
||||
BasicPort wl_addr_port(std::string(DECODER_WL_ADDRESS_PORT_NAME), wl_addr_size);
|
||||
module_manager.add_port(module_id, wl_addr_port, ModuleManager::MODULE_INPUT_PORT);
|
||||
|
@ -773,6 +852,10 @@ void add_top_module_sram_ports(ModuleManager& module_manager,
|
|||
|
||||
break;
|
||||
}
|
||||
case CONFIG_MEM_QL_MEMORY_BANK: {
|
||||
add_top_module_ql_memory_bank_sram_ports(module_manager, module_id, circuit_lib, config_protocol, blwl_sr_banks, num_config_bits);
|
||||
break;
|
||||
}
|
||||
case CONFIG_MEM_SCAN_CHAIN: {
|
||||
/* Note that configuration chain tail is an output while head is an input
|
||||
* IMPORTANT: this is co-designed with function generate_sram_port_names()
|
||||
|
@ -798,8 +881,8 @@ void add_top_module_sram_ports(ModuleManager& module_manager,
|
|||
module_manager.add_port(module_id, en_port, ModuleManager::MODULE_INPUT_PORT);
|
||||
|
||||
size_t max_num_config_bits = 0;
|
||||
for (const size_t& curr_num_config_bits : num_config_bits) {
|
||||
max_num_config_bits = std::max(max_num_config_bits, curr_num_config_bits);
|
||||
for (const auto& curr_num_config_bits : num_config_bits) {
|
||||
max_num_config_bits = std::max(max_num_config_bits, curr_num_config_bits.first);
|
||||
}
|
||||
|
||||
BasicPort addr_port(std::string(DECODER_ADDRESS_PORT_NAME), max_num_config_bits);
|
||||
|
@ -910,7 +993,7 @@ static
|
|||
void add_top_module_nets_cmos_memory_bank_config_bus(ModuleManager& module_manager,
|
||||
DecoderLibrary& decoder_lib,
|
||||
const ModuleId& top_module,
|
||||
const vtr::vector<ConfigRegionId, size_t>& num_config_bits) {
|
||||
const TopModuleNumConfigBits& num_config_bits) {
|
||||
/* Find Enable port from the top-level module */
|
||||
ModulePortId en_port = module_manager.find_module_port(top_module, std::string(DECODER_ENABLE_PORT_NAME));
|
||||
BasicPort en_port_info = module_manager.module_port(top_module, en_port);
|
||||
|
@ -935,13 +1018,13 @@ void add_top_module_nets_cmos_memory_bank_config_bus(ModuleManager& module_manag
|
|||
|
||||
/* Each memory bank has a unified number of BL/WLs */
|
||||
size_t num_bls = 0;
|
||||
for (const size_t& curr_config_bits : num_config_bits) {
|
||||
num_bls = std::max(num_bls, find_memory_decoder_data_size(curr_config_bits));
|
||||
for (const auto& curr_config_bits : num_config_bits) {
|
||||
num_bls = std::max(num_bls, find_memory_decoder_data_size(curr_config_bits.first));
|
||||
}
|
||||
|
||||
size_t num_wls = 0;
|
||||
for (const size_t& curr_config_bits : num_config_bits) {
|
||||
num_wls = std::max(num_wls, find_memory_decoder_data_size(curr_config_bits));
|
||||
for (const auto& curr_config_bits : num_config_bits) {
|
||||
num_wls = std::max(num_wls, find_memory_decoder_data_size(curr_config_bits.first));
|
||||
}
|
||||
|
||||
/* Create separated memory bank circuitry, i.e., BL/WL decoders for each region */
|
||||
|
@ -953,9 +1036,9 @@ void add_top_module_nets_cmos_memory_bank_config_bus(ModuleManager& module_manag
|
|||
* Otherwise, we create one and add it to the decoder library
|
||||
*/
|
||||
DecoderId bl_decoder_id = decoder_lib.find_decoder(bl_addr_size, num_bls,
|
||||
true, true, false);
|
||||
true, true, false, false);
|
||||
if (DecoderId::INVALID() == bl_decoder_id) {
|
||||
bl_decoder_id = decoder_lib.add_decoder(bl_addr_size, num_bls, true, true, false);
|
||||
bl_decoder_id = decoder_lib.add_decoder(bl_addr_size, num_bls, true, true, false, false);
|
||||
}
|
||||
VTR_ASSERT(DecoderId::INVALID() != bl_decoder_id);
|
||||
|
||||
|
@ -981,9 +1064,9 @@ void add_top_module_nets_cmos_memory_bank_config_bus(ModuleManager& module_manag
|
|||
* Otherwise, we create one and add it to the decoder library
|
||||
*/
|
||||
DecoderId wl_decoder_id = decoder_lib.find_decoder(wl_addr_size, num_wls,
|
||||
true, false, false);
|
||||
true, false, false, false);
|
||||
if (DecoderId::INVALID() == wl_decoder_id) {
|
||||
wl_decoder_id = decoder_lib.add_decoder(wl_addr_size, num_wls, true, false, false);
|
||||
wl_decoder_id = decoder_lib.add_decoder(wl_addr_size, num_wls, true, false, false, false);
|
||||
}
|
||||
VTR_ASSERT(DecoderId::INVALID() != wl_decoder_id);
|
||||
|
||||
|
@ -1430,9 +1513,9 @@ void add_top_module_nets_cmos_memory_frame_decoder_config_bus(ModuleManager& mod
|
|||
/* Search the decoder library and try to find one
|
||||
* If not found, create a new module and add it to the module manager
|
||||
*/
|
||||
DecoderId decoder_id = decoder_lib.find_decoder(addr_size, data_size, true, false, false);
|
||||
DecoderId decoder_id = decoder_lib.find_decoder(addr_size, data_size, true, false, false, false);
|
||||
if (DecoderId::INVALID() == decoder_id) {
|
||||
decoder_id = decoder_lib.add_decoder(addr_size, data_size, true, false, false);
|
||||
decoder_id = decoder_lib.add_decoder(addr_size, data_size, true, false, false, false);
|
||||
}
|
||||
VTR_ASSERT(DecoderId::INVALID() != decoder_id);
|
||||
|
||||
|
@ -1582,7 +1665,7 @@ static
|
|||
void add_top_module_nets_cmos_memory_frame_config_bus(ModuleManager& module_manager,
|
||||
DecoderLibrary& decoder_lib,
|
||||
const ModuleId& top_module,
|
||||
const vtr::vector<ConfigRegionId, size_t>& num_config_bits) {
|
||||
const TopModuleNumConfigBits& num_config_bits) {
|
||||
/* Find the number of address bits for the top-level module */
|
||||
ModulePortId top_addr_port = module_manager.find_module_port(top_module, std::string(DECODER_ADDRESS_PORT_NAME));
|
||||
BasicPort top_addr_port_info = module_manager.module_port(top_module, top_addr_port);
|
||||
|
@ -1598,7 +1681,7 @@ void add_top_module_nets_cmos_memory_frame_config_bus(ModuleManager& module_mana
|
|||
* - The number of address bits of the configurable child is the same as top-level
|
||||
*/
|
||||
if ( (1 == module_manager.region_configurable_children(top_module, config_region).size())
|
||||
&& (num_config_bits[config_region] == top_addr_size)) {
|
||||
&& (num_config_bits[config_region].first == top_addr_size)) {
|
||||
add_top_module_nets_cmos_memory_frame_short_config_bus(module_manager, top_module, config_region);
|
||||
} else {
|
||||
add_top_module_nets_cmos_memory_frame_decoder_config_bus(module_manager, decoder_lib, top_module, config_region);
|
||||
|
@ -1653,9 +1736,11 @@ void add_top_module_nets_cmos_memory_frame_config_bus(ModuleManager& module_mana
|
|||
static
|
||||
void add_top_module_nets_cmos_memory_config_bus(ModuleManager& module_manager,
|
||||
DecoderLibrary& decoder_lib,
|
||||
MemoryBankShiftRegisterBanks& blwl_sr_banks,
|
||||
const ModuleId& parent_module,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const vtr::vector<ConfigRegionId, size_t>& num_config_bits) {
|
||||
const TopModuleNumConfigBits& num_config_bits) {
|
||||
switch (config_protocol.type()) {
|
||||
case CONFIG_MEM_STANDALONE:
|
||||
add_module_nets_cmos_flatten_memory_config_bus(module_manager, parent_module,
|
||||
|
@ -1670,6 +1755,10 @@ void add_top_module_nets_cmos_memory_config_bus(ModuleManager& module_manager,
|
|||
case CONFIG_MEM_MEMORY_BANK:
|
||||
add_top_module_nets_cmos_memory_bank_config_bus(module_manager, decoder_lib, parent_module, num_config_bits);
|
||||
break;
|
||||
case CONFIG_MEM_QL_MEMORY_BANK:
|
||||
add_top_module_nets_cmos_ql_memory_bank_config_bus(module_manager, decoder_lib, blwl_sr_banks,
|
||||
parent_module, circuit_lib, config_protocol, num_config_bits);
|
||||
break;
|
||||
case CONFIG_MEM_FRAME_BASED:
|
||||
add_top_module_nets_cmos_memory_frame_config_bus(module_manager, decoder_lib, parent_module, num_config_bits);
|
||||
break;
|
||||
|
@ -1714,17 +1803,21 @@ void add_top_module_nets_cmos_memory_config_bus(ModuleManager& module_manager,
|
|||
*******************************************************************/
|
||||
void add_top_module_nets_memory_config_bus(ModuleManager& module_manager,
|
||||
DecoderLibrary& decoder_lib,
|
||||
MemoryBankShiftRegisterBanks& blwl_sr_banks,
|
||||
const ModuleId& parent_module,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const e_circuit_model_design_tech& mem_tech,
|
||||
const vtr::vector<ConfigRegionId, size_t>& num_config_bits) {
|
||||
const TopModuleNumConfigBits& num_config_bits) {
|
||||
|
||||
vtr::ScopedStartFinishTimer timer("Add module nets for configuration buses");
|
||||
|
||||
switch (mem_tech) {
|
||||
case CIRCUIT_MODEL_DESIGN_CMOS:
|
||||
add_top_module_nets_cmos_memory_config_bus(module_manager, decoder_lib,
|
||||
parent_module,
|
||||
blwl_sr_banks,
|
||||
parent_module,
|
||||
circuit_lib,
|
||||
config_protocol,
|
||||
num_config_bits);
|
||||
break;
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
#include "device_rr_gsb.h"
|
||||
#include "fabric_key.h"
|
||||
#include "config_protocol.h"
|
||||
#include "memory_bank_shift_register_banks.h"
|
||||
#include "build_top_module_memory_utils.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
|
@ -48,25 +50,28 @@ int load_top_module_memory_modules_from_fabric_key(ModuleManager& module_manager
|
|||
const ConfigProtocol& config_protocol,
|
||||
const FabricKey& fabric_key);
|
||||
|
||||
vtr::vector<ConfigRegionId, size_t> find_top_module_regional_num_config_bit(const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& sram_model,
|
||||
const e_config_protocol_type& config_protocol_type);
|
||||
TopModuleNumConfigBits find_top_module_regional_num_config_bit(const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& sram_model,
|
||||
const e_config_protocol_type& config_protocol_type);
|
||||
|
||||
void add_top_module_sram_ports(ModuleManager& module_manager,
|
||||
const ModuleId& module_id,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& sram_model,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const vtr::vector<ConfigRegionId, size_t>& num_config_bits);
|
||||
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
|
||||
const TopModuleNumConfigBits& num_config_bits);
|
||||
|
||||
void add_top_module_nets_memory_config_bus(ModuleManager& module_manager,
|
||||
DecoderLibrary& decoder_lib,
|
||||
MemoryBankShiftRegisterBanks& blwl_sr_banks,
|
||||
const ModuleId& parent_module,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const e_circuit_model_design_tech& mem_tech,
|
||||
const vtr::vector<ConfigRegionId, size_t>& num_config_bits);
|
||||
const TopModuleNumConfigBits& num_config_bits);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,53 @@
|
|||
#ifndef BUILD_TOP_MODULE_MEMORY_BANK_H
|
||||
#define BUILD_TOP_MODULE_MEMORY_BANK_H
|
||||
|
||||
/********************************************************************
|
||||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <array>
|
||||
#include "vtr_vector.h"
|
||||
#include "vtr_ndmatrix.h"
|
||||
#include "module_manager.h"
|
||||
#include "config_protocol.h"
|
||||
#include "circuit_library.h"
|
||||
#include "decoder_library.h"
|
||||
#include "memory_bank_shift_register_banks.h"
|
||||
#include "build_top_module_memory_utils.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
*******************************************************************/
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_manager,
|
||||
DecoderLibrary& decoder_lib,
|
||||
MemoryBankShiftRegisterBanks& blwl_sr_banks,
|
||||
const ModuleId& top_module,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const TopModuleNumConfigBits& num_config_bits);
|
||||
|
||||
void add_top_module_ql_memory_bank_sram_ports(ModuleManager& module_manager,
|
||||
const ModuleId& module_id,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
|
||||
const TopModuleNumConfigBits& num_config_bits);
|
||||
|
||||
int load_top_module_shift_register_banks_from_fabric_key(const FabricKey& fabric_key,
|
||||
MemoryBankShiftRegisterBanks& blwl_sr_banks);
|
||||
|
||||
void sync_memory_bank_shift_register_banks_with_config_protocol_settings(ModuleManager& module_manager,
|
||||
MemoryBankShiftRegisterBanks& blwl_sr_banks,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const ModuleId& top_module,
|
||||
const CircuitLibrary& circuit_lib);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
#endif
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef BUILD_TOP_MODULE_MEMORY_UTILS_H
|
||||
#define BUILD_TOP_MODULE_MEMORY_UTILS_H
|
||||
|
||||
/********************************************************************
|
||||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "vtr_vector.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
*******************************************************************/
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
/* A data structure to store the number of configuration bits for each configurable region
|
||||
* of the top-level module.
|
||||
* For different configuration protocol, the std::pair<size_t, size_t> represents different data
|
||||
* See details in each function about how the data is organized
|
||||
*/
|
||||
typedef vtr::vector<ConfigRegionId, std::pair<size_t, size_t>> TopModuleNumConfigBits;
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
#endif
|
|
@ -50,6 +50,21 @@ bool FabricGlobalPortInfo::global_port_is_prog(const FabricGlobalPortId& global_
|
|||
return global_port_is_prog_[global_port_id];
|
||||
}
|
||||
|
||||
bool FabricGlobalPortInfo::global_port_is_shift_register(const FabricGlobalPortId& global_port_id) const {
|
||||
VTR_ASSERT(valid_global_port_id(global_port_id));
|
||||
return global_port_is_shift_register_[global_port_id];
|
||||
}
|
||||
|
||||
bool FabricGlobalPortInfo::global_port_is_bl(const FabricGlobalPortId& global_port_id) const {
|
||||
VTR_ASSERT(valid_global_port_id(global_port_id));
|
||||
return global_port_is_bl_[global_port_id];
|
||||
}
|
||||
|
||||
bool FabricGlobalPortInfo::global_port_is_wl(const FabricGlobalPortId& global_port_id) const {
|
||||
VTR_ASSERT(valid_global_port_id(global_port_id));
|
||||
return global_port_is_wl_[global_port_id];
|
||||
}
|
||||
|
||||
bool FabricGlobalPortInfo::global_port_is_config_enable(const FabricGlobalPortId& global_port_id) const {
|
||||
VTR_ASSERT(valid_global_port_id(global_port_id));
|
||||
return global_port_is_config_enable_[global_port_id];
|
||||
|
@ -77,6 +92,9 @@ FabricGlobalPortId FabricGlobalPortInfo::create_global_port(const ModulePortId&
|
|||
global_port_is_set_.push_back(false);
|
||||
global_port_is_reset_.push_back(false);
|
||||
global_port_is_prog_.push_back(false);
|
||||
global_port_is_shift_register_.push_back(false);
|
||||
global_port_is_bl_.push_back(false);
|
||||
global_port_is_wl_.push_back(false);
|
||||
global_port_is_io_.push_back(false);
|
||||
global_port_is_config_enable_.push_back(false);
|
||||
global_port_default_values_.push_back(0);
|
||||
|
@ -108,6 +126,24 @@ void FabricGlobalPortInfo::set_global_port_is_prog(const FabricGlobalPortId& glo
|
|||
global_port_is_prog_[global_port_id] = is_prog;
|
||||
}
|
||||
|
||||
void FabricGlobalPortInfo::set_global_port_is_shift_register(const FabricGlobalPortId& global_port_id,
|
||||
const bool& is_shift_register) {
|
||||
VTR_ASSERT(valid_global_port_id(global_port_id));
|
||||
global_port_is_shift_register_[global_port_id] = is_shift_register;
|
||||
}
|
||||
|
||||
void FabricGlobalPortInfo::set_global_port_is_bl(const FabricGlobalPortId& global_port_id,
|
||||
const bool& is_bl) {
|
||||
VTR_ASSERT(valid_global_port_id(global_port_id));
|
||||
global_port_is_bl_[global_port_id] = is_bl;
|
||||
}
|
||||
|
||||
void FabricGlobalPortInfo::set_global_port_is_wl(const FabricGlobalPortId& global_port_id,
|
||||
const bool& is_wl) {
|
||||
VTR_ASSERT(valid_global_port_id(global_port_id));
|
||||
global_port_is_wl_[global_port_id] = is_wl;
|
||||
}
|
||||
|
||||
void FabricGlobalPortInfo::set_global_port_is_config_enable(const FabricGlobalPortId& global_port_id,
|
||||
const bool& is_config_enable) {
|
||||
VTR_ASSERT(valid_global_port_id(global_port_id));
|
||||
|
|
|
@ -36,6 +36,9 @@ class FabricGlobalPortInfo {
|
|||
bool global_port_is_set(const FabricGlobalPortId& global_port_id) const;
|
||||
bool global_port_is_reset(const FabricGlobalPortId& global_port_id) const;
|
||||
bool global_port_is_prog(const FabricGlobalPortId& global_port_id) const;
|
||||
bool global_port_is_bl(const FabricGlobalPortId& global_port_id) const;
|
||||
bool global_port_is_wl(const FabricGlobalPortId& global_port_id) const;
|
||||
bool global_port_is_shift_register(const FabricGlobalPortId& global_port_id) const;
|
||||
bool global_port_is_config_enable(const FabricGlobalPortId& global_port_id) const;
|
||||
bool global_port_is_io(const FabricGlobalPortId& global_port_id) const;
|
||||
size_t global_port_default_value(const FabricGlobalPortId& global_port_id) const;
|
||||
|
@ -52,6 +55,12 @@ class FabricGlobalPortInfo {
|
|||
const bool& is_reset);
|
||||
void set_global_port_is_prog(const FabricGlobalPortId& global_port_id,
|
||||
const bool& is_prog);
|
||||
void set_global_port_is_shift_register(const FabricGlobalPortId& global_port_id,
|
||||
const bool& is_shift_register);
|
||||
void set_global_port_is_bl(const FabricGlobalPortId& global_port_id,
|
||||
const bool& is_bl);
|
||||
void set_global_port_is_wl(const FabricGlobalPortId& global_port_id,
|
||||
const bool& is_wl);
|
||||
void set_global_port_is_config_enable(const FabricGlobalPortId& global_port_id,
|
||||
const bool& is_config_enable);
|
||||
void set_global_port_is_io(const FabricGlobalPortId& global_port_id,
|
||||
|
@ -68,6 +77,9 @@ class FabricGlobalPortInfo {
|
|||
vtr::vector<FabricGlobalPortId, bool> global_port_is_reset_;
|
||||
vtr::vector<FabricGlobalPortId, bool> global_port_is_set_;
|
||||
vtr::vector<FabricGlobalPortId, bool> global_port_is_prog_;
|
||||
vtr::vector<FabricGlobalPortId, bool> global_port_is_shift_register_;
|
||||
vtr::vector<FabricGlobalPortId, bool> global_port_is_bl_;
|
||||
vtr::vector<FabricGlobalPortId, bool> global_port_is_wl_;
|
||||
vtr::vector<FabricGlobalPortId, bool> global_port_is_config_enable_;
|
||||
vtr::vector<FabricGlobalPortId, bool> global_port_is_io_;
|
||||
vtr::vector<FabricGlobalPortId, size_t> global_port_default_values_;
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
|
||||
#include "openfpga_naming.h"
|
||||
|
||||
#include "memory_utils.h"
|
||||
|
||||
#include "fabric_key_writer.h"
|
||||
|
||||
/* begin namespace openfpga */
|
||||
|
@ -29,6 +31,8 @@ namespace openfpga {
|
|||
***************************************************************************************/
|
||||
int write_fabric_key_to_xml_file(const ModuleManager& module_manager,
|
||||
const std::string& fname,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
|
||||
const bool& verbose) {
|
||||
std::string timer_message = std::string("Write fabric key to XML file '") + fname + std::string("'");
|
||||
|
||||
|
@ -62,14 +66,31 @@ int write_fabric_key_to_xml_file(const ModuleManager& module_manager,
|
|||
size_t num_regions = module_manager.regions(top_module).size();
|
||||
fabric_key.reserve_regions(num_regions);
|
||||
|
||||
/* Create regions for the keys and load keys by region */
|
||||
/* Create regions and build a id map */
|
||||
std::map<ConfigRegionId, FabricRegionId> region_id_map;
|
||||
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
|
||||
FabricRegionId fabric_region = fabric_key.create_region();
|
||||
fabric_key.reserve_region_keys(fabric_region, module_manager.region_configurable_children(top_module, config_region).size());
|
||||
region_id_map[config_region] = fabric_region;
|
||||
}
|
||||
|
||||
/* Create regions for the keys and load keys by region */
|
||||
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
|
||||
/* Must have a valid one-to-one region mapping */
|
||||
auto result = region_id_map.find(config_region);
|
||||
VTR_ASSERT_SAFE(result != region_id_map.end());
|
||||
FabricRegionId fabric_region = result->second;
|
||||
|
||||
for (size_t ichild = 0; ichild < module_manager.region_configurable_children(top_module, config_region).size(); ++ichild) {
|
||||
/* Each configuration protocol has some child which should not be in the list. They are typically decoders */
|
||||
size_t curr_region_num_config_child = module_manager.region_configurable_children(top_module, config_region).size();
|
||||
size_t num_child_to_skip = estimate_num_configurable_children_to_skip_by_config_protocol(config_protocol, curr_region_num_config_child);
|
||||
curr_region_num_config_child -= num_child_to_skip;
|
||||
|
||||
fabric_key.reserve_region_keys(fabric_region, curr_region_num_config_child);
|
||||
|
||||
for (size_t ichild = 0; ichild < curr_region_num_config_child; ++ichild) {
|
||||
ModuleId child_module = module_manager.region_configurable_children(top_module, config_region)[ichild];
|
||||
size_t child_instance = module_manager.region_configurable_child_instances(top_module, config_region)[ichild];
|
||||
vtr::Point<int> child_coord = module_manager.region_configurable_child_coordinates(top_module, config_region)[ichild];
|
||||
|
||||
FabricKeyId key = fabric_key.create_key();
|
||||
fabric_key.set_key_name(key, module_manager.module_name(child_module));
|
||||
|
@ -79,11 +100,46 @@ int write_fabric_key_to_xml_file(const ModuleManager& module_manager,
|
|||
fabric_key.set_key_alias(key, module_manager.instance_name(top_module, child_module, child_instance));
|
||||
}
|
||||
|
||||
/* Add key coordinate */
|
||||
fabric_key.set_key_coordinate(key, child_coord);
|
||||
|
||||
/* Add keys to the region */
|
||||
fabric_key.add_key_to_region(fabric_region, key);
|
||||
}
|
||||
}
|
||||
|
||||
/* Skip invalid region, some architecture may not have BL/WL banks */
|
||||
if (0 < blwl_sr_banks.regions().size()) {
|
||||
/* Add BL shift register bank information, if there is any */
|
||||
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
|
||||
auto result = region_id_map.find(config_region);
|
||||
/* Must have a valid one-to-one region mapping */
|
||||
VTR_ASSERT_SAFE(result != region_id_map.end());
|
||||
FabricRegionId fabric_region = result->second;
|
||||
for (const FabricBitLineBankId& bank : blwl_sr_banks.bl_banks(config_region)) {
|
||||
FabricBitLineBankId fabric_bank = fabric_key.create_bl_shift_register_bank(fabric_region);
|
||||
for (const BasicPort& data_port : blwl_sr_banks.bl_bank_data_ports(config_region, bank)) {
|
||||
fabric_key.add_data_port_to_bl_shift_register_bank(fabric_region, fabric_bank, data_port);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Add WL shift register bank information, if there is any */
|
||||
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
|
||||
auto result = region_id_map.find(config_region);
|
||||
/* Must have a valid one-to-one region mapping */
|
||||
VTR_ASSERT_SAFE(result != region_id_map.end());
|
||||
FabricRegionId fabric_region = result->second;
|
||||
|
||||
for (const FabricWordLineBankId& bank : blwl_sr_banks.wl_banks(config_region)) {
|
||||
FabricWordLineBankId fabric_bank = fabric_key.create_wl_shift_register_bank(fabric_region);
|
||||
for (const BasicPort& data_port : blwl_sr_banks.wl_bank_data_ports(config_region, bank)) {
|
||||
fabric_key.add_data_port_to_wl_shift_register_bank(fabric_region, fabric_bank, data_port);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VTR_LOGV(verbose,
|
||||
"Created %lu regions and %lu keys for the top module %s.\n",
|
||||
num_regions, num_keys, top_module_name.c_str());
|
||||
|
|
|
@ -4,8 +4,10 @@
|
|||
/********************************************************************
|
||||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
#include "vpr_context.h"
|
||||
#include "openfpga_context.h"
|
||||
#include <string.h>
|
||||
#include "module_manager.h"
|
||||
#include "config_protocol.h"
|
||||
#include "memory_bank_shift_register_banks.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
|
@ -16,6 +18,8 @@ namespace openfpga {
|
|||
|
||||
int write_fabric_key_to_xml_file(const ModuleManager& module_manager,
|
||||
const std::string& fname,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
|
||||
const bool& verbose);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
|
|
@ -0,0 +1,495 @@
|
|||
#include <algorithm>
|
||||
#include "vtr_assert.h"
|
||||
#include "openfpga_reserved_words.h"
|
||||
#include "memory_bank_shift_register_banks.h"
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
ModuleManager::region_range MemoryBankShiftRegisterBanks::regions() const {
|
||||
return vtr::make_range(config_region_ids_.begin(), config_region_ids_.end());
|
||||
}
|
||||
|
||||
std::vector<size_t> MemoryBankShiftRegisterBanks::bl_bank_unique_sizes() const {
|
||||
std::vector<size_t> unique_sizes;
|
||||
for (const auto& region : bl_bank_data_ports_) {
|
||||
for (const auto& bank : region) {
|
||||
ConfigRegionId region_id = ConfigRegionId(®ion - &bl_bank_data_ports_[ConfigRegionId(0)]);
|
||||
FabricBitLineBankId bank_id = FabricBitLineBankId(&bank - ®ion[FabricBitLineBankId(0)]);
|
||||
size_t cur_bank_size = bl_bank_size(region_id, bank_id);
|
||||
if (unique_sizes.end() == std::find(unique_sizes.begin(), unique_sizes.end(), cur_bank_size)) {
|
||||
unique_sizes.push_back(cur_bank_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
return unique_sizes;
|
||||
}
|
||||
|
||||
std::vector<ModuleId> MemoryBankShiftRegisterBanks::bl_bank_unique_modules() const {
|
||||
std::vector<ModuleId> unique_modules;
|
||||
for (const auto& region : bl_bank_modules_) {
|
||||
for (const auto& bank : region) {
|
||||
if (unique_modules.end() == std::find(unique_modules.begin(), unique_modules.end(), bank)) {
|
||||
unique_modules.push_back(bank);
|
||||
}
|
||||
}
|
||||
}
|
||||
return unique_modules;
|
||||
}
|
||||
|
||||
size_t MemoryBankShiftRegisterBanks::bl_bank_size(const ConfigRegionId& region_id, const FabricBitLineBankId& bank_id) const {
|
||||
size_t cur_bank_size = 0;
|
||||
for (const auto& data_port : bl_bank_data_ports(region_id, bank_id)) {
|
||||
cur_bank_size += data_port.get_width();
|
||||
}
|
||||
return cur_bank_size;
|
||||
}
|
||||
|
||||
FabricKey::fabric_bit_line_bank_range MemoryBankShiftRegisterBanks::bl_banks(const ConfigRegionId& region_id) const {
|
||||
VTR_ASSERT(valid_region_id(region_id));
|
||||
return vtr::make_range(bl_bank_ids_[region_id].begin(), bl_bank_ids_[region_id].end());
|
||||
}
|
||||
|
||||
std::vector<size_t> MemoryBankShiftRegisterBanks::wl_bank_unique_sizes() const {
|
||||
std::vector<size_t> unique_sizes;
|
||||
for (const auto& region : wl_bank_data_ports_) {
|
||||
for (const auto& bank : region) {
|
||||
ConfigRegionId region_id = ConfigRegionId(®ion - &wl_bank_data_ports_[ConfigRegionId(0)]);
|
||||
FabricWordLineBankId bank_id = FabricWordLineBankId(&bank - ®ion[FabricWordLineBankId(0)]);
|
||||
size_t cur_bank_size = wl_bank_size(region_id, bank_id);
|
||||
if (unique_sizes.end() == std::find(unique_sizes.begin(), unique_sizes.end(), cur_bank_size)) {
|
||||
unique_sizes.push_back(cur_bank_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
return unique_sizes;
|
||||
}
|
||||
|
||||
std::vector<ModuleId> MemoryBankShiftRegisterBanks::wl_bank_unique_modules() const {
|
||||
std::vector<ModuleId> unique_modules;
|
||||
for (const auto& region : wl_bank_modules_) {
|
||||
for (const auto& bank : region) {
|
||||
if (unique_modules.end() == std::find(unique_modules.begin(), unique_modules.end(), bank)) {
|
||||
unique_modules.push_back(bank);
|
||||
}
|
||||
}
|
||||
}
|
||||
return unique_modules;
|
||||
}
|
||||
|
||||
size_t MemoryBankShiftRegisterBanks::wl_bank_size(const ConfigRegionId& region_id, const FabricWordLineBankId& bank_id) const {
|
||||
size_t cur_bank_size = 0;
|
||||
for (const auto& data_port : wl_bank_data_ports(region_id, bank_id)) {
|
||||
cur_bank_size += data_port.get_width();
|
||||
}
|
||||
return cur_bank_size;
|
||||
}
|
||||
|
||||
FabricKey::fabric_word_line_bank_range MemoryBankShiftRegisterBanks::wl_banks(const ConfigRegionId& region_id) const {
|
||||
VTR_ASSERT(valid_region_id(region_id));
|
||||
return vtr::make_range(wl_bank_ids_[region_id].begin(), wl_bank_ids_[region_id].end());
|
||||
}
|
||||
|
||||
std::vector<BasicPort> MemoryBankShiftRegisterBanks::bl_bank_data_ports(const ConfigRegionId& region_id, const FabricBitLineBankId& bank_id) const {
|
||||
VTR_ASSERT(valid_bl_bank_id(region_id, bank_id));
|
||||
return bl_bank_data_ports_[region_id][bank_id];
|
||||
}
|
||||
|
||||
std::vector<BasicPort> MemoryBankShiftRegisterBanks::wl_bank_data_ports(const ConfigRegionId& region_id, const FabricWordLineBankId& bank_id) const {
|
||||
VTR_ASSERT(valid_wl_bank_id(region_id, bank_id));
|
||||
return wl_bank_data_ports_[region_id][bank_id];
|
||||
}
|
||||
|
||||
FabricBitLineBankId MemoryBankShiftRegisterBanks::find_bl_shift_register_bank_id(const ConfigRegionId& region,
|
||||
const BasicPort& bl_port) const {
|
||||
if (is_bl_bank_dirty_) {
|
||||
build_bl_port_fast_lookup();
|
||||
}
|
||||
|
||||
VTR_ASSERT(valid_region_id(region));
|
||||
const auto& result = bl_ports_to_sr_bank_ids_[region].find(bl_port);
|
||||
if (result == bl_ports_to_sr_bank_ids_[region].end()) {
|
||||
return FabricBitLineBankId::INVALID();
|
||||
}
|
||||
return result->second;
|
||||
}
|
||||
|
||||
BasicPort MemoryBankShiftRegisterBanks::find_bl_shift_register_bank_data_port(const ConfigRegionId& region,
|
||||
const BasicPort& bl_port) const {
|
||||
if (is_bl_bank_dirty_) {
|
||||
build_bl_port_fast_lookup();
|
||||
}
|
||||
|
||||
VTR_ASSERT(valid_region_id(region));
|
||||
const auto& result = bl_ports_to_sr_bank_ports_[region].find(bl_port);
|
||||
if (result == bl_ports_to_sr_bank_ports_[region].end()) {
|
||||
return BasicPort();
|
||||
}
|
||||
return result->second;
|
||||
}
|
||||
|
||||
std::vector<size_t> MemoryBankShiftRegisterBanks::bl_shift_register_bank_sink_child_ids(const ConfigRegionId& region_id,
|
||||
const FabricBitLineBankId& bank_id,
|
||||
const BasicPort& src_port) const {
|
||||
VTR_ASSERT(valid_bl_bank_id(region_id, bank_id));
|
||||
auto result = bl_bank_sink_child_ids_[region_id][bank_id].find(src_port);
|
||||
if (result == bl_bank_sink_child_ids_[region_id][bank_id].end()) {
|
||||
return std::vector<size_t>(); /* Not found, return an empty list */
|
||||
}
|
||||
return result->second;
|
||||
}
|
||||
|
||||
std::vector<size_t> MemoryBankShiftRegisterBanks::bl_shift_register_bank_sink_child_pin_ids(const ConfigRegionId& region_id,
|
||||
const FabricBitLineBankId& bank_id,
|
||||
const BasicPort& src_port) const {
|
||||
VTR_ASSERT(valid_bl_bank_id(region_id, bank_id));
|
||||
auto result = bl_bank_sink_child_pin_ids_[region_id][bank_id].find(src_port);
|
||||
if (result == bl_bank_sink_child_pin_ids_[region_id][bank_id].end()) {
|
||||
return std::vector<size_t>(); /* Not found, return an empty list */
|
||||
}
|
||||
return result->second;
|
||||
}
|
||||
|
||||
std::vector<BasicPort> MemoryBankShiftRegisterBanks::bl_shift_register_bank_source_ports(const ConfigRegionId& region_id,
|
||||
const FabricBitLineBankId& bank_id) const {
|
||||
VTR_ASSERT(valid_bl_bank_id(region_id, bank_id));
|
||||
std::vector<BasicPort> src_ports;
|
||||
|
||||
size_t cur_pin =0;
|
||||
for (const BasicPort& wide_port : bl_bank_data_ports(region_id, bank_id)) {
|
||||
for (size_t ipin = 0; ipin < wide_port.pins().size(); ++ipin) {
|
||||
src_ports.push_back(BasicPort(std::string(MEMORY_BL_PORT_NAME), cur_pin, cur_pin));
|
||||
cur_pin++;
|
||||
}
|
||||
}
|
||||
|
||||
return src_ports;
|
||||
}
|
||||
|
||||
ModuleId MemoryBankShiftRegisterBanks::bl_shift_register_bank_module(const ConfigRegionId& region_id,
|
||||
const FabricBitLineBankId& bank_id) const {
|
||||
VTR_ASSERT(valid_bl_bank_id(region_id, bank_id));
|
||||
return bl_bank_modules_[region_id][bank_id];
|
||||
}
|
||||
|
||||
size_t MemoryBankShiftRegisterBanks::bl_shift_register_bank_instance(const ConfigRegionId& region_id,
|
||||
const FabricBitLineBankId& bank_id) const {
|
||||
VTR_ASSERT(valid_bl_bank_id(region_id, bank_id));
|
||||
return bl_bank_instances_[region_id][bank_id];
|
||||
}
|
||||
|
||||
FabricWordLineBankId MemoryBankShiftRegisterBanks::find_wl_shift_register_bank_id(const ConfigRegionId& region,
|
||||
const BasicPort& wl_port) const {
|
||||
if (is_wl_bank_dirty_) {
|
||||
build_wl_port_fast_lookup();
|
||||
}
|
||||
|
||||
VTR_ASSERT(valid_region_id(region));
|
||||
const auto& result = wl_ports_to_sr_bank_ids_[region].find(wl_port);
|
||||
if (result == wl_ports_to_sr_bank_ids_[region].end()) {
|
||||
return FabricWordLineBankId::INVALID();
|
||||
}
|
||||
return result->second;
|
||||
}
|
||||
|
||||
BasicPort MemoryBankShiftRegisterBanks::find_wl_shift_register_bank_data_port(const ConfigRegionId& region,
|
||||
const BasicPort& wl_port) const {
|
||||
if (is_wl_bank_dirty_) {
|
||||
build_wl_port_fast_lookup();
|
||||
}
|
||||
|
||||
VTR_ASSERT(valid_region_id(region));
|
||||
const auto& result = wl_ports_to_sr_bank_ports_[region].find(wl_port);
|
||||
if (result == wl_ports_to_sr_bank_ports_[region].end()) {
|
||||
return BasicPort();
|
||||
}
|
||||
return result->second;
|
||||
}
|
||||
|
||||
void MemoryBankShiftRegisterBanks::resize_regions(const size_t& num_regions) {
|
||||
config_region_ids_.resize(num_regions);
|
||||
for (size_t iregion = 0; iregion < num_regions; ++iregion) {
|
||||
config_region_ids_[ConfigRegionId(iregion)] = ConfigRegionId(iregion);
|
||||
}
|
||||
bl_bank_ids_.resize(num_regions);
|
||||
bl_bank_data_ports_.resize(num_regions);
|
||||
bl_bank_modules_.resize(num_regions);
|
||||
bl_bank_instances_.resize(num_regions);
|
||||
bl_bank_sink_child_ids_.resize(num_regions);
|
||||
bl_bank_sink_child_pin_ids_.resize(num_regions);
|
||||
|
||||
wl_bank_ids_.resize(num_regions);
|
||||
wl_bank_data_ports_.resize(num_regions);
|
||||
wl_bank_modules_.resize(num_regions);
|
||||
wl_bank_instances_.resize(num_regions);
|
||||
wl_bank_sink_child_ids_.resize(num_regions);
|
||||
wl_bank_sink_child_pin_ids_.resize(num_regions);
|
||||
}
|
||||
|
||||
void MemoryBankShiftRegisterBanks::link_bl_shift_register_bank_to_module(const ConfigRegionId& region_id,
|
||||
const FabricBitLineBankId& bank_id,
|
||||
const ModuleId& module_id) {
|
||||
VTR_ASSERT(valid_bl_bank_id(region_id, bank_id));
|
||||
bl_bank_modules_[region_id][bank_id] = module_id;
|
||||
}
|
||||
|
||||
void MemoryBankShiftRegisterBanks::link_bl_shift_register_bank_to_instance(const ConfigRegionId& region_id,
|
||||
const FabricBitLineBankId& bank_id,
|
||||
const size_t& instance_id) {
|
||||
VTR_ASSERT(valid_bl_bank_id(region_id, bank_id));
|
||||
bl_bank_instances_[region_id][bank_id] = instance_id;
|
||||
}
|
||||
|
||||
void MemoryBankShiftRegisterBanks::link_wl_shift_register_bank_to_module(const ConfigRegionId& region_id,
|
||||
const FabricWordLineBankId& bank_id,
|
||||
const ModuleId& module_id) {
|
||||
VTR_ASSERT(valid_wl_bank_id(region_id, bank_id));
|
||||
wl_bank_modules_[region_id][bank_id] = module_id;
|
||||
}
|
||||
|
||||
void MemoryBankShiftRegisterBanks::link_wl_shift_register_bank_to_instance(const ConfigRegionId& region_id,
|
||||
const FabricWordLineBankId& bank_id,
|
||||
const size_t& instance_id) {
|
||||
VTR_ASSERT(valid_wl_bank_id(region_id, bank_id));
|
||||
wl_bank_instances_[region_id][bank_id] = instance_id;
|
||||
}
|
||||
|
||||
void MemoryBankShiftRegisterBanks::add_bl_shift_register_bank_sink_node(const ConfigRegionId& region,
|
||||
const FabricBitLineBankId& bank,
|
||||
const BasicPort& src_port,
|
||||
const size_t& sink_child_id,
|
||||
const size_t& sink_child_pin_id) {
|
||||
VTR_ASSERT(valid_bl_bank_id(region, bank));
|
||||
bl_bank_sink_child_ids_[region][bank][src_port].push_back(sink_child_id);
|
||||
bl_bank_sink_child_pin_ids_[region][bank][src_port].push_back(sink_child_pin_id);
|
||||
}
|
||||
|
||||
void MemoryBankShiftRegisterBanks::add_wl_shift_register_bank_sink_node(const ConfigRegionId& region,
|
||||
const FabricWordLineBankId& bank,
|
||||
const BasicPort& src_port,
|
||||
const size_t& sink_child_id,
|
||||
const size_t& sink_child_pin_id) {
|
||||
VTR_ASSERT(valid_wl_bank_id(region, bank));
|
||||
wl_bank_sink_child_ids_[region][bank][src_port].push_back(sink_child_id);
|
||||
wl_bank_sink_child_pin_ids_[region][bank][src_port].push_back(sink_child_pin_id);
|
||||
}
|
||||
|
||||
void MemoryBankShiftRegisterBanks::reserve_bl_shift_register_banks(const ConfigRegionId& region_id, const size_t& num_banks) {
|
||||
VTR_ASSERT(valid_region_id(region_id));
|
||||
bl_bank_ids_[region_id].reserve(num_banks);
|
||||
bl_bank_data_ports_[region_id].reserve(num_banks);
|
||||
bl_bank_modules_[region_id].reserve(num_banks);
|
||||
bl_bank_instances_[region_id].reserve(num_banks);
|
||||
bl_bank_sink_child_ids_[region_id].reserve(num_banks);
|
||||
bl_bank_sink_child_pin_ids_[region_id].reserve(num_banks);
|
||||
}
|
||||
|
||||
void MemoryBankShiftRegisterBanks::reserve_bl_shift_register_banks(const FabricRegionId& region_id, const size_t& num_banks) {
|
||||
ConfigRegionId config_region_id = ConfigRegionId(size_t(region_id));
|
||||
reserve_bl_shift_register_banks(config_region_id, num_banks);
|
||||
}
|
||||
|
||||
void MemoryBankShiftRegisterBanks::reserve_wl_shift_register_banks(const ConfigRegionId& region_id, const size_t& num_banks) {
|
||||
VTR_ASSERT(valid_region_id(region_id));
|
||||
wl_bank_ids_[region_id].reserve(num_banks);
|
||||
wl_bank_data_ports_[region_id].reserve(num_banks);
|
||||
wl_bank_modules_[region_id].reserve(num_banks);
|
||||
wl_bank_instances_[region_id].reserve(num_banks);
|
||||
wl_bank_sink_child_ids_[region_id].reserve(num_banks);
|
||||
wl_bank_sink_child_pin_ids_[region_id].reserve(num_banks);
|
||||
}
|
||||
|
||||
void MemoryBankShiftRegisterBanks::reserve_wl_shift_register_banks(const FabricRegionId& region_id, const size_t& num_banks) {
|
||||
ConfigRegionId config_region_id = ConfigRegionId(size_t(region_id));
|
||||
reserve_wl_shift_register_banks(config_region_id, num_banks);
|
||||
}
|
||||
|
||||
FabricBitLineBankId MemoryBankShiftRegisterBanks::create_bl_shift_register_bank(const ConfigRegionId& region_id) {
|
||||
VTR_ASSERT(valid_region_id(region_id));
|
||||
|
||||
/* Create a new id */
|
||||
FabricBitLineBankId bank = FabricBitLineBankId(bl_bank_ids_[region_id].size());
|
||||
bl_bank_ids_[region_id].push_back(bank);
|
||||
bl_bank_data_ports_[region_id].emplace_back();
|
||||
bl_bank_modules_[region_id].push_back(ModuleId::INVALID());
|
||||
bl_bank_instances_[region_id].emplace_back();
|
||||
bl_bank_sink_child_ids_[region_id].emplace_back();
|
||||
bl_bank_sink_child_pin_ids_[region_id].emplace_back();
|
||||
|
||||
return bank;
|
||||
}
|
||||
|
||||
FabricBitLineBankId MemoryBankShiftRegisterBanks::create_bl_shift_register_bank(const FabricRegionId& region_id) {
|
||||
ConfigRegionId config_region_id = ConfigRegionId(size_t(region_id));
|
||||
return create_bl_shift_register_bank(config_region_id);
|
||||
}
|
||||
|
||||
void MemoryBankShiftRegisterBanks::add_data_port_to_bl_shift_register_bank(const FabricRegionId& region_id,
|
||||
const FabricBitLineBankId& bank_id,
|
||||
const openfpga::BasicPort& data_port) {
|
||||
ConfigRegionId config_region_id = ConfigRegionId(size_t(region_id));
|
||||
add_data_port_to_bl_shift_register_bank(config_region_id, bank_id, data_port);
|
||||
}
|
||||
|
||||
void MemoryBankShiftRegisterBanks::add_data_port_to_bl_shift_register_bank(const ConfigRegionId& region_id,
|
||||
const FabricBitLineBankId& bank_id,
|
||||
const openfpga::BasicPort& data_port) {
|
||||
VTR_ASSERT(valid_bl_bank_id(region_id, bank_id));
|
||||
bl_bank_data_ports_[region_id][bank_id].push_back(data_port);
|
||||
is_bl_bank_dirty_ = true;
|
||||
}
|
||||
|
||||
FabricWordLineBankId MemoryBankShiftRegisterBanks::create_wl_shift_register_bank(const FabricRegionId& region_id) {
|
||||
ConfigRegionId config_region_id = ConfigRegionId(size_t(region_id));
|
||||
return create_wl_shift_register_bank(config_region_id);
|
||||
}
|
||||
|
||||
FabricWordLineBankId MemoryBankShiftRegisterBanks::create_wl_shift_register_bank(const ConfigRegionId& region_id) {
|
||||
VTR_ASSERT(valid_region_id(region_id));
|
||||
|
||||
/* Create a new id */
|
||||
FabricWordLineBankId bank = FabricWordLineBankId(wl_bank_ids_[region_id].size());
|
||||
wl_bank_ids_[region_id].push_back(bank);
|
||||
wl_bank_data_ports_[region_id].emplace_back();
|
||||
wl_bank_modules_[region_id].push_back(ModuleId::INVALID());
|
||||
wl_bank_instances_[region_id].emplace_back();
|
||||
wl_bank_sink_child_ids_[region_id].emplace_back();
|
||||
wl_bank_sink_child_pin_ids_[region_id].emplace_back();
|
||||
|
||||
return bank;
|
||||
}
|
||||
|
||||
void MemoryBankShiftRegisterBanks::add_data_port_to_wl_shift_register_bank(const FabricRegionId& region_id,
|
||||
const FabricWordLineBankId& bank_id,
|
||||
const openfpga::BasicPort& data_port) {
|
||||
ConfigRegionId config_region_id = ConfigRegionId(size_t(region_id));
|
||||
add_data_port_to_wl_shift_register_bank(config_region_id, bank_id, data_port);
|
||||
}
|
||||
|
||||
void MemoryBankShiftRegisterBanks::add_data_port_to_wl_shift_register_bank(const ConfigRegionId& region_id,
|
||||
const FabricWordLineBankId& bank_id,
|
||||
const openfpga::BasicPort& data_port) {
|
||||
VTR_ASSERT(valid_wl_bank_id(region_id, bank_id));
|
||||
wl_bank_data_ports_[region_id][bank_id].push_back(data_port);
|
||||
is_wl_bank_dirty_ = true;
|
||||
}
|
||||
|
||||
std::vector<size_t> MemoryBankShiftRegisterBanks::wl_shift_register_bank_sink_child_ids(const ConfigRegionId& region_id,
|
||||
const FabricWordLineBankId& bank_id,
|
||||
const BasicPort& src_port) const {
|
||||
VTR_ASSERT(valid_wl_bank_id(region_id, bank_id));
|
||||
auto result = wl_bank_sink_child_ids_[region_id][bank_id].find(src_port);
|
||||
if (result == wl_bank_sink_child_ids_[region_id][bank_id].end()) {
|
||||
return std::vector<size_t>(); /* Not found, return an empty list */
|
||||
}
|
||||
return result->second;
|
||||
}
|
||||
|
||||
ModuleId MemoryBankShiftRegisterBanks::wl_shift_register_bank_module(const ConfigRegionId& region_id,
|
||||
const FabricWordLineBankId& bank_id) const {
|
||||
VTR_ASSERT(valid_wl_bank_id(region_id, bank_id));
|
||||
return wl_bank_modules_[region_id][bank_id];
|
||||
}
|
||||
|
||||
size_t MemoryBankShiftRegisterBanks::wl_shift_register_bank_instance(const ConfigRegionId& region_id,
|
||||
const FabricWordLineBankId& bank_id) const {
|
||||
VTR_ASSERT(valid_wl_bank_id(region_id, bank_id));
|
||||
return wl_bank_instances_[region_id][bank_id];
|
||||
}
|
||||
|
||||
std::vector<size_t> MemoryBankShiftRegisterBanks::wl_shift_register_bank_sink_child_pin_ids(const ConfigRegionId& region_id,
|
||||
const FabricWordLineBankId& bank_id,
|
||||
const BasicPort& src_port) const {
|
||||
VTR_ASSERT(valid_wl_bank_id(region_id, bank_id));
|
||||
auto result = wl_bank_sink_child_pin_ids_[region_id][bank_id].find(src_port);
|
||||
if (result == wl_bank_sink_child_pin_ids_[region_id][bank_id].end()) {
|
||||
return std::vector<size_t>(); /* Not found, return an empty list */
|
||||
}
|
||||
return result->second;
|
||||
}
|
||||
|
||||
std::vector<BasicPort> MemoryBankShiftRegisterBanks::wl_shift_register_bank_source_ports(const ConfigRegionId& region_id,
|
||||
const FabricWordLineBankId& bank_id) const {
|
||||
VTR_ASSERT(valid_wl_bank_id(region_id, bank_id));
|
||||
std::vector<BasicPort> src_ports;
|
||||
|
||||
size_t cur_pin = 0;
|
||||
for (const BasicPort& wide_port : wl_bank_data_ports(region_id, bank_id)) {
|
||||
for (size_t ipin = 0; ipin < wide_port.pins().size(); ++ipin) {
|
||||
src_ports.push_back(BasicPort(std::string(MEMORY_WL_PORT_NAME), cur_pin, cur_pin));
|
||||
cur_pin++;
|
||||
}
|
||||
}
|
||||
|
||||
return src_ports;
|
||||
}
|
||||
|
||||
bool MemoryBankShiftRegisterBanks::valid_region_id(const ConfigRegionId& region) const {
|
||||
return size_t(region) < bl_bank_ids_.size();
|
||||
}
|
||||
|
||||
bool MemoryBankShiftRegisterBanks::valid_bl_bank_id(const ConfigRegionId& region_id, const FabricBitLineBankId& bank_id) const {
|
||||
if (!valid_region_id(region_id)) {
|
||||
return false;
|
||||
}
|
||||
return ( size_t(bank_id) < bl_bank_ids_[region_id].size() ) && ( bank_id == bl_bank_ids_[region_id][bank_id] );
|
||||
}
|
||||
|
||||
bool MemoryBankShiftRegisterBanks::valid_wl_bank_id(const ConfigRegionId& region_id, const FabricWordLineBankId& bank_id) const {
|
||||
if (!valid_region_id(region_id)) {
|
||||
return false;
|
||||
}
|
||||
return ( size_t(bank_id) < wl_bank_ids_[region_id].size() ) && ( bank_id == wl_bank_ids_[region_id][bank_id] );
|
||||
}
|
||||
|
||||
bool MemoryBankShiftRegisterBanks::empty() const {
|
||||
return bl_bank_ids_.empty() && wl_bank_ids_.empty();
|
||||
}
|
||||
|
||||
void MemoryBankShiftRegisterBanks::build_bl_port_fast_lookup() const {
|
||||
bl_ports_to_sr_bank_ids_.resize(bl_bank_data_ports_.size());
|
||||
bl_ports_to_sr_bank_ports_.resize(bl_bank_data_ports_.size());
|
||||
for (const auto& region : bl_bank_data_ports_) {
|
||||
for (const auto& bank : region) {
|
||||
size_t cur_pin = 0;
|
||||
for (const auto& port : bank) {
|
||||
for (const size_t& bl_index : port.pins()) {
|
||||
BasicPort bl_port(std::string(MEMORY_BL_PORT_NAME), bl_index, bl_index);
|
||||
BasicPort sr_bl_port(std::string(MEMORY_BL_PORT_NAME), cur_pin, cur_pin);
|
||||
ConfigRegionId region_id = ConfigRegionId(®ion - &bl_bank_data_ports_[ConfigRegionId(0)]);
|
||||
FabricBitLineBankId bank_id = FabricBitLineBankId(&bank - ®ion[FabricBitLineBankId(0)]);
|
||||
bl_ports_to_sr_bank_ids_[region_id][bl_port] = bank_id;
|
||||
bl_ports_to_sr_bank_ports_[region_id][bl_port] = sr_bl_port;
|
||||
cur_pin++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Clear the flag, now fast look-up is synchronized */
|
||||
is_bl_bank_dirty_ = false;
|
||||
}
|
||||
|
||||
void MemoryBankShiftRegisterBanks::build_wl_port_fast_lookup() const {
|
||||
wl_ports_to_sr_bank_ids_.resize(wl_bank_data_ports_.size());
|
||||
wl_ports_to_sr_bank_ports_.resize(wl_bank_data_ports_.size());
|
||||
for (const auto& region : wl_bank_data_ports_) {
|
||||
for (const auto& bank : region) {
|
||||
size_t cur_pin = 0;
|
||||
for (const auto& port : bank) {
|
||||
for (const size_t& wl_index : port.pins()) {
|
||||
BasicPort wl_port(std::string(MEMORY_WL_PORT_NAME), wl_index, wl_index);
|
||||
BasicPort sr_wl_port(std::string(MEMORY_WL_PORT_NAME), cur_pin, cur_pin);
|
||||
ConfigRegionId region_id = ConfigRegionId(®ion - &wl_bank_data_ports_[ConfigRegionId(0)]);
|
||||
FabricWordLineBankId bank_id = FabricWordLineBankId(&bank - ®ion[FabricWordLineBankId(0)]);
|
||||
wl_ports_to_sr_bank_ids_[region_id][wl_port] = bank_id;
|
||||
wl_ports_to_sr_bank_ports_[region_id][wl_port] = sr_wl_port;
|
||||
cur_pin++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Clear the flag, now fast look-up is synchronized */
|
||||
is_wl_bank_dirty_ = false;
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
|
@ -0,0 +1,238 @@
|
|||
#ifndef MEMORY_BANK_SHIFT_REGISTER_BANKS_H
|
||||
#define MEMORY_BANK_SHIFT_REGISTER_BANKS_H
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "vtr_vector.h"
|
||||
#include "fabric_key.h"
|
||||
#include "module_manager.h"
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
/******************************************************************************
|
||||
* This files includes data structures that stores detailed information about
|
||||
* shift register banks for each configuration region in the top-level module, including
|
||||
* - Module id of each shift register bank
|
||||
* - Instance id of each shift register bank
|
||||
* - The connectivity of of each shift register bank to reconfigurable child under a configuration region
|
||||
* - The ids of each child to be connected
|
||||
* - The Bit Line (BL) or Word Line (WL) pin id of each child
|
||||
|
||||
* @note This data structure is mainly used as a database for adding connections around shift register banks in top-level module
|
||||
******************************************************************************/
|
||||
class MemoryBankShiftRegisterBanks {
|
||||
public: /* Accessors: aggregates */
|
||||
ModuleManager::region_range regions() const;
|
||||
FabricKey::fabric_bit_line_bank_range bl_banks(const ConfigRegionId& region_id) const;
|
||||
FabricKey::fabric_word_line_bank_range wl_banks(const ConfigRegionId& region_id) const;
|
||||
public: /* Accessors */
|
||||
/* @brief Return a list of unique sizes of shift register banks for BL protocol */
|
||||
std::vector<size_t> bl_bank_unique_sizes() const;
|
||||
|
||||
/* @brief Return a list of unique modules of shift register banks for BL protocol */
|
||||
std::vector<ModuleId> bl_bank_unique_modules() const;
|
||||
|
||||
/* @brief Return the size of a BL shift register bank */
|
||||
size_t bl_bank_size(const ConfigRegionId& region_id, const FabricBitLineBankId& bank_id) const;
|
||||
|
||||
/* @brief Return a list of data ports which will be driven by a BL shift register bank */
|
||||
std::vector<BasicPort> bl_bank_data_ports(const ConfigRegionId& region_id, const FabricBitLineBankId& bank_id) const;
|
||||
|
||||
/** @brief find the BL shift register bank id to which a BL port is connected to */
|
||||
FabricBitLineBankId find_bl_shift_register_bank_id(const ConfigRegionId& region, const BasicPort& bl_port) const;
|
||||
|
||||
/** @brief find the data port of a BL shift register bank id to which a BL port is connected to */
|
||||
BasicPort find_bl_shift_register_bank_data_port(const ConfigRegionId& region, const BasicPort& bl_port) const;
|
||||
|
||||
/** @brief Return the module id of a BL shift register bank */
|
||||
ModuleId bl_shift_register_bank_module(const ConfigRegionId& region_id,
|
||||
const FabricBitLineBankId& bank_id) const;
|
||||
|
||||
/** @brief Return the instance id of a BL shift register bank */
|
||||
size_t bl_shift_register_bank_instance(const ConfigRegionId& region_id,
|
||||
const FabricBitLineBankId& bank_id) const;
|
||||
|
||||
/** @brief return the child ids at top-level module to which a data port (1-bit) of a BL shift register bank is connected to
|
||||
* @note a BL may drive multiple children (children on the same column share the same BLs)
|
||||
*/
|
||||
std::vector<size_t> bl_shift_register_bank_sink_child_ids(const ConfigRegionId& region_id,
|
||||
const FabricBitLineBankId& bank_id,
|
||||
const BasicPort& src_port) const;
|
||||
|
||||
/** @brief return the child pin id of the child module at top-level module
|
||||
* to which a data port (1-bit) of a BL shift register bank is connected to
|
||||
* @note a BL may drive multiple children (children on the same column share the same BLs)
|
||||
*/
|
||||
std::vector<size_t> bl_shift_register_bank_sink_child_pin_ids(const ConfigRegionId& region_id,
|
||||
const FabricBitLineBankId& bank_id,
|
||||
const BasicPort& src_port) const;
|
||||
|
||||
/** @brief Return a list of single-bit ports which are the data ports of a BL shift register bank */
|
||||
std::vector<BasicPort> bl_shift_register_bank_source_ports(const ConfigRegionId& region_id,
|
||||
const FabricBitLineBankId& bank_id) const;
|
||||
|
||||
/* @brief Return a list of unique sizes of shift register banks for WL protocol */
|
||||
std::vector<size_t> wl_bank_unique_sizes() const;
|
||||
|
||||
/* @brief Return a list of unique modules of shift register banks for WL protocol */
|
||||
std::vector<ModuleId> wl_bank_unique_modules() const;
|
||||
|
||||
/* @brief Return the size of a WL shift register bank */
|
||||
size_t wl_bank_size(const ConfigRegionId& region_id, const FabricWordLineBankId& bank_id) const;
|
||||
|
||||
/* @brief Return a list of data ports which will be driven by a WL shift register bank */
|
||||
std::vector<BasicPort> wl_bank_data_ports(const ConfigRegionId& region_id, const FabricWordLineBankId& bank_id) const;
|
||||
|
||||
/** @brief find the WL shift register bank id to which a BL port is connected to */
|
||||
FabricWordLineBankId find_wl_shift_register_bank_id(const ConfigRegionId& region, const BasicPort& wl_port) const;
|
||||
|
||||
/** @brief find the data port of a WL shift register bank id to which a BL port is connected to */
|
||||
BasicPort find_wl_shift_register_bank_data_port(const ConfigRegionId& region, const BasicPort& wl_port) const;
|
||||
|
||||
/** @brief Return the module id of a WL shift register bank */
|
||||
ModuleId wl_shift_register_bank_module(const ConfigRegionId& region_id,
|
||||
const FabricWordLineBankId& bank_id) const;
|
||||
|
||||
/** @brief Return the instance id of a WL shift register bank */
|
||||
size_t wl_shift_register_bank_instance(const ConfigRegionId& region_id,
|
||||
const FabricWordLineBankId& bank_id) const;
|
||||
|
||||
/** @brief return the child id at top-level module to which a data port (1-bit) of a WL shift register bank is connected to
|
||||
* @note a WL may drive multiple children (children on the same row share the same WLs)
|
||||
*/
|
||||
std::vector<size_t> wl_shift_register_bank_sink_child_ids(const ConfigRegionId& region,
|
||||
const FabricWordLineBankId& bank_id,
|
||||
const BasicPort& src_port) const;
|
||||
|
||||
/** @brief return the child pin id of the child module at top-level module
|
||||
* to which a data port (1-bit) of a WL shift register bank is connected to
|
||||
* @note a WL may drive multiple children (children on the same row share the same WLs)
|
||||
*/
|
||||
std::vector<size_t> wl_shift_register_bank_sink_child_pin_ids(const ConfigRegionId& region,
|
||||
const FabricWordLineBankId& bank_id,
|
||||
const BasicPort& src_port) const;
|
||||
|
||||
/** @brief Return a list of single-bit ports which are the data ports of a WL shift register bank */
|
||||
std::vector<BasicPort> wl_shift_register_bank_source_ports(const ConfigRegionId& region_id,
|
||||
const FabricWordLineBankId& bank_id) const;
|
||||
|
||||
public: /* Mutators */
|
||||
void resize_regions(const size_t& num_regions);
|
||||
|
||||
/* Reserve a number of banks to be memory efficent */
|
||||
void reserve_bl_shift_register_banks(const FabricRegionId& region_id, const size_t& num_banks);
|
||||
void reserve_bl_shift_register_banks(const ConfigRegionId& region_id, const size_t& num_banks);
|
||||
|
||||
/* Create a new shift register bank for BLs and return an id */
|
||||
FabricBitLineBankId create_bl_shift_register_bank(const FabricRegionId& region_id);
|
||||
FabricBitLineBankId create_bl_shift_register_bank(const ConfigRegionId& region_id);
|
||||
|
||||
/* Add a data port to a given BL shift register bank */
|
||||
void add_data_port_to_bl_shift_register_bank(const FabricRegionId& region_id,
|
||||
const FabricBitLineBankId& bank_id,
|
||||
const openfpga::BasicPort& data_port);
|
||||
void add_data_port_to_bl_shift_register_bank(const ConfigRegionId& region_id,
|
||||
const FabricBitLineBankId& bank_id,
|
||||
const openfpga::BasicPort& data_port);
|
||||
|
||||
/* Link a BL shift register bank to a module id */
|
||||
void link_bl_shift_register_bank_to_module(const ConfigRegionId& region_id,
|
||||
const FabricBitLineBankId& bank_id,
|
||||
const ModuleId& module_id);
|
||||
|
||||
/* Link a BL shift register bank to a instance id */
|
||||
void link_bl_shift_register_bank_to_instance(const ConfigRegionId& region_id,
|
||||
const FabricBitLineBankId& bank_id,
|
||||
const size_t& instance_id);
|
||||
|
||||
/* @brief Add the child id and pin id of BL to which a shift register is connected to under a specific configuration region of top-level module */
|
||||
void add_bl_shift_register_bank_sink_node(const ConfigRegionId& region,
|
||||
const FabricBitLineBankId& bank,
|
||||
const BasicPort& src_port,
|
||||
const size_t& sink_child_id,
|
||||
const size_t& sink_child_pin_id);
|
||||
|
||||
/* Reserve a number of banks to be memory efficent */
|
||||
void reserve_wl_shift_register_banks(const FabricRegionId& region_id, const size_t& num_banks);
|
||||
void reserve_wl_shift_register_banks(const ConfigRegionId& region_id, const size_t& num_banks);
|
||||
|
||||
/* Create a new shift register bank for WLs and return an id */
|
||||
FabricWordLineBankId create_wl_shift_register_bank(const FabricRegionId& region_id);
|
||||
FabricWordLineBankId create_wl_shift_register_bank(const ConfigRegionId& region_id);
|
||||
|
||||
/* Add a data port to a given WL shift register bank */
|
||||
void add_data_port_to_wl_shift_register_bank(const FabricRegionId& region_id,
|
||||
const FabricWordLineBankId& bank_id,
|
||||
const openfpga::BasicPort& data_port);
|
||||
void add_data_port_to_wl_shift_register_bank(const ConfigRegionId& region_id,
|
||||
const FabricWordLineBankId& bank_id,
|
||||
const openfpga::BasicPort& data_port);
|
||||
|
||||
/* Link a WL shift register bank to a module id */
|
||||
void link_wl_shift_register_bank_to_module(const ConfigRegionId& region_id,
|
||||
const FabricWordLineBankId& bank_id,
|
||||
const ModuleId& module_id);
|
||||
|
||||
/* Link a WL shift register bank to a instance id */
|
||||
void link_wl_shift_register_bank_to_instance(const ConfigRegionId& region_id,
|
||||
const FabricWordLineBankId& bank_id,
|
||||
const size_t& instance_id);
|
||||
|
||||
/* @brief Add the child id and pin id of WL to which a shift register is connected to under a specific configuration region of top-level module */
|
||||
void add_wl_shift_register_bank_sink_node(const ConfigRegionId& region,
|
||||
const FabricWordLineBankId& bank,
|
||||
const BasicPort& src_port,
|
||||
const size_t& sink_child_id,
|
||||
const size_t& sink_child_pin_id);
|
||||
|
||||
public: /* Validators */
|
||||
bool valid_region_id(const ConfigRegionId& region) const;
|
||||
bool valid_bl_bank_id(const ConfigRegionId& region_id, const FabricBitLineBankId& bank_id) const;
|
||||
bool valid_wl_bank_id(const ConfigRegionId& region_id, const FabricWordLineBankId& bank_id) const;
|
||||
bool empty() const;
|
||||
|
||||
private: /* Internal Mutators */
|
||||
/** @brief Build the mapping from a BL/WL port to shift register bank and assoicated pins
|
||||
* @note we use const here because the caller functions, e.g., find_bl_shift_register_bank_id(), is const
|
||||
* even though it does modify internal data
|
||||
*/
|
||||
void build_bl_port_fast_lookup() const;
|
||||
void build_wl_port_fast_lookup() const;
|
||||
|
||||
private: /* Internal data */
|
||||
vtr::vector<ConfigRegionId, ConfigRegionId> config_region_ids_;
|
||||
|
||||
/* General information about the BL shift register bank */
|
||||
vtr::vector<ConfigRegionId, vtr::vector<FabricBitLineBankId, FabricBitLineBankId>> bl_bank_ids_;
|
||||
vtr::vector<ConfigRegionId, vtr::vector<FabricBitLineBankId, std::vector<BasicPort>>> bl_bank_data_ports_;
|
||||
vtr::vector<ConfigRegionId, vtr::vector<FabricBitLineBankId, ModuleId>> bl_bank_modules_;
|
||||
vtr::vector<ConfigRegionId, vtr::vector<FabricBitLineBankId, size_t>> bl_bank_instances_;
|
||||
vtr::vector<ConfigRegionId, vtr::vector<FabricBitLineBankId, std::map<BasicPort, std::vector<size_t>>>> bl_bank_sink_child_ids_;
|
||||
vtr::vector<ConfigRegionId, vtr::vector<FabricBitLineBankId, std::map<BasicPort, std::vector<size_t>>>> bl_bank_sink_child_pin_ids_;
|
||||
|
||||
/* General information about the WL shift register bank */
|
||||
vtr::vector<ConfigRegionId, vtr::vector<FabricWordLineBankId, FabricWordLineBankId>> wl_bank_ids_;
|
||||
vtr::vector<ConfigRegionId, vtr::vector<FabricWordLineBankId, std::vector<BasicPort>>> wl_bank_data_ports_;
|
||||
vtr::vector<ConfigRegionId, vtr::vector<FabricWordLineBankId, ModuleId>> wl_bank_modules_;
|
||||
vtr::vector<ConfigRegionId, vtr::vector<FabricWordLineBankId, size_t>> wl_bank_instances_;
|
||||
vtr::vector<ConfigRegionId, vtr::vector<FabricWordLineBankId, std::map<BasicPort, std::vector<size_t>>>> wl_bank_sink_child_ids_;
|
||||
vtr::vector<ConfigRegionId, vtr::vector<FabricWordLineBankId, std::map<BasicPort, std::vector<size_t>>>> wl_bank_sink_child_pin_ids_;
|
||||
|
||||
/* Fast look-up: given a BL/Wl port, e.g., bl[i], find out
|
||||
* - the shift register bank id
|
||||
* - the output pin id of the shift register bank
|
||||
*/
|
||||
mutable vtr::vector<ConfigRegionId, std::map<BasicPort, FabricBitLineBankId>> bl_ports_to_sr_bank_ids_;
|
||||
mutable vtr::vector<ConfigRegionId, std::map<BasicPort, BasicPort>> bl_ports_to_sr_bank_ports_;
|
||||
mutable vtr::vector<ConfigRegionId, std::map<BasicPort, FabricWordLineBankId>> wl_ports_to_sr_bank_ids_;
|
||||
mutable vtr::vector<ConfigRegionId, std::map<BasicPort, BasicPort>> wl_ports_to_sr_bank_ports_;
|
||||
|
||||
/* A flag to indicate that the general information of the shift register banks have been modified, fast look-up has to be updated */
|
||||
mutable bool is_bl_bank_dirty_ = false;
|
||||
mutable bool is_wl_bank_dirty_ = false;
|
||||
};
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
#endif
|
|
@ -84,6 +84,13 @@ std::vector<size_t> ModuleManager::configurable_child_instances(const ModuleId&
|
|||
return configurable_child_instances_[parent_module];
|
||||
}
|
||||
|
||||
std::vector<vtr::Point<int>> ModuleManager::configurable_child_coordinates(const ModuleId& parent_module) const {
|
||||
/* Validate the module_id */
|
||||
VTR_ASSERT(valid_module_id(parent_module));
|
||||
|
||||
return configurable_child_coordinates_[parent_module];
|
||||
}
|
||||
|
||||
/* Find the source ids of modules */
|
||||
ModuleManager::module_net_src_range ModuleManager::module_net_sources(const ModuleId& module, const ModuleNetId& net) const {
|
||||
/* Validate the module_id */
|
||||
|
@ -135,6 +142,22 @@ std::vector<size_t> ModuleManager::region_configurable_child_instances(const Mod
|
|||
return region_config_child_instances;
|
||||
}
|
||||
|
||||
std::vector<vtr::Point<int>> ModuleManager::region_configurable_child_coordinates(const ModuleId& parent_module,
|
||||
const ConfigRegionId& region) const {
|
||||
/* Validate the module_id */
|
||||
VTR_ASSERT(valid_module_id(parent_module));
|
||||
VTR_ASSERT(valid_region_id(parent_module, region));
|
||||
|
||||
std::vector<vtr::Point<int>> region_config_child_coordinates;
|
||||
region_config_child_coordinates.reserve(config_region_children_[parent_module][region].size());
|
||||
|
||||
for (const size_t& child_id : config_region_children_[parent_module][region]) {
|
||||
region_config_child_coordinates.push_back(configurable_child_coordinates_[parent_module][child_id]);
|
||||
}
|
||||
|
||||
return region_config_child_coordinates;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Public Accessors
|
||||
******************************************************************************/
|
||||
|
@ -534,6 +557,7 @@ ModuleId ModuleManager::add_module(const std::string& name) {
|
|||
configurable_children_.emplace_back();
|
||||
configurable_child_instances_.emplace_back();
|
||||
configurable_child_regions_.emplace_back();
|
||||
configurable_child_coordinates_.emplace_back();
|
||||
|
||||
config_region_ids_.emplace_back();
|
||||
config_region_children_.emplace_back();
|
||||
|
@ -716,7 +740,8 @@ void ModuleManager::set_child_instance_name(const ModuleId& parent_module,
|
|||
*/
|
||||
void ModuleManager::add_configurable_child(const ModuleId& parent_module,
|
||||
const ModuleId& child_module,
|
||||
const size_t& child_instance) {
|
||||
const size_t& child_instance,
|
||||
const vtr::Point<int> coord) {
|
||||
/* Validate the id of both parent and child modules */
|
||||
VTR_ASSERT ( valid_module_id(parent_module) );
|
||||
VTR_ASSERT ( valid_module_id(child_module) );
|
||||
|
@ -726,6 +751,7 @@ void ModuleManager::add_configurable_child(const ModuleId& parent_module,
|
|||
configurable_children_[parent_module].push_back(child_module);
|
||||
configurable_child_instances_[parent_module].push_back(child_instance);
|
||||
configurable_child_regions_[parent_module].push_back(ConfigRegionId::INVALID());
|
||||
configurable_child_coordinates_[parent_module].push_back(coord);
|
||||
}
|
||||
|
||||
void ModuleManager::reserve_configurable_child(const ModuleId& parent_module,
|
||||
|
@ -738,9 +764,12 @@ void ModuleManager::reserve_configurable_child(const ModuleId& parent_module,
|
|||
if (num_children > configurable_child_instances_[parent_module].size()) {
|
||||
configurable_child_instances_[parent_module].reserve(num_children);
|
||||
}
|
||||
if (num_children > configurable_child_instances_[parent_module].size()) {
|
||||
if (num_children > configurable_child_regions_[parent_module].size()) {
|
||||
configurable_child_regions_[parent_module].reserve(num_children);
|
||||
}
|
||||
if (num_children > configurable_child_coordinates_[parent_module].size()) {
|
||||
configurable_child_coordinates_[parent_module].reserve(num_children);
|
||||
}
|
||||
}
|
||||
|
||||
ConfigRegionId ModuleManager::add_config_region(const ModuleId& module) {
|
||||
|
@ -981,6 +1010,7 @@ void ModuleManager::clear_configurable_children(const ModuleId& parent_module) {
|
|||
configurable_children_[parent_module].clear();
|
||||
configurable_child_instances_[parent_module].clear();
|
||||
configurable_child_regions_[parent_module].clear();
|
||||
configurable_child_coordinates_[parent_module].clear();
|
||||
}
|
||||
|
||||
void ModuleManager::clear_config_region(const ModuleId& parent_module) {
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <unordered_map>
|
||||
|
||||
#include "vtr_vector.h"
|
||||
#include "vtr_geometry.h"
|
||||
#include "module_manager_fwd.h"
|
||||
#include "openfpga_port.h"
|
||||
|
||||
|
@ -148,6 +149,8 @@ class ModuleManager {
|
|||
std::vector<ModuleId> configurable_children(const ModuleId& parent_module) const;
|
||||
/* Find all the instances of configurable child modules under a parent module */
|
||||
std::vector<size_t> configurable_child_instances(const ModuleId& parent_module) const;
|
||||
/* Find the coordindate of a configurable child module under a parent module */
|
||||
std::vector<vtr::Point<int>> configurable_child_coordinates(const ModuleId& parent_module) const;
|
||||
/* Find the source ids of modules */
|
||||
module_net_src_range module_net_sources(const ModuleId& module, const ModuleNetId& net) const;
|
||||
/* Find the sink ids of modules */
|
||||
|
@ -161,6 +164,10 @@ class ModuleManager {
|
|||
/* Find all the instances of configurable child modules under a region of a parent module */
|
||||
std::vector<size_t> region_configurable_child_instances(const ModuleId& parent_module,
|
||||
const ConfigRegionId& region) const;
|
||||
|
||||
/* Find all the coordinates of configurable child modules under a region of a parent module */
|
||||
std::vector<vtr::Point<int>> region_configurable_child_coordinates(const ModuleId& parent_module,
|
||||
const ConfigRegionId& region) const;
|
||||
|
||||
public: /* Public accessors */
|
||||
size_t num_modules() const;
|
||||
|
@ -252,8 +259,13 @@ class ModuleManager {
|
|||
void add_child_module(const ModuleId& parent_module, const ModuleId& child_module);
|
||||
/* Set the instance name of a child module */
|
||||
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);
|
||||
/* Add a configurable child module to module
|
||||
* This function also set the coordinate of a configurable child
|
||||
* The coordinate is a relative position in each region, which is used to
|
||||
* idenify BL/WL sharing
|
||||
* By default, it is an invalid coordinate
|
||||
*/
|
||||
void add_configurable_child(const ModuleId& module, const ModuleId& child_module, const size_t& child_instance, const vtr::Point<int> coord = vtr::Point<int>(-1, -1));
|
||||
/* Reserved a number of configurable children
|
||||
* for memory efficiency
|
||||
*/
|
||||
|
@ -350,6 +362,7 @@ class ModuleManager {
|
|||
vtr::vector<ModuleId, std::vector<ModuleId>> configurable_children_; /* Child modules with configurable memory bits that this module contain */
|
||||
vtr::vector<ModuleId, std::vector<size_t>> configurable_child_instances_; /* Instances of child modules with configurable memory bits that this module contain */
|
||||
vtr::vector<ModuleId, std::vector<ConfigRegionId>> configurable_child_regions_; /* Instances of child modules with configurable memory bits that this module contain */
|
||||
vtr::vector<ModuleId, std::vector<vtr::Point<int>>> configurable_child_coordinates_; /* Relative coorindates of child modules with configurable memory bits that this module contain */
|
||||
|
||||
/* Configurable regions to group the configurable children
|
||||
* Note:
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include "openfpga_naming.h"
|
||||
|
||||
#include "memory_utils.h"
|
||||
#include "module_manager_utils.h"
|
||||
|
||||
#include "build_grid_bitstream.h"
|
||||
|
@ -63,7 +64,7 @@ static
|
|||
size_t rec_estimate_device_bitstream_num_bits(const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const ModuleId& parent_module,
|
||||
const e_config_protocol_type& config_protocol_type) {
|
||||
const ConfigProtocol& config_protocol) {
|
||||
size_t num_bits = 0;
|
||||
|
||||
/* If a child module has no configurable children, this is a leaf node
|
||||
|
@ -84,27 +85,13 @@ size_t rec_estimate_device_bitstream_num_bits(const ModuleManager& module_manage
|
|||
if (parent_module == top_module) {
|
||||
for (const ConfigRegionId& config_region : module_manager.regions(parent_module)) {
|
||||
size_t curr_region_num_config_child = module_manager.region_configurable_children(parent_module, config_region).size();
|
||||
|
||||
/* Frame-based configuration protocol will have 1 decoder
|
||||
* if there are more than 1 configurable children
|
||||
*/
|
||||
if ( (CONFIG_MEM_FRAME_BASED == config_protocol_type)
|
||||
&& (2 <= curr_region_num_config_child)) {
|
||||
curr_region_num_config_child--;
|
||||
}
|
||||
|
||||
/* Memory configuration protocol will have 2 decoders
|
||||
* at the top-level
|
||||
*/
|
||||
if (CONFIG_MEM_MEMORY_BANK == config_protocol_type) {
|
||||
VTR_ASSERT(2 <= curr_region_num_config_child);
|
||||
curr_region_num_config_child -= 2;
|
||||
}
|
||||
size_t num_child_to_skip = estimate_num_configurable_children_to_skip_by_config_protocol(config_protocol, curr_region_num_config_child);
|
||||
curr_region_num_config_child -= num_child_to_skip;
|
||||
|
||||
/* Visit all the children in a recursively way */
|
||||
for (size_t ichild = 0; ichild < curr_region_num_config_child; ++ichild) {
|
||||
ModuleId child_module = module_manager.region_configurable_children(parent_module, config_region)[ichild];
|
||||
num_bits += rec_estimate_device_bitstream_num_bits(module_manager, top_module, child_module, config_protocol_type);
|
||||
num_bits += rec_estimate_device_bitstream_num_bits(module_manager, top_module, child_module, config_protocol);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -115,14 +102,14 @@ size_t rec_estimate_device_bitstream_num_bits(const ModuleManager& module_manage
|
|||
/* Frame-based configuration protocol will have 1 decoder
|
||||
* if there are more than 1 configurable children
|
||||
*/
|
||||
if ( (CONFIG_MEM_FRAME_BASED == config_protocol_type)
|
||||
if ( (CONFIG_MEM_FRAME_BASED == config_protocol.type())
|
||||
&& (2 <= num_configurable_children)) {
|
||||
num_configurable_children--;
|
||||
}
|
||||
|
||||
for (size_t ichild = 0; ichild < num_configurable_children; ++ichild) {
|
||||
ModuleId child_module = module_manager.configurable_children(parent_module)[ichild];
|
||||
num_bits += rec_estimate_device_bitstream_num_bits(module_manager, top_module, child_module, config_protocol_type);
|
||||
num_bits += rec_estimate_device_bitstream_num_bits(module_manager, top_module, child_module, config_protocol);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -170,7 +157,7 @@ BitstreamManager build_device_bitstream(const VprContext& vpr_ctx,
|
|||
size_t num_bits_to_reserve = rec_estimate_device_bitstream_num_bits(openfpga_ctx.module_graph(),
|
||||
top_module,
|
||||
top_module,
|
||||
openfpga_ctx.arch().config_protocol.type());
|
||||
openfpga_ctx.arch().config_protocol);
|
||||
bitstream_manager.reserve_bits(num_bits_to_reserve);
|
||||
VTR_LOGV(verbose, "Reserved %lu configuration bits\n", num_bits_to_reserve);
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "decoder_library_utils.h"
|
||||
#include "bitstream_manager_utils.h"
|
||||
#include "build_fabric_bitstream.h"
|
||||
#include "build_fabric_bitstream_memory_bank.h"
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
@ -489,6 +490,7 @@ void rec_build_module_fabric_dependent_frame_bitstream(const BitstreamManager& b
|
|||
*******************************************************************/
|
||||
static
|
||||
void build_module_fabric_dependent_bitstream(const ConfigProtocol& config_protocol,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const BitstreamManager& bitstream_manager,
|
||||
const ConfigBlockId& top_block,
|
||||
const ModuleManager& module_manager,
|
||||
|
@ -575,6 +577,13 @@ void build_module_fabric_dependent_bitstream(const ConfigProtocol& config_protoc
|
|||
}
|
||||
break;
|
||||
}
|
||||
case CONFIG_MEM_QL_MEMORY_BANK: {
|
||||
build_module_fabric_dependent_bitstream_ql_memory_bank(config_protocol, circuit_lib,
|
||||
bitstream_manager, top_block,
|
||||
module_manager, top_module,
|
||||
fabric_bitstream);
|
||||
break;
|
||||
}
|
||||
case CONFIG_MEM_FRAME_BASED: {
|
||||
|
||||
/* Find address port size */
|
||||
|
@ -694,6 +703,7 @@ void build_module_fabric_dependent_bitstream(const ConfigProtocol& config_protoc
|
|||
*******************************************************************/
|
||||
FabricBitstream build_fabric_dependent_bitstream(const BitstreamManager& bitstream_manager,
|
||||
const ModuleManager& module_manager,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const bool& verbose) {
|
||||
FabricBitstream fabric_bitstream;
|
||||
|
@ -712,7 +722,7 @@ FabricBitstream build_fabric_dependent_bitstream(const BitstreamManager& bitstre
|
|||
VTR_ASSERT(0 == top_module_name.compare(bitstream_manager.block_name(top_block[0])));
|
||||
|
||||
/* Start build-up formally */
|
||||
build_module_fabric_dependent_bitstream(config_protocol,
|
||||
build_module_fabric_dependent_bitstream(config_protocol, circuit_lib,
|
||||
bitstream_manager, top_block[0],
|
||||
module_manager, top_module,
|
||||
fabric_bitstream);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*******************************************************************/
|
||||
#include <vector>
|
||||
#include "config_protocol.h"
|
||||
#include "circuit_library.h"
|
||||
#include "bitstream_manager.h"
|
||||
#include "fabric_bitstream.h"
|
||||
#include "module_manager.h"
|
||||
|
@ -19,6 +20,7 @@ namespace openfpga {
|
|||
|
||||
FabricBitstream build_fabric_dependent_bitstream(const BitstreamManager& bitstream_manager,
|
||||
const ModuleManager& module_manager,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const bool& verbose);
|
||||
|
||||
|
|
|
@ -0,0 +1,371 @@
|
|||
/********************************************************************
|
||||
* This file includes functions to build fabric dependent bitstream
|
||||
* for memory bank configuration protocol
|
||||
*******************************************************************/
|
||||
#include <string>
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
|
||||
/* Headers from vtrutil library */
|
||||
#include "vtr_assert.h"
|
||||
#include "vtr_log.h"
|
||||
#include "vtr_time.h"
|
||||
|
||||
/* Headers from openfpgautil library */
|
||||
#include "openfpga_decode.h"
|
||||
|
||||
#include "openfpga_reserved_words.h"
|
||||
#include "openfpga_naming.h"
|
||||
|
||||
#include "decoder_library_utils.h"
|
||||
#include "bitstream_manager_utils.h"
|
||||
#include "memory_utils.h"
|
||||
#include "memory_bank_utils.h"
|
||||
#include "build_fabric_bitstream_memory_bank.h"
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
/********************************************************************
|
||||
* This function aims to build a bitstream for memory-bank protocol
|
||||
* It will walk through all the configurable children under a module
|
||||
* in a recursive way, following a Depth-First Search (DFS) strategy
|
||||
* For each configuration child, we use its instance name as a key to spot the
|
||||
* configuration bits in bitstream manager.
|
||||
* Note that it is guarentee that the instance name in module manager is
|
||||
* consistent with the block names in bitstream manager
|
||||
* We use this link to reorganize the bitstream in the sequence of memories as we stored
|
||||
* in the configurable_children() and configurable_child_instances() of each module of module manager
|
||||
*
|
||||
* In such configuration organization, each memory cell has an unique index.
|
||||
* Using this index, we can infer the address codes for both BL and WL decoders.
|
||||
* Note that, we must get the number of BLs and WLs before using this function!
|
||||
*******************************************************************/
|
||||
static
|
||||
void rec_build_module_fabric_dependent_ql_memory_bank_regional_bitstream(const BitstreamManager& bitstream_manager,
|
||||
const ConfigBlockId& parent_block,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const ModuleId& parent_module,
|
||||
const ConfigRegionId& config_region,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& sram_model,
|
||||
const size_t& bl_addr_size,
|
||||
const size_t& wl_addr_size,
|
||||
size_t& num_bls_cur_tile,
|
||||
const std::map<int, size_t>& bl_start_index_per_tile,
|
||||
size_t& num_wls_cur_tile,
|
||||
const std::map<int, size_t>& wl_start_index_per_tile,
|
||||
vtr::Point<int>& tile_coord,
|
||||
std::map<vtr::Point<int>, size_t>& cur_mem_index,
|
||||
FabricBitstream& fabric_bitstream,
|
||||
const FabricBitRegionId& fabric_bitstream_region) {
|
||||
|
||||
/* Depth-first search: if we have any children in the parent_block,
|
||||
* we dive to the next level first!
|
||||
*/
|
||||
if (0 < bitstream_manager.block_children(parent_block).size()) {
|
||||
/* For top module:
|
||||
* - Use regional configurable children
|
||||
* - we will skip the two decoders at the end of the configurable children list
|
||||
*/
|
||||
if (parent_module == top_module) {
|
||||
std::vector<ModuleId> configurable_children = module_manager.region_configurable_children(parent_module, config_region);
|
||||
|
||||
VTR_ASSERT(2 <= configurable_children.size());
|
||||
size_t num_config_child_to_skip = estimate_num_configurable_children_to_skip_by_config_protocol(config_protocol,
|
||||
configurable_children.size());
|
||||
size_t num_configurable_children = configurable_children.size() - num_config_child_to_skip;
|
||||
|
||||
/* Early exit if there is no configurable children */
|
||||
if (0 == num_configurable_children) {
|
||||
/* Ensure that there should be no configuration bits in the parent block */
|
||||
VTR_ASSERT(0 == bitstream_manager.block_bits(parent_block).size());
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t child_id = 0; child_id < num_configurable_children; ++child_id) {
|
||||
ModuleId child_module = configurable_children[child_id];
|
||||
size_t child_instance = module_manager.region_configurable_child_instances(parent_module, config_region)[child_id];
|
||||
|
||||
tile_coord = module_manager.region_configurable_child_coordinates(parent_module, config_region)[child_id];
|
||||
num_bls_cur_tile = find_module_ql_memory_bank_num_blwls(module_manager, child_module, circuit_lib, sram_model, CONFIG_MEM_QL_MEMORY_BANK, CIRCUIT_MODEL_PORT_BL);
|
||||
num_wls_cur_tile = find_module_ql_memory_bank_num_blwls(module_manager, child_module, circuit_lib, sram_model, CONFIG_MEM_QL_MEMORY_BANK, CIRCUIT_MODEL_PORT_WL);
|
||||
|
||||
/* Get the instance name and ensure it is not empty */
|
||||
std::string instance_name = module_manager.instance_name(parent_module, child_module, child_instance);
|
||||
|
||||
/* Find the child block that matches the instance name! */
|
||||
ConfigBlockId child_block = bitstream_manager.find_child_block(parent_block, instance_name);
|
||||
/* We must have one valid block id! */
|
||||
VTR_ASSERT(true == bitstream_manager.valid_block_id(child_block));
|
||||
|
||||
/* Go recursively */
|
||||
rec_build_module_fabric_dependent_ql_memory_bank_regional_bitstream(bitstream_manager, child_block,
|
||||
module_manager, top_module, child_module,
|
||||
config_region,
|
||||
config_protocol,
|
||||
circuit_lib, sram_model,
|
||||
bl_addr_size, wl_addr_size,
|
||||
num_bls_cur_tile, bl_start_index_per_tile,
|
||||
num_wls_cur_tile, wl_start_index_per_tile,
|
||||
tile_coord,
|
||||
cur_mem_index,
|
||||
fabric_bitstream,
|
||||
fabric_bitstream_region);
|
||||
}
|
||||
} else {
|
||||
VTR_ASSERT(parent_module != top_module);
|
||||
/* For other modules:
|
||||
* - Use configurable children directly
|
||||
* - no need to exclude decoders as they are not there
|
||||
*/
|
||||
std::vector<ModuleId> configurable_children = module_manager.configurable_children(parent_module);
|
||||
|
||||
size_t num_configurable_children = configurable_children.size();
|
||||
|
||||
/* Early exit if there is no configurable children */
|
||||
if (0 == num_configurable_children) {
|
||||
/* Ensure that there should be no configuration bits in the parent block */
|
||||
VTR_ASSERT(0 == bitstream_manager.block_bits(parent_block).size());
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t child_id = 0; child_id < num_configurable_children; ++child_id) {
|
||||
ModuleId child_module = configurable_children[child_id];
|
||||
size_t child_instance = module_manager.configurable_child_instances(parent_module)[child_id];
|
||||
|
||||
/* Get the instance name and ensure it is not empty */
|
||||
std::string instance_name = module_manager.instance_name(parent_module, child_module, child_instance);
|
||||
|
||||
/* Find the child block that matches the instance name! */
|
||||
ConfigBlockId child_block = bitstream_manager.find_child_block(parent_block, instance_name);
|
||||
/* We must have one valid block id! */
|
||||
VTR_ASSERT(true == bitstream_manager.valid_block_id(child_block));
|
||||
|
||||
/* Go recursively */
|
||||
rec_build_module_fabric_dependent_ql_memory_bank_regional_bitstream(bitstream_manager, child_block,
|
||||
module_manager, top_module, child_module,
|
||||
config_region,
|
||||
config_protocol,
|
||||
circuit_lib, sram_model,
|
||||
bl_addr_size, wl_addr_size,
|
||||
num_bls_cur_tile, bl_start_index_per_tile,
|
||||
num_wls_cur_tile, wl_start_index_per_tile,
|
||||
tile_coord,
|
||||
cur_mem_index,
|
||||
fabric_bitstream,
|
||||
fabric_bitstream_region);
|
||||
}
|
||||
}
|
||||
/* Ensure that there should be no configuration bits in the parent block */
|
||||
VTR_ASSERT(0 == bitstream_manager.block_bits(parent_block).size());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Note that, reach here, it means that this is a leaf node.
|
||||
* We add the configuration bits to the fabric_bitstream,
|
||||
* And then, we can return
|
||||
*/
|
||||
for (const ConfigBitId& config_bit : bitstream_manager.block_bits(parent_block)) {
|
||||
FabricBitId fabric_bit = fabric_bitstream.add_bit(config_bit);
|
||||
|
||||
/* The BL address to be decoded depends on the protocol
|
||||
* - flatten BLs: use 1-hot decoding
|
||||
* - BL decoders: fully encoded
|
||||
* - Shift register: use 1-hot decoding
|
||||
*/
|
||||
size_t cur_bl_index = bl_start_index_per_tile.at(tile_coord.x()) + cur_mem_index[tile_coord] % num_bls_cur_tile;
|
||||
std::vector<char> bl_addr_bits_vec;
|
||||
if (BLWL_PROTOCOL_DECODER == config_protocol.bl_protocol_type()) {
|
||||
bl_addr_bits_vec = itobin_charvec(cur_bl_index, bl_addr_size);
|
||||
} else if (BLWL_PROTOCOL_FLATTEN == config_protocol.bl_protocol_type()
|
||||
|| BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type()) {
|
||||
bl_addr_bits_vec = ito1hot_charvec(cur_bl_index, bl_addr_size, DONT_CARE_CHAR);
|
||||
}
|
||||
|
||||
/* Find WL address */
|
||||
size_t cur_wl_index = wl_start_index_per_tile.at(tile_coord.y()) + std::floor(cur_mem_index[tile_coord] / num_bls_cur_tile);
|
||||
std::vector<char> wl_addr_bits_vec;
|
||||
if (BLWL_PROTOCOL_DECODER == config_protocol.wl_protocol_type()) {
|
||||
wl_addr_bits_vec = itobin_charvec(cur_wl_index, wl_addr_size);
|
||||
} else if (BLWL_PROTOCOL_FLATTEN == config_protocol.wl_protocol_type()
|
||||
|| BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.wl_protocol_type()) {
|
||||
wl_addr_bits_vec = ito1hot_charvec(cur_wl_index, wl_addr_size);
|
||||
}
|
||||
|
||||
/* Set BL address */
|
||||
fabric_bitstream.set_bit_bl_address(fabric_bit, bl_addr_bits_vec, BLWL_PROTOCOL_DECODER != config_protocol.bl_protocol_type());
|
||||
|
||||
/* Set WL address */
|
||||
fabric_bitstream.set_bit_wl_address(fabric_bit, wl_addr_bits_vec, BLWL_PROTOCOL_DECODER != config_protocol.wl_protocol_type());
|
||||
|
||||
/* Set data input */
|
||||
fabric_bitstream.set_bit_din(fabric_bit, bitstream_manager.bit_value(config_bit));
|
||||
|
||||
/* Add the bit to the region */
|
||||
fabric_bitstream.add_bit_to_region(fabric_bitstream_region, fabric_bit);
|
||||
|
||||
/* Increase the memory index */
|
||||
cur_mem_index[tile_coord]++;
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Main function to build a fabric-dependent bitstream
|
||||
* by considering the QuickLogic memory banks
|
||||
*******************************************************************/
|
||||
void build_module_fabric_dependent_bitstream_ql_memory_bank(const ConfigProtocol& config_protocol,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const BitstreamManager& bitstream_manager,
|
||||
const ConfigBlockId& top_block,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
FabricBitstream& fabric_bitstream) {
|
||||
/* Ensure we are in the correct type of configuration protocol*/
|
||||
VTR_ASSERT(config_protocol.type() == CONFIG_MEM_QL_MEMORY_BANK);
|
||||
|
||||
/* For different BL control protocol, the address ports are different
|
||||
* - flatten BLs: the address port should be raw BL ports at top-level module.
|
||||
* Due to each configuration region has separated BLs, the address port should be the one with largest size
|
||||
* - BL decoders: the address port should be the BL address port at top-level module
|
||||
* - Shift register: the address port size will be calculated by the total number of unique BLs per child module in each configuration region
|
||||
* Due to each configuration region has separated BLs, the address port should be the one with largest size
|
||||
*/
|
||||
ModulePortId bl_addr_port;
|
||||
BasicPort bl_addr_port_info;
|
||||
if (BLWL_PROTOCOL_DECODER == config_protocol.bl_protocol_type()) {
|
||||
bl_addr_port = module_manager.find_module_port(top_module, std::string(DECODER_BL_ADDRESS_PORT_NAME));
|
||||
bl_addr_port_info = module_manager.module_port(top_module, bl_addr_port);
|
||||
} else if (BLWL_PROTOCOL_FLATTEN == config_protocol.bl_protocol_type()) {
|
||||
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
|
||||
ModulePortId temp_bl_addr_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(std::string(MEMORY_BL_PORT_NAME), config_region));
|
||||
BasicPort temp_bl_addr_port_info = module_manager.module_port(top_module, temp_bl_addr_port);
|
||||
if (!bl_addr_port || (temp_bl_addr_port_info.get_width() > bl_addr_port_info.get_width())) {
|
||||
bl_addr_port = temp_bl_addr_port;
|
||||
bl_addr_port_info = temp_bl_addr_port_info;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
VTR_ASSERT(BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type());
|
||||
bl_addr_port_info.set_width(1); /* Deposit minimum width */
|
||||
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
|
||||
size_t num_bls = compute_memory_bank_regional_num_bls(module_manager, top_module, config_region, circuit_lib, config_protocol.memory_model());
|
||||
bl_addr_port_info.set_width(std::max(num_bls, bl_addr_port_info.get_width()));
|
||||
}
|
||||
}
|
||||
|
||||
/* For different WL control protocol, the address ports are different
|
||||
* - flatten WLs: the address port should be raw WL ports at top-level module.
|
||||
* Due to each configuration region has separated WLs, the address port should be the one with largest size
|
||||
* - WL decoders: the address port should be the WL address port at top-level module
|
||||
* - Shift register: the address port size will be calculated by the total number of unique WLs per child module in each configuration region
|
||||
* Due to each configuration region has separated WLs, the address port should be the one with largest size
|
||||
*/
|
||||
ModulePortId wl_addr_port;
|
||||
BasicPort wl_addr_port_info;
|
||||
if (BLWL_PROTOCOL_DECODER == config_protocol.wl_protocol_type()) {
|
||||
wl_addr_port = module_manager.find_module_port(top_module, std::string(DECODER_WL_ADDRESS_PORT_NAME));
|
||||
wl_addr_port_info = module_manager.module_port(top_module, wl_addr_port);
|
||||
} else if (BLWL_PROTOCOL_FLATTEN == config_protocol.wl_protocol_type()) {
|
||||
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
|
||||
ModulePortId temp_wl_addr_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(std::string(MEMORY_WL_PORT_NAME), config_region));
|
||||
BasicPort temp_wl_addr_port_info = module_manager.module_port(top_module, temp_wl_addr_port);
|
||||
if (!wl_addr_port || (temp_wl_addr_port_info.get_width() > wl_addr_port_info.get_width())) {
|
||||
wl_addr_port = temp_wl_addr_port;
|
||||
wl_addr_port_info = temp_wl_addr_port_info;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
VTR_ASSERT(BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.wl_protocol_type());
|
||||
wl_addr_port_info.set_width(1); /* Deposit minimum width */
|
||||
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
|
||||
size_t num_wls = compute_memory_bank_regional_num_wls(module_manager, top_module, config_region, circuit_lib, config_protocol.memory_model());
|
||||
wl_addr_port_info.set_width(std::max(num_wls, wl_addr_port_info.get_width()));
|
||||
}
|
||||
}
|
||||
|
||||
/* Reserve bits before build-up */
|
||||
fabric_bitstream.set_use_address(true);
|
||||
fabric_bitstream.set_use_wl_address(true);
|
||||
fabric_bitstream.set_bl_address_length(bl_addr_port_info.get_width());
|
||||
fabric_bitstream.set_wl_address_length(wl_addr_port_info.get_width());
|
||||
fabric_bitstream.reserve_bits(bitstream_manager.num_bits());
|
||||
|
||||
/* Build bitstreams by region */
|
||||
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
|
||||
/* Find port information for local BL and WL decoder in this region */
|
||||
std::vector<ModuleId> configurable_children = module_manager.region_configurable_children(top_module, config_region);
|
||||
VTR_ASSERT(2 <= configurable_children.size());
|
||||
|
||||
/* Build the bitstream for all the blocks in this region */
|
||||
FabricBitRegionId fabric_bitstream_region = fabric_bitstream.add_region();
|
||||
|
||||
/* Find the BL/WL port (different region may have different sizes of BL/WLs) */
|
||||
ModulePortId cur_bl_addr_port;
|
||||
BasicPort cur_bl_addr_port_info;
|
||||
if (BLWL_PROTOCOL_DECODER == config_protocol.bl_protocol_type()) {
|
||||
cur_bl_addr_port = module_manager.find_module_port(top_module, std::string(DECODER_BL_ADDRESS_PORT_NAME));
|
||||
cur_bl_addr_port_info = module_manager.module_port(top_module, cur_bl_addr_port);
|
||||
} else if (BLWL_PROTOCOL_FLATTEN == config_protocol.bl_protocol_type()) {
|
||||
cur_bl_addr_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(std::string(MEMORY_BL_PORT_NAME), config_region));
|
||||
cur_bl_addr_port_info = module_manager.module_port(top_module, cur_bl_addr_port);
|
||||
} else {
|
||||
VTR_ASSERT(BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type());
|
||||
cur_bl_addr_port_info.set_width(compute_memory_bank_regional_num_bls(module_manager, top_module, config_region, circuit_lib, config_protocol.memory_model()));
|
||||
}
|
||||
|
||||
ModulePortId cur_wl_addr_port;
|
||||
BasicPort cur_wl_addr_port_info;
|
||||
if (BLWL_PROTOCOL_DECODER == config_protocol.wl_protocol_type()) {
|
||||
cur_wl_addr_port = module_manager.find_module_port(top_module, std::string(DECODER_WL_ADDRESS_PORT_NAME));
|
||||
cur_wl_addr_port_info = module_manager.module_port(top_module, cur_wl_addr_port);
|
||||
} else if (BLWL_PROTOCOL_FLATTEN == config_protocol.wl_protocol_type()) {
|
||||
cur_wl_addr_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(std::string(MEMORY_WL_PORT_NAME), config_region));
|
||||
cur_wl_addr_port_info = module_manager.module_port(top_module, cur_wl_addr_port);
|
||||
} else {
|
||||
VTR_ASSERT(BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.wl_protocol_type());
|
||||
cur_wl_addr_port_info.set_width(compute_memory_bank_regional_num_wls(module_manager, top_module, config_region, circuit_lib, config_protocol.memory_model()));
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
* Precompute the BLs and WLs distribution across the FPGA fabric
|
||||
* The distribution is a matrix which contains the starting index of BL/WL for each column or row
|
||||
*/
|
||||
std::pair<int, int> child_x_range = compute_memory_bank_regional_configurable_child_x_range(module_manager, top_module, config_region);
|
||||
std::pair<int, int> child_y_range = compute_memory_bank_regional_configurable_child_y_range(module_manager, top_module, config_region);
|
||||
|
||||
std::map<int, size_t> num_bls_per_tile = compute_memory_bank_regional_bitline_numbers_per_tile(module_manager, top_module,
|
||||
config_region,
|
||||
circuit_lib, config_protocol.memory_model());
|
||||
std::map<int, size_t> num_wls_per_tile = compute_memory_bank_regional_wordline_numbers_per_tile(module_manager, top_module,
|
||||
config_region,
|
||||
circuit_lib, config_protocol.memory_model());
|
||||
|
||||
std::map<int, size_t> bl_start_index_per_tile = compute_memory_bank_regional_blwl_start_index_per_tile(child_x_range, num_bls_per_tile);
|
||||
std::map<int, size_t> wl_start_index_per_tile = compute_memory_bank_regional_blwl_start_index_per_tile(child_y_range, num_wls_per_tile);
|
||||
|
||||
vtr::Point<int> temp_coord;
|
||||
std::map<vtr::Point<int>, size_t> cur_mem_index;
|
||||
size_t temp_num_bls_cur_tile = 0;
|
||||
size_t temp_num_wls_cur_tile = 0;
|
||||
|
||||
rec_build_module_fabric_dependent_ql_memory_bank_regional_bitstream(bitstream_manager, top_block,
|
||||
module_manager, top_module, top_module,
|
||||
config_region,
|
||||
config_protocol,
|
||||
circuit_lib, config_protocol.memory_model(),
|
||||
cur_bl_addr_port_info.get_width(),
|
||||
cur_wl_addr_port_info.get_width(),
|
||||
temp_num_bls_cur_tile, bl_start_index_per_tile,
|
||||
temp_num_wls_cur_tile, wl_start_index_per_tile,
|
||||
temp_coord,
|
||||
cur_mem_index,
|
||||
fabric_bitstream,
|
||||
fabric_bitstream_region);
|
||||
}
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
|
@ -0,0 +1,31 @@
|
|||
#ifndef BUILD_FABRIC_BITSTREAM_MEMORY_BANK_H
|
||||
#define BUILD_FABRIC_BITSTREAM_MEMORY_BANK_H
|
||||
|
||||
/********************************************************************
|
||||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
#include <vector>
|
||||
#include "config_protocol.h"
|
||||
#include "circuit_library.h"
|
||||
#include "bitstream_manager.h"
|
||||
#include "fabric_bitstream.h"
|
||||
#include "module_manager.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
*******************************************************************/
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
void build_module_fabric_dependent_bitstream_ql_memory_bank(const ConfigProtocol& config_protocol,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const BitstreamManager& bitstream_manager,
|
||||
const ConfigBlockId& top_block,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
FabricBitstream& fabric_bitstream);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
#endif
|
|
@ -139,24 +139,35 @@ FabricBitId FabricBitstream::add_bit(const ConfigBitId& config_bit_id) {
|
|||
}
|
||||
|
||||
void FabricBitstream::set_bit_address(const FabricBitId& bit_id,
|
||||
const std::vector<char>& address) {
|
||||
const std::vector<char>& address,
|
||||
const bool& tolerant_short_address) {
|
||||
VTR_ASSERT(true == valid_bit_id(bit_id));
|
||||
VTR_ASSERT(true == use_address_);
|
||||
VTR_ASSERT(address_length_ == address.size());
|
||||
if (tolerant_short_address) {
|
||||
VTR_ASSERT(address_length_ >= address.size());
|
||||
} else {
|
||||
VTR_ASSERT(address_length_ == address.size());
|
||||
}
|
||||
bit_addresses_[bit_id] = address;
|
||||
}
|
||||
|
||||
void FabricBitstream::set_bit_bl_address(const FabricBitId& bit_id,
|
||||
const std::vector<char>& address) {
|
||||
set_bit_address(bit_id, address);
|
||||
const std::vector<char>& address,
|
||||
const bool& tolerant_short_address) {
|
||||
set_bit_address(bit_id, address, tolerant_short_address);
|
||||
}
|
||||
|
||||
void FabricBitstream::set_bit_wl_address(const FabricBitId& bit_id,
|
||||
const std::vector<char>& address) {
|
||||
const std::vector<char>& address,
|
||||
const bool& tolerant_short_address) {
|
||||
VTR_ASSERT(true == valid_bit_id(bit_id));
|
||||
VTR_ASSERT(true == use_address_);
|
||||
VTR_ASSERT(true == use_wl_address_);
|
||||
VTR_ASSERT(wl_address_length_ == address.size());
|
||||
if (tolerant_short_address) {
|
||||
VTR_ASSERT(wl_address_length_ >= address.size());
|
||||
} else {
|
||||
VTR_ASSERT(wl_address_length_ == address.size());
|
||||
}
|
||||
bit_wl_addresses_[bit_id] = address;
|
||||
}
|
||||
|
||||
|
|
|
@ -135,13 +135,16 @@ class FabricBitstream {
|
|||
FabricBitId add_bit(const ConfigBitId& config_bit_id);
|
||||
|
||||
void set_bit_address(const FabricBitId& bit_id,
|
||||
const std::vector<char>& address);
|
||||
const std::vector<char>& address,
|
||||
const bool& tolerant_short_address = false);
|
||||
|
||||
void set_bit_bl_address(const FabricBitId& bit_id,
|
||||
const std::vector<char>& address);
|
||||
const std::vector<char>& address,
|
||||
const bool& tolerant_short_address = false);
|
||||
|
||||
void set_bit_wl_address(const FabricBitId& bit_id,
|
||||
const std::vector<char>& address);
|
||||
const std::vector<char>& address,
|
||||
const bool& tolerant_short_address = false);
|
||||
|
||||
void set_bit_din(const FabricBitId& bit_id,
|
||||
const char& din);
|
||||
|
|
|
@ -87,6 +87,7 @@ bool find_bit_value_to_skip_for_fast_configuration(const e_config_protocol_type&
|
|||
}
|
||||
break;
|
||||
}
|
||||
case CONFIG_MEM_QL_MEMORY_BANK:
|
||||
case CONFIG_MEM_MEMORY_BANK:
|
||||
case CONFIG_MEM_FRAME_BASED: {
|
||||
/* Count how many logic '1' and logic '0' bits we can skip */
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
#include "memory_bank_flatten_fabric_bitstream.h"
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
size_t MemoryBankFlattenFabricBitstream::size() const {
|
||||
return bitstream_.size();
|
||||
}
|
||||
|
||||
size_t MemoryBankFlattenFabricBitstream::bl_vector_size() const {
|
||||
/* The address sizes and data input sizes are the same across any element,
|
||||
* just get it from the 1st element to save runtime
|
||||
*/
|
||||
size_t bl_vec_size = 0;
|
||||
for (const auto& bl_vec : bitstream_.begin()->second) {
|
||||
bl_vec_size += bl_vec.size();
|
||||
}
|
||||
return bl_vec_size;
|
||||
}
|
||||
|
||||
size_t MemoryBankFlattenFabricBitstream::wl_vector_size() const {
|
||||
/* The address sizes and data input sizes are the same across any element,
|
||||
* just get it from the 1st element to save runtime
|
||||
*/
|
||||
size_t wl_vec_size = 0;
|
||||
for (const auto& wl_vec : bitstream_.begin()->first) {
|
||||
wl_vec_size += wl_vec.size();
|
||||
}
|
||||
return wl_vec_size;
|
||||
}
|
||||
|
||||
std::vector<std::string> MemoryBankFlattenFabricBitstream::bl_vector(const std::vector<std::string>& wl_vec) const {
|
||||
return bitstream_.at(wl_vec);
|
||||
}
|
||||
|
||||
std::vector<std::vector<std::string>> MemoryBankFlattenFabricBitstream::wl_vectors() const {
|
||||
std::vector<std::vector<std::string>> wl_vecs;
|
||||
for (const auto& pair : bitstream_) {
|
||||
wl_vecs.push_back(pair.first);
|
||||
}
|
||||
return wl_vecs;
|
||||
}
|
||||
|
||||
void MemoryBankFlattenFabricBitstream::add_blwl_vectors(const std::vector<std::string>& bl_vec,
|
||||
const std::vector<std::string>& wl_vec) {
|
||||
/* TODO: Add sanity check. Give a warning if the wl vector is already there */
|
||||
bitstream_[wl_vec] = bl_vec;
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
|
@ -0,0 +1,49 @@
|
|||
#ifndef MEMORY_BANK_FLATTEN_FABRIC_BITSTREAM_H
|
||||
#define MEMORY_BANK_FLATTEN_FABRIC_BITSTREAM_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "vtr_vector.h"
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
/******************************************************************************
|
||||
* This files includes data structures that stores a downloadable format of fabric bitstream
|
||||
* which is compatible with memory bank configuration protocol using flatten BL/WL buses
|
||||
* @note This data structure is mainly used to output bitstream file for compatible protocols
|
||||
******************************************************************************/
|
||||
class MemoryBankFlattenFabricBitstream {
|
||||
public: /* Accessors */
|
||||
/* @brief Return the length of bitstream */
|
||||
size_t size() const;
|
||||
|
||||
/* @brief Return the BL address size */
|
||||
size_t bl_vector_size() const;
|
||||
|
||||
/* @brief Return the WL address size */
|
||||
size_t wl_vector_size() const;
|
||||
|
||||
/* @brief Return the BL vectors with a given WL key */
|
||||
std::vector<std::string> bl_vector(const std::vector<std::string>& wl_vec) const;
|
||||
|
||||
/* @brief Return all the WL vectors in a downloaded sequence */
|
||||
std::vector<std::vector<std::string>> wl_vectors() const;
|
||||
|
||||
public: /* Mutators */
|
||||
/* @brief add a pair of BL/WL vectors to the bitstream database */
|
||||
void add_blwl_vectors(const std::vector<std::string>& bl_vec,
|
||||
const std::vector<std::string>& wl_vec);
|
||||
public: /* Validators */
|
||||
private: /* Internal data */
|
||||
/* [(wl_bank0, wl_bank1, ...)] = [(bl_bank0, bl_bank1, ...)]
|
||||
* Must use (WL, BL) as pairs in the map!!!
|
||||
* This is because BL data may not be unique while WL must be unique
|
||||
*/
|
||||
std::map<std::vector<std::string>, std::vector<std::string>> bitstream_;
|
||||
};
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
#endif
|
|
@ -0,0 +1,82 @@
|
|||
#include "vtr_assert.h"
|
||||
#include "memory_bank_shift_register_fabric_bitstream.h"
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
MemoryBankShiftRegisterFabricBitstream::word_range MemoryBankShiftRegisterFabricBitstream::words() const {
|
||||
return vtr::make_range(bitstream_word_ids_.begin(), bitstream_word_ids_.end());
|
||||
}
|
||||
|
||||
size_t MemoryBankShiftRegisterFabricBitstream::num_words() const {
|
||||
return bitstream_word_ids_.size();
|
||||
}
|
||||
|
||||
size_t MemoryBankShiftRegisterFabricBitstream::bl_word_size() const {
|
||||
/* For a fast runtime, we just inspect the last element
|
||||
* It is the validator which should ensure all the words have a uniform size
|
||||
*/
|
||||
return bitstream_word_bls_[bitstream_word_ids_.back()].size();
|
||||
}
|
||||
|
||||
size_t MemoryBankShiftRegisterFabricBitstream::wl_word_size() const {
|
||||
/* For a fast runtime, we just inspect the last element
|
||||
* It is the validator which should ensure all the words have a uniform size
|
||||
*/
|
||||
return bitstream_word_wls_[bitstream_word_ids_.back()].size();
|
||||
}
|
||||
|
||||
size_t MemoryBankShiftRegisterFabricBitstream::bl_width() const {
|
||||
/* For a fast runtime, we just inspect the last element
|
||||
* It is the validator which should ensure all the words have a uniform size
|
||||
*/
|
||||
return bitstream_word_bls_[bitstream_word_ids_.back()].back().size();
|
||||
}
|
||||
|
||||
size_t MemoryBankShiftRegisterFabricBitstream::wl_width() const {
|
||||
/* For a fast runtime, we just inspect the last element
|
||||
* It is the validator which should ensure all the words have a uniform size
|
||||
*/
|
||||
return bitstream_word_wls_[bitstream_word_ids_.back()].back().size();
|
||||
}
|
||||
|
||||
std::vector<std::string> MemoryBankShiftRegisterFabricBitstream::bl_vectors(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id) const {
|
||||
VTR_ASSERT(valid_word_id(word_id));
|
||||
return bitstream_word_bls_[word_id];
|
||||
}
|
||||
|
||||
std::vector<std::string> MemoryBankShiftRegisterFabricBitstream::wl_vectors(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id) const {
|
||||
VTR_ASSERT(valid_word_id(word_id));
|
||||
return bitstream_word_wls_[word_id];
|
||||
}
|
||||
|
||||
MemoryBankShiftRegisterFabricBitstreamWordId MemoryBankShiftRegisterFabricBitstream::create_word() {
|
||||
/* Create a new id*/
|
||||
MemoryBankShiftRegisterFabricBitstreamWordId word_id = MemoryBankShiftRegisterFabricBitstreamWordId(bitstream_word_ids_.size());
|
||||
/* Update the id list */
|
||||
bitstream_word_ids_.push_back(word_id);
|
||||
|
||||
/* Initialize other attributes */
|
||||
bitstream_word_bls_.emplace_back();
|
||||
bitstream_word_wls_.emplace_back();
|
||||
|
||||
return word_id;
|
||||
}
|
||||
|
||||
void MemoryBankShiftRegisterFabricBitstream::add_bl_vectors(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id,
|
||||
const std::string& bl_vec) {
|
||||
VTR_ASSERT(valid_word_id(word_id));
|
||||
return bitstream_word_bls_[word_id].push_back(bl_vec);
|
||||
}
|
||||
|
||||
void MemoryBankShiftRegisterFabricBitstream::add_wl_vectors(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id,
|
||||
const std::string& wl_vec) {
|
||||
VTR_ASSERT(valid_word_id(word_id));
|
||||
return bitstream_word_wls_[word_id].push_back(wl_vec);
|
||||
}
|
||||
|
||||
bool MemoryBankShiftRegisterFabricBitstream::valid_word_id(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id) const {
|
||||
return ( size_t(word_id) < bitstream_word_ids_.size() ) && ( word_id == bitstream_word_ids_[word_id] );
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
|
@ -0,0 +1,96 @@
|
|||
#ifndef MEMORY_BANK_SHIFT_REGISTER_FABRIC_BITSTREAM_H
|
||||
#define MEMORY_BANK_SHIFT_REGISTER_FABRIC_BITSTREAM_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "vtr_vector.h"
|
||||
#include "memory_bank_shift_register_fabric_bitstream_fwd.h"
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
/******************************************************************************
|
||||
* This files includes data structures that stores a downloadable format of fabric bitstream
|
||||
* which is compatible with memory bank configuration protocol using shift register to control BL/WLs
|
||||
* @note This data structure is mainly used to output bitstream file for compatible protocols
|
||||
******************************************************************************/
|
||||
class MemoryBankShiftRegisterFabricBitstream {
|
||||
public: /* Types */
|
||||
typedef vtr::vector<MemoryBankShiftRegisterFabricBitstreamWordId, MemoryBankShiftRegisterFabricBitstreamWordId>::const_iterator word_iterator;
|
||||
/* Create range */
|
||||
typedef vtr::Range<word_iterator> word_range;
|
||||
|
||||
public: /* Accessors: aggregates */
|
||||
word_range words() const;
|
||||
|
||||
public: /* Accessors */
|
||||
/* @brief Return the length of bitstream */
|
||||
size_t num_words() const;
|
||||
|
||||
/* @brief Return the length of BL part of each word. All the word should have a uniform size */
|
||||
size_t bl_word_size() const;
|
||||
|
||||
/* @brief Return the length of WL part of each word. All the word should have a uniform size */
|
||||
size_t wl_word_size() const;
|
||||
|
||||
/* @brief Return the width of each BL word, which is the number of heads through which a BL word can be loaded in parallel */
|
||||
size_t bl_width() const;
|
||||
|
||||
/* @brief Return the width of each WL word, which is the number of heads through which a WL word can be loaded in parallel */
|
||||
size_t wl_width() const;
|
||||
|
||||
/* @brief Return the BL vectors with a given word id*/
|
||||
std::vector<std::string> bl_vectors(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id) const;
|
||||
|
||||
/* @brief Return the WL vectors in a given word id */
|
||||
std::vector<std::string> wl_vectors(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id) const;
|
||||
|
||||
public: /* Mutators */
|
||||
/* @brief Create a new word */
|
||||
MemoryBankShiftRegisterFabricBitstreamWordId create_word();
|
||||
|
||||
/* @brief Add BLs to a given word */
|
||||
void add_bl_vectors(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id,
|
||||
const std::string& bl_vec);
|
||||
|
||||
/* @brief Add WLs to a given word */
|
||||
void add_wl_vectors(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id,
|
||||
const std::string& wl_vec);
|
||||
|
||||
public: /* Validators */
|
||||
bool valid_word_id(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id) const;
|
||||
|
||||
private: /* Internal data */
|
||||
/* Organization of the bitstream
|
||||
*
|
||||
* ============= Begin of Word 1 ==============
|
||||
* |<--No of -->|<-- No of -->|
|
||||
* | BL heads | WL heads |
|
||||
* 010101 .. 101 101110 .. 001 ----
|
||||
* ... ... ^
|
||||
* |
|
||||
* max. shift register length per word
|
||||
* |
|
||||
* v
|
||||
* 110001 .. 111 100100 .. 110 ----
|
||||
* ============= End of Word 1 ==============
|
||||
* ============= Begin of Word 2 ==============
|
||||
* 010101 .. 101 101110 .. 001 ----
|
||||
* ... ... ^
|
||||
* |
|
||||
* max. shift register length per word
|
||||
* |
|
||||
* v
|
||||
* 110001 .. 111 100100 .. 110 ----
|
||||
* ============= End of Word 2 ==============
|
||||
* .... more words
|
||||
*/
|
||||
vtr::vector<MemoryBankShiftRegisterFabricBitstreamWordId, MemoryBankShiftRegisterFabricBitstreamWordId> bitstream_word_ids_;
|
||||
vtr::vector<MemoryBankShiftRegisterFabricBitstreamWordId, std::vector<std::string>> bitstream_word_bls_;
|
||||
vtr::vector<MemoryBankShiftRegisterFabricBitstreamWordId, std::vector<std::string>> bitstream_word_wls_;
|
||||
};
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
#endif
|
|
@ -0,0 +1,23 @@
|
|||
/**************************************************
|
||||
* This file includes only declarations for
|
||||
* the data structures for MemoryBankShiftRegisterFabricBitstream
|
||||
* Please refer to memory_bank_shift_register_fabric_bitstream.h for more details
|
||||
*************************************************/
|
||||
#ifndef MEMORY_BANK_SHIFT_REGISTER_FABRIC_BITSTREAM_FWD_H
|
||||
#define MEMORY_BANK_SHIFT_REGISTER_FABRIC_BITSTREAM_FWD_H
|
||||
|
||||
#include "vtr_strong_id.h"
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
/* Strong Ids for ModuleManager */
|
||||
struct memory_bank_shift_register_fabric_bitstream_word_id_tag;
|
||||
|
||||
typedef vtr::StrongId<memory_bank_shift_register_fabric_bitstream_word_id_tag> MemoryBankShiftRegisterFabricBitstreamWordId;
|
||||
|
||||
class MemoryBankShiftRegisterFabricBitstream;
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
#endif
|
|
@ -12,6 +12,7 @@
|
|||
#include "vtr_time.h"
|
||||
|
||||
/* Headers from openfpgautil library */
|
||||
#include "openfpga_decode.h"
|
||||
#include "openfpga_digest.h"
|
||||
#include "openfpga_version.h"
|
||||
|
||||
|
@ -180,6 +181,113 @@ int write_memory_bank_fabric_bitstream_to_text_file(std::fstream& fp,
|
|||
return status;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Write the fabric bitstream fitting a memory bank protocol
|
||||
* to a plain text file
|
||||
*
|
||||
* Return:
|
||||
* - 0 if succeed
|
||||
* - 1 if critical errors occured
|
||||
*******************************************************************/
|
||||
static
|
||||
int write_memory_bank_flatten_fabric_bitstream_to_text_file(std::fstream& fp,
|
||||
const bool& fast_configuration,
|
||||
const bool& bit_value_to_skip,
|
||||
const FabricBitstream& fabric_bitstream,
|
||||
const bool& keep_dont_care_bits) {
|
||||
int status = 0;
|
||||
|
||||
char dont_care_bit = '0';
|
||||
if (keep_dont_care_bits) {
|
||||
dont_care_bit = DONT_CARE_CHAR;
|
||||
}
|
||||
MemoryBankFlattenFabricBitstream fabric_bits = build_memory_bank_flatten_fabric_bitstream(fabric_bitstream, fast_configuration, bit_value_to_skip, dont_care_bit);
|
||||
|
||||
/* The address sizes and data input sizes are the same across any element,
|
||||
* just get it from the 1st element to save runtime
|
||||
*/
|
||||
size_t bl_addr_size = fabric_bits.bl_vector_size();
|
||||
size_t wl_addr_size = fabric_bits.wl_vector_size();
|
||||
|
||||
/* Output information about how to intepret the bitstream */
|
||||
fp << "// Bitstream length: " << fabric_bits.size() << std::endl;
|
||||
fp << "// Bitstream width (LSB -> MSB): ";
|
||||
fp << "<bl_address " << bl_addr_size << " bits>";
|
||||
fp << "<wl_address " << wl_addr_size << " bits>";
|
||||
fp << std::endl;
|
||||
|
||||
for (const auto& wl_vec : fabric_bits.wl_vectors()) {
|
||||
/* Write BL address code */
|
||||
for (const auto& bl_unit : fabric_bits.bl_vector(wl_vec)) {
|
||||
fp << bl_unit;
|
||||
}
|
||||
/* Write WL address code */
|
||||
for (const auto& wl_unit : wl_vec) {
|
||||
fp << wl_unit;
|
||||
}
|
||||
fp << std::endl;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Write the fabric bitstream fitting a memory bank protocol
|
||||
* to a plain text file
|
||||
*
|
||||
* Return:
|
||||
* - 0 if succeed
|
||||
* - 1 if critical errors occured
|
||||
*******************************************************************/
|
||||
static
|
||||
int write_memory_bank_shift_register_fabric_bitstream_to_text_file(std::fstream& fp,
|
||||
const bool& fast_configuration,
|
||||
const bool& bit_value_to_skip,
|
||||
const FabricBitstream& fabric_bitstream,
|
||||
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
|
||||
const bool& keep_dont_care_bits) {
|
||||
int status = 0;
|
||||
|
||||
char dont_care_bit = '0';
|
||||
if (keep_dont_care_bits) {
|
||||
dont_care_bit = DONT_CARE_CHAR;
|
||||
}
|
||||
MemoryBankShiftRegisterFabricBitstream fabric_bits = build_memory_bank_shift_register_fabric_bitstream(fabric_bitstream, blwl_sr_banks, fast_configuration, bit_value_to_skip, dont_care_bit);
|
||||
|
||||
/* Output information about how to intepret the bitstream */
|
||||
fp << "// Bitstream word count: " << fabric_bits.num_words() << std::endl;
|
||||
fp << "// Bitstream bl word size: " << fabric_bits.bl_word_size() << std::endl;
|
||||
fp << "// Bitstream wl word size: " << fabric_bits.wl_word_size() << std::endl;
|
||||
fp << "// Bitstream width (LSB -> MSB): ";
|
||||
fp << "<bl shift register heads " << fabric_bits.bl_width() << " bits>";
|
||||
fp << "<wl shift register heads " << fabric_bits.wl_width() << " bits>";
|
||||
fp << std::endl;
|
||||
|
||||
size_t word_cnt = 0;
|
||||
|
||||
for (const auto& word : fabric_bits.words()) {
|
||||
fp << "// Word " << word_cnt << std::endl;
|
||||
|
||||
/* Write BL address code */
|
||||
fp << "// BL part " << std::endl;
|
||||
for (const auto& bl_vec : fabric_bits.bl_vectors(word)) {
|
||||
fp << bl_vec;
|
||||
fp << std::endl;
|
||||
}
|
||||
|
||||
/* Write WL address code */
|
||||
fp << "// WL part " << std::endl;
|
||||
for (const auto& wl_vec : fabric_bits.wl_vectors(word)) {
|
||||
fp << wl_vec;
|
||||
fp << std::endl;
|
||||
}
|
||||
|
||||
word_cnt++;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Write the fabric bitstream fitting a frame-based protocol
|
||||
* to a plain text file
|
||||
|
@ -256,10 +364,12 @@ int write_frame_based_fabric_bitstream_to_text_file(std::fstream& fp,
|
|||
*******************************************************************/
|
||||
int write_fabric_bitstream_to_text_file(const BitstreamManager& bitstream_manager,
|
||||
const FabricBitstream& fabric_bitstream,
|
||||
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const FabricGlobalPortInfo& global_ports,
|
||||
const std::string& fname,
|
||||
const bool& fast_configuration,
|
||||
const bool& keep_dont_care_bits,
|
||||
const bool& verbose) {
|
||||
/* Ensure that we have a valid file name */
|
||||
if (true == fname.empty()) {
|
||||
|
@ -306,6 +416,36 @@ int write_fabric_bitstream_to_text_file(const BitstreamManager& bitstream_manage
|
|||
bitstream_manager,
|
||||
fabric_bitstream);
|
||||
break;
|
||||
case CONFIG_MEM_QL_MEMORY_BANK: {
|
||||
/* Bitstream organization depends on the BL/WL protocols
|
||||
* - If BL uses decoders, we have to config each memory cell one by one.
|
||||
* - If BL uses flatten, we can configure all the memory cells on the same row by enabling dedicated WL
|
||||
* In such case, we will merge the BL data under the same WL address
|
||||
* Fast configuration is applicable when a row of BLs are all zeros/ones while we have a global reset/set for all the memory cells
|
||||
* - if BL uses shift-register, same as the flatten.
|
||||
*/
|
||||
if (BLWL_PROTOCOL_DECODER == config_protocol.bl_protocol_type()) {
|
||||
status = write_memory_bank_fabric_bitstream_to_text_file(fp,
|
||||
apply_fast_configuration,
|
||||
bit_value_to_skip,
|
||||
fabric_bitstream);
|
||||
} else if (BLWL_PROTOCOL_FLATTEN == config_protocol.bl_protocol_type()) {
|
||||
status = write_memory_bank_flatten_fabric_bitstream_to_text_file(fp,
|
||||
apply_fast_configuration,
|
||||
bit_value_to_skip,
|
||||
fabric_bitstream,
|
||||
keep_dont_care_bits);
|
||||
} else {
|
||||
VTR_ASSERT(BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type());
|
||||
status = write_memory_bank_shift_register_fabric_bitstream_to_text_file(fp,
|
||||
apply_fast_configuration,
|
||||
bit_value_to_skip,
|
||||
fabric_bitstream,
|
||||
blwl_sr_banks,
|
||||
keep_dont_care_bits);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CONFIG_MEM_MEMORY_BANK:
|
||||
status = write_memory_bank_fabric_bitstream_to_text_file(fp,
|
||||
apply_fast_configuration,
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "bitstream_manager.h"
|
||||
#include "fabric_bitstream.h"
|
||||
#include "config_protocol.h"
|
||||
#include "memory_bank_shift_register_banks.h"
|
||||
#include "fabric_global_port_info.h"
|
||||
|
||||
/********************************************************************
|
||||
|
@ -20,10 +21,12 @@ namespace openfpga {
|
|||
|
||||
int write_fabric_bitstream_to_text_file(const BitstreamManager& bitstream_manager,
|
||||
const FabricBitstream& fabric_bitstream,
|
||||
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const FabricGlobalPortInfo& global_ports,
|
||||
const std::string& fname,
|
||||
const bool& fast_configuration,
|
||||
const bool& keep_dont_care_bits,
|
||||
const bool& verbose);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
|
|
@ -103,6 +103,7 @@ int write_fabric_config_bit_to_xml_file(std::fstream& fp,
|
|||
case CONFIG_MEM_STANDALONE:
|
||||
case CONFIG_MEM_SCAN_CHAIN:
|
||||
break;
|
||||
case CONFIG_MEM_QL_MEMORY_BANK:
|
||||
case CONFIG_MEM_MEMORY_BANK: {
|
||||
/* Bit line address */
|
||||
write_tab_to_file(fp, xml_hierarchy_depth + 1);
|
||||
|
|
|
@ -97,7 +97,7 @@ void print_pnr_sdc_global_clock_ports(std::fstream& fp,
|
|||
/* Should try to find a port defintion from simulation parameters
|
||||
* If found, it means that we need to use special clock name!
|
||||
*/
|
||||
for (const SimulationClockId& sim_clock : sim_setting.clocks()) {
|
||||
for (const SimulationClockId& sim_clock : sim_setting.operating_clocks()) {
|
||||
if (port_to_constrain == sim_setting.clock_port(sim_clock)) {
|
||||
clock_period = 1./sim_setting.clock_frequency(sim_clock);
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ namespace openfpga {
|
|||
********************************************************************/
|
||||
void fpga_fabric_verilog(ModuleManager &module_manager,
|
||||
NetlistManager &netlist_manager,
|
||||
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
|
||||
const CircuitLibrary &circuit_lib,
|
||||
const MuxLibrary &mux_lib,
|
||||
const DecoderLibrary &decoder_lib,
|
||||
|
@ -94,6 +95,7 @@ void fpga_fabric_verilog(ModuleManager &module_manager,
|
|||
* Without the modules in the module manager, core logic generation is not possible!!!
|
||||
*/
|
||||
print_verilog_submodule(module_manager, netlist_manager,
|
||||
blwl_sr_banks,
|
||||
mux_lib, decoder_lib, circuit_lib,
|
||||
submodule_dir_path,
|
||||
options);
|
||||
|
@ -147,6 +149,7 @@ void fpga_fabric_verilog(ModuleManager &module_manager,
|
|||
int fpga_verilog_full_testbench(const ModuleManager &module_manager,
|
||||
const BitstreamManager &bitstream_manager,
|
||||
const FabricBitstream &fabric_bitstream,
|
||||
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
|
||||
const AtomContext &atom_ctx,
|
||||
const PlacementContext &place_ctx,
|
||||
const PinConstraints& pin_constraints,
|
||||
|
@ -173,7 +176,7 @@ int fpga_verilog_full_testbench(const ModuleManager &module_manager,
|
|||
/* Generate full testbench for verification, including configuration phase and operating phase */
|
||||
std::string top_testbench_file_path = src_dir_path + netlist_name + std::string(AUTOCHECK_TOP_TESTBENCH_VERILOG_FILE_POSTFIX);
|
||||
print_verilog_full_testbench(module_manager,
|
||||
bitstream_manager, fabric_bitstream,
|
||||
bitstream_manager, fabric_bitstream, blwl_sr_banks,
|
||||
circuit_lib,
|
||||
config_protocol,
|
||||
fabric_global_port_info,
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "io_location_map.h"
|
||||
#include "fabric_global_port_info.h"
|
||||
#include "vpr_netlist_annotation.h"
|
||||
#include "memory_bank_shift_register_banks.h"
|
||||
#include "fabric_verilog_options.h"
|
||||
#include "verilog_testbench_options.h"
|
||||
|
||||
|
@ -35,6 +36,7 @@ namespace openfpga {
|
|||
|
||||
void fpga_fabric_verilog(ModuleManager& module_manager,
|
||||
NetlistManager& netlist_manager,
|
||||
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const MuxLibrary& mux_lib,
|
||||
const DecoderLibrary& decoder_lib,
|
||||
|
@ -46,6 +48,7 @@ void fpga_fabric_verilog(ModuleManager& module_manager,
|
|||
int fpga_verilog_full_testbench(const ModuleManager& module_manager,
|
||||
const BitstreamManager& bitstream_manager,
|
||||
const FabricBitstream& fabric_bitstream,
|
||||
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
|
||||
const AtomContext& atom_ctx,
|
||||
const PlacementContext& place_ctx,
|
||||
const PinConstraints& pin_constraints,
|
||||
|
|
|
@ -26,6 +26,7 @@ constexpr char* MUXES_VERILOG_FILE_NAME = "muxes.v";
|
|||
constexpr char* LOCAL_ENCODER_VERILOG_FILE_NAME = "local_encoder.v";
|
||||
constexpr char* ARCH_ENCODER_VERILOG_FILE_NAME = "arch_encoder.v";
|
||||
constexpr char* MEMORIES_VERILOG_FILE_NAME = "memories.v";
|
||||
constexpr char* SHIFT_REGISTER_BANKS_VERILOG_FILE_NAME = "shift_register_banks.v";
|
||||
constexpr char* WIRES_VERILOG_FILE_NAME = "wires.v";
|
||||
constexpr char* ESSENTIALS_VERILOG_FILE_NAME = "inv_buf_passgate.v";
|
||||
constexpr char* CONFIG_PERIPHERAL_VERILOG_FILE_NAME = "config_peripherals.v";
|
||||
|
|
|
@ -289,6 +289,20 @@ void print_verilog_arch_decoder_module(std::fstream& fp,
|
|||
data_inv_port = module_manager.module_port(module_id, data_inv_port_id);
|
||||
}
|
||||
|
||||
/* Find readback port */
|
||||
ModulePortId readback_port_id = module_manager.find_module_port(module_id, std::string(DECODER_READBACK_PORT_NAME));
|
||||
BasicPort readback_port;
|
||||
if (readback_port_id) {
|
||||
readback_port = module_manager.module_port(module_id, readback_port_id);
|
||||
}
|
||||
|
||||
/* Find data read-enable port */
|
||||
ModulePortId data_ren_port_id = module_manager.find_module_port(module_id, std::string(DECODER_DATA_READ_ENABLE_PORT_NAME));
|
||||
BasicPort data_ren_port;
|
||||
if (data_ren_port_id) {
|
||||
data_ren_port = module_manager.module_port(module_id, data_ren_port_id);
|
||||
}
|
||||
|
||||
/* dump module definition + ports */
|
||||
print_verilog_module_declaration(fp, module_manager, module_id, default_net_type);
|
||||
/* Finish dumping ports */
|
||||
|
@ -303,10 +317,18 @@ void print_verilog_arch_decoder_module(std::fstream& fp,
|
|||
* else data_out is driven by '0'
|
||||
*/
|
||||
if (1 == data_size) {
|
||||
/* Output logics for data output */
|
||||
fp << "always@(" << generate_verilog_port(VERILOG_PORT_CONKT, addr_port);
|
||||
fp << " or " << generate_verilog_port(VERILOG_PORT_CONKT, enable_port);
|
||||
/* If there is a readback port, the data output is only enabled when readback is disabled */
|
||||
if (readback_port_id) {
|
||||
fp << " or " << "~" << generate_verilog_port(VERILOG_PORT_CONKT, readback_port);
|
||||
}
|
||||
fp << ") begin" << std::endl;
|
||||
fp << "\tif ((" << generate_verilog_port(VERILOG_PORT_CONKT, enable_port) << " == 1'b1) && (";
|
||||
if (readback_port_id) {
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, readback_port) << " == 1'b0) && (";
|
||||
}
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, addr_port) << " == 1'b0))";
|
||||
fp << " begin" << std::endl;
|
||||
fp << "\t\t" << generate_verilog_port_constant_values(data_port, std::vector<size_t>(1, 1)) << ";" << std::endl;
|
||||
|
@ -315,6 +337,26 @@ void print_verilog_arch_decoder_module(std::fstream& fp,
|
|||
fp << "\t" << "end" << std::endl;
|
||||
fp << "end" << std::endl;
|
||||
|
||||
/* Output logics for data readback output */
|
||||
if (data_ren_port_id) {
|
||||
fp << "always@(" << generate_verilog_port(VERILOG_PORT_CONKT, addr_port);
|
||||
fp << " or " << generate_verilog_port(VERILOG_PORT_CONKT, enable_port);
|
||||
/* If there is a readback port, the data output is only enabled when readback is disabled */
|
||||
if (readback_port_id) {
|
||||
fp << " or " << generate_verilog_port(VERILOG_PORT_CONKT, readback_port);
|
||||
}
|
||||
fp << ") begin" << std::endl;
|
||||
fp << "\tif ((" << generate_verilog_port(VERILOG_PORT_CONKT, enable_port) << " == 1'b1) && (";
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, readback_port) << " == 1'b1) && (";
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, addr_port) << " == 1'b0))";
|
||||
fp << " begin" << std::endl;
|
||||
fp << "\t\t" << generate_verilog_port_constant_values(data_ren_port, std::vector<size_t>(1, 1)) << ";" << std::endl;
|
||||
fp << "\t" << "end else begin" << std::endl;
|
||||
fp << "\t\t" << generate_verilog_port_constant_values(data_ren_port, std::vector<size_t>(1, 0)) << ";" << std::endl;
|
||||
fp << "\t" << "end" << std::endl;
|
||||
fp << "end" << std::endl;
|
||||
}
|
||||
|
||||
/* Depend on if the inverted data output port is needed or not */
|
||||
if (true == decoder_lib.use_data_inv_port(decoder)) {
|
||||
print_verilog_wire_connection(fp, data_inv_port, addr_port, true);
|
||||
|
@ -344,10 +386,23 @@ void print_verilog_arch_decoder_module(std::fstream& fp,
|
|||
* The rest of addr codes 3'b110, 3'b111 will be decoded to data=8'b0_0000;
|
||||
*/
|
||||
|
||||
/* Output logics for data output */
|
||||
fp << "always@(" << generate_verilog_port(VERILOG_PORT_CONKT, addr_port);
|
||||
/* If there is a readback port, the data output is only enabled when readback is disabled */
|
||||
if (readback_port_id) {
|
||||
fp << " or " << "~" << generate_verilog_port(VERILOG_PORT_CONKT, readback_port);
|
||||
}
|
||||
fp << " or " << generate_verilog_port(VERILOG_PORT_CONKT, enable_port);
|
||||
fp << ") begin" << std::endl;
|
||||
fp << "\tif (" << generate_verilog_port(VERILOG_PORT_CONKT, enable_port) << " == 1'b1) begin" << std::endl;
|
||||
if (readback_port_id) {
|
||||
fp << "\tif (";
|
||||
fp << "(" << generate_verilog_port(VERILOG_PORT_CONKT, enable_port) << " == 1'b1) ";
|
||||
fp << "&&";
|
||||
fp << "(" << generate_verilog_port(VERILOG_PORT_CONKT, readback_port) << " == 1'b0) ";
|
||||
fp << ") begin" << std::endl;
|
||||
} else {
|
||||
fp << "\tif (" << generate_verilog_port(VERILOG_PORT_CONKT, enable_port) << " == 1'b1) begin" << std::endl;
|
||||
}
|
||||
fp << "\t\t" << "case (" << generate_verilog_port(VERILOG_PORT_CONKT, addr_port) << ")" << std::endl;
|
||||
/* Create a string for addr and data */
|
||||
for (size_t i = 0; i < data_size; ++i) {
|
||||
|
@ -373,6 +428,46 @@ void print_verilog_arch_decoder_module(std::fstream& fp,
|
|||
|
||||
fp << "end" << std::endl;
|
||||
|
||||
/* Output logics for data readback output */
|
||||
if (data_ren_port_id) {
|
||||
fp << "always@(" << generate_verilog_port(VERILOG_PORT_CONKT, addr_port);
|
||||
/* If there is a readback port, the data output is only enabled when readback is disabled */
|
||||
if (readback_port_id) {
|
||||
fp << " or " << generate_verilog_port(VERILOG_PORT_CONKT, readback_port);
|
||||
}
|
||||
fp << " or " << generate_verilog_port(VERILOG_PORT_CONKT, enable_port);
|
||||
fp << ") begin" << std::endl;
|
||||
fp << "\tif (";
|
||||
fp << "(" << generate_verilog_port(VERILOG_PORT_CONKT, enable_port) << " == 1'b1) ";
|
||||
fp << "&&";
|
||||
fp << "(" << generate_verilog_port(VERILOG_PORT_CONKT, readback_port) << " == 1'b1) ";
|
||||
fp << ") begin" << std::endl;
|
||||
fp << "\t\t" << "case (" << generate_verilog_port(VERILOG_PORT_CONKT, addr_port) << ")" << std::endl;
|
||||
/* Create a string for addr and data */
|
||||
for (size_t i = 0; i < data_size; ++i) {
|
||||
fp << "\t\t\t" << generate_verilog_constant_values(itobin_vec(i, addr_size));
|
||||
fp << " : ";
|
||||
fp << generate_verilog_port_constant_values(data_ren_port, ito1hot_vec(i, data_size));
|
||||
fp << ";" << std::endl;
|
||||
}
|
||||
/* Different from MUX decoder, we assign default values which is all zero */
|
||||
fp << "\t\t\t" << "default";
|
||||
fp << " : ";
|
||||
fp << generate_verilog_port_constant_values(data_ren_port, ito1hot_vec(data_size, data_size));
|
||||
fp << ";" << std::endl;
|
||||
|
||||
fp << "\t\t" << "endcase" << std::endl;
|
||||
fp << "\t" << "end" << std::endl;
|
||||
|
||||
/* If enable is not active, we should give all zero */
|
||||
fp << "\t" << "else begin" << std::endl;
|
||||
fp << "\t\t" << generate_verilog_port_constant_values(data_ren_port, ito1hot_vec(data_size, data_size));
|
||||
fp << ";" << std::endl;
|
||||
fp << "\t" << "end" << std::endl;
|
||||
|
||||
fp << "end" << std::endl;
|
||||
}
|
||||
|
||||
if (true == decoder_lib.use_data_inv_port(decoder)) {
|
||||
print_verilog_wire_connection(fp, data_inv_port, data_port, true);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
/*********************************************************************
|
||||
* This file includes functions to generate Verilog submodules for
|
||||
* the memories that are affiliated to multiplexers and other programmable
|
||||
* circuit models, such as IOPADs, LUTs, etc.
|
||||
********************************************************************/
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
/* Headers from vtrutil library */
|
||||
#include "vtr_assert.h"
|
||||
#include "vtr_log.h"
|
||||
|
||||
/* Headers from openfpgautil library */
|
||||
#include "openfpga_digest.h"
|
||||
|
||||
#include "mux_graph.h"
|
||||
#include "module_manager.h"
|
||||
#include "circuit_library_utils.h"
|
||||
#include "mux_utils.h"
|
||||
|
||||
#include "openfpga_naming.h"
|
||||
|
||||
#include "verilog_constants.h"
|
||||
#include "verilog_writer_utils.h"
|
||||
#include "verilog_module_writer.h"
|
||||
#include "verilog_shift_register_banks.h"
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
/*********************************************************************
|
||||
* Generate Verilog modules for
|
||||
* the shift register banks that are used to control BL/WLs
|
||||
********************************************************************/
|
||||
void print_verilog_submodule_shift_register_banks(const ModuleManager& module_manager,
|
||||
NetlistManager& netlist_manager,
|
||||
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
|
||||
const std::string& submodule_dir,
|
||||
const FabricVerilogOption& options) {
|
||||
|
||||
/* Plug in with the mux subckt */
|
||||
std::string verilog_fname(submodule_dir + std::string(SHIFT_REGISTER_BANKS_VERILOG_FILE_NAME));
|
||||
|
||||
/* Create the file stream */
|
||||
std::fstream fp;
|
||||
fp.open(verilog_fname, std::fstream::out | std::fstream::trunc);
|
||||
|
||||
check_file_stream(verilog_fname.c_str(), fp);
|
||||
|
||||
/* Print out debugging information for if the file is not opened/created properly */
|
||||
VTR_LOG("Writing Verilog netlist for shift register banks '%s' ...",
|
||||
verilog_fname.c_str());
|
||||
|
||||
print_verilog_file_header(fp, "Shift register banks used in FPGA");
|
||||
|
||||
/* Create the memory circuits for the multiplexer */
|
||||
for (const ModuleId& sr_module : blwl_sr_banks.bl_bank_unique_modules()) {
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(sr_module));
|
||||
/* Write the module content in Verilog format */
|
||||
write_verilog_module_to_file(fp, module_manager, sr_module,
|
||||
options.explicit_port_mapping(),
|
||||
options.default_net_type());
|
||||
|
||||
/* Add an empty line as a splitter */
|
||||
fp << std::endl;
|
||||
}
|
||||
|
||||
for (const ModuleId& sr_module : blwl_sr_banks.wl_bank_unique_modules()) {
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(sr_module));
|
||||
/* Write the module content in Verilog format */
|
||||
write_verilog_module_to_file(fp, module_manager, sr_module,
|
||||
options.explicit_port_mapping(),
|
||||
options.default_net_type());
|
||||
|
||||
/* Add an empty line as a splitter */
|
||||
fp << std::endl;
|
||||
}
|
||||
|
||||
/* Close the file stream */
|
||||
fp.close();
|
||||
|
||||
/* Add fname to the netlist name list */
|
||||
NetlistId nlist_id = netlist_manager.add_netlist(verilog_fname);
|
||||
VTR_ASSERT(NetlistId::INVALID() != nlist_id);
|
||||
netlist_manager.set_netlist_type(nlist_id, NetlistManager::SUBMODULE_NETLIST);
|
||||
|
||||
VTR_LOG("Done\n");
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
|
@ -0,0 +1,29 @@
|
|||
#ifndef VERILOG_SHIFT_REGISTER_BANKS_H
|
||||
#define VERILOG_SHIFT_REGISTER_BANKS_H
|
||||
|
||||
/********************************************************************
|
||||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
#include <fstream>
|
||||
|
||||
#include "memory_bank_shift_register_banks.h"
|
||||
#include "module_manager.h"
|
||||
#include "netlist_manager.h"
|
||||
#include "fabric_verilog_options.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
*******************************************************************/
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
void print_verilog_submodule_shift_register_banks(const ModuleManager& module_manager,
|
||||
NetlistManager& netlist_manager,
|
||||
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
|
||||
const std::string& submodule_dir,
|
||||
const FabricVerilogOption& options);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
#endif
|
|
@ -14,6 +14,7 @@
|
|||
#include "verilog_lut.h"
|
||||
#include "verilog_wire.h"
|
||||
#include "verilog_memory.h"
|
||||
#include "verilog_shift_register_banks.h"
|
||||
#include "verilog_writer_utils.h"
|
||||
|
||||
#include "verilog_constants.h"
|
||||
|
@ -33,6 +34,7 @@ namespace openfpga {
|
|||
********************************************************************/
|
||||
void print_verilog_submodule(ModuleManager& module_manager,
|
||||
NetlistManager& netlist_manager,
|
||||
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
|
||||
const MuxLibrary& mux_lib,
|
||||
const DecoderLibrary& decoder_lib,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
|
@ -84,14 +86,22 @@ void print_verilog_submodule(ModuleManager& module_manager,
|
|||
submodule_dir,
|
||||
fpga_verilog_opts.default_net_type());
|
||||
|
||||
/* 4. Memories */
|
||||
/* Memories */
|
||||
print_verilog_submodule_memories(const_cast<const ModuleManager&>(module_manager),
|
||||
netlist_manager,
|
||||
mux_lib, circuit_lib,
|
||||
submodule_dir,
|
||||
fpga_verilog_opts);
|
||||
|
||||
/* 5. Dump template for all the modules */
|
||||
/* Shift register banks */
|
||||
print_verilog_submodule_shift_register_banks(const_cast<const ModuleManager&>(module_manager),
|
||||
netlist_manager,
|
||||
blwl_sr_banks,
|
||||
submodule_dir,
|
||||
fpga_verilog_opts);
|
||||
|
||||
|
||||
/* Dump template for all the modules */
|
||||
if (true == fpga_verilog_opts.print_user_defined_template()) {
|
||||
print_verilog_submodule_templates(const_cast<const ModuleManager&>(module_manager),
|
||||
circuit_lib,
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "netlist_manager.h"
|
||||
#include "mux_library.h"
|
||||
#include "decoder_library.h"
|
||||
#include "memory_bank_shift_register_banks.h"
|
||||
#include "fabric_verilog_options.h"
|
||||
|
||||
/********************************************************************
|
||||
|
@ -19,6 +20,7 @@ namespace openfpga {
|
|||
|
||||
void print_verilog_submodule(ModuleManager& module_manager,
|
||||
NetlistManager& netlist_manager,
|
||||
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
|
||||
const MuxLibrary& mux_lib,
|
||||
const DecoderLibrary& decoder_lib,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
|
|
|
@ -515,7 +515,7 @@ void print_verilog_testbench_clock_stimuli(std::fstream& fp,
|
|||
/* Skip all the unrelated pin constraints */
|
||||
VTR_ASSERT(clock_port.get_name() == pin_constraints.net(pin_constraint));
|
||||
/* Try to find which clock source is considered in simulation settings for this pin */
|
||||
for (const SimulationClockId& sim_clock_id : simulation_parameters.clocks()) {
|
||||
for (const SimulationClockId& sim_clock_id : simulation_parameters.operating_clocks()) {
|
||||
if (pin_constraints.pin(pin_constraint) == simulation_parameters.clock_port(sim_clock_id)) {
|
||||
clk_freq_to_use = (0.5 / simulation_parameters.clock_frequency(sim_clock_id)) / VERILOG_SIM_TIMESCALE;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
#include "vtr_assert.h"
|
||||
#include "vtr_time.h"
|
||||
|
||||
/* Headers from openfpgashell library */
|
||||
#include "command_exit_codes.h"
|
||||
|
||||
/* Headers from openfpgautil library */
|
||||
#include "openfpga_port.h"
|
||||
#include "openfpga_digest.h"
|
||||
|
@ -29,46 +32,14 @@
|
|||
#include "verilog_constants.h"
|
||||
#include "verilog_writer_utils.h"
|
||||
#include "verilog_testbench_utils.h"
|
||||
#include "verilog_top_testbench_memory_bank.h"
|
||||
#include "verilog_top_testbench.h"
|
||||
|
||||
#include "verilog_top_testbench_constants.h"
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
/********************************************************************
|
||||
* Local variables used only in this file
|
||||
*******************************************************************/
|
||||
constexpr char* TOP_TESTBENCH_REFERENCE_INSTANCE_NAME = "REF_DUT";
|
||||
constexpr char* TOP_TESTBENCH_FPGA_INSTANCE_NAME = "FPGA_DUT";
|
||||
constexpr char* TOP_TESTBENCH_REFERENCE_OUTPUT_POSTFIX = "_benchmark";
|
||||
constexpr char* TOP_TESTBENCH_FPGA_OUTPUT_POSTFIX = "_fpga";
|
||||
|
||||
constexpr char* TOP_TESTBENCH_CHECKFLAG_PORT_POSTFIX = "_flag";
|
||||
|
||||
constexpr char* TOP_TESTBENCH_PROG_TASK_NAME = "prog_cycle_task";
|
||||
|
||||
constexpr char* TOP_TESTBENCH_SIM_START_PORT_NAME = "sim_start";
|
||||
|
||||
constexpr char* TOP_TESTBENCH_ERROR_COUNTER = "nb_error";
|
||||
|
||||
constexpr char* TOP_TB_RESET_PORT_NAME = "greset";
|
||||
constexpr char* TOP_TB_SET_PORT_NAME = "gset";
|
||||
constexpr char* TOP_TB_PROG_RESET_PORT_NAME = "prog_reset";
|
||||
constexpr char* TOP_TB_PROG_SET_PORT_NAME = "prog_set";
|
||||
constexpr char* TOP_TB_CONFIG_DONE_PORT_NAME = "config_done";
|
||||
constexpr char* TOP_TB_OP_CLOCK_PORT_NAME = "op_clock";
|
||||
constexpr char* TOP_TB_OP_CLOCK_PORT_PREFIX = "operating_clk_";
|
||||
constexpr char* TOP_TB_PROG_CLOCK_PORT_NAME = "prog_clock";
|
||||
constexpr char* TOP_TB_INOUT_REG_POSTFIX = "_reg";
|
||||
constexpr char* TOP_TB_CLOCK_REG_POSTFIX = "_reg";
|
||||
constexpr char* TOP_TB_BITSTREAM_LENGTH_VARIABLE = "BITSTREAM_LENGTH";
|
||||
constexpr char* TOP_TB_BITSTREAM_WIDTH_VARIABLE = "BITSTREAM_WIDTH";
|
||||
constexpr char* TOP_TB_BITSTREAM_MEM_REG_NAME = "bit_mem";
|
||||
constexpr char* TOP_TB_BITSTREAM_INDEX_REG_NAME = "bit_index";
|
||||
constexpr char* TOP_TB_BITSTREAM_ITERATOR_REG_NAME = "ibit";
|
||||
constexpr char* TOP_TB_BITSTREAM_SKIP_FLAG_REG_NAME = "skip_bits";
|
||||
|
||||
constexpr char* AUTOCHECK_TOP_TESTBENCH_VERILOG_MODULE_POSTFIX = "_autocheck_top_tb";
|
||||
|
||||
/********************************************************************
|
||||
* Generate a simulation clock port name
|
||||
* This function is designed to produce a uniform clock naming for these ports
|
||||
|
@ -160,6 +131,17 @@ void print_verilog_top_testbench_memory_bank_port(std::fstream& fp,
|
|||
BasicPort din_port = module_manager.module_port(top_module, din_port_id);
|
||||
fp << generate_verilog_port(VERILOG_PORT_REG, din_port) << ";" << std::endl;
|
||||
|
||||
/* Print the optional readback port for the decoder here */
|
||||
print_verilog_comment(fp, std::string("---- Readback port for memory decoders -----"));
|
||||
ModulePortId readback_port_id = module_manager.find_module_port(top_module,
|
||||
std::string(DECODER_READBACK_PORT_NAME));
|
||||
if (readback_port_id) {
|
||||
BasicPort readback_port = module_manager.module_port(top_module, readback_port_id);
|
||||
fp << generate_verilog_port(VERILOG_PORT_WIRE, readback_port) << ";" << std::endl;
|
||||
/* Disable readback in full testbenches */
|
||||
print_verilog_wire_constant_values(fp, readback_port, std::vector<size_t>(readback_port.get_width(), 0));
|
||||
}
|
||||
|
||||
/* Generate enable signal waveform here:
|
||||
* which is a 90 degree phase shift than the programming clock
|
||||
*/
|
||||
|
@ -249,6 +231,9 @@ void print_verilog_top_testbench_config_protocol_port(std::fstream& fp,
|
|||
case CONFIG_MEM_SCAN_CHAIN:
|
||||
print_verilog_top_testbench_config_chain_port(fp, module_manager, top_module);
|
||||
break;
|
||||
case CONFIG_MEM_QL_MEMORY_BANK:
|
||||
print_verilog_top_testbench_ql_memory_bank_port(fp, module_manager, top_module, config_protocol);
|
||||
break;
|
||||
case CONFIG_MEM_MEMORY_BANK:
|
||||
print_verilog_top_testbench_memory_bank_port(fp, module_manager, top_module);
|
||||
break;
|
||||
|
@ -289,6 +274,11 @@ void print_verilog_top_testbench_global_clock_ports_stimuli(std::fstream& fp,
|
|||
/* Find the module port */
|
||||
ModulePortId module_global_port = fabric_global_port_info.global_module_port(fabric_global_port);
|
||||
VTR_ASSERT(true == module_manager.valid_module_port_id(top_module, module_global_port));
|
||||
|
||||
/* Skip shift register clocks, they are handled in another way */
|
||||
if (true == fabric_global_port_info.global_port_is_shift_register(fabric_global_port)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BasicPort stimuli_clock_port;
|
||||
if (true == fabric_global_port_info.global_port_is_prog(fabric_global_port)) {
|
||||
|
@ -308,7 +298,7 @@ void print_verilog_top_testbench_global_clock_ports_stimuli(std::fstream& fp,
|
|||
/* Should try to find a port defintion from simulation parameters
|
||||
* If found, it means that we need to use special clock name!
|
||||
*/
|
||||
for (const SimulationClockId& sim_clock : simulation_parameters.clocks()) {
|
||||
for (const SimulationClockId& sim_clock : simulation_parameters.operating_clocks()) {
|
||||
if (global_port_to_connect == simulation_parameters.clock_port(sim_clock)) {
|
||||
stimuli_clock_port.set_name(generate_top_testbench_clock_name(std::string(TOP_TB_OP_CLOCK_PORT_PREFIX), simulation_parameters.clock_name(sim_clock)));
|
||||
}
|
||||
|
@ -581,6 +571,11 @@ void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp,
|
|||
fabric_global_port_info,
|
||||
simulation_parameters);
|
||||
|
||||
print_verilog_top_testbench_global_shift_register_clock_ports_stimuli(fp,
|
||||
module_manager,
|
||||
top_module,
|
||||
fabric_global_port_info);
|
||||
|
||||
print_verilog_top_testbench_global_config_done_ports_stimuli(fp,
|
||||
module_manager,
|
||||
top_module,
|
||||
|
@ -658,7 +653,7 @@ void print_verilog_top_testbench_benchmark_clock_ports(std::fstream& fp,
|
|||
/* Skip all the unrelated pin constraints */
|
||||
VTR_ASSERT(clock_port_name == pin_constraints.net(pin_constraint));
|
||||
/* Try to find which clock source is considered in simulation settings for this pin */
|
||||
for (const SimulationClockId& sim_clock_id : simulation_parameters.clocks()) {
|
||||
for (const SimulationClockId& sim_clock_id : simulation_parameters.operating_clocks()) {
|
||||
if (pin_constraints.pin(pin_constraint) == simulation_parameters.clock_port(sim_clock_id)) {
|
||||
std::string sim_clock_port_name = generate_top_testbench_clock_name(std::string(TOP_TB_OP_CLOCK_PORT_PREFIX), simulation_parameters.clock_name(sim_clock_id));
|
||||
clock_source_to_connect = BasicPort(sim_clock_port_name, 1);
|
||||
|
@ -760,7 +755,7 @@ void print_verilog_top_testbench_ports(std::fstream& fp,
|
|||
fp << generate_verilog_port(VERILOG_PORT_REG, prog_clock_register_port) << ";" << std::endl;
|
||||
|
||||
/* Multiple operating clocks based on the simulation settings */
|
||||
for (const SimulationClockId& sim_clock : simulation_parameters.clocks()) {
|
||||
for (const SimulationClockId& sim_clock : simulation_parameters.operating_clocks()) {
|
||||
std::string sim_clock_port_name = generate_top_testbench_clock_name(std::string(TOP_TB_OP_CLOCK_PORT_PREFIX), simulation_parameters.clock_name(sim_clock));
|
||||
BasicPort sim_clock_port(sim_clock_port_name, 1);
|
||||
fp << generate_verilog_port(VERILOG_PORT_WIRE, sim_clock_port) << ";" << std::endl;
|
||||
|
@ -828,7 +823,7 @@ void print_verilog_top_testbench_ports(std::fstream& fp,
|
|||
* Note that this will not applicable to configuration chain!!!
|
||||
*******************************************************************/
|
||||
static
|
||||
size_t calculate_num_config_clock_cycles(const e_config_protocol_type& sram_orgz_type,
|
||||
size_t calculate_num_config_clock_cycles(const ConfigProtocol& config_protocol,
|
||||
const bool& fast_configuration,
|
||||
const bool& bit_value_to_skip,
|
||||
const BitstreamManager& bitstream_manager,
|
||||
|
@ -839,7 +834,7 @@ size_t calculate_num_config_clock_cycles(const e_config_protocol_type& sram_orgz
|
|||
size_t num_config_clock_cycles = 1 + regional_bitstream_max_size;
|
||||
|
||||
/* Branch on the type of configuration protocol */
|
||||
switch (sram_orgz_type) {
|
||||
switch (config_protocol.type()) {
|
||||
case CONFIG_MEM_STANDALONE:
|
||||
/* We just need 1 clock cycle to load all the configuration bits
|
||||
* since all the ports are exposed at the top-level
|
||||
|
@ -867,6 +862,25 @@ size_t calculate_num_config_clock_cycles(const e_config_protocol_type& sram_orgz
|
|||
100. * ((float)num_config_clock_cycles / (float)(1 + regional_bitstream_max_size) - 1.));
|
||||
}
|
||||
break;
|
||||
case CONFIG_MEM_QL_MEMORY_BANK: {
|
||||
if (BLWL_PROTOCOL_DECODER == config_protocol.bl_protocol_type()) {
|
||||
/* For fast configuration, we will skip all the zero data points */
|
||||
num_config_clock_cycles = 1 + build_memory_bank_fabric_bitstream_by_address(fabric_bitstream).size();
|
||||
if (true == fast_configuration) {
|
||||
size_t full_num_config_clock_cycles = num_config_clock_cycles;
|
||||
num_config_clock_cycles = 1 + find_memory_bank_fast_configuration_fabric_bitstream_size(fabric_bitstream, bit_value_to_skip);
|
||||
VTR_LOG("Fast configuration reduces number of configuration clock cycles from %lu to %lu (compression_rate = %f%)\n",
|
||||
full_num_config_clock_cycles,
|
||||
num_config_clock_cycles,
|
||||
100. * ((float)num_config_clock_cycles / (float)full_num_config_clock_cycles - 1.));
|
||||
}
|
||||
} else if (BLWL_PROTOCOL_FLATTEN == config_protocol.bl_protocol_type()) {
|
||||
num_config_clock_cycles = 1 + build_memory_bank_flatten_fabric_bitstream(fabric_bitstream, fast_configuration, bit_value_to_skip).size();
|
||||
} else if (BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type()) {
|
||||
num_config_clock_cycles = 1 + build_memory_bank_flatten_fabric_bitstream(fabric_bitstream, fast_configuration, bit_value_to_skip).size();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CONFIG_MEM_MEMORY_BANK: {
|
||||
/* For fast configuration, we will skip all the zero data points */
|
||||
num_config_clock_cycles = 1 + build_memory_bank_fabric_bitstream_by_address(fabric_bitstream).size();
|
||||
|
@ -1009,7 +1023,7 @@ void print_verilog_top_testbench_generic_stimulus(std::fstream& fp,
|
|||
fp << std::endl;
|
||||
|
||||
/* Generate stimuli waveform for multiple user-defined operating clock signals */
|
||||
for (const SimulationClockId& sim_clock : simulation_parameters.clocks()) {
|
||||
for (const SimulationClockId& sim_clock : simulation_parameters.operating_clocks()) {
|
||||
print_verilog_comment(fp, "----- Begin raw operating clock signal '" + simulation_parameters.clock_name(sim_clock) + "' generation -----");
|
||||
std::string sim_clock_port_name = generate_top_testbench_clock_name(std::string(TOP_TB_OP_CLOCK_PORT_PREFIX), simulation_parameters.clock_name(sim_clock));
|
||||
BasicPort sim_clock_port(sim_clock_port_name, 1);
|
||||
|
@ -1110,26 +1124,42 @@ void print_verilog_top_testbench_generic_stimulus(std::fstream& fp,
|
|||
* 1. the enable signal
|
||||
*******************************************************************/
|
||||
static
|
||||
void print_verilog_top_testbench_configuration_protocol_stimulus(std::fstream& fp,
|
||||
const e_config_protocol_type& config_protocol_type,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const float& prog_clock_period,
|
||||
const float& timescale) {
|
||||
int print_verilog_top_testbench_configuration_protocol_stimulus(std::fstream& fp,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const SimulationSetting& sim_settings,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const bool& fast_configuration,
|
||||
const bool& bit_value_to_skip,
|
||||
const FabricBitstream& fabric_bitstream,
|
||||
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
|
||||
const float& prog_clock_period,
|
||||
const float& timescale) {
|
||||
/* Validate the file stream */
|
||||
valid_file_stream(fp);
|
||||
|
||||
/* Branch on the type of configuration protocol */
|
||||
switch (config_protocol_type) {
|
||||
switch (config_protocol.type()) {
|
||||
case CONFIG_MEM_STANDALONE:
|
||||
break;
|
||||
case CONFIG_MEM_SCAN_CHAIN:
|
||||
break;
|
||||
case CONFIG_MEM_QL_MEMORY_BANK:
|
||||
return print_verilog_top_testbench_configuration_protocol_ql_memory_bank_stimulus(fp,
|
||||
config_protocol, sim_settings,
|
||||
module_manager, top_module,
|
||||
fast_configuration, bit_value_to_skip,
|
||||
fabric_bitstream, blwl_sr_banks,
|
||||
prog_clock_period, timescale);
|
||||
break;
|
||||
case CONFIG_MEM_MEMORY_BANK:
|
||||
case CONFIG_MEM_FRAME_BASED: {
|
||||
ModulePortId en_port_id = module_manager.find_module_port(top_module,
|
||||
std::string(DECODER_ENABLE_PORT_NAME));
|
||||
BasicPort en_port = module_manager.module_port(top_module, en_port_id);
|
||||
BasicPort en_port(std::string(DECODER_ENABLE_PORT_NAME), 1);
|
||||
if (en_port_id) {
|
||||
en_port = module_manager.module_port(top_module, en_port_id);
|
||||
}
|
||||
BasicPort en_register_port(std::string(en_port.get_name() + std::string(TOP_TB_CLOCK_REG_POSTFIX)), 1);
|
||||
print_verilog_comment(fp, std::string("---- Generate enable signal waveform -----"));
|
||||
print_verilog_shifted_clock_stimuli(fp, en_register_port,
|
||||
|
@ -1142,6 +1172,8 @@ void print_verilog_top_testbench_configuration_protocol_stimulus(std::fstream& f
|
|||
"Invalid SRAM organization type!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return CMD_EXEC_SUCCESS;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
|
@ -1702,16 +1734,17 @@ void print_verilog_full_testbench_frame_decoder_bitstream(std::fstream& fp,
|
|||
static
|
||||
void print_verilog_full_testbench_bitstream(std::fstream& fp,
|
||||
const std::string& bitstream_file,
|
||||
const e_config_protocol_type& config_protocol_type,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const bool& fast_configuration,
|
||||
const bool& bit_value_to_skip,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const BitstreamManager& bitstream_manager,
|
||||
const FabricBitstream& fabric_bitstream) {
|
||||
const FabricBitstream& fabric_bitstream,
|
||||
const MemoryBankShiftRegisterBanks& blwl_sr_banks) {
|
||||
|
||||
/* Branch on the type of configuration protocol */
|
||||
switch (config_protocol_type) {
|
||||
switch (config_protocol.type()) {
|
||||
case CONFIG_MEM_STANDALONE:
|
||||
print_verilog_full_testbench_vanilla_bitstream(fp,
|
||||
bitstream_file,
|
||||
|
@ -1735,6 +1768,14 @@ void print_verilog_full_testbench_bitstream(std::fstream& fp,
|
|||
module_manager, top_module,
|
||||
fabric_bitstream);
|
||||
break;
|
||||
case CONFIG_MEM_QL_MEMORY_BANK:
|
||||
print_verilog_full_testbench_ql_memory_bank_bitstream(fp, bitstream_file,
|
||||
config_protocol,
|
||||
fast_configuration,
|
||||
bit_value_to_skip,
|
||||
module_manager, top_module,
|
||||
fabric_bitstream, blwl_sr_banks);
|
||||
break;
|
||||
case CONFIG_MEM_FRAME_BASED:
|
||||
print_verilog_full_testbench_frame_decoder_bitstream(fp, bitstream_file,
|
||||
fast_configuration,
|
||||
|
@ -1855,6 +1896,7 @@ void print_verilog_top_testbench_check(std::fstream& fp,
|
|||
int print_verilog_full_testbench(const ModuleManager& module_manager,
|
||||
const BitstreamManager& bitstream_manager,
|
||||
const FabricBitstream& fabric_bitstream,
|
||||
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const FabricGlobalPortInfo& global_ports,
|
||||
|
@ -1922,12 +1964,12 @@ int print_verilog_full_testbench(const ModuleManager& module_manager,
|
|||
float prog_clock_period = (1./simulation_parameters.programming_clock_frequency());
|
||||
float default_op_clock_period = (1./simulation_parameters.default_operating_clock_frequency());
|
||||
float max_op_clock_period = 0.;
|
||||
for (const SimulationClockId& clock_id : simulation_parameters.clocks()) {
|
||||
for (const SimulationClockId& clock_id : simulation_parameters.operating_clocks()) {
|
||||
max_op_clock_period = std::max(max_op_clock_period, (float)(1./simulation_parameters.clock_frequency(clock_id)));
|
||||
}
|
||||
|
||||
/* Estimate the number of configuration clock cycles */
|
||||
size_t num_config_clock_cycles = calculate_num_config_clock_cycles(config_protocol.type(),
|
||||
size_t num_config_clock_cycles = calculate_num_config_clock_cycles(config_protocol,
|
||||
apply_fast_configuration,
|
||||
bit_value_to_skip,
|
||||
bitstream_manager,
|
||||
|
@ -1942,11 +1984,18 @@ int print_verilog_full_testbench(const ModuleManager& module_manager,
|
|||
VERILOG_SIM_TIMESCALE);
|
||||
|
||||
/* Generate stimuli for programming interface */
|
||||
print_verilog_top_testbench_configuration_protocol_stimulus(fp,
|
||||
config_protocol.type(),
|
||||
module_manager, top_module,
|
||||
prog_clock_period,
|
||||
VERILOG_SIM_TIMESCALE);
|
||||
int status = CMD_EXEC_SUCCESS;
|
||||
status = print_verilog_top_testbench_configuration_protocol_stimulus(fp,
|
||||
config_protocol, simulation_parameters,
|
||||
module_manager, top_module,
|
||||
fast_configuration, bit_value_to_skip,
|
||||
fabric_bitstream, blwl_sr_banks,
|
||||
prog_clock_period,
|
||||
VERILOG_SIM_TIMESCALE);
|
||||
|
||||
if (status == CMD_EXEC_FATAL_ERROR) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Identify the stimulus for global reset/set for programming purpose:
|
||||
* - If only reset port is seen we turn on Reset
|
||||
|
@ -2009,11 +2058,11 @@ int print_verilog_full_testbench(const ModuleManager& module_manager,
|
|||
/* load bitstream to FPGA fabric in a configuration phase */
|
||||
print_verilog_full_testbench_bitstream(fp,
|
||||
bitstream_file,
|
||||
config_protocol.type(),
|
||||
config_protocol,
|
||||
apply_fast_configuration,
|
||||
bit_value_to_skip,
|
||||
module_manager, top_module,
|
||||
bitstream_manager, fabric_bitstream);
|
||||
bitstream_manager, fabric_bitstream, blwl_sr_banks);
|
||||
|
||||
/* Add signal initialization:
|
||||
* Bypass writing codes to files due to the autogenerated codes are very large.
|
||||
|
@ -2091,7 +2140,7 @@ int print_verilog_full_testbench(const ModuleManager& module_manager,
|
|||
/* Close the file stream */
|
||||
fp.close();
|
||||
|
||||
return 0;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "fabric_global_port_info.h"
|
||||
#include "vpr_netlist_annotation.h"
|
||||
#include "simulation_setting.h"
|
||||
#include "memory_bank_shift_register_banks.h"
|
||||
#include "verilog_testbench_options.h"
|
||||
|
||||
/********************************************************************
|
||||
|
@ -29,6 +30,7 @@ namespace openfpga {
|
|||
int print_verilog_full_testbench(const ModuleManager& module_manager,
|
||||
const BitstreamManager& bitstream_manager,
|
||||
const FabricBitstream& fabric_bitstream,
|
||||
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const FabricGlobalPortInfo& global_ports,
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
#ifndef VERILOG_TOP_TESTBENCH_CONSTANTS
|
||||
#define VERILOG_TOP_TESTBENCH_CONSTANTS
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
constexpr char* TOP_TESTBENCH_REFERENCE_INSTANCE_NAME = "REF_DUT";
|
||||
constexpr char* TOP_TESTBENCH_FPGA_INSTANCE_NAME = "FPGA_DUT";
|
||||
constexpr char* TOP_TESTBENCH_REFERENCE_OUTPUT_POSTFIX = "_benchmark";
|
||||
constexpr char* TOP_TESTBENCH_FPGA_OUTPUT_POSTFIX = "_fpga";
|
||||
|
||||
constexpr char* TOP_TESTBENCH_CHECKFLAG_PORT_POSTFIX = "_flag";
|
||||
|
||||
constexpr char* TOP_TESTBENCH_PROG_TASK_NAME = "prog_cycle_task";
|
||||
|
||||
constexpr char* TOP_TESTBENCH_SIM_START_PORT_NAME = "sim_start";
|
||||
|
||||
constexpr char* TOP_TESTBENCH_ERROR_COUNTER = "nb_error";
|
||||
|
||||
constexpr char* TOP_TB_RESET_PORT_NAME = "greset";
|
||||
constexpr char* TOP_TB_SET_PORT_NAME = "gset";
|
||||
constexpr char* TOP_TB_PROG_RESET_PORT_NAME = "prog_reset";
|
||||
constexpr char* TOP_TB_PROG_SET_PORT_NAME = "prog_set";
|
||||
constexpr char* TOP_TB_CONFIG_DONE_PORT_NAME = "config_done";
|
||||
constexpr char* TOP_TB_OP_CLOCK_PORT_NAME = "op_clock";
|
||||
constexpr char* TOP_TB_OP_CLOCK_PORT_PREFIX = "operating_clk_";
|
||||
constexpr char* TOP_TB_PROG_CLOCK_PORT_NAME = "prog_clock";
|
||||
constexpr char* TOP_TB_INOUT_REG_POSTFIX = "_reg";
|
||||
constexpr char* TOP_TB_CLOCK_REG_POSTFIX = "_reg";
|
||||
constexpr char* TOP_TB_BITSTREAM_LENGTH_VARIABLE = "BITSTREAM_LENGTH";
|
||||
constexpr char* TOP_TB_BITSTREAM_WIDTH_VARIABLE = "BITSTREAM_WIDTH";
|
||||
constexpr char* TOP_TB_BITSTREAM_MEM_REG_NAME = "bit_mem";
|
||||
constexpr char* TOP_TB_BITSTREAM_INDEX_REG_NAME = "bit_index";
|
||||
constexpr char* TOP_TB_BITSTREAM_ITERATOR_REG_NAME = "ibit";
|
||||
constexpr char* TOP_TB_BITSTREAM_SKIP_FLAG_REG_NAME = "skip_bits";
|
||||
|
||||
constexpr char* AUTOCHECK_TOP_TESTBENCH_VERILOG_MODULE_POSTFIX = "_autocheck_top_tb";
|
||||
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue