Merge pull request #231 from lnis-uofu/dev

Extended LUT Support: Now accept external LUT netlists with embedded custom logic
This commit is contained in:
tangxifan 2021-02-11 13:57:17 -07:00 committed by GitHub
commit 702bd3bbd5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 1911 additions and 106 deletions

View File

@ -14,6 +14,9 @@ run-task fpga_verilog/lut_design/single_mode --debug --show_thread_logs
echo -e "Testing Verilog generation for LUTs: simple fracturable LUT4 ";
run-task fpga_verilog/lut_design/frac_lut4 --debug --show_thread_logs
echo -e "Testing Verilog generation for LUTs: fracturable LUT4 with embedded carry logic";
run-task fpga_verilog/lut_design/frac_lut4_arith --debug --show_thread_logs
echo -e "Testing Verilog generation for LUTs: native fracturable LUT4 ";
run-task fpga_verilog/lut_design/frac_native_lut4 --debug --show_thread_logs

View File

@ -689,8 +689,8 @@ Template
<lut_input_inverter exist="<string>" circuit_model_name="<string>"/>
<lut_intermediate_buffer exist="<string>" circuit_model_name="<string>" location_map="<string>"/>
<pass_gate_logic type="<string>" circuit_model_name="<string>"/>
<port type="input" prefix="<string>" size="<int>" tri_state_map="<string>" circuit_model_name="<string>"/>
<port type="output" prefix="<string>" size="<int>" lut_frac_level="<int>" lut_output_mask="<int>"/>
<port type="input" prefix="<string>" size="<int>" tri_state_map="<string>" circuit_model_name="<string>" is_harden_lut_port="<bool>"/>
<port type="output" prefix="<string>" size="<int>" lut_frac_level="<int>" lut_output_mask="<int>" is_harden_lut_port="<bool>"/>
<port type="sram" prefix="<string>" size="<int>" mode_select="<bool>" circuit_model_name="<string>" default_val="<int>"/>
</circuit_model>
@ -736,18 +736,22 @@ Template
.. note:: For a LUT, three types of ports (``input``, ``output`` and ``sram``) should be defined. If the user provides an customized Verilog/SPICE netlist, the bandwidth of ports should be defined to the same as the Verilog/SPICE netlist. To support customizable LUTs, each type of port contain special keywords.
.. option:: <port type="input" prefix="<string>" size="<int>" tri_state_map="<string>" circuit_model_name="<string>"/>
.. option:: <port type="input" prefix="<string>" size="<int>" tri_state_map="<string>" circuit_model_name="<string>" is_harden_lut_port="<bool>"/>
- ``tri_state_map="[-|1]"`` Customize which inputs are fixed to constant values when the LUT is in fracturable modes. For example, ``tri_state_map="----11"`` indicates that the last two inputs will be fixed to be logic '1' when a 6-input LUT is in fracturable modes.
- ``circuit_model_name="<string>"`` Specify the circuit model to build logic gates in order to tri-state the inputs in fracturable LUT modes. It is required to use an ``AND`` gate to force logic '0' or an ``OR`` gate to force logic '1' for the input ports.
.. option:: <port type="output" prefix="<string>" size="<int>" lut_frac_level="<int>" lut_output_mask="<int>"/>
- ``is_harden_lut_port="[true|false]"`` Specify if the input drives a harden logic inside a LUT. A harden input is supposed **NOT** to drive any multiplexer input (the internal multiplexer of LUT). As a result, such inputs are not considered to implement any truth table mapped to the LUT. If enabled, the input will **NOT** be considered for wiring to internal multiplexers as well as bitstream generation. By default, an input port is treated **NOT** to be a harden LUT port.
.. option:: <port type="output" prefix="<string>" size="<int>" lut_frac_level="<int>" lut_output_mask="<int>" is_harden_lut_port="<bool>"/>
- ``lut_frac_level="<int>"`` Specify the level in LUT multiplexer tree where the output port are wired to. For example, ``lut_frac_level="4"`` in a fracturable LUT6 means that the output are potentially wired to the 4th stage of a LUT multiplexer and it is an output of a LUT4.
- ``lut_output_mask="<int>"`` Describe which fracturable outputs are used. For instance, in a 6-LUT, there are potentially four LUT4 outputs can be wired out. ``lut_output_mask="0,2"`` indicates that only the first and the thrid LUT4 outputs will be used in fracturable mode.
- ``is_harden_lut_port="[true|false]"`` Specify if the output is driven by a harden logic inside a LUT. A harden input is supposed **NOT** to be driven by any multiplexer output (the internal multiplexer of LUT). As a result, such outputs are not considered to implement any truth table mapped to the LUT. If enabled, the output will **NOT** be considered for wiring to internal multiplexers as well as bitstream generation. By default, an output port is treated **NOT** to be a harden LUT port.
.. note:: The size of the output port should be consistent to the length of ``lut_output_mask``.
.. option:: <port type="sram" prefix="<string>" size="<int>" mode_select="<bool>" circuit_model_name="<string>" default_val="<int>"/>
@ -912,6 +916,54 @@ This example shows:
- There will be two outputs wired to the 5th stage of routing multiplexer (the outputs of dual 5-input LUTs)
.. _circuit_model_lut_harden_logic_example:
LUT with Harden Logic
`````````````````````
:numref:`fig_lut_arith` illustrates the detailed schematic of a fracturable 4-input LUT coupled with carry logic gates. For fracturable LUT schematic, please refer to :numref:`fig_std_frac_lut`.
This feature allows users to fully customize their LUT circuit implementation while being compatible with OpenFPGA's bitstream generator when mapping truth tables to the LUTs.
.. warning:: OpenFPGA does **NOT** support netlist autogeneration for the LUT with harden logic. Users should build their own netlist and use ``verilog_netlist`` syntax of :ref:`circuit_library` to include it.
.. _fig_lut_arith:
.. figure:: ./figures/lut_arith_example.svg
:scale: 80%
:alt: detailed lut composition
Detailed schematic of a fracturable 4-input LUT with embedded carry logic.
The code describing this LUT is:
.. code-block:: xml
<circuit_model type="lut" name="frac_lut4_arith" prefix="frac_lut4_arith" dump_structural_verilog="true" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/verilog/frac_lut4_arith.v">
<design_technology type="cmos" fracturable_lut="true"/>
<input_buffer exist="false"/>
<output_buffer exist="true" circuit_model_name="sky130_fd_sc_hd__buf_2"/>
<lut_input_inverter exist="true" circuit_model_name="sky130_fd_sc_hd__inv_1"/>
<lut_input_buffer exist="true" circuit_model_name="sky130_fd_sc_hd__buf_2"/>
<lut_intermediate_buffer exist="true" circuit_model_name="sky130_fd_sc_hd__buf_2" location_map="-1-"/>
<pass_gate_logic circuit_model_name="sky130_fd_sc_hd__mux2_1"/>
<port type="input" prefix="in" size="4" tri_state_map="---1" circuit_model_name="sky130_fd_sc_hd__or2_1"/>
<port type="input" prefix="cin" size="1" is_harden_lut_port="true"/>
<port type="output" prefix="lut3_out" size="2" lut_frac_level="3" lut_output_mask="0,1"/>
<port type="output" prefix="lut4_out" size="1" lut_output_mask="0"/>
<port type="output" prefix="cout" size="1" is_harden_lut_port="true"/>
<port type="sram" prefix="sram" size="16"/>
<port type="sram" prefix="mode" size="2" mode_select="true" circuit_model_name="DFFRQ" default_val="1"/>
</circuit_model>
This example shows:
- Fracturable 4-input LUT which is configurable by 16 SRAM cells.
- There are two output wired to the 3th stage of routing multiplexer (the outputs of dual 3-input LUTs)
- There are two outputs wired to the 2th stage of routing multiplexer (the outputs of 2-input LUTs in the in the lower part of SRAM cells). Note that the two outputs drive the embedded carry logic
- There is a harden carry logic, i.e., a 2-input MUX, to implement high-performance carry function.
- There is a mode-switch multiplexer at ``cin`` port, which is used to switch between arithemetic mode and regular LUT mode.
.. note:: If the embedded harden logic are driven partially by LUT outputs, users may use the :ref:`file_formats_bitstream_setting` to gaurantee correct bitstream generation for the LUTs.
Flip-Flops
~~~~~~~~~~
@ -1012,6 +1064,8 @@ This example shows:
- The first output port **MUST** be the data output port, e.g., ``Q``.
- The second output port **MUST** be the **inverted** data output port, e.g., ``QN``.
.. _circuit_model_ccff_enable_example:
Configuration-chain Flip-flop with Configure Enable Signals
```````````````````````````````````````````````````````````
@ -1049,6 +1103,9 @@ The code describing this FF is:
- The second output port **MUST** be the **inverted** data output port which is activated by the configure enable signal, e.g., ``QN``.
- The second output port **MUST** be the data output port which is activated by the configure enable signal, e.g., ``Q``.
.. _circuit_model_ccff_scanable_example:
Configuration-chain Flip-flop with Scan Input
`````````````````````````````````````````````

View File

@ -0,0 +1,177 @@
<?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 version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" viewBox="179.38898 285.84 341.16036 252.71838" width="341.16036" height="252.71838">
<defs>
<font-face font-family="Times New Roman" font-size="15" panose-1="2 2 8 3 7 5 5 2 3 4" units-per-em="1000" underline-position="-108.88672" underline-thickness="95.21484" slope="0" x-height="456.54297" cap-height="662.1094" ascent="891.1133" descent="-216.3086" font-weight="700">
<font-face-src>
<font-face-name name="TimesNewRomanPS-BoldMT"/>
</font-face-src>
</font-face>
<font-face font-family="Courier" font-size="11" units-per-em="1000" underline-position="-144.04297" underline-thickness="91.79688" slope="-1090.9091" x-height="456.54297" cap-height="586.91406" ascent="753.90625" descent="-246.09375" font-style="italic" font-weight="700">
<font-face-src>
<font-face-name name="Courier-BoldOblique"/>
</font-face-src>
</font-face>
<font-face font-family="Times New Roman" font-size="12" panose-1="2 2 8 3 7 5 5 2 3 4" units-per-em="1000" underline-position="-108.88672" underline-thickness="95.21484" slope="0" x-height="456.54297" cap-height="662.1094" ascent="891.1133" descent="-216.3086" font-weight="700">
<font-face-src>
<font-face-name name="TimesNewRomanPS-BoldMT"/>
</font-face-src>
</font-face>
<font-face font-family="Courier" font-size="11" units-per-em="1000" underline-position="-178.22266" underline-thickness="57.61719" slope="-1090.9091" x-height="456.54297" cap-height="586.91406" ascent="753.90625" descent="-246.09375" font-style="italic" font-weight="400">
<font-face-src>
<font-face-name name="Courier-Oblique"/>
</font-face-src>
</font-face>
</defs>
<metadata> Produced by OmniGraffle 7.18.2\n2021-02-10 18:07:14 +0000</metadata>
<g id="arith_lut" stroke-opacity="1" stroke-dasharray="none" fill-opacity="1" fill="none" stroke="none">
<title>arith_lut</title>
<g id="arith_lut_图层_1">
<title>图层 1</title>
<g id="Graphic_37">
<rect x="205.83603" y="305.33566" width="241.28396" height="213.72704" fill="#ffffc0"/>
<path d="M 447.12 305.33566 L 205.83603 305.33566 L 205.83603 519.0627 L 447.12 519.0627 Z" stroke="gray" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="4.0,4.0" stroke-width="1"/>
</g>
<g id="Line_36">
<path d="M 326.478 412.1992 L 335.6363 338 L 447.12 336.96777" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
</g>
<g id="Graphic_35">
<rect x="279.02144" y="316.73116" width="56.5337" height="139.87187" fill="#417fff"/>
<rect x="279.02144" y="316.73116" width="56.5337" height="139.87187" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
<text transform="translate(284.02144 361.7113)" fill="white">
<tspan font-family="Times New Roman" font-size="15" font-weight="700" fill="white" x="1.6091366" y="13">Fractu</tspan>
<tspan font-family="Times New Roman" font-size="15" font-weight="700" fill="white" x="6.604254" y="29.637207">rable </tspan>
<tspan font-family="Times New Roman" font-size="15" font-weight="700" fill="white" x="1.5981503" y="46.274414">4-LUT</tspan>
</text>
</g>
<g id="Line_34">
<line x1="205.83603" y1="370.74403" x2="279.26538" y2="370.89634" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
</g>
<g id="Line_33">
<line x1="204.93" y1="409.81623" x2="278.35934" y2="409.96854" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
</g>
<g id="Graphic_32">
<text transform="translate(181.48965 433.30334)" fill="black">
<tspan font-family="Courier" font-size="11" font-style="italic" font-weight="700" fill="black" x="0" y="10">in3</tspan>
</text>
</g>
<g id="Graphic_31">
<text transform="translate(182.23359 325.73767)" fill="black">
<tspan font-family="Courier" font-size="11" font-style="italic" font-weight="700" fill="black" x="0" y="10">in0</tspan>
</text>
</g>
<g id="Graphic_30">
<text transform="translate(182.23359 363.27142)" fill="black">
<tspan font-family="Courier" font-size="11" font-style="italic" font-weight="700" fill="black" x="0" y="10">in1</tspan>
</text>
</g>
<g id="Graphic_29">
<text transform="translate(181.48965 401.4314)" fill="black">
<tspan font-family="Courier" font-size="11" font-style="italic" font-weight="700" fill="black" x="0" y="10">in2</tspan>
</text>
</g>
<g id="Line_26">
<line x1="205.40787" y1="331.73767" x2="278.83722" y2="331.89" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
</g>
<g id="Graphic_25">
<text transform="translate(448.98254 362.52783)" fill="black">
<tspan font-family="Courier" font-size="11" font-style="italic" font-weight="700" fill="black" x="0" y="10">LUT4_out</tspan>
</text>
</g>
<g id="Line_24">
<line x1="205.40787" y1="442.95306" x2="278.83722" y2="443.10537" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
</g>
<g id="Line_23">
<line x1="335.8274" y1="370.08026" x2="447.12" y2="369.241" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
</g>
<g id="Line_22">
<line x1="335.55514" y1="407.5" x2="447.12" y2="407.2651" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
</g>
<g id="Graphic_21">
<text transform="translate(447.52875 330.12783)" fill="black">
<tspan font-family="Courier" font-size="11" font-style="italic" font-weight="700" fill="black" x="0" y="10">LUT3_out[0]</tspan>
</text>
</g>
<g id="Graphic_20">
<text transform="translate(447.52875 400.68783)" fill="black">
<tspan font-family="Courier" font-size="11" font-style="italic" font-weight="700" fill="black" x="0" y="10">LUT3_out[1]</tspan>
</text>
</g>
<g id="Line_16">
<path d="M 232.07211 305.33566 L 231.38833 385.98385 L 251.39685 385.9529" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
</g>
<g id="Graphic_15">
<text transform="translate(222.25315 289.08783)" fill="black">
<tspan font-family="Courier" font-size="11" font-style="italic" font-weight="700" fill="black" x="0" y="10">cin</tspan>
</text>
</g>
<g id="Graphic_14">
<path d="M 250.8219 376.87824 L 250.8267 425.9176 C 250.8267 425.9176 266.13377 418.54753 265.8503 418.26407 C 265.56685 417.9806 265.56206 382.26407 265.56206 382.26407 Z" fill="#417fff"/>
<path d="M 250.8219 376.87824 L 250.8267 425.9176 C 250.8267 425.9176 266.13377 418.54753 265.8503 418.26407 C 265.56685 417.9806 265.56206 382.26407 265.56206 382.26407 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
</g>
<g id="Graphic_13">
<text transform="translate(253.56688 379.6333)" fill="white">
<tspan font-family="Times New Roman" font-size="12" font-weight="700" fill="white" x="0" y="11">M</tspan>
<tspan font-family="Times New Roman" font-size="12" font-weight="700" fill="white" x="1.3300781" y="25.509766">U</tspan>
<tspan font-family="Times New Roman" font-size="12" font-weight="700" fill="white" x="1.3300781" y="40.01953">X</tspan>
</text>
</g>
<g id="Graphic_12">
<text transform="translate(344.71927 413.06407)" fill="black">
<tspan font-family="Courier" font-size="11" font-style="italic" font-weight="400" fill="black" x="0" y="10">LUT2_out[1]</tspan>
</text>
</g>
<g id="Line_11">
<path d="M 335.95678 452.0359 L 335.628 451.2862 L 374.75 451.30757 L 374.75 501 L 386.9667 500.901" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
</g>
<g id="Graphic_10">
<path d="M 433.6331 493.1958 L 384.59373 493.2006 C 384.59373 493.2006 391.9638 508.5077 392.24727 508.2242 C 392.53074 507.94075 428.24727 507.93597 428.24727 507.93597 Z" fill="#417fff"/>
<path d="M 433.6331 493.1958 L 384.59373 493.2006 C 384.59373 493.2006 391.9638 508.5077 392.24727 508.2242 C 392.53074 507.94075 428.24727 507.93597 428.24727 507.93597 Z" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
</g>
<g id="Graphic_8">
<text transform="translate(395.9708 493.4571)" fill="white">
<tspan font-family="Times New Roman" font-size="12" font-weight="700" fill="white" x="0" y="11">MUX</tspan>
</text>
</g>
<g id="Graphic_7">
<text transform="translate(344.71927 432.55974)" fill="black">
<tspan font-family="Courier" font-size="11" font-style="italic" font-weight="400" fill="black" x="0" y="10">LUT2_out[0]</tspan>
</text>
</g>
<g id="Line_6">
<path d="M 232.16333 384.83773 L 231.72166 469.9529 L 400.75 469 L 401.25 493.1958 L 400.5304 492.508" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
</g>
<g id="Graphic_5">
<ellipse cx="232.15476" cy="386.48915" rx="2.58243758861829" ry="2.75000439423021" fill="black"/>
<ellipse cx="232.15476" cy="386.48915" rx="2.58243758861829" ry="2.75000439423021" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/>
</g>
<g id="Line_4">
<line x1="410.2999" y1="519.0627" x2="410.2999" y2="508.2281" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
</g>
<g id="Graphic_3">
<text transform="translate(397.09776 522.31054)" fill="black">
<tspan font-family="Courier" font-size="11" font-style="italic" font-weight="700" fill="black" x="0" y="10">cout</tspan>
</text>
</g>
<g id="Line_38">
<line x1="259.75" y1="305.33566" x2="259.34253" y2="380.604" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
</g>
<g id="Line_9">
<path d="M 335.55514 429.38477 L 425.8331 429 L 424.96936 492.5 L 423.7264 493.1958" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
</g>
<g id="Graphic_39">
<text transform="translate(246.0857 289.08783)" fill="black">
<tspan font-family="Courier" font-size="11" font-style="italic" font-weight="700" fill="black" x="0" y="10">mode[0]</tspan>
</text>
</g>
<g id="Line_40">
<line x1="307.75" y1="305.33566" x2="307.691" y2="315.73118" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
</g>
<g id="Graphic_41">
<text transform="translate(303.37425 289.08783)" fill="black">
<tspan font-family="Courier" font-size="11" font-style="italic" font-weight="700" fill="black" x="0" y="10">mode[1]</tspan>
</text>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -1,61 +1,65 @@
Technical Highlights
--------------------
The follow lists of technical features are created to help users spot their needs in customizing FPGA fabrics.(**as of October 2020**)
The follow lists of technical features are created to help users spot their needs in customizing FPGA fabrics.(**as of February 2021**)
Supported Circuit Designs
~~~~~~~~~~~~~~~~~~~~~~~~~
+---------------+-----------------+--------------+-----------------------------------------------------+
| Circuit Types | Auto-generation | User-Defined | Design Topologies |
+===============+=================+==============+=====================================================+
| Inverter | Yes | Yes | - :ref:`circuit_model_power_gated_inverter_example` |
| | | | - :ref:`circuit_model_inverter_1x_example` |
| | | | - :ref:`circuit_model_tapered_inv_16x_example` |
+---------------+-----------------+--------------+-----------------------------------------------------+
| Buffer | Yes | Yes | - :ref:`circuit_model_buffer_2x_example` |
| | | | - :ref:`circuit_model_power_gated_buffer_example` |
| | | | - :ref:`circuit_model_tapered_buffer_64x_example` |
+---------------+-----------------+--------------+-----------------------------------------------------+
| AND gate | Yes | Yes | - :ref:`circuit_model_and2_example` |
+---------------+-----------------+--------------+-----------------------------------------------------+
| OR gate | Yes | Yes | - :ref:`circuit_model_or2_example` |
+---------------+-----------------+--------------+-----------------------------------------------------+
| MUX2 gate | Yes | Yes | - :ref:`circuit_model_mux2_gate_example` |
+---------------+-----------------+--------------+-----------------------------------------------------+
| Pass gate | Yes | Yes | - :ref:`circuit_model_tgate_example` |
| | | | - :ref:`circuit_model_pass_transistor_example` |
+---------------+-----------------+--------------+-----------------------------------------------------+
| Look-Up Table | Yes | Yes | - **Any size** |
| | | | - :ref:`circuit_model_single_output_lut_example` |
| | | | - :ref:`circuit_model_frac_lut_example` |
+---------------+-----------------+--------------+-----------------------------------------------------+
| Routing | Yes | No | - **Any size** |
| Multiplexer | | | - :ref:`circuit_model_mux_multilevel_example` |
| | | | - :ref:`circuit_model_mux_1level_example` |
| | | | - :ref:`circuit_model_mux_tree_example` |
| | | | - :ref:`circuit_model_mux_stdcell_example` |
| | | | - :ref:`circuit_model_mux_local_encoder_example` |
| | | | - :ref:`circuit_model_mux_const_input_example` |
+---------------+-----------------+--------------+-----------------------------------------------------+
| Configurable | No | Yes | - :ref:`circuit_model_config_latch_example` |
| Memory | | | - :ref:`circuit_model_sram_blwl_example` |
| | | | - :ref:`circuit_model_dff_example` |
| | | | - :ref:`circuit_model_ccff_example` |
+---------------+-----------------+--------------+-----------------------------------------------------+
| Block RAM | No | Yes | - **Any size** |
| | | | - Single-port |
| | | | - Dual-port |
| | | | - Fracturable |
+---------------+-----------------+--------------+-----------------------------------------------------+
| Arithmetic | No | Yes | - **Any size** |
| Units | | | - Multiplier |
| | | | - :ref:`circuit_model_full_adder_example` |
+---------------+-----------------+--------------+-----------------------------------------------------+
| I/O | No | Yes | - :ref:`circuit_model_gpio_example` |
| | | | - Bi-directional buffer |
| | | | - AIB |
+---------------+-----------------+--------------+-----------------------------------------------------+
+-----------------+--------------+-----------+-----------------------------------------------------+
| | Circuit Types | | Auto- | | User- | | Design Topologies |
| | | | generation | | Defined | |
+=================+==============+===========+=====================================================+
| Inverter | Yes | Yes | - :ref:`circuit_model_power_gated_inverter_example` |
| | | | - :ref:`circuit_model_inverter_1x_example` |
| | | | - :ref:`circuit_model_tapered_inv_16x_example` |
+-----------------+--------------+-----------+-----------------------------------------------------+
| Buffer | Yes | Yes | - :ref:`circuit_model_buffer_2x_example` |
| | | | - :ref:`circuit_model_power_gated_buffer_example` |
| | | | - :ref:`circuit_model_tapered_buffer_64x_example` |
+-----------------+--------------+-----------+-----------------------------------------------------+
| AND gate | Yes | Yes | - :ref:`circuit_model_and2_example` |
+-----------------+--------------+-----------+-----------------------------------------------------+
| OR gate | Yes | Yes | - :ref:`circuit_model_or2_example` |
+-----------------+--------------+-----------+-----------------------------------------------------+
| MUX2 gate | Yes | Yes | - :ref:`circuit_model_mux2_gate_example` |
+-----------------+--------------+-----------+-----------------------------------------------------+
| Pass gate | Yes | Yes | - :ref:`circuit_model_tgate_example` |
| | | | - :ref:`circuit_model_pass_transistor_example` |
+-----------------+--------------+-----------+-----------------------------------------------------+
| Look-Up Table | Yes | Yes | - **Any size** |
| | | | - :ref:`circuit_model_single_output_lut_example` |
| | | | - :ref:`circuit_model_frac_lut_example` |
| | | | - :ref:`circuit_model_lut_harden_logic_example` |
+-----------------+--------------+-----------+-----------------------------------------------------+
| | Routing | Yes | No | - **Any size** |
| | Multiplexer | | | - :ref:`circuit_model_mux_multilevel_example` |
| | | | - :ref:`circuit_model_mux_1level_example` |
| | | | - :ref:`circuit_model_mux_tree_example` |
| | | | - :ref:`circuit_model_mux_stdcell_example` |
| | | | - :ref:`circuit_model_mux_local_encoder_example` |
| | | | - :ref:`circuit_model_mux_const_input_example` |
+-----------------+--------------+-----------+-----------------------------------------------------+
| | Configurable | No | Yes | - :ref:`circuit_model_config_latch_example` |
| | Memory | | | - :ref:`circuit_model_sram_blwl_example` |
| | | | - :ref:`circuit_model_dff_example` |
| | | | - :ref:`circuit_model_ccff_example` |
| | | | - :ref:`circuit_model_ccff_enable_example` |
| | | | - :ref:`circuit_model_ccff_scanable_example` |
+-----------------+--------------+-----------+-----------------------------------------------------+
| Block RAM | No | Yes | - **Any size** |
| | | | - Single-port |
| | | | - Dual-port |
| | | | - Fracturable |
+-----------------+--------------+-----------+-----------------------------------------------------+
| | Arithmetic | No | Yes | - **Any size** |
| | Units | | | - Multiplier |
| | | | - :ref:`circuit_model_full_adder_example` |
+-----------------+--------------+-----------+-----------------------------------------------------+
| I/O | No | Yes | - :ref:`circuit_model_gpio_example` |
| | | | - Bi-directional buffer |
| | | | - AIB |
+-----------------+--------------+-----------+-----------------------------------------------------+
* The user defined netlist could come from a standard cell

View File

@ -964,6 +964,13 @@ size_t CircuitLibrary::port_lut_frac_level(const CircuitPortId& circuit_port_id)
return port_lut_frac_level_[circuit_port_id];
}
/* Return if the port drives or is driven by a harden logic inside a LUT */
bool CircuitLibrary::port_is_harden_lut_port(const CircuitPortId& circuit_port_id) const {
/* validate the circuit_port_id */
VTR_ASSERT(valid_circuit_port_id(circuit_port_id));
return port_is_harden_lut_port_[circuit_port_id];
}
/* Return indices of internal nodes in a LUT multiplexing structure to which the output port is wired to */
std::vector<size_t> CircuitLibrary::port_lut_output_mask(const CircuitPortId& circuit_port_id) const {
/* validate the circuit_port_id */
@ -1390,6 +1397,7 @@ CircuitPortId CircuitLibrary::add_model_port(const CircuitModelId& model_id,
port_inv_model_ids_.push_back(CircuitModelId::INVALID());
port_tri_state_maps_.emplace_back();
port_lut_frac_level_.push_back(-1);
port_is_harden_lut_port_.push_back(false);
port_lut_output_masks_.emplace_back();
port_sram_orgz_.push_back(NUM_CONFIG_PROTOCOL_TYPES);
@ -1576,6 +1584,17 @@ void CircuitLibrary::set_port_lut_frac_level(const CircuitPortId& circuit_port_i
return;
}
/* Set the LUT fracturable level for a port of a circuit model, only applicable to LUTs */
void CircuitLibrary::set_port_is_harden_lut_port(const CircuitPortId& circuit_port_id,
const bool& is_harden_lut_port) {
/* validate the circuit_port_id */
VTR_ASSERT(valid_circuit_port_id(circuit_port_id));
/* Make sure this is a LUT */
VTR_ASSERT(CIRCUIT_MODEL_LUT == model_type(port_model_ids_[circuit_port_id]));
port_is_harden_lut_port_[circuit_port_id] = is_harden_lut_port;
return;
}
/* Set the LUT fracturable level for a port of a circuit model, only applicable to LUTs */
void CircuitLibrary::set_port_lut_output_mask(const CircuitPortId& circuit_port_id,
const std::vector<size_t>& lut_output_masks) {

View File

@ -289,6 +289,7 @@ class CircuitLibrary {
bool port_is_config_enable(const CircuitPortId& circuit_port_id) const;
bool port_is_prog(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;
std::string port_tri_state_map(const CircuitPortId& circuit_port_id) const;
CircuitModelId port_tri_state_model(const CircuitPortId& circuit_port_id) const;
@ -383,6 +384,8 @@ class CircuitLibrary {
const std::string& tri_state_map);
void set_port_lut_frac_level(const CircuitPortId& circuit_port_id,
const size_t& lut_frac_level);
void set_port_is_harden_lut_port(const CircuitPortId& circuit_port_id,
const bool& is_harden_lut_port);
void set_port_lut_output_mask(const CircuitPortId& circuit_port_id,
const std::vector<size_t>& lut_output_masks);
void set_port_sram_orgz(const CircuitPortId& circuit_port_id,
@ -563,6 +566,7 @@ class CircuitLibrary {
vtr::vector<CircuitPortId, CircuitModelId> port_inv_model_ids_;
vtr::vector<CircuitPortId, std::string> port_tri_state_maps_;
vtr::vector<CircuitPortId, size_t> port_lut_frac_level_;
vtr::vector<CircuitPortId, bool> port_is_harden_lut_port_;
vtr::vector<CircuitPortId, std::vector<size_t>> port_lut_output_masks_;
vtr::vector<CircuitPortId, enum e_config_protocol_type> port_sram_orgz_;

View File

@ -454,6 +454,16 @@ void read_xml_circuit_port(pugi::xml_node& xml_port,
circuit_lib.set_port_lut_frac_level(port, get_attribute(xml_port, "lut_frac_level", loc_data, pugiutil::ReqOpt::OPTIONAL).as_int(-1));
}
/* Identify if the port carries a harden functionality rather than a reconfigurable port
* This is only applicable to LUT circuit models.
* The super LUT circuit model (whose netlists are supposed to be provided by users) contains
* some hard logic inside, e.g., a carry logic.
* By default, a port does NOT carry a hard functionality
*/
if (CIRCUIT_MODEL_LUT == circuit_lib.model_type(model)) {
circuit_lib.set_port_is_harden_lut_port(port, get_attribute(xml_port, "is_harden_lut_port", loc_data, pugiutil::ReqOpt::OPTIONAL).as_bool(false));
}
/* Identify the output mask of the port in LUTs, by default it will be applied to each pin of this port
* This is only applicable to output ports of a LUT
*/

View File

@ -186,6 +186,14 @@ void write_xml_circuit_port(std::fstream& fp,
}
}
/* LUT harden port attributes */
if (CIRCUIT_MODEL_LUT == circuit_lib.model_type(model)) {
if (true == circuit_lib.port_is_harden_lut_port(port)) {
write_xml_attribute(fp, "is_harden_lut_port", "true");
}
}
/* I/O port attributes */
if (true == circuit_lib.port_is_io(port)) {
write_xml_attribute(fp, "is_io", "true");

View File

@ -45,8 +45,13 @@ void build_lut_module(ModuleManager& module_manager,
std::vector<CircuitPortId> lut_global_ports = circuit_lib.model_global_ports_by_type(lut_model, CIRCUIT_MODEL_PORT_INPUT, false, true);
/* Get the input ports from the mux */
std::vector<CircuitPortId> lut_input_ports = circuit_lib.model_ports_by_type(lut_model, CIRCUIT_MODEL_PORT_INPUT, true);
/* Find the inputs that drive the internal LUT MUX */
std::vector<CircuitPortId> lut_mux_input_ports = find_lut_circuit_model_input_port(circuit_lib, lut_model, false);
/* Get the output ports from the mux */
std::vector<CircuitPortId> lut_output_ports = circuit_lib.model_ports_by_type(lut_model, CIRCUIT_MODEL_PORT_OUTPUT, false);
/* Find the outputs that are driven the internal LUT MUX */
std::vector<CircuitPortId> lut_mux_output_ports = find_lut_circuit_model_output_port(circuit_lib, lut_model, false);
/* Classify SRAM ports into two categories: regular (not for mode select) and mode-select */
std::vector<CircuitPortId> lut_regular_sram_ports = find_circuit_regular_sram_ports(circuit_lib, lut_model);
@ -60,8 +65,8 @@ void build_lut_module(ModuleManager& module_manager,
/* Single-output LUTs:
* We should have only 1 input port, 1 output port and 1 SRAM port
*/
VTR_ASSERT (1 == lut_input_ports.size());
VTR_ASSERT (1 == lut_output_ports.size());
VTR_ASSERT (1 == lut_mux_input_ports.size());
VTR_ASSERT (1 == lut_mux_output_ports.size());
VTR_ASSERT (1 == lut_regular_sram_ports.size());
VTR_ASSERT (0 == lut_mode_select_sram_ports.size());
} else {
@ -70,8 +75,8 @@ void build_lut_module(ModuleManager& module_manager,
* We should have only 1 input port, a few output ports (fracturable outputs)
* and two SRAM ports
*/
VTR_ASSERT (1 == lut_input_ports.size());
VTR_ASSERT (1 <= lut_output_ports.size());
VTR_ASSERT (1 == lut_mux_input_ports.size());
VTR_ASSERT (1 <= lut_mux_output_ports.size());
VTR_ASSERT (1 == lut_regular_sram_ports.size());
VTR_ASSERT ( (0 == lut_mode_select_sram_ports.size())
|| (1 == lut_mode_select_sram_ports.size()));
@ -155,10 +160,10 @@ void build_lut_module(ModuleManager& module_manager,
* +--------------------------------------+
*/
/* Get the tri-state port map for the input ports*/
std::string tri_state_map = circuit_lib.port_tri_state_map(lut_input_ports[0]);
std::string tri_state_map = circuit_lib.port_tri_state_map(lut_mux_input_ports[0]);
size_t mode_select_port_lsb = 0;
for (const auto& pin : circuit_lib.pins(lut_input_ports[0])) {
ModulePortId lut_module_input_port_id = module_manager.find_module_port(lut_module, circuit_lib.port_prefix(lut_input_ports[0]));
for (const auto& pin : circuit_lib.pins(lut_mux_input_ports[0])) {
ModulePortId lut_module_input_port_id = module_manager.find_module_port(lut_module, circuit_lib.port_prefix(lut_mux_input_ports[0]));
VTR_ASSERT(true == module_manager.valid_module_port_id(lut_module, lut_module_input_port_id));
/* Create a module net for the connection */
@ -200,7 +205,7 @@ void build_lut_module(ModuleManager& module_manager,
required_gate_type = CIRCUIT_MODEL_GATE_OR;
}
/* Get the circuit model of the gate */
CircuitModelId gate_model = circuit_lib.port_tri_state_model(lut_input_ports[0]);
CircuitModelId gate_model = circuit_lib.port_tri_state_model(lut_mux_input_ports[0]);
/* Check this is the gate we want ! */
VTR_ASSERT (required_gate_type == circuit_lib.gate_type(gate_model));
@ -290,7 +295,7 @@ void build_lut_module(ModuleManager& module_manager,
std::vector<ModuleNetId> lut_mux_sram_inv_nets;
/* Now we need to add inverters by instanciating the modules */
for (size_t pin = 0; pin < circuit_lib.port_size(lut_input_ports[0]); ++pin) {
for (size_t pin = 0; pin < circuit_lib.port_size(lut_mux_input_ports[0]); ++pin) {
ModuleNetId lut_mux_sram_inv_net = add_inverter_buffer_child_module_and_nets(module_manager, lut_module,
circuit_lib, input_inverter_model,
mode_selected_nets[pin]);
@ -308,7 +313,7 @@ void build_lut_module(ModuleManager& module_manager,
std::vector<ModuleNetId> lut_mux_sram_nets;
/* Now we need to add inverters by instanciating the modules and add module nets */
for (size_t pin = 0; pin < circuit_lib.port_size(lut_input_ports[0]); ++pin) {
for (size_t pin = 0; pin < circuit_lib.port_size(lut_mux_input_ports[0]); ++pin) {
ModuleNetId lut_mux_sram_net = add_inverter_buffer_child_module_and_nets(module_manager, lut_module,
circuit_lib, input_buffer_model,
mode_selected_nets[pin]);
@ -362,7 +367,7 @@ void build_lut_module(ModuleManager& module_manager,
*/
ModulePortId lut_sram_port_id = module_manager.find_module_port(lut_module, circuit_lib.port_prefix(lut_regular_sram_ports[0]));
BasicPort lut_sram_port = module_manager.module_port(lut_module, lut_sram_port_id);
ModulePortId lut_mux_input_port_id = module_manager.find_module_port(lut_mux_module, circuit_lib.port_prefix(lut_input_ports[0]));
ModulePortId lut_mux_input_port_id = module_manager.find_module_port(lut_mux_module, circuit_lib.port_prefix(lut_mux_input_ports[0]));
BasicPort lut_mux_input_port = module_manager.module_port(lut_mux_module, lut_mux_input_port_id);
VTR_ASSERT(lut_mux_input_port.get_width() == lut_sram_port.get_width());
/* Wire the port to lut_mux_sram_net */
@ -372,7 +377,7 @@ void build_lut_module(ModuleManager& module_manager,
module_manager.add_module_net_sink(lut_module, net, lut_mux_module, lut_mux_instance, lut_mux_input_port_id, lut_mux_input_port.pins()[pin_id]);
}
for (const auto& port : lut_output_ports) {
for (const auto& port : lut_mux_output_ports) {
ModulePortId lut_output_port_id = module_manager.find_module_port(lut_module, circuit_lib.port_prefix(port));
BasicPort lut_output_port = module_manager.module_port(lut_module, lut_output_port_id);
ModulePortId lut_mux_output_port_id = module_manager.find_module_port(lut_mux_module, circuit_lib.port_prefix(port));
@ -407,6 +412,11 @@ void build_lut_modules(ModuleManager& module_manager,
if (CIRCUIT_MODEL_LUT != circuit_lib.model_type(lut_model)) {
continue;
}
/* We skip user-defined models */
if ( (false == circuit_lib.model_verilog_netlist(lut_model).empty())
|| (false == circuit_lib.model_spice_netlist(lut_model).empty()) ) {
continue;
}
build_lut_module(module_manager, circuit_lib, lut_model);
}
}

View File

@ -734,8 +734,18 @@ vtr::vector<MuxInputId, ModuleNetId> build_mux_module_input_buffers(ModuleManage
const MuxGraph& mux_graph) {
vtr::vector<MuxInputId, ModuleNetId> mux_input_nets(mux_graph.num_inputs(), ModuleNetId::INVALID());
/* Get the input ports from the mux */
std::vector<CircuitPortId> mux_input_ports = circuit_lib.model_ports_by_type(mux_model, CIRCUIT_MODEL_PORT_INPUT, true);
/* Get the input ports from the mux:
* - LUT may have ports that are driven by harden logic,
* which should not be included when building the mux graph
*/
std::vector<CircuitPortId> mux_input_ports;
if (CIRCUIT_MODEL_LUT == circuit_lib.model_type(mux_model)) {
mux_input_ports = find_lut_circuit_model_input_port(circuit_lib, mux_model, false, false);
} else {
VTR_ASSERT(CIRCUIT_MODEL_MUX == circuit_lib.model_type(mux_model));
mux_input_ports = circuit_lib.model_ports_by_type(mux_model, CIRCUIT_MODEL_PORT_INPUT, true);
}
/* We should have only 1 input port! */
VTR_ASSERT(1 == mux_input_ports.size());
@ -849,8 +859,18 @@ vtr::vector<MuxOutputId, ModuleNetId> build_mux_module_output_buffers(ModuleMana
/* Create module nets for output ports */
vtr::vector<MuxOutputId, ModuleNetId> mux_output_nets(mux_graph.num_outputs(), ModuleNetId::INVALID());
/* Get the output ports from the mux */
std::vector<CircuitPortId> mux_output_ports = circuit_lib.model_ports_by_type(mux_model, CIRCUIT_MODEL_PORT_OUTPUT, false);
/* Get the output ports from the mux:
* - LUT may have ports that are driven by harden logic,
* which should not be included when building the mux graph
* - LUT may have global output ports that are wired directly to top-level module
*/
std::vector<CircuitPortId> mux_output_ports;
if (CIRCUIT_MODEL_LUT == circuit_lib.model_type(mux_model)) {
mux_output_ports = find_lut_circuit_model_output_port(circuit_lib, mux_model, false, true);
} else {
VTR_ASSERT(CIRCUIT_MODEL_MUX == circuit_lib.model_type(mux_model));
mux_output_ports = circuit_lib.model_ports_by_type(mux_model, CIRCUIT_MODEL_PORT_OUTPUT, false);
}
/* Iterate over all the outputs in the MUX module */
for (const auto& output_port : mux_output_ports) {
@ -1096,10 +1116,32 @@ void build_cmos_mux_module(ModuleManager& module_manager,
const MuxGraph& mux_graph) {
/* Get the global ports required by MUX (and any submodules) */
std::vector<CircuitPortId> mux_global_ports = circuit_lib.model_global_ports_by_type(mux_model, CIRCUIT_MODEL_PORT_INPUT, true, true);
/* Get the input ports from the mux */
std::vector<CircuitPortId> mux_input_ports = circuit_lib.model_ports_by_type(mux_model, CIRCUIT_MODEL_PORT_INPUT, true);
/* Get the output ports from the mux */
std::vector<CircuitPortId> mux_output_ports = circuit_lib.model_ports_by_type(mux_model, CIRCUIT_MODEL_PORT_OUTPUT, false);
/* Get the input ports from the mux:
* - LUT may have ports that are driven by harden logic,
* which should not be included when building the mux graph
*/
std::vector<CircuitPortId> mux_input_ports;
if (CIRCUIT_MODEL_LUT == circuit_lib.model_type(mux_model)) {
mux_input_ports = find_lut_circuit_model_input_port(circuit_lib, mux_model, false, false);
} else {
VTR_ASSERT(CIRCUIT_MODEL_MUX == circuit_lib.model_type(mux_model));
mux_input_ports = circuit_lib.model_ports_by_type(mux_model, CIRCUIT_MODEL_PORT_INPUT, true);
}
/* Get the output ports from the mux:
* - LUT may have ports that are driven by harden logic,
* which should not be included when building the mux graph
* - LUT may have global output ports that are wired directly to top-level module
*/
std::vector<CircuitPortId> mux_output_ports;
if (CIRCUIT_MODEL_LUT == circuit_lib.model_type(mux_model)) {
mux_output_ports = find_lut_circuit_model_output_port(circuit_lib, mux_model, false, true);
} else {
VTR_ASSERT(CIRCUIT_MODEL_MUX == circuit_lib.model_type(mux_model));
mux_output_ports = circuit_lib.model_ports_by_type(mux_model, CIRCUIT_MODEL_PORT_OUTPUT, false);
}
/* Get the sram ports from the mux
* Multiplexing structure does not mode_sram_ports, they are handled in LUT modules
* Here we just bypass it.

View File

@ -407,7 +407,7 @@ void build_lut_bitstream(BitstreamManager& bitstream_manager,
VTR_ASSERT(CIRCUIT_MODEL_LUT == circuit_lib.model_type(lut_model));
/* Find the input ports for LUT size, this is used to decode the LUT memory bits! */
std::vector<CircuitPortId> model_input_ports = circuit_lib.model_ports_by_type(lut_model, CIRCUIT_MODEL_PORT_INPUT, true);
std::vector<CircuitPortId> model_input_ports = find_lut_circuit_model_input_port(circuit_lib, lut_model, false);
VTR_ASSERT(1 == model_input_ports.size());
size_t lut_size = circuit_lib.port_size(model_input_ports[0]);

View File

@ -89,7 +89,9 @@ int print_sdc_disable_lut_configure_ports(std::fstream& fp,
}
const std::string& sram_inv_port_name = circuit_lib.port_lib_name(sram_port) + INV_PORT_POSTFIX;
VTR_ASSERT(true == module_manager.valid_module_port_id(programmable_module, module_manager.find_module_port(programmable_module, sram_inv_port_name)));
if (false == module_manager.valid_module_port_id(programmable_module, module_manager.find_module_port(programmable_module, sram_inv_port_name))) {
continue;
}
if (CMD_EXEC_FATAL_ERROR ==
rec_print_sdc_disable_timing_for_module_ports(fp,
flatten_names,

View File

@ -11,6 +11,7 @@
/* Headers from readarchopenfpga library */
#include "circuit_types.h"
#include "circuit_library.h"
#include "circuit_library_utils.h"
#include "mux_utils.h"
#include "pb_type_utils.h"
@ -182,7 +183,7 @@ void build_lut_mux_library(MuxLibrary& mux_lib,
}
/* Find the MUX size required by the LUT */
/* Get input ports which are not global ports! */
std::vector<CircuitPortId> input_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_INPUT, true);
std::vector<CircuitPortId> input_ports = find_lut_circuit_model_input_port(circuit_lib, circuit_model, false);
VTR_ASSERT(1 == input_ports.size());
/* MUX size = 2^lut_size */
size_t lut_mux_size = (size_t)pow(2., (double)(circuit_lib.port_size(input_ports[0])));

View File

@ -50,39 +50,47 @@ static
std::vector<int> generate_lut_rotated_input_pin_map(const std::vector<AtomNetId>& input_nets,
const AtomContext& atom_ctx,
const AtomBlockId& atom_blk,
const VprDeviceAnnotation& device_annotation,
const CircuitLibrary& circuit_lib,
const t_pb_graph_node* pb_graph_node) {
/* Find the pin rotation status and record it ,
* Note that some LUT inputs may not be used, we set them to be open by default
*/
std::vector<int> rotated_pin_map(input_nets.size(), -1);
VTR_ASSERT(1 == pb_graph_node->num_input_ports);
for (int iport = 0; iport < pb_graph_node->num_input_ports; ++iport) {
for (int ipin = 0; ipin < pb_graph_node->num_input_pins[iport]; ++ipin) {
/* Skip the input pin that do not drive by LUT MUXes */
CircuitPortId circuit_port = device_annotation.pb_circuit_port(pb_graph_node->input_pins[iport][ipin].port);
if (true == circuit_lib.port_is_harden_lut_port(circuit_port)) {
continue;
}
for (int ipin = 0; ipin < pb_graph_node->num_input_pins[0]; ++ipin) {
/* The lut pb_graph_node may not be the primitive node
* because VPR adds two default modes to its LUT pb_type
* If so, we will use the LUT mode of the pb_graph node
*/
t_port* lut_pb_type_in_port = pb_graph_node->input_pins[0][ipin].port;
if (0 != pb_graph_node->pb_type->num_modes) {
VTR_ASSERT(2 == pb_graph_node->pb_type->num_modes);
VTR_ASSERT(1 == pb_graph_node->pb_type->modes[VPR_PB_TYPE_LUT_MODE].num_pb_type_children);
lut_pb_type_in_port = &(pb_graph_node->pb_type->modes[VPR_PB_TYPE_LUT_MODE].pb_type_children[0].ports[0]);
VTR_ASSERT(std::string(lut_pb_type_in_port->name) == std::string(pb_graph_node->input_pins[0][ipin].port->name));
VTR_ASSERT(lut_pb_type_in_port->num_pins == pb_graph_node->input_pins[0][ipin].port->num_pins);
}
/* The lut pb_graph_node may not be the primitive node
* because VPR adds two default modes to its LUT pb_type
* If so, we will use the LUT mode of the pb_graph node
*/
t_port* lut_pb_type_in_port = pb_graph_node->input_pins[iport][ipin].port;
if (0 != pb_graph_node->pb_type->num_modes) {
VTR_ASSERT(2 == pb_graph_node->pb_type->num_modes);
VTR_ASSERT(1 == pb_graph_node->pb_type->modes[VPR_PB_TYPE_LUT_MODE].num_pb_type_children);
lut_pb_type_in_port = &(pb_graph_node->pb_type->modes[VPR_PB_TYPE_LUT_MODE].pb_type_children[0].ports[iport]);
VTR_ASSERT(std::string(lut_pb_type_in_port->name) == std::string(pb_graph_node->input_pins[iport][ipin].port->name));
VTR_ASSERT(lut_pb_type_in_port->num_pins == pb_graph_node->input_pins[iport][ipin].port->num_pins);
}
/* Port exists (some LUTs may have no input and hence no port in the atom netlist) */
AtomPortId atom_port = atom_ctx.nlist.find_atom_port(atom_blk, lut_pb_type_in_port->model_port);
if (!atom_port) {
continue;
}
/* Port exists (some LUTs may have no input and hence no port in the atom netlist) */
AtomPortId atom_port = atom_ctx.nlist.find_atom_port(atom_blk, lut_pb_type_in_port->model_port);
if (!atom_port) {
continue;
}
for (AtomPinId atom_pin : atom_ctx.nlist.port_pins(atom_port)) {
AtomNetId atom_pin_net = atom_ctx.nlist.pin_net(atom_pin);
if (atom_pin_net == input_nets[ipin]) {
rotated_pin_map[ipin] = atom_ctx.nlist.pin_port_bit(atom_pin);
break;
for (AtomPinId atom_pin : atom_ctx.nlist.port_pins(atom_port)) {
AtomNetId atom_pin_net = atom_ctx.nlist.pin_net(atom_pin);
if (atom_pin_net == input_nets[ipin]) {
rotated_pin_map[ipin] = atom_ctx.nlist.pin_port_bit(atom_pin);
break;
}
}
}
}
@ -109,15 +117,27 @@ void build_physical_pb_lut_truth_tables(PhysicalPb& physical_pb,
/* Find all the nets mapped to each inputs */
std::vector<AtomNetId> input_nets;
VTR_ASSERT(1 == pb_graph_node->num_input_ports);
for (int ipin = 0; ipin < pb_graph_node->num_input_pins[0]; ++ipin) {
input_nets.push_back(physical_pb.pb_graph_pin_atom_net(lut_pb_id, &(pb_graph_node->input_pins[0][ipin])));
for (int iport = 0; iport < pb_graph_node->num_input_ports; ++iport) {
for (int ipin = 0; ipin < pb_graph_node->num_input_pins[iport]; ++ipin) {
/* Skip the input pin that do not drive by LUT MUXes */
CircuitPortId circuit_port = device_annotation.pb_circuit_port(pb_graph_node->input_pins[iport][ipin].port);
if (true == circuit_lib.port_is_harden_lut_port(circuit_port)) {
continue;
}
input_nets.push_back(physical_pb.pb_graph_pin_atom_net(lut_pb_id, &(pb_graph_node->input_pins[iport][ipin])));
}
}
/* Find all the nets mapped to each outputs */
for (int iport = 0; iport < pb_graph_node->num_output_ports; ++iport) {
for (int ipin = 0; ipin < pb_graph_node->num_output_pins[iport]; ++ipin) {
const t_pb_graph_pin* output_pin = &(pb_graph_node->output_pins[iport][ipin]);
/* Skip the output ports that are not driven by LUT MUXes */
CircuitPortId circuit_port = device_annotation.pb_circuit_port(output_pin->port);
if (true == circuit_lib.port_is_harden_lut_port(circuit_port)) {
continue;
}
AtomNetId output_net = physical_pb.pb_graph_pin_atom_net(lut_pb_id, output_pin);
/* Bypass unmapped pins */
if (AtomNetId::INVALID() == output_net) {
@ -135,7 +155,7 @@ void build_physical_pb_lut_truth_tables(PhysicalPb& physical_pb,
VTR_ASSERT(true == atom_ctx.nlist.valid_block_id(atom_blk));
const AtomNetlist::TruthTable& orig_tt = atom_ctx.nlist.block_truth_table(atom_blk);
std::vector<int> rotated_pin_map = generate_lut_rotated_input_pin_map(input_nets, atom_ctx, atom_blk, pb_graph_node);
std::vector<int> rotated_pin_map = generate_lut_rotated_input_pin_map(input_nets, atom_ctx, atom_blk, device_annotation, circuit_lib, pb_graph_node);
adapt_tt = lut_truth_table_adaption(orig_tt, rotated_pin_map);
}

View File

@ -368,4 +368,54 @@ CircuitPortId find_circuit_model_power_gate_enb_port(const CircuitLibrary& circu
return enb_port;
}
/************************************************************************
* Try to find the input ports for a LUT circuit model (EXCLUDE the global ports)
* which can optionally include those ports drives or is driven by hard logic
***********************************************************************/
std::vector<CircuitPortId> find_lut_circuit_model_input_port(const CircuitLibrary& circuit_lib,
const CircuitModelId& circuit_model,
const bool& include_harden_port,
const bool& include_global_port) {
VTR_ASSERT(CIRCUIT_MODEL_LUT == circuit_lib.model_type(circuit_model));
std::vector<CircuitPortId> input_ports;
/* Find all the non-global input ports */
for (const auto& port : circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_INPUT, !include_global_port)) {
/* Skip harden ports if specified */
if ( (true == circuit_lib.port_is_harden_lut_port(port))
&& (false == include_harden_port)) {
continue;
}
input_ports.push_back(port);
}
return input_ports;
}
/************************************************************************
* Try to find the output ports for a LUT circuit model (EXCLUDE the global ports)
* which can optionally include those ports drives or is driven by hard logic
***********************************************************************/
std::vector<CircuitPortId> find_lut_circuit_model_output_port(const CircuitLibrary& circuit_lib,
const CircuitModelId& circuit_model,
const bool& include_harden_port,
const bool& include_global_port) {
VTR_ASSERT(CIRCUIT_MODEL_LUT == circuit_lib.model_type(circuit_model));
std::vector<CircuitPortId> output_ports;
/* Find all the non-global input ports */
for (const auto& port : circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_OUTPUT, !include_global_port)) {
/* Skip harden ports if specified */
if ( (true == circuit_lib.port_is_harden_lut_port(port))
&& (false == include_harden_port)) {
continue;
}
output_ports.push_back(port);
}
return output_ports;
}
} /* end namespace openfpga */

View File

@ -51,6 +51,16 @@ CircuitPortId find_circuit_model_power_gate_en_port(const CircuitLibrary& circui
CircuitPortId find_circuit_model_power_gate_enb_port(const CircuitLibrary& circuit_lib,
const CircuitModelId& circuit_model);
std::vector<CircuitPortId> find_lut_circuit_model_input_port(const CircuitLibrary& circuit_lib,
const CircuitModelId& circuit_model,
const bool& include_harden_port,
const bool& include_global_port = true);
std::vector<CircuitPortId> find_lut_circuit_model_output_port(const CircuitLibrary& circuit_lib,
const CircuitModelId& circuit_model,
const bool& include_harden_port,
const bool& include_global_port = true);
} /* end namespace openfpga */
#endif

View File

@ -0,0 +1,19 @@
# This is an artificial microbenchmark
# which is designed to validate the support
# on using bitstream information from the .param
# attribute of hard macro of LUTs
#
.model and2
.inputs a b
.outputs c
.subckt adder_lut4 in[1]=a in[0]=b lut4_out[0]=c
.param LUT 1000100010001000
.end
.model adder_lut4
.inputs in[3] in[2] in[1] in[0] cin
.outputs lut4_out[0] cout
.blackbox
.end

View File

@ -0,0 +1,265 @@
<!-- Architecture annotation for OpenFPGA framework
This annotation supports the k4_frac_cc_sky130nm.xml
- General purpose logic block
- K = 6, N = 10, I = 40
- Single mode
- Routing architecture
- L = 4, fc_in = 0.15, fc_out = 0.1
- Skywater 130nm PDK
- circuit models are binded to the opensource skywater
foundry middle-speed (ms) standard cell library
-->
<openfpga_architecture>
<technology_library>
<device_library>
<device_model name="logic" type="transistor">
<lib type="industry" corner="TOP_TT" ref="M" path="${OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.pm"/>
<design vdd="0.9" pn_ratio="2"/>
<pmos name="pch" chan_length="40e-9" min_width="140e-9" variation="logic_transistor_var"/>
<nmos name="nch" chan_length="40e-9" min_width="140e-9" variation="logic_transistor_var"/>
</device_model>
<device_model name="io" type="transistor">
<lib type="academia" ref="M" path="${OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.pm"/>
<design vdd="2.5" pn_ratio="3"/>
<pmos name="pch_25" chan_length="270e-9" min_width="320e-9" variation="io_transistor_var"/>
<nmos name="nch_25" chan_length="270e-9" min_width="320e-9" variation="io_transistor_var"/>
</device_model>
</device_library>
<variation_library>
<variation name="logic_transistor_var" abs_deviation="0.1" num_sigma="3"/>
<variation name="io_transistor_var" abs_deviation="0.1" num_sigma="3"/>
</variation_library>
</technology_library>
<circuit_library>
<circuit_model type="inv_buf" name="sky130_fd_sc_hd__inv_1" prefix="sky130_fd_sc_hd__inv_1" is_default="true">
<design_technology type="cmos" topology="inverter" size="1"/>
<device_technology device_model_name="logic"/>
<port type="input" prefix="in" lib_name="A" size="1"/>
<port type="output" prefix="out" lib_name="Y" size="1"/>
<delay_matrix type="rise" in_port="in" out_port="out">
10e-12
</delay_matrix>
<delay_matrix type="fall" in_port="in" out_port="out">
10e-12
</delay_matrix>
</circuit_model>
<circuit_model type="inv_buf" name="sky130_fd_sc_hd__buf_2" prefix="sky130_fd_sc_hd__buf_2" is_default="false">
<design_technology type="cmos" topology="buffer" size="1" num_level="2" f_per_stage="2"/>
<device_technology device_model_name="logic"/>
<port type="input" prefix="in" lib_name="A" size="1"/>
<port type="output" prefix="out" lib_name="X" size="1"/>
<delay_matrix type="rise" in_port="in" out_port="out">
10e-12
</delay_matrix>
<delay_matrix type="fall" in_port="in" out_port="out">
10e-12
</delay_matrix>
</circuit_model>
<circuit_model type="inv_buf" name="sky130_fd_sc_hd__buf_4" prefix="sky130_fd_sc_hd__buf_4" is_default="false">
<design_technology type="cmos" topology="buffer" size="1" num_level="2" f_per_stage="4"/>
<device_technology device_model_name="logic"/>
<port type="input" prefix="in" lib_name="A" size="1"/>
<port type="output" prefix="out" lib_name="X" size="1"/>
<delay_matrix type="rise" in_port="in" out_port="out">
10e-12
</delay_matrix>
<delay_matrix type="fall" in_port="in" out_port="out">
10e-12
</delay_matrix>
</circuit_model>
<circuit_model type="inv_buf" name="sky130_fd_sc_hd__inv_2" prefix="sky130_fd_sc_hd__inv_2" is_default="false">
<design_technology type="cmos" topology="buffer" size="1"/>
<device_technology device_model_name="logic"/>
<port type="input" prefix="in" lib_name="A" size="1"/>
<port type="output" prefix="out" lib_name="Y" size="1"/>
<delay_matrix type="rise" in_port="in" out_port="out">
10e-12
</delay_matrix>
<delay_matrix type="fall" in_port="in" out_port="out">
10e-12
</delay_matrix>
</circuit_model>
<circuit_model type="gate" name="sky130_fd_sc_hd__or2_1" prefix="sky130_fd_sc_hd__or2_1" is_default="true">
<design_technology type="cmos" topology="OR"/>
<device_technology device_model_name="logic"/>
<input_buffer exist="false"/>
<output_buffer exist="false"/>
<port type="input" prefix="a" lib_name="A" size="1"/>
<port type="input" prefix="b" lib_name="B" size="1"/>
<port type="output" prefix="out" lib_name="X" size="1"/>
<delay_matrix type="rise" in_port="a b" out_port="out">
10e-12 5e-12
</delay_matrix>
<delay_matrix type="fall" in_port="a b" out_port="out">
10e-12 5e-12
</delay_matrix>
</circuit_model>
<!-- Define a circuit model for the standard cell MUX2
OpenFPGA requires the following truth table for the MUX2
When the select signal sel is enabled, the first input, i.e., in0
will be propagated to the output, i.e., out
If your standard cell provider does not offer the exact truth table,
you can simply swap the inputs as shown in the example below
-->
<circuit_model type="gate" name="sky130_fd_sc_hd__mux2_1" prefix="sky130_fd_sc_hd__mux2_1">
<design_technology type="cmos" topology="MUX2"/>
<device_technology device_model_name="logic"/>
<input_buffer exist="false"/>
<output_buffer exist="false"/>
<port type="input" prefix="in0" lib_name="A1" size="1"/>
<port type="input" prefix="in1" lib_name="A0" size="1"/>
<port type="input" prefix="sel" lib_name="S" size="1"/>
<port type="output" prefix="out" lib_name="X" size="1"/>
</circuit_model>
<circuit_model type="chan_wire" name="chan_segment" prefix="track_seg" is_default="true">
<design_technology type="cmos"/>
<input_buffer exist="false"/>
<output_buffer exist="false"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<wire_param model_type="pi" R="101" C="22.5e-15" num_level="1"/>
<!-- model_type could be T, res_val and cap_val DON'T CARE -->
</circuit_model>
<circuit_model type="wire" name="direct_interc" prefix="direct_interc" is_default="true">
<design_technology type="cmos"/>
<input_buffer exist="false"/>
<output_buffer exist="false"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<wire_param model_type="pi" R="0" C="0" num_level="1"/>
<!-- model_type could be T, res_val cap_val should be defined -->
</circuit_model>
<circuit_model type="mux" name="mux_tree" prefix="mux_tree" is_default="true" dump_structural_verilog="true">
<design_technology type="cmos" structure="tree" add_const_input="true" const_input_val="1"/>
<input_buffer exist="false"/>
<output_buffer exist="false"/>
<pass_gate_logic circuit_model_name="sky130_fd_sc_hd__mux2_1"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<port type="sram" prefix="sram" size="1"/>
</circuit_model>
<circuit_model type="mux" name="mux_tree_tapbuf" prefix="mux_tree_tapbuf" dump_structural_verilog="true">
<design_technology type="cmos" structure="tree" add_const_input="true" const_input_val="1"/>
<input_buffer exist="false"/>
<output_buffer exist="true" circuit_model_name="sky130_fd_sc_hd__buf_4"/>
<pass_gate_logic circuit_model_name="sky130_fd_sc_hd__mux2_1"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<port type="sram" prefix="sram" size="1"/>
</circuit_model>
<!--DFF subckt ports should be defined as <D> <Q> <CLK> <RESET> <SET> -->
<circuit_model type="ff" name="SDFFRQ" prefix="SDFFRQ" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/verilog/dff.v">
<design_technology type="cmos"/>
<input_buffer exist="true" circuit_model_name="sky130_fd_sc_hd__inv_1"/>
<output_buffer exist="true" circuit_model_name="sky130_fd_sc_hd__inv_1"/>
<port type="input" prefix="D" size="1"/>
<port type="input" prefix="DI" lib_name="SI" size="1"/>
<port type="input" prefix="Test_en" lib_name="SE" size="1" is_global="true" default_val="0"/>
<port type="input" prefix="reset" lib_name="RST" size="1" default_val="0"/>
<port type="output" prefix="Q" size="1"/>
<port type="clock" prefix="clk" lib_name="CK" size="1" default_val="0" />
</circuit_model>
<circuit_model type="lut" name="frac_lut4_arith" prefix="frac_lut4_arith" dump_structural_verilog="true" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/verilog/frac_lut4_arith.v">
<design_technology type="cmos" fracturable_lut="true"/>
<input_buffer exist="false"/>
<output_buffer exist="true" circuit_model_name="sky130_fd_sc_hd__buf_2"/>
<lut_input_inverter exist="true" circuit_model_name="sky130_fd_sc_hd__inv_1"/>
<lut_input_buffer exist="true" circuit_model_name="sky130_fd_sc_hd__buf_2"/>
<lut_intermediate_buffer exist="true" circuit_model_name="sky130_fd_sc_hd__buf_2" location_map="-1-"/>
<pass_gate_logic circuit_model_name="sky130_fd_sc_hd__mux2_1"/>
<port type="input" prefix="in" size="4" tri_state_map="---1" circuit_model_name="sky130_fd_sc_hd__or2_1"/>
<port type="input" prefix="cin" size="1" is_harden_lut_port="true"/>
<port type="output" prefix="lut3_out" size="2" lut_frac_level="3" lut_output_mask="0,1"/>
<port type="output" prefix="lut4_out" size="1" lut_output_mask="0"/>
<port type="output" prefix="cout" size="1" is_harden_lut_port="true"/>
<port type="sram" prefix="sram" size="16"/>
<port type="sram" prefix="mode" size="2" mode_select="true" circuit_model_name="DFFRQ" default_val="1"/>
</circuit_model>
<!--Scan-chain DFF subckt ports should be defined as <D> <Q> <Qb> <CLK> <RESET> <SET> -->
<circuit_model type="ccff" name="DFFRQ" prefix="DFFRQ" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/verilog/dff.v">
<design_technology type="cmos"/>
<input_buffer exist="true" circuit_model_name="sky130_fd_sc_hd__inv_1"/>
<output_buffer exist="true" circuit_model_name="sky130_fd_sc_hd__inv_1"/>
<port type="input" prefix="D" size="1"/>
<port type="output" prefix="Q" size="1"/>
<port type="clock" prefix="prog_clk" lib_name="CK" size="1" is_global="true" default_val="0" is_prog="true"/>
<port type="input" prefix="pReset" lib_name="RST" size="1" is_global="true" default_val="0" is_prog="true" is_reset="true"/>
</circuit_model>
<circuit_model type="iopad" name="EMBEDDED_IO_ISOLN" prefix="EMBEDDED_IO_ISOLN" is_default="true" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/verilog/gpio.v">
<design_technology type="cmos"/>
<input_buffer exist="true" circuit_model_name="sky130_fd_sc_hd__inv_1"/>
<output_buffer exist="true" circuit_model_name="sky130_fd_sc_hd__inv_1"/>
<port type="input" prefix="SOC_IN" lib_name="SOC_IN" size="1" is_global="true" is_io="true" is_data_io="true"/>
<port type="output" prefix="SOC_OUT" lib_name="SOC_OUT" size="1" is_global="true" is_io="true" is_data_io="true"/>
<port type="output" prefix="SOC_DIR" lib_name="SOC_DIR" size="1" is_global="true" is_io="true"/>
<port type="input" prefix="IO_ISOL_N" lib_name="IO_ISOL_N" size="1" is_global="true" default_val="1"/>
<port type="output" prefix="inpad" lib_name="FPGA_IN" size="1"/>
<port type="input" prefix="outpad" lib_name="FPGA_OUT" size="1"/>
<port type="sram" prefix="en" lib_name="FPGA_DIR" size="1" mode_select="true" circuit_model_name="DFFRQ" default_val="1"/>
</circuit_model>
</circuit_library>
<configuration_protocol>
<organization type="scan_chain" circuit_model_name="DFFRQ" num_regions="1"/>
</configuration_protocol>
<connection_block>
<switch name="ipin_cblock" circuit_model_name="mux_tree_tapbuf"/>
</connection_block>
<switch_block>
<switch name="L1_mux" circuit_model_name="mux_tree_tapbuf"/>
<switch name="L2_mux" circuit_model_name="mux_tree_tapbuf"/>
<switch name="L4_mux" circuit_model_name="mux_tree_tapbuf"/>
</switch_block>
<routing_segment>
<segment name="L1" circuit_model_name="chan_segment"/>
<segment name="L2" circuit_model_name="chan_segment"/>
<segment name="L4" circuit_model_name="chan_segment"/>
</routing_segment>
<direct_connection>
<direct name="carry_chain" circuit_model_name="direct_interc"/>
<direct name="shift_register" circuit_model_name="direct_interc"/>
<direct name="scan_chain" circuit_model_name="direct_interc" type="column" x_dir="positive" y_dir="positive"/>
</direct_connection>
<tile_annotations>
<global_port name="clk" is_clock="true" default_val="0">
<tile name="clb" port="clk" x="-1" y="-1"/>
</global_port>
<global_port name="Reset" is_reset="true" default_val="1">
<tile name="clb" port="reset" x="-1" y="-1"/>
</global_port>
</tile_annotations>
<pb_type_annotations>
<!-- physical pb_type binding in complex block IO -->
<pb_type name="io" physical_mode_name="physical" idle_mode_name="inpad"/>
<!-- IMPORTANT: must set unused I/Os to operating in INPUT mode !!! -->
<pb_type name="io[physical].iopad" circuit_model_name="EMBEDDED_IO_ISOLN" mode_bits="1"/>
<pb_type name="io[inpad].inpad" physical_pb_type_name="io[physical].iopad" mode_bits="1"/>
<pb_type name="io[outpad].outpad" physical_pb_type_name="io[physical].iopad" mode_bits="0"/>
<!-- End physical pb_type binding in complex block IO -->
<!-- physical pb_type binding in complex block CLB -->
<!-- physical mode will be the default mode if not specified -->
<pb_type name="clb.fle" physical_mode_name="physical"/>
<pb_type name="clb.fle[physical].fabric.frac_logic.frac_lut4_arith" circuit_model_name="frac_lut4_arith" mode_bits="00"/>
<pb_type name="clb.fle[physical].fabric.ff" circuit_model_name="SDFFRQ"/>
<!-- Binding operating pb_type to physical pb_type -->
<!-- Binding operating pb_types in mode 'arithmetic' -->
<pb_type name="clb.fle[arithmetic].soft_adder.adder_lut4" physical_pb_type_name="clb.fle[physical].fabric.frac_logic.frac_lut4_arith" mode_bits="11"/>
<!-- Binding operating pb_types in mode 'n2_lut3' -->
<pb_type name="clb.fle[n2_lut3].lut3inter.ble3.lut3" physical_pb_type_name="clb.fle[physical].fabric.frac_logic.frac_lut4_arith" mode_bits="01" physical_pb_type_index_factor="0.5">
<!-- Binding the lut3 to the first 3 inputs of fracturable lut4 -->
<port name="in" physical_mode_port="in[0:2]"/>
<port name="out" physical_mode_port="lut3_out[0:0]" physical_mode_pin_rotate_offset="1"/>
</pb_type>
<pb_type name="clb.fle[n2_lut3].lut3inter.ble3.ff" physical_pb_type_name="clb.fle[physical].fabric.ff"/>
<!-- Binding operating pb_types in mode 'ble4' -->
<pb_type name="clb.fle[n1_lut4].ble4.lut4" physical_pb_type_name="clb.fle[physical].fabric.frac_logic.frac_lut4_arith" mode_bits="00">
<!-- Binding the lut4 to the first 4 inputs of fracturable lut4 -->
<port name="in" physical_mode_port="in[0:3]"/>
<port name="out" physical_mode_port="lut4_out"/>
</pb_type>
<pb_type name="clb.fle[n1_lut4].ble4.ff" physical_pb_type_name="clb.fle[physical].fabric.ff" physical_pb_type_index_factor="2" physical_pb_type_index_offset="0"/>
<!-- Binding operating pb_types in mode 'shift_register' -->
<pb_type name="clb.fle[shift_register].shift_reg.ff" physical_pb_type_name="clb.fle[physical].fabric.ff"/>
<!-- End physical pb_type binding in complex block IO -->
</pb_type_annotations>
</openfpga_architecture>

View File

@ -0,0 +1,274 @@
//-----------------------------------------------------
// Design Name : frac_lut4_arith
// File Name : frac_lut4_arith.v
// Function : 4-input Look Up Table with integrated carry logic
// - mode_bit[0] switch between arithmetic mode and LUT mode
// - mode_bit[1] switch between regular LUT mode and fracturable
// mode
// Note : The HDL is a technology mapped netlist based on the Skywater
// 130nm High-Density cell library.
// TODO: Create a behavioral HDL version so that we are portable
// between PDKs
// Coder : Xifan TANG
//-----------------------------------------------------
module frac_lut4_arith (
input [0:3] in,
input [0:0] cin,
output [0:1] lut3_out,
output [0:0] lut4_out,
output [0:0] cout,
input [0:15] sram,
input [0:1] mode);
//----- BEGIN wire-connection ports -----
wire [0:3] in;
wire [0:0] cin;
wire [0:1] lut2_out;
wire [0:1] lut3_out;
wire [0:0] lut4_out;
wire [0:0] cout;
wire [0:0] arith_in2;
//----- END wire-connection ports -----
//----- BEGIN Registered ports -----
//----- END Registered ports -----
wire [0:0] sky130_fd_sc_hd__buf_2_0_X;
wire [0:0] sky130_fd_sc_hd__buf_2_1_X;
wire [0:0] sky130_fd_sc_hd__buf_2_2_X;
wire [0:0] sky130_fd_sc_hd__buf_2_3_X;
wire [0:0] sky130_fd_sc_hd__inv_1_0_Y;
wire [0:0] sky130_fd_sc_hd__inv_1_1_Y;
wire [0:0] sky130_fd_sc_hd__inv_1_2_Y;
wire [0:0] sky130_fd_sc_hd__inv_1_3_Y;
wire [0:0] sky130_fd_sc_hd__or2_1_0_X;
// ----- BEGIN Local short connections -----
// ----- END Local short connections -----
// ----- BEGIN Local output short connections -----
// ----- END Local output short connections -----
sky130_fd_sc_hd__or2_1 sky130_fd_sc_hd__or2_1_0_ (
.A(mode[1]),
.B(in[3]),
.X(sky130_fd_sc_hd__or2_1_0_X[0]));
sky130_fd_sc_hd__inv_1 sky130_fd_sc_hd__inv_1_0_ (
.A(in[0]),
.Y(sky130_fd_sc_hd__inv_1_0_Y[0]));
sky130_fd_sc_hd__inv_1 sky130_fd_sc_hd__inv_1_1_ (
.A(in[1]),
.Y(sky130_fd_sc_hd__inv_1_1_Y[0]));
assign arith_in2 = mode[0] ? in[2] : cin;
sky130_fd_sc_hd__inv_1 sky130_fd_sc_hd__inv_1_2_ (
.A(arith_in2),
.Y(sky130_fd_sc_hd__inv_1_2_Y[0]));
sky130_fd_sc_hd__inv_1 sky130_fd_sc_hd__inv_1_3_ (
.A(sky130_fd_sc_hd__or2_1_0_X[0]),
.Y(sky130_fd_sc_hd__inv_1_3_Y[0]));
sky130_fd_sc_hd__buf_2 sky130_fd_sc_hd__buf_2_0_ (
.A(in[0]),
.X(sky130_fd_sc_hd__buf_2_0_X[0]));
sky130_fd_sc_hd__buf_2 sky130_fd_sc_hd__buf_2_1_ (
.A(in[1]),
.X(sky130_fd_sc_hd__buf_2_1_X[0]));
sky130_fd_sc_hd__buf_2 sky130_fd_sc_hd__buf_2_2_ (
.A(in[2]),
.X(sky130_fd_sc_hd__buf_2_2_X[0]));
sky130_fd_sc_hd__buf_2 sky130_fd_sc_hd__buf_2_3_ (
.A(sky130_fd_sc_hd__or2_1_0_X[0]),
.X(sky130_fd_sc_hd__buf_2_3_X[0]));
frac_lut4_mux frac_lut4_mux_0_ (
.in(sram[0:15]),
.sram({sky130_fd_sc_hd__buf_2_0_X[0], sky130_fd_sc_hd__buf_2_1_X[0], sky130_fd_sc_hd__buf_2_2_X[0], sky130_fd_sc_hd__buf_2_3_X[0]}),
.sram_inv({sky130_fd_sc_hd__inv_1_0_Y[0], sky130_fd_sc_hd__inv_1_1_Y[0], sky130_fd_sc_hd__inv_1_2_Y[0], sky130_fd_sc_hd__inv_1_3_Y[0]}),
.lut2_out(lut2_out[0:1]),
.lut3_out(lut3_out[0:1]),
.lut4_out(lut4_out[0]));
assign cout = lut2_out[0] ? cin : lut2_out[1];
endmodule
// ----- Verilog module for frac_lut4_mux -----
module frac_lut4_mux(in,
sram,
sram_inv,
lut2_out,
lut3_out,
lut4_out);
//----- INPUT PORTS -----
input [0:15] in;
//----- INPUT PORTS -----
input [0:3] sram;
//----- INPUT PORTS -----
input [0:3] sram_inv;
//----- OUTPUT PORTS -----
output [0:1] lut2_out;
//----- OUTPUT PORTS -----
output [0:1] lut3_out;
//----- OUTPUT PORTS -----
output [0:0] lut4_out;
//----- BEGIN wire-connection ports -----
//----- END wire-connection ports -----
//----- BEGIN Registered ports -----
//----- END Registered ports -----
wire [0:0] sky130_fd_sc_hd__buf_2_5_X;
wire [0:0] sky130_fd_sc_hd__buf_2_6_X;
wire [0:0] sky130_fd_sc_hd__mux2_1_0_X;
wire [0:0] sky130_fd_sc_hd__mux2_1_10_X;
wire [0:0] sky130_fd_sc_hd__mux2_1_11_X;
wire [0:0] sky130_fd_sc_hd__mux2_1_12_X;
wire [0:0] sky130_fd_sc_hd__mux2_1_13_X;
wire [0:0] sky130_fd_sc_hd__mux2_1_14_X;
wire [0:0] sky130_fd_sc_hd__mux2_1_1_X;
wire [0:0] sky130_fd_sc_hd__mux2_1_2_X;
wire [0:0] sky130_fd_sc_hd__mux2_1_3_X;
wire [0:0] sky130_fd_sc_hd__mux2_1_4_X;
wire [0:0] sky130_fd_sc_hd__mux2_1_5_X;
wire [0:0] sky130_fd_sc_hd__mux2_1_6_X;
wire [0:0] sky130_fd_sc_hd__mux2_1_7_X;
wire [0:0] sky130_fd_sc_hd__mux2_1_8_X;
wire [0:0] sky130_fd_sc_hd__mux2_1_9_X;
// ----- BEGIN Local short connections -----
// ----- END Local short connections -----
// ----- BEGIN Local output short connections -----
// ----- END Local output short connections -----
sky130_fd_sc_hd__buf_2 sky130_fd_sc_hd__buf_2_0_ (
.A(sky130_fd_sc_hd__mux2_1_10_X[0]),
.X(lut2_out[0]));
sky130_fd_sc_hd__buf_2 sky130_fd_sc_hd__buf_2_1_ (
.A(sky130_fd_sc_hd__mux2_1_11_X[0]),
.X(lut2_out[1]));
sky130_fd_sc_hd__buf_2 sky130_fd_sc_hd__buf_2_2_ (
.A(sky130_fd_sc_hd__mux2_1_12_X[0]),
.X(lut3_out[0]));
sky130_fd_sc_hd__buf_2 sky130_fd_sc_hd__buf_2_3_ (
.A(sky130_fd_sc_hd__mux2_1_13_X[0]),
.X(lut3_out[1]));
sky130_fd_sc_hd__buf_2 sky130_fd_sc_hd__buf_2_4_ (
.A(sky130_fd_sc_hd__mux2_1_14_X[0]),
.X(lut4_out[0]));
sky130_fd_sc_hd__buf_2 sky130_fd_sc_hd__buf_2_5_ (
.A(sky130_fd_sc_hd__mux2_1_8_X[0]),
.X(sky130_fd_sc_hd__buf_2_5_X[0]));
sky130_fd_sc_hd__buf_2 sky130_fd_sc_hd__buf_2_6_ (
.A(sky130_fd_sc_hd__mux2_1_9_X[0]),
.X(sky130_fd_sc_hd__buf_2_6_X[0]));
sky130_fd_sc_hd__mux2_1 mux_l1_in_0_ (
.A1(in[0]),
.A0(in[1]),
.S(sram[0]),
.X(sky130_fd_sc_hd__mux2_1_0_X[0]));
sky130_fd_sc_hd__mux2_1 mux_l1_in_1_ (
.A1(in[2]),
.A0(in[3]),
.S(sram[0]),
.X(sky130_fd_sc_hd__mux2_1_1_X[0]));
sky130_fd_sc_hd__mux2_1 mux_l1_in_2_ (
.A1(in[4]),
.A0(in[5]),
.S(sram[0]),
.X(sky130_fd_sc_hd__mux2_1_2_X[0]));
sky130_fd_sc_hd__mux2_1 mux_l1_in_3_ (
.A1(in[6]),
.A0(in[7]),
.S(sram[0]),
.X(sky130_fd_sc_hd__mux2_1_3_X[0]));
sky130_fd_sc_hd__mux2_1 mux_l1_in_4_ (
.A1(in[8]),
.A0(in[9]),
.S(sram[0]),
.X(sky130_fd_sc_hd__mux2_1_4_X[0]));
sky130_fd_sc_hd__mux2_1 mux_l1_in_5_ (
.A1(in[10]),
.A0(in[11]),
.S(sram[0]),
.X(sky130_fd_sc_hd__mux2_1_5_X[0]));
sky130_fd_sc_hd__mux2_1 mux_l1_in_6_ (
.A1(in[12]),
.A0(in[13]),
.S(sram[0]),
.X(sky130_fd_sc_hd__mux2_1_6_X[0]));
sky130_fd_sc_hd__mux2_1 mux_l1_in_7_ (
.A1(in[14]),
.A0(in[15]),
.S(sram[0]),
.X(sky130_fd_sc_hd__mux2_1_7_X[0]));
sky130_fd_sc_hd__mux2_1 mux_l2_in_0_ (
.A1(sky130_fd_sc_hd__mux2_1_0_X[0]),
.A0(sky130_fd_sc_hd__mux2_1_1_X[0]),
.S(sram[1]),
.X(sky130_fd_sc_hd__mux2_1_8_X[0]));
sky130_fd_sc_hd__mux2_1 mux_l2_in_1_ (
.A1(sky130_fd_sc_hd__mux2_1_2_X[0]),
.A0(sky130_fd_sc_hd__mux2_1_3_X[0]),
.S(sram[1]),
.X(sky130_fd_sc_hd__mux2_1_9_X[0]));
sky130_fd_sc_hd__mux2_1 mux_l2_in_2_ (
.A1(sky130_fd_sc_hd__mux2_1_4_X[0]),
.A0(sky130_fd_sc_hd__mux2_1_5_X[0]),
.S(sram[1]),
.X(sky130_fd_sc_hd__mux2_1_10_X[0]));
sky130_fd_sc_hd__mux2_1 mux_l2_in_3_ (
.A1(sky130_fd_sc_hd__mux2_1_6_X[0]),
.A0(sky130_fd_sc_hd__mux2_1_7_X[0]),
.S(sram[1]),
.X(sky130_fd_sc_hd__mux2_1_11_X[0]));
sky130_fd_sc_hd__mux2_1 mux_l3_in_0_ (
.A1(sky130_fd_sc_hd__buf_2_5_X[0]),
.A0(sky130_fd_sc_hd__buf_2_6_X[0]),
.S(sram[2]),
.X(sky130_fd_sc_hd__mux2_1_12_X[0]));
sky130_fd_sc_hd__mux2_1 mux_l3_in_1_ (
.A1(sky130_fd_sc_hd__mux2_1_10_X[0]),
.A0(sky130_fd_sc_hd__mux2_1_11_X[0]),
.S(sram[2]),
.X(sky130_fd_sc_hd__mux2_1_13_X[0]));
sky130_fd_sc_hd__mux2_1 mux_l4_in_0_ (
.A1(sky130_fd_sc_hd__mux2_1_12_X[0]),
.A0(sky130_fd_sc_hd__mux2_1_13_X[0]),
.S(sram[3]),
.X(sky130_fd_sc_hd__mux2_1_14_X[0]));
endmodule
// ----- END Verilog module for frac_lut4_mux -----

View File

@ -0,0 +1,3 @@
<openfpga_bitstream_setting>
<pb_type name="clb.fle[arithmetic].soft_adder.adder_lut4" source="eblif" content=".param LUT"/>
</openfpga_bitstream_setting>

View File

@ -0,0 +1,38 @@
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# Configuration file for running experiments
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs
# Each job execute fpga_flow script on combination of architecture & benchmark
# timeout_each_job is timeout for each job
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
[GENERAL]
run_engine=openfpga_shell
power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml
power_analysis = false
spice_output=false
verilog_output=true
timeout_each_job = 1*60
fpga_flow=vpr_blif
[OpenFPGA_SHELL]
openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/bitstream_setting_example_script.openfpga
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_frac_N8_reset_softadderSuperLUT_register_scan_chain_caravel_io_skywater130nm_fdhd_cc_openfpga.xml
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/fixed_sim_openfpga.xml
openfpga_bitstream_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/tasks/fpga_verilog/lut_design/frac_lut4_arith/config/bitstream_annotation.xml
openfpga_vpr_circuit_format=eblif
[ARCHITECTURES]
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_frac_N8_tileable_reset_softadderSuperLUT_register_scan_chain_nonLR_caravel_io_skywater130nm.xml
[BENCHMARKS]
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2_frac_lut4_arith.eblif
[SYNTHESIS_PARAM]
bench0_top = and2
bench0_act = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.act
bench0_verilog = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.v
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
end_flow_with_test=
vpr_fpga_verilog_formal_verification_top_netlist=

View File

@ -0,0 +1,789 @@
<!--
Low-cost homogeneous FPGA Architecture.
- Skywater 130 nm technology
- General purpose logic block:
K = 4, N = 8, fracturable 4 LUTs (can operate as one 4-LUT or two 3-LUTs with all 3 inputs shared)
with optionally registered outputs
- Routing architecture:
- 10% L = 1, fc_in = 0.15, Fc_out = 0.10
- 10% L = 2, fc_in = 0.15, Fc_out = 0.10
- 80% L = 4, fc_in = 0.15, Fc_out = 0.10
- 100 routing tracks per channel
Authors: Xifan Tang
-->
<architecture>
<!--
ODIN II specific config begins
Describes the types of user-specified netlist blocks (in blif, this corresponds to
".model [type_of_block]") that this architecture supports.
Note: Basic LUTs, I/Os, and flip-flops are not included here as there are
already special structures in blif (.names, .input, .output, and .latch)
that describe them.
-->
<models>
<!-- A virtual model for I/O to be used in the physical mode of io block -->
<model name="io">
<input_ports>
<port name="outpad"/>
</input_ports>
<output_ports>
<port name="inpad"/>
</output_ports>
</model>
<model name="adder_lut4">
<input_ports>
<port name="in" combinational_sink_ports="lut4_out cout"/>
<port name="cin" combinational_sink_ports="lut4_out cout"/>
</input_ports>
<output_ports>
<port name="lut4_out"/>
<port name="cout"/>
</output_ports>
</model>
<model name="frac_lut4_arith">
<input_ports>
<port name="in" combinational_sink_ports="lut3_out lut4_out cout"/>
<port name="cin" combinational_sink_ports="lut3_out lut4_out cout"/>
</input_ports>
<output_ports>
<port name="lut3_out"/>
<port name="lut4_out"/>
<port name="cout"/>
</output_ports>
</model>
<!-- A virtual model for scan-chain flip-flop to be used in the physical mode of FF -->
<model name="scff">
<input_ports>
<port name="D" clock="clk"/>
<port name="DI" clock="clk"/>
<port name="reset" clock="clk"/>
<port name="clk" is_clock="1"/>
</input_ports>
<output_ports>
<port name="Q" clock="clk"/>
</output_ports>
</model>
</models>
<tiles>
<!-- Do NOT add clock pins to I/O here!!! VPR does not build clock network in the way that OpenFPGA can support
If you need to register the I/O, define clocks in the circuit models
These clocks can be handled in back-end
-->
<!-- Top-side has 1 I/O per tile -->
<tile name="io_top" capacity="1" area="0">
<equivalent_sites>
<site pb_type="io"/>
</equivalent_sites>
<input name="outpad" num_pins="1"/>
<output name="inpad" num_pins="1"/>
<fc in_type="frac" in_val="0.15" out_type="frac" out_val="0.10"/>
<pinlocations pattern="custom">
<loc side="bottom">io_top.outpad io_top.inpad</loc>
</pinlocations>
</tile>
<!-- Right-side has 1 I/O per tile -->
<tile name="io_right" capacity="1" area="0">
<equivalent_sites>
<site pb_type="io"/>
</equivalent_sites>
<input name="outpad" num_pins="1"/>
<output name="inpad" num_pins="1"/>
<fc in_type="frac" in_val="0.15" out_type="frac" out_val="0.10"/>
<pinlocations pattern="custom">
<loc side="left">io_right.outpad io_right.inpad</loc>
</pinlocations>
</tile>
<!-- Bottom-side has 9 I/O per tile -->
<tile name="io_bottom" capacity="9" area="0">
<equivalent_sites>
<site pb_type="io"/>
</equivalent_sites>
<input name="outpad" num_pins="1"/>
<output name="inpad" num_pins="1"/>
<fc in_type="frac" in_val="0.15" out_type="frac" out_val="0.10"/>
<pinlocations pattern="custom">
<loc side="top">io_bottom.outpad io_bottom.inpad</loc>
</pinlocations>
</tile>
<!-- Left-side has 1 I/O per tile -->
<tile name="io_left" capacity="1" area="0">
<equivalent_sites>
<site pb_type="io"/>
</equivalent_sites>
<input name="outpad" num_pins="1"/>
<output name="inpad" num_pins="1"/>
<fc in_type="frac" in_val="0.15" out_type="frac" out_val="0.10"/>
<pinlocations pattern="custom">
<loc side="right">io_left.outpad io_left.inpad</loc>
</pinlocations>
</tile>
<!-- CLB has most pins on the top and right sides -->
<tile name="clb" area="53894">
<equivalent_sites>
<site pb_type="clb"/>
</equivalent_sites>
<input name="I0" num_pins="2" equivalent="full"/>
<input name="I0i" num_pins="2" equivalent="none"/>
<input name="I1" num_pins="2" equivalent="full"/>
<input name="I1i" num_pins="2" equivalent="none"/>
<input name="I2" num_pins="2" equivalent="full"/>
<input name="I2i" num_pins="2" equivalent="none"/>
<input name="I3" num_pins="2" equivalent="full"/>
<input name="I3i" num_pins="2" equivalent="none"/>
<input name="I4" num_pins="2" equivalent="full"/>
<input name="I4i" num_pins="2" equivalent="none"/>
<input name="I5" num_pins="2" equivalent="full"/>
<input name="I5i" num_pins="2" equivalent="none"/>
<input name="I6" num_pins="2" equivalent="full"/>
<input name="I6i" num_pins="2" equivalent="none"/>
<input name="I7" num_pins="2" equivalent="full"/>
<input name="I7i" num_pins="2" equivalent="none"/>
<input name="reg_in" num_pins="1"/>
<input name="sc_in" num_pins="1"/>
<input name="cin" num_pins="1"/>
<input name="reset" num_pins="1" is_non_clock_global="true"/>
<output name="O" num_pins="16" equivalent="none"/>
<output name="reg_out" num_pins="1"/>
<output name="sc_out" num_pins="1"/>
<output name="cout" num_pins="1"/>
<clock name="clk" num_pins="1"/>
<fc in_type="frac" in_val="0.15" out_type="frac" out_val="0.10">
<fc_override port_name="reg_in" fc_type="frac" fc_val="0"/>
<fc_override port_name="reg_out" fc_type="frac" fc_val="0"/>
<fc_override port_name="sc_in" fc_type="frac" fc_val="0"/>
<fc_override port_name="sc_out" fc_type="frac" fc_val="0"/>
<fc_override port_name="cin" fc_type="frac" fc_val="0"/>
<fc_override port_name="cout" fc_type="frac" fc_val="0"/>
<fc_override port_name="clk" fc_type="frac" fc_val="0"/>
<fc_override port_name="reset" fc_type="frac" fc_val="0"/>
</fc>
<!--pinlocations pattern="spread"/-->
<pinlocations pattern="custom">
<loc side="left">clb.clk clb.reset</loc>
<loc side="top">clb.reg_in clb.sc_in clb.cin clb.O[7:0] clb.I0 clb.I0i clb.I1 clb.I1i clb.I2 clb.I2i clb.I3 clb.I3i</loc>
<loc side="right">clb.O[15:8] clb.I4 clb.I4i clb.I5 clb.I5i clb.I6 clb.I6i clb.I7 clb.I7i</loc>
<loc side="bottom">clb.reg_out clb.sc_out clb.cout</loc>
</pinlocations>
</tile>
</tiles>
<!-- ODIN II specific config ends -->
<!-- Physical descriptions begin -->
<layout tileable="true">
<auto_layout aspect_ratio="1.0">
<!--Perimeter of 'io' blocks with 'EMPTY' blocks at corners-->
<row type="io_top" starty="H-1" priority="100"/>
<row type="io_bottom" starty="0" priority="100"/>
<col type="io_left" startx="0" priority="100"/>
<col type="io_right" startx="W-1" priority="100"/>
<corners type="EMPTY" priority="101"/>
<!--Fill with 'clb'-->
<fill type="clb" priority="10"/>
</auto_layout>
<fixed_layout name="2x2" width="4" height="4">
<!--Perimeter of 'io' blocks with 'EMPTY' blocks at corners-->
<row type="io_top" starty="H-1" priority="100"/>
<row type="io_bottom" starty="0" priority="100"/>
<col type="io_left" startx="0" priority="100"/>
<col type="io_right" startx="W-1" priority="100"/>
<corners type="EMPTY" priority="101"/>
<!--Fill with 'clb'-->
<fill type="clb" priority="10"/>
</fixed_layout>
<fixed_layout name="12x12" width="14" height="14">
<!--Perimeter of 'io' blocks with 'EMPTY' blocks at corners-->
<row type="io_top" starty="H-1" priority="100"/>
<row type="io_bottom" starty="0" priority="100"/>
<col type="io_left" startx="0" priority="100"/>
<col type="io_right" startx="W-1" priority="100"/>
<corners type="EMPTY" priority="101"/>
<!--Fill with 'clb'-->
<fill type="clb" priority="10"/>
</fixed_layout>
</layout>
<device>
<!-- VB & JL: Using Ian Kuon's transistor sizing and drive strength data for routing, at 40 nm. Ian used BPTM
models. We are modifying the delay values however, to include metal C and R, which allows more architecture
experimentation. We are also modifying the relative resistance of PMOS to be 1.8x that of NMOS
(vs. Ian's 3x) as 1.8x lines up with Jeff G's data from a 45 nm process (and is more typical of
45 nm in general). I'm upping the Rmin_nmos from Ian's just over 6k to nearly 9k, and dropping
RminW_pmos from 18k to 16k to hit this 1.8x ratio, while keeping the delays of buffers approximately
lined up with Stratix IV.
We are using Jeff G.'s capacitance data for 45 nm (in tech/ptm_45nm).
Jeff's tables list C in for transistors with widths in multiples of the minimum feature size (45 nm).
The minimum contactable transistor is 2.5 * 45 nm, so I need to multiply drive strength sizes in this file
by 2.5x when looking up in Jeff's tables.
The delay values are lined up with Stratix IV, which has an architecture similar to this
proposed FPGA, and which is also 40 nm
C_ipin_cblock: input capacitance of a track buffer, which VPR assumes is a single-stage
4x minimum drive strength buffer. -->
<sizing R_minW_nmos="8926" R_minW_pmos="16067"/>
<!-- The grid_logic_tile_area below will be used for all blocks that do not explicitly set their own (non-routing)
area; set to 0 since we explicitly set the area of all blocks currently in this architecture file.
-->
<area grid_logic_tile_area="0"/>
<chan_width_distr>
<x distr="uniform" peak="1.000000"/>
<y distr="uniform" peak="1.000000"/>
</chan_width_distr>
<switch_block type="wilton" fs="3" sub_type="subset" sub_fs="3"/>
<connection_block input_switch_name="ipin_cblock"/>
</device>
<switchlist>
<!-- VB: the mux_trans_size and buf_size data below is in minimum width transistor *areas*, assuming the purple
book area formula. This means the mux transistors are about 5x minimum drive strength.
We assume the first stage of the buffer is 3x min drive strength to be reasonable given the large
mux transistors, and this gives a reasonable stage ratio of a bit over 5x to the second stage. We assume
the n and p transistors in the first stage are equal-sized to lower the buffer trip point, since it's fed
by a pass transistor mux. We can then reverse engineer the buffer second stage to hit the specified
buf_size (really buffer area) - 16.2x minimum drive nmos and 1.8*16.2 = 29.2x minimum drive.
I then took the data from Jeff G.'s PTM modeling of 45 nm to get the Cin (gate of first stage) and Cout
(diff of second stage) listed below. Jeff's models are in tech/ptm_45nm, and are in min feature multiples.
The minimum contactable transistor is 2.5 * 45 nm, so I need to multiply the drive strength sizes above by
2.5x when looking up in Jeff's tables.
Finally, we choose a switch delay (58 ps) that leads to length 4 wires having a delay equal to that of SIV of 126 ps.
This also leads to the switch being 46% of the total wire delay, which is reasonable. -->
<switch type="mux" name="L1_mux" R="551" Cin=".77e-15" Cout="4e-15" Tdel="58e-12" mux_trans_size="2.630740" buf_size="27.645901"/>
<switch type="mux" name="L2_mux" R="551" Cin=".77e-15" Cout="4e-15" Tdel="58e-12" mux_trans_size="2.630740" buf_size="27.645901"/>
<switch type="mux" name="L4_mux" R="551" Cin=".77e-15" Cout="4e-15" Tdel="58e-12" mux_trans_size="2.630740" buf_size="27.645901"/>
<!--switch ipin_cblock resistance set to yeild for 4x minimum drive strength buffer-->
<switch type="mux" name="ipin_cblock" R="2231.5" Cout="0." Cin="1.47e-15" Tdel="7.247000e-11" mux_trans_size="1.222260" buf_size="auto"/>
</switchlist>
<segmentlist>
<!--- VB & JL: using ITRS metal stack data, 96 nm half pitch wires, which are intermediate metal width/space.
With the 96 nm half pitch, such wires would take 60 um of height, vs. a 90 nm high (approximated as square) Stratix IV tile so this seems
reasonable. Using a tile length of 90 nm, corresponding to the length of a Stratix IV tile if it were square. -->
<!-- GIVE a specific name for the segment! OpenFPGA appreciate that! -->
<segment name="L1" freq="0.10" length="1" type="unidir" Rmetal="101" Cmetal="22.5e-15">
<mux name="L1_mux"/>
<sb type="pattern">1 1</sb>
<cb type="pattern">1</cb>
</segment>
<segment name="L2" freq="0.10" length="2" type="unidir" Rmetal="101" Cmetal="22.5e-15">
<mux name="L2_mux"/>
<sb type="pattern">1 1 1</sb>
<cb type="pattern">1 1</cb>
</segment>
<segment name="L4" freq="0.80" length="4" type="unidir" Rmetal="101" Cmetal="22.5e-15">
<mux name="L4_mux"/>
<sb type="pattern">1 1 1 1 1</sb>
<cb type="pattern">1 1 1 1</cb>
</segment>
</segmentlist>
<directlist>
<direct name="carry_chain" from_pin="clb.cout" to_pin="clb.cin" x_offset="0" y_offset="-1" z_offset="0"/>
<direct name="shift_register" from_pin="clb.reg_out" to_pin="clb.reg_in" x_offset="0" y_offset="-1" z_offset="0"/>
<direct name="scan_chain" from_pin="clb.sc_out" to_pin="clb.sc_in" x_offset="0" y_offset="-1" z_offset="0"/>
</directlist>
<complexblocklist>
<!-- Define input pads begin -->
<pb_type name="io">
<input name="outpad" num_pins="1"/>
<output name="inpad" num_pins="1"/>
<!-- Do NOT add clock pins to I/O here!!! VPR does not build clock network in the way that OpenFPGA can support
If you need to register the I/O, define clocks in the circuit models
These clocks can be handled in back-end
-->
<!-- A mode denotes the physical implementation of an I/O
This mode will be not packable but is mainly used for fabric verilog generation
-->
<mode name="physical" disable_packing="true">
<pb_type name="iopad" blif_model=".subckt io" num_pb="1">
<input name="outpad" num_pins="1"/>
<output name="inpad" num_pins="1"/>
</pb_type>
<interconnect>
<direct name="outpad" input="io.outpad" output="iopad.outpad">
<delay_constant max="1.394e-11" in_port="io.outpad" out_port="iopad.outpad"/>
</direct>
<direct name="inpad" input="iopad.inpad" output="io.inpad">
<delay_constant max="4.243e-11" in_port="iopad.inpad" out_port="io.inpad"/>
</direct>
</interconnect>
</mode>
<!-- IOs can operate as either inputs or outputs.
Delays below come from Ian Kuon. They are small, so they should be interpreted as
the delays to and from registers in the I/O (and generally I/Os are registered
today and that is when you timing analyze them.
-->
<mode name="inpad">
<pb_type name="inpad" blif_model=".input" num_pb="1">
<output name="inpad" num_pins="1"/>
</pb_type>
<interconnect>
<direct name="inpad" input="inpad.inpad" output="io.inpad">
<delay_constant max="4.243e-11" in_port="inpad.inpad" out_port="io.inpad"/>
</direct>
</interconnect>
</mode>
<mode name="outpad">
<pb_type name="outpad" blif_model=".output" num_pb="1">
<input name="outpad" num_pins="1"/>
</pb_type>
<interconnect>
<direct name="outpad" input="io.outpad" output="outpad.outpad">
<delay_constant max="1.394e-11" in_port="io.outpad" out_port="outpad.outpad"/>
</direct>
</interconnect>
</mode>
<power method="ignore"/>
</pb_type>
<!-- Define I/O pads ends -->
<!-- Define general purpose logic block (CLB) begin -->
<!-- -Due to the absence of local routing,
the 4 inputs of fracturable LUT4 are no longer equivalent,
because the 4th input can not be switched when the dual-LUT3 modes are used.
So pin equivalence should be applied to the first 3 inputs only
-->
<pb_type name="clb">
<input name="I0" num_pins="2" equivalent="full"/>
<input name="I0i" num_pins="2" equivalent="none"/>
<input name="I1" num_pins="2" equivalent="full"/>
<input name="I1i" num_pins="2" equivalent="none"/>
<input name="I2" num_pins="2" equivalent="full"/>
<input name="I2i" num_pins="2" equivalent="none"/>
<input name="I3" num_pins="2" equivalent="full"/>
<input name="I3i" num_pins="2" equivalent="none"/>
<input name="I4" num_pins="2" equivalent="full"/>
<input name="I4i" num_pins="2" equivalent="none"/>
<input name="I5" num_pins="2" equivalent="full"/>
<input name="I5i" num_pins="2" equivalent="none"/>
<input name="I6" num_pins="2" equivalent="full"/>
<input name="I6i" num_pins="2" equivalent="none"/>
<input name="I7" num_pins="2" equivalent="full"/>
<input name="I7i" num_pins="2" equivalent="none"/>
<input name="reg_in" num_pins="1"/>
<input name="sc_in" num_pins="1"/>
<input name="cin" num_pins="1"/>
<input name="reset" num_pins="1" is_non_clock_global="true"/>
<output name="O" num_pins="16" equivalent="none"/>
<output name="reg_out" num_pins="1"/>
<output name="sc_out" num_pins="1"/>
<output name="cout" num_pins="1"/>
<clock name="clk" num_pins="1"/>
<!-- Describe fracturable logic element.
Each fracturable logic element has a 6-LUT that can alternatively operate as two 5-LUTs with shared inputs.
The outputs of the fracturable logic element can be optionally registered
-->
<pb_type name="fle" num_pb="8">
<input name="in" num_pins="4"/>
<input name="reg_in" num_pins="1"/>
<input name="sc_in" num_pins="1"/>
<input name="cin" num_pins="1"/>
<input name="reset" num_pins="1"/>
<output name="out" num_pins="2"/>
<output name="reg_out" num_pins="1"/>
<output name="sc_out" num_pins="1"/>
<output name="cout" num_pins="1"/>
<clock name="clk" num_pins="1"/>
<!-- Physical mode definition begin (physical implementation of the fle) -->
<mode name="physical" disable_packing="true">
<pb_type name="fabric" num_pb="1">
<input name="in" num_pins="4"/>
<input name="reg_in" num_pins="1"/>
<input name="sc_in" num_pins="1"/>
<input name="cin" num_pins="1"/>
<input name="reset" num_pins="1"/>
<output name="out" num_pins="2"/>
<output name="reg_out" num_pins="1"/>
<output name="sc_out" num_pins="1"/>
<output name="cout" num_pins="1"/>
<clock name="clk" num_pins="1"/>
<pb_type name="frac_logic" num_pb="1">
<input name="in" num_pins="4"/>
<input name="cin" num_pins="1"/>
<output name="out" num_pins="2"/>
<output name="cout" num_pins="1"/>
<!-- Define LUT -->
<pb_type name="frac_lut4_arith" blif_model=".subckt frac_lut4_arith" num_pb="1">
<input name="in" num_pins="4"/>
<input name="cin" num_pins="1"/>
<output name="lut3_out" num_pins="2"/>
<output name="lut4_out" num_pins="1"/>
<output name="cout" num_pins="1"/>
<delay_constant max="0.3e-9" in_port="frac_lut4_arith.cin" out_port="frac_lut4_arith.lut3_out"/>
<delay_constant max="0.3e-9" in_port="frac_lut4_arith.cin" out_port="frac_lut4_arith.lut4_out"/>
<delay_constant max="0.3e-9" in_port="frac_lut4_arith.cin" out_port="frac_lut4_arith.cout"/>
<delay_constant max="0.3e-9" in_port="frac_lut4_arith.in" out_port="frac_lut4_arith.lut3_out"/>
<delay_constant max="0.3e-9" in_port="frac_lut4_arith.in" out_port="frac_lut4_arith.lut4_out"/>
<delay_constant max="0.3e-9" in_port="frac_lut4_arith.in" out_port="frac_lut4_arith.cout"/>
</pb_type>
<interconnect>
<direct name="direct1" input="frac_logic.in[0:3]" output="frac_lut4_arith.in[0:3]"/>
<direct name="direct2" input="frac_logic.cin" output="frac_lut4_arith.cin"/>
<direct name="direct3" input="frac_lut4_arith.cout" output="frac_logic.cout"/>
<direct name="direct4" input="frac_lut4_arith.lut3_out[1]" output="frac_logic.out[1]"/>
<!-- Xifan Tang: I use out[0] because the output of lut6 in lut6 mode is wired to the out[0] -->
<mux name="mux1" input="frac_lut4_arith.lut4_out frac_lut4_arith.lut3_out[0]" output="frac_logic.out[0]"/>
</interconnect>
</pb_type>
<!-- Define flip-flop with scan-chain capability, DI is the scan-chain data input -->
<pb_type name="ff" blif_model=".subckt scff" num_pb="2">
<input name="D" num_pins="1"/>
<input name="DI" num_pins="1"/>
<input name="reset" num_pins="1"/>
<output name="Q" num_pins="1"/>
<clock name="clk" num_pins="1"/>
<T_setup value="66e-12" port="ff.D" clock="clk"/>
<T_setup value="66e-12" port="ff.DI" clock="clk"/>
<T_setup value="66e-12" port="ff.reset" clock="clk"/>
<T_clock_to_Q max="124e-12" port="ff.Q" clock="clk"/>
</pb_type>
<interconnect>
<direct name="direct1" input="fabric.in" output="frac_logic.in"/>
<direct name="direct2" input="fabric.cin" output="frac_logic.cin"/>
<direct name="direct3" input="fabric.sc_in" output="ff[0].DI"/>
<direct name="direct4" input="ff[0].Q" output="ff[1].DI"/>
<direct name="direct5" input="ff[1].Q" output="fabric.sc_out"/>
<direct name="direct6" input="ff[1].Q" output="fabric.reg_out"/>
<direct name="direct7" input="frac_logic.cout" output="fabric.cout"/>
<complete name="complete1" input="fabric.clk" output="ff[1:0].clk"/>
<complete name="complete2" input="fabric.reset" output="ff[1:0].reset"/>
<mux name="mux1" input="frac_logic.out[0:0] fabric.reg_in" output="ff[0:0].D">
<delay_constant max="25e-12" in_port="frac_logic.out[0:0]" out_port="ff[0:0].D"/>
<delay_constant max="45e-12" in_port="fabric.reg_in" out_port="ff[0:0].D"/>
</mux>
<mux name="mux2" input="frac_logic.out[1:1] ff[0:0].Q" output="ff[1:1].D">
<delay_constant max="25e-12" in_port="frac_logic.out[1:1]" out_port="ff[1:1].D"/>
<delay_constant max="45e-12" in_port="ff[0:0].Q" out_port="ff[1:1].D"/>
</mux>
<mux name="mux3" input="ff[0].Q frac_logic.out[0]" output="fabric.out[0]">
<!-- LUT to output is faster than FF to output on a Stratix IV -->
<delay_constant max="25e-12" in_port="frac_logic.out[0]" out_port="fabric.out[0]"/>
<delay_constant max="45e-12" in_port="ff[0].Q" out_port="fabric.out[0]"/>
</mux>
<mux name="mux4" input="ff[1].Q frac_logic.out[1]" output="fabric.out[1]">
<!-- LUT to output is faster than FF to output on a Stratix IV -->
<delay_constant max="25e-12" in_port="frac_logic.out[1]" out_port="fabric.out[1]"/>
<delay_constant max="45e-12" in_port="ff[1].Q" out_port="fabric.out[1]"/>
</mux>
</interconnect>
</pb_type>
<interconnect>
<direct name="direct1" input="fle.in" output="fabric.in"/>
<direct name="direct2" input="fle.reg_in" output="fabric.reg_in"/>
<direct name="direct3" input="fle.sc_in" output="fabric.sc_in"/>
<direct name="direct4" input="fle.cin" output="fabric.cin"/>
<direct name="direct5" input="fabric.out" output="fle.out"/>
<direct name="direct6" input="fabric.reg_out" output="fle.reg_out"/>
<direct name="direct7" input="fabric.sc_out" output="fle.sc_out"/>
<direct name="direct8" input="fabric.cout" output="fle.cout"/>
<direct name="direct9" input="fle.clk" output="fabric.clk"/>
<direct name="direct10" input="fle.reset" output="fabric.reset"/>
</interconnect>
</mode>
<!-- Physical mode definition end (physical implementation of the fle) -->
<!-- Arithmetic mode definition begin -->
<mode name="arithmetic">
<pb_type name="soft_adder" num_pb="1">
<input name="in" num_pins="4"/>
<input name="cin" num_pins="1"/>
<output name="sumout" num_pins="1"/>
<output name="cout" num_pins="1"/>
<!-- Define special LUT marco to be used as adder -->
<pb_type name="adder_lut4" blif_model=".subckt adder_lut4" num_pb="1">
<input name="cin" num_pins="1"/>
<input name="in" num_pins="4"/>
<output name="lut4_out" num_pins="1"/>
<output name="cout" num_pins="1"/>
<delay_constant max="0.3e-9" in_port="adder_lut4.cin" out_port="adder_lut4.lut4_out"/>
<delay_constant max="0.3e-9" in_port="adder_lut4.cin" out_port="adder_lut4.cout"/>
<delay_constant max="0.3e-9" in_port="adder_lut4.in" out_port="adder_lut4.lut4_out"/>
<delay_constant max="0.3e-9" in_port="adder_lut4.in" out_port="adder_lut4.cout"/>
</pb_type>
<interconnect>
<direct name="direct1" input="soft_adder.in[0:1]" output="adder_lut4.in[0:1]"/>
<direct name="direct2" input="soft_adder.in[3:3]" output="adder_lut4.in[3:3]"/>
<direct name="direct3" input="soft_adder.cin" output="adder_lut4.cin">
<!-- Pack pattern to build an adder chain connection considered by packer -->
<pack_pattern name="chain" in_port="soft_adder.cin" out_port="adder_lut4.cin"/>
</direct>
<direct name="direct4" input="adder_lut4.cout" output="soft_adder.cout">
<!-- Pack pattern to build an adder chain connection considered by packer -->
<pack_pattern name="chain" in_port="adder_lut4.cout" out_port="soft_adder.cout"/>
</direct>
<direct name="direct5" input="adder_lut4.lut4_out" output="soft_adder.sumout[0:0]">
</direct>
<!-- The MUX may not be needed once we limit the number of inputs of adder_lut4 to be 2 -->
<mux name="mux1" input="soft_adder.cin soft_adder.in[2:2]" output="adder_lut4.in[2:2]">
</mux>
</interconnect>
</pb_type>
<interconnect>
<direct name="direct1" input="fle.in" output="soft_adder.in"/>
<direct name="direct2" input="fle.cin" output="soft_adder.cin">
<!-- Pack pattern to build an adder chain connection considered by packer -->
<pack_pattern name="chain" in_port="fle.cin" out_port="soft_adder.cin"/>
</direct>
<direct name="direct3" input="soft_adder.sumout" output="fle.out[0:0]"/>
<direct name="direct4" input="soft_adder.cout" output="fle.cout">
<!-- Pack pattern to build an adder chain connection considered by packer -->
<pack_pattern name="chain" in_port="soft_adder.cout" out_port="fle.cout"/>
</direct>
</interconnect>
</mode>
<!-- Arithmetic mode definition end -->
<!-- Dual 3-LUT mode definition begin -->
<mode name="n2_lut3">
<pb_type name="lut3inter" num_pb="1">
<input name="in" num_pins="3"/>
<output name="out" num_pins="2"/>
<clock name="clk" num_pins="1"/>
<pb_type name="ble3" num_pb="2">
<input name="in" num_pins="3"/>
<output name="out" num_pins="1"/>
<clock name="clk" num_pins="1"/>
<!-- Define the LUT -->
<pb_type name="lut3" blif_model=".names" num_pb="1" class="lut">
<input name="in" num_pins="3" port_class="lut_in"/>
<output name="out" num_pins="1" port_class="lut_out"/>
<!-- LUT timing using delay matrix -->
<!-- These are the physical delay inputs on a Stratix IV LUT but because VPR cannot do LUT rebalancing,
we instead take the average of these numbers to get more stable results
82e-12
173e-12
261e-12
263e-12
398e-12
-->
<delay_matrix type="max" in_port="lut3.in" out_port="lut3.out">
235e-12
235e-12
235e-12
</delay_matrix>
</pb_type>
<!-- Define the flip-flop -->
<pb_type name="ff" blif_model=".latch" num_pb="1" class="flipflop">
<input name="D" num_pins="1" port_class="D"/>
<output name="Q" num_pins="1" port_class="Q"/>
<clock name="clk" num_pins="1" port_class="clock"/>
<T_setup value="66e-12" port="ff.D" clock="clk"/>
<T_clock_to_Q max="124e-12" port="ff.Q" clock="clk"/>
</pb_type>
<interconnect>
<direct name="direct1" input="ble3.in[2:0]" output="lut3[0:0].in[2:0]"/>
<direct name="direct2" input="lut3[0:0].out" output="ff[0:0].D">
<!-- Advanced user option that tells CAD tool to find LUT+FF pairs in netlist -->
<pack_pattern name="ble3" in_port="lut3[0:0].out" out_port="ff[0:0].D"/>
</direct>
<direct name="direct3" input="ble3.clk" output="ff[0:0].clk"/>
<mux name="mux1" input="ff[0:0].Q lut3.out[0:0]" output="ble3.out[0:0]">
<!-- LUT to output is faster than FF to output on a Stratix IV -->
<delay_constant max="25e-12" in_port="lut3.out[0:0]" out_port="ble3.out[0:0]"/>
<delay_constant max="45e-12" in_port="ff[0:0].Q" out_port="ble3.out[0:0]"/>
</mux>
</interconnect>
</pb_type>
<interconnect>
<direct name="direct1" input="lut3inter.in" output="ble3[0:0].in"/>
<direct name="direct2" input="lut3inter.in" output="ble3[1:1].in"/>
<direct name="direct3" input="ble3[1:0].out" output="lut3inter.out"/>
<complete name="complete1" input="lut3inter.clk" output="ble3[1:0].clk"/>
</interconnect>
</pb_type>
<interconnect>
<direct name="direct1" input="fle.in[2:0]" output="lut3inter.in"/>
<direct name="direct2" input="lut3inter.out" output="fle.out"/>
<direct name="direct3" input="fle.clk" output="lut3inter.clk"/>
</interconnect>
</mode>
<!-- Dual 3-LUT mode definition end -->
<!-- 4-LUT mode definition begin -->
<mode name="n1_lut4">
<!-- Define 4-LUT mode -->
<pb_type name="ble4" num_pb="1">
<input name="in" num_pins="4"/>
<output name="out" num_pins="1"/>
<clock name="clk" num_pins="1"/>
<!-- Define LUT -->
<pb_type name="lut4" blif_model=".names" num_pb="1" class="lut">
<input name="in" num_pins="4" port_class="lut_in"/>
<output name="out" num_pins="1" port_class="lut_out"/>
<!-- LUT timing using delay matrix -->
<!-- These are the physical delay inputs on a Stratix IV LUT but because VPR cannot do LUT rebalancing,
we instead take the average of these numbers to get more stable results
82e-12
173e-12
261e-12
263e-12
398e-12
397e-12
-->
<delay_matrix type="max" in_port="lut4.in" out_port="lut4.out">
261e-12
261e-12
261e-12
261e-12
</delay_matrix>
</pb_type>
<!-- Define flip-flop -->
<pb_type name="ff" blif_model=".latch" num_pb="1" class="flipflop">
<input name="D" num_pins="1" port_class="D"/>
<output name="Q" num_pins="1" port_class="Q"/>
<clock name="clk" num_pins="1" port_class="clock"/>
<T_setup value="66e-12" port="ff.D" clock="clk"/>
<T_clock_to_Q max="124e-12" port="ff.Q" clock="clk"/>
</pb_type>
<interconnect>
<direct name="direct1" input="ble4.in" output="lut4[0:0].in"/>
<direct name="direct2" input="lut4.out" output="ff.D">
<!-- Advanced user option that tells CAD tool to find LUT+FF pairs in netlist -->
<pack_pattern name="ble4" in_port="lut4.out" out_port="ff.D"/>
</direct>
<direct name="direct3" input="ble4.clk" output="ff.clk"/>
<mux name="mux1" input="ff.Q lut4.out" output="ble4.out">
<!-- LUT to output is faster than FF to output on a Stratix IV -->
<delay_constant max="25e-12" in_port="lut4.out" out_port="ble4.out"/>
<delay_constant max="45e-12" in_port="ff.Q" out_port="ble4.out"/>
</mux>
</interconnect>
</pb_type>
<interconnect>
<direct name="direct1" input="fle.in" output="ble4.in"/>
<direct name="direct2" input="ble4.out" output="fle.out[0:0]"/>
<direct name="direct3" input="fle.clk" output="ble4.clk"/>
</interconnect>
</mode>
<!-- 4-LUT mode definition end -->
<!-- Define shift register begin -->
<mode name="shift_register">
<pb_type name="shift_reg" num_pb="1">
<input name="reg_in" num_pins="1"/>
<output name="ff_out" num_pins="2"/>
<output name="reg_out" num_pins="1"/>
<clock name="clk" num_pins="1"/>
<pb_type name="ff" blif_model=".latch" num_pb="2" class="flipflop">
<input name="D" num_pins="1" port_class="D"/>
<output name="Q" num_pins="1" port_class="Q"/>
<clock name="clk" num_pins="1" port_class="clock"/>
<T_setup value="66e-12" port="ff.D" clock="clk"/>
<T_clock_to_Q max="124e-12" port="ff.Q" clock="clk"/>
</pb_type>
<interconnect>
<direct name="direct1" input="shift_reg.reg_in" output="ff[0].D"/>
<direct name="direct2" input="ff[0].Q" output="ff[1].D"/>
<direct name="direct3" input="ff[1].Q" output="shift_reg.reg_out"/>
<direct name="direct4" input="ff[0].Q" output="shift_reg.ff_out[0:0]"/>
<direct name="direct5" input="ff[1].Q" output="shift_reg.ff_out[1:1]"/>
<complete name="complete1" input="shift_reg.clk" output="ff.clk"/>
</interconnect>
</pb_type>
<interconnect>
<direct name="direct1" input="fle.reg_in" output="shift_reg.reg_in"/>
<direct name="direct2" input="shift_reg.reg_out" output="fle.reg_out"/>
<direct name="direct3" input="shift_reg.ff_out" output="fle.out"/>
<direct name="direct4" input="fle.clk" output="shift_reg.clk"/>
</interconnect>
</mode>
<!-- Define shift register end -->
</pb_type>
<interconnect>
<!-- We use direct connections to reduce the area to the most
The global local routing is going to compensate the loss in routability
-->
<!-- FIXME: The implicit port definition results in I0[0] connected to
in[2]. Such twisted connection is not expected.
I[0] should be connected to in[0]
-->
<direct name="direct_fle0" input="clb.I0[0:1]" output="fle[0:0].in[0:1]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle0i" input="clb.I0i[0:1]" output="fle[0:0].in[2:3]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle1" input="clb.I1[0:1]" output="fle[1:1].in[0:1]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle1i" input="clb.I1i[0:1]" output="fle[1:1].in[2:3]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle2" input="clb.I2[0:1]" output="fle[2:2].in[0:1]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle2i" input="clb.I2i[0:1]" output="fle[2:2].in[2:3]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle3" input="clb.I3[0:1]" output="fle[3:3].in[0:1]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle3i" input="clb.I3i[0:1]" output="fle[3:3].in[2:3]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle4" input="clb.I4[0:1]" output="fle[4:4].in[0:1]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle4i" input="clb.I4i[0:1]" output="fle[4:4].in[2:3]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle5" input="clb.I5[0:1]" output="fle[5:5].in[0:1]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle5i" input="clb.I5i[0:1]" output="fle[5:5].in[2:3]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle6" input="clb.I6[0:1]" output="fle[6:6].in[0:1]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle6i" input="clb.I6i[0:1]" output="fle[6:6].in[2:3]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle7" input="clb.I7[0:1]" output="fle[7:7].in[0:1]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<direct name="direct_fle7i" input="clb.I7i[0:1]" output="fle[7:7].in[2:3]">
<!-- TODO: Timing should be backannotated from post-PnR results -->
</direct>
<complete name="clks" input="clb.clk" output="fle[7:0].clk">
</complete>
<complete name="resets" input="clb.reset" output="fle[7:0].reset">
</complete>
<!-- This way of specifying direct connection to clb outputs is important because this architecture uses automatic spreading of opins.
By grouping to output pins in this fashion, if a logic block is completely filled by 6-LUTs,
then the outputs those 6-LUTs take get evenly distributed across all four sides of the CLB instead of clumped on two sides (which is what happens with a more
naive specification).
-->
<direct name="clbouts1" input="fle[3:0].out[0:1]" output="clb.O[7:0]"/>
<direct name="clbouts2" input="fle[7:4].out[0:1]" output="clb.O[15:8]"/>
<!-- Shift register chain links -->
<direct name="shift_register_in" input="clb.reg_in" output="fle[0:0].reg_in">
<!-- Put all inter-block carry chain delay on this one edge -->
<delay_constant max="0.16e-9" in_port="clb.reg_in" out_port="fle[0:0].reg_in"/>
<!--pack_pattern name="chain" in_port="clb.reg_in" out_port="fle[0:0].reg_in"/-->
</direct>
<direct name="shift_register_out" input="fle[7:7].reg_out" output="clb.reg_out">
<!--pack_pattern name="chain" in_port="fle[7:7].reg_out" out_port="clb.reg_out"/-->
</direct>
<direct name="shift_register_link" input="fle[6:0].reg_out" output="fle[7:1].reg_in">
<!--pack_pattern name="chain" in_port="fle[6:0].reg_out" out_port="fle[7:1].reg_in"/-->
</direct>
<!-- Scan chain links -->
<direct name="scan_chain_in" input="clb.sc_in" output="fle[0:0].sc_in">
<!-- Put all inter-block carry chain delay on this one edge -->
<delay_constant max="0.16e-9" in_port="clb.sc_in" out_port="fle[0:0].sc_in"/>
</direct>
<direct name="scan_chain_out" input="fle[7:7].sc_out" output="clb.sc_out">
</direct>
<direct name="scan_chain_link" input="fle[6:0].sc_out" output="fle[7:1].sc_in">
</direct>
<!-- Carry chain links -->
<direct name="carry_chain_in" input="clb.cin" output="fle[0:0].cin">
<!-- Put all inter-block carry chain delay on this one edge -->
<pack_pattern name="chain" in_port="clb.cin" out_port="fle[0:0].cin"/>
<delay_constant max="0.16e-9" in_port="clb.cin" out_port="fle[0:0].cin"/>
</direct>
<direct name="carry_chain_out" input="fle[7:7].cout" output="clb.cout">
<pack_pattern name="chain" in_port="fle[7:7].cout" out_port="clb.cout"/>
</direct>
<direct name="carry_chain_link" input="fle[6:0].cout" output="fle[7:1].cin">
<pack_pattern name="chain" in_port="fle[6:0].cout" out_port="fle[7:1].cin"/>
</direct>
</interconnect>
<!-- Every input pin is driven by 15% of the tracks in a channel, every output pin is driven by 10% of the tracks in a channel -->
<!-- Place this general purpose logic block in any unspecified column -->
</pb_type>
<!-- Define general purpose logic block (CLB) ends -->
</complexblocklist>
</architecture>