Merge remote-tracking branch 'lnis_origin/dev' into ganesh_dev
This commit is contained in:
commit
937ebd1b85
|
@ -1,5 +1,10 @@
|
|||
language: cpp
|
||||
|
||||
# cache results
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.ccache
|
||||
|
||||
# Currently sudo is not required, NO ENV is used
|
||||
|
||||
# Supported Operating systems
|
||||
|
|
|
@ -10,8 +10,8 @@ if [[ $TRAVIS_OS_NAME == 'osx' ]]; then
|
|||
#make
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_BUILD_TYPE=debug -DENABLE_VPR_GRAPHICS=off
|
||||
make -j2
|
||||
cmake .. -DCMAKE_BUILD_TYPE=debug -DENABLE_VPR_GRAPHICS=off
|
||||
make -j16
|
||||
alias python3.5="python3"
|
||||
ln -s /opt/local/bin/python3 /opt/local/bin/python3.5
|
||||
else
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
cmake_minimum_required(VERSION 2.8.12)
|
||||
|
||||
find_program(CCACHE_FOUND ccache)
|
||||
if(CCACHE_FOUND)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
|
||||
endif(CCACHE_FOUND)
|
||||
|
||||
if (${CMAKE_VERSION} VERSION_GREATER "3.8")
|
||||
#For cmake >= 3.9 INTERPROCEDURAL_OPTIMIZATION behaviour we need to explicitly
|
||||
#set the cmake policy version number
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
Circuit model examples
|
||||
======================
|
||||
The next subsections are dedicated to detailed examples of each circuit model type. Through these examples awe give a global overview of the different implementations which are available for the user.
|
||||
The next subsections are dedicated to detailed examples of each circuit model type. Through these examples, we give a global overview of the different implementations which are available for the user.
|
||||
|
||||
Inverters and Buffers
|
||||
---------------------
|
||||
|
@ -17,11 +17,11 @@ Inverters and Buffers
|
|||
|
||||
* design_technology:
|
||||
|
||||
* **topology:** [inverter|buffer]. Specify the type of this component, can be either an inverter or a buffer.
|
||||
* **topology:** [``inverter`` | ``buffer``]. Specify the type of this component, can be either an inverter or a buffer.
|
||||
|
||||
* **size:** Specify the driving strength of inverter/buffer. For a buffer, the size is the driving strength of the inverter at the second level. We consider a two-level structure for a buffer here. The support for multi-level structure of a buffer will be introduced in the tapered options.
|
||||
|
||||
* **tapered:** [on|off]. Define if the buffer is a tapered (multi-level) buffer. *If "on" the following parameter are required.*
|
||||
* **tapered:** [``on`` | ``off``]. Define if the buffer is a tapered (multi-level) buffer. When ``on`` is defined, the following parameter are required.*
|
||||
|
||||
* **tap_drive_level:** Define the number of levels of a tapered buffer. This parameter is valid only when tapered is turned on.
|
||||
|
||||
|
@ -54,6 +54,21 @@ This example shows:
|
|||
* Size of 1 for the output strength
|
||||
* The tapered parameter is not declared and is off by default
|
||||
|
||||
**Power-gated Inverter x1 example**
|
||||
|
||||
The XML code describing an inverter which can be power-gated by the control signals ``EN`` and ``ENB`` :
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<circuit_model type="inv_buf" name="INVTX1" prefix="INVTX1">
|
||||
<design_technology type="cmos" topology="inverter" size="3" tapered="off" power_gated="true"/>
|
||||
<port type="input" prefix="in" size="1" lib_name="I"/>
|
||||
<port type="input" prefix="EN" size="1" lib_name="EN" is_global="true" default_val="0" is_config_enable="true"/>
|
||||
<port type="input" prefix="ENB" size="1" lib_name="ENB" is_global="true" default_val="1" is_config_enable="true"/>
|
||||
<port type="output" prefix="out" size="1" lib_name="Z"/>
|
||||
</circuit_model>
|
||||
|
||||
.. note:: For power-gated inverters: all the control signals must be set as ``config_enable`` so that the testbench generation will generate testing waveforms. If the power-gated inverters are auto-generated , all the ``config_enable`` signals must be ``global`` signals as well. If the pwoer-gated inverters come from user-defined netlists, restrictions on ``global`` signals are free.
|
||||
|
||||
**Buffer x2 example**
|
||||
|
||||
|
@ -132,7 +147,7 @@ Pass-gate Logic
|
|||
|
||||
* design_technology:
|
||||
|
||||
* **topology:** [transmission_gate|pass_transistor]. The transmission gate consists of a NMOS transistor and a PMOS transistor. The pass transistor consists of a NMOS transistor.
|
||||
* **topology:** [``transmission_gate`` | ``pass_transistor``]. The transmission gate consists of a NMOS transistor and a PMOS transistor. The pass transistor consists of a NMOS transistor.
|
||||
|
||||
* **nmos_size:** the size of NMOS transistor in a transmission gate or pass_transistor, expressed in terms of the min_width defined in XML node <transistors>.
|
||||
|
||||
|
@ -163,7 +178,7 @@ The XML code describing this pass-gate is:
|
|||
</circuit_model>
|
||||
|
||||
This example shows:
|
||||
* Topology is **transmission_gate**, which means the component need entries for each transistor gate (pmos and nmos)
|
||||
* Topology is ``transmission_gate``, which means the component need entries for each transistor gate (pmos and nmos)
|
||||
* 3 inputs considered, 1 for signal and 2 to control the transistors gates
|
||||
* No input or output buffer used, these parameters can be uninitialized
|
||||
|
||||
|
@ -191,7 +206,7 @@ The XML code describing this pass-gate is:
|
|||
</circuit_model>
|
||||
|
||||
This example shows:
|
||||
* Topology is **pass_transistor**, which means the component need an entry for the transistor gate (nmos)
|
||||
* Topology is ``pass_transistor``, which means the component need an entry for the transistor gate (nmos)
|
||||
* 2 inputs considered, 1 for signal and 1 to control the transistor gate
|
||||
* No input or output buffer used, these parameters can be uninitialized
|
||||
|
||||
|
@ -335,7 +350,7 @@ If we arbitrarily fix the number of Mux entries at 4, the following code could i
|
|||
**This example shows:**
|
||||
* The tree topology, 4 entries split in 2 2-to-1 Muxes then another one make the final selection.
|
||||
* The possibility to select the input or output buffers
|
||||
* The number of entries parametrized by *size* in input port-type.
|
||||
* The number of entries parametrized by ``size`` in input port-type.
|
||||
|
||||
Look-Up Tables
|
||||
--------------
|
||||
|
@ -375,9 +390,9 @@ Instructions of defining design parameters:
|
|||
|
||||
* **pass_gate_logic:** Specify the pass-gates of the internal multiplexer, the same as the multiplexers.
|
||||
|
||||
* **port:** 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. For input ports, the keyword tri_state_map aims to 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. The circuit_model_name of input port is used to specify which logic gates will be used 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. For output ports, the keyword lut_frac_level is used to 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. The keyword lut_output_mask describes 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. Note that the size of the output port should be consistent to the length of lut_output_mask.
|
||||
* **port:** 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. For input ports, the keyword tri_state_map aims to 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. The circuit_model_name of input port is used to specify which logic gates will be used 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. For output ports, the keyword lut_frac_level is used to 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. The keyword lut_output_mask describes 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. Note that the size of the output port should be consistent to the length of lut_output_mask.
|
||||
|
||||
* **SRAM port for mode selection:** To enable switch between different operating modes, the SRAM bits of a fracturable LUT consists of two parts: configuration memory and mode selecting. The SRAM port for mode selection is specified through the XML keyword mode_select. Note that the size of such SRAM port should be consistent to the number of 1s or 0s in the tri_state_map.
|
||||
* **SRAM port for mode selection:** To enable switch between different operating modes, the SRAM bits of a fracturable LUT consists of two parts: configuration memory and mode selecting. The SRAM port for mode selection is specified through the XML keyword mode_select. Note that the size of such SRAM port should be consistent to the number of 1s or 0s in the ``tri_state_map``.
|
||||
|
||||
**LUT example**
|
||||
|
||||
|
@ -431,9 +446,11 @@ Flip-Flops
|
|||
|
||||
Instructions of defining design parameters:
|
||||
|
||||
* **circuit_model type:** can be ff or scff. FF is typical Flip-Flop, SCFF is Scan-Chain Flip-Flop
|
||||
* **circuit_model type:** can be ``ff`` or ``scff``. FF is typical Flip-Flop, SCFF is Scan-Chain Flip-Flop
|
||||
|
||||
* **port:** three types of ports (input, output and clock) should be defined. If the user provides a customized Verilog/SPICE netlist, the bandwidth of ports should be defined to the same as the Verilog/SPICE netlist.
|
||||
* **port:** three types of ports (``input``, ``output`` and ``clock``) should be defined. If the user provides a customized Verilog/SPICE netlist, the bandwidth of ports should be defined to the same as the Verilog/SPICE netlist.
|
||||
|
||||
.. note:: In a valid FPGA architecture, users should provide at least either a SCFF or a SRAM, so that the configurations can loaded to core logic.
|
||||
|
||||
**FF example**
|
||||
|
||||
|
@ -513,15 +530,15 @@ Hard Logics
|
|||
|
||||
Instructions of defining design parameters:
|
||||
|
||||
* **port:** two types of ports (input and output) should be defined. If the user provides a user-defined Verilog/SPICE netlist, the bandwidth of ports should be defined to the same as the Verilog/SPICE netlist.
|
||||
* **port:** two types of ports (``input`` and ``output``) should be defined. If the user provides a user-defined Verilog/SPICE netlist, the bandwidth of ports should be defined to the same as the Verilog/SPICE netlist.
|
||||
|
||||
Routing Wire Segments
|
||||
---------------------
|
||||
|
||||
FPGA-Verilog/SPICE provides two types of Verilog/SPICE models for the wire segments in FPGA architecture:
|
||||
|
||||
* One type is called **wire**, which targets the local wires inside the logic blocks. The wire has one input and one output, directly connecting the output of a driver and the input of the downstream unit, respectively
|
||||
* The other type is called **chan_wire**, especially targeting the channel wires. The channel wires have one input and two outputs, one of which is connected to the inputs of Connection Boxes while the other is connected to the inputs of Switch Boxes. Two outputs are created because from the view of layout, the inputs of Connection Boxes are typically connected to the middle point of channel wires, which has less parasitic resistances and capacitances than connected to the ending point.
|
||||
* One type is called ``wire``, which targets the local wires inside the logic blocks. The wire has one input and one output, directly connecting the output of a driver and the input of the downstream unit, respectively
|
||||
* The other type is called ``chan_wire``, especially targeting the channel wires. The channel wires have one input and two outputs, one of which is connected to the inputs of Connection Boxes while the other is connected to the inputs of Switch Boxes. Two outputs are created because from the view of layout, the inputs of Connection Boxes are typically connected to the middle point of channel wires, which has less parasitic resistances and capacitances than connected to the ending point.
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
|
@ -540,13 +557,13 @@ FPGA-Verilog/SPICE provides two types of Verilog/SPICE models for the wire segme
|
|||
|
||||
Instructions of defining design parameters:
|
||||
|
||||
* **type:** can be [wire|chan_wire]. The Verilog/SPICE model wire targets the local wire inside the logic block while the chan_wire targets the channel wires in global routing.
|
||||
* **type:** can be [``wire`` | ``chan_wire``]. The Verilog/SPICE model wire targets the local wire inside the logic block while the chan_wire targets the channel wires in global routing.
|
||||
|
||||
* **port:** two types of ports (input and output) 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.
|
||||
* **port:** two types of ports (``input`` and ``output``) 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.
|
||||
|
||||
* **wire_param:**
|
||||
|
||||
* **model_type:** can be [pi|T], corresponding to the π-type and T-type RC wire models.
|
||||
* **model_type:** can be [``pi`` | ``T``], corresponding to the π-type and T-type RC wire models.
|
||||
* **res_val:** specify the total resistance of the wire
|
||||
* **cap_val:** specify the total capacitance of the wire.
|
||||
* **level:** specify the number of levels of the RC wire model.
|
||||
|
@ -575,7 +592,7 @@ The code describing this wire is:
|
|||
</circuit_model>
|
||||
|
||||
**This example shows**
|
||||
* How to use the *wire_param* for a π-type RC wire model
|
||||
* How to use the ``wire_param`` for a π-type RC wire model
|
||||
* How to use this circuit_model to auto-generate the Verilog/SPICE netlist
|
||||
|
||||
I/O pads
|
||||
|
@ -600,7 +617,7 @@ I/O pads
|
|||
|
||||
Instructions of defining design parameters:
|
||||
|
||||
* **port:** two types of ports (input and output) should be defined. If the user provides a user-defined Verilog/SPICE netlist, the bandwidth of ports should be defined to the same as the Verilog/SPICE netlist.
|
||||
* **port:** four types of ports (``input``, ``output``, ``inout`` and ``sram``) should be defined. If the user provides a user-defined Verilog/SPICE netlist, the bandwidth of ports should be defined to the same as the Verilog/SPICE netlist.
|
||||
|
||||
**IO-pad example**
|
||||
|
||||
|
@ -628,6 +645,6 @@ The code describing this IO-Pad is:
|
|||
|
||||
**This example shows**
|
||||
|
||||
* The association of the verilog netlist file *io.v*
|
||||
* The association of the verilog netlist file ``io.v``
|
||||
* The inout pad port_type, which means as inout as output.
|
||||
* The instantiation of a SCFF as sram
|
||||
|
|
|
@ -13,24 +13,24 @@ Define circuit_models
|
|||
|
||||
<module_circuit_models>
|
||||
<circuit_model type="string" name="string" prefix="string" is_default="int"
|
||||
spice_netlist="string" verilog_netlist="string" dump_structural_verilog="string">
|
||||
circuit_netlist="string" verilog_netlist="string" dump_structural_verilog="string">
|
||||
<transistor-level circuit_design_features="developped_further" />
|
||||
</circuit_model>
|
||||
</module_circuit_models>
|
||||
|
||||
* **module_circuit_models**: the father node for all the spice models. All the spice models should be defined under this XML node.
|
||||
* **module_circuit_models**: the father node for all the circuit models. All the circuit models should be defined under this XML node.
|
||||
|
||||
* **circuit_model**: the child node defining transistor-level modeling parameters.
|
||||
|
||||
* **type**: can be [ inv_buf | pass_gate | mux | wire | chan_wire | sram | lut | ff | scff | hard_logic | iopad ]. Specify the type of circuit model. The provided types cover all the modules in FPGAs. For the circuit models in the type of mux/wire/chan_wire/lut, FPGA-Verilog/SPICE can auto-generate Verilog/SPICE netlists. For the rest, FPGA-Verilog/SPICE requires a user-defined Verilog/SPICE netlist.
|
||||
* **type**: can be [ ``inv_buf`` | ``pass_gate`` | ``gate`` | ``mux`` | ``wire`` | ``chan_wire`` | ``sram`` | ``lut`` | ``ff`` | ``scff`` | ``hard_logic`` | ``iopad`` ]. Specify the type of circuit model. The provided types cover all the modules in FPGAs. For the circuit models in the type of mux/wire/chan_wire/lut, FPGA-Verilog/SPICE can auto-generate Verilog/SPICE netlists. For the rest, FPGA-Verilog/SPICE requires a user-defined Verilog/SPICE netlist.
|
||||
|
||||
* **name**: define the name of this circuit model. The name should be unique and will be used to create the sub-circuit of the circuit model in Verilog/SPICE netlists. Note that for a customized Verilog/SPICE netlist, the name defined here should be the name of the top-level sub-circuit in the customized Verilog/SPICE netlist. FPGA-Verilog/SPICE will check if the given name is conflicted with any reserved words.
|
||||
|
||||
* **prefix**: specify the name of the circuit_model to shown in the auto-generated Verilog/SPICE netlists. The prefix can be the same as the name defined above. And again, the prefix should be unique.
|
||||
|
||||
* **is_default**: can be [1|0], corresponding to [true|false] respectively. Specify this circuit model is the default one for some modules, such as multiplexers. If a module is not linked to any spice model by users, FPGA-Verilog/SPICE will find the default spice model defined in the same type and link. For a spice model type, only one spice model can be set as default.
|
||||
* **is_default**: can be [``1`` | ``0``], corresponding to [``true`` | ``false``] respectively. Specify this circuit model is the default one for some modules, such as multiplexers. If a module is not linked to any circuit model by users, FPGA-Verilog/SPICE will find the default circuit model defined in the same type and link. For a circuit model type, only one circuit model can be set as default.
|
||||
|
||||
* **spice_netlist**: specify the path and file name of a customized Verilog/SPICE netlist. For some modules such as SRAMs, FFs, inpads, and outpads, FPGA-Verilog/SPICE does not support auto-generation of the transistor-level sub-circuits because their circuit design is highly dependent on the technology nodes. These circuit designs should be specified by users. For the other modules that can be auto-generated by FPGA-Verilog/SPICE, the user can also define a custom netlist. Multiplexers cannot be user-defined.
|
||||
* **circuit_netlist**: specify the path and file name of a customized Verilog/SPICE netlist. For some modules such as SRAMs, FFs, inpads, and outpads, FPGA-Verilog/SPICE does not support auto-generation of the transistor-level sub-circuits because their circuit design is highly dependent on the technology nodes. These circuit designs should be specified by users. For the other modules that can be auto-generated by FPGA-Verilog/SPICE, the user can also define a custom netlist. Multiplexers cannot be user-defined.
|
||||
|
||||
* **verilog_netlist**: specify the path and file name of a customized Verilog netlist. For some modules such as SRAMs, FFs, inpad and outpads, FPGA-Verilog/SPICE does not support auto-generation of the transistor-level sub-circuits because their circuit design is highly dependent on the technology nodes. These circuit designs should be specified by users. For the other modules that can be auto-generated by FPGA-Verilog/SPICE, the user can also define a custom netlist. Multiplexers cannot be user-defined.
|
||||
|
||||
|
@ -40,7 +40,7 @@ Define circuit_models
|
|||
|
||||
.. note:: The user-defined netlists, such as LUTs, the decoding methodology should comply with the auto-generated LUTs (See Section 4.5)
|
||||
|
||||
.. note:: Under the XML node circuit_model, the features of transistor-level designs can be defined. In the following table, we show the common features supported for all the modules. Then, we will introduce unique features supported only for some spice models types.
|
||||
.. note:: Under the XML node circuit_model, the features of transistor-level designs can be defined. In the following table, we show the common features supported for all the modules. Then, we will introduce unique features supported only for some circuit models types.
|
||||
|
||||
|
||||
Transistor level
|
||||
|
@ -73,13 +73,13 @@ Transistor level
|
|||
|
||||
* pass_gate_logic: defined the parameters in pass-gates, which are used in building multiplexers and LUTs.
|
||||
|
||||
* **circuit_model_name:** Specify the name of the circuit model which is used to implement transmission gate, the type of specified spice model should be pass_gate.
|
||||
* **circuit_model_name:** Specify the name of the circuit model which is used to implement transmission gate, the type of specified circuit model should be pass_gate.
|
||||
|
||||
* port: define the port list of a circuit model.
|
||||
|
||||
* **type:** can be [input|output|sram|clock]. For programmable modules, such as multiplexers and LUTs, SRAM ports should be defined. For registers, such as FFs and memory banks, clock ports should be defined.
|
||||
|
||||
* **prefix:** the name of the port. Each port will be shown as <prefix>[i] in Verilog/SPICE netlists.
|
||||
* **prefix:** the name of the port. Each port will be shown as ``<prefix>[i]`` in Verilog/SPICE netlists.
|
||||
|
||||
* **size:** bandwidth of the port.
|
||||
|
||||
|
@ -87,14 +87,14 @@ Transistor level
|
|||
|
||||
* **circuit_model_name:** only valid when the type of port is sram. Specify the name of the circuit model which is connected to this port.
|
||||
|
||||
* **mode_select:** can be either true or false. Specify if this port controls the mode switching in a configurable logic block. Only valid when the type of this port is sram. (A configurable logic block can operate in different modes, which is controlled by SRAM bits.)
|
||||
* **mode_select:** can be either ``true`` or ``false``. Specify if this port controls the mode switching in a configurable logic block. Only valid when the type of this port is sram. (A configurable logic block can operate in different modes, which is controlled by SRAM bits.)
|
||||
|
||||
* **is_global:** can be either true or false. Specify if this port is a global port, which will be routed globally. Note that when multiple global ports are defined with the same name, these global ports will be short-wired together.
|
||||
* **is_global:** can be either ``true`` or ``false``. Specify if this port is a global port, which will be routed globally. Note that when multiple global ports are defined with the same name, these global ports will be short-wired together.
|
||||
|
||||
* **is_set:** can be either true or false. Specify if this port controls a set signal. Only valid when is_global is true. All the set ports are connected to global set voltage stimuli in testbenches.
|
||||
* **is_set:** can be either ``true`` or ``false``. Specify if this port controls a set signal. Only valid when ``is_global`` is true. All the set ports are connected to global set voltage stimuli in testbenches.
|
||||
|
||||
* **is_reset:** can be either true or false. Specify if this port controls a reset signal. Only valid when is_global is true. All the reset ports are connected to a global reset voltage stimuli in testbenches.
|
||||
* **is_reset:** can be either ``true`` or ``false``. Specify if this port controls a reset signal. Only valid when ``is_global`` is true. All the reset ports are connected to a global reset voltage stimuli in testbenches.
|
||||
|
||||
* **is_config_enable:** can be either true or false. Only valid when is_global is true. Specify if this port controls a configuration-enable signal. This port is only enabled during FPGA configuration, and always disabled during FPGA operation. All the config_enable ports are connected to global configuration-enable voltage stimuli in testbenches.
|
||||
* **is_config_enable:** can be either ``true`` or ``false``. Only valid when ``is_global`` is true. Specify if this port controls a configuration-enable signal. This port is only enabled during FPGA configuration, and always disabled during FPGA operation. All the ``config_enable`` ports are connected to global configuration-enable voltage stimuli in testbenches.
|
||||
|
||||
.. note:: Different types of ``circuit_model`` have different XML syntax, with which users can highly customize their circuit topologies. See refer to examples of ``circuit_model`` for more details.
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
results
|
|
@ -1,6 +0,0 @@
|
|||
# Circuit Names, fixed routing channel width,
|
||||
# PID/*.v, 120
|
||||
up_counter/*.v, 30
|
||||
# MultiBitAdder/*.v, 30
|
||||
# i2c_master_top/*.v, 40
|
||||
# asynch_fifo/*.v, 30
|
|
@ -1,32 +0,0 @@
|
|||
# Standard Configuration Example
|
||||
[dir_path]
|
||||
script_base = OPENFPGAPATHKEYWORD/fpga_flow/scripts/
|
||||
benchmark_dir = OPENFPGAPATHKEYWORD/fpga_flow/benchmarks/Verilog/lattice_ultra_example
|
||||
# yosys_path = OPENFPGAPATHKEYWORD/yosys/yosys
|
||||
yosys_path = /research/ece/lnis/USERS/alacchi/Current_release/branch_multimode/OpenFPGA/yosys/yosys
|
||||
odin2_path = OPENFPGAPATHKEYWORD/fpga_flow/not_used_atm/odin2.exe
|
||||
cirkit_path = OPENFPGAPATHKEYWORD/fpga_flow/not_used_atm/cirkit
|
||||
abc_path = OPENFPGAPATHKEYWORD/yosys/yosys-abc
|
||||
abc_mccl_path = OPENFPGAPATHKEYWORD/abc_with_bb_support/abc
|
||||
abc_with_bb_support_path = OPENFPGAPATHKEYWORD/abc_with_bb_support/abc
|
||||
mpack1_path = OPENFPGAPATHKEYWORD/fpga_flow/not_used_atm/mpack1
|
||||
m2net_path = OPENFPGAPATHKEYWORD/fpga_flow/not_used_atm/m2net
|
||||
mpack2_path = OPENFPGAPATHKEYWORD/fpga_flow/not_used_atm/mpack2
|
||||
vpr_path = OPENFPGAPATHKEYWORD/vpr7_x2p/vpr/vpr
|
||||
rpt_dir = /var/tmp/Openfpga/results
|
||||
ace_path = OPENFPGAPATHKEYWORD/ace2/ace
|
||||
|
||||
[flow_conf]
|
||||
#Flow Types standard|mpack2|mpack1|vtr_standard|vtr|yosys_vpr
|
||||
flow_type = yosys_vpr
|
||||
vpr_arch = OPENFPGAPATHKEYWORD/fpga_flow/arch/winbond90/k6_N10_rram_memory_bank_SC_winbond90.xml
|
||||
mpack1_abc_stdlib = Not_Required
|
||||
m2net_conf = Not_Required
|
||||
mpack2_arch = Not_Required
|
||||
power_tech_xml = OPENFPGAPATHKEYWORD/fpga_flow/tech/winbond90nm/winbond90nm_power_properties.xml
|
||||
|
||||
[csv_tags]
|
||||
mpack1_tags = Global mapping efficiency: | efficiency: | occupancy wo buf: | efficiency wo buf:
|
||||
mpack2_tags = BLE Number: | BLE Fill Rate:
|
||||
vpr_tags = Netlist clb blocks: | Final critical path: | Total logic delay: | total net delay: | Total routing area: | Total used logic block area: | Total wirelength: | Packing took | Placement took | Routing took | Average net density: | Median net density: | Recommend no. of clock cycles:
|
||||
vpr_power_tags = PB Types | Routing | Switch Box | Connection Box | Primitives | Interc Structures | lut6 | ff
|
|
@ -1,6 +0,0 @@
|
|||
# Circuit Names, fixed routing channel width,
|
||||
# PID/*.v, 120
|
||||
up_counter/*.v, 30
|
||||
# MultiBitAdder/*.v, 30
|
||||
# i2c_master_top/*.v, 40
|
||||
# asynch_fifo/*.v, 30
|
|
@ -4,24 +4,7 @@ set -e
|
|||
# Make sure a clear start
|
||||
default_task='lattice_benchmark'
|
||||
pwd_path="$PWD"
|
||||
|
||||
# ========================= Read command argument =========================
|
||||
usage() { echo "Usage: $0 [-b <benchmark_name>] [-s] run spice only [-p] run vpr only " 1>&2; exit 1; }
|
||||
|
||||
while getopts ":b:vpr:spice:" o; do
|
||||
case "${o}" in
|
||||
b)
|
||||
bench=${OPTARG};;
|
||||
v)
|
||||
vpr=1;;
|
||||
s)
|
||||
spice=1;;
|
||||
esac
|
||||
done
|
||||
# ==========================================================================
|
||||
|
||||
task_name=${bench:-$default_task} # run task defined in argument else run default task
|
||||
echo "Running task ${task_name}"
|
||||
task_name=${1:-$default_task} # run task defined in argument else run default task
|
||||
config_file="$PWD/configs/${task_name}.conf"
|
||||
bench_txt="$PWD/benchmarks/List/${task_name}.txt"
|
||||
rpt_file="$PWD/csv_rpts/fpga_spice/${task_name}.csv"
|
||||
|
@ -33,45 +16,22 @@ config_file_final=$(echo ${config_file/.conf/_final.conf})
|
|||
|
||||
# List of argument passed to FPGA flow
|
||||
vpr_config_flags=(
|
||||
"-conf ${config_file_final}"
|
||||
"-benchmark ${bench_txt}"
|
||||
"-rpt ${rpt_file}"
|
||||
"-vpr_fpga_verilog_dir ${verilog_path}"
|
||||
"-N 10"
|
||||
"-K 6"
|
||||
"-remove_designs"
|
||||
"-ace_d 0.5"
|
||||
"-multi_thread 1"
|
||||
# "-route_chan_width 10"
|
||||
"-vpr_fpga_x2p_rename_illegal_port"
|
||||
"-vpr_fpga_verilog"
|
||||
"-vpr_fpga_bitstream_generator"
|
||||
"-vpr_fpga_verilog_print_autocheck_top_testbench"
|
||||
"-vpr_fpga_verilog_include_timing"
|
||||
"-vpr_fpga_verilog_include_signal_init"
|
||||
"-vpr_fpga_verilog_formal_verification_top_netlist"
|
||||
"-fix_route_chan_width"
|
||||
# "-vpr_fpga_verilog_include_icarus_simulator"
|
||||
"-power"
|
||||
"-vpr_fpga_spice spice_taskfile"
|
||||
"-vpr_fpga_spice_simulator_path /uusoc/facility/cad_tools/Synopsys/lnis_tools/hspice/P-2019.06/hspice/bin/"
|
||||
# "-vpr_fpga_spice_print_top_tb"
|
||||
"-vpr_fpga_spice_print_component_tb",
|
||||
# "-vpr_fpga_spice_print_grid_tb"
|
||||
)
|
||||
|
||||
spice_config_flags=(
|
||||
"-conf /research/ece/lnis/USERS/alacchi/Ganesh/OpenFPGA/fpga_flow/vpr_fpga_spice_conf/sample.conf"
|
||||
"-task /research/ece/lnis/USERS/alacchi/Ganesh/OpenFPGA/fpga_flow/scripts/spice_taskfile_yosys_vpr.txt"
|
||||
"-rpt ${rpt_file/.csv/_spice_result.csv}"
|
||||
"-multi_thread 10"
|
||||
# "-parse_grid_tb"
|
||||
"-parse_pb_mux_tb"
|
||||
"-parse_cb_mux_tb"
|
||||
"-parse_sb_mux_tb"
|
||||
"-parse_lut_tb"
|
||||
# "-parse_hardlogic_tb"
|
||||
'-N 10'
|
||||
'-K 6'
|
||||
'-ace_d 0.5'
|
||||
'-multi_thread 1'
|
||||
'-vpr_fpga_x2p_rename_illegal_port'
|
||||
'-vpr_fpga_verilog'
|
||||
'-vpr_fpga_bitstream_generator'
|
||||
'-vpr_fpga_verilog_print_autocheck_top_testbench'
|
||||
'-vpr_fpga_verilog_include_timing'
|
||||
'-vpr_fpga_verilog_include_signal_init'
|
||||
'-vpr_fpga_verilog_formal_verification_top_netlist'
|
||||
'-fix_route_chan_width'
|
||||
'-vpr_fpga_verilog_include_icarus_simulator'
|
||||
'-power'
|
||||
)
|
||||
# vpr_config_flags+=("$@") # Append provided arguments
|
||||
|
||||
#=============== Argument Sanity Check =====================
|
||||
#Check if script running in correct (OpenFPGA/fpga_flow) folder
|
||||
|
@ -103,19 +63,9 @@ sed 's/OPENFPGAPATHKEYWORD/'"${OPENFPGAPATHKEYWORD}"'/g' $config_file >$config_f
|
|||
#==================Clean result, change directory and execute ===============
|
||||
cd ${pwd_path}/scripts
|
||||
|
||||
if [[ -n "$vpr" ]]; then
|
||||
# Create echo and execute VPR command
|
||||
command="perl fpga_flow.pl $(echo ${vpr_config_flags[@]})"
|
||||
echo -e "\n* * * * * * * * * * * \n"${command} "\n* * * * * * * * * * * \n"
|
||||
eval ${command}
|
||||
fi
|
||||
# perl fpga_flow.pl -conf ${config_file_final} -benchmark ${bench_txt} -rpt ${rpt_file} -vpr_fpga_verilog_dir $verilog_path $(echo "${vpr_config_flags[@]}")
|
||||
|
||||
if [[ -n "$spice" ]]; then
|
||||
# Create echo and SPICE Execution
|
||||
command="perl run_fpga_spice.pl $(echo ${spice_config_flags[@]})"
|
||||
echo -e "\n* * * * * * * * * * * \n"${command} "\n* * * * * * * * * * * \n"
|
||||
eval ${command}
|
||||
fi
|
||||
perl fpga_flow.pl -conf ${config_file_final} -benchmark ${bench_txt} -rpt ${rpt_file} -N 10 -K 6 -ace_d 0.5 -multi_thread 1 -vpr_fpga_x2p_rename_illegal_port -vpr_fpga_verilog -vpr_fpga_verilog_dir $verilog_path -vpr_fpga_bitstream_generator -vpr_fpga_verilog_print_autocheck_top_testbench -vpr_fpga_verilog_include_timing -vpr_fpga_verilog_include_signal_init -vpr_fpga_verilog_formal_verification_top_netlist -fix_route_chan_width -vpr_fpga_verilog_include_icarus_simulator -power
|
||||
|
||||
echo "Netlists successfully generated and simulated"
|
||||
exit 0
|
||||
exit 0
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/perl -w
|
||||
#!usr/bin/perl -w
|
||||
# use the strict mode
|
||||
use strict;
|
||||
# Use the Shell enviornment
|
||||
|
@ -1208,7 +1208,6 @@ sub run_odin2($ $ $) {
|
|||
}
|
||||
|
||||
sub run_pro_blif_3arg($ $ $) {
|
||||
# Adopt blif format
|
||||
my ($abc_blif_out_bak, $abc_blif_out, $initial_blif) = @_;
|
||||
my ($pro_blif_path) = ($conf_ptr->{dir_path}->{script_base}->{val});
|
||||
|
||||
|
@ -1328,7 +1327,7 @@ sub run_std_vpr($ $ $ $ $ $ $ $ $)
|
|||
{
|
||||
my ($blif,$bm,$arch,$net,$place,$route,$fix_chan_width,$log,$act_file) = @_;
|
||||
my ($vpr_dir,$vpr_name) = &split_prog_path($conf_ptr->{dir_path}->{vpr_path}->{val});
|
||||
|
||||
|
||||
my ($power_opts);
|
||||
if ("on" eq $opt_ptr->{power}) {
|
||||
$power_opts = "--power --activity_file $act_file --tech_properties $conf_ptr->{flow_conf}->{power_tech_xml}->{val}";
|
||||
|
@ -1801,7 +1800,7 @@ sub run_vpr_in_flow($ $ $ $ $ $ $ $ $ $ $ $) {
|
|||
print "INFO: try route_chan_width($min_chan_width) success!\n";
|
||||
last; #Jump out
|
||||
} elsif ($max_route_width_retry < $min_chan_width) {
|
||||
# I set a threshold of 1000 as it is the limit of VPR
|
||||
# I set a threshold of 1000 as it is the limit of VPR
|
||||
die "ERROR: Route Fail for $abc_blif_out with a min_chan_width of $min_chan_width!\n";
|
||||
} else {
|
||||
print "INFO: try route_chan_width($min_chan_width) failed! Retry with +2...\n";
|
||||
|
@ -1827,7 +1826,7 @@ sub run_vpr_in_flow($ $ $ $ $ $ $ $ $ $ $ $) {
|
|||
print "INFO: try route_chan_width($fix_chan_width) success!\n";
|
||||
last; #Jump out
|
||||
} elsif ($max_route_width_retry < $fix_chan_width) {
|
||||
# I set a threshold of 1000 as it is the limit of VPR
|
||||
# I set a threshold of 1000 as it is the limit of VPR
|
||||
die "ERROR: Route Fail for $abc_blif_out with a min_chan_width of $fix_chan_width!\n";
|
||||
} else {
|
||||
print "INFO: try route_chan_width($fix_chan_width) failed! Retry with +2...\n";
|
||||
|
@ -3062,11 +3061,11 @@ sub gen_csv_rpt_vtr_flow($ $)
|
|||
my @keywords;
|
||||
my ($K_val,$N_val) = ($opt_ptr->{K_val},$opt_ptr->{N_val});
|
||||
|
||||
# adapt to matlab format if the option is enabled
|
||||
# adapt to matlab format if the option is enabled
|
||||
if ("on" eq $opt_ptr->{matlab_rpt}) {
|
||||
# Print the data name
|
||||
# Print the data name
|
||||
print $CSVFH "$opt_ptr->{matlab_rpt_val} = [\n";
|
||||
# We will set the stats line to be commented
|
||||
# We will set the stats line to be commented
|
||||
print $CSVFH "%";
|
||||
}
|
||||
|
||||
|
@ -3097,7 +3096,7 @@ sub gen_csv_rpt_vtr_flow($ $)
|
|||
print $CSVFH "\n";
|
||||
# Check log/stats one by one
|
||||
foreach $tmp(@benchmark_names) {
|
||||
$tmp =~ s/\.v$//g;
|
||||
$tmp =~ s/\.v$//g;
|
||||
print $CSVFH "$tmp";
|
||||
print $CSVFH ",$rpt_h{$tag}->{$tmp}->{$N_val}->{$K_val}->{LUTs}";
|
||||
if ("on" eq $opt_ptr->{min_route_chan_width}) {
|
||||
|
@ -3146,12 +3145,12 @@ sub gen_csv_rpt_yosys_vpr_flow($ $)
|
|||
my ($tmp,$ikw,$tmpkw);
|
||||
my @keywords;
|
||||
my ($K_val,$N_val) = ($opt_ptr->{K_val},$opt_ptr->{N_val});
|
||||
|
||||
# adapt to matlab format if the option is enabled
|
||||
|
||||
# adapt to matlab format if the option is enabled
|
||||
if ("on" eq $opt_ptr->{matlab_rpt}) {
|
||||
# Print the data name
|
||||
# Print the data name
|
||||
print $CSVFH "$opt_ptr->{matlab_rpt_val} = [\n";
|
||||
# We will set the stats line to be commented
|
||||
# We will set the stats line to be commented
|
||||
print $CSVFH "%";
|
||||
}
|
||||
|
||||
|
@ -3185,9 +3184,9 @@ sub gen_csv_rpt_yosys_vpr_flow($ $)
|
|||
my @tokens = split('/', $tmp);
|
||||
$tmp = $tokens[0];
|
||||
|
||||
# For matlab script, we use {} for string
|
||||
# For matlab script, we use {} for string
|
||||
if ("on" eq $opt_ptr->{matlab_rpt}) {
|
||||
print $CSVFH "{'$tmp'}";
|
||||
print $CSVFH "{'$tmp'}";
|
||||
} else {
|
||||
print $CSVFH "$tmp";
|
||||
}
|
||||
|
@ -3239,12 +3238,12 @@ sub gen_csv_rpt_standard_flow($ $)
|
|||
my ($tmp,$ikw,$tmpkw);
|
||||
my @keywords;
|
||||
my ($K_val,$N_val) = ($opt_ptr->{K_val},$opt_ptr->{N_val});
|
||||
|
||||
# adapt to matlab format if the option is enabled
|
||||
|
||||
# adapt to matlab format if the option is enabled
|
||||
if ("on" eq $opt_ptr->{matlab_rpt}) {
|
||||
# Print the data name
|
||||
# Print the data name
|
||||
print $CSVFH "$opt_ptr->{matlab_rpt_val} = [\n";
|
||||
# We will set the stats line to be commented
|
||||
# We will set the stats line to be commented
|
||||
print $CSVFH "%";
|
||||
}
|
||||
|
||||
|
@ -3296,7 +3295,7 @@ sub gen_csv_rpt_standard_flow($ $)
|
|||
@keywords = split /\|/,$conf_ptr->{csv_tags}->{vpr_tags}->{val};
|
||||
for($ikw=0; $ikw < ($#keywords+1); $ikw++) {
|
||||
$tmpkw = $keywords[$ikw];
|
||||
$tmpkw =~ s/\s//g;
|
||||
$tmpkw =~ s/\s//g;
|
||||
print $CSVFH ",$rpt_ptr->{$tag}->{$tmp}->{$N_val}->{$K_val}->{$keywords[$ikw]}";
|
||||
}
|
||||
if ("on" eq $opt_ptr->{power}) {
|
||||
|
@ -3332,11 +3331,11 @@ sub gen_csv_rpt_mpack2_flow($ $)
|
|||
my @keywords;
|
||||
my ($K_val,$N_val) = ($opt_ptr->{K_val},$opt_ptr->{N_val});
|
||||
|
||||
# adapt to matlab format if the option is enabled
|
||||
# adapt to matlab format if the option is enabled
|
||||
if ("on" eq $opt_ptr->{matlab_rpt}) {
|
||||
# Print the data name
|
||||
# Print the data name
|
||||
print $CSVFH "$opt_ptr->{matlab_rpt_val} = [\n";
|
||||
# We will set the stats line to be commented
|
||||
# We will set the stats line to be commented
|
||||
print $CSVFH "%";
|
||||
}
|
||||
|
||||
|
@ -3372,7 +3371,7 @@ sub gen_csv_rpt_mpack2_flow($ $)
|
|||
print $CSVFH "\n";
|
||||
# Check log/stats one by one
|
||||
foreach $tmp(@benchmark_names) {
|
||||
$tmp =~ s/\.blif$//g;
|
||||
$tmp =~ s/\.blif$//g;
|
||||
print $CSVFH "$tmp";
|
||||
if ("on" eq $opt_ptr->{min_route_chan_width}) {
|
||||
print $CSVFH ",$rpt_h{$tag}->{$tmp}->{$N_val}->{$K_val}->{min_route_chan_width}";
|
||||
|
@ -3427,11 +3426,11 @@ sub gen_csv_rpt_mpack1_flow($ $)
|
|||
my @keywords;
|
||||
my ($N_val,$M_val) = ($opt_ptr->{N_val},$opt_ptr->{M_val});
|
||||
|
||||
# adapt to matlab format if the option is enabled
|
||||
# adapt to matlab format if the option is enabled
|
||||
if ("on" eq $opt_ptr->{matlab_rpt}) {
|
||||
# Print the data name
|
||||
# Print the data name
|
||||
print $CSVFH "$opt_ptr->{matlab_rpt_val} = [\n";
|
||||
# We will set the stats line to be commented
|
||||
# We will set the stats line to be commented
|
||||
print $CSVFH "%";
|
||||
}
|
||||
|
||||
|
@ -3457,7 +3456,7 @@ sub gen_csv_rpt_mpack1_flow($ $)
|
|||
print $CSVFH "\n";
|
||||
# Check log/stats one by one
|
||||
foreach $tmp(@benchmark_names) {
|
||||
$tmp =~ s/\.blif$//g;
|
||||
$tmp =~ s/\.blif$//g;
|
||||
print $CSVFH "$tmp";
|
||||
#foreach $tmpkw(@keywords) {
|
||||
print $CSVFH ",$rpt_ptr->{$tag}->{$tmp}->{$N_val}->{$M_val}->{MATRIX}";
|
||||
|
|
|
@ -12,11 +12,11 @@ hardlogic_tb_dir_name = hardlogic_tb
|
|||
cb_tb_dir_name = cb_tb
|
||||
sb_tb_dir_name = sb_tb
|
||||
# Prefix
|
||||
top_tb_prefix =
|
||||
top_tb_prefix =
|
||||
pb_mux_tb_prefix = _grid
|
||||
cb_mux_tb_prefix = _cb
|
||||
sb_mux_tb_prefix = _sb
|
||||
lut_tb_prefix = _grid
|
||||
lut_tb_prefix = _grid
|
||||
hardlogic_tb_prefix = _grid
|
||||
grid_tb_prefix = _grid
|
||||
cb_tb_prefix = _cb
|
||||
|
@ -34,34 +34,35 @@ sb_tb_postfix = _sb_testbench.sp
|
|||
|
||||
[task_conf]
|
||||
auto_check = on
|
||||
num_pb_mux_tb =
|
||||
num_cb_mux_tb =
|
||||
num_sb_mux_tb =
|
||||
num_lut_mux_tb =
|
||||
num_hardlogic_tb =
|
||||
num_grid_mux_tb =
|
||||
num_top_tb =
|
||||
num_cb_tb =
|
||||
num_sb_tb =
|
||||
num_pb_mux_tb =
|
||||
num_cb_mux_tb =
|
||||
num_sb_mux_tb =
|
||||
num_lut_mux_tb =
|
||||
num_hardlogic_tb =
|
||||
num_grid_mux_tb =
|
||||
num_top_tb =
|
||||
num_cb_tb =
|
||||
num_sb_tb =
|
||||
|
||||
[csv_tags]
|
||||
#top_tb_leakage_power_tags = leakage_power_sram_local_routing|leakage_power_sram_luts|leakage_power_sram_cbs|leakage_power_sram_sbs|leakage_power_io|leakage_power_local_interc|total_leakage_power_lut5|total_leakage_power_lut6|total_leakage_power_dff|leakage_power_cbs|leakage_power_sbs
|
||||
top_tb_leakage_power_tags = leakage_power_sram_local_routing | leakage_power_sram_luts | leakage_power_sram_cbs | leakage_power_sram_sbs | leakage_power_local_interc | total_leakage_power_lut6 | total_leakage_power_dff | leakage_power_cbs | leakage_power_sbs
|
||||
top_tb_leakage_power_tags = leakage_power_sram_local_routing|leakage_power_sram_luts|leakage_power_sram_cbs|leakage_power_sram_sbs|leakage_power_local_interc|total_leakage_power_lut6|total_leakage_power_dff|leakage_power_cbs|leakage_power_sbs
|
||||
#top_tb_dynamic_power_tags = energy_per_cycle_sram_local_routing|energy_per_cycle_sram_luts|energy_per_cycle_sram_cbs|energy_per_cycle_sram_sbs|energy_per_cycle_io|energy_per_cycle_local_routing|total_energy_per_cycle_lut5|total_energy_per_cycle_lut6|total_energy_per_cycle_dff|energy_per_cycle_cbs|energy_per_cycle_sbs
|
||||
top_tb_dynamic_power_tags = energy_per_cycle_sram_local_routing | energy_per_cycle_sram_luts | energy_per_cycle_sram_cbs | energy_per_cycle_sram_sbs | energy_per_cycle_local_routing | total_energy_per_cycle_lut6 | total_energy_per_cycle_dff | energy_per_cycle_cbs | energy_per_cycle_sbs #|crit_path_delay
|
||||
pb_mux_tb_leakage_power_tags = total_leakage_srams | total_leakage_power_pb_mux
|
||||
cb_mux_tb_leakage_power_tags = total_leakage_srams | total_leakage_power_cb_mux
|
||||
sb_mux_tb_leakage_power_tags = total_leakage_srams | total_leakage_power_sb_mux
|
||||
pb_mux_tb_dynamic_power_tags = total_energy_per_cycle_srams | total_energy_per_cycle_pb_mux
|
||||
cb_mux_tb_dynamic_power_tags = total_energy_per_cycle_srams | total_energy_per_cycle_cb_mux
|
||||
sb_mux_tb_dynamic_power_tags = total_energy_per_cycle_srams | total_energy_per_cycle_sb_mux
|
||||
lut_tb_leakage_power_tags = leakage_power_sram_luts | total_leakage_power_lut6
|
||||
lut_tb_dynamic_power_tags = energy_per_cycle_sram_luts | total_energy_per_cycle_lut6
|
||||
top_tb_dynamic_power_tags = energy_per_cycle_sram_local_routing|energy_per_cycle_sram_luts|energy_per_cycle_sram_cbs|energy_per_cycle_sram_sbs|energy_per_cycle_local_routing|total_energy_per_cycle_lut6|total_energy_per_cycle_dff|energy_per_cycle_cbs|energy_per_cycle_sbs #|crit_path_delay
|
||||
pb_mux_tb_leakage_power_tags = total_leakage_srams|total_leakage_power_pb_mux
|
||||
cb_mux_tb_leakage_power_tags = total_leakage_srams|total_leakage_power_cb_mux
|
||||
sb_mux_tb_leakage_power_tags = total_leakage_srams|total_leakage_power_sb_mux
|
||||
pb_mux_tb_dynamic_power_tags = total_energy_per_cycle_srams|total_energy_per_cycle_pb_mux
|
||||
cb_mux_tb_dynamic_power_tags = total_energy_per_cycle_srams|total_energy_per_cycle_cb_mux
|
||||
sb_mux_tb_dynamic_power_tags = total_energy_per_cycle_srams|total_energy_per_cycle_sb_mux
|
||||
lut_tb_leakage_power_tags = leakage_power_sram_luts|total_leakage_power_lut6
|
||||
lut_tb_dynamic_power_tags = energy_per_cycle_sram_luts|total_energy_per_cycle_lut6
|
||||
hardlogic_tb_leakage_power_tags = total_leakage_power_dff
|
||||
hardlogic_tb_dynamic_power_tags = total_energy_per_cycle_dff
|
||||
grid_tb_leakage_power_tags = leakage_power_sram_local_routing | leakage_power_sram_luts | leakage_power_local_routing | total_leakage_power_lut6 | total_leakage_power_dff
|
||||
grid_tb_dynamic_power_tags = total_energy_per_cycle_sram_local_routing | total_energy_per_cycle_sram_luts | total_energy_per_cycle_local_routing | total_energy_per_cycle_lut6 | total_energy_per_cycle_dff
|
||||
cb_tb_leakage_power_tags = leakage_power_cb | leakage_power_sram_cb
|
||||
cb_tb_dynamic_power_tags = energy_per_cycle_cb | energy_per_cycle_sram_cb
|
||||
sb_tb_leakage_power_tags = leakage_power_sb | leakage_power_sram_sb
|
||||
sb_tb_dynamic_power_tags = energy_per_cycle_sb | energy_per_cycle_sram_sb
|
||||
grid_tb_leakage_power_tags = leakage_power_sram_local_routing|leakage_power_sram_luts|leakage_power_local_routing|total_leakage_power_lut6|total_leakage_power_dff
|
||||
grid_tb_dynamic_power_tags = total_energy_per_cycle_sram_local_routing|total_energy_per_cycle_sram_luts|total_energy_per_cycle_local_routing|total_energy_per_cycle_lut6|total_energy_per_cycle_dff
|
||||
cb_tb_leakage_power_tags = leakage_power_cb|leakage_power_sram_cb
|
||||
cb_tb_dynamic_power_tags = energy_per_cycle_cb|energy_per_cycle_sram_cb
|
||||
sb_tb_leakage_power_tags = leakage_power_sb|leakage_power_sram_sb
|
||||
sb_tb_dynamic_power_tags = energy_per_cycle_sb|energy_per_cycle_sram_sb
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +0,0 @@
|
|||
XSym
|
||||
0006
|
||||
de6ba653dd63797278d7fa829999bf6c
|
||||
run003
|
||||
|
91
run_test.sh
91
run_test.sh
|
@ -15,8 +15,7 @@
|
|||
# --vpr_fpga_verilog_include_signal_init \
|
||||
# --vpr_fpga_verilog_print_autocheck_top_testbench
|
||||
|
||||
|
||||
|
||||
# Test popular multi-mode architecture
|
||||
python3.5 openfpga_flow/scripts/run_fpga_flow.py \
|
||||
./openfpga_flow/arch/template/k6_N10_sram_chain_HC_template.xml \
|
||||
./openfpga_flow/benchmarks/Test_Modes/test_modes.blif \
|
||||
|
@ -26,6 +25,64 @@ python3.5 openfpga_flow/scripts/run_fpga_flow.py \
|
|||
--base_verilog ./openfpga_flow/benchmarks/Test_Modes/test_modes.v \
|
||||
--power \
|
||||
--power_tech ./openfpga_flow/tech/PTM_45nm/45nm.xml \
|
||||
#--fix_route_chan_width 300 \
|
||||
--min_route_chan_width 1.3 \
|
||||
--vpr_fpga_verilog \
|
||||
--vpr_fpga_verilog_dir . \
|
||||
--vpr_fpga_x2p_rename_illegal_port \
|
||||
--vpr_fpga_verilog_include_icarus_simulator \
|
||||
--vpr_fpga_verilog_formal_verification_top_netlist \
|
||||
--vpr_fpga_verilog_include_timing \
|
||||
--vpr_fpga_verilog_include_signal_init \
|
||||
--vpr_fpga_verilog_print_autocheck_top_testbench \
|
||||
--debug \
|
||||
--vpr_fpga_bitstream_generator \
|
||||
--vpr_fpga_verilog_print_user_defined_template \
|
||||
--vpr_fpga_verilog_print_report_timing_tcl \
|
||||
--vpr_fpga_verilog_print_sdc_pnr \
|
||||
--vpr_fpga_verilog_print_sdc_analysis \
|
||||
--vpr_fpga_x2p_compact_routing_hierarchy \
|
||||
--end_flow_with_test
|
||||
|
||||
# Test Standard cell MUX2
|
||||
python3.5 openfpga_flow/scripts/run_fpga_flow.py \
|
||||
./openfpga_flow/arch/template/k8_N10_sram_chain_FC_template.xml \
|
||||
./openfpga_flow/benchmarks/Test_Modes/test_modes.blif \
|
||||
--fpga_flow vpr_blif \
|
||||
--top_module test_modes \
|
||||
--activity_file ./openfpga_flow/benchmarks/Test_Modes/test_modes.act \
|
||||
--base_verilog ./openfpga_flow/benchmarks/Test_Modes/test_modes.v \
|
||||
--power \
|
||||
--power_tech ./openfpga_flow/tech/PTM_45nm/45nm.xml \
|
||||
#--fix_route_chan_width 300 \
|
||||
--min_route_chan_width 1.3 \
|
||||
--vpr_fpga_verilog \
|
||||
--vpr_fpga_verilog_dir . \
|
||||
--vpr_fpga_x2p_rename_illegal_port \
|
||||
--vpr_fpga_verilog_include_icarus_simulator \
|
||||
--vpr_fpga_verilog_formal_verification_top_netlist \
|
||||
--vpr_fpga_verilog_include_timing \
|
||||
--vpr_fpga_verilog_include_signal_init \
|
||||
--vpr_fpga_verilog_print_autocheck_top_testbench \
|
||||
--debug \
|
||||
--vpr_fpga_bitstream_generator \
|
||||
--vpr_fpga_verilog_print_user_defined_template \
|
||||
--vpr_fpga_verilog_print_report_timing_tcl \
|
||||
--vpr_fpga_verilog_print_sdc_pnr \
|
||||
--vpr_fpga_verilog_print_sdc_analysis \
|
||||
--vpr_fpga_x2p_compact_routing_hierarchy \
|
||||
--end_flow_with_test
|
||||
|
||||
# Test local encoder feature
|
||||
python3.5 openfpga_flow/scripts/run_fpga_flow.py \
|
||||
./openfpga_flow/arch/template/k6_N10_sram_chain_HC_local_encoder_template.xml \
|
||||
./openfpga_flow/benchmarks/Test_Modes/test_modes.blif \
|
||||
--fpga_flow vpr_blif \
|
||||
--top_module test_modes \
|
||||
--activity_file ./openfpga_flow/benchmarks/Test_Modes/test_modes.act \
|
||||
--base_verilog ./openfpga_flow/benchmarks/Test_Modes/test_modes.v \
|
||||
--power \
|
||||
--power_tech ./openfpga_flow/tech/PTM_45nm/45nm.xml \
|
||||
--fix_route_chan_width 300 \
|
||||
--vpr_fpga_verilog \
|
||||
--vpr_fpga_verilog_dir . \
|
||||
|
@ -44,3 +101,33 @@ python3.5 openfpga_flow/scripts/run_fpga_flow.py \
|
|||
--vpr_fpga_x2p_compact_routing_hierarchy \
|
||||
--end_flow_with_test
|
||||
|
||||
# Test tileable routing feature
|
||||
#python3.5 openfpga_flow/scripts/run_fpga_flow.py \
|
||||
#./openfpga_flow/arch/template/k6_N10_sram_chain_HC_tileable_template.xml \
|
||||
#./openfpga_flow/benchmarks/Test_Modes/test_modes.blif \
|
||||
#--fpga_flow vpr_blif \
|
||||
#--top_module test_modes \
|
||||
#--activity_file ./openfpga_flow/benchmarks/Test_Modes/test_modes.act \
|
||||
#--base_verilog ./openfpga_flow/benchmarks/Test_Modes/test_modes.v \
|
||||
#--power \
|
||||
#--power_tech ./openfpga_flow/tech/PTM_45nm/45nm.xml \
|
||||
##--fix_route_chan_width 300 \
|
||||
#--min_route_chan_width 1.3 \
|
||||
#--vpr_fpga_verilog \
|
||||
#--vpr_fpga_verilog_dir . \
|
||||
#--vpr_fpga_x2p_rename_illegal_port \
|
||||
#--vpr_fpga_verilog_include_icarus_simulator \
|
||||
#--vpr_fpga_verilog_formal_verification_top_netlist \
|
||||
#--vpr_fpga_verilog_include_timing \
|
||||
#--vpr_fpga_verilog_include_signal_init \
|
||||
#--vpr_fpga_verilog_print_autocheck_top_testbench \
|
||||
#--debug \
|
||||
#--vpr_fpga_bitstream_generator \
|
||||
#--vpr_fpga_verilog_print_user_defined_template \
|
||||
#--vpr_fpga_verilog_print_report_timing_tcl \
|
||||
#--vpr_fpga_verilog_print_sdc_pnr \
|
||||
#--vpr_fpga_verilog_print_sdc_analysis \
|
||||
#--vpr_fpga_x2p_compact_routing_hierarchy \
|
||||
#--vpr_use_tileable_route_chan_width \
|
||||
#--end_flow_with_test
|
||||
|
||||
|
|
|
@ -58,16 +58,16 @@ static
|
|||
size_t check_circuit_library_unique_names(const CircuitLibrary& circuit_lib) {
|
||||
size_t num_err = 0;
|
||||
|
||||
for (size_t i = 0; i < circuit_lib.num_circuit_models(); ++i) {
|
||||
for (size_t i = 0; i < circuit_lib.num_models(); ++i) {
|
||||
/* Skip for the last element, because the inner loop will access it */
|
||||
if (i == circuit_lib.num_circuit_models() - 1) {
|
||||
if (i == circuit_lib.num_models() - 1) {
|
||||
continue;
|
||||
}
|
||||
/* Get the name of reference */
|
||||
const std::string& i_name = circuit_lib.circuit_model_name(CircuitModelId(i));
|
||||
for (size_t j = i + 1; j < circuit_lib.num_circuit_models(); ++j) {
|
||||
const std::string& i_name = circuit_lib.model_name(CircuitModelId(i));
|
||||
for (size_t j = i + 1; j < circuit_lib.num_models(); ++j) {
|
||||
/* Compare the name of candidate */
|
||||
const std::string& j_name = circuit_lib.circuit_model_name(CircuitModelId(j));
|
||||
const std::string& j_name = circuit_lib.model_name(CircuitModelId(j));
|
||||
/* Compare the name and skip for different names */
|
||||
if (0 != i_name.compare(j_name)) {
|
||||
continue;
|
||||
|
@ -92,24 +92,24 @@ static
|
|||
size_t check_circuit_library_unique_prefix(const CircuitLibrary& circuit_lib) {
|
||||
size_t num_err = 0;
|
||||
|
||||
for (size_t i = 0; i < circuit_lib.num_circuit_models(); ++i) {
|
||||
for (size_t i = 0; i < circuit_lib.num_models(); ++i) {
|
||||
/* Skip for the last element, because the inner loop will access it */
|
||||
if (i == circuit_lib.num_circuit_models() - 1) {
|
||||
if (i == circuit_lib.num_models() - 1) {
|
||||
continue;
|
||||
}
|
||||
/* Get the name of reference */
|
||||
const std::string& i_prefix = circuit_lib.circuit_model_prefix(CircuitModelId(i));
|
||||
for (size_t j = i + 1; j < circuit_lib.num_circuit_models(); ++j) {
|
||||
const std::string& i_prefix = circuit_lib.model_prefix(CircuitModelId(i));
|
||||
for (size_t j = i + 1; j < circuit_lib.num_models(); ++j) {
|
||||
/* Compare the name of candidate */
|
||||
const std::string& j_prefix = circuit_lib.circuit_model_prefix(CircuitModelId(j));
|
||||
const std::string& j_prefix = circuit_lib.model_prefix(CircuitModelId(j));
|
||||
/* Compare the name and skip for different prefix */
|
||||
if (0 != i_prefix.compare(j_prefix)) {
|
||||
continue;
|
||||
}
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"Circuit model(name=%s) and (name=%s) share the same prefix, which is invalid!\n",
|
||||
circuit_lib.circuit_model_name(CircuitModelId(i)).c_str(),
|
||||
circuit_lib.circuit_model_name(CircuitModelId(j)).c_str(),
|
||||
circuit_lib.model_name(CircuitModelId(i)).c_str(),
|
||||
circuit_lib.model_name(CircuitModelId(j)).c_str(),
|
||||
i_prefix.c_str());
|
||||
/* Incremental the counter for errors */
|
||||
num_err++;
|
||||
|
@ -129,7 +129,7 @@ size_t check_circuit_model_required(const CircuitLibrary& circuit_lib,
|
|||
size_t num_err = 0;
|
||||
|
||||
/* We must have an IOPAD*/
|
||||
if ( 0 == circuit_lib.circuit_models_by_type(circuit_model_type_to_check).size()) {
|
||||
if ( 0 == circuit_lib.models_by_type(circuit_model_type_to_check).size()) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"At least one %s circuit model is required!\n",
|
||||
CIRCUIT_MODEL_TYPE_STRING[size_t(circuit_model_type_to_check)]);
|
||||
|
@ -150,11 +150,11 @@ size_t check_one_circuit_model_port_required(const CircuitLibrary& circuit_lib,
|
|||
size_t num_err = 0;
|
||||
|
||||
for (const auto& port_type: port_types_to_check) {
|
||||
if (0 == circuit_lib.ports_by_type(circuit_model, port_type).size()) {
|
||||
if (0 == circuit_lib.model_ports_by_type(circuit_model, port_type).size()) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"%s circuit model(name=%s) does not have %s port\n",
|
||||
CIRCUIT_MODEL_TYPE_STRING[size_t(circuit_lib.circuit_model_type(circuit_model))],
|
||||
circuit_lib.circuit_model_name(circuit_model).c_str(),
|
||||
CIRCUIT_MODEL_TYPE_STRING[size_t(circuit_lib.model_type(circuit_model))],
|
||||
circuit_lib.model_name(circuit_model).c_str(),
|
||||
CIRCUIT_MODEL_PORT_TYPE_STRING[size_t(port_type)]);
|
||||
/* Incremental the counter for errors */
|
||||
num_err++;
|
||||
|
@ -175,11 +175,11 @@ size_t check_one_circuit_model_port_size_required(const CircuitLibrary& circuit_
|
|||
|
||||
size_t num_err = 0;
|
||||
|
||||
if (port_size_to_check != circuit_lib.port_size(circuit_model, circuit_port)) {
|
||||
if (port_size_to_check != circuit_lib.port_size(circuit_port)) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"Port of circuit model(name=%s) does not have a port(type=%s) of size=%d.\n",
|
||||
circuit_lib.circuit_model_name(circuit_model).c_str(),
|
||||
CIRCUIT_MODEL_PORT_TYPE_STRING[size_t(circuit_lib.port_type(circuit_model, circuit_port))],
|
||||
circuit_lib.model_name(circuit_model).c_str(),
|
||||
CIRCUIT_MODEL_PORT_TYPE_STRING[size_t(circuit_lib.port_type(circuit_port))],
|
||||
port_size_to_check);
|
||||
/* Incremental the counter for errors */
|
||||
num_err++;
|
||||
|
@ -202,13 +202,13 @@ size_t check_one_circuit_model_port_type_and_size_required(const CircuitLibrary&
|
|||
|
||||
size_t num_err = 0;
|
||||
|
||||
std::vector<CircuitPortId> ports = circuit_lib.ports_by_type(circuit_model, port_type_to_check, include_global_ports);
|
||||
std::vector<CircuitPortId> ports = circuit_lib.model_ports_by_type(circuit_model, port_type_to_check, false == include_global_ports);
|
||||
if (num_ports_to_check != ports.size()) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"Expect %d %s ports for a %s circuit model, but only have %d %s ports!\n",
|
||||
num_ports_to_check,
|
||||
CIRCUIT_MODEL_PORT_TYPE_STRING[size_t(port_type_to_check)],
|
||||
CIRCUIT_MODEL_TYPE_STRING[size_t(circuit_lib.circuit_model_type(circuit_model))],
|
||||
CIRCUIT_MODEL_TYPE_STRING[size_t(circuit_lib.model_type(circuit_model))],
|
||||
CIRCUIT_MODEL_PORT_TYPE_STRING[size_t(port_type_to_check)],
|
||||
ports.size());
|
||||
num_err++;
|
||||
|
@ -232,7 +232,7 @@ size_t check_circuit_model_port_required(const CircuitLibrary& circuit_lib,
|
|||
const std::vector<enum e_spice_model_port_type>& port_types_to_check) {
|
||||
size_t num_err = 0;
|
||||
|
||||
for (const auto& id : circuit_lib.circuit_models_by_type(circuit_model_type_to_check)) {
|
||||
for (const auto& id : circuit_lib.models_by_type(circuit_model_type_to_check)) {
|
||||
num_err += check_one_circuit_model_port_required(circuit_lib, id, port_types_to_check);
|
||||
}
|
||||
|
||||
|
@ -248,7 +248,7 @@ size_t check_required_default_circuit_model(const CircuitLibrary& circuit_lib,
|
|||
const enum e_spice_model_type& circuit_model_type) {
|
||||
size_t num_err = 0;
|
||||
|
||||
if (CIRCUIT_MODEL_OPEN_ID == circuit_lib.default_circuit_model(circuit_model_type)) {
|
||||
if (CircuitModelId::INVALID() == circuit_lib.default_model(circuit_model_type)) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"A default circuit model for the type %s! Try to define it in your architecture file!\n",
|
||||
CIRCUIT_MODEL_TYPE_STRING[size_t(circuit_model_type)]);
|
||||
|
@ -266,7 +266,7 @@ size_t check_ff_circuit_model_ports(const CircuitLibrary& circuit_lib,
|
|||
size_t num_err = 0;
|
||||
|
||||
/* Check the type of circuit model */
|
||||
VTR_ASSERT(SPICE_MODEL_FF == circuit_lib.circuit_model_type(circuit_model));
|
||||
VTR_ASSERT(SPICE_MODEL_FF == circuit_lib.model_type(circuit_model));
|
||||
/* Check if we have D, Set and Reset */
|
||||
num_err += check_one_circuit_model_port_type_and_size_required(circuit_lib, circuit_model,
|
||||
SPICE_MODEL_PORT_INPUT,
|
||||
|
@ -293,7 +293,7 @@ size_t check_scff_circuit_model_ports(const CircuitLibrary& circuit_lib,
|
|||
size_t num_err = 0;
|
||||
|
||||
/* Check the type of circuit model */
|
||||
VTR_ASSERT(SPICE_MODEL_SCFF == circuit_lib.circuit_model_type(circuit_model));
|
||||
VTR_ASSERT(SPICE_MODEL_SCFF == circuit_lib.model_type(circuit_model));
|
||||
|
||||
/* Check if we have D, Set and Reset */
|
||||
num_err += check_one_circuit_model_port_type_and_size_required(circuit_lib, circuit_model,
|
||||
|
@ -322,7 +322,7 @@ size_t check_sram_circuit_model_ports(const CircuitLibrary& circuit_lib,
|
|||
size_t num_err = 0;
|
||||
|
||||
/* Check the type of circuit model */
|
||||
VTR_ASSERT(SPICE_MODEL_SRAM == circuit_lib.circuit_model_type(circuit_model));
|
||||
VTR_ASSERT(SPICE_MODEL_SRAM == circuit_lib.model_type(circuit_model));
|
||||
|
||||
/* Check if we has 1 output with size 2 */
|
||||
num_err += check_one_circuit_model_port_type_and_size_required(circuit_lib, circuit_model,
|
||||
|
@ -345,6 +345,39 @@ size_t check_sram_circuit_model_ports(const CircuitLibrary& circuit_lib,
|
|||
return num_err;
|
||||
}
|
||||
|
||||
/* Check all the ports make sure, they satisfy the restriction */
|
||||
static
|
||||
size_t check_circuit_library_ports(const CircuitLibrary& circuit_lib) {
|
||||
size_t num_err = 0;
|
||||
|
||||
/* Check global ports: make sure all the global ports are input ports */
|
||||
for (const auto& port : circuit_lib.ports()) {
|
||||
if ( (circuit_lib.port_is_global(port))
|
||||
&& (!circuit_lib.is_input_port(port)) ) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"Circuit port (type=%s) of model (name=%s) is defined as global but not an input port!\n",
|
||||
CIRCUIT_MODEL_PORT_TYPE_STRING[size_t(circuit_lib.port_type(port))],
|
||||
circuit_lib.model_name(port).c_str());
|
||||
num_err++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check set/reset/config_enable ports: make sure they are all global ports */
|
||||
for (const auto& port : circuit_lib.ports()) {
|
||||
if ( ( (circuit_lib.port_is_set(port))
|
||||
|| (circuit_lib.port_is_reset(port))
|
||||
|| (circuit_lib.port_is_config_enable(port)) )
|
||||
&& (!circuit_lib.port_is_global(port)) ) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"Circuit port (type=%s) of model (name=%s) is defined as a set/reset/config_enable port but it is not global!\n",
|
||||
CIRCUIT_MODEL_PORT_TYPE_STRING[size_t(circuit_lib.port_type(port))],
|
||||
circuit_lib.model_name(port).c_str());
|
||||
num_err++;
|
||||
}
|
||||
}
|
||||
|
||||
return num_err;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Check points to make sure we have a valid circuit library
|
||||
|
@ -375,6 +408,9 @@ void check_circuit_library(const CircuitLibrary& circuit_lib) {
|
|||
*/
|
||||
num_err += check_circuit_library_unique_prefix(circuit_lib);
|
||||
|
||||
/* Check global ports */
|
||||
num_err += check_circuit_library_ports(circuit_lib);
|
||||
|
||||
/* 3. Check io has been defined and has input and output ports
|
||||
* [a] We must have an IOPAD!
|
||||
* [b] For each IOPAD, we must have at least an input, an output, an INOUT and an SRAM port
|
||||
|
@ -403,8 +439,8 @@ void check_circuit_library(const CircuitLibrary& circuit_lib) {
|
|||
num_err += check_circuit_model_port_required(circuit_lib, SPICE_MODEL_MUX, mux_port_types_required);
|
||||
|
||||
/* 5. We must have at least one SRAM or SCFF */
|
||||
if ( ( 0 == circuit_lib.circuit_models_by_type(SPICE_MODEL_SRAM).size())
|
||||
&& ( 0 == circuit_lib.circuit_models_by_type(SPICE_MODEL_SCFF).size()) ) {
|
||||
if ( ( 0 == circuit_lib.models_by_type(SPICE_MODEL_SRAM).size())
|
||||
&& ( 0 == circuit_lib.models_by_type(SPICE_MODEL_SCFF).size()) ) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"At least one %s or %s circuit model is required!\n",
|
||||
CIRCUIT_MODEL_TYPE_STRING[size_t(SPICE_MODEL_SRAM)],
|
||||
|
|
|
@ -47,7 +47,9 @@
|
|||
*/
|
||||
/* Header files should be included in a sequence */
|
||||
/* Standard header files required go first */
|
||||
#include "circuit_library.h"
|
||||
#include <vector>
|
||||
#include "spice_types.h"
|
||||
#include "circuit_library_fwd.h"
|
||||
|
||||
/* Check points to make sure we have a valid circuit library */
|
||||
size_t check_one_circuit_model_port_required(const CircuitLibrary& circuit_lib,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -49,7 +49,6 @@
|
|||
/* Standard header files required go first */
|
||||
#include <string>
|
||||
|
||||
#include "vtr_strong_id.h"
|
||||
#include "vtr_geometry.h"
|
||||
|
||||
#include "vtr_vector.h"
|
||||
|
@ -57,22 +56,7 @@
|
|||
|
||||
#include "circuit_types.h"
|
||||
|
||||
/************************************************************************
|
||||
* Create strong id for Circuit Models/Ports to avoid illegal type casting
|
||||
***********************************************************************/
|
||||
struct circuit_model_id_tag;
|
||||
struct circuit_port_id_tag;
|
||||
struct circuit_edge_id_tag;
|
||||
|
||||
typedef vtr::StrongId<circuit_model_id_tag> CircuitModelId;
|
||||
typedef vtr::StrongId<circuit_port_id_tag> CircuitPortId;
|
||||
typedef vtr::StrongId<circuit_edge_id_tag> CircuitEdgeId;
|
||||
|
||||
|
||||
/* Alias for open ids */
|
||||
#define CIRCUIT_MODEL_OPEN_ID CircuitModelId(-1)
|
||||
#define CIRCUIT_PORT_OPEN_ID CircuitPortId(-1)
|
||||
#define CIRCUIT_EDGE_OPEN_ID CircuitEdgeId(-1)
|
||||
#include "circuit_library_fwd.h"
|
||||
|
||||
/************************************************************************
|
||||
* The class CircuitLibrary is a critical data structure for OpenFPGA
|
||||
|
@ -81,20 +65,22 @@ typedef vtr::StrongId<circuit_edge_id_tag> CircuitEdgeId;
|
|||
* It includes the following data:
|
||||
*
|
||||
* ------ Fundamental Information -----
|
||||
* 1. circuit_model_ids_ : unique identifier to find a circuit model
|
||||
* 1. model_ids_ : unique identifier to find a circuit model
|
||||
* Use a strong id for search, to avoid illegal type casting
|
||||
* 2. circuit_model_types_: types of the circuit model, see details in the definition of enum e_spice_model_type
|
||||
* 3. circuit_model_names_: unique names for each circuit models.
|
||||
* 2. model_types_: types of the circuit model, see details in the definition of enum e_spice_model_type
|
||||
* 3. model_names_: unique names for each circuit models.
|
||||
* It should be the same as user-defined Verilog modules, if it is not auto-generated
|
||||
* 4. circuit_model_prefix_: the prefix of a circuit model when it is instanciated
|
||||
* 4. model_prefix_: the prefix of a circuit model when it is instanciated
|
||||
* 5. verilog_netlist_: specified path and file name of Verilog netlist if a circuit model is not auto-generated
|
||||
* 6. spice_netlist_: specified path and file name of SPICE netlist if a circuit model is not auto-generated
|
||||
* 7. is_default_: indicate if the circuit model is the default one among all those in the same type
|
||||
* 8. sub_models_: the sub circuit models included by a circuit model. It is a collection of unique circuit model ids
|
||||
* found in the CircuitModelId of pass-gate/buffers/port-related circuit models.
|
||||
*
|
||||
* ------ Fast look-ups-----
|
||||
* 1. circuit_model_lookup_: A multi-dimension vector to provide fast look-up on circuit models for users
|
||||
* 1. model_lookup_: A multi-dimension vector to provide fast look-up on circuit models for users
|
||||
* It classifies CircuitModelIds by their type and set the default model in the first element for each type.
|
||||
* 2. circuit_model_port_lookup_: A multi-dimension vector to provide fast look-up on ports of circuit models for users
|
||||
* 2. model_port_lookup_: A multi-dimension vector to provide fast look-up on ports of circuit models for users
|
||||
* It classifies Ports by their types
|
||||
*
|
||||
* ------ Verilog generation options -----
|
||||
|
@ -109,15 +95,16 @@ typedef vtr::StrongId<circuit_edge_id_tag> CircuitEdgeId;
|
|||
* Use vectors to simplify the defition of buffer existence:
|
||||
* index (low=0 to high) represents INPUT, OUTPUT, LUT_INPUT_BUF, LUT_INPUT_INV, LUT_INTER_BUFFER
|
||||
* 1. buffer_existence_: specify if this circuit model has an buffer
|
||||
* 2. buffer_circuit_model_name_: specify the name of circuit model for the buffer
|
||||
* 3. buffer_circuit_model_id_: specify the id of circuit model for the buffer
|
||||
* 2. buffer_model_name_: specify the name of circuit model for the buffer
|
||||
* 3. buffer_model_id_: specify the id of circuit model for the buffer
|
||||
*
|
||||
* ------ Pass-gate-related parameters ------
|
||||
* 1. pass_gate_logic_circuit_model_name_: specify the name of circuit model for the pass gate logic
|
||||
* 2. pass_gate_logic_circuit_model_id_: specify the id of circuit model for the pass gate logic
|
||||
* 1. pass_gate_logic_model_name_: specify the name of circuit model for the pass gate logic
|
||||
* 2. pass_gate_logic_model_id_: specify the id of circuit model for the pass gate logic
|
||||
*
|
||||
* ------ Port information ------
|
||||
* 1. port_ids_: unique id of ports belonging to a circuit model
|
||||
* 1. port_model_ids_: unique id of the parent circuit model for the port
|
||||
* 2. port_types_: types of ports belonging to a circuit model
|
||||
* 3. port_sizes_: width of ports belonging to a circuit model
|
||||
* 4. port_prefix_: prefix of a port when instance of a circuit model
|
||||
|
@ -129,10 +116,10 @@ typedef vtr::StrongId<circuit_edge_id_tag> CircuitEdgeId;
|
|||
* 10. port_is_set: specify if this port is a set signal which needs special pulse widths in testbenches
|
||||
* 11. port_is_config_enable: specify if this port is a config_enable signal which needs special pulse widths in testbenches
|
||||
* 12. port_is_prog: specify if this port is for FPGA programming use which needs special pulse widths in testbenches
|
||||
* 13. port_circuit_model_name: the name of circuit model linked to the port
|
||||
* 14. port_circuit_model_ids_: the Id of circuit model linked to the port
|
||||
* 15. port_inv_circuit_model_names_: the name of inverter circuit model linked to the port
|
||||
* 16. port_inv_circuit_model_ids_: the Id of inverter circuit model linked to the port
|
||||
* 13. port_tri_state_model_name: the name of circuit model linked to tri-state the port
|
||||
* 14. port_tri_state_model_ids_: the Id of circuit model linked to tri-state the port
|
||||
* 15. port_inv_model_names_: the name of inverter circuit model linked to the port
|
||||
* 16. port_inv_model_ids_: the Id of inverter circuit model linked to the port
|
||||
* 17. port_tri_state_map_: only applicable to inputs of LUTs, the tri-state map applied to each pin of this port
|
||||
* 18. port_lut_frac_level_: only applicable to outputs of LUTs, indicate which level of outputs inside LUT multiplexing structure will be used
|
||||
* 19. port_lut_output_mask_: only applicable to outputs of LUTs, indicate which output at an internal level of LUT multiplexing structure will be used
|
||||
|
@ -196,7 +183,7 @@ typedef vtr::StrongId<circuit_edge_id_tag> CircuitEdgeId;
|
|||
*
|
||||
* ------ Metal wire-related parameters ------
|
||||
* Note: only applicable to circuit models whose type is wires or channel wires
|
||||
* 1. wire_types_: types of the metal wire for the circuit_model
|
||||
* 1. wire_types_: types of the metal wire for the model
|
||||
* 2. wire_res_val_: resistance value of the metal wire for the circuit model
|
||||
* 3. wire_cap_val_: capacitance value of the metal wire for the circuit model
|
||||
* 4. wire_num_levels_: number of levels of the metal wire model for the circuit model
|
||||
|
@ -218,267 +205,283 @@ class CircuitLibrary {
|
|||
public: /* Constructors */
|
||||
CircuitLibrary();
|
||||
public: /* Accessors: aggregates */
|
||||
circuit_model_range circuit_models() const;
|
||||
circuit_port_range ports(const CircuitModelId& circuit_model_id) const;
|
||||
std::vector<CircuitModelId> circuit_models_by_type(const enum e_spice_model_type& type) const;
|
||||
std::vector<CircuitPortId> ports_by_type(const CircuitModelId& circuit_model_id, const enum e_spice_model_port_type& port_type) const;
|
||||
std::vector<CircuitPortId> ports_by_type(const CircuitModelId& circuit_model_id, const enum e_spice_model_port_type& port_type, const bool& include_global_port) const;
|
||||
std::vector<CircuitPortId> input_ports(const CircuitModelId& circuit_model_id) const;
|
||||
std::vector<CircuitPortId> output_ports(const CircuitModelId& circuit_model_id) const;
|
||||
std::vector<size_t> pins(const CircuitModelId& circuit_model_id, const CircuitPortId& circuit_port_id) const;
|
||||
circuit_model_range models() const;
|
||||
circuit_port_range ports() const;
|
||||
std::vector<CircuitModelId> models_by_type(const enum e_spice_model_type& type) const;
|
||||
public: /* Public Accessors: Basic data query on Circuit Models*/
|
||||
size_t num_circuit_models() const;
|
||||
enum e_spice_model_type circuit_model_type(const CircuitModelId& circuit_model_id) const;
|
||||
std::string circuit_model_name(const CircuitModelId& circuit_model_id) const;
|
||||
std::string circuit_model_prefix(const CircuitModelId& circuit_model_id) const;
|
||||
std::string circuit_model_verilog_netlist(const CircuitModelId& circuit_model_id) const;
|
||||
std::string circuit_model_spice_netlist(const CircuitModelId& circuit_model_id) const;
|
||||
bool circuit_model_is_default(const CircuitModelId& circuit_model_id) const;
|
||||
bool dump_structural_verilog(const CircuitModelId& circuit_model_id) const;
|
||||
bool dump_explicit_port_map(const CircuitModelId& circuit_model_id) const;
|
||||
enum e_spice_model_design_tech design_tech_type(const CircuitModelId& circuit_model_id) const;
|
||||
bool is_power_gated(const CircuitModelId& circuit_model_id) const;
|
||||
bool is_input_buffered(const CircuitModelId& circuit_model_id) const;
|
||||
bool is_output_buffered(const CircuitModelId& circuit_model_id) const;
|
||||
bool is_lut_intermediate_buffered(const CircuitModelId& circuit_model_id) const;
|
||||
enum e_spice_model_structure mux_structure(const CircuitModelId& circuit_model_id) const;
|
||||
size_t num_models() const;
|
||||
enum e_spice_model_type model_type(const CircuitModelId& model_id) const;
|
||||
std::string model_name(const CircuitModelId& model_id) const;
|
||||
std::string model_prefix(const CircuitModelId& model_id) const;
|
||||
std::string model_verilog_netlist(const CircuitModelId& model_id) const;
|
||||
std::string model_spice_netlist(const CircuitModelId& model_id) const;
|
||||
bool model_is_default(const CircuitModelId& model_id) const;
|
||||
bool dump_structural_verilog(const CircuitModelId& model_id) const;
|
||||
bool dump_explicit_port_map(const CircuitModelId& model_id) const;
|
||||
enum e_spice_model_design_tech design_tech_type(const CircuitModelId& model_id) const;
|
||||
bool is_power_gated(const CircuitModelId& model_id) const;
|
||||
/* General buffer information */
|
||||
bool is_input_buffered(const CircuitModelId& model_id) const;
|
||||
bool is_output_buffered(const CircuitModelId& model_id) const;
|
||||
/* LUT-related information */
|
||||
bool is_lut_intermediate_buffered(const CircuitModelId& model_id) const;
|
||||
/* Pass-gate-logic information */
|
||||
CircuitModelId pass_gate_logic_model(const CircuitModelId& model_id) const;
|
||||
enum e_spice_model_pass_gate_logic_type pass_gate_logic_type(const CircuitModelId& model_id) const;
|
||||
/* Multiplexer information */
|
||||
enum e_spice_model_structure mux_structure(const CircuitModelId& model_id) const;
|
||||
size_t mux_num_levels(const CircuitModelId& model_id) const;
|
||||
bool mux_add_const_input(const CircuitModelId& model_id) const;
|
||||
size_t mux_const_input_value(const CircuitModelId& model_id) const;
|
||||
/* Gate information */
|
||||
enum e_spice_model_gate_type gate_type(const CircuitModelId& model_id) const;
|
||||
/* Buffer information */
|
||||
enum e_spice_model_buffer_type buffer_type(const CircuitModelId& model_id) const;
|
||||
size_t buffer_num_levels(const CircuitModelId& model_id) const;
|
||||
/* Delay information */
|
||||
size_t num_delay_info(const CircuitModelId& model_id) const;
|
||||
public: /* Public Accessors: Basic data query on cirucit models' Circuit Ports*/
|
||||
CircuitPortId model_port(const CircuitModelId& model_id, const std::string& name) const;
|
||||
size_t num_model_ports(const CircuitModelId& model_id) const;
|
||||
size_t num_model_ports_by_type(const CircuitModelId& model_id, const enum e_spice_model_port_type& port_type, const bool& include_global_port) const;
|
||||
std::vector<CircuitPortId> model_ports(const CircuitModelId& model_id) const;
|
||||
std::vector<CircuitPortId> model_global_ports(const CircuitModelId& model_id, const bool& recursive) const;
|
||||
std::vector<CircuitPortId> model_global_ports_by_type(const CircuitModelId& model_id,
|
||||
const enum e_spice_model_port_type& type,
|
||||
const bool& recursive) const;
|
||||
std::vector<CircuitPortId> model_ports_by_type(const CircuitModelId& model_id, const enum e_spice_model_port_type& port_type) const;
|
||||
std::vector<CircuitPortId> model_ports_by_type(const CircuitModelId& model_id, const enum e_spice_model_port_type& port_type, const bool& include_global_port) const;
|
||||
std::vector<CircuitPortId> model_input_ports(const CircuitModelId& model_id) const;
|
||||
std::vector<CircuitPortId> model_output_ports(const CircuitModelId& model_id) const;
|
||||
std::vector<size_t> pins(const CircuitPortId& circuit_port_id) const;
|
||||
public: /* Public Accessors: Basic data query on Circuit Ports*/
|
||||
bool is_input_port(const CircuitModelId& circuit_model_id, const CircuitPortId& circuit_port_id) const;
|
||||
bool is_output_port(const CircuitModelId& circuit_model_id, const CircuitPortId& circuit_port_id) const;
|
||||
CircuitPortId port(const CircuitModelId& circuit_model_id, const std::string& name) const;
|
||||
size_t num_ports(const CircuitModelId& circuit_model_id) const;
|
||||
size_t num_ports_by_type(const CircuitModelId& circuit_model_id, const enum e_spice_model_port_type& port_type, const bool& include_global_port) const;
|
||||
enum e_spice_model_port_type port_type(const CircuitModelId& circuit_model_id, const CircuitPortId& circuit_port_id) const;
|
||||
size_t port_size(const CircuitModelId& circuit_model_id, const CircuitPortId& circuit_port_id) const;
|
||||
std::string port_prefix(const CircuitModelId& circuit_model_id, const CircuitPortId& circuit_port_id) const;
|
||||
std::string port_lib_name(const CircuitModelId& circuit_model_id, const CircuitPortId& circuit_port_id) const;
|
||||
std::string port_inv_prefix(const CircuitModelId& circuit_model_id, const CircuitPortId& circuit_port_id) const;
|
||||
size_t port_default_value(const CircuitModelId& circuit_model_id, const CircuitPortId& circuit_port_id) const;
|
||||
bool port_is_mode_select(const CircuitModelId& circuit_model_id, const CircuitPortId& circuit_port_id) const;
|
||||
bool port_is_global(const CircuitModelId& circuit_model_id, const CircuitPortId& circuit_port_id) const;
|
||||
bool port_is_reset(const CircuitModelId& circuit_model_id, const CircuitPortId& circuit_port_id) const;
|
||||
bool port_is_set(const CircuitModelId& circuit_model_id, const CircuitPortId& circuit_port_id) const;
|
||||
bool port_is_config_enable(const CircuitModelId& circuit_model_id, const CircuitPortId& circuit_port_id) const;
|
||||
bool port_is_prog(const CircuitModelId& circuit_model_id, const CircuitPortId& circuit_port_id) const;
|
||||
public: /* Public Accessors: Methods to find circuit model */
|
||||
CircuitModelId circuit_model(const char* name) const;
|
||||
CircuitModelId circuit_model(const std::string& name) const;
|
||||
CircuitModelId default_circuit_model(const enum e_spice_model_type& type) const;
|
||||
bool is_input_port(const CircuitPortId& circuit_port_id) const;
|
||||
bool is_output_port(const CircuitPortId& circuit_port_id) const;
|
||||
enum e_spice_model_port_type port_type(const CircuitPortId& circuit_port_id) const;
|
||||
size_t port_size(const CircuitPortId& circuit_port_id) const;
|
||||
std::string port_prefix(const CircuitPortId& circuit_port_id) const;
|
||||
std::string port_lib_name(const CircuitPortId& circuit_port_id) const;
|
||||
std::string port_inv_prefix(const CircuitPortId& circuit_port_id) const;
|
||||
size_t port_default_value(const CircuitPortId& circuit_port_id) const;
|
||||
bool port_is_mode_select(const CircuitPortId& circuit_port_id) const;
|
||||
bool port_is_global(const CircuitPortId& circuit_port_id) const;
|
||||
bool port_is_reset(const CircuitPortId& circuit_port_id) const;
|
||||
bool port_is_set(const CircuitPortId& circuit_port_id) const;
|
||||
bool port_is_config_enable(const CircuitPortId& circuit_port_id) const;
|
||||
bool port_is_prog(const CircuitPortId& circuit_port_id) const;
|
||||
CircuitModelId port_parent_model(const CircuitPortId& circuit_port_id) const;
|
||||
std::string model_name(const CircuitPortId& port_id) const;
|
||||
public: /* Public Accessors: Timing graph */
|
||||
CircuitEdgeId edge(const CircuitModelId& circuit_model_id,
|
||||
const CircuitPortId& from_port, const size_t from_pin,
|
||||
/* Get source/sink nodes and delay of edges */
|
||||
std::vector<CircuitEdgeId> timing_edges_by_model(const CircuitModelId& model_id) const;
|
||||
CircuitPortId timing_edge_src_port(const CircuitEdgeId& edge) const;
|
||||
size_t timing_edge_src_pin(const CircuitEdgeId& edge) const;
|
||||
CircuitPortId timing_edge_sink_port(const CircuitEdgeId& edge) const;
|
||||
size_t timing_edge_sink_pin(const CircuitEdgeId& edge) const;
|
||||
float timing_edge_delay(const CircuitEdgeId& edge, const enum spice_model_delay_type& delay_type) const;
|
||||
public: /* Public Accessors: Methods to find circuit model */
|
||||
CircuitModelId model(const char* name) const;
|
||||
CircuitModelId model(const std::string& name) const;
|
||||
CircuitModelId default_model(const enum e_spice_model_type& type) const;
|
||||
public: /* Public Accessors: Timing graph */
|
||||
CircuitEdgeId edge(const CircuitPortId& from_port, const size_t from_pin,
|
||||
const CircuitPortId& to_port, const size_t to_pin);
|
||||
public: /* Public Mutators */
|
||||
CircuitModelId add_circuit_model();
|
||||
CircuitModelId add_model(const enum e_spice_model_type& type);
|
||||
/* Fundamental information */
|
||||
void set_circuit_model_type(const CircuitModelId& circuit_model_id, const enum e_spice_model_type& type);
|
||||
void set_circuit_model_name(const CircuitModelId& circuit_model_id, const std::string& name);
|
||||
void set_circuit_model_prefix(const CircuitModelId& circuit_model_id, const std::string& prefix);
|
||||
void set_circuit_model_verilog_netlist(const CircuitModelId& circuit_model_id, const std::string& verilog_netlist);
|
||||
void set_circuit_model_spice_netlist(const CircuitModelId& circuit_model_id, const std::string& spice_netlist);
|
||||
void set_circuit_model_is_default(const CircuitModelId& circuit_model_id, const bool& is_default);
|
||||
void set_model_name(const CircuitModelId& model_id, const std::string& name);
|
||||
void set_model_prefix(const CircuitModelId& model_id, const std::string& prefix);
|
||||
void set_model_verilog_netlist(const CircuitModelId& model_id, const std::string& verilog_netlist);
|
||||
void set_model_spice_netlist(const CircuitModelId& model_id, const std::string& spice_netlist);
|
||||
void set_model_is_default(const CircuitModelId& model_id, const bool& is_default);
|
||||
/* Verilog generator options */
|
||||
void set_circuit_model_dump_structural_verilog(const CircuitModelId& circuit_model_id, const bool& dump_structural_verilog);
|
||||
void set_circuit_model_dump_explicit_port_map(const CircuitModelId& circuit_model_id, const bool& dump_explicit_port_map);
|
||||
void set_model_dump_structural_verilog(const CircuitModelId& model_id, const bool& dump_structural_verilog);
|
||||
void set_model_dump_explicit_port_map(const CircuitModelId& model_id, const bool& dump_explicit_port_map);
|
||||
/* Design technology information */
|
||||
void set_circuit_model_design_tech_type(const CircuitModelId& circuit_model_id, const enum e_spice_model_design_tech& design_tech_type);
|
||||
void set_circuit_model_is_power_gated(const CircuitModelId& circuit_model_id, const bool& is_power_gated);
|
||||
void set_model_design_tech_type(const CircuitModelId& model_id, const enum e_spice_model_design_tech& design_tech_type);
|
||||
void set_model_is_power_gated(const CircuitModelId& model_id, const bool& is_power_gated);
|
||||
/* Buffer existence */
|
||||
void set_circuit_model_input_buffer(const CircuitModelId& circuit_model_id,
|
||||
const bool& existence, const std::string& circuit_model_name);
|
||||
void set_circuit_model_output_buffer(const CircuitModelId& circuit_model_id,
|
||||
const bool& existence, const std::string& circuit_model_name);
|
||||
void set_circuit_model_lut_input_buffer(const CircuitModelId& circuit_model_id,
|
||||
const bool& existence, const std::string& circuit_model_name);
|
||||
void set_circuit_model_lut_input_inverter(const CircuitModelId& circuit_model_id,
|
||||
const bool& existence, const std::string& circuit_model_name);
|
||||
void set_circuit_model_lut_intermediate_buffer(const CircuitModelId& circuit_model_id,
|
||||
const bool& existence, const std::string& circuit_model_name);
|
||||
void set_circuit_model_lut_intermediate_buffer_location_map(const CircuitModelId& circuit_model_id,
|
||||
const std::string& location_map);
|
||||
void set_model_input_buffer(const CircuitModelId& model_id,
|
||||
const bool& existence, const std::string& model_name);
|
||||
void set_model_output_buffer(const CircuitModelId& model_id,
|
||||
const bool& existence, const std::string& model_name);
|
||||
void set_model_lut_input_buffer(const CircuitModelId& model_id,
|
||||
const bool& existence, const std::string& model_name);
|
||||
void set_model_lut_input_inverter(const CircuitModelId& model_id,
|
||||
const bool& existence, const std::string& model_name);
|
||||
void set_model_lut_intermediate_buffer(const CircuitModelId& model_id,
|
||||
const bool& existence, const std::string& model_name);
|
||||
void set_model_lut_intermediate_buffer_location_map(const CircuitModelId& model_id,
|
||||
const std::string& location_map);
|
||||
/* Pass-gate-related parameters */
|
||||
void set_circuit_model_pass_gate_logic(const CircuitModelId& circuit_model_id, const std::string& circuit_model_name);
|
||||
void set_model_pass_gate_logic(const CircuitModelId& model_id, const std::string& model_name);
|
||||
/* Port information */
|
||||
CircuitPortId add_circuit_model_port(const CircuitModelId& circuit_model_id);
|
||||
void set_port_type(const CircuitModelId& circuit_model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
const enum e_spice_model_port_type& port_type);
|
||||
void set_port_size(const CircuitModelId& circuit_model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
CircuitPortId add_model_port(const CircuitModelId& model_id,
|
||||
const enum e_spice_model_port_type& port_type);
|
||||
void set_port_size(const CircuitPortId& circuit_port_id,
|
||||
const size_t& port_size);
|
||||
void set_port_prefix(const CircuitModelId& circuit_model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
void set_port_prefix(const CircuitPortId& circuit_port_id,
|
||||
const std::string& port_prefix);
|
||||
void set_port_lib_name(const CircuitModelId& circuit_model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
void set_port_lib_name(const CircuitPortId& circuit_port_id,
|
||||
const std::string& lib_name);
|
||||
void set_port_inv_prefix(const CircuitModelId& circuit_model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
void set_port_inv_prefix(const CircuitPortId& circuit_port_id,
|
||||
const std::string& inv_prefix);
|
||||
void set_port_default_value(const CircuitModelId& circuit_model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
void set_port_default_value(const CircuitPortId& circuit_port_id,
|
||||
const size_t& default_val);
|
||||
void set_port_is_mode_select(const CircuitModelId& circuit_model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
void set_port_is_mode_select(const CircuitPortId& circuit_port_id,
|
||||
const bool& is_mode_select);
|
||||
void set_port_is_global(const CircuitModelId& circuit_model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
void set_port_is_global(const CircuitPortId& circuit_port_id,
|
||||
const bool& is_global);
|
||||
void set_port_is_reset(const CircuitModelId& circuit_model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
void set_port_is_reset(const CircuitPortId& circuit_port_id,
|
||||
const bool& is_reset);
|
||||
void set_port_is_set(const CircuitModelId& circuit_model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
void set_port_is_set(const CircuitPortId& circuit_port_id,
|
||||
const bool& is_set);
|
||||
void set_port_is_config_enable(const CircuitModelId& circuit_model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
void set_port_is_config_enable(const CircuitPortId& circuit_port_id,
|
||||
const bool& is_config_enable);
|
||||
void set_port_is_prog(const CircuitModelId& circuit_model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
void set_port_is_prog(const CircuitPortId& circuit_port_id,
|
||||
const bool& is_prog);
|
||||
void set_port_circuit_model_name(const CircuitModelId& circuit_model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
const std::string& circuit_model_name);
|
||||
void set_port_circuit_model_id(const CircuitModelId& circuit_model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
const CircuitModelId& port_circuit_model_id);
|
||||
void set_port_inv_circuit_model_name(const CircuitModelId& circuit_model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
const std::string& inv_circuit_model_name);
|
||||
void set_port_inv_circuit_model_id(const CircuitModelId& circuit_model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
const CircuitModelId& inv_circuit_model_id);
|
||||
void set_port_tri_state_map(const CircuitModelId& circuit_model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
void set_port_tri_state_model_name(const CircuitPortId& circuit_port_id,
|
||||
const std::string& model_name);
|
||||
void set_port_tri_state_model_id(const CircuitPortId& circuit_port_id,
|
||||
const CircuitModelId& port_model_id);
|
||||
void set_port_inv_model_name(const CircuitPortId& circuit_port_id,
|
||||
const std::string& inv_model_name);
|
||||
void set_port_inv_model_id(const CircuitPortId& circuit_port_id,
|
||||
const CircuitModelId& inv_model_id);
|
||||
void set_port_tri_state_map(const CircuitPortId& circuit_port_id,
|
||||
const std::string& tri_state_map);
|
||||
void set_port_lut_frac_level(const CircuitModelId& circuit_model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
void set_port_lut_frac_level(const CircuitPortId& circuit_port_id,
|
||||
const size_t& lut_frac_level);
|
||||
void set_port_lut_output_mask(const CircuitModelId& circuit_model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
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 CircuitModelId& circuit_model_id,
|
||||
const CircuitPortId& circuit_port_id,
|
||||
void set_port_sram_orgz(const CircuitPortId& circuit_port_id,
|
||||
const enum e_sram_orgz& sram_orgz);
|
||||
/* Delay information */
|
||||
void add_delay_info(const CircuitModelId& circuit_model_id,
|
||||
void add_delay_info(const CircuitModelId& model_id,
|
||||
const enum spice_model_delay_type& delay_type);
|
||||
void set_delay_in_port_names(const CircuitModelId& circuit_model_id,
|
||||
void set_delay_in_port_names(const CircuitModelId& model_id,
|
||||
const enum spice_model_delay_type& delay_type,
|
||||
const std::string& in_port_names);
|
||||
void set_delay_out_port_names(const CircuitModelId& circuit_model_id,
|
||||
void set_delay_out_port_names(const CircuitModelId& model_id,
|
||||
const enum spice_model_delay_type& delay_type,
|
||||
const std::string& out_port_names);
|
||||
void set_delay_values(const CircuitModelId& circuit_model_id,
|
||||
void set_delay_values(const CircuitModelId& model_id,
|
||||
const enum spice_model_delay_type& delay_type,
|
||||
const std::string& delay_values);
|
||||
/* Buffer/Inverter-related parameters */
|
||||
void set_buffer_type(const CircuitModelId& circuit_model_id,
|
||||
void set_buffer_type(const CircuitModelId& model_id,
|
||||
const enum e_spice_model_buffer_type& buffer_type);
|
||||
void set_buffer_size(const CircuitModelId& circuit_model_id,
|
||||
void set_buffer_size(const CircuitModelId& model_id,
|
||||
const float& buffer_size);
|
||||
void set_buffer_num_levels(const CircuitModelId& circuit_model_id,
|
||||
void set_buffer_num_levels(const CircuitModelId& model_id,
|
||||
const size_t& num_levels);
|
||||
void set_buffer_f_per_stage(const CircuitModelId& circuit_model_id,
|
||||
void set_buffer_f_per_stage(const CircuitModelId& model_id,
|
||||
const size_t& f_per_stage);
|
||||
/* Pass-gate-related parameters */
|
||||
void set_pass_gate_logic_type(const CircuitModelId& circuit_model_id,
|
||||
void set_pass_gate_logic_type(const CircuitModelId& model_id,
|
||||
const enum e_spice_model_pass_gate_logic_type& pass_gate_logic_type);
|
||||
void set_pass_gate_logic_nmos_size(const CircuitModelId& circuit_model_id,
|
||||
void set_pass_gate_logic_nmos_size(const CircuitModelId& model_id,
|
||||
const float& nmos_size);
|
||||
void set_pass_gate_logic_pmos_size(const CircuitModelId& circuit_model_id,
|
||||
void set_pass_gate_logic_pmos_size(const CircuitModelId& model_id,
|
||||
const float& pmos_size);
|
||||
/* Multiplexer-related parameters */
|
||||
void set_mux_structure(const CircuitModelId& circuit_model_id,
|
||||
void set_mux_structure(const CircuitModelId& model_id,
|
||||
const enum e_spice_model_structure& mux_structure);
|
||||
void set_mux_num_levels(const CircuitModelId& circuit_model_id,
|
||||
void set_mux_num_levels(const CircuitModelId& model_id,
|
||||
const size_t& num_levels);
|
||||
void set_mux_const_input_value(const CircuitModelId& circuit_model_id,
|
||||
void set_mux_const_input_value(const CircuitModelId& model_id,
|
||||
const size_t& const_input_value);
|
||||
void set_mux_use_local_encoder(const CircuitModelId& circuit_model_id,
|
||||
void set_mux_use_local_encoder(const CircuitModelId& model_id,
|
||||
const bool& use_local_encoder);
|
||||
void set_mux_use_advanced_rram_design(const CircuitModelId& circuit_model_id,
|
||||
void set_mux_use_advanced_rram_design(const CircuitModelId& model_id,
|
||||
const bool& use_advanced_rram_design);
|
||||
/* LUT-related parameters */
|
||||
void set_lut_is_fracturable(const CircuitModelId& circuit_model_id,
|
||||
void set_lut_is_fracturable(const CircuitModelId& model_id,
|
||||
const bool& is_fracturable);
|
||||
/* Gate-related parameters */
|
||||
void set_gate_type(const CircuitModelId& circuit_model_id,
|
||||
void set_gate_type(const CircuitModelId& model_id,
|
||||
const enum e_spice_model_gate_type& gate_type);
|
||||
/* RRAM-related design technology information */
|
||||
void set_rram_rlrs(const CircuitModelId& circuit_model_id,
|
||||
void set_rram_rlrs(const CircuitModelId& model_id,
|
||||
const float& rlrs);
|
||||
void set_rram_rhrs(const CircuitModelId& circuit_model_id,
|
||||
void set_rram_rhrs(const CircuitModelId& model_id,
|
||||
const float& rhrs);
|
||||
void set_rram_wprog_set_nmos(const CircuitModelId& circuit_model_id,
|
||||
void set_rram_wprog_set_nmos(const CircuitModelId& model_id,
|
||||
const float& wprog_set_nmos);
|
||||
void set_rram_wprog_set_pmos(const CircuitModelId& circuit_model_id,
|
||||
void set_rram_wprog_set_pmos(const CircuitModelId& model_id,
|
||||
const float& wprog_set_pmos);
|
||||
void set_rram_wprog_reset_nmos(const CircuitModelId& circuit_model_id,
|
||||
void set_rram_wprog_reset_nmos(const CircuitModelId& model_id,
|
||||
const float& wprog_reset_nmos);
|
||||
void set_rram_wprog_reset_pmos(const CircuitModelId& circuit_model_id,
|
||||
void set_rram_wprog_reset_pmos(const CircuitModelId& model_id,
|
||||
const float& wprog_reset_pmos);
|
||||
/* Wire parameters */
|
||||
void set_wire_type(const CircuitModelId& circuit_model_id,
|
||||
void set_wire_type(const CircuitModelId& model_id,
|
||||
const enum e_wire_model_type& wire_type);
|
||||
void set_wire_r(const CircuitModelId& circuit_model_id,
|
||||
void set_wire_r(const CircuitModelId& model_id,
|
||||
const float& r_val);
|
||||
void set_wire_c(const CircuitModelId& circuit_model_id,
|
||||
void set_wire_c(const CircuitModelId& model_id,
|
||||
const float& c_val);
|
||||
void set_wire_num_levels(const CircuitModelId& circuit_model_id,
|
||||
void set_wire_num_levels(const CircuitModelId& model_id,
|
||||
const size_t& num_level);
|
||||
private: /* Private Mutators: builders */
|
||||
void set_model_buffer(const CircuitModelId& model_id, const enum e_buffer_type buffer_type, const bool& existence, const std::string& model_name);
|
||||
void link_port_tri_state_model();
|
||||
void link_port_inv_model();
|
||||
void link_buffer_model(const CircuitModelId& model_id);
|
||||
void link_pass_gate_logic_model(const CircuitModelId& model_id);
|
||||
bool is_unique_submodel(const CircuitModelId& model_id, const CircuitModelId& submodel_id);
|
||||
void build_submodels();
|
||||
void build_model_timing_graph(const CircuitModelId& model_id);
|
||||
public: /* Public Mutators: builders */
|
||||
void set_circuit_model_buffer(const CircuitModelId& circuit_model_id, const enum e_buffer_type buffer_type, const bool& existence, const std::string& circuit_model_name);
|
||||
void link_port_circuit_model(const CircuitModelId& circuit_model_id);
|
||||
void link_port_inv_circuit_model(const CircuitModelId& circuit_model_id);
|
||||
void link_port_circuit_models(const CircuitModelId& circuit_model_id);
|
||||
void link_buffer_circuit_model(const CircuitModelId& circuit_model_id);
|
||||
void link_pass_gate_logic_circuit_model(const CircuitModelId& circuit_model_id);
|
||||
void build_circuit_model_links();
|
||||
void build_circuit_model_timing_graph(const CircuitModelId& circuit_model_id);
|
||||
void build_model_links();
|
||||
void build_timing_graphs();
|
||||
public: /* Internal mutators: build timing graphs */
|
||||
void add_edge(const CircuitModelId& circuit_model_id,
|
||||
void add_edge(const CircuitModelId& model_id,
|
||||
const CircuitPortId& from_port, const size_t& from_pin,
|
||||
const CircuitPortId& to_port, const size_t& to_pin);
|
||||
void set_edge_delay(const CircuitModelId& circuit_model_id,
|
||||
void set_edge_delay(const CircuitModelId& model_id,
|
||||
const CircuitEdgeId& circuit_edge_id,
|
||||
const enum spice_model_delay_type& delay_type,
|
||||
const float& delay_value);
|
||||
/* validate the circuit_edge_id */
|
||||
void set_timing_graph_delays(const CircuitModelId& circuit_model_id);
|
||||
void set_timing_graph_delays(const CircuitModelId& model_id);
|
||||
public: /* Internal mutators: build fast look-ups */
|
||||
void build_circuit_model_lookup();
|
||||
void build_circuit_model_port_lookup(const CircuitModelId& circuit_model_id);
|
||||
void build_model_lookup();
|
||||
void build_model_port_lookup();
|
||||
private: /* Internal invalidators/validators */
|
||||
/* Validators */
|
||||
bool valid_circuit_model_id(const CircuitModelId& circuit_model_id) const;
|
||||
bool valid_circuit_port_id(const CircuitModelId& circuit_model_id, const CircuitPortId& circuit_port_id) const;
|
||||
bool valid_circuit_pin_id(const CircuitModelId& circuit_model_id, const CircuitPortId& circuit_port_id, const size_t& pin_id) const;
|
||||
bool valid_delay_type(const CircuitModelId& circuit_model_id, const enum spice_model_delay_type& delay_type) const;
|
||||
bool valid_circuit_edge_id(const CircuitModelId& circuit_model_id, const CircuitEdgeId& circuit_edge_id) const;
|
||||
bool valid_model_id(const CircuitModelId& model_id) const;
|
||||
bool valid_circuit_port_id(const CircuitPortId& circuit_port_id) const;
|
||||
bool valid_circuit_pin_id(const CircuitPortId& circuit_port_id, const size_t& pin_id) const;
|
||||
bool valid_edge_id(const CircuitEdgeId& edge_id) const;
|
||||
bool valid_delay_type(const CircuitModelId& model_id, const enum spice_model_delay_type& delay_type) const;
|
||||
bool valid_circuit_edge_id(const CircuitEdgeId& circuit_edge_id) const;
|
||||
bool valid_mux_const_input_value(const size_t& const_input_value) const;
|
||||
/* Invalidators */
|
||||
void invalidate_circuit_model_lookup() const;
|
||||
void invalidate_circuit_model_port_lookup(const CircuitModelId& circuit_model_id) const;
|
||||
void invalidate_circuit_model_timing_graph(const CircuitModelId& circuit_model_id);
|
||||
void invalidate_model_lookup() const;
|
||||
void invalidate_model_port_lookup() const;
|
||||
void invalidate_model_timing_graph();
|
||||
private: /* Internal data */
|
||||
/* Fundamental information */
|
||||
vtr::vector<CircuitModelId, CircuitModelId> circuit_model_ids_;
|
||||
vtr::vector<CircuitModelId, enum e_spice_model_type> circuit_model_types_;
|
||||
vtr::vector<CircuitModelId, std::string> circuit_model_names_;
|
||||
vtr::vector<CircuitModelId, std::string> circuit_model_prefix_;
|
||||
vtr::vector<CircuitModelId, std::string> circuit_model_verilog_netlists_;
|
||||
vtr::vector<CircuitModelId, std::string> circuit_model_spice_netlists_;
|
||||
vtr::vector<CircuitModelId, bool> circuit_model_is_default_;
|
||||
vtr::vector<CircuitModelId, CircuitModelId> model_ids_;
|
||||
vtr::vector<CircuitModelId, enum e_spice_model_type> model_types_;
|
||||
vtr::vector<CircuitModelId, std::string> model_names_;
|
||||
vtr::vector<CircuitModelId, std::string> model_prefix_;
|
||||
vtr::vector<CircuitModelId, std::string> model_verilog_netlists_;
|
||||
vtr::vector<CircuitModelId, std::string> model_spice_netlists_;
|
||||
vtr::vector<CircuitModelId, bool> model_is_default_;
|
||||
|
||||
/* Submodules that a circuit model contains */
|
||||
vtr::vector<CircuitModelId, std::vector<CircuitModelId>> sub_models_;
|
||||
|
||||
/* fast look-up for circuit models to categorize by types
|
||||
* [type][num_ids]
|
||||
* Important: we force the default circuit model in the first element for each type
|
||||
*/
|
||||
typedef std::vector<std::vector<CircuitModelId>> CircuitModelLookup;
|
||||
mutable CircuitModelLookup circuit_model_lookup_; /* [circuit_model_type][circuit_model_ids] */
|
||||
typedef std::vector<std::vector<std::vector<CircuitPortId>>> CircuitModelPortLookup;
|
||||
mutable CircuitModelPortLookup circuit_model_port_lookup_; /* [circuit_model_id][port_type][port_ids] */
|
||||
mutable CircuitModelLookup model_lookup_; /* [model_type][model_ids] */
|
||||
typedef vtr::vector<CircuitModelId, std::vector<std::vector<CircuitPortId>>> CircuitModelPortLookup;
|
||||
mutable CircuitModelPortLookup model_port_lookup_; /* [model_id][port_type][port_ids] */
|
||||
|
||||
/* Verilog generator options */
|
||||
vtr::vector<CircuitModelId, bool> dump_structural_verilog_;
|
||||
|
@ -490,46 +493,48 @@ class CircuitLibrary {
|
|||
|
||||
/* Buffer existence */
|
||||
vtr::vector<CircuitModelId, std::vector<bool>> buffer_existence_;
|
||||
vtr::vector<CircuitModelId, std::vector<std::string>> buffer_circuit_model_names_;
|
||||
vtr::vector<CircuitModelId, std::vector<CircuitModelId>> buffer_circuit_model_ids_;
|
||||
vtr::vector<CircuitModelId, std::vector<std::string>> buffer_model_names_;
|
||||
vtr::vector<CircuitModelId, std::vector<CircuitModelId>> buffer_model_ids_;
|
||||
vtr::vector<CircuitModelId, std::vector<std::string>> buffer_location_maps_;
|
||||
|
||||
/* Pass-gate-related parameters */
|
||||
vtr::vector<CircuitModelId, std::string> pass_gate_logic_circuit_model_names_;
|
||||
vtr::vector<CircuitModelId, CircuitModelId> pass_gate_logic_circuit_model_ids_;
|
||||
vtr::vector<CircuitModelId, std::string> pass_gate_logic_model_names_;
|
||||
vtr::vector<CircuitModelId, CircuitModelId> pass_gate_logic_model_ids_;
|
||||
|
||||
/* Port information */
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, CircuitPortId>> port_ids_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, enum e_spice_model_port_type>> port_types_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, size_t>> port_sizes_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, std::string>> port_prefix_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, std::string>> port_lib_names_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, std::string>> port_inv_prefix_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, size_t>> port_default_values_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, bool>> port_is_mode_select_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, bool>> port_is_global_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, bool>> port_is_reset_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, bool>> port_is_set_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, bool>> port_is_config_enable_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, bool>> port_is_prog_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, std::string>> port_circuit_model_names_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, CircuitModelId>> port_circuit_model_ids_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, std::string>> port_inv_circuit_model_names_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, CircuitModelId>> port_inv_circuit_model_ids_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, std::string>> port_tri_state_maps_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, size_t>> port_lut_frac_level_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, std::vector<size_t>>> port_lut_output_masks_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, enum e_sram_orgz>> port_sram_orgz_;
|
||||
vtr::vector<CircuitPortId, CircuitPortId> port_ids_;
|
||||
vtr::vector<CircuitPortId, CircuitModelId> port_model_ids_;
|
||||
vtr::vector<CircuitPortId, enum e_spice_model_port_type> port_types_;
|
||||
vtr::vector<CircuitPortId, size_t> port_sizes_;
|
||||
vtr::vector<CircuitPortId, std::string> port_prefix_;
|
||||
vtr::vector<CircuitPortId, std::string> port_lib_names_;
|
||||
vtr::vector<CircuitPortId, std::string> port_inv_prefix_;
|
||||
vtr::vector<CircuitPortId, size_t> port_default_values_;
|
||||
vtr::vector<CircuitPortId, bool> port_is_mode_select_;
|
||||
vtr::vector<CircuitPortId, bool> port_is_global_;
|
||||
vtr::vector<CircuitPortId, bool> port_is_reset_;
|
||||
vtr::vector<CircuitPortId, bool> port_is_set_;
|
||||
vtr::vector<CircuitPortId, bool> port_is_config_enable_;
|
||||
vtr::vector<CircuitPortId, bool> port_is_prog_;
|
||||
vtr::vector<CircuitPortId, std::string> port_tri_state_model_names_;
|
||||
vtr::vector<CircuitPortId, CircuitModelId> port_tri_state_model_ids_;
|
||||
vtr::vector<CircuitPortId, std::string> port_inv_model_names_;
|
||||
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, std::vector<size_t>> port_lut_output_masks_;
|
||||
vtr::vector<CircuitPortId, enum e_sram_orgz> port_sram_orgz_;
|
||||
|
||||
/* Timing graphs */
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitEdgeId, CircuitEdgeId>> edge_ids_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, vtr::vector<size_t, CircuitEdgeId>>> port_in_edge_ids_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitPortId, vtr::vector<size_t, CircuitEdgeId>>> port_out_edge_ids_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitEdgeId, CircuitPortId>> edge_src_port_ids_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitEdgeId, size_t>> edge_src_pin_ids_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitEdgeId, CircuitPortId>> edge_sink_port_ids_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitEdgeId, size_t>> edge_sink_pin_ids_;
|
||||
vtr::vector<CircuitModelId, vtr::vector<CircuitEdgeId, std::vector<float>>> edge_timing_info_; /* x0 => trise, x1 => tfall */
|
||||
vtr::vector<CircuitEdgeId, CircuitEdgeId> edge_ids_;
|
||||
vtr::vector<CircuitEdgeId, CircuitModelId> edge_parent_model_ids_;
|
||||
vtr::vector<CircuitPortId, vtr::vector<size_t, CircuitEdgeId>> port_in_edge_ids_;
|
||||
vtr::vector<CircuitPortId, vtr::vector<size_t, CircuitEdgeId>> port_out_edge_ids_;
|
||||
vtr::vector<CircuitEdgeId, CircuitPortId> edge_src_port_ids_;
|
||||
vtr::vector<CircuitEdgeId, size_t> edge_src_pin_ids_;
|
||||
vtr::vector<CircuitEdgeId, CircuitPortId> edge_sink_port_ids_;
|
||||
vtr::vector<CircuitEdgeId, size_t> edge_sink_pin_ids_;
|
||||
vtr::vector<CircuitEdgeId, std::vector<float>> edge_timing_info_; /* x0 => trise, x1 => tfall */
|
||||
|
||||
/* Delay information */
|
||||
vtr::vector<CircuitModelId, std::vector<enum spice_model_delay_type>> delay_types_;
|
||||
|
@ -569,7 +574,6 @@ class CircuitLibrary {
|
|||
vtr::vector<CircuitModelId, enum e_wire_model_type> wire_types_;
|
||||
vtr::vector<CircuitModelId, vtr::Point<float>> wire_rc_; /* x => wire_res_val, y=> wire_cap_val */
|
||||
vtr::vector<CircuitModelId, size_t> wire_num_levels_;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/************************************************************************
|
||||
* A header file for CircuitLibrary class, including critical data declaration
|
||||
* Please include this file only for using any CircuitLibrary data structure
|
||||
* Refer to circuit_library.h for more details
|
||||
***********************************************************************/
|
||||
|
||||
/************************************************************************
|
||||
* Create strong id for Circuit Models/Ports to avoid illegal type casting
|
||||
***********************************************************************/
|
||||
#ifndef CIRCUIT_LIBRARY_FWD_H
|
||||
#define CIRCUIT_LIBRARY_FWD_H
|
||||
|
||||
#include "vtr_strong_id.h"
|
||||
|
||||
struct circuit_model_id_tag;
|
||||
struct circuit_port_id_tag;
|
||||
struct circuit_edge_id_tag;
|
||||
|
||||
typedef vtr::StrongId<circuit_model_id_tag> CircuitModelId;
|
||||
typedef vtr::StrongId<circuit_port_id_tag> CircuitPortId;
|
||||
typedef vtr::StrongId<circuit_edge_id_tag> CircuitEdgeId;
|
||||
|
||||
/* Short declaration of class */
|
||||
class CircuitLibrary;
|
||||
|
||||
#endif
|
|
@ -101,6 +101,8 @@ enum e_spice_model_buffer_type {
|
|||
enum e_spice_model_pass_gate_logic_type {
|
||||
SPICE_MODEL_PASS_GATE_TRANSMISSION,
|
||||
SPICE_MODEL_PASS_GATE_TRANSISTOR,
|
||||
SPICE_MODEL_PASS_GATE_RRAM, /* RRAM can be treated as a special type of pass-gate logic */
|
||||
SPICE_MODEL_PASS_GATE_STDCELL, /* Standard cell as a special type of pass-gate logic */
|
||||
NUM_CIRCUIT_MODEL_PASS_GATE_TYPES
|
||||
};
|
||||
|
||||
|
|
|
@ -13,6 +13,27 @@ BasicPort::BasicPort() {
|
|||
msb_ = 0;
|
||||
}
|
||||
|
||||
/* Quick constructor */
|
||||
BasicPort::BasicPort(const char* name, const size_t& lsb, const size_t& msb) {
|
||||
set_name(std::string(name));
|
||||
set_width(lsb, msb);
|
||||
}
|
||||
|
||||
BasicPort::BasicPort(const std::string& name, const size_t& lsb, const size_t& msb) {
|
||||
set_name(name);
|
||||
set_width(lsb, msb);
|
||||
}
|
||||
|
||||
BasicPort::BasicPort(const char* name, const size_t& width) {
|
||||
set_name(std::string(name));
|
||||
set_width(width);
|
||||
}
|
||||
|
||||
BasicPort::BasicPort(const std::string& name, const size_t& width) {
|
||||
set_name(name);
|
||||
set_width(width);
|
||||
}
|
||||
|
||||
/* Copy constructor */
|
||||
BasicPort::BasicPort(const BasicPort& basic_port) {
|
||||
set(basic_port);
|
||||
|
@ -59,7 +80,7 @@ void BasicPort::set_name(const std::string& name) {
|
|||
}
|
||||
|
||||
/* set the port LSB and MSB */
|
||||
void BasicPort::set_width(size_t width) {
|
||||
void BasicPort::set_width(const size_t& width) {
|
||||
if (0 == width) {
|
||||
make_invalid();
|
||||
return;
|
||||
|
@ -70,7 +91,7 @@ void BasicPort::set_width(size_t width) {
|
|||
}
|
||||
|
||||
/* set the port LSB and MSB */
|
||||
void BasicPort::set_width(size_t lsb, size_t msb) {
|
||||
void BasicPort::set_width(const size_t& lsb, const size_t& msb) {
|
||||
/* If lsb and msb is invalid, we make a default port */
|
||||
if (lsb > msb) {
|
||||
make_invalid();
|
||||
|
@ -81,18 +102,18 @@ void BasicPort::set_width(size_t lsb, size_t msb) {
|
|||
return;
|
||||
}
|
||||
|
||||
void BasicPort::set_lsb(size_t lsb) {
|
||||
void BasicPort::set_lsb(const size_t& lsb) {
|
||||
lsb_ = lsb;
|
||||
return;
|
||||
}
|
||||
|
||||
void BasicPort::set_msb(size_t msb) {
|
||||
void BasicPort::set_msb(const size_t& msb) {
|
||||
msb_ = msb;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Increase the port width */
|
||||
void BasicPort::expand(size_t width) {
|
||||
void BasicPort::expand(const size_t& width) {
|
||||
if (0 == width) {
|
||||
return; /* ignore zero-width port */
|
||||
}
|
||||
|
@ -114,7 +135,7 @@ void BasicPort::revert() {
|
|||
}
|
||||
|
||||
/* rotate: increase both lsb and msb by an offset */
|
||||
bool BasicPort::rotate(size_t offset) {
|
||||
bool BasicPort::rotate(const size_t& offset) {
|
||||
/* If current port is invalid or offset is 0,
|
||||
* we do nothing
|
||||
*/
|
||||
|
@ -134,7 +155,7 @@ bool BasicPort::rotate(size_t offset) {
|
|||
}
|
||||
|
||||
/* rotate: decrease both lsb and msb by an offset */
|
||||
bool BasicPort::counter_rotate(size_t offset) {
|
||||
bool BasicPort::counter_rotate(const size_t& offset) {
|
||||
/* If current port is invalid or offset is 0,
|
||||
* we do nothing
|
||||
*/
|
||||
|
|
|
@ -11,6 +11,10 @@
|
|||
class BasicPort {
|
||||
public: /* Constructors */
|
||||
BasicPort();
|
||||
BasicPort(const char* name, const size_t& lsb, const size_t& msb);
|
||||
BasicPort(const char* name, const size_t& width);
|
||||
BasicPort(const std::string& name, const size_t& lsb, const size_t& msb);
|
||||
BasicPort(const std::string& name, const size_t& width);
|
||||
BasicPort(const BasicPort& basic_port); /* Copy constructor */
|
||||
public: /* Accessors */
|
||||
size_t get_width() const; /* get the port width */
|
||||
|
@ -21,14 +25,14 @@ class BasicPort {
|
|||
public: /* Mutators */
|
||||
void set(const BasicPort& basic_port); /* copy */
|
||||
void set_name(const std::string& name); /* set the port LSB and MSB */
|
||||
void set_width(size_t width); /* set the port LSB and MSB */
|
||||
void set_width(size_t lsb, size_t msb); /* set the port LSB and MSB */
|
||||
void set_lsb(size_t lsb);
|
||||
void set_msb(size_t msb);
|
||||
void expand(size_t width); /* Increase the port width */
|
||||
void set_width(const size_t& width); /* set the port LSB and MSB */
|
||||
void set_width(const size_t& lsb, const size_t& msb); /* set the port LSB and MSB */
|
||||
void set_lsb(const size_t& lsb);
|
||||
void set_msb(const size_t& msb);
|
||||
void expand(const size_t& width); /* Increase the port width */
|
||||
void revert(); /* Swap lsb and msb */
|
||||
bool rotate(size_t offset); /* rotate */
|
||||
bool counter_rotate(size_t offset); /* counter rotate */
|
||||
bool rotate(const size_t& offset); /* rotate */
|
||||
bool counter_rotate(const size_t& offset); /* counter rotate */
|
||||
void reset(); /* Reset to initial port */
|
||||
void combine(const BasicPort& port); /* Combine two ports */
|
||||
private: /* internal functions */
|
||||
|
|
|
@ -510,13 +510,18 @@ static void ProcessSpiceModelBuffer(ezxml_t Node,
|
|||
ezxml_set_attr(Node, "topology", NULL);
|
||||
|
||||
/*Find Tapered*/
|
||||
/* Set default values*/
|
||||
buffer->tapered_buf = 0;
|
||||
buffer->tap_buf_level = 2;
|
||||
buffer->f_per_stage = 4;
|
||||
/* Parse XML */
|
||||
Prop = my_strdup(FindProperty(Node, "tapered", read_buf_info));
|
||||
if (NULL != Prop) {
|
||||
if (0 == strcmp(Prop,"on")) {
|
||||
buffer->tapered_buf = 1;
|
||||
/* Try to dig more properites ...*/
|
||||
buffer->tap_buf_level = GetIntProperty(Node, "tap_drive_level", TRUE, 1);
|
||||
buffer->f_per_stage = GetIntProperty(Node, "f_per_stage", FALSE, 4);
|
||||
buffer->tap_buf_level = GetIntProperty(Node, "tap_drive_level", TRUE, 2);
|
||||
buffer->f_per_stage = GetIntProperty(Node, "f_per_stage", FALSE, 4);
|
||||
ezxml_set_attr(Node, "tap_drive_level", NULL);
|
||||
ezxml_set_attr(Node, "f_per_stage", NULL);
|
||||
} else if (0 == strcmp(FindProperty(Node,"tapered",TRUE),"off")) {
|
||||
|
@ -1573,38 +1578,36 @@ CircuitLibrary build_circuit_library(int num_spice_model, t_spice_model* spice_m
|
|||
/* Go spice_model by spice_model */
|
||||
for (int imodel = 0; imodel < num_spice_model; ++imodel) {
|
||||
/* Add a spice model to the circuit_lib */
|
||||
CircuitModelId model_id = circuit_lib.add_circuit_model();
|
||||
CircuitModelId model_id = circuit_lib.add_model(spice_models[imodel].type);
|
||||
/* Fill fundamental attributes */
|
||||
/* Basic information*/
|
||||
circuit_lib.set_circuit_model_type(model_id, spice_models[imodel].type);
|
||||
|
||||
std::string name(spice_models[imodel].name);
|
||||
circuit_lib.set_circuit_model_name(model_id, name);
|
||||
circuit_lib.set_model_name(model_id, name);
|
||||
|
||||
std::string prefix(spice_models[imodel].prefix);
|
||||
circuit_lib.set_circuit_model_prefix(model_id, prefix);
|
||||
circuit_lib.set_model_prefix(model_id, prefix);
|
||||
|
||||
if (NULL != spice_models[imodel].verilog_netlist) {
|
||||
std::string verilog_netlist(spice_models[imodel].verilog_netlist);
|
||||
circuit_lib.set_circuit_model_verilog_netlist(model_id, verilog_netlist);
|
||||
circuit_lib.set_model_verilog_netlist(model_id, verilog_netlist);
|
||||
}
|
||||
|
||||
if (NULL != spice_models[imodel].model_netlist) {
|
||||
std::string spice_netlist(spice_models[imodel].model_netlist);
|
||||
circuit_lib.set_circuit_model_spice_netlist(model_id, spice_netlist);
|
||||
circuit_lib.set_model_spice_netlist(model_id, spice_netlist);
|
||||
}
|
||||
|
||||
circuit_lib.set_circuit_model_is_default(model_id, 0 != spice_models[imodel].is_default);
|
||||
circuit_lib.set_model_is_default(model_id, 0 != spice_models[imodel].is_default);
|
||||
|
||||
/* Verilog generatioin options */
|
||||
circuit_lib.set_circuit_model_dump_structural_verilog(model_id, TRUE == spice_models[imodel].dump_structural_verilog);
|
||||
circuit_lib.set_model_dump_structural_verilog(model_id, TRUE == spice_models[imodel].dump_structural_verilog);
|
||||
|
||||
circuit_lib.set_circuit_model_dump_explicit_port_map(model_id, TRUE == spice_models[imodel].dump_explicit_port_map);
|
||||
circuit_lib.set_model_dump_explicit_port_map(model_id, TRUE == spice_models[imodel].dump_explicit_port_map);
|
||||
|
||||
/* Design technology information */
|
||||
circuit_lib.set_circuit_model_design_tech_type(model_id, spice_models[imodel].design_tech);
|
||||
circuit_lib.set_model_design_tech_type(model_id, spice_models[imodel].design_tech);
|
||||
|
||||
circuit_lib.set_circuit_model_is_power_gated(model_id, TRUE == spice_models[imodel].design_tech_info.power_gated);
|
||||
circuit_lib.set_model_is_power_gated(model_id, TRUE == spice_models[imodel].design_tech_info.power_gated);
|
||||
|
||||
/* Buffer linking information */
|
||||
if (NULL != spice_models[imodel].input_buffer) {
|
||||
|
@ -1612,28 +1615,28 @@ CircuitLibrary build_circuit_library(int num_spice_model, t_spice_model* spice_m
|
|||
if (NULL != spice_models[imodel].input_buffer->spice_model_name) {
|
||||
model_name = spice_models[imodel].input_buffer->spice_model_name;
|
||||
}
|
||||
circuit_lib.set_circuit_model_input_buffer(model_id, 0 != spice_models[imodel].input_buffer->exist, model_name);
|
||||
circuit_lib.set_model_input_buffer(model_id, 0 != spice_models[imodel].input_buffer->exist, model_name);
|
||||
}
|
||||
if (NULL != spice_models[imodel].output_buffer) {
|
||||
std::string model_name;
|
||||
if (NULL != spice_models[imodel].output_buffer->spice_model_name) {
|
||||
model_name = spice_models[imodel].output_buffer->spice_model_name;
|
||||
}
|
||||
circuit_lib.set_circuit_model_output_buffer(model_id, 0 != spice_models[imodel].output_buffer->exist, model_name);
|
||||
circuit_lib.set_model_output_buffer(model_id, 0 != spice_models[imodel].output_buffer->exist, model_name);
|
||||
}
|
||||
if (NULL != spice_models[imodel].lut_input_buffer) {
|
||||
std::string model_name;
|
||||
if (NULL != spice_models[imodel].lut_input_buffer->spice_model_name) {
|
||||
model_name = spice_models[imodel].lut_input_buffer->spice_model_name;
|
||||
}
|
||||
circuit_lib.set_circuit_model_lut_input_buffer(model_id, 0 != spice_models[imodel].lut_input_buffer->exist, model_name);
|
||||
circuit_lib.set_model_lut_input_buffer(model_id, 0 != spice_models[imodel].lut_input_buffer->exist, model_name);
|
||||
}
|
||||
if (NULL != spice_models[imodel].lut_input_inverter) {
|
||||
std::string model_name;
|
||||
if (NULL != spice_models[imodel].lut_input_inverter->spice_model_name) {
|
||||
model_name = spice_models[imodel].lut_input_inverter->spice_model_name;
|
||||
}
|
||||
circuit_lib.set_circuit_model_lut_input_inverter(model_id, 0 != spice_models[imodel].lut_input_inverter->exist, model_name);
|
||||
circuit_lib.set_model_lut_input_inverter(model_id, 0 != spice_models[imodel].lut_input_inverter->exist, model_name);
|
||||
}
|
||||
if ( (NULL != spice_models[imodel].lut_intermediate_buffer)
|
||||
&& (1 == spice_models[imodel].lut_intermediate_buffer->exist) ) {
|
||||
|
@ -1641,19 +1644,19 @@ CircuitLibrary build_circuit_library(int num_spice_model, t_spice_model* spice_m
|
|||
if (NULL != spice_models[imodel].lut_intermediate_buffer->spice_model_name) {
|
||||
model_name = spice_models[imodel].lut_intermediate_buffer->spice_model_name;
|
||||
}
|
||||
circuit_lib.set_circuit_model_lut_intermediate_buffer(model_id, 0 != spice_models[imodel].lut_intermediate_buffer->exist, model_name);
|
||||
circuit_lib.set_model_lut_intermediate_buffer(model_id, 0 != spice_models[imodel].lut_intermediate_buffer->exist, model_name);
|
||||
|
||||
std::string model_location_map;
|
||||
if (NULL != spice_models[imodel].lut_intermediate_buffer->location_map) {
|
||||
model_location_map = spice_models[imodel].lut_intermediate_buffer->location_map;
|
||||
}
|
||||
circuit_lib.set_circuit_model_lut_intermediate_buffer_location_map(model_id, model_location_map);
|
||||
circuit_lib.set_model_lut_intermediate_buffer_location_map(model_id, model_location_map);
|
||||
}
|
||||
|
||||
/* Pass-gate-logic linking information */
|
||||
if (NULL != spice_models[imodel].pass_gate_logic) {
|
||||
std::string model_name(spice_models[imodel].pass_gate_logic->spice_model_name);
|
||||
circuit_lib.set_circuit_model_pass_gate_logic(model_id, model_name);
|
||||
circuit_lib.set_model_pass_gate_logic(model_id, model_name);
|
||||
}
|
||||
|
||||
/* Buffer information */
|
||||
|
@ -1728,65 +1731,63 @@ CircuitLibrary build_circuit_library(int num_spice_model, t_spice_model* spice_m
|
|||
|
||||
/* Ports */
|
||||
for (int iport = 0; iport < spice_models[imodel].num_port; ++iport) {
|
||||
CircuitPortId port_id = circuit_lib.add_circuit_model_port(model_id);
|
||||
CircuitPortId port_id = circuit_lib.add_model_port(model_id, spice_models[imodel].ports[iport].type);
|
||||
/* Fill fundamental attributes */
|
||||
circuit_lib.set_port_type(model_id, port_id, spice_models[imodel].ports[iport].type);
|
||||
|
||||
circuit_lib.set_port_size(model_id, port_id, spice_models[imodel].ports[iport].size);
|
||||
circuit_lib.set_port_size(port_id, spice_models[imodel].ports[iport].size);
|
||||
|
||||
std::string port_prefix(spice_models[imodel].ports[iport].prefix);
|
||||
circuit_lib.set_port_prefix(model_id, port_id, port_prefix);
|
||||
circuit_lib.set_port_prefix(port_id, port_prefix);
|
||||
|
||||
std::string port_lib_name(spice_models[imodel].ports[iport].lib_name);
|
||||
circuit_lib.set_port_lib_name(model_id, port_id, port_lib_name);
|
||||
circuit_lib.set_port_lib_name(port_id, port_lib_name);
|
||||
|
||||
if (NULL != spice_models[imodel].ports[iport].inv_prefix) {
|
||||
std::string port_inv_prefix(spice_models[imodel].ports[iport].inv_prefix);
|
||||
circuit_lib.set_port_inv_prefix(model_id, port_id, port_inv_prefix);
|
||||
circuit_lib.set_port_inv_prefix(port_id, port_inv_prefix);
|
||||
}
|
||||
|
||||
circuit_lib.set_port_default_value(model_id, port_id, spice_models[imodel].ports[iport].default_val);
|
||||
circuit_lib.set_port_default_value(port_id, spice_models[imodel].ports[iport].default_val);
|
||||
|
||||
circuit_lib.set_port_is_mode_select(model_id, port_id, TRUE == spice_models[imodel].ports[iport].mode_select);
|
||||
circuit_lib.set_port_is_global(model_id, port_id, TRUE == spice_models[imodel].ports[iport].is_global);
|
||||
circuit_lib.set_port_is_reset(model_id, port_id, TRUE == spice_models[imodel].ports[iport].is_reset);
|
||||
circuit_lib.set_port_is_set(model_id, port_id, TRUE == spice_models[imodel].ports[iport].is_set);
|
||||
circuit_lib.set_port_is_config_enable(model_id, port_id, TRUE == spice_models[imodel].ports[iport].is_config_enable);
|
||||
circuit_lib.set_port_is_prog(model_id, port_id, TRUE == spice_models[imodel].ports[iport].is_prog);
|
||||
circuit_lib.set_port_is_mode_select(port_id, TRUE == spice_models[imodel].ports[iport].mode_select);
|
||||
circuit_lib.set_port_is_global(port_id, TRUE == spice_models[imodel].ports[iport].is_global);
|
||||
circuit_lib.set_port_is_reset(port_id, TRUE == spice_models[imodel].ports[iport].is_reset);
|
||||
circuit_lib.set_port_is_set(port_id, TRUE == spice_models[imodel].ports[iport].is_set);
|
||||
circuit_lib.set_port_is_config_enable(port_id, TRUE == spice_models[imodel].ports[iport].is_config_enable);
|
||||
circuit_lib.set_port_is_prog(port_id, TRUE == spice_models[imodel].ports[iport].is_prog);
|
||||
|
||||
if (NULL != spice_models[imodel].ports[iport].spice_model_name) {
|
||||
std::string port_model_name(spice_models[imodel].ports[iport].spice_model_name);
|
||||
circuit_lib.set_port_circuit_model_name(model_id, port_id, port_model_name);
|
||||
circuit_lib.set_port_tri_state_model_name(port_id, port_model_name);
|
||||
}
|
||||
|
||||
if (NULL != spice_models[imodel].ports[iport].inv_spice_model_name) {
|
||||
std::string port_inv_model_name(spice_models[imodel].ports[iport].inv_spice_model_name);
|
||||
circuit_lib.set_port_inv_circuit_model_name(model_id, port_id, port_inv_model_name);
|
||||
circuit_lib.set_port_inv_model_name(port_id, port_inv_model_name);
|
||||
}
|
||||
|
||||
if (NULL != spice_models[imodel].ports[iport].tri_state_map) {
|
||||
std::string port_tri_state_map(spice_models[imodel].ports[iport].tri_state_map);
|
||||
circuit_lib.set_port_tri_state_map(model_id, port_id, port_tri_state_map);
|
||||
circuit_lib.set_port_tri_state_map(port_id, port_tri_state_map);
|
||||
}
|
||||
|
||||
if (SPICE_MODEL_LUT == spice_models[imodel].type) {
|
||||
circuit_lib.set_port_lut_frac_level(model_id, port_id, spice_models[imodel].ports[iport].lut_frac_level);
|
||||
circuit_lib.set_port_lut_frac_level(port_id, spice_models[imodel].ports[iport].lut_frac_level);
|
||||
|
||||
std::vector<size_t> port_lut_output_mask;
|
||||
for (int ipin = 0; ipin < spice_models[imodel].ports[iport].size; ++ipin) {
|
||||
port_lut_output_mask.push_back(spice_models[imodel].ports[iport].lut_output_mask[ipin]);
|
||||
}
|
||||
circuit_lib.set_port_lut_output_mask(model_id, port_id, port_lut_output_mask);
|
||||
circuit_lib.set_port_lut_output_mask(port_id, port_lut_output_mask);
|
||||
}
|
||||
|
||||
if (SPICE_MODEL_PORT_SRAM == spice_models[imodel].ports[iport].type) {
|
||||
circuit_lib.set_port_sram_orgz(model_id, port_id, spice_models[imodel].ports[iport].organization);
|
||||
circuit_lib.set_port_sram_orgz(port_id, spice_models[imodel].ports[iport].organization);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Build circuit_model links */
|
||||
circuit_lib.build_circuit_model_links();
|
||||
circuit_lib.build_model_links();
|
||||
|
||||
/* Build timing graph */
|
||||
circuit_lib.build_timing_graphs();
|
||||
|
|
|
@ -0,0 +1,724 @@
|
|||
/**************************************************
|
||||
* This file includes member functions for the
|
||||
* data structures in mux_graph.h
|
||||
*************************************************/
|
||||
#include <cmath>
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
|
||||
#include "util.h"
|
||||
#include "vtr_assert.h"
|
||||
#include "mux_utils.h"
|
||||
#include "mux_graph.h"
|
||||
|
||||
/**************************************************
|
||||
* Member functions for the class MuxGraph
|
||||
*************************************************/
|
||||
|
||||
/**************************************************
|
||||
* Public Constructors
|
||||
*************************************************/
|
||||
|
||||
/* Create an object based on a Circuit Model which is MUX */
|
||||
MuxGraph::MuxGraph(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const size_t& mux_size) {
|
||||
/* Build the graph for a given multiplexer model */
|
||||
build_mux_graph(circuit_lib, circuit_model, mux_size);
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Private Constructors
|
||||
*************************************************/
|
||||
/* Create an empty graph */
|
||||
MuxGraph::MuxGraph() {
|
||||
return;
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Public Accessors : Aggregates
|
||||
*************************************************/
|
||||
//Accessors
|
||||
MuxGraph::node_range MuxGraph::nodes() const {
|
||||
return vtr::make_range(node_ids_.begin(), node_ids_.end());
|
||||
}
|
||||
|
||||
MuxGraph::edge_range MuxGraph::edges() const {
|
||||
return vtr::make_range(edge_ids_.begin(), edge_ids_.end());
|
||||
}
|
||||
|
||||
MuxGraph::mem_range MuxGraph::memories() const {
|
||||
return vtr::make_range(mem_ids_.begin(), mem_ids_.end());
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Public Accessors: Data query
|
||||
*************************************************/
|
||||
|
||||
/* Find the number of inputs in the MUX graph */
|
||||
size_t MuxGraph::num_inputs() const {
|
||||
/* need to check if the graph is valid or not */
|
||||
VTR_ASSERT_SAFE(valid_mux_graph());
|
||||
/* Sum up the number of INPUT nodes in each level */
|
||||
size_t num_inputs = 0;
|
||||
for (auto node_per_level : node_lookup_) {
|
||||
num_inputs += node_per_level[MUX_INPUT_NODE].size();
|
||||
}
|
||||
return num_inputs;
|
||||
}
|
||||
|
||||
/* Find the number of outputs in the MUX graph */
|
||||
size_t MuxGraph::num_outputs() const {
|
||||
/* need to check if the graph is valid or not */
|
||||
VTR_ASSERT_SAFE(valid_mux_graph());
|
||||
/* Sum up the number of INPUT nodes in each level */
|
||||
size_t num_outputs = 0;
|
||||
for (auto node_per_level : node_lookup_) {
|
||||
num_outputs += node_per_level[MUX_OUTPUT_NODE].size();
|
||||
}
|
||||
return num_outputs;
|
||||
}
|
||||
|
||||
|
||||
/* Find the number of levels in the MUX graph */
|
||||
size_t MuxGraph::num_levels() const {
|
||||
/* need to check if the graph is valid or not */
|
||||
VTR_ASSERT_SAFE(valid_mux_graph());
|
||||
/* The num_levels by definition excludes the level for outputs, so a deduection is applied */
|
||||
return node_lookup_.size() - 1;
|
||||
}
|
||||
|
||||
/* Find the number of configuration memories in the MUX graph */
|
||||
size_t MuxGraph::num_memory_bits() const {
|
||||
/* need to check if the graph is valid or not */
|
||||
VTR_ASSERT_SAFE(valid_mux_graph());
|
||||
return mem_ids_.size();
|
||||
}
|
||||
|
||||
/* Find the sizes of each branch of a MUX */
|
||||
std::vector<size_t> MuxGraph::branch_sizes() const {
|
||||
std::vector<size_t> branch;
|
||||
/* Visit each internal nodes/output nodes and find the the number of incoming edges */
|
||||
for (auto node : node_ids_ ) {
|
||||
/* Bypass input nodes */
|
||||
if ( (MUX_OUTPUT_NODE != node_types_[node])
|
||||
&& (MUX_INTERNAL_NODE != node_types_[node]) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t branch_size = node_in_edges_[node].size();
|
||||
|
||||
/* make sure the branch size is valid */
|
||||
VTR_ASSERT_SAFE(valid_mux_implementation_num_inputs(branch_size));
|
||||
|
||||
/* Nodes with the same number of incoming edges, indicate the same size of branch circuit */
|
||||
std::vector<size_t>::iterator it;
|
||||
it = std::find(branch.begin(), branch.end(), branch_size);
|
||||
/* if already exists a branch with the same size, skip updating the vector */
|
||||
if (it != branch.end()) {
|
||||
continue;
|
||||
}
|
||||
branch.push_back(branch_size);
|
||||
}
|
||||
|
||||
/* Sort the branch by size */
|
||||
std::sort(branch.begin(), branch.end());
|
||||
|
||||
return branch;
|
||||
}
|
||||
|
||||
/* Build a subgraph from the given node
|
||||
* The strategy is very simple, we just
|
||||
* extract a 1-level graph from here
|
||||
*/
|
||||
MuxGraph MuxGraph::subgraph(const MuxNodeId& root_node) const {
|
||||
/* Validate the node */
|
||||
VTR_ASSERT_SAFE(this->valid_node_id(root_node));
|
||||
|
||||
/* Generate an empty graph */
|
||||
MuxGraph mux_graph;
|
||||
|
||||
/* A map to record node-to-node mapping from origin graph to subgraph */
|
||||
std::map<MuxNodeId, MuxNodeId> node2node_map;
|
||||
|
||||
/* A map to record edge-to-edge mapping from origin graph to subgraph */
|
||||
std::map<MuxEdgeId, MuxEdgeId> edge2edge_map;
|
||||
|
||||
/* Add output nodes to subgraph */
|
||||
MuxNodeId to_node_subgraph = mux_graph.add_node(MUX_OUTPUT_NODE);
|
||||
mux_graph.node_levels_[to_node_subgraph] = 1;
|
||||
/* Update the node-to-node map */
|
||||
node2node_map[root_node] = to_node_subgraph;
|
||||
|
||||
/* Add input nodes and edges to subgraph */
|
||||
size_t input_cnt = 0;
|
||||
for (auto edge_origin : this->node_in_edges_[root_node]) {
|
||||
VTR_ASSERT_SAFE(1 == edge_src_nodes_[edge_origin].size());
|
||||
/* Add nodes */
|
||||
MuxNodeId from_node_origin = this->edge_src_nodes_[edge_origin][0];
|
||||
MuxNodeId from_node_subgraph = mux_graph.add_node(MUX_INPUT_NODE);
|
||||
/* Configure the nodes */
|
||||
mux_graph.node_levels_[from_node_subgraph] = 0;
|
||||
mux_graph.node_input_ids_[from_node_subgraph] = MuxInputId(input_cnt);
|
||||
input_cnt++;
|
||||
/* Update the node-to-node map */
|
||||
node2node_map[from_node_origin] = from_node_subgraph;
|
||||
|
||||
/* Add edges */
|
||||
MuxEdgeId edge_subgraph = mux_graph.add_edge(node2node_map[from_node_origin], node2node_map[root_node]);
|
||||
edge2edge_map[edge_origin] = edge_subgraph;
|
||||
/* Configure edges */
|
||||
mux_graph.edge_models_[edge_subgraph] = this->edge_models_[edge_origin];
|
||||
mux_graph.edge_inv_mem_[edge_subgraph] = this->edge_inv_mem_[edge_origin];
|
||||
}
|
||||
|
||||
/* A map to record mem-to-mem mapping from origin graph to subgraph */
|
||||
std::map<MuxMemId, MuxMemId> mem2mem_map;
|
||||
|
||||
/* Add memory bits and configure edges */
|
||||
for (auto edge_origin : this->node_in_edges_[root_node]) {
|
||||
MuxMemId mem_origin = this->edge_mem_ids_[edge_origin];
|
||||
/* Try to find if the mem is already in the list */
|
||||
std::map<MuxMemId, MuxMemId>::iterator it = mem2mem_map.find(mem_origin);
|
||||
if (it != mem2mem_map.end()) {
|
||||
/* Found, we skip mem addition. But make sure we have a valid one */
|
||||
VTR_ASSERT_SAFE(MuxMemId::INVALID() != mem2mem_map[mem_origin]);
|
||||
/* configure the edge */
|
||||
mux_graph.edge_mem_ids_[edge2edge_map[edge_origin]] = mem2mem_map[mem_origin];
|
||||
continue;
|
||||
}
|
||||
/* Not found, we add a memory bit and record in the mem-to-mem map */
|
||||
MuxMemId mem_subgraph = mux_graph.add_mem();
|
||||
mem2mem_map[mem_origin] = mem_subgraph;
|
||||
}
|
||||
|
||||
/* Since the graph is finalized, it is time to build the fast look-up */
|
||||
mux_graph.build_node_lookup();
|
||||
|
||||
return mux_graph;
|
||||
}
|
||||
|
||||
/* Generate MUX graphs for its branches
|
||||
* Similar to the branch_sizes() method,
|
||||
* we search all the internal nodes and
|
||||
* find out what are the input sizes of
|
||||
* the branches.
|
||||
* Then we extract unique subgraphs and return
|
||||
*/
|
||||
std::vector<MuxGraph> MuxGraph::build_mux_branch_graphs() const {
|
||||
std::map<size_t, bool> branch_done; /* A map showing the status of graph generation */
|
||||
|
||||
std::vector<MuxGraph> branch_graphs;
|
||||
|
||||
/* Visit each internal nodes/output nodes and find the the number of incoming edges */
|
||||
for (auto node : node_ids_ ) {
|
||||
/* Bypass input nodes */
|
||||
if ( (MUX_OUTPUT_NODE != node_types_[node])
|
||||
&& (MUX_INTERNAL_NODE != node_types_[node]) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t branch_size = node_in_edges_[node].size();
|
||||
|
||||
/* make sure the branch size is valid */
|
||||
VTR_ASSERT_SAFE(valid_mux_implementation_num_inputs(branch_size));
|
||||
|
||||
/* check if the branch have been done in sub-graph extraction! */
|
||||
std::map<size_t, bool>::iterator it = branch_done.find(branch_size);
|
||||
/* if it is done, we can skip */
|
||||
if (it != branch_done.end()) {
|
||||
VTR_ASSERT(branch_done[branch_size]);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Generate a subgraph and push back */
|
||||
branch_graphs.push_back(subgraph(node));
|
||||
|
||||
/* Mark it is done for this branch size */
|
||||
branch_done[branch_size] = true;
|
||||
}
|
||||
|
||||
return branch_graphs;
|
||||
}
|
||||
|
||||
/* Get the node id of a given input */
|
||||
MuxNodeId MuxGraph::node_id(const MuxInputId& input_id) const {
|
||||
/* Use the node_lookup to accelerate the search */
|
||||
for (const auto& lvl : node_lookup_) {
|
||||
for (const auto& cand_node : lvl[MUX_INPUT_NODE]) {
|
||||
if (input_id == node_input_ids_[cand_node]) {
|
||||
return cand_node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return MuxNodeId::INVALID();
|
||||
}
|
||||
|
||||
/* Decode memory bits based on an input id */
|
||||
std::vector<size_t> MuxGraph::decode_memory_bits(const MuxInputId& input_id) const {
|
||||
/* initialize the memory bits: TODO: support default value */
|
||||
std::vector<size_t> mem_bits(mem_ids_.size(), 0);
|
||||
|
||||
/* valid the input */
|
||||
VTR_ASSERT_SAFE(valid_input_id(input_id));
|
||||
|
||||
/* Route the input to the output and update mem */
|
||||
MuxNodeId next_node = node_id(input_id);
|
||||
while ( 0 < node_out_edges_[next_node].size() ) {
|
||||
VTR_ASSERT_SAFE (1 == node_out_edges_[next_node].size());
|
||||
MuxEdgeId edge = node_out_edges_[next_node][0];
|
||||
|
||||
/* Configure the mem bits:
|
||||
* if inv_mem is enabled, it means 0 to enable this edge
|
||||
* otherwise, it is 1 to enable this edge
|
||||
*/
|
||||
MuxMemId mem = edge_mem_ids_[edge];
|
||||
VTR_ASSERT_SAFE (valid_mem_id(mem));
|
||||
if (true == edge_inv_mem_[edge]) {
|
||||
mem_bits[size_t(mem)] = 0;
|
||||
} else {
|
||||
mem_bits[size_t(mem)] = 1;
|
||||
}
|
||||
|
||||
/* each edge must have 1 fan-out */
|
||||
VTR_ASSERT_SAFE (1 == edge_sink_nodes_[edge].size());
|
||||
|
||||
/* Visit the next node */
|
||||
next_node = edge_sink_nodes_[edge][0];
|
||||
}
|
||||
VTR_ASSERT_SAFE(MUX_OUTPUT_NODE == node_types_[next_node]);
|
||||
|
||||
return mem_bits;
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Private mutators: basic operations
|
||||
*************************************************/
|
||||
/* Add a unconfigured node to the MuxGraph */
|
||||
MuxNodeId MuxGraph::add_node(const enum e_mux_graph_node_type& node_type) {
|
||||
MuxNodeId node = MuxNodeId(node_ids_.size());
|
||||
/* Push to the node list */
|
||||
node_ids_.push_back(node);
|
||||
/* Resize the other node-related vectors */
|
||||
node_types_.push_back(node_type);
|
||||
node_input_ids_.push_back(MuxInputId::INVALID());
|
||||
node_levels_.push_back(-1);
|
||||
node_in_edges_.emplace_back();
|
||||
node_out_edges_.emplace_back();
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/* Add a edge connecting two nodes */
|
||||
MuxEdgeId MuxGraph::add_edge(const MuxNodeId& from_node, const MuxNodeId& to_node) {
|
||||
MuxEdgeId edge = MuxEdgeId(edge_ids_.size());
|
||||
/* Push to the node list */
|
||||
edge_ids_.push_back(edge);
|
||||
/* Resize the other node-related vectors */
|
||||
edge_models_.push_back(CircuitModelId::INVALID());
|
||||
edge_mem_ids_.push_back(MuxMemId::INVALID());
|
||||
edge_inv_mem_.push_back(false);
|
||||
|
||||
/* update the edge-node connections */
|
||||
VTR_ASSERT(valid_node_id(from_node));
|
||||
edge_src_nodes_.emplace_back();
|
||||
edge_src_nodes_[edge].push_back(from_node);
|
||||
node_out_edges_[from_node].push_back(edge);
|
||||
|
||||
VTR_ASSERT(valid_node_id(to_node));
|
||||
edge_sink_nodes_.emplace_back();
|
||||
edge_sink_nodes_[edge].push_back(to_node);
|
||||
node_in_edges_[to_node].push_back(edge);
|
||||
|
||||
return edge;
|
||||
}
|
||||
|
||||
/* Add a memory bit to the MuxGraph */
|
||||
MuxMemId MuxGraph::add_mem() {
|
||||
MuxMemId mem = MuxMemId(mem_ids_.size());
|
||||
/* Push to the node list */
|
||||
mem_ids_.push_back(mem);
|
||||
/* Resize the other node-related vectors */
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
/* Link an edge to a memory bit */
|
||||
void MuxGraph::set_edge_mem_id(const MuxEdgeId& edge, const MuxMemId& mem) {
|
||||
/* Make sure we have valid edge and mem */
|
||||
VTR_ASSERT( valid_edge_id(edge) && valid_mem_id(mem) );
|
||||
|
||||
edge_mem_ids_[edge] = mem;
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Private mutators: graph builders
|
||||
*************************************************/
|
||||
|
||||
/* Build a graph for a multi-level multiplexer implementation
|
||||
* support both generic multi-level and tree-like multiplexers
|
||||
*
|
||||
* a N:1 multi-level MUX
|
||||
* ----------------------
|
||||
*
|
||||
* input_node --->+
|
||||
* |
|
||||
* input_node --->|
|
||||
* |--->+
|
||||
* ... | |
|
||||
* | |
|
||||
* input_node --->+ |---> ...
|
||||
* |
|
||||
* ... --->+ --->+
|
||||
* |
|
||||
* ... ... |---> output_node
|
||||
* |
|
||||
* ... --->+ --->+
|
||||
* |
|
||||
* input_node --->+ |---> ...
|
||||
* | |
|
||||
* input_node --->| |
|
||||
* |--->+
|
||||
* ... |
|
||||
* |
|
||||
* input_node --->+
|
||||
*
|
||||
* tree-like multiplexer graph will look like:
|
||||
* --------------------------------------------
|
||||
*
|
||||
* input_node --->+
|
||||
* |--->+
|
||||
* input_node --->+ |---> ...
|
||||
* |
|
||||
* --->+ --->+
|
||||
* ... ... ... |----> output_node
|
||||
* ... --->+ --->+
|
||||
* |---> ...
|
||||
* input_node --->+ |
|
||||
* |--->+
|
||||
* input_node --->+
|
||||
*
|
||||
*/
|
||||
void MuxGraph::build_multilevel_mux_graph(const size_t& mux_size,
|
||||
const size_t& num_levels, const size_t& num_inputs_per_branch,
|
||||
const CircuitModelId& pgl_model) {
|
||||
/* Make sure mux_size for each branch is valid */
|
||||
VTR_ASSERT(valid_mux_implementation_num_inputs(num_inputs_per_branch));
|
||||
|
||||
/* In regular cases, there is 1 mem bit for each input of a branch */
|
||||
size_t num_mems_per_level = num_inputs_per_branch;
|
||||
/* For 2-input branch, only 1 mem bit is needed for each level! */
|
||||
if (2 == num_inputs_per_branch) {
|
||||
num_mems_per_level = 1;
|
||||
}
|
||||
/* Number of memory bits is definite, add them */
|
||||
for (size_t i = 0; i < num_mems_per_level * num_levels; ++i) {
|
||||
add_mem();
|
||||
}
|
||||
|
||||
/* Create a fast node lookup locally.
|
||||
* Only used for building the graph
|
||||
* it sorts the nodes by levels and ids at each level
|
||||
*/
|
||||
std::vector<std::vector<MuxNodeId>> node_lookup; /* [num_levels][num_nodes_per_level] */
|
||||
node_lookup.resize(num_levels + 1);
|
||||
|
||||
/* Number of outputs is definite, add and configure */
|
||||
MuxNodeId output_node = add_node(MUX_OUTPUT_NODE);
|
||||
node_levels_[output_node] = num_levels;
|
||||
/* Update node lookup */
|
||||
node_lookup[num_levels].push_back(output_node);
|
||||
|
||||
/* keep a list of node ids which can be candidates for input nodes */
|
||||
std::vector<MuxNodeId> input_node_ids;
|
||||
|
||||
/* Add internal nodes level by level,
|
||||
* we start from the last level, following a strategy like tree growing
|
||||
*/
|
||||
for (size_t lvl = num_levels - 1; ; --lvl) {
|
||||
/* Expand from the existing nodes
|
||||
* Last level should expand from output_node
|
||||
* Other levels will expand from internal nodes!
|
||||
*/
|
||||
for (MuxNodeId seed_node : node_lookup[lvl + 1]) {
|
||||
/* Add a new node and connect to seed_node, until we reach the num_inputs_per_branch */
|
||||
for (size_t i = 0; i < num_inputs_per_branch; ++i) {
|
||||
/* We deposite a type of INTERNAL_NODE,
|
||||
* later it will be configured to INPUT if it is in the input list
|
||||
*/
|
||||
MuxNodeId expand_node = add_node(MUX_INTERNAL_NODE);
|
||||
|
||||
/* Node level is deterministic */
|
||||
node_levels_[expand_node] = lvl;
|
||||
|
||||
/* Create an edge and connect the two nodes */
|
||||
MuxEdgeId edge = add_edge(expand_node, seed_node);
|
||||
/* Configure the edge */
|
||||
edge_models_[edge] = pgl_model;
|
||||
|
||||
/* Memory id depends on the level and offset in the current branch
|
||||
* if number of inputs per branch is 2, it indicates a tree-like multiplexer,
|
||||
* every two edges will share one memory bit
|
||||
* otherwise, each edge corresponds to a memory bit
|
||||
*/
|
||||
|
||||
if ( 2 == num_inputs_per_branch) {
|
||||
MuxMemId mem_id = MuxMemId(lvl);
|
||||
set_edge_mem_id(edge, mem_id);
|
||||
/* If this is a second edge in the branch, we will assign it to an inverted edge */
|
||||
if (0 != i % num_inputs_per_branch) {
|
||||
edge_inv_mem_[edge] = true;
|
||||
}
|
||||
} else {
|
||||
MuxMemId mem_id = MuxMemId( lvl * num_inputs_per_branch + i );
|
||||
set_edge_mem_id(edge, mem_id);
|
||||
}
|
||||
|
||||
/* Update node lookup */
|
||||
node_lookup[lvl].push_back(expand_node);
|
||||
|
||||
/* Push the node to input list, and then remove the seed_node from the list */
|
||||
input_node_ids.push_back(expand_node);
|
||||
/* Remove the node if the seed node is the list */
|
||||
std::vector<MuxNodeId>::iterator it = find(input_node_ids.begin(), input_node_ids.end(), seed_node);
|
||||
if (it != input_node_ids.end()) {
|
||||
input_node_ids.erase(it);
|
||||
}
|
||||
|
||||
/* Check the number of input nodes, if already meet the demand, we can finish here */
|
||||
if (mux_size != input_node_ids.size()) {
|
||||
continue; /* We need more inputs, keep looping */
|
||||
}
|
||||
|
||||
/* The graph is done, we configure the input nodes and then we can return */
|
||||
/* We must be in level 0 !*/
|
||||
VTR_ASSERT( 0 == lvl ) ;
|
||||
for (MuxNodeId input_node : input_node_ids) {
|
||||
node_types_[input_node] = MUX_INPUT_NODE;
|
||||
}
|
||||
|
||||
/* Sort the nodes by the levels and offset */
|
||||
size_t input_cnt = 0;
|
||||
for (auto lvl_nodes : node_lookup) {
|
||||
for (MuxNodeId cand_node : lvl_nodes) {
|
||||
if (MUX_INPUT_NODE != node_types_[cand_node]) {
|
||||
continue;
|
||||
}
|
||||
/* Update the input node ids */
|
||||
node_input_ids_[cand_node] = MuxInputId(input_cnt);
|
||||
/* Update the counter */
|
||||
input_cnt++;
|
||||
}
|
||||
}
|
||||
/* Make sure we visited all the inputs in the cache */
|
||||
VTR_ASSERT(input_cnt == input_node_ids.size());
|
||||
/* Finish building the graph for a multi-level multiplexer */
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Finish building the graph for a multi-level multiplexer */
|
||||
}
|
||||
|
||||
/* Build the graph for a given one-level multiplexer implementation
|
||||
* a N:1 one-level MUX
|
||||
*
|
||||
* input_node --->+
|
||||
* |
|
||||
* input_node --->|
|
||||
* |--> output_node
|
||||
* ... |
|
||||
* |
|
||||
* input_node --->+
|
||||
*/
|
||||
void MuxGraph::build_onelevel_mux_graph(const size_t& mux_size,
|
||||
const CircuitModelId& pgl_model) {
|
||||
/* Make sure mux_size is valid */
|
||||
VTR_ASSERT(valid_mux_implementation_num_inputs(mux_size));
|
||||
|
||||
/* We definitely know how many nodes we need,
|
||||
* N inputs, 1 output and 0 internal nodes
|
||||
*/
|
||||
MuxNodeId output_node = add_node(MUX_OUTPUT_NODE);
|
||||
node_levels_[output_node] = 1;
|
||||
|
||||
for (size_t i = 0; i < mux_size; ++i) {
|
||||
MuxNodeId input_node = add_node(MUX_INPUT_NODE);
|
||||
/* All the node belong to level 0 (we have only 1 level) */
|
||||
node_input_ids_[input_node] = MuxInputId(i);
|
||||
node_levels_[input_node] = 0;
|
||||
|
||||
/* We definitely know how many edges we need,
|
||||
* the same as mux_size, add a edge connecting two nodes
|
||||
*/
|
||||
MuxEdgeId edge = add_edge(input_node, output_node);
|
||||
/* Configure the edge */
|
||||
edge_models_[edge] = pgl_model;
|
||||
|
||||
/* Create a memory bit*/
|
||||
MuxMemId mem = add_mem();
|
||||
/* Link the edge to a memory bit */
|
||||
set_edge_mem_id(edge, mem);
|
||||
}
|
||||
/* Finish building the graph for a one-level multiplexer */
|
||||
}
|
||||
|
||||
/* Build the graph for a given multiplexer model */
|
||||
void MuxGraph::build_mux_graph(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const size_t& mux_size) {
|
||||
/* Make sure this model is a MUX */
|
||||
VTR_ASSERT((SPICE_MODEL_MUX == circuit_lib.model_type(circuit_model))
|
||||
|| (SPICE_MODEL_LUT == circuit_lib.model_type(circuit_model)) );
|
||||
|
||||
/* Make sure mux_size is valid */
|
||||
VTR_ASSERT(valid_mux_implementation_num_inputs(mux_size));
|
||||
|
||||
size_t impl_mux_size = find_mux_implementation_num_inputs(circuit_lib, circuit_model, mux_size);
|
||||
|
||||
/* Depends on the mux size, the implemented multiplexer structure may change! */
|
||||
enum e_spice_model_structure impl_structure = find_mux_implementation_structure(circuit_lib, circuit_model, impl_mux_size);
|
||||
|
||||
/* Branch on multiplexer structures, leading to different building strategies */
|
||||
switch (impl_structure) {
|
||||
case SPICE_MODEL_STRUCTURE_TREE: {
|
||||
/* Find the number of levels */
|
||||
size_t num_levels = find_treelike_mux_num_levels(impl_mux_size);
|
||||
|
||||
/* Find the number of inputs per branch, this is not final */
|
||||
size_t num_inputs_per_branch = 2;
|
||||
|
||||
/* Build a multilevel mux graph */
|
||||
build_multilevel_mux_graph(impl_mux_size, num_levels, num_inputs_per_branch, circuit_lib.pass_gate_logic_model(circuit_model));
|
||||
break;
|
||||
}
|
||||
case SPICE_MODEL_STRUCTURE_ONELEVEL: {
|
||||
build_onelevel_mux_graph(impl_mux_size, circuit_lib.pass_gate_logic_model(circuit_model));
|
||||
break;
|
||||
}
|
||||
case SPICE_MODEL_STRUCTURE_MULTILEVEL: {
|
||||
/* Find the number of inputs per branch, this is not final */
|
||||
size_t num_inputs_per_branch = find_multilevel_mux_branch_num_inputs(impl_mux_size, circuit_lib.mux_num_levels(circuit_model));
|
||||
|
||||
/* Build a multilevel mux graph */
|
||||
build_multilevel_mux_graph(impl_mux_size, circuit_lib.mux_num_levels(circuit_model),
|
||||
num_inputs_per_branch,
|
||||
circuit_lib.pass_gate_logic_model(circuit_model));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s, [LINE%d]) Invalid multiplexer structure for circuit model (name=%s)!\n",
|
||||
__FILE__, __LINE__, circuit_lib.model_name(circuit_model).c_str());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Since the graph is finalized, it is time to build the fast look-up */
|
||||
build_node_lookup();
|
||||
}
|
||||
|
||||
/* Build fast node lookup */
|
||||
void MuxGraph::build_node_lookup() {
|
||||
/* Invalidate the node lookup if necessary */
|
||||
invalidate_node_lookup();
|
||||
|
||||
/* Find the maximum number of levels */
|
||||
size_t num_levels = 0;
|
||||
for (auto node : nodes()) {
|
||||
num_levels = std::max((int)node_levels_[node], (int)num_levels);
|
||||
}
|
||||
|
||||
/* Resize node_lookup */
|
||||
node_lookup_.resize(num_levels + 1);
|
||||
for (size_t lvl = 0; lvl < node_lookup_.size(); ++lvl) {
|
||||
/* Resize by number of node types */
|
||||
node_lookup_[lvl].resize(NUM_MUX_NODE_TYPES);
|
||||
}
|
||||
|
||||
/* Fill the node lookup */
|
||||
for (auto node : nodes()) {
|
||||
node_lookup_[node_levels_[node]][size_t(node_types_[node])].push_back(node);
|
||||
}
|
||||
}
|
||||
|
||||
/* Invalidate (empty) the node fast lookup*/
|
||||
void MuxGraph::invalidate_node_lookup() {
|
||||
node_lookup_.clear();
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Private validators
|
||||
*************************************************/
|
||||
|
||||
/* valid ids */
|
||||
bool MuxGraph::valid_node_id(const MuxNodeId& node) const {
|
||||
return size_t(node) < node_ids_.size() && node_ids_[node] == node;
|
||||
}
|
||||
|
||||
bool MuxGraph::valid_edge_id(const MuxEdgeId& edge) const {
|
||||
return size_t(edge) < edge_ids_.size() && edge_ids_[edge] == edge;
|
||||
}
|
||||
|
||||
bool MuxGraph::valid_mem_id(const MuxMemId& mem) const {
|
||||
return size_t(mem) < mem_ids_.size() && mem_ids_[mem] == mem;
|
||||
}
|
||||
|
||||
/* validate an input id (from which data path signal will be progagated to the output */
|
||||
bool MuxGraph::valid_input_id(const MuxInputId& input_id) const {
|
||||
for (const auto& lvl : node_lookup_) {
|
||||
for (const auto& node : lvl[MUX_INPUT_NODE]) {
|
||||
if (size_t(input_id) > size_t(node_input_ids_[node])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MuxGraph::valid_node_lookup() const {
|
||||
return node_lookup_.empty();
|
||||
}
|
||||
|
||||
/* validate a mux graph and see if it is valid */
|
||||
bool MuxGraph::valid_mux_graph() const {
|
||||
/* A valid MUX graph should be
|
||||
* 1. every node has 1 fan-out except output node
|
||||
* 2. every input can be routed to the output node
|
||||
*/
|
||||
for (const auto& node : nodes()) {
|
||||
/* output node has 0 fan-out*/
|
||||
if (MUX_OUTPUT_NODE == node_types_[node]) {
|
||||
continue;
|
||||
}
|
||||
/* other nodes should have 1 fan-out */
|
||||
if (1 != node_out_edges_[node].size()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Try to route to output */
|
||||
for (const auto& node : nodes()) {
|
||||
if (MUX_INPUT_NODE == node_types_[node]) {
|
||||
MuxNodeId next_node = node;
|
||||
while ( 0 < node_out_edges_[next_node].size() ) {
|
||||
MuxEdgeId edge = node_out_edges_[next_node][0];
|
||||
/* each edge must have 1 fan-out */
|
||||
if (1 != edge_sink_nodes_[edge].size()) {
|
||||
return false;
|
||||
}
|
||||
next_node = edge_sink_nodes_[edge][0];
|
||||
}
|
||||
if (MUX_OUTPUT_NODE != node_types_[next_node]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* End of Member functions for the class MuxGraph
|
||||
*************************************************/
|
|
@ -0,0 +1,136 @@
|
|||
/**************************************************
|
||||
* This file includes a data structure to describe
|
||||
* the internal structure of a multiplexer
|
||||
* using a generic graph representation
|
||||
* A Branch is a N:1 MUX in the part of MUX graph
|
||||
*
|
||||
* branch_input --->+
|
||||
* |
|
||||
* branch_input --->|
|
||||
* |--> branch_out
|
||||
* ... |
|
||||
* |
|
||||
* branch_input --->+
|
||||
*
|
||||
* A short example of how a two-level MUX is organized by branches
|
||||
*
|
||||
* +-----------+ +--------+
|
||||
* mux_inputs--->| Branch[0] |--->| |
|
||||
* +-----------+ | |
|
||||
* ... | Branch |---> mux_out
|
||||
* +-----------+ | [N+1] |
|
||||
* mux_inputs--->| Branch[N] |--->| |
|
||||
* +-----------+ +--------+
|
||||
*
|
||||
*************************************************/
|
||||
|
||||
#ifndef MUX_GRAPH_H
|
||||
#define MUX_GRAPH_H
|
||||
|
||||
#include "vtr_vector.h"
|
||||
#include "vtr_range.h"
|
||||
#include "mux_graph_fwd.h"
|
||||
#include "circuit_library.h"
|
||||
|
||||
class MuxGraph {
|
||||
private: /* data types used only in this class */
|
||||
enum e_mux_graph_node_type {
|
||||
MUX_INPUT_NODE,
|
||||
MUX_INTERNAL_NODE,
|
||||
MUX_OUTPUT_NODE,
|
||||
NUM_MUX_NODE_TYPES
|
||||
};
|
||||
public: /* Types and ranges */
|
||||
typedef vtr::vector<MuxNodeId, MuxNodeId>::const_iterator node_iterator;
|
||||
typedef vtr::vector<MuxEdgeId, MuxEdgeId>::const_iterator edge_iterator;
|
||||
typedef vtr::vector<MuxMemId, MuxMemId>::const_iterator mem_iterator;
|
||||
|
||||
typedef vtr::Range<node_iterator> node_range;
|
||||
typedef vtr::Range<edge_iterator> edge_range;
|
||||
typedef vtr::Range<mem_iterator> mem_range;
|
||||
public: /* Public Constructors */
|
||||
/* Create an object based on a Circuit Model which is MUX */
|
||||
MuxGraph(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const size_t& mux_size);
|
||||
private: /* Private Constructors*/
|
||||
/* Create an empty graph */
|
||||
MuxGraph();
|
||||
public: /* Public accessors: Aggregates */
|
||||
node_range nodes() const;
|
||||
edge_range edges() const;
|
||||
mem_range memories() const;
|
||||
public: /* Public accessors: Data query */
|
||||
/* Find the number of inputs in the MUX graph */
|
||||
size_t num_inputs() const;
|
||||
/* Find the number of outputs in the MUX graph */
|
||||
size_t num_outputs() const;
|
||||
/* Find the number of levels in the MUX graph */
|
||||
size_t num_levels() const;
|
||||
/* Find the number of SRAMs in the MUX graph */
|
||||
size_t num_memory_bits() const;
|
||||
/* Find the sizes of each branch of a MUX */
|
||||
std::vector<size_t> branch_sizes() const;
|
||||
/* Generate MUX graphs for its branches */
|
||||
MuxGraph subgraph(const MuxNodeId& node) const;
|
||||
std::vector<MuxGraph> build_mux_branch_graphs() const;
|
||||
/* Get the node id of a given input */
|
||||
MuxNodeId node_id(const MuxInputId& input_id) const;
|
||||
/* Decode memory bits based on an input id */
|
||||
std::vector<size_t> decode_memory_bits(const MuxInputId& input_id) const;
|
||||
private: /* Private mutators : basic operations */
|
||||
/* Add a unconfigured node to the MuxGraph */
|
||||
MuxNodeId add_node(const enum e_mux_graph_node_type& node_type);
|
||||
/* Add a edge connecting two nodes */
|
||||
MuxEdgeId add_edge(const MuxNodeId& from_node, const MuxNodeId& to_node);
|
||||
/* Add a memory bit to the MuxGraph */
|
||||
MuxMemId add_mem();
|
||||
/* Link an edge to a mem */
|
||||
void set_edge_mem_id(const MuxEdgeId& edge, const MuxMemId& mem);
|
||||
private: /* Private mutators : graph builders */
|
||||
void build_multilevel_mux_graph(const size_t& mux_size,
|
||||
const size_t& num_levels, const size_t& num_inputs_per_branch,
|
||||
const CircuitModelId& pgl_model) ;
|
||||
/* Build the graph for a given one-level multiplexer implementation */
|
||||
void build_onelevel_mux_graph(const size_t& mux_size,
|
||||
const CircuitModelId& pgl_model) ;
|
||||
/* Build the graph for a given multiplexer model */
|
||||
void build_mux_graph(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const size_t& mux_size);
|
||||
/* Build fast node lookup */
|
||||
void build_node_lookup();
|
||||
private: /* Private validators */
|
||||
/* valid ids */
|
||||
bool valid_node_id(const MuxNodeId& node) const;
|
||||
bool valid_edge_id(const MuxEdgeId& edge) const;
|
||||
bool valid_mem_id(const MuxMemId& mem) const;
|
||||
bool valid_input_id(const MuxInputId& input_id) const;
|
||||
/* validate/invalidate node lookup */
|
||||
bool valid_node_lookup() const;
|
||||
void invalidate_node_lookup();
|
||||
/* validate graph */
|
||||
bool valid_mux_graph() const;
|
||||
private: /* Internal data */
|
||||
vtr::vector<MuxNodeId, MuxNodeId> node_ids_; /* Unique ids for each node */
|
||||
vtr::vector<MuxNodeId, enum e_mux_graph_node_type> node_types_; /* type of each node, input/output/internal */
|
||||
vtr::vector<MuxNodeId, MuxInputId> node_input_ids_; /* Unique ids for each node as an input of the MUX */
|
||||
vtr::vector<MuxNodeId, size_t> node_levels_; /* at which level, each node belongs to */
|
||||
vtr::vector<MuxNodeId, std::vector<MuxEdgeId>> node_in_edges_; /* ids of incoming edges to each node */
|
||||
vtr::vector<MuxNodeId, std::vector<MuxEdgeId>> node_out_edges_; /* ids of outgoing edges from each node */
|
||||
|
||||
vtr::vector<MuxEdgeId, MuxEdgeId> edge_ids_; /* Unique ids for each edge */
|
||||
vtr::vector<MuxEdgeId, std::vector<MuxNodeId>> edge_src_nodes_; /* source nodes drive this edge */
|
||||
vtr::vector<MuxEdgeId, std::vector<MuxNodeId>> edge_sink_nodes_; /* sink nodes this edge drives */
|
||||
vtr::vector<MuxEdgeId, CircuitModelId> edge_models_; /* type of each edge: tgate/pass-gate */
|
||||
vtr::vector<MuxEdgeId, MuxMemId> edge_mem_ids_; /* ids of memory bit that control the edge */
|
||||
vtr::vector<MuxEdgeId, bool> edge_inv_mem_; /* if the edge is controlled by an inverted output of a memory bit */
|
||||
|
||||
vtr::vector<MuxMemId, MuxMemId> mem_ids_; /* ids of configuration memories */
|
||||
|
||||
/* fast look-up */
|
||||
typedef std::vector<std::vector<std::vector<MuxNodeId>>> NodeLookup;
|
||||
mutable NodeLookup node_lookup_; /* [num_levels][num_types][num_nodes_per_level] */
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,24 @@
|
|||
/**************************************************
|
||||
* This file includes only declarations for
|
||||
* the data structures to describe multiplexer structures
|
||||
* Please refer to mux_graph.h for more details
|
||||
*************************************************/
|
||||
#ifndef MUX_GRAPH_FWD_H
|
||||
#define MUX_GRAPH_FWD_H
|
||||
|
||||
#include "vtr_strong_id.h"
|
||||
|
||||
/* Strong Ids for MUXes */
|
||||
struct mux_node_id_tag;
|
||||
struct mux_edge_id_tag;
|
||||
struct mux_mem_id_tag;
|
||||
struct mux_input_id_tag;
|
||||
|
||||
typedef vtr::StrongId<mux_node_id_tag> MuxNodeId;
|
||||
typedef vtr::StrongId<mux_edge_id_tag> MuxEdgeId;
|
||||
typedef vtr::StrongId<mux_mem_id_tag> MuxMemId;
|
||||
typedef vtr::StrongId<mux_input_id_tag> MuxInputId;
|
||||
|
||||
class MuxGraph;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,114 @@
|
|||
/**************************************************
|
||||
* This file includes member functions for the
|
||||
* data structures in mux_library.h
|
||||
*************************************************/
|
||||
|
||||
#include "vtr_assert.h"
|
||||
|
||||
#include "mux_library.h"
|
||||
|
||||
/**************************************************
|
||||
* Member functions for the class MuxLibrary
|
||||
*************************************************/
|
||||
|
||||
/**************************************************
|
||||
* Public accessors: aggregates
|
||||
*************************************************/
|
||||
MuxLibrary::mux_range MuxLibrary::muxes() const {
|
||||
return vtr::make_range(mux_ids_.begin(), mux_ids_.end());
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Public accessors: data query
|
||||
*************************************************/
|
||||
/* Get a MUX graph (read-only) */
|
||||
MuxId MuxLibrary::mux_graph(const CircuitModelId& circuit_model,
|
||||
const size_t& mux_size) const {
|
||||
/* Make sure we have a valid mux look-up */
|
||||
VTR_ASSERT_SAFE(valid_mux_lookup());
|
||||
/* Validate circuit model id and mux_size */
|
||||
VTR_ASSERT_SAFE(valid_mux_size(circuit_model, mux_size));
|
||||
|
||||
return mux_lookup_[circuit_model][mux_size];
|
||||
}
|
||||
|
||||
const MuxGraph& MuxLibrary::mux_graph(const MuxId& mux_id) const {
|
||||
VTR_ASSERT_SAFE(valid_mux_id(mux_id));
|
||||
return mux_graphs_[mux_id];
|
||||
}
|
||||
|
||||
/* Get a mux circuit model id */
|
||||
CircuitModelId MuxLibrary::mux_circuit_model(const MuxId& mux_id) const {
|
||||
VTR_ASSERT_SAFE(valid_mux_id(mux_id));
|
||||
return mux_circuit_models_[mux_id];
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Private mutators:
|
||||
*************************************************/
|
||||
/* Add a mux to the library */
|
||||
void MuxLibrary::add_mux(const CircuitLibrary& circuit_lib, const CircuitModelId& circuit_model, const size_t& mux_size) {
|
||||
/* First, check if there is already an existing graph */
|
||||
if (valid_mux_size(circuit_model, mux_size)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* create a new id for the mux */
|
||||
MuxId mux = MuxId(mux_ids_.size());
|
||||
/* Push to the node list */
|
||||
mux_ids_.push_back(mux);
|
||||
/* Add a mux graph */
|
||||
mux_graphs_.push_back(MuxGraph(circuit_lib, circuit_model, mux_size));
|
||||
/* Recorde mux cirucit model id */
|
||||
mux_circuit_models_.push_back(circuit_model);
|
||||
|
||||
/* update mux_lookup*/
|
||||
mux_lookup_[circuit_model][mux_size] = mux;
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Private accessors: validator and invalidators
|
||||
*************************************************/
|
||||
bool MuxLibrary::valid_mux_id(const MuxId& mux) const {
|
||||
return size_t(mux) < mux_ids_.size() && mux_ids_[mux] == mux;
|
||||
}
|
||||
|
||||
bool MuxLibrary::valid_mux_lookup() const {
|
||||
return mux_lookup_.empty();
|
||||
}
|
||||
|
||||
bool MuxLibrary::valid_mux_circuit_model_id(const CircuitModelId& circuit_model) const {
|
||||
MuxLookup::iterator it = mux_lookup_.find(circuit_model);
|
||||
return (it != mux_lookup_.end());
|
||||
}
|
||||
|
||||
bool MuxLibrary::valid_mux_size(const CircuitModelId& circuit_model, const size_t& mux_size) const {
|
||||
if (false == valid_mux_circuit_model_id(circuit_model)) {
|
||||
return false;
|
||||
}
|
||||
std::map<size_t, MuxId>::iterator it = mux_lookup_[circuit_model].find(mux_size);
|
||||
return (it != mux_lookup_[circuit_model].end());
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Private mutators: validator and invalidators
|
||||
*************************************************/
|
||||
|
||||
/* Build fast node lookup */
|
||||
void MuxLibrary::build_mux_lookup() {
|
||||
/* Invalidate the mux lookup if necessary */
|
||||
invalidate_mux_lookup();
|
||||
}
|
||||
|
||||
/* Invalidate (empty) the mux fast lookup*/
|
||||
void MuxLibrary::invalidate_mux_lookup() {
|
||||
mux_lookup_.clear();
|
||||
}
|
||||
|
||||
|
||||
/**************************************************
|
||||
* End of Member functions for the class MuxLibrary
|
||||
*************************************************/
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
/**************************************************
|
||||
* This file includes a data structure to describe
|
||||
* the multiplexer implementations in FPGA architectures
|
||||
* MuxLibrary is a collection of multiplexers
|
||||
* with various circuit-level description (related to
|
||||
* the information available in CircuitLibrary
|
||||
* and the input size of multiplexers)
|
||||
*************************************************/
|
||||
|
||||
#ifndef MUX_LIBRARY_H
|
||||
#define MUX_LIBRARY_H
|
||||
|
||||
#include <map>
|
||||
#include "mux_graph.h"
|
||||
#include "mux_library_fwd.h"
|
||||
|
||||
class MuxLibrary {
|
||||
public: /* Types and ranges */
|
||||
typedef vtr::vector<MuxId, MuxId>::const_iterator mux_iterator;
|
||||
|
||||
typedef vtr::Range<mux_iterator> mux_range;
|
||||
public: /* Public accessors: Aggregates */
|
||||
mux_range muxes() const;
|
||||
public: /* Public accessors */
|
||||
/* Get a MUX graph (read-only) */
|
||||
MuxId mux_graph(const CircuitModelId& circuit_model, const size_t& mux_size) const;
|
||||
const MuxGraph& mux_graph(const MuxId& mux_id) const;
|
||||
/* Get a mux circuit model id */
|
||||
CircuitModelId mux_circuit_model(const MuxId& mux_id) const;
|
||||
public: /* Public mutators */
|
||||
/* Add a mux to the library */
|
||||
void add_mux(const CircuitLibrary& circuit_lib, const CircuitModelId& circuit_model, const size_t& mux_size);
|
||||
private: /* Private accessors */
|
||||
bool valid_mux_id(const MuxId& mux) const;
|
||||
bool valid_mux_lookup() const;
|
||||
bool valid_mux_circuit_model_id(const CircuitModelId& circuit_model) const;
|
||||
bool valid_mux_size(const CircuitModelId& circuit_model, const size_t& mux_size) const;
|
||||
private: /* Private mutators: mux_lookup */
|
||||
void build_mux_lookup();
|
||||
/* Invalidate (empty) the mux fast lookup*/
|
||||
void invalidate_mux_lookup();
|
||||
private: /* Internal data */
|
||||
/* MUX graph-based desription */
|
||||
vtr::vector<MuxId, MuxId> mux_ids_; /* Unique identifier for each mux graph */
|
||||
vtr::vector<MuxId, MuxGraph> mux_graphs_; /* Graphs describing MUX internal structures */
|
||||
vtr::vector<MuxId, CircuitModelId> mux_circuit_models_; /* circuit model id in circuit library */
|
||||
|
||||
/* Local encoder description */
|
||||
//vtr::vector<MuxLocalDecoderId, Decoder> mux_local_encoders_; /* Graphs describing MUX internal structures */
|
||||
|
||||
/* a fast look-up to search mux_graphs with given circuit model and mux size */
|
||||
typedef std::map<CircuitModelId, std::map<size_t, MuxId>> MuxLookup;
|
||||
mutable MuxLookup mux_lookup_;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,20 @@
|
|||
/**************************************************
|
||||
* This file includes only declarations for
|
||||
* the data structures to describe multiplexer structures
|
||||
* Please refer to mux_library.h for more details
|
||||
*************************************************/
|
||||
#ifndef MUX_LIBRARY_FWD_H
|
||||
#define MUX_LIBRARY_FWD_H
|
||||
|
||||
#include "vtr_strong_id.h"
|
||||
|
||||
/* Strong Ids for MUXes */
|
||||
struct mux_id_tag;
|
||||
struct mux_local_decoder_id_tag;
|
||||
|
||||
typedef vtr::StrongId<mux_id_tag> MuxId;
|
||||
typedef vtr::StrongId<mux_local_decoder_id_tag> MuxLocalDecoderId;
|
||||
|
||||
class MuxLibrary;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,158 @@
|
|||
/**************************************************
|
||||
* This file includes a series of most utilized functions
|
||||
* that are used to implement a multiplexer
|
||||
*************************************************/
|
||||
#include <cmath>
|
||||
|
||||
#include "spice_types.h"
|
||||
#include "util.h"
|
||||
#include "vtr_assert.h"
|
||||
#include "mux_utils.h"
|
||||
|
||||
/* Validate the number of inputs for a multiplexer implementation,
|
||||
* the minimum supported size is 2
|
||||
* otherwise, there is no need for a MUX
|
||||
*/
|
||||
bool valid_mux_implementation_num_inputs(const size_t& mux_size) {
|
||||
return (2 <= mux_size);
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Find the actual number of inputs for a multiplexer implementation
|
||||
* 1. if there are no requirements on constant inputs, mux_size is the actual one
|
||||
* 2. if there exist constant inputs, mux_size should plus 1
|
||||
*************************************************/
|
||||
size_t find_mux_implementation_num_inputs(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const size_t& mux_size) {
|
||||
/* Should be either MUX or LUT
|
||||
* LUTs do have an tree-like MUX, but there is no need for a constant input!
|
||||
*/
|
||||
VTR_ASSERT ((SPICE_MODEL_MUX == circuit_lib.model_type(circuit_model))
|
||||
|| (SPICE_MODEL_LUT == circuit_lib.model_type(circuit_model)) );
|
||||
|
||||
if (SPICE_MODEL_LUT == circuit_lib.model_type(circuit_model)) {
|
||||
return mux_size;
|
||||
}
|
||||
|
||||
if (true == circuit_lib.mux_add_const_input(circuit_model)) {
|
||||
return mux_size + 1;
|
||||
}
|
||||
return mux_size;
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Find the structure for a multiplexer implementation
|
||||
* 1. In most cases, the structure should follow the
|
||||
* mux_structure defined by users in the CircuitLibrary
|
||||
* 2. However, a special case may apply when mux_size is 2
|
||||
* In such case, we will force a TREE structure
|
||||
* regardless of users' specification as this is the
|
||||
* most efficient structure
|
||||
*************************************************/
|
||||
enum e_spice_model_structure find_mux_implementation_structure(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const size_t& mux_size) {
|
||||
/* Ensure the mux size is valid ! */
|
||||
VTR_ASSERT(valid_mux_implementation_num_inputs(mux_size));
|
||||
|
||||
/* Branch on the mux sizes */
|
||||
if (2 == mux_size) {
|
||||
/* Tree-like is the best structure of CMOS MUX2 */
|
||||
if (SPICE_MODEL_DESIGN_CMOS == circuit_lib.design_tech_type(circuit_model)) {
|
||||
return SPICE_MODEL_STRUCTURE_TREE;
|
||||
}
|
||||
VTR_ASSERT_SAFE(SPICE_MODEL_DESIGN_RRAM == circuit_lib.design_tech_type(circuit_model));
|
||||
/* One-level is the best structure of RRAM MUX2 */
|
||||
return SPICE_MODEL_STRUCTURE_ONELEVEL;
|
||||
}
|
||||
|
||||
return circuit_lib.mux_structure(circuit_model);
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Find the number of levels for a tree-like multiplexer implementation
|
||||
*************************************************/
|
||||
size_t find_treelike_mux_num_levels(const size_t& mux_size) {
|
||||
/* Do log2(mux_size), have a basic number */
|
||||
size_t level = (size_t)(log((double)mux_size)/log(2.));
|
||||
/* Fix the error, i.e. mux_size=5, level = 2, we have to complete */
|
||||
while (mux_size > pow(2.,(double)level)) {
|
||||
level++;
|
||||
}
|
||||
|
||||
return level;
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Find the number of inputs for majority of branches
|
||||
* in a multi-level multiplexer implementation
|
||||
*************************************************/
|
||||
size_t find_multilevel_mux_branch_num_inputs(const size_t& mux_size,
|
||||
const size_t& mux_level) {
|
||||
/* Special Case: mux_size = 2 */
|
||||
if (2 == mux_size) {
|
||||
return mux_size;
|
||||
}
|
||||
|
||||
if (1 == mux_level) {
|
||||
return mux_size;
|
||||
}
|
||||
|
||||
if (2 == mux_level) {
|
||||
size_t num_input_per_unit = (size_t)sqrt(mux_size);
|
||||
while ( num_input_per_unit * num_input_per_unit < mux_size) {
|
||||
num_input_per_unit++;
|
||||
}
|
||||
return num_input_per_unit;
|
||||
}
|
||||
|
||||
VTR_ASSERT_SAFE(2 < mux_level);
|
||||
|
||||
size_t num_input_per_unit = 2;
|
||||
while (pow((double)num_input_per_unit, (double)mux_level) < mux_size) {
|
||||
num_input_per_unit++;
|
||||
}
|
||||
|
||||
if (!valid_mux_implementation_num_inputs(num_input_per_unit)) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s,[LINE%d]) Number of inputs of each basis should be at least 2!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return num_input_per_unit;
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Convert a linked list of MUX architecture to MuxLibrary
|
||||
* TODO: this function will be deleted when MUXLibrary fully
|
||||
* replace legacy data structures
|
||||
*************************************************/
|
||||
MuxLibrary convert_mux_arch_to_library(const CircuitLibrary& circuit_lib, t_llist* muxes_head) {
|
||||
t_llist* temp = muxes_head;
|
||||
MuxLibrary mux_lib;
|
||||
|
||||
/* Walk through the linked list */
|
||||
while(temp) {
|
||||
VTR_ASSERT_SAFE(NULL != temp->dptr);
|
||||
t_spice_mux_model* cur_spice_mux_model = (t_spice_mux_model*)(temp->dptr);
|
||||
|
||||
/* Bypass the spice models who has a user-defined subckt */
|
||||
if (NULL != cur_spice_mux_model->spice_model->verilog_netlist) {
|
||||
/* Move on to the next*/
|
||||
temp = temp->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Build a MUX graph for the model */
|
||||
/* Find the circuit model id by the name */
|
||||
CircuitModelId circuit_model = circuit_lib.model(cur_spice_mux_model->spice_model->name);
|
||||
mux_lib.add_mux(circuit_lib, circuit_model, cur_spice_mux_model->size);
|
||||
|
||||
/* Move on to the next*/
|
||||
temp = temp->next;
|
||||
}
|
||||
|
||||
return mux_lib;
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/**************************************************
|
||||
* This file includes only declaration for the
|
||||
* functions in mux_utils.c
|
||||
* Please refer to the source file for more details
|
||||
*************************************************/
|
||||
#ifndef MUX_UTILS_H
|
||||
#define MUX_UTILS_H
|
||||
|
||||
#include "linkedlist.h"
|
||||
#include "circuit_library.h"
|
||||
#include "mux_library.h"
|
||||
|
||||
bool valid_mux_implementation_num_inputs(const size_t& mux_size);
|
||||
|
||||
size_t find_mux_implementation_num_inputs(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const size_t& mux_size);
|
||||
|
||||
|
||||
enum e_spice_model_structure find_mux_implementation_structure(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const size_t& mux_size);
|
||||
|
||||
size_t find_treelike_mux_num_levels(const size_t& mux_size);
|
||||
|
||||
size_t find_multilevel_mux_branch_num_inputs(const size_t& mux_size,
|
||||
const size_t& mux_level);
|
||||
|
||||
MuxLibrary convert_mux_arch_to_library(const CircuitLibrary& circuit_lib, t_llist* muxes_head);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,43 @@
|
|||
/************************************************
|
||||
* This file includes functions to
|
||||
* generate module/port names for Verilog
|
||||
* and SPICE netlists
|
||||
***********************************************/
|
||||
#include "vtr_assert.h"
|
||||
|
||||
#include "fpga_x2p_naming.h"
|
||||
|
||||
/************************************************
|
||||
* Generate the module name for a multiplexer in Verilog format
|
||||
***********************************************/
|
||||
std::string generate_verilog_mux_subckt_name(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const size_t& mux_size,
|
||||
const std::string& postfix) {
|
||||
std::string module_name = circuit_lib.model_name(circuit_model);
|
||||
module_name += "_size";
|
||||
module_name += std::to_string(mux_size);
|
||||
module_name += postfix;
|
||||
|
||||
return module_name;
|
||||
}
|
||||
|
||||
/************************************************
|
||||
* Generate the module name of a branch for a
|
||||
* multiplexer in Verilog format
|
||||
***********************************************/
|
||||
std::string generate_verilog_mux_branch_subckt_name(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const size_t& mux_size,
|
||||
const std::string& postfix) {
|
||||
/* If the tgate spice model of this MUX is a MUX2 standard cell,
|
||||
* the mux_subckt name will be the name of the standard cell
|
||||
*/
|
||||
CircuitModelId subckt_model = circuit_lib.pass_gate_logic_model(circuit_model);
|
||||
if (SPICE_MODEL_GATE == circuit_lib.model_type(subckt_model)) {
|
||||
VTR_ASSERT (SPICE_MODEL_GATE_MUX2 == circuit_lib.gate_type(subckt_model));
|
||||
return circuit_lib.model_name(subckt_model);
|
||||
}
|
||||
|
||||
return generate_verilog_mux_subckt_name(circuit_lib, circuit_model, mux_size, postfix);
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/************************************************
|
||||
* Header file for fpga_x2p_naming.cpp
|
||||
* Include functions to generate module/port names
|
||||
* for Verilog and SPICE netlists
|
||||
***********************************************/
|
||||
|
||||
#ifndef FPGA_X2P_NAMING_H
|
||||
#define FPGA_X2P_NAMING_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "circuit_library.h"
|
||||
|
||||
std::string generate_verilog_mux_subckt_name(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const size_t& mux_size,
|
||||
const std::string& posfix) ;
|
||||
|
||||
std::string generate_verilog_mux_branch_subckt_name(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const size_t& mux_size,
|
||||
const std::string& posfix);
|
||||
|
||||
#endif
|
|
@ -12,6 +12,7 @@
|
|||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <algorithm>
|
||||
|
||||
/* Include vpr structs*/
|
||||
#include "util.h"
|
||||
|
@ -63,6 +64,7 @@ char* my_gettime() {
|
|||
return c_time_string;
|
||||
}
|
||||
|
||||
|
||||
char* format_dir_path(char* dir_path) {
|
||||
int len = strlen(dir_path); /* String length without the last "\0"*/
|
||||
int i;
|
||||
|
@ -82,6 +84,26 @@ char* format_dir_path(char* dir_path) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
/************************************************
|
||||
* Format a path of directory:
|
||||
* 1. Replace "\" with "/"
|
||||
* 2. add a "/" if the string does not end with a "/"
|
||||
***********************************************/
|
||||
std::string format_dir_path(const std::string& dir_path) {
|
||||
std::string ret = dir_path;
|
||||
|
||||
/* Replace "\" with "/" */
|
||||
std::replace(ret.begin(), ret.end(), '\\', '/');
|
||||
|
||||
/* Complete the string with a "/" if it does not end with that */
|
||||
if ('/' != ret.back()) {
|
||||
ret.push_back('/');
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int try_access_file(char* file_path) {
|
||||
/* F_OK checks existence and also R_OK, W_OK, X_OK,
|
||||
* for readable, writable, excutable
|
||||
|
@ -228,6 +250,17 @@ char* chomp_file_name_postfix(char* file_name) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
void check_file_handler(std::fstream& fp) {
|
||||
/* Make sure we have a valid file handler*/
|
||||
/* Print out debugging information for if the file is not opened/created properly */
|
||||
if (!fp.is_open() || !fp.good()) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(FILE:%s,LINE[%d])Failure in create file!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Print SRAM bits, typically in a comment line */
|
||||
void fprint_commented_sram_bits(FILE* fp,
|
||||
|
@ -3217,7 +3250,7 @@ int count_cb_info_num_ipin_rr_nodes(t_cb cur_cb_info) {
|
|||
|
||||
/* Add a subckt file name to a linked list */
|
||||
t_llist* add_one_subckt_file_name_to_llist(t_llist* cur_head,
|
||||
char* subckt_file_path) {
|
||||
const char* subckt_file_path) {
|
||||
t_llist* new_head = NULL;
|
||||
|
||||
if (NULL == cur_head) {
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
#ifndef FPGA_X2P_UTILS_H
|
||||
#define FPGA_X2P_UTILS_H
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "my_free_fwd.h"
|
||||
#include "rr_blocks_naming.h"
|
||||
|
||||
void check_file_handler(std::fstream& fp);
|
||||
|
||||
char* my_gettime();
|
||||
|
||||
char* format_dir_path(char* dir_path);
|
||||
char* format_dir_path(char* dir_path); /* TODO: TO BE REMOVED !!! */
|
||||
std::string format_dir_path(const std::string& dir_path);
|
||||
|
||||
int try_access_file(char* file_path);
|
||||
|
||||
|
@ -376,7 +381,7 @@ boolean is_cb_exist(t_rr_type cb_type,
|
|||
int count_cb_info_num_ipin_rr_nodes(t_cb cur_cb_info);
|
||||
|
||||
t_llist* add_one_subckt_file_name_to_llist(t_llist* cur_head,
|
||||
char* subckt_file_path);
|
||||
const char* subckt_file_path);
|
||||
|
||||
boolean check_subckt_file_exist_in_llist(t_llist* subckt_llist_head,
|
||||
char* subckt_file_name);
|
||||
|
|
|
@ -81,31 +81,31 @@
|
|||
CircuitModelId link_circuit_model_by_name_and_type(const char* circuit_model_name,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const enum e_spice_model_type& model_type) {
|
||||
CircuitModelId circuit_model = CIRCUIT_MODEL_OPEN_ID;
|
||||
CircuitModelId circuit_model = CircuitModelId::INVALID();
|
||||
/* If the circuit_model_name is not defined, we use the default*/
|
||||
if (NULL == circuit_model_name) {
|
||||
circuit_model = circuit_lib.default_circuit_model(model_type);
|
||||
circuit_model = circuit_lib.default_model(model_type);
|
||||
} else {
|
||||
circuit_model = circuit_lib.circuit_model(circuit_model_name);
|
||||
circuit_model = circuit_lib.model(circuit_model_name);
|
||||
}
|
||||
|
||||
/* Check the circuit model, we should have one! */
|
||||
if (CIRCUIT_MODEL_OPEN_ID == circuit_model) {
|
||||
if (CircuitModelId::INVALID() == circuit_model) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s,LINE[%d]) Fail to find a defined circuit model called %s!\n",
|
||||
__FILE__, __LINE__,
|
||||
circuit_lib.circuit_model_name(circuit_model).c_str());
|
||||
circuit_lib.model_name(circuit_model).c_str());
|
||||
return circuit_model; /* Return here, no need to check the model_type */
|
||||
}
|
||||
|
||||
/* Check the type of circuit model, make sure it is the one we want */
|
||||
if (model_type != circuit_lib.circuit_model_type(circuit_model)) {
|
||||
if (model_type != circuit_lib.model_type(circuit_model)) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s,LINE[%d]) Invalid type when trying to find circuit model called %s! Expect %s but found %s!\n",
|
||||
__FILE__, __LINE__,
|
||||
circuit_model_name,
|
||||
CIRCUIT_MODEL_TYPE_STRING[size_t(model_type)],
|
||||
CIRCUIT_MODEL_TYPE_STRING[size_t(circuit_lib.circuit_model_type(circuit_model))]);
|
||||
CIRCUIT_MODEL_TYPE_STRING[size_t(circuit_lib.model_type(circuit_model))]);
|
||||
}
|
||||
|
||||
return circuit_model;
|
||||
|
@ -196,7 +196,6 @@ void link_sram_inf(t_sram_inf* cur_sram_inf,
|
|||
**************************************************************************/
|
||||
t_port* find_pb_type_port_match_circuit_model_port(const t_pb_type* pb_type,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const CircuitPortId& circuit_port) {
|
||||
t_port* ret = NULL;
|
||||
size_t num_found = 0;
|
||||
|
@ -204,10 +203,10 @@ t_port* find_pb_type_port_match_circuit_model_port(const t_pb_type* pb_type,
|
|||
/* Search ports */
|
||||
for (int iport = 0; iport < pb_type->num_ports; iport++) {
|
||||
/* Match the name and port size*/
|
||||
if ( (0 == circuit_lib.port_prefix(circuit_model, circuit_port).compare(pb_type->ports[iport].name))
|
||||
&& (size_t(pb_type->ports[iport].num_pins) == circuit_lib.port_size(circuit_model, circuit_port))) {
|
||||
if ( (0 == circuit_lib.port_prefix(circuit_port).compare(pb_type->ports[iport].name))
|
||||
&& (size_t(pb_type->ports[iport].num_pins) == circuit_lib.port_size(circuit_port))) {
|
||||
/* Match the type*/
|
||||
switch (circuit_lib.port_type(circuit_model, circuit_port)) {
|
||||
switch (circuit_lib.port_type(circuit_port)) {
|
||||
case SPICE_MODEL_PORT_INPUT:
|
||||
if ((IN_PORT == pb_type->ports[iport].type)
|
||||
&&(0 == pb_type->ports[iport].is_clock)) {
|
||||
|
@ -235,8 +234,9 @@ t_port* find_pb_type_port_match_circuit_model_port(const t_pb_type* pb_type,
|
|||
case SPICE_MODEL_PORT_SRAM:
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,"(File:%s, [LINE%d])Invalid type for circuit model port(%s)!\n",
|
||||
__FILE__, __LINE__, circuit_lib.port_prefix(circuit_model, circuit_port));
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s, [LINE%d])Invalid type for circuit model port(%s)!\n",
|
||||
__FILE__, __LINE__, circuit_lib.port_prefix(circuit_port).c_str());
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
@ -246,7 +246,7 @@ t_port* find_pb_type_port_match_circuit_model_port(const t_pb_type* pb_type,
|
|||
if (1 < num_found) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s, [LINE%d])More than 1 pb_type(%s) port match spice_model_port(%s)!\n",
|
||||
__FILE__, __LINE__, pb_type->name, circuit_lib.port_prefix(circuit_model, circuit_port).c_str());
|
||||
__FILE__, __LINE__, pb_type->name, circuit_lib.port_prefix(circuit_port).c_str());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
@ -267,17 +267,17 @@ int link_pb_type_port_to_circuit_model_ports(const t_pb_type* cur_pb_type,
|
|||
|
||||
/* Initialize each port */
|
||||
for (int iport = 0; iport < cur_pb_type->num_ports; iport++) {
|
||||
cur_pb_type->ports[iport].circuit_model_port = CIRCUIT_PORT_OPEN_ID;
|
||||
cur_pb_type->ports[iport].circuit_model_port = CircuitPortId::INVALID();
|
||||
}
|
||||
|
||||
/* Return if SPICE_MODEL is NULL */
|
||||
if (CIRCUIT_MODEL_OPEN_ID == circuit_model) {
|
||||
if (CircuitModelId::INVALID() == circuit_model) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* For each port, find a SPICE model port, which has the same name and port size */
|
||||
for (auto& port : circuit_lib.ports(circuit_model)) {
|
||||
t_port* cur_pb_type_port = find_pb_type_port_match_circuit_model_port(cur_pb_type, circuit_lib, circuit_model, port);
|
||||
for (auto& port : circuit_lib.model_ports(circuit_model)) {
|
||||
t_port* cur_pb_type_port = find_pb_type_port_match_circuit_model_port(cur_pb_type, circuit_lib, port);
|
||||
/* Not every spice_model_port can find a mapped pb_type_port.
|
||||
* Since a pb_type only includes necessary ports in technology mapping.
|
||||
* ports for physical designs may be ignored !
|
||||
|
@ -290,11 +290,11 @@ int link_pb_type_port_to_circuit_model_ports(const t_pb_type* cur_pb_type,
|
|||
* but each pb_type_port should be mapped to a spice_model_port
|
||||
*/
|
||||
for (int iport = 0; iport < cur_pb_type->num_ports; iport++) {
|
||||
if (CIRCUIT_PORT_OPEN_ID == cur_pb_type->ports[iport].circuit_model_port) {
|
||||
if (CircuitPortId::INVALID() == cur_pb_type->ports[iport].circuit_model_port) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s, [LINE%d])Pb_type(%s) Port(%s) cannot find a corresponding port in SPICE model(%s)\n",
|
||||
__FILE__, __LINE__, cur_pb_type->name, cur_pb_type->ports[iport].name,
|
||||
circuit_lib.circuit_model_name(circuit_model).c_str());
|
||||
circuit_lib.model_name(circuit_model).c_str());
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
@ -319,7 +319,7 @@ void link_pb_type_interc_circuit_model_by_type(t_interconnect* cur_interc,
|
|||
circuit_lib,
|
||||
model_type);
|
||||
/* Check the circuit model, we should have one! */
|
||||
if (CIRCUIT_MODEL_OPEN_ID == cur_interc->circuit_model) {
|
||||
if (CircuitModelId::INVALID() == cur_interc->circuit_model) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s,LINE[%d]) Error in linking circuit model for interconnect(name %s)! Check [LINE%d] in architecture file)!\n",
|
||||
__FILE__, __LINE__,
|
||||
|
@ -415,8 +415,8 @@ void link_pb_types_circuit_model_rec(t_pb_type* cur_pb_type,
|
|||
return;
|
||||
}
|
||||
/* Let's find a matched circuit model!*/
|
||||
cur_pb_type->circuit_model = circuit_lib.circuit_model(cur_pb_type->spice_model_name);
|
||||
if (CIRCUIT_MODEL_OPEN_ID == cur_pb_type->circuit_model) {
|
||||
cur_pb_type->circuit_model = circuit_lib.model(cur_pb_type->spice_model_name);
|
||||
if (CircuitModelId::INVALID() == cur_pb_type->circuit_model) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s,LINE[%d]) Fail to find a defined circuit model called %s, in pb_type(%s)!\n",
|
||||
__FILE__, __LINE__, cur_pb_type->spice_model_name, cur_pb_type->name);
|
||||
|
@ -428,14 +428,14 @@ void link_pb_types_circuit_model_rec(t_pb_type* cur_pb_type,
|
|||
}
|
||||
|
||||
/* Otherwise, initialize it to be OPEN node */
|
||||
cur_pb_type->circuit_model = CIRCUIT_MODEL_OPEN_ID;
|
||||
cur_pb_type->circuit_model = CircuitModelId::INVALID();
|
||||
|
||||
/* Traversal the hierarchy*/
|
||||
for (int imode = 0; imode < cur_pb_type->num_modes; imode++) {
|
||||
/* Task 1: Find the interconnections and match the spice_model */
|
||||
for (int jinterc = 0; jinterc < cur_pb_type->modes[imode].num_interconnect; jinterc++) {
|
||||
/* Initialize it to be OPEN node */
|
||||
cur_pb_type->modes[imode].interconnect[jinterc].circuit_model = CIRCUIT_MODEL_OPEN_ID;
|
||||
cur_pb_type->modes[imode].interconnect[jinterc].circuit_model = CircuitModelId::INVALID();
|
||||
link_pb_type_interc_circuit_model(&(cur_pb_type->modes[imode].interconnect[jinterc]),
|
||||
circuit_lib);
|
||||
}
|
||||
|
@ -453,12 +453,12 @@ size_t check_circuit_model_structure_match_switch_inf(const t_switch_inf& target
|
|||
const CircuitLibrary& circuit_lib) {
|
||||
size_t num_err = 0;
|
||||
|
||||
VTR_ASSERT_SAFE(CIRCUIT_MODEL_OPEN_ID != target_switch_inf.circuit_model);
|
||||
VTR_ASSERT_SAFE(CircuitModelId::INVALID() != target_switch_inf.circuit_model);
|
||||
if (target_switch_inf.structure != circuit_lib.mux_structure(target_switch_inf.circuit_model)) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s,[LINE%d]) Mismatch in MUX structure between circuit model(%s, %s) and switch_inf(%s, %s)!\n",
|
||||
__FILE__, __LINE__,
|
||||
circuit_lib.circuit_model_name(target_switch_inf.circuit_model).c_str(),
|
||||
circuit_lib.model_name(target_switch_inf.circuit_model).c_str(),
|
||||
CIRCUIT_MODEL_STRUCTURE_TYPE_STRING[size_t(circuit_lib.mux_structure(target_switch_inf.circuit_model))],
|
||||
target_switch_inf.name,
|
||||
CIRCUIT_MODEL_STRUCTURE_TYPE_STRING[size_t(target_switch_inf.structure)]);
|
||||
|
@ -494,7 +494,7 @@ void link_circuit_library_to_arch(t_arch* arch,
|
|||
for (int i = 0; i < arch->num_cb_switch; i++) {
|
||||
arch->cb_switches[i].circuit_model = link_circuit_model_by_name_and_type(arch->cb_switches[i].spice_model_name,
|
||||
arch->spice->circuit_lib, SPICE_MODEL_MUX);
|
||||
if (CIRCUIT_MODEL_OPEN_ID == arch->cb_switches[i].circuit_model) {
|
||||
if (CircuitModelId::INVALID() == arch->cb_switches[i].circuit_model) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(FILE:%s, LINE[%d])Invalid circuit model name(%s) of Switch(%s) is undefined in circuit models!\n",
|
||||
__FILE__, __LINE__, arch->cb_switches[i].spice_model_name, arch->cb_switches[i].name);
|
||||
|
@ -517,7 +517,7 @@ void link_circuit_library_to_arch(t_arch* arch,
|
|||
for (int i = 0; i < arch->num_switches; i++) {
|
||||
arch->Switches[i].circuit_model = link_circuit_model_by_name_and_type(arch->Switches[i].spice_model_name,
|
||||
arch->spice->circuit_lib, SPICE_MODEL_MUX);
|
||||
if (CIRCUIT_MODEL_OPEN_ID == arch->Switches[i].circuit_model) {
|
||||
if (CircuitModelId::INVALID() == arch->Switches[i].circuit_model) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(FILE:%s, LINE[%d])Invalid circuit model name(%s) of Switch(%s) is undefined in circuit models!\n",
|
||||
__FILE__, __LINE__, arch->Switches[i].spice_model_name, arch->Switches[i].name);
|
||||
|
@ -533,7 +533,7 @@ void link_circuit_library_to_arch(t_arch* arch,
|
|||
for (int i = 0; i < routing_arch->num_switch; i++) {
|
||||
switch_inf[i].circuit_model = link_circuit_model_by_name_and_type(switch_inf[i].spice_model_name,
|
||||
arch->spice->circuit_lib, SPICE_MODEL_MUX);
|
||||
if (CIRCUIT_MODEL_OPEN_ID == switch_inf[i].circuit_model) {
|
||||
if (CircuitModelId::INVALID() == switch_inf[i].circuit_model) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(FILE:%s, LINE[%d])Invalid circuit model name(%s) of Switch(%s) is undefined in circuit models!\n",
|
||||
__FILE__, __LINE__, switch_inf[i].spice_model_name, switch_inf[i].name);
|
||||
|
@ -548,7 +548,7 @@ void link_circuit_library_to_arch(t_arch* arch,
|
|||
for (int i = 0; i < arch->num_segments; i++) {
|
||||
arch->Segments[i].circuit_model = link_circuit_model_by_name_and_type(arch->Segments[i].spice_model_name,
|
||||
arch->spice->circuit_lib, SPICE_MODEL_CHAN_WIRE);
|
||||
if (CIRCUIT_MODEL_OPEN_ID == arch->Segments[i].circuit_model) {
|
||||
if (CircuitModelId::INVALID() == arch->Segments[i].circuit_model) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(FILE:%s, LINE[%d])Invalid circuit model name(%s) of Segment(Length:%d) is undefined in circuit models!\n",
|
||||
__FILE__ ,__LINE__,
|
||||
|
@ -563,7 +563,7 @@ void link_circuit_library_to_arch(t_arch* arch,
|
|||
arch->Directs[i].circuit_model = link_circuit_model_by_name_and_type(arch->Directs[i].spice_model_name,
|
||||
arch->spice->circuit_lib, SPICE_MODEL_WIRE);
|
||||
/* Check SPICE model type */
|
||||
if (CIRCUIT_MODEL_OPEN_ID == arch->Directs[i].circuit_model) {
|
||||
if (CircuitModelId::INVALID() == arch->Directs[i].circuit_model) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(FILE:%s, LINE[%d])Invalid circuit model name(%s) of CLB to CLB Direct Connection (name=%s) is undefined in circuit models!\n",
|
||||
__FILE__ ,__LINE__,
|
||||
|
|
|
@ -54,7 +54,6 @@ CircuitModelId link_circuit_model_by_name_and_type(const char* circuit_model_nam
|
|||
|
||||
t_port* find_pb_type_port_match_circuit_model_port(const t_pb_type* pb_type,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const CircuitPortId& circuit_port);
|
||||
|
||||
void link_circuit_library_to_arch(t_arch* arch,
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
/******************************************************************************
|
||||
* Memember functions for data structure ModuleManager
|
||||
******************************************************************************/
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include "vtr_assert.h"
|
||||
|
||||
#include "circuit_library.h"
|
||||
#include "module_manager.h"
|
||||
|
||||
/******************************************************************************
|
||||
* Public Constructors
|
||||
******************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
* Public Accessors
|
||||
******************************************************************************/
|
||||
/* Return number of modules */
|
||||
size_t ModuleManager::num_modules() const {
|
||||
return ids_.size();
|
||||
}
|
||||
|
||||
/* Find the name of a module */
|
||||
std::string ModuleManager::module_name(const ModuleId& module_id) const {
|
||||
/* Validate the module_id */
|
||||
VTR_ASSERT(valid_module_id(module_id));
|
||||
return names_[module_id];
|
||||
}
|
||||
|
||||
/* Get the string of a module port type */
|
||||
std::string ModuleManager::module_port_type_str(const enum e_module_port_type& port_type) const {
|
||||
std::array<const char*, NUM_MODULE_PORT_TYPES> MODULE_PORT_TYPE_STRING = {{"GLOBAL PORTS", "INOUT PORTS", "INPUT PORTS", "OUTPUT PORTS", "CLOCK PORTS"}};
|
||||
return MODULE_PORT_TYPE_STRING[port_type];
|
||||
}
|
||||
|
||||
/* Find a list of ports of a module by a given types */
|
||||
std::vector<BasicPort> ModuleManager::module_ports_by_type(const ModuleId& module_id, const enum e_module_port_type& port_type) const {
|
||||
/* Validate the module_id */
|
||||
VTR_ASSERT(valid_module_id(module_id));
|
||||
|
||||
std::vector<BasicPort> ports;
|
||||
for (const auto& port : port_ids_[module_id]) {
|
||||
/* Skip unmatched ports */
|
||||
if (port_type != port_types_[module_id][port]) {
|
||||
continue;
|
||||
}
|
||||
ports.push_back(ports_[module_id][port]);
|
||||
}
|
||||
|
||||
return ports;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Public Mutators
|
||||
******************************************************************************/
|
||||
/* Add a module */
|
||||
ModuleId ModuleManager::add_module(const std::string& name) {
|
||||
/* Find if the name has been used. If used, return an invalid Id and report error! */
|
||||
std::map<std::string, ModuleId>::iterator it = name_id_map_.find(name);
|
||||
if (it != name_id_map_.end()) {
|
||||
return ModuleId::INVALID();
|
||||
}
|
||||
|
||||
/* Create an new id */
|
||||
ModuleId module = ModuleId(ids_.size());
|
||||
ids_.push_back(module);
|
||||
|
||||
/* Allocate other attributes */
|
||||
names_.push_back(name);
|
||||
parents_.emplace_back();
|
||||
children_.emplace_back();
|
||||
|
||||
port_ids_.emplace_back();
|
||||
ports_.emplace_back();
|
||||
port_types_.emplace_back();
|
||||
|
||||
/* Register in the name-to-id map */
|
||||
name_id_map_[name] = module;
|
||||
|
||||
/* Build port lookup */
|
||||
port_lookup_.emplace_back();
|
||||
port_lookup_[module].resize(NUM_MODULE_PORT_TYPES);
|
||||
|
||||
/* Return the new id */
|
||||
return module;
|
||||
}
|
||||
|
||||
/* Add a port to a module */
|
||||
ModulePortId ModuleManager::add_port(const ModuleId& module,
|
||||
const BasicPort& port_info, const enum e_module_port_type& port_type) {
|
||||
/* Validate the id of module */
|
||||
VTR_ASSERT( valid_module_id(module) );
|
||||
|
||||
/* Add port and fill port attributes */
|
||||
ModulePortId port = ModulePortId(port_ids_[module].size());
|
||||
port_ids_[module].push_back(port);
|
||||
ports_[module].push_back(port_info);
|
||||
port_types_[module].push_back(port_type);
|
||||
|
||||
/* Update fast look-up for port */
|
||||
port_lookup_[module][port_type].push_back(port);
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
/* Add a child module to a parent module */
|
||||
void ModuleManager::add_child_module(const ModuleId& parent_module, const ModuleId& child_module) {
|
||||
/* Validate the id of both parent and child modules */
|
||||
VTR_ASSERT ( valid_module_id(parent_module) );
|
||||
VTR_ASSERT ( valid_module_id(child_module) );
|
||||
|
||||
/* Try to find if the parent module is already in the list */
|
||||
std::vector<ModuleId>::iterator parent_it = std::find(parents_[child_module].begin(), parents_[child_module].end(), parent_module);
|
||||
if (parent_it == parents_[child_module].end()) {
|
||||
/* Update the parent module of child module */
|
||||
parents_[child_module].push_back(parent_module);
|
||||
}
|
||||
|
||||
std::vector<ModuleId>::iterator child_it = std::find(children_[child_module].begin(), children_[child_module].end(), child_module);
|
||||
if (child_it == children_[parent_module].end()) {
|
||||
/* Update the child module of parent module */
|
||||
children_[parent_module].push_back(child_module);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Private validators/invalidators
|
||||
******************************************************************************/
|
||||
bool ModuleManager::valid_module_id(const ModuleId& module) const {
|
||||
return ( size_t(module) < ids_.size() ) && ( module == ids_[module] );
|
||||
}
|
||||
|
||||
bool ModuleManager::valid_module_port_id(const ModuleId& module, const ModulePortId& port) const {
|
||||
if (false == valid_module_id(module)) {
|
||||
return false;
|
||||
}
|
||||
return ( size_t(port) < port_ids_[module].size() ) && ( port == port_ids_[module][port] );
|
||||
}
|
||||
|
||||
void ModuleManager::invalidate_name2id_map() {
|
||||
name_id_map_.clear();
|
||||
}
|
||||
|
||||
void ModuleManager::invalidate_port_lookup() {
|
||||
port_lookup_.clear();
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/******************************************************************************
|
||||
* This files includes data structures for module management.
|
||||
* It keeps a list of modules that have been generated, the port map of the modules,
|
||||
* parents and children of each modules. This will ease instanciation of modules
|
||||
* with explicit port map and outputting a hierarchy of modules
|
||||
*
|
||||
* Module includes the basic information:
|
||||
* 1. unique identifier
|
||||
* 2. module name: which should be unique
|
||||
* 3. port list: basic information of all the ports belonging to the module
|
||||
* 4. port types: types of each port, which will matter how we output the ports
|
||||
* 5. parent modules: ids of parent modules
|
||||
* 6. children modules: ids of child modules
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef MODULE_MANAGER_H
|
||||
#define MODULE_MANAGER_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include "module_manager_fwd.h"
|
||||
#include "device_port.h"
|
||||
|
||||
class ModuleManager {
|
||||
public: /* Private data structures */
|
||||
enum e_module_port_type {
|
||||
MODULE_GLOBAL_PORT,
|
||||
MODULE_INOUT_PORT,
|
||||
MODULE_INPUT_PORT,
|
||||
MODULE_OUTPUT_PORT,
|
||||
MODULE_CLOCK_PORT,
|
||||
NUM_MODULE_PORT_TYPES
|
||||
};
|
||||
public: /* Public Constructors */
|
||||
public: /* Public accessors */
|
||||
size_t num_modules() const;
|
||||
std::string module_name(const ModuleId& module_id) const;
|
||||
std::string module_port_type_str(const enum e_module_port_type& port_type) const;
|
||||
std::vector<BasicPort> module_ports_by_type(const ModuleId& module_id, const enum e_module_port_type& port_type) const;
|
||||
public: /* Public mutators */
|
||||
/* Add a module */
|
||||
ModuleId add_module(const std::string& name);
|
||||
/* Add a port to a module */
|
||||
ModulePortId add_port(const ModuleId& module,
|
||||
const BasicPort& port_info, const enum e_module_port_type& port_type);
|
||||
/* Add a child module to a parent module */
|
||||
void add_child_module(const ModuleId& parent_module, const ModuleId& child_module);
|
||||
private: /* Private validators/invalidators */
|
||||
bool valid_module_id(const ModuleId& module) const;
|
||||
bool valid_module_port_id(const ModuleId& module, const ModulePortId& port) const;
|
||||
void invalidate_name2id_map();
|
||||
void invalidate_port_lookup();
|
||||
private: /* Internal data */
|
||||
vtr::vector<ModuleId, ModuleId> ids_; /* Unique identifier for each Module */
|
||||
vtr::vector<ModuleId, std::string> names_; /* Unique identifier for each Module */
|
||||
vtr::vector<ModuleId, std::vector<ModuleId>> parents_; /* Parent modules that include the module */
|
||||
vtr::vector<ModuleId, std::vector<ModuleId>> children_; /* Child modules that this module contain */
|
||||
|
||||
vtr::vector<ModuleId, vtr::vector<ModulePortId, ModulePortId>> port_ids_; /* List of ports for each Module */
|
||||
vtr::vector<ModuleId, vtr::vector<ModulePortId, BasicPort>> ports_; /* List of ports for each Module */
|
||||
vtr::vector<ModuleId, vtr::vector<ModulePortId, enum e_module_port_type>> port_types_; /* Type of ports */
|
||||
|
||||
/* fast look-up for module */
|
||||
std::map<std::string, ModuleId> name_id_map_;
|
||||
/* fast look-up for ports */
|
||||
typedef vtr::vector<ModuleId, std::vector<std::vector<ModulePortId>>> PortLookup;
|
||||
mutable PortLookup port_lookup_; /* [module_ids][port_types][port_ids] */
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,20 @@
|
|||
/**************************************************
|
||||
* This file includes only declarations for
|
||||
* the data structures for module managers
|
||||
* Please refer to module_manager.h for more details
|
||||
*************************************************/
|
||||
#ifndef MODULE_MANAGER_FWD_H
|
||||
#define MODULE_MANAGER_FWD_H
|
||||
|
||||
#include "vtr_strong_id.h"
|
||||
|
||||
/* Strong Ids for ModuleManager */
|
||||
struct module_id_tag;
|
||||
struct module_port_id_tag;
|
||||
|
||||
typedef vtr::StrongId<module_id_tag> ModuleId;
|
||||
typedef vtr::StrongId<module_port_id_tag> ModulePortId;
|
||||
|
||||
class ModuleManager;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,51 @@
|
|||
/******************************************************************************
|
||||
* This files includes most utilized functions
|
||||
* for data structures for module management.
|
||||
******************************************************************************/
|
||||
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
|
||||
#include "vtr_assert.h"
|
||||
|
||||
#include "spice_types.h"
|
||||
|
||||
#include "circuit_library.h"
|
||||
#include "module_manager.h"
|
||||
#include "module_manager_utils.h"
|
||||
|
||||
ModuleId add_circuit_model_to_module_manager(ModuleManager& module_manager,
|
||||
const CircuitLibrary& circuit_lib, const CircuitModelId& circuit_model) {
|
||||
ModuleId module = module_manager.add_module(circuit_lib.model_name(circuit_model));
|
||||
|
||||
/* Add ports */
|
||||
/* Find global ports and add one by one */
|
||||
for (const auto& port : circuit_lib.model_global_ports(circuit_model, true)) {
|
||||
BasicPort port_info(circuit_lib.port_lib_name(port), circuit_lib.port_size(port));
|
||||
module_manager.add_port(module, port_info, ModuleManager::MODULE_GLOBAL_PORT);
|
||||
}
|
||||
|
||||
/* Find other ports and add one by one */
|
||||
/* Create a type-to-type map for ports */
|
||||
std::map<enum e_spice_model_port_type, ModuleManager::e_module_port_type> port_type2type_map;
|
||||
port_type2type_map[SPICE_MODEL_PORT_INOUT] = ModuleManager::MODULE_INOUT_PORT;
|
||||
port_type2type_map[SPICE_MODEL_PORT_INPUT] = ModuleManager::MODULE_INPUT_PORT;
|
||||
port_type2type_map[SPICE_MODEL_PORT_CLOCK] = ModuleManager::MODULE_INPUT_PORT;
|
||||
port_type2type_map[SPICE_MODEL_PORT_SRAM] = ModuleManager::MODULE_INPUT_PORT;
|
||||
port_type2type_map[SPICE_MODEL_PORT_BL] = ModuleManager::MODULE_INPUT_PORT;
|
||||
port_type2type_map[SPICE_MODEL_PORT_BLB] = ModuleManager::MODULE_INPUT_PORT;
|
||||
port_type2type_map[SPICE_MODEL_PORT_WL] = ModuleManager::MODULE_INPUT_PORT;
|
||||
port_type2type_map[SPICE_MODEL_PORT_WLB] = ModuleManager::MODULE_INPUT_PORT;
|
||||
port_type2type_map[SPICE_MODEL_PORT_OUTPUT] = ModuleManager::MODULE_OUTPUT_PORT;
|
||||
|
||||
/* Input ports (ignore all the global ports when searching the circuit_lib */
|
||||
for (const auto& kv : port_type2type_map) {
|
||||
for (const auto& port : circuit_lib.model_ports_by_type(circuit_model, kv.first, true)) {
|
||||
BasicPort port_info(circuit_lib.port_lib_name(port), circuit_lib.port_size(port));
|
||||
module_manager.add_port(module, port_info, kv.second);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the new id */
|
||||
return module;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
/******************************************************************************
|
||||
* This files includes declarations for most utilized functions
|
||||
* for data structures for module management.
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef MODULE_MANAGER_UTILS_H
|
||||
#define MODULE_MANAGER_UTILS_H
|
||||
|
||||
ModuleId add_circuit_model_to_module_manager(ModuleManager& module_manager,
|
||||
const CircuitLibrary& circuit_lib, const CircuitModelId& circuit_model);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -32,6 +32,8 @@
|
|||
#include "fpga_x2p_globals.h"
|
||||
#include "fpga_bitstream.h"
|
||||
|
||||
#include "module_manager.h"
|
||||
|
||||
/* Include SynVerilog headers */
|
||||
#include "verilog_global.h"
|
||||
#include "verilog_utils.h"
|
||||
|
@ -148,6 +150,9 @@ void vpr_fpga_verilog(t_vpr_setup vpr_setup,
|
|||
|
||||
t_sram_orgz_info* sram_verilog_orgz_info = NULL;
|
||||
|
||||
/* Module manager for the Verilog modules created */
|
||||
ModuleManager module_manager;
|
||||
|
||||
/* Check if the routing architecture we support*/
|
||||
if (UNI_DIRECTIONAL != vpr_setup.RoutingArch.directionality) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR, "FPGA synthesizable Verilog dumping only support uni-directional routing architecture!\n");
|
||||
|
@ -269,7 +274,7 @@ void vpr_fpga_verilog(t_vpr_setup vpr_setup,
|
|||
vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts.dump_explicit_verilog);
|
||||
|
||||
/* Dump internal structures of submodules */
|
||||
dump_verilog_submodules(sram_verilog_orgz_info, src_dir_path, submodule_dir_path,
|
||||
dump_verilog_submodules(module_manager, sram_verilog_orgz_info, src_dir_path, submodule_dir_path,
|
||||
Arch, &vpr_setup.RoutingArch,
|
||||
vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts);
|
||||
|
||||
|
@ -415,6 +420,8 @@ void vpr_fpga_verilog(t_vpr_setup vpr_setup,
|
|||
chomped_circuit_name,
|
||||
*(Arch.spice) );
|
||||
|
||||
vpr_printf(TIO_MESSAGE_INFO, "Outputted %lu Verilog modules in total.\n", module_manager.num_modules());
|
||||
|
||||
/* End time count */
|
||||
t_end = clock();
|
||||
|
||||
|
|
|
@ -803,9 +803,9 @@ void dump_compact_verilog_defined_one_switch_box(t_sram_orgz_info* cur_sram_orgz
|
|||
chan_coordinator.get_x(), chan_coordinator.get_y(), itrack,
|
||||
rr_sb.get_chan_node_direction(side_manager.get_side(), itrack)));
|
||||
if (true == is_explicit_mapping) {
|
||||
fprintf(fp, ")",itrack);
|
||||
fprintf(fp, ")");
|
||||
}
|
||||
fprintf(fp, ",\n",itrack);
|
||||
fprintf(fp, ",\n");
|
||||
}
|
||||
fprintf(fp, "//----- %s side inputs: CLB output pins -----\n", convert_side_index_to_string(side));
|
||||
/* Dump OPINs of adjacent CLBs */
|
||||
|
|
|
@ -0,0 +1,542 @@
|
|||
/************************************************
|
||||
* This file includes functions on
|
||||
* outputting Verilog netlists for essential gates
|
||||
* which are inverters, buffers, transmission-gates
|
||||
* logic gates etc.
|
||||
***********************************************/
|
||||
#include <fstream>
|
||||
#include "vtr_assert.h"
|
||||
|
||||
/* Device-level header files */
|
||||
#include "spice_types.h"
|
||||
#include "device_port.h"
|
||||
|
||||
/* FPGA-X2P context header files */
|
||||
#include "fpga_x2p_utils.h"
|
||||
#include "module_manager.h"
|
||||
#include "module_manager_utils.h"
|
||||
|
||||
/* FPGA-Verilog context header files */
|
||||
#include "verilog_global.h"
|
||||
#include "verilog_writer_utils.h"
|
||||
#include "verilog_submodule_utils.h"
|
||||
#include "verilog_essential_gates.h"
|
||||
|
||||
/************************************************
|
||||
* Print Verilog body codes of a power-gated inverter
|
||||
* This function does NOT generate any port map !
|
||||
***********************************************/
|
||||
static
|
||||
void print_verilog_power_gated_invbuf_body(std::fstream& fp,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const CircuitPortId& input_port,
|
||||
const CircuitPortId& output_port,
|
||||
const std::vector<CircuitPortId>& power_gate_ports) {
|
||||
/* Ensure a valid file handler*/
|
||||
check_file_handler(fp);
|
||||
|
||||
print_verilog_comment(fp, std::string("----- Verilog codes of a power-gated inverter -----"));
|
||||
|
||||
/* Create a sensitive list */
|
||||
fp << "\treg " << circuit_lib.port_lib_name(output_port) << "_reg;" << std::endl;
|
||||
|
||||
fp << "\talways @(" << std::endl;
|
||||
/* Power-gate port first*/
|
||||
for (const auto& power_gate_port : power_gate_ports) {
|
||||
/* Skip first comma to dump*/
|
||||
if (0 < &power_gate_port - &power_gate_ports[0]) {
|
||||
fp << ",";
|
||||
}
|
||||
fp << circuit_lib.port_lib_name(power_gate_port);
|
||||
}
|
||||
fp << circuit_lib.port_lib_name(input_port) << ") begin" << std::endl;
|
||||
|
||||
/* Dump the case of power-gated */
|
||||
fp << "\t\tif (";
|
||||
/* For the first pin, we skip output comma */
|
||||
size_t port_cnt = 0;
|
||||
for (const auto& power_gate_port : power_gate_ports) {
|
||||
for (const auto& power_gate_pin : circuit_lib.pins(power_gate_port)) {
|
||||
if (0 < port_cnt) {
|
||||
fp << std::endl << "\t\t&&";
|
||||
}
|
||||
fp << "(";
|
||||
|
||||
/* Power-gated signal are disable during operating, enabled during configuration,
|
||||
* Therefore, we need to reverse them here
|
||||
*/
|
||||
if (0 == circuit_lib.port_default_value(power_gate_port)) {
|
||||
fp << "~";
|
||||
}
|
||||
|
||||
fp << circuit_lib.port_lib_name(power_gate_port) << "[" << power_gate_pin << "])";
|
||||
|
||||
port_cnt++; /* Update port counter*/
|
||||
}
|
||||
}
|
||||
|
||||
fp << ") begin" << std::endl;
|
||||
fp << "\t\t\tassign " << circuit_lib.port_lib_name(output_port) << "_reg = ";
|
||||
|
||||
/* Branch on the type of inverter/buffer:
|
||||
* 1. If this is an inverter or an tapered(multi-stage) buffer with odd number of stages,
|
||||
* we invert the input to output
|
||||
* 2. If this is a buffer or an tapere(multi-stage) buffer with even number of stages,
|
||||
* we wire the input to output
|
||||
*/
|
||||
if ( (SPICE_MODEL_BUF_INV == circuit_lib.buffer_type(circuit_model))
|
||||
|| ( (SPICE_MODEL_BUF_BUF == circuit_lib.buffer_type(circuit_model))
|
||||
&& (size_t(-1) != circuit_lib.buffer_num_levels(circuit_model))
|
||||
&& (1 == circuit_lib.buffer_num_levels(circuit_model) % 2 ) ) ) {
|
||||
fp << "~";
|
||||
}
|
||||
|
||||
fp << circuit_lib.port_lib_name(input_port) << ";" << std::endl;
|
||||
fp << "\t\tend else begin" << std::endl;
|
||||
fp << "\t\t\tassign " << circuit_lib.port_lib_name(output_port) << "_reg = 1'bz;" << std::endl;
|
||||
fp << "\t\tend" << std::endl;
|
||||
fp << "\tend" << std::endl;
|
||||
fp << "\tassign " << circuit_lib.port_lib_name(output_port) << " = " << circuit_lib.port_lib_name(output_port) << "_reg;" << std::endl;
|
||||
}
|
||||
|
||||
/************************************************
|
||||
* Print Verilog body codes of a regular inverter
|
||||
* This function does NOT generate any port map !
|
||||
***********************************************/
|
||||
static
|
||||
void print_verilog_invbuf_body(std::fstream& fp,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const CircuitPortId& input_port,
|
||||
const CircuitPortId& output_port) {
|
||||
/* Ensure a valid file handler*/
|
||||
check_file_handler(fp);
|
||||
|
||||
print_verilog_comment(fp, std::string("----- Verilog codes of a regular inverter -----"));
|
||||
|
||||
fp << "\tassign " << circuit_lib.port_lib_name(output_port) << " = (" << circuit_lib.port_lib_name(input_port) << " === 1'bz)? $random : ";
|
||||
|
||||
/* Branch on the type of inverter/buffer:
|
||||
* 1. If this is an inverter or an tapered(multi-stage) buffer with odd number of stages,
|
||||
* we invert the input to output
|
||||
* 2. If this is a buffer or an tapere(multi-stage) buffer with even number of stages,
|
||||
* we wire the input to output
|
||||
*/
|
||||
if ( (SPICE_MODEL_BUF_INV == circuit_lib.buffer_type(circuit_model))
|
||||
|| ( (SPICE_MODEL_BUF_BUF == circuit_lib.buffer_type(circuit_model))
|
||||
&& (size_t(-1) != circuit_lib.buffer_num_levels(circuit_model))
|
||||
&& (1 == circuit_lib.buffer_num_levels(circuit_model) % 2 ) ) ) {
|
||||
fp << "~";
|
||||
}
|
||||
|
||||
fp << circuit_lib.port_lib_name(input_port) << ";" << std::endl;
|
||||
}
|
||||
|
||||
/************************************************
|
||||
* Print a Verilog module of inverter or buffer
|
||||
* or tapered buffer to a file
|
||||
***********************************************/
|
||||
static
|
||||
void print_verilog_invbuf_module(ModuleManager& module_manager,
|
||||
std::fstream& fp,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model) {
|
||||
/* Ensure a valid file handler*/
|
||||
check_file_handler(fp);
|
||||
|
||||
/* Find the input port, output port and global inputs*/
|
||||
std::vector<CircuitPortId> input_ports = circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_INPUT, true);
|
||||
std::vector<CircuitPortId> output_ports = circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_OUTPUT, true);
|
||||
std::vector<CircuitPortId> global_ports = circuit_lib.model_global_ports_by_type(circuit_model, SPICE_MODEL_PORT_INPUT, true);
|
||||
|
||||
/* Make sure:
|
||||
* There is only 1 input port and 1 output port,
|
||||
* each size of which is 1
|
||||
*/
|
||||
VTR_ASSERT( (1 == input_ports.size()) && (1 == circuit_lib.port_size(input_ports[0])) );
|
||||
VTR_ASSERT( (1 == output_ports.size()) && (1 == circuit_lib.port_size(output_ports[0])) );
|
||||
|
||||
/* TODO: move the check codes to check_circuit_library.h */
|
||||
/* If the circuit model is power-gated, we need to find at least one global config_enable signals */
|
||||
if (true == circuit_lib.is_power_gated(circuit_model)) {
|
||||
/* Check all the ports we have are good for a power-gated circuit model */
|
||||
size_t num_err = 0;
|
||||
/* We need at least one global port */
|
||||
if (0 == global_ports.size()) {
|
||||
num_err++;
|
||||
}
|
||||
/* All the global ports should be config_enable */
|
||||
for (const auto& port : global_ports) {
|
||||
if (false == circuit_lib.port_is_config_enable(port)) {
|
||||
num_err++;
|
||||
}
|
||||
}
|
||||
/* Report errors if there are any */
|
||||
if (0 < num_err) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"Inverter/buffer circuit model (name=%s) is power-gated. At least one config-enable global port is required!\n",
|
||||
circuit_lib.model_name(circuit_model).c_str());
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Create a Verilog Module based on the circuit model, and add to module manager */
|
||||
ModuleId module_id = add_circuit_model_to_module_manager(module_manager, circuit_lib, circuit_model);
|
||||
|
||||
/* dump module definition + ports */
|
||||
print_verilog_module_declaration(fp, module_manager, module_id);
|
||||
/* Finish dumping ports */
|
||||
|
||||
/* Assign logics : depending on topology */
|
||||
/* Error out for unsupported technology */
|
||||
if ( ( SPICE_MODEL_BUF_INV != circuit_lib.buffer_type(circuit_model))
|
||||
&& ( SPICE_MODEL_BUF_BUF != circuit_lib.buffer_type(circuit_model)) ) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s,[LINE%d])Invalid topology for circuit model (name=%s)!\n",
|
||||
__FILE__, __LINE__, circuit_lib.model_name(circuit_model).c_str());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (TRUE == circuit_lib.is_power_gated(circuit_model)) {
|
||||
/* Output Verilog codes for a power-gated inverter */
|
||||
print_verilog_power_gated_invbuf_body(fp, circuit_lib, circuit_model, input_ports[0], output_ports[0], global_ports);
|
||||
} else {
|
||||
/* Output Verilog codes for a regular inverter */
|
||||
print_verilog_invbuf_body(fp, circuit_lib, circuit_model, input_ports[0], output_ports[0]);
|
||||
}
|
||||
|
||||
/* Print timing info */
|
||||
print_verilog_submodule_timing(fp, circuit_lib, circuit_model);
|
||||
|
||||
/* Print signal initialization */
|
||||
print_verilog_submodule_signal_init(fp, circuit_lib, circuit_model);
|
||||
|
||||
/* Put an end to the Verilog module */
|
||||
print_verilog_module_end(fp, circuit_lib.model_name(circuit_model));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/************************************************
|
||||
* Print a Verilog module of a pass-gate,
|
||||
* either transmission-gate or pass-transistor
|
||||
***********************************************/
|
||||
static
|
||||
void print_verilog_passgate_module(ModuleManager& module_manager,
|
||||
std::fstream& fp,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model) {
|
||||
/* Ensure a valid file handler*/
|
||||
check_file_handler(fp);
|
||||
|
||||
/* Find the input port, output port*/
|
||||
std::vector<CircuitPortId> input_ports = circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_INPUT, true);
|
||||
std::vector<CircuitPortId> output_ports = circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_OUTPUT, true);
|
||||
std::vector<CircuitPortId> global_ports = circuit_lib.model_global_ports_by_type(circuit_model, SPICE_MODEL_PORT_INPUT, true);
|
||||
|
||||
switch (circuit_lib.pass_gate_logic_type(circuit_model)) {
|
||||
case SPICE_MODEL_PASS_GATE_TRANSMISSION:
|
||||
/* Make sure:
|
||||
* There is only 3 input port (in, sel, selb),
|
||||
* each size of which is 1
|
||||
*/
|
||||
VTR_ASSERT( 3 == input_ports.size() );
|
||||
for (const auto& input_port : input_ports) {
|
||||
VTR_ASSERT(1 == circuit_lib.port_size(input_port));
|
||||
}
|
||||
break;
|
||||
case SPICE_MODEL_PASS_GATE_TRANSISTOR:
|
||||
/* Make sure:
|
||||
* There is only 2 input port (in, sel),
|
||||
* each size of which is 1
|
||||
*/
|
||||
VTR_ASSERT( 2 == input_ports.size() );
|
||||
for (const auto& input_port : input_ports) {
|
||||
VTR_ASSERT(1 == circuit_lib.port_size(input_port));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s,[LINE%d])Invalid topology for circuit model (name=%s)!\n",
|
||||
__FILE__, __LINE__, circuit_lib.model_name(circuit_model).c_str());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Make sure:
|
||||
* There is only 1 output port,
|
||||
* each size of which is 1
|
||||
*/
|
||||
VTR_ASSERT( (1 == output_ports.size()) && (1 == circuit_lib.port_size(output_ports[0])) );
|
||||
|
||||
/* Create a Verilog Module based on the circuit model, and add to module manager */
|
||||
ModuleId module_id = add_circuit_model_to_module_manager(module_manager, circuit_lib, circuit_model);
|
||||
|
||||
/* dump module definition + ports */
|
||||
print_verilog_module_declaration(fp, module_manager, module_id);
|
||||
/* Finish dumping ports */
|
||||
|
||||
/* Dump logics: we propagate input to the output when the gate is '1'
|
||||
* the input is blocked from output when the gate is '0'
|
||||
*/
|
||||
fp << "\tassign " << circuit_lib.port_lib_name(output_ports[0]) << " = ";
|
||||
fp << circuit_lib.port_lib_name(input_ports[1]) << " ? " << circuit_lib.port_lib_name(input_ports[0]);
|
||||
fp << " : 1'bz;" << std::endl;
|
||||
|
||||
/* Print timing info */
|
||||
print_verilog_submodule_timing(fp, circuit_lib, circuit_model);
|
||||
|
||||
/* Print signal initialization */
|
||||
print_verilog_submodule_signal_init(fp, circuit_lib, circuit_model);
|
||||
|
||||
/* Put an end to the Verilog module */
|
||||
print_verilog_module_end(fp, circuit_lib.model_name(circuit_model));
|
||||
}
|
||||
|
||||
/************************************************
|
||||
* Print Verilog body codes of an N-input AND gate
|
||||
***********************************************/
|
||||
static
|
||||
void print_verilog_and_or_gate_body(std::fstream& fp,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const std::vector<CircuitPortId>& input_ports,
|
||||
const std::vector<CircuitPortId>& output_ports) {
|
||||
/* Ensure a valid file handler*/
|
||||
check_file_handler(fp);
|
||||
|
||||
/* Find the logic operator for the gate */
|
||||
std::string gate_verilog_operator;
|
||||
switch (circuit_lib.gate_type(circuit_model)) {
|
||||
case SPICE_MODEL_GATE_AND:
|
||||
gate_verilog_operator = "&";
|
||||
break;
|
||||
case SPICE_MODEL_GATE_OR:
|
||||
gate_verilog_operator = "|";
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s,[LINE%d])Invalid topology for circuit model (name=%s)!\n",
|
||||
__FILE__, __LINE__, circuit_lib.model_name(circuit_model).c_str());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Output verilog codes */
|
||||
print_verilog_comment(fp, std::string("----- Verilog codes of a " + std::to_string(input_ports.size()) + "-input " + std::to_string(output_ports.size()) + "-output AND gate -----"));
|
||||
|
||||
for (const auto& output_port : output_ports) {
|
||||
for (const auto& output_pin : circuit_lib.pins(output_port)) {
|
||||
BasicPort output_port_info(circuit_lib.port_lib_name(output_port), output_pin, output_pin);
|
||||
fp << "\tassign " << generate_verilog_port(VERILOG_PORT_CONKT, output_port_info);
|
||||
fp << " = ";
|
||||
|
||||
size_t port_cnt = 0;
|
||||
for (const auto& input_port : input_ports) {
|
||||
for (const auto& input_pin : circuit_lib.pins(input_port)) {
|
||||
/* Do not output AND/OR operator for the first element in the loop */
|
||||
if (0 < port_cnt) {
|
||||
fp << " " << gate_verilog_operator << " ";
|
||||
}
|
||||
|
||||
BasicPort input_port_info(circuit_lib.port_lib_name(input_port), input_pin, input_pin);
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, input_port_info);
|
||||
|
||||
/* Increment the counter for port */
|
||||
port_cnt++;
|
||||
}
|
||||
}
|
||||
fp << ";" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************
|
||||
* Print Verilog body codes of an 2-input MUX gate
|
||||
***********************************************/
|
||||
static
|
||||
void print_verilog_mux2_gate_body(std::fstream& fp,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const std::vector<CircuitPortId>& input_ports,
|
||||
const std::vector<CircuitPortId>& output_ports) {
|
||||
/* Ensure a valid file handler*/
|
||||
check_file_handler(fp);
|
||||
|
||||
/* TODO: Move the check codes to check_circuit_library.cpp */
|
||||
size_t num_err = 0;
|
||||
/* Check on the port sequence and map */
|
||||
/* MUX2 should only have 1 output port with size 1 */
|
||||
if (1 != output_ports.size()) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s, [LINE%d]) MUX2 circuit model (%s) must have only 1 output!\n",
|
||||
__FILE__, __LINE__, circuit_lib.model_name(circuit_model).c_str());
|
||||
num_err++;
|
||||
}
|
||||
for (const auto& output_port : output_ports) {
|
||||
/* Bypass port size of 1 */
|
||||
if (1 == circuit_lib.port_size(output_port)) {
|
||||
continue;
|
||||
}
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s, [LINE%d]) Output port size of a MUX2 circuit model (%s) must be 1!\n",
|
||||
__FILE__, __LINE__, circuit_lib.model_name(circuit_model).c_str());
|
||||
num_err++;
|
||||
}
|
||||
/* MUX2 should only have 3 output port, each of which has a port size of 1 */
|
||||
if (3 != input_ports.size()) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s, [LINE%d]) MUX2 circuit model (%s) must have only 3 input!\n",
|
||||
__FILE__, __LINE__, circuit_lib.model_name(circuit_model).c_str());
|
||||
num_err++;
|
||||
}
|
||||
|
||||
for (const auto& input_port : input_ports) {
|
||||
/* Bypass port size of 1 */
|
||||
if (1 == circuit_lib.port_size(input_port)) {
|
||||
continue;
|
||||
}
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s, [LINE%d]) Input size MUX2 circuit model (%s) must be 1!\n",
|
||||
__FILE__, __LINE__, circuit_lib.model_name(circuit_model).c_str());
|
||||
num_err++;
|
||||
}
|
||||
if (0 < num_err) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Now, we output the logic of MUX2
|
||||
* IMPORTANT Restriction:
|
||||
* We always assum the first two inputs are data inputs
|
||||
* the third input is the select port
|
||||
*/
|
||||
fp << "\tassign ";
|
||||
BasicPort out_port_info(circuit_lib.port_lib_name(output_ports[0]), 0, 0);
|
||||
BasicPort sel_port_info(circuit_lib.port_lib_name(input_ports[2]), 0, 0);
|
||||
BasicPort in0_port_info(circuit_lib.port_lib_name(input_ports[0]), 0, 0);
|
||||
BasicPort in1_port_info(circuit_lib.port_lib_name(input_ports[1]), 0, 0);
|
||||
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, out_port_info);
|
||||
fp << " = ";
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, sel_port_info);
|
||||
fp << " ? ";
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, in0_port_info);
|
||||
fp << " : ";
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, in1_port_info);
|
||||
fp << ";" << std::endl;
|
||||
}
|
||||
|
||||
/************************************************
|
||||
* Print a Verilog module of a logic gate
|
||||
* which are standard cells
|
||||
* Supported gate types:
|
||||
* 1. N-input AND
|
||||
* 2. N-input OR
|
||||
* 3. 2-input MUX
|
||||
***********************************************/
|
||||
static
|
||||
void print_verilog_gate_module(ModuleManager& module_manager,
|
||||
std::fstream& fp,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model) {
|
||||
/* Ensure a valid file handler*/
|
||||
check_file_handler(fp);
|
||||
|
||||
/* Find the input port, output port*/
|
||||
std::vector<CircuitPortId> input_ports = circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_INPUT, true);
|
||||
std::vector<CircuitPortId> output_ports = circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_OUTPUT, true);
|
||||
std::vector<CircuitPortId> global_ports = circuit_lib.model_global_ports_by_type(circuit_model, SPICE_MODEL_PORT_INPUT, true);
|
||||
|
||||
/* Make sure:
|
||||
* There is only 1 output port,
|
||||
* each size of which is 1
|
||||
*/
|
||||
VTR_ASSERT( (1 == output_ports.size()) && (1 == circuit_lib.port_size(output_ports[0])) );
|
||||
|
||||
/* Create a Verilog Module based on the circuit model, and add to module manager */
|
||||
ModuleId module_id = add_circuit_model_to_module_manager(module_manager, circuit_lib, circuit_model);
|
||||
|
||||
/* dump module definition + ports */
|
||||
print_verilog_module_declaration(fp, module_manager, module_id);
|
||||
/* Finish dumping ports */
|
||||
|
||||
/* Dump logics */
|
||||
switch (circuit_lib.gate_type(circuit_model)) {
|
||||
case SPICE_MODEL_GATE_AND:
|
||||
case SPICE_MODEL_GATE_OR:
|
||||
print_verilog_and_or_gate_body(fp, circuit_lib, circuit_model, input_ports, output_ports);
|
||||
break;
|
||||
case SPICE_MODEL_GATE_MUX2:
|
||||
print_verilog_mux2_gate_body(fp, circuit_lib, circuit_model, input_ports, output_ports);
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s,[LINE%d])Invalid topology for circuit model (name=%s)!\n",
|
||||
__FILE__, __LINE__, circuit_lib.model_name(circuit_model).c_str());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Print timing info */
|
||||
print_verilog_submodule_timing(fp, circuit_lib, circuit_model);
|
||||
|
||||
/* Print signal initialization */
|
||||
print_verilog_submodule_signal_init(fp, circuit_lib, circuit_model);
|
||||
|
||||
/* Put an end to the Verilog module */
|
||||
print_verilog_module_end(fp, circuit_lib.model_name(circuit_model));
|
||||
}
|
||||
|
||||
/************************************************
|
||||
* Generate the Verilog netlist for essential gates
|
||||
* include inverters, buffers, transmission-gates,
|
||||
* etc.
|
||||
***********************************************/
|
||||
void print_verilog_submodule_essentials(ModuleManager& module_manager,
|
||||
const std::string& verilog_dir,
|
||||
const std::string& submodule_dir,
|
||||
const CircuitLibrary& circuit_lib) {
|
||||
/* TODO: remove .bak when this part is completed and tested */
|
||||
std::string verilog_fname = submodule_dir + essentials_verilog_file_name;
|
||||
|
||||
std::fstream fp;
|
||||
|
||||
/* Create the file stream */
|
||||
fp.open(verilog_fname, std::fstream::out | std::fstream::trunc);
|
||||
/* Check if the file stream if valid or not */
|
||||
check_file_handler(fp);
|
||||
|
||||
/* Create file */
|
||||
vpr_printf(TIO_MESSAGE_INFO,
|
||||
"Generating Verilog netlist (%s) for essential gates...\n",
|
||||
__FILE__, __LINE__, essentials_verilog_file_name);
|
||||
|
||||
print_verilog_file_header(fp, "Essential gates");
|
||||
|
||||
print_verilog_include_defines_preproc_file(fp, verilog_dir);
|
||||
|
||||
for (const auto& circuit_model : circuit_lib.models()) {
|
||||
/* By pass user-defined modules */
|
||||
if (!circuit_lib.model_verilog_netlist(circuit_model).empty()) {
|
||||
continue;
|
||||
}
|
||||
if (SPICE_MODEL_INVBUF == circuit_lib.model_type(circuit_model)) {
|
||||
print_verilog_invbuf_module(module_manager, fp, circuit_lib, circuit_model);
|
||||
continue;
|
||||
}
|
||||
if (SPICE_MODEL_PASSGATE == circuit_lib.model_type(circuit_model)) {
|
||||
print_verilog_passgate_module(module_manager, fp, circuit_lib, circuit_model);
|
||||
continue;
|
||||
}
|
||||
if (SPICE_MODEL_GATE == circuit_lib.model_type(circuit_model)) {
|
||||
print_verilog_gate_module(module_manager, fp, circuit_lib, circuit_model);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Close file handler*/
|
||||
fp.close();
|
||||
|
||||
/* Add fname to the linked list */
|
||||
submodule_verilog_subckt_file_path_head = add_one_subckt_file_name_to_llist(submodule_verilog_subckt_file_path_head, verilog_fname.c_str());
|
||||
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/************************************************
|
||||
* Header file for verilog_submodule_essential.cpp
|
||||
* Include function declaration on
|
||||
* outputting Verilog netlists for essential gates
|
||||
* which are inverters, buffers, transmission-gates
|
||||
* logic gates etc.
|
||||
***********************************************/
|
||||
|
||||
#ifndef VERILOG_ESSENTIAL_GATES_H
|
||||
#define VERILOG_ESSENTIAL_GATES_H
|
||||
|
||||
#include <string>
|
||||
#include "circuit_library.h"
|
||||
|
||||
void print_verilog_submodule_essentials(ModuleManager& module_manager,
|
||||
const std::string& verilog_dir,
|
||||
const std::string& submodule_dir,
|
||||
const CircuitLibrary& circuit_lib);
|
||||
|
||||
#endif
|
|
@ -1,3 +1,5 @@
|
|||
#ifndef VERILOG_GLOBAL_H
|
||||
#define VERILOG_GLOBAL_H
|
||||
/* global parameters for dumping synthesizable verilog */
|
||||
|
||||
extern char* verilog_netlist_file_postfix;
|
||||
|
@ -140,8 +142,10 @@ VERILOG_PORT_OUTPUT,
|
|||
VERILOG_PORT_INOUT,
|
||||
VERILOG_PORT_WIRE,
|
||||
VERILOG_PORT_REG,
|
||||
VERILOG_PORT_CONKT
|
||||
VERILOG_PORT_CONKT,
|
||||
NUM_VERILOG_PORT_TYPES
|
||||
};
|
||||
constexpr std::array<const char*, NUM_VERILOG_PORT_TYPES> VERILOG_PORT_TYPE_STRING = {{"input", "output", "inout", "wire", "reg", ""}}; /* string version of enum e_verilog_port_type */
|
||||
|
||||
enum e_verilog_tb_type {
|
||||
VERILOG_TB_TOP,
|
||||
|
@ -149,3 +153,5 @@ VERILOG_TB_BLIF_TOP,
|
|||
VERILOG_TB_AUTOCHECK_TOP,
|
||||
VERILOG_TB_FORMAL_VERIFICATION
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,224 @@
|
|||
/***********************************************
|
||||
* This file includes functions to generate
|
||||
* Verilog submodules for multiplexers.
|
||||
* including both fundamental submodules
|
||||
* such as a branch in a multiplexer
|
||||
* and the full multiplexer
|
||||
**********************************************/
|
||||
#include <string>
|
||||
|
||||
#include "util.h"
|
||||
#include "vtr_assert.h"
|
||||
|
||||
/* Device-level header files */
|
||||
#include "mux_graph.h"
|
||||
#include "physical_types.h"
|
||||
#include "vpr_types.h"
|
||||
|
||||
/* FPGA-X2P context header files */
|
||||
#include "spice_types.h"
|
||||
#include "fpga_x2p_naming.h"
|
||||
#include "fpga_x2p_utils.h"
|
||||
|
||||
/* FPGA-Verilog context header files */
|
||||
#include "verilog_global.h"
|
||||
#include "verilog_writer_utils.h"
|
||||
#include "verilog_mux.h"
|
||||
|
||||
/***********************************************
|
||||
* Generate Verilog codes modeling an branch circuit
|
||||
* for a multiplexer with the given size
|
||||
**********************************************/
|
||||
static
|
||||
void generate_verilog_cmos_mux_branch_module_structural(std::fstream& fp,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const std::string& module_name,
|
||||
const MuxGraph& mux_graph) {
|
||||
/* Get the tgate model */
|
||||
CircuitModelId tgate_model = circuit_lib.pass_gate_logic_model(circuit_model);
|
||||
|
||||
/* Skip output if the tgate model is a MUX2, it is handled by essential-gate generator */
|
||||
if (SPICE_MODEL_GATE == circuit_lib.model_type(tgate_model)) {
|
||||
VTR_ASSERT(SPICE_MODEL_GATE_MUX2 == circuit_lib.gate_type(tgate_model));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get model ports of tgate */
|
||||
std::vector<CircuitPortId> tgate_input_ports = circuit_lib.model_ports_by_type(tgate_model, SPICE_MODEL_PORT_INPUT, true);
|
||||
std::vector<CircuitPortId> tgate_output_ports = circuit_lib.model_ports_by_type(tgate_model, SPICE_MODEL_PORT_OUTPUT, true);
|
||||
std::vector<CircuitPortId> tgate_global_ports = circuit_lib.model_global_ports_by_type(tgate_model, SPICE_MODEL_PORT_INPUT, true);
|
||||
VTR_ASSERT(3 == tgate_input_ports.size());
|
||||
VTR_ASSERT(1 == tgate_output_ports.size());
|
||||
|
||||
/* Make sure we have a valid file handler*/
|
||||
check_file_handler(fp);
|
||||
|
||||
/* Generate the Verilog netlist according to the mux_graph */
|
||||
/* Find out the number of inputs */
|
||||
size_t num_inputs = mux_graph.num_inputs();
|
||||
/* Find out the number of outputs */
|
||||
size_t num_outputs = mux_graph.num_outputs();
|
||||
/* Find out the number of memory bits */
|
||||
size_t num_mems = mux_graph.num_memory_bits();
|
||||
|
||||
/* Check codes to ensure the port of Verilog netlists will match */
|
||||
/* MUX graph must have only 1 output */
|
||||
VTR_ASSERT(1 == num_outputs);
|
||||
/* MUX graph must have only 1 level*/
|
||||
VTR_ASSERT(1 == mux_graph.num_levels());
|
||||
|
||||
/* Print Verilog module */
|
||||
print_verilog_module_definition(fp, module_name);
|
||||
|
||||
/* Create port information */
|
||||
/* Configure each input port */
|
||||
BasicPort input_port("in", num_inputs);
|
||||
|
||||
/* Configure each output port */
|
||||
BasicPort output_port("out", num_outputs);
|
||||
|
||||
/* Configure each memory port */
|
||||
BasicPort mem_port("mem", num_mems);
|
||||
BasicPort mem_inv_port("mem_inv", num_mems);
|
||||
|
||||
/* TODO: Generate global ports */
|
||||
for (const auto& port : tgate_global_ports) {
|
||||
/* Configure each global port */
|
||||
BasicPort basic_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port));
|
||||
/* Print port */
|
||||
fp << "\t" << generate_verilog_port(VERILOG_PORT_INPUT, basic_port) << "," << std::endl;
|
||||
}
|
||||
|
||||
/* TODO: add a module to the Module Manager */
|
||||
|
||||
/* Port list */
|
||||
fp << "\t" << generate_verilog_port(VERILOG_PORT_INPUT, input_port) << "," << std::endl;
|
||||
fp << "\t" << generate_verilog_port(VERILOG_PORT_OUTPUT, output_port) << "," << std::endl;
|
||||
fp << "\t" << generate_verilog_port(VERILOG_PORT_INPUT, mem_port) << "," << std::endl;
|
||||
fp << "\t" << generate_verilog_port(VERILOG_PORT_INPUT, mem_inv_port) << std::endl;
|
||||
fp << ");" << std::endl;
|
||||
|
||||
/* Verilog Behavior description for a MUX */
|
||||
print_verilog_comment(fp, std::string("---- Structure-level description -----"));
|
||||
/* Special case: only one memory, switch case is simpler
|
||||
* When mem = 1, propagate input 0;
|
||||
* when mem = 0, propagate input 1;
|
||||
*/
|
||||
/* TODO: we should output the netlist following the connections in mux_graph */
|
||||
if (1 == num_mems) {
|
||||
/* Transmission gates are connected to each input and also the output*/
|
||||
fp << "\t" << circuit_lib.model_name(tgate_model) << " " << circuit_lib.model_prefix(tgate_model) << "_0 ";
|
||||
/* Dump explicit port map if required */
|
||||
/* TODO: add global port support for tgate model */
|
||||
if (true == circuit_lib.dump_explicit_port_map(tgate_model)) {
|
||||
fp << " (";
|
||||
fp << " ." << circuit_lib.port_lib_name(tgate_input_ports[0]) << "(" << "in[0]" << "),";
|
||||
fp << " ." << circuit_lib.port_lib_name(tgate_input_ports[1]) << "(" << generate_verilog_port(VERILOG_PORT_CONKT, mem_port) << "),";
|
||||
fp << " ." << circuit_lib.port_lib_name(tgate_input_ports[2]) << "(" << generate_verilog_port(VERILOG_PORT_CONKT, mem_inv_port) << "),";
|
||||
fp << " ." << circuit_lib.port_lib_name(tgate_output_ports[0]) << "(" << generate_verilog_port(VERILOG_PORT_CONKT, output_port) << ")";
|
||||
fp << ");" << std::endl;
|
||||
} else {
|
||||
fp << " (";
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, input_port);
|
||||
fp << ", " << generate_verilog_port(VERILOG_PORT_CONKT, mem_port);
|
||||
fp << ", " << generate_verilog_port(VERILOG_PORT_CONKT, mem_inv_port);
|
||||
fp << ", " << generate_verilog_port(VERILOG_PORT_CONKT, output_port);
|
||||
fp << ");" << std::endl;
|
||||
}
|
||||
/* Transmission gates are connected to each input and also the output*/
|
||||
fp << "\t" << circuit_lib.model_name(tgate_model) << " " << circuit_lib.model_prefix(tgate_model) << "_1 ";
|
||||
/* Dump explicit port map if required */
|
||||
if (true == circuit_lib.dump_explicit_port_map(tgate_model)) {
|
||||
fp << " (";
|
||||
fp << " ." << circuit_lib.port_lib_name(tgate_input_ports[0]) << "(" << "in[1]" << "),";
|
||||
fp << " ." << circuit_lib.port_lib_name(tgate_input_ports[1]) << "(" << generate_verilog_port(VERILOG_PORT_CONKT, mem_inv_port) << "),";
|
||||
fp << " ." << circuit_lib.port_lib_name(tgate_input_ports[2]) << "(" << generate_verilog_port(VERILOG_PORT_CONKT, mem_port) << "),";
|
||||
fp << " ." << circuit_lib.port_lib_name(tgate_output_ports[0]) << "(" << generate_verilog_port(VERILOG_PORT_CONKT, output_port) << ")";
|
||||
fp << ");" << std::endl;
|
||||
} else {
|
||||
fp << " (";
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, input_port);
|
||||
fp << ", " << generate_verilog_port(VERILOG_PORT_CONKT, mem_inv_port);
|
||||
fp << ", " << generate_verilog_port(VERILOG_PORT_CONKT, mem_port);
|
||||
fp << ", " << generate_verilog_port(VERILOG_PORT_CONKT, output_port);
|
||||
fp << ");" << std::endl;
|
||||
}
|
||||
} else {
|
||||
/* Other cases, we need to follow the rules:
|
||||
* When mem[k] is enabled, switch on input[k]
|
||||
* Only one memory bit is enabled!
|
||||
*/
|
||||
for (size_t i = 0; i < num_mems; i++) {
|
||||
fp << "\t" << circuit_lib.model_name(tgate_model) << " " << circuit_lib.model_prefix(tgate_model) << "_" << i << " ";
|
||||
if (true == circuit_lib.dump_explicit_port_map(tgate_model)) {
|
||||
fp << " (";
|
||||
fp << " ." << circuit_lib.port_lib_name(tgate_input_ports[0]) << "(" << "in[" << i << "]" << "),";
|
||||
fp << " ." << circuit_lib.port_lib_name(tgate_input_ports[1]) << "(" << "mem[" << i << "]" << "),";
|
||||
fp << " ." << circuit_lib.port_lib_name(tgate_input_ports[2]) << "(" << "mem_inv[" << i << "]" << "),";
|
||||
fp << " ." << circuit_lib.port_lib_name(tgate_output_ports[0]) << "(" << generate_verilog_port(VERILOG_PORT_CONKT, output_port) << ")";
|
||||
fp << ");" << std::endl;
|
||||
} else {
|
||||
fp << " (";
|
||||
fp << "in[" << i << "]";
|
||||
fp << ", " << "mem[" << i << "]";
|
||||
fp << ", " << "mem_inv[" << i << "]";
|
||||
fp << ", " << generate_verilog_port(VERILOG_PORT_CONKT, output_port);
|
||||
fp << ");" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Put an end to the Verilog module */
|
||||
print_verilog_module_end(fp, module_name);
|
||||
}
|
||||
|
||||
/***********************************************
|
||||
* Generate Verilog codes modeling an branch circuit
|
||||
* for a multiplexer with the given size
|
||||
**********************************************/
|
||||
void generate_verilog_mux_branch_module(std::fstream& fp,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const size_t& mux_size,
|
||||
const MuxGraph& mux_graph) {
|
||||
std::string module_name = generate_verilog_mux_branch_subckt_name(circuit_lib, circuit_model, mux_size, verilog_mux_basis_posfix);
|
||||
|
||||
/* Multiplexers built with different technology is in different organization */
|
||||
switch (circuit_lib.design_tech_type(circuit_model)) {
|
||||
case SPICE_MODEL_DESIGN_CMOS:
|
||||
if (true == circuit_lib.dump_structural_verilog(circuit_model)) {
|
||||
generate_verilog_cmos_mux_branch_module_structural(fp, circuit_lib, circuit_model, module_name, mux_graph);
|
||||
} else {
|
||||
/*
|
||||
dump_verilog_cmos_mux_one_basis_module(fp, mux_basis_subckt_name,
|
||||
mux_size,
|
||||
num_input_basis_subckt,
|
||||
cur_spice_model,
|
||||
special_basis);
|
||||
*/
|
||||
}
|
||||
break;
|
||||
case SPICE_MODEL_DESIGN_RRAM:
|
||||
/* If requested, we can dump structural verilog for basis module */
|
||||
/*
|
||||
if (true == circuit_lib.dump_structural_verilog(circuit_model)) {
|
||||
dump_verilog_rram_mux_one_basis_module_structural(fp, mux_basis_subckt_name,
|
||||
num_input_basis_subckt,
|
||||
cur_spice_model);
|
||||
} else {
|
||||
dump_verilog_rram_mux_one_basis_module(fp, mux_basis_subckt_name,
|
||||
num_input_basis_subckt,
|
||||
cur_spice_model);
|
||||
}
|
||||
*/
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(FILE:%s,LINE[%d]) Invalid design technology of multiplexer (name: %s)\n",
|
||||
__FILE__, __LINE__, circuit_lib.model_name(circuit_model).c_str());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/***********************************************
|
||||
* Header file for verilog_submodule_mux.cpp
|
||||
**********************************************/
|
||||
|
||||
#ifndef VERILOG_MUX_H
|
||||
#define VERILOG_MUX_H
|
||||
|
||||
/* Include other header files which are dependency on the function declared below */
|
||||
#include <fstream>
|
||||
|
||||
#include "circuit_library.h"
|
||||
#include "mux_graph.h"
|
||||
#include "mux_library.h"
|
||||
|
||||
void generate_verilog_mux_branch_module(std::fstream& fp,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model,
|
||||
const size_t& mux_size,
|
||||
const MuxGraph& mux_graph);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,121 @@
|
|||
/************************************************
|
||||
* This file includes most utilized functions for
|
||||
* generating Verilog sub-modules
|
||||
* such as timing matrix and signal initialization
|
||||
***********************************************/
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
#include <iomanip>
|
||||
#include "vtr_assert.h"
|
||||
|
||||
/* Device-level header files */
|
||||
#include "spice_types.h"
|
||||
#include "device_port.h"
|
||||
|
||||
/* FPGA-X2P context header files */
|
||||
#include "fpga_x2p_utils.h"
|
||||
|
||||
/* FPGA-Verilog context header files */
|
||||
#include "verilog_global.h"
|
||||
#include "verilog_writer_utils.h"
|
||||
#include "verilog_submodule_utils.h"
|
||||
|
||||
/* All values are printed with this precision value. The higher the
|
||||
* value, the more accurate timing assignment is. Using a number of 6
|
||||
* guarentees that a precision of femtosecond which is sufficent for
|
||||
* electrical simulation (simulation timescale is 10-9
|
||||
*/
|
||||
/* constexpr int FLOAT_PRECISION = std::numeric_limits<float>::max_digits10; */
|
||||
constexpr int FLOAT_PRECISION = 6;
|
||||
|
||||
/************************************************
|
||||
* Print a timing matrix defined in theecircuit model
|
||||
* into a Verilog format.
|
||||
* This function print all the timing edges available
|
||||
* in the circuit model (any pin-to-pin delay)
|
||||
***********************************************/
|
||||
void print_verilog_submodule_timing(std::fstream& fp,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model) {
|
||||
/* return if there is no delay info */
|
||||
if ( 0 == circuit_lib.num_delay_info(circuit_model)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Return if there is no ports */
|
||||
if (0 == circuit_lib.num_model_ports(circuit_model)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Ensure a valid file handler*/
|
||||
check_file_handler(fp);
|
||||
|
||||
fp << std::endl;
|
||||
fp << "`ifdef " << verilog_timing_preproc_flag << std::endl;
|
||||
print_verilog_comment(fp, std::string("------ BEGIN Pin-to-pin Timing constraints -----"));
|
||||
fp << "\tspecify" << std::endl;
|
||||
|
||||
/* Read out pin-to-pin delays by finding out all the edges belonging to a circuit model */
|
||||
for (const auto& timing_edge : circuit_lib.timing_edges_by_model(circuit_model)) {
|
||||
CircuitPortId src_port = circuit_lib.timing_edge_src_port(timing_edge);
|
||||
size_t src_pin = circuit_lib.timing_edge_src_pin(timing_edge);
|
||||
BasicPort src_port_info(circuit_lib.port_lib_name(src_port), src_pin, src_pin);
|
||||
|
||||
CircuitPortId sink_port = circuit_lib.timing_edge_sink_port(timing_edge);
|
||||
size_t sink_pin = circuit_lib.timing_edge_sink_pin(timing_edge);
|
||||
BasicPort sink_port_info(circuit_lib.port_lib_name(sink_port), sink_pin, sink_pin);
|
||||
|
||||
fp << "\t\t";
|
||||
fp << "(" << generate_verilog_port(VERILOG_PORT_CONKT, src_port_info);
|
||||
fp << " => ";
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, sink_port_info) << ")";
|
||||
fp << " = ";
|
||||
fp << "(" << std::setprecision(FLOAT_PRECISION) << circuit_lib.timing_edge_delay(timing_edge, SPICE_MODEL_DELAY_RISE) / verilog_sim_timescale;
|
||||
fp << ", ";
|
||||
fp << std::setprecision(FLOAT_PRECISION) << circuit_lib.timing_edge_delay(timing_edge, SPICE_MODEL_DELAY_FALL) / verilog_sim_timescale << ")";
|
||||
fp << ";" << std::endl;
|
||||
}
|
||||
|
||||
fp << "\tendspecify" << std::endl;
|
||||
print_verilog_comment(fp, std::string("------ END Pin-to-pin Timing constraints -----"));
|
||||
fp << "`endif" << std::endl;
|
||||
|
||||
}
|
||||
|
||||
void print_verilog_submodule_signal_init(std::fstream& fp,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model) {
|
||||
/* Ensure a valid file handler*/
|
||||
check_file_handler(fp);
|
||||
|
||||
fp << std::endl;
|
||||
fp << "`ifdef " << verilog_signal_init_preproc_flag << std::endl;
|
||||
print_verilog_comment(fp, std::string("------ BEGIN driver initialization -----"));
|
||||
fp << "\tinitial begin" << std::endl;
|
||||
fp << "\t`ifdef " << verilog_formal_verification_preproc_flag << std::endl;
|
||||
|
||||
/* Only for formal verification: deposite a zero signal values */
|
||||
/* Initialize each input port */
|
||||
for (const auto& input_port : circuit_lib.model_input_ports(circuit_model)) {
|
||||
BasicPort input_port_info(circuit_lib.port_lib_name(input_port), circuit_lib.port_size(input_port));
|
||||
fp << "\t\t$deposit(";
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, input_port_info);
|
||||
fp << ", " << circuit_lib.port_size(input_port) << "'b" << std::string(circuit_lib.port_size(input_port), '0');
|
||||
fp << ");" << std::endl;
|
||||
}
|
||||
fp << "\t`else" << std::endl;
|
||||
|
||||
/* Regular case: deposite initial signal values: a random value */
|
||||
for (const auto& input_port : circuit_lib.model_input_ports(circuit_model)) {
|
||||
BasicPort input_port_info(circuit_lib.port_lib_name(input_port), circuit_lib.port_size(input_port));
|
||||
fp << "\t\t$deposit(";
|
||||
fp << generate_verilog_port(VERILOG_PORT_CONKT, input_port_info);
|
||||
fp << ", $random);" << std::endl;
|
||||
}
|
||||
|
||||
fp << "\t`endif\n" << std::endl;
|
||||
fp << "\tend" << std::endl;
|
||||
print_verilog_comment(fp, std::string("------ END driver initialization -----"));
|
||||
fp << "`endif" << std::endl;
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
/************************************************
|
||||
* Header file for verilog_submodule_utils.cpp
|
||||
* Include function declaration on
|
||||
* most utilized functions for Verilog modules
|
||||
* such as timing matrix and signal initialization
|
||||
***********************************************/
|
||||
|
||||
#ifndef VERILOG_SUBMODULE_UTILS_H
|
||||
#define VERILOG_SUBMODULE_UTILS_H
|
||||
|
||||
#include <fstream>
|
||||
|
||||
void print_verilog_submodule_timing(std::fstream& fp,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model);
|
||||
|
||||
void print_verilog_submodule_signal_init(std::fstream& fp,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model);
|
||||
|
||||
#endif
|
|
@ -38,6 +38,10 @@
|
|||
|
||||
#include "verilog_submodules.h"
|
||||
|
||||
#include "mux_utils.h"
|
||||
#include "verilog_mux.h"
|
||||
#include "verilog_essential_gates.h"
|
||||
|
||||
/***** Subroutines *****/
|
||||
|
||||
static
|
||||
|
@ -128,544 +132,6 @@ void dump_verilog_submodule_signal_init(FILE* fp,
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Dump a module of inverter or buffer or tapered buffer */
|
||||
static
|
||||
void dump_verilog_invbuf_module(FILE* fp,
|
||||
t_spice_model* invbuf_spice_model) {
|
||||
int ipin, iport, port_cnt;
|
||||
int num_input_port = 0;
|
||||
int num_output_port = 0;
|
||||
int num_powergate_port = 0;
|
||||
t_spice_model_port** input_port = NULL;
|
||||
t_spice_model_port** output_port = NULL;
|
||||
t_spice_model_port** powergate_port = NULL;
|
||||
|
||||
/* Ensure a valid file handler*/
|
||||
if (NULL == fp) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid File handler.\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fprintf(fp, "//----- Verilog module for %s -----\n",
|
||||
invbuf_spice_model->name);
|
||||
|
||||
/* Find the input port, output port*/
|
||||
input_port = find_spice_model_ports(invbuf_spice_model, SPICE_MODEL_PORT_INPUT, &num_input_port, TRUE);
|
||||
output_port = find_spice_model_ports(invbuf_spice_model, SPICE_MODEL_PORT_OUTPUT, &num_output_port, TRUE);
|
||||
powergate_port = find_spice_model_config_done_ports(invbuf_spice_model, SPICE_MODEL_PORT_INPUT, &num_powergate_port, FALSE);
|
||||
|
||||
/* Make sure:
|
||||
* There is only 1 input port and 1 output port,
|
||||
* each size of which is 1
|
||||
*/
|
||||
assert(1 == num_input_port);
|
||||
assert(1 == input_port[0]->size);
|
||||
assert(1 == num_output_port);
|
||||
assert(1 == output_port[0]->size);
|
||||
|
||||
/* If power-gated, we need to find enable signals */
|
||||
if (TRUE == invbuf_spice_model->design_tech_info.power_gated) {
|
||||
if (0 == num_powergate_port) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Inverter, buffer SPICE model is power-gated, but cannot find any power-gate port!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
assert ( 0 < num_powergate_port);
|
||||
}
|
||||
|
||||
/* dump module body */
|
||||
fprintf(fp, "module %s (\n",
|
||||
invbuf_spice_model->name);
|
||||
/* Dump global ports */
|
||||
if (0 < rec_dump_verilog_spice_model_lib_global_ports(fp, invbuf_spice_model, TRUE, FALSE, FALSE)) {
|
||||
fprintf(fp, ",\n");
|
||||
}
|
||||
/* Dump ports */
|
||||
fprintf(fp, "input [0:0] %s,\n", input_port[0]->lib_name);
|
||||
fprintf(fp, "output [0:0] %s\n", output_port[0]->lib_name);
|
||||
fprintf(fp, ");\n");
|
||||
/* Finish dumping ports */
|
||||
|
||||
/* Assign logics : depending on topology */
|
||||
switch (invbuf_spice_model->design_tech_info.buffer_info->type) {
|
||||
case SPICE_MODEL_BUF_INV:
|
||||
if (TRUE == invbuf_spice_model->design_tech_info.power_gated) {
|
||||
/* Create a sensitive list */
|
||||
fprintf(fp, "reg %s_reg;\n", output_port[0]->lib_name);
|
||||
fprintf(fp, "always @(");
|
||||
/* Power-gate port first*/
|
||||
for (iport = 0; iport < num_powergate_port; iport++) {
|
||||
fprintf(fp, "%s,", powergate_port[iport]->lib_name);
|
||||
}
|
||||
fprintf(fp, "%s) begin\n",
|
||||
input_port[0]->lib_name);
|
||||
/* Dump the case of power-gated */
|
||||
fprintf(fp, " if (");
|
||||
port_cnt = 0; /* Initialize the counter: decide if we need to put down '&&' */
|
||||
for (iport = 0; iport < num_powergate_port; iport++) {
|
||||
if (0 == powergate_port[iport]->default_val) {
|
||||
for (ipin = 0; ipin < powergate_port[iport]->size; ipin++) {
|
||||
if ( 0 < port_cnt ) {
|
||||
fprintf(fp, "\n\t&&");
|
||||
}
|
||||
/* Power-gated signal are disable during operating, enabled during configuration,
|
||||
* Therefore, we need to reverse them here
|
||||
*/
|
||||
fprintf(fp, "(~%s[%d])",
|
||||
powergate_port[iport]->lib_name,
|
||||
ipin);
|
||||
port_cnt++; /* Update port counter*/
|
||||
}
|
||||
} else {
|
||||
assert (1 == powergate_port[iport]->default_val);
|
||||
for (ipin = 0; ipin < powergate_port[iport]->size; ipin++) {
|
||||
if ( 0 < port_cnt ) {
|
||||
fprintf(fp, "\n\t&&");
|
||||
}
|
||||
/* Power-gated signal are disable during operating, enabled during configuration,
|
||||
* Therefore, we need to reverse them here
|
||||
*/
|
||||
fprintf(fp, "(%s[%d])",
|
||||
powergate_port[iport]->lib_name,
|
||||
ipin);
|
||||
port_cnt++; /* Update port counter*/
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf(fp, ") begin\n");
|
||||
fprintf(fp, "\t\tassign %s_reg = ~%s;\n",
|
||||
output_port[0]->lib_name,
|
||||
input_port[0]->lib_name);
|
||||
fprintf(fp, "\tend else begin\n");
|
||||
fprintf(fp, "\t\tassign %s_reg = 1'bz;\n",
|
||||
output_port[0]->lib_name);
|
||||
fprintf(fp, "\tend\n");
|
||||
fprintf(fp, "end\n");
|
||||
fprintf(fp, "assign %s = %s_reg;\n",
|
||||
output_port[0]->lib_name,
|
||||
output_port[0]->lib_name);
|
||||
} else {
|
||||
fprintf(fp, "assign %s = (%s === 1'bz)? $random : ~%s;\n",
|
||||
output_port[0]->lib_name,
|
||||
input_port[0]->lib_name,
|
||||
input_port[0]->lib_name);
|
||||
}
|
||||
break;
|
||||
case SPICE_MODEL_BUF_BUF:
|
||||
if (TRUE == invbuf_spice_model->design_tech_info.power_gated) {
|
||||
/* Create a sensitive list */
|
||||
fprintf(fp, "reg %s_reg;\n", output_port[0]->lib_name);
|
||||
fprintf(fp, "always @(");
|
||||
/* Power-gate port first*/
|
||||
for (iport = 0; iport < num_powergate_port; iport++) {
|
||||
fprintf(fp, "%s,", powergate_port[iport]->lib_name);
|
||||
}
|
||||
fprintf(fp, "%s) begin\n",
|
||||
input_port[0]->lib_name);
|
||||
/* Dump the case of power-gated */
|
||||
fprintf(fp, " if (");
|
||||
port_cnt = 0; /* Initialize the counter: decide if we need to put down '&&' */
|
||||
for (iport = 0; iport < num_powergate_port; iport++) {
|
||||
if (0 == powergate_port[iport]->default_val) {
|
||||
for (ipin = 0; ipin < powergate_port[iport]->size; ipin++) {
|
||||
if ( 0 < port_cnt ) {
|
||||
fprintf(fp, "\n\t&&");
|
||||
}
|
||||
/* Power-gated signal are disable during operating, enabled during configuration,
|
||||
* Therefore, we need to reverse them here
|
||||
*/
|
||||
fprintf(fp, "(~%s[%d])",
|
||||
powergate_port[iport]->lib_name,
|
||||
ipin);
|
||||
port_cnt++; /* Update port counter*/
|
||||
}
|
||||
} else {
|
||||
assert (1 == powergate_port[iport]->default_val);
|
||||
for (ipin = 0; ipin < powergate_port[iport]->size; ipin++) {
|
||||
if ( 0 < port_cnt ) {
|
||||
fprintf(fp, "\n\t&&");
|
||||
}
|
||||
/* Power-gated signal are disable during operating, enabled during configuration,
|
||||
* Therefore, we need to reverse them here
|
||||
*/
|
||||
fprintf(fp, "(%s[%d])",
|
||||
powergate_port[iport]->lib_name,
|
||||
ipin);
|
||||
port_cnt++; /* Update port counter*/
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf(fp, ") begin\n");
|
||||
fprintf(fp, "\t\tassign %s_reg = %s;\n",
|
||||
output_port[0]->lib_name,
|
||||
input_port[0]->lib_name);
|
||||
fprintf(fp, "\tend else begin\n");
|
||||
fprintf(fp, "\t\tassign %s_reg = 1'bz;\n",
|
||||
output_port[0]->lib_name);
|
||||
fprintf(fp, "\tend\n");
|
||||
fprintf(fp, "end\n");
|
||||
fprintf(fp, "assign %s = %s_reg;\n",
|
||||
output_port[0]->lib_name,
|
||||
output_port[0]->lib_name);
|
||||
|
||||
} else if (FALSE == invbuf_spice_model->design_tech_info.buffer_info->tapered_buf) {
|
||||
fprintf(fp, "assign %s = (%s === 1'bz)? $random : %s;\n",
|
||||
output_port[0]->lib_name,
|
||||
input_port[0]->lib_name,
|
||||
input_port[0]->lib_name);
|
||||
} else {
|
||||
assert (TRUE == invbuf_spice_model->design_tech_info.buffer_info->tapered_buf);
|
||||
fprintf(fp, "assign %s = (%s === 1'bz)? $random : ",
|
||||
output_port[0]->lib_name,
|
||||
input_port[0]->lib_name);
|
||||
/* depend on the stage, we may invert the output */
|
||||
if (1 == invbuf_spice_model->design_tech_info.buffer_info->tap_buf_level % 2) {
|
||||
fprintf(fp, "~");
|
||||
}
|
||||
fprintf(fp, "%s;\n",
|
||||
input_port[0]->lib_name);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid topology for spice model (%s)!\n",
|
||||
__FILE__, __LINE__, invbuf_spice_model->name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Print timing info */
|
||||
dump_verilog_submodule_timing(fp, invbuf_spice_model);
|
||||
|
||||
dump_verilog_submodule_signal_init(fp, invbuf_spice_model);
|
||||
|
||||
fprintf(fp, "endmodule\n");
|
||||
|
||||
fprintf(fp, "\n");
|
||||
|
||||
/* Free */
|
||||
my_free(input_port);
|
||||
my_free(output_port);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Dump a module of pass-gate logic */
|
||||
static
|
||||
void dump_verilog_passgate_module(FILE* fp,
|
||||
t_spice_model* passgate_spice_model) {
|
||||
int iport;
|
||||
int num_input_port = 0;
|
||||
int num_output_port = 0;
|
||||
t_spice_model_port** input_port = NULL;
|
||||
t_spice_model_port** output_port = NULL;
|
||||
|
||||
/* Ensure a valid file handler*/
|
||||
if (NULL == fp) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid File handler.\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Find the input port, output port*/
|
||||
input_port = find_spice_model_ports(passgate_spice_model, SPICE_MODEL_PORT_INPUT, &num_input_port, TRUE);
|
||||
output_port = find_spice_model_ports(passgate_spice_model, SPICE_MODEL_PORT_OUTPUT, &num_output_port, TRUE);
|
||||
|
||||
/* Make sure:
|
||||
* There is only 1 output port,
|
||||
* each size of which is 1
|
||||
*/
|
||||
assert(1 == num_output_port);
|
||||
assert(1 == output_port[0]->size);
|
||||
|
||||
fprintf(fp, "//----- Verilog module for %s -----\n",
|
||||
passgate_spice_model->name);
|
||||
|
||||
/* dump module body */
|
||||
fprintf(fp, "module %s (\n",
|
||||
passgate_spice_model->name);
|
||||
|
||||
/* Dump global ports */
|
||||
if (0 < rec_dump_verilog_spice_model_lib_global_ports(fp, passgate_spice_model, TRUE, FALSE, FALSE)) {
|
||||
fprintf(fp, ",\n");
|
||||
}
|
||||
|
||||
/* Assign ports : depending on topology */
|
||||
switch (passgate_spice_model->design_tech_info.pass_gate_info->type) {
|
||||
case SPICE_MODEL_PASS_GATE_TRANSMISSION:
|
||||
/* Make sure:
|
||||
* There is only 3 input port (in, sel, selb),
|
||||
* each size of which is 1
|
||||
*/
|
||||
assert(3 == num_input_port);
|
||||
for (iport = 0; iport < num_input_port; iport++) {
|
||||
assert(1 == input_port[iport]->size);
|
||||
}
|
||||
/* Dump ports */
|
||||
fprintf(fp, "input [0:0] %s,\n", input_port[0]->lib_name);
|
||||
fprintf(fp, "input [0:0] %s,\n", input_port[1]->lib_name);
|
||||
fprintf(fp, "input [0:0] %s,\n", input_port[2]->lib_name);
|
||||
fprintf(fp, "output [0:0] %s\n", output_port[0]->lib_name);
|
||||
fprintf(fp, ");\n");
|
||||
/* Finish dumping ports */
|
||||
|
||||
break;
|
||||
case SPICE_MODEL_PASS_GATE_TRANSISTOR:
|
||||
/* Make sure:
|
||||
* There is only 2 input port (in, sel),
|
||||
* each size of which is 1
|
||||
*/
|
||||
assert(2 == num_input_port);
|
||||
for (iport = 0; iport < num_input_port; iport++) {
|
||||
assert(1 == input_port[iport]->size);
|
||||
}
|
||||
/* Dump ports */
|
||||
fprintf(fp, "input [0:0] %s,\n", input_port[0]->lib_name);
|
||||
fprintf(fp, "input [0:0] %s,\n", input_port[1]->lib_name);
|
||||
fprintf(fp, "output [0:0] %s\n", output_port[0]->lib_name);
|
||||
fprintf(fp, ");\n");
|
||||
/* Finish dumping ports */
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid topology for spice model (%s)!\n",
|
||||
__FILE__, __LINE__, passgate_spice_model->name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Dump logics */
|
||||
fprintf(fp, "assign %s = %s? %s : 1'bz;\n",
|
||||
output_port[0]->lib_name,
|
||||
input_port[1]->lib_name,
|
||||
input_port[0]->lib_name);
|
||||
|
||||
/* Print timing info */
|
||||
dump_verilog_submodule_timing(fp, passgate_spice_model);
|
||||
|
||||
/* Print signal initialization */
|
||||
dump_verilog_submodule_signal_init(fp, passgate_spice_model);
|
||||
|
||||
fprintf(fp, "endmodule\n");
|
||||
|
||||
fprintf(fp, "\n");
|
||||
|
||||
/* Free */
|
||||
my_free(input_port);
|
||||
my_free(output_port);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Dump a module of pass-gate logic */
|
||||
static
|
||||
void dump_verilog_gate_module(FILE* fp,
|
||||
t_spice_model* gate_spice_model) {
|
||||
int iport, ipin, jport, jpin;
|
||||
int num_input_port = 0;
|
||||
int num_output_port = 0;
|
||||
t_spice_model_port** input_port = NULL;
|
||||
t_spice_model_port** output_port = NULL;
|
||||
|
||||
/* Ensure a valid file handler*/
|
||||
if (NULL == fp) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Invalid File handler.\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Find the input port, output port*/
|
||||
input_port = find_spice_model_ports(gate_spice_model, SPICE_MODEL_PORT_INPUT, &num_input_port, TRUE);
|
||||
output_port = find_spice_model_ports(gate_spice_model, SPICE_MODEL_PORT_OUTPUT, &num_output_port, TRUE);
|
||||
|
||||
/* Make sure:
|
||||
* There is only 1 output port,
|
||||
* each size of which is 1
|
||||
*/
|
||||
assert(1 == num_output_port);
|
||||
assert(1 == output_port[0]->size);
|
||||
|
||||
assert(0 < num_input_port);
|
||||
|
||||
fprintf(fp, "//----- Verilog module for %s -----\n",
|
||||
gate_spice_model->name);
|
||||
|
||||
/* dump module body */
|
||||
fprintf(fp, "module %s (\n",
|
||||
gate_spice_model->name);
|
||||
|
||||
/* Dump global ports */
|
||||
if (0 < rec_dump_verilog_spice_model_lib_global_ports(fp, gate_spice_model, TRUE, FALSE, FALSE)) {
|
||||
fprintf(fp, ",\n");
|
||||
}
|
||||
|
||||
/* Dump ports */
|
||||
for (iport = 0; iport < num_input_port; iport++) {
|
||||
fprintf(fp, "input [0:%d] %s,\n",
|
||||
input_port[iport]->size - 1, input_port[iport]->lib_name);
|
||||
}
|
||||
for (iport = 0; iport < num_output_port; iport++) {
|
||||
fprintf(fp, "output [0:%d] %s\n",
|
||||
output_port[iport]->size - 1, output_port[iport]->lib_name);
|
||||
}
|
||||
fprintf(fp, ");\n");
|
||||
|
||||
/* Dump logics */
|
||||
switch (gate_spice_model->design_tech_info.gate_info->type) {
|
||||
case SPICE_MODEL_GATE_AND:
|
||||
for (iport = 0; iport < num_output_port; iport++) {
|
||||
for (ipin = 0; ipin < output_port[iport]->size; ipin++) {
|
||||
fprintf(fp, "assign %s[%d] = ",
|
||||
output_port[iport]->lib_name, ipin);
|
||||
for (jport = 0; jport < num_input_port; jport++) {
|
||||
for (jpin = 0; jpin < input_port[jport]->size; jpin++) {
|
||||
fprintf(fp, "%s[%d]",
|
||||
input_port[jport]->lib_name, jpin);
|
||||
if ((jport == num_input_port - 1) && (jpin == input_port[jport]->size - 1)) {
|
||||
continue; /* Stop output AND sign for the last element in the loop */
|
||||
}
|
||||
fprintf(fp, " & ");
|
||||
}
|
||||
}
|
||||
fprintf(fp, ";\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SPICE_MODEL_GATE_OR:
|
||||
for (iport = 0; iport < num_output_port; iport++) {
|
||||
for (ipin = 0; ipin < output_port[iport]->size; ipin++) {
|
||||
fprintf(fp, "assign %s[%d] = ",
|
||||
output_port[iport]->lib_name, ipin);
|
||||
for (jport = 0; jport < num_input_port; jport++) {
|
||||
for (jpin = 0; jpin < input_port[jport]->size; jpin++) {
|
||||
fprintf(fp, "%s[%d]",
|
||||
input_port[jport]->lib_name, jpin);
|
||||
if ((jport == num_input_port - 1) && (jpin == input_port[jport]->size - 1)) {
|
||||
continue; /* Stop output AND sign for the last element in the loop */
|
||||
}
|
||||
fprintf(fp, " | ");
|
||||
}
|
||||
}
|
||||
fprintf(fp, ";\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SPICE_MODEL_GATE_MUX2:
|
||||
/* Check on the port sequence and map */
|
||||
/* MUX2 should only have 1 output port with size 1 */
|
||||
if (1 != num_output_port) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s, [LINE%d]) MUX2 circuit model must have only 1 output!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
} else if (1 != output_port[0]->size) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s, [LINE%d]) Output size of a MUX2 circuit model must be 1!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
/* MUX2 should only have 3 output port, each of which has a port size of 1 */
|
||||
if (3 != num_input_port) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s, [LINE%d]) MUX2 circuit model must have only 3 input!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
} else {
|
||||
for (iport = 0; iport < num_input_port; iport++) {
|
||||
/* Bypass port size of 1 */
|
||||
if (1 == input_port[iport]->size) {
|
||||
continue;
|
||||
}
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s, [LINE%d]) Input size MUX2 circuit model must be 1!\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
/* Now, we output the logic of MUX2
|
||||
* IMPORTANT Restriction:
|
||||
* We always assum the first two inputs are data inputs
|
||||
* the third input is the select port
|
||||
*/
|
||||
fprintf(fp, "assign %s[%d] = %s[%d] ? %s[%d] : %s[%d];\n",
|
||||
output_port[0]->lib_name, 0,
|
||||
input_port[2]->lib_name, 0,
|
||||
input_port[0]->lib_name, 0,
|
||||
input_port[1]->lib_name, 0);
|
||||
break;
|
||||
default:
|
||||
vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,[LINE%d])Invalid topology for spice model (%s)!\n",
|
||||
__FILE__, __LINE__, gate_spice_model->name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
/* Print timing info */
|
||||
dump_verilog_submodule_timing(fp, gate_spice_model);
|
||||
|
||||
/* Print signal initialization */
|
||||
dump_verilog_submodule_signal_init(fp, gate_spice_model);
|
||||
|
||||
fprintf(fp, "endmodule\n");
|
||||
|
||||
fprintf(fp, "\n");
|
||||
|
||||
/* Free */
|
||||
my_free(input_port);
|
||||
my_free(output_port);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Dump Essential modules:
|
||||
* 1. inverters
|
||||
* 2. buffers
|
||||
* 3. pass-gate logics */
|
||||
static
|
||||
void dump_verilog_submodule_essentials(char* verilog_dir, char* submodule_dir,
|
||||
int num_spice_model,
|
||||
t_spice_model* spice_models) {
|
||||
int imodel;
|
||||
char* verilog_name = my_strcat(submodule_dir, essentials_verilog_file_name);
|
||||
FILE* fp = NULL;
|
||||
|
||||
/* Create file */
|
||||
fp = fopen(verilog_name, "w");
|
||||
if (NULL == fp) {
|
||||
vpr_printf(TIO_MESSAGE_ERROR,"(FILE:%s,LINE[%d])Failure in create Verilog netlist %s",
|
||||
__FILE__, __LINE__, essentials_verilog_file_name);
|
||||
exit(1);
|
||||
}
|
||||
dump_verilog_file_header(fp,"Essential gates");
|
||||
|
||||
verilog_include_defines_preproc_file(fp, verilog_dir);
|
||||
|
||||
/* Output essential models*/
|
||||
for (imodel = 0; imodel < num_spice_model; imodel++) {
|
||||
/* By pass user-defined modules */
|
||||
if (NULL != spice_models[imodel].verilog_netlist) {
|
||||
continue;
|
||||
}
|
||||
if (SPICE_MODEL_INVBUF == spice_models[imodel].type) {
|
||||
dump_verilog_invbuf_module(fp, &(spice_models[imodel]));
|
||||
}
|
||||
if (SPICE_MODEL_PASSGATE == spice_models[imodel].type) {
|
||||
dump_verilog_passgate_module(fp, &(spice_models[imodel]));
|
||||
}
|
||||
if (SPICE_MODEL_GATE == spice_models[imodel].type) {
|
||||
dump_verilog_gate_module(fp, &(spice_models[imodel]));
|
||||
}
|
||||
}
|
||||
|
||||
/* Close file handler*/
|
||||
fclose(fp);
|
||||
|
||||
/* Add fname to the linked list */
|
||||
submodule_verilog_subckt_file_path_head = add_one_subckt_file_name_to_llist(submodule_verilog_subckt_file_path_head, verilog_name);
|
||||
|
||||
/* Free */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Dump a CMOS MUX basis module */
|
||||
static
|
||||
void dump_verilog_cmos_mux_one_basis_module(FILE* fp,
|
||||
|
@ -2762,7 +2228,7 @@ void dump_verilog_submodule_muxes(t_sram_orgz_info* cur_sram_orgz_info,
|
|||
|
||||
/* Alloc the muxes*/
|
||||
muxes_head = stats_spice_muxes(num_switch, switches, spice, routing_arch);
|
||||
|
||||
|
||||
/* Print the muxes netlist*/
|
||||
fp = fopen(verilog_name, "w");
|
||||
if (NULL == fp) {
|
||||
|
@ -2826,6 +2292,41 @@ void dump_verilog_submodule_muxes(t_sram_orgz_info* cur_sram_orgz_info,
|
|||
temp = temp->next;
|
||||
}
|
||||
|
||||
/* Generate modules into a .bak file now. Rename after it is verified */
|
||||
std::string verilog_fname(my_strcat(submodule_dir, muxes_verilog_file_name));
|
||||
verilog_fname += ".bak";
|
||||
|
||||
/* Create the file stream */
|
||||
std::fstream sfp;
|
||||
sfp.open(verilog_fname, std::fstream::out | std::fstream::trunc);
|
||||
|
||||
/* Print out debugging information for if the file is not opened/created properly */
|
||||
vpr_printf(TIO_MESSAGE_INFO,
|
||||
"Creating Verilog netlist for Multiplexers (%s) ...\n",
|
||||
verilog_fname.c_str());
|
||||
check_file_handler(sfp);
|
||||
|
||||
/* TODO: this conversion is temporary. Will be removed after code reconstruction */
|
||||
MuxLibrary mux_lib = convert_mux_arch_to_library(spice->circuit_lib, muxes_head);
|
||||
|
||||
/* Generate basis sub-circuit for unique branches shared by the multiplexers */
|
||||
for (auto mux : mux_lib.muxes()) {
|
||||
const MuxGraph& mux_graph = mux_lib.mux_graph(mux);
|
||||
CircuitModelId mux_circuit_model = mux_lib.mux_circuit_model(mux);
|
||||
/* Create a mux graph for the branch circuit */
|
||||
std::vector<MuxGraph> branch_mux_graphs = mux_graph.build_mux_branch_graphs();
|
||||
/* Create branch circuits, which are N:1 one-level or 2:1 tree-like MUXes */
|
||||
for (auto branch_mux_graph : branch_mux_graphs) {
|
||||
generate_verilog_mux_branch_module(sfp, spice->circuit_lib, mux_circuit_model,
|
||||
mux_graph.num_inputs(), branch_mux_graph);
|
||||
}
|
||||
}
|
||||
|
||||
/* Dump MUX graph one by one */
|
||||
|
||||
/* Close the file steam */
|
||||
sfp.close();
|
||||
|
||||
/* TODO:
|
||||
* Scan-chain configuration circuit does not need any BLs/WLs!
|
||||
* SRAM MUX does not need any reserved BL/WLs!
|
||||
|
@ -4005,7 +3506,8 @@ void dump_verilog_submodule_templates(t_sram_orgz_info* cur_sram_orgz_info,
|
|||
/* Dump verilog files of submodules to be used in FPGA components :
|
||||
* 1. MUXes
|
||||
*/
|
||||
void dump_verilog_submodules(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
void dump_verilog_submodules(ModuleManager& module_manager,
|
||||
t_sram_orgz_info* cur_sram_orgz_info,
|
||||
char* verilog_dir,
|
||||
char* submodule_dir,
|
||||
t_arch Arch,
|
||||
|
@ -4014,9 +3516,10 @@ void dump_verilog_submodules(t_sram_orgz_info* cur_sram_orgz_info,
|
|||
|
||||
/* 0. basic units: inverter, buffers and pass-gate logics, */
|
||||
vpr_printf(TIO_MESSAGE_INFO, "Generating essential modules...\n");
|
||||
dump_verilog_submodule_essentials(verilog_dir, submodule_dir,
|
||||
Arch.spice->num_spice_model,
|
||||
Arch.spice->spice_models);
|
||||
print_verilog_submodule_essentials(module_manager,
|
||||
std::string(verilog_dir),
|
||||
std::string(submodule_dir),
|
||||
Arch.spice->circuit_lib);
|
||||
|
||||
/* 1. MUXes */
|
||||
vpr_printf(TIO_MESSAGE_INFO, "Generating modules of multiplexers...\n");
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
#ifndef VERILOG_SUBMODULES_H
|
||||
#define VERILOG_SUBMODULES_H
|
||||
void dump_verilog_submodules(t_sram_orgz_info* cur_sram_orgz_info,
|
||||
|
||||
#include "module_manager.h"
|
||||
|
||||
void dump_verilog_submodules(ModuleManager& module_manager,
|
||||
t_sram_orgz_info* cur_sram_orgz_info,
|
||||
char* verilog_dir,
|
||||
char* submodule_dir,
|
||||
t_arch Arch,
|
||||
|
|
|
@ -844,7 +844,6 @@ int rec_dump_verilog_spice_model_lib_global_ports(FILE* fp,
|
|||
return dumped_port_cnt;
|
||||
}
|
||||
|
||||
|
||||
/* Dump all the global ports that are stored in the linked list
|
||||
* Return the number of ports that have been dumped
|
||||
*/
|
||||
|
|
|
@ -48,6 +48,7 @@ void dump_verilog_subckt_header_file(t_llist* subckt_llist_head,
|
|||
|
||||
char determine_verilog_generic_port_split_sign(enum e_dump_verilog_port_type dump_port_type);
|
||||
|
||||
|
||||
void dump_verilog_generic_port(FILE* fp,
|
||||
enum e_dump_verilog_port_type dump_port_type,
|
||||
char* port_name, int port_lsb, int port_msb);
|
||||
|
|
|
@ -0,0 +1,168 @@
|
|||
/************************************************
|
||||
* Include functions for most frequently
|
||||
* used Verilog writers
|
||||
***********************************************/
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include "vtr_assert.h"
|
||||
|
||||
/* Device-level header files */
|
||||
|
||||
/* FPGA-X2P context header files */
|
||||
#include "spice_types.h"
|
||||
#include "fpga_x2p_utils.h"
|
||||
|
||||
/* FPGA-Verilog context header files */
|
||||
#include "verilog_global.h"
|
||||
#include "verilog_writer_utils.h"
|
||||
|
||||
/************************************************
|
||||
* Generate header comments for a Verilog netlist
|
||||
* include the description
|
||||
***********************************************/
|
||||
void print_verilog_file_header(std::fstream& fp,
|
||||
const std::string& usage) {
|
||||
check_file_handler(fp);
|
||||
|
||||
auto end = std::chrono::system_clock::now();
|
||||
std::time_t end_time = std::chrono::system_clock::to_time_t(end);
|
||||
|
||||
fp << "//-------------------------------------------" << std::endl;
|
||||
fp << "//\tFPGA Synthesizable Verilog Netlist" << std::endl;
|
||||
fp << "//\tDescription: " << usage << std::endl;
|
||||
fp << "//\tAuthor: Xifan TANG" << std::endl;
|
||||
fp << "//\tOrganization: University of Utah" << std::endl;
|
||||
fp << "//\tDate: " << std::ctime(&end_time) ;
|
||||
fp << "//-------------------------------------------" << std::endl;
|
||||
fp << "//----- Time scale -----" << std::endl;
|
||||
fp << "`timescale 1ns / 1ps" << std::endl;
|
||||
fp << "\n";
|
||||
}
|
||||
|
||||
|
||||
/************************************************
|
||||
* Generate include files for a Verilog netlist
|
||||
***********************************************/
|
||||
void print_verilog_include_defines_preproc_file(std::fstream& fp,
|
||||
const std::string& verilog_dir) {
|
||||
check_file_handler(fp);
|
||||
|
||||
/* Generate the file name */
|
||||
std::string include_file_path = format_dir_path(verilog_dir);
|
||||
include_file_path += defines_verilog_file_name;
|
||||
|
||||
fp << "//------ Include defines: preproc flags -----" << std::endl;
|
||||
fp << "`include \"" << include_file_path << "\"" << std::endl;
|
||||
fp << "//------ End Include defines: preproc flags -----" << std::endl;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/************************************************
|
||||
* Print a Verilog comment line
|
||||
***********************************************/
|
||||
void print_verilog_comment(std::fstream& fp,
|
||||
const std::string& comment) {
|
||||
check_file_handler(fp);
|
||||
|
||||
fp << "// " << comment << std::endl;
|
||||
}
|
||||
|
||||
/************************************************
|
||||
* Print a Verilog module definition
|
||||
***********************************************/
|
||||
void print_verilog_module_definition(std::fstream& fp,
|
||||
const std::string& module_name) {
|
||||
check_file_handler(fp);
|
||||
|
||||
print_verilog_comment(fp, std::string("//----- Verilog module for " + module_name + " -----"));
|
||||
fp << "module " << module_name << "(" << std::endl;
|
||||
}
|
||||
|
||||
/************************************************
|
||||
* Print a Verilog module ports based on the module id
|
||||
***********************************************/
|
||||
void print_verilog_module_ports(std::fstream& fp,
|
||||
const ModuleManager& module_manager, const ModuleId& module_id) {
|
||||
check_file_handler(fp);
|
||||
|
||||
/* port type2type mapping */
|
||||
std::map<ModuleManager::e_module_port_type, enum e_dump_verilog_port_type> port_type2type_map;
|
||||
port_type2type_map[ModuleManager::MODULE_GLOBAL_PORT] = VERILOG_PORT_INPUT;
|
||||
port_type2type_map[ModuleManager::MODULE_INOUT_PORT] = VERILOG_PORT_INOUT;
|
||||
port_type2type_map[ModuleManager::MODULE_INPUT_PORT] = VERILOG_PORT_INPUT;
|
||||
port_type2type_map[ModuleManager::MODULE_OUTPUT_PORT] = VERILOG_PORT_OUTPUT;
|
||||
port_type2type_map[ModuleManager::MODULE_CLOCK_PORT] = VERILOG_PORT_INPUT;
|
||||
|
||||
/* Port sequence: global, inout, input, output and clock ports, */
|
||||
size_t port_cnt = 0;
|
||||
for (const auto& kv : port_type2type_map) {
|
||||
for (const auto& port : module_manager.module_ports_by_type(module_id, kv.first)) {
|
||||
if (0 != port_cnt) {
|
||||
/* Do not dump a comma for the first port */
|
||||
fp << ", //----- " << module_manager.module_port_type_str(kv.first) << " -----" << std::endl;
|
||||
}
|
||||
/* Print port */
|
||||
fp << "\t" << generate_verilog_port(kv.second, port) << std::endl;
|
||||
port_cnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************
|
||||
* Print a Verilog module declaration (definition + port list
|
||||
***********************************************/
|
||||
void print_verilog_module_declaration(std::fstream& fp,
|
||||
const ModuleManager& module_manager, const ModuleId& module_id) {
|
||||
check_file_handler(fp);
|
||||
|
||||
print_verilog_module_definition(fp, module_manager.module_name(module_id));
|
||||
|
||||
print_verilog_module_ports(fp, module_manager, module_id);
|
||||
|
||||
fp << std::endl << ");" << std::endl;
|
||||
}
|
||||
|
||||
|
||||
/************************************************
|
||||
* Print an end line for a Verilog module
|
||||
***********************************************/
|
||||
void print_verilog_module_end(std::fstream& fp,
|
||||
const std::string& module_name) {
|
||||
check_file_handler(fp);
|
||||
|
||||
fp << "endmodule" << std::endl;
|
||||
print_verilog_comment(fp, std::string("//----- END Verilog module for " + module_name + " -----"));
|
||||
fp << std::endl;
|
||||
}
|
||||
|
||||
/* Generate a string of a Verilog port */
|
||||
std::string generate_verilog_port(const enum e_dump_verilog_port_type& verilog_port_type,
|
||||
const BasicPort& port_info) {
|
||||
std::string verilog_line;
|
||||
|
||||
/* Ensure the port type is valid */
|
||||
VTR_ASSERT(verilog_port_type < NUM_VERILOG_PORT_TYPES);
|
||||
|
||||
std::string size_str = "[" + std::to_string(port_info.get_lsb()) + ":" + std::to_string(port_info.get_msb()) + "]";
|
||||
|
||||
/* Only connection require a format of <port_name>[<lsb>:<msb>]
|
||||
* others require a format of <port_type> [<lsb>:<msb>] <port_name>
|
||||
*/
|
||||
if (VERILOG_PORT_CONKT == verilog_port_type) {
|
||||
/* When LSB == MSB, we can use a simplified format <port_type>[<lsb>]*/
|
||||
if ( 1 == port_info.get_width()) {
|
||||
size_str = "[" + std::to_string(port_info.get_lsb()) + "]";
|
||||
}
|
||||
verilog_line = port_info.get_name() + size_str;
|
||||
} else {
|
||||
verilog_line = VERILOG_PORT_TYPE_STRING[verilog_port_type];
|
||||
verilog_line += " " + size_str + " " + port_info.get_name();
|
||||
}
|
||||
|
||||
return verilog_line;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/************************************************
|
||||
* Header file for verilog_writer_utils.cpp
|
||||
* Include function declaration for most frequently
|
||||
* used Verilog writers
|
||||
***********************************************/
|
||||
#ifndef VERILOG_WRITER_UTILS_H
|
||||
#define VERILOG_WRITER_UTILS_H
|
||||
|
||||
#include <string>
|
||||
#include "device_port.h"
|
||||
#include "module_manager.h"
|
||||
|
||||
void print_verilog_file_header(std::fstream& fp,
|
||||
const std::string& usage);
|
||||
|
||||
void print_verilog_include_defines_preproc_file(std::fstream& fp,
|
||||
const std::string& verilog_dir);
|
||||
|
||||
void print_verilog_comment(std::fstream& fp,
|
||||
const std::string& comment);
|
||||
|
||||
void print_verilog_module_definition(std::fstream& fp,
|
||||
const std::string& module_name);
|
||||
|
||||
void print_verilog_module_ports(std::fstream& fp,
|
||||
const ModuleManager& module_manager, const ModuleId& module_id);
|
||||
|
||||
void print_verilog_module_declaration(std::fstream& fp,
|
||||
const ModuleManager& module_manager, const ModuleId& module_id);
|
||||
|
||||
void print_verilog_module_end(std::fstream& fp,
|
||||
const std::string& module_name);
|
||||
|
||||
std::string generate_verilog_port(const enum e_dump_verilog_port_type& dump_port_type,
|
||||
const BasicPort& port_info);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,30 @@
|
|||
* Sub Circuit
|
||||
* 1-Bit Full-Adder circuit netlist
|
||||
.subckt adder inA inB Cin Cout Sumout svdd sgnd size=1
|
||||
X01 nd1 inA svdd svdd vpr_pmos W='size*beta*wp' L='pl'
|
||||
X02 nd1 inB svdd svdd vpr_pmos W='size*beta*wp' L='pl'
|
||||
X03 nd2 inB nd1 svdd vpr_pmos W='size*beta*wp' L='pl'
|
||||
X04 nco inA nd2 svdd vpr_pmos W='size*beta*wp' L='pl'
|
||||
X05 nco Cin nd1 svdd vpr_pmos W='size*beta*wp' L='pl'
|
||||
X06 nco Cin nd3 sgnd vpr_nmos W='size*wn' L='nl'
|
||||
X07 nd3 inA sgnd sgnd vpr_nmos W='size*wn' L='nl'
|
||||
X08 nd3 inB sgnd sgnd vpr_nmos W='size*wn' L='nl'
|
||||
X09 nco inA nd4 sgnd vpr_nmos W='size*wn' L='nl'
|
||||
X10 nd4 inB sgnd sgnd vpr_nmos W='size*wn' L='nl'
|
||||
Xo1 nco Cout svdd sgnd inv size='size'
|
||||
X11 nd5 inA svdd svdd vpr_pmos W='size*beta*wp' L='pl'
|
||||
X12 nd5 inB svdd svdd vpr_pmos W='size*beta*wp' L='pl'
|
||||
X13 nd5 Cin svdd svdd vpr_pmos W='size*beta*wp' L='pl'
|
||||
X14 nd6 inA nd5 svdd vpr_pmos W='size*beta*wp' L='pl'
|
||||
X15 nd7 inB nd6 svdd vpr_pmos W='size*beta*wp' L='pl'
|
||||
X16 ndS Cin nd7 svdd vpr_pmos W='size*beta*wp' L='pl'
|
||||
X23 nds nco nd5 svdd vpr_pmos W='size*beta*wp' L='pl'
|
||||
X24 nds nco nd8 sgnd vpr_nmos W='size*wn' L='nl'
|
||||
X17 nd8 inA sgnd sgnd vpr_nmos W='size*wn' L='nl'
|
||||
X18 nd8 inB sgnd sgnd vpr_nmos W='size*wn' L='nl'
|
||||
X19 nd8 Cin sgnd sgnd vpr_nmos W='size*wn' L='nl'
|
||||
X20 ndS Cin nd9 sgnd vpr_nmos W='size*wn' L='nl'
|
||||
X21 nd9 inA n10 sgnd vpr_nmos W='size*wn' L='nl'
|
||||
X22 n10 inB sgnd sgnd vpr_nmos W='size*wn' L='nl'
|
||||
Xo2 nds Sumout svdd sgnd inv size='size'
|
||||
.eom
|
|
@ -0,0 +1,25 @@
|
|||
* Sub Circuits
|
||||
*
|
||||
* Static D Flip-flop
|
||||
.subckt static_dff set rst clk D Q svdd sgnd size=1
|
||||
* Input inverter
|
||||
Xinv_clk clk clk_b svdd sgnd inv size=size
|
||||
Xinv_set set set_b svdd sgnd inv size=size
|
||||
Xinv_rst rst rst_b svdd sgnd inv size=size
|
||||
Xinv_d D s1_n1 svdd sgnd inv size=size
|
||||
Xcpt0 s1_n1 s1_n2 clk_b clk svdd sgnd cpt nmos_size='size' pmos_size='size*beta'
|
||||
Xset0 s1_n2 set_b svdd svdd vpr_pmos L=pl W='size*wp'
|
||||
Xrst0 s1_n2 rst sgnd sgnd vpr_nmos L=nl W='size*wn'
|
||||
Xinv1 s1_n2 s1_q svdd sgnd inv size=size
|
||||
Xinv2 s1_q s1_n3 svdd sgnd inv size=size
|
||||
Xcpt1 s1_n3 s1_n2 clk clk_b svdd sgnd cpt nmos_size='size' pmos_size='size*beta'
|
||||
* Stage 2
|
||||
R3 s1_q s2_n1 0
|
||||
Xcpt2 s2_n1 s2_n2 clk clk_b svdd sgnd cpt nmos_size='size' pmos_size='size*beta'
|
||||
Xrst1 s2_n2 rst_b svdd svdd vpr_pmos L=pl W='size*wp'
|
||||
Xset1 s2_n2 set sgnd sgnd vpr_nmos L=nl W='size*wn'
|
||||
Xinv4 s2_n2 Qb svdd sgnd inv size=size
|
||||
Xinv5 Qb s2_n3 svdd sgnd inv size=size
|
||||
Xcpt3 s2_n3 s2_n2 clk_b clk svdd sgnd cpt nmos_size='size' pmos_size='size*beta'
|
||||
Xinv_out Qb Q svdd sgnd inv size=size
|
||||
.eom static_dff
|
|
@ -0,0 +1,68 @@
|
|||
Testbench for D-type Flip-flop with set and reset
|
||||
*********************************
|
||||
* HSPICE Netlist *
|
||||
* Author: Xifan TANG *
|
||||
* Organization: EPFL,LSI *
|
||||
*********************************
|
||||
*
|
||||
* Use Standard CMOS Technology
|
||||
****** Include Technology Library ******
|
||||
.lib '/home/xitang/tangxifan-eda-tools/branches/subvt_fpga/process/tsmc40nm/toplevel_crn45gs_2d5_v1d1_shrink0d9_embedded_usage.l' TOP_TT
|
||||
****** Transistor Parameters ******
|
||||
.param beta=2
|
||||
.param nl=4e-08
|
||||
.param wn=1.4e-07
|
||||
.param pl=4e-08
|
||||
.param wp=1.4e-07
|
||||
|
||||
****** Include subckt netlists: NMOS and PMOS *****
|
||||
.include '/home/xitang/tangxifan-eda-tools/branches/vpr7_rram/vpr/spice_test/subckt/nmos_pmos.sp'
|
||||
****** Include subckt netlists: Inverters, Buffers *****
|
||||
.include '/home/xitang/tangxifan-eda-tools/branches/vpr7_rram/vpr/spice_test/subckt/inv_buf_trans_gate.sp'
|
||||
|
||||
.include '/home/xitang/tangxifan-eda-tools/branches/vpr7_rram/vpr/SpiceNetlists/ff.sp'
|
||||
|
||||
.param clk_freq = 1e9
|
||||
*Temperature
|
||||
.temp 25
|
||||
*Global nodes
|
||||
.global vdd gnd
|
||||
*Print node capacitance
|
||||
.option captab
|
||||
*Print waveforms
|
||||
.option POST
|
||||
* Parameters for measurements
|
||||
.param clk2d=3e-09
|
||||
.param clk_pwl=3e-09
|
||||
.param clk_pwh=1.5e-08
|
||||
.param slew=1e-11
|
||||
.param thold=3e-09
|
||||
.param vsp=0.9
|
||||
* Parameters for Measuring Slew
|
||||
.param slew_upper_threshold_pct_rise=0.9
|
||||
.param slew_lower_threshold_pct_rise=0.1
|
||||
.param slew_upper_threshold_pct_fall=0.1
|
||||
.param slew_lower_threshold_pct_fall=0.9
|
||||
* Parameters for Measuring Delay
|
||||
.param input_threshold_pct_rise=0.5
|
||||
.param input_threshold_pct_fall=0.5
|
||||
.param output_threshold_pct_rise=0.5
|
||||
.param output_threshold_pct_fall=0.5
|
||||
|
||||
Xdff[0] set rst clk d q vdd gnd static_dff
|
||||
|
||||
Vsupply vdd gnd 'vsp'
|
||||
*Stimulates
|
||||
vset set gnd 0
|
||||
vrst rst gnd 0
|
||||
vclk_in clk gnd pulse (0 vsp '0.5/clk_freq' '0.025/clk_freq' '0.025/clk_freq' '0.4875/clk_freq' '1/clk_freq')
|
||||
* Measuring Clk2Q, Setup Time and Hold Time
|
||||
vdata D gnd pulse (0 vsp '0.25/clk_freq' '0.025/clk_freq' '0.025/clk_freq' '2*0.4875/clk_freq' '2/clk_freq')
|
||||
|
||||
*Simulation
|
||||
.tran 1e-15 '10/clk_freq'
|
||||
.meas tran slew_q trig v(Q) val='slew_lower_threshold_pct_fall*vsp' fall=1 td='2*clk_pwl+clk_pwh+2*slew'
|
||||
+ targ v(Q) val='slew_upper_threshold_pct_fall*vsp' fall=1 td='2*clk_pwl+clk_pwh+2*slew'
|
||||
.meas tran clk2q trig v(CLK) val='input_threshold_pct_fall*vsp' rise=2
|
||||
+ targ v(Q) val='output_threshold_pct_fall*vsp' fall=1 td='2*clk_pwl+clk_pwh+2*slew'
|
||||
.end TSPC Flip-flop with set and reset
|
|
@ -0,0 +1,16 @@
|
|||
* Sub Circuit
|
||||
* OR2 gate
|
||||
.subckt or2 in0 in1 out svdd sgnd size=1
|
||||
Xp0 ntwk_n0 in0 svdd svdd vpr_pmos L=pl W='size*beta*wp'
|
||||
Xp1 ntwk_n0 in1 ntwk_n1 svdd vpr_pmos L=pl W='size*beta*wp'
|
||||
Xn0 ntwk_n1 in0 sgnd sgnd vpr_nmos L=nl W='wn*size'
|
||||
Xn1 ntwk_n1 in1 sgnd sgnd vpr_nmos L=nl W='wn*size'
|
||||
.eom
|
||||
|
||||
* AND2 gate
|
||||
.subckt and2 in0 in1 out svdd sgnd size=1
|
||||
Xp0 ntwk_n0 in0 svdd svdd vpr_pmos L=pl W='wp*size*beta'
|
||||
Xp1 ntwk_n0 in1 svdd svdd vpr_pmos L=pl W='wp*size*beta'
|
||||
Xn0 ntwk_n0 in0 ntwk_n1 sgnd vpr_nmos L=nl W='wn*size'
|
||||
Xn1 ntwk_n1 in1 sgnd sgnd vpr_nmos L=nl W='wn*size'
|
||||
.eom
|
|
@ -0,0 +1,11 @@
|
|||
* Sub Circuit
|
||||
* IO pads
|
||||
* When direction = 0, pad <= dout
|
||||
* When direction = 1, pad => din
|
||||
.subckt iopad zin dout din pad direction direction_inv svdd sgnd
|
||||
Xbuf0 pad din_inter svdd sgnd buf size=2
|
||||
Xbuf1 dout pad_inter svdd sgnd buf size=2
|
||||
*Xinv0 direction direction_inv svdd sgnd inv size=1
|
||||
Xcpt0 din_inter din direction direction_inv svdd sgnd cpt
|
||||
Xcpt1 pad_inter pad direction_inv direction svdd sgnd cpt
|
||||
.eom iopad
|
|
@ -0,0 +1,10 @@
|
|||
* Sub Circuit
|
||||
* SRAM
|
||||
* Input to force write the stored bit
|
||||
.subckt sram6T in out outb svdd sgnd size=1
|
||||
Xinv0 loop_out loop_outb svdd sgnd inv size=size
|
||||
Xinv1 loop_outb loop_out svdd sgnd inv size=size
|
||||
Xout_pt loop_out out svdd sgnd svdd sgnd cpt nmos_size='size' pmos_size='size*beta'
|
||||
Xoutb_pt loop_outb outb svdd sgnd svdd sgnd cpt
|
||||
Rin in loop_out 0
|
||||
.eom sram6T
|
|
@ -0,0 +1,19 @@
|
|||
//------ Module: sram6T_blwl -----//
|
||||
//------ Verilog file: sram.v -----//
|
||||
//------ Author: Xifan TANG -----//
|
||||
module adder(
|
||||
input [0:0] a, // Input a
|
||||
input [0:0] b, // Input b
|
||||
input [0:0] cin, // Input cin
|
||||
output [0:0] cout, // Output carry
|
||||
output [0:0] sumout // Output sum
|
||||
);
|
||||
//wire[1:0] int_calc;
|
||||
|
||||
//assign int_calc = a + b + cin;
|
||||
//assign cout = int_calc[1];
|
||||
//assign sumout = int_calc[0];
|
||||
assign sumout = a ^ b ^ cin;
|
||||
assign cout = (a & b) | (a & cin) | (b & cin);
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
//-----------------------------------------------------
|
||||
// Design Name : static_dff
|
||||
// File Name : ff.v
|
||||
// Function : D flip-flop with asyn reset and set
|
||||
// Coder : Xifan TANG
|
||||
//-----------------------------------------------------
|
||||
//------ Include defines: preproc flags -----
|
||||
`include "GENERATED_DIR_KEYWORD/SRC/fpga_defines.v"
|
||||
module static_dff (
|
||||
/* Global ports go first */
|
||||
input set, // set input
|
||||
input reset, // Reset input
|
||||
input clk, // Clock Input
|
||||
/* Local ports follow */
|
||||
input D, // Data Input
|
||||
output Q // Q output
|
||||
);
|
||||
//------------Internal Variables--------
|
||||
reg q_reg;
|
||||
|
||||
//-------------Code Starts Here---------
|
||||
always @ ( posedge clk or posedge reset or posedge set)
|
||||
if (reset) begin
|
||||
q_reg <= 1'b0;
|
||||
end else if (set) begin
|
||||
q_reg <= 1'b1;
|
||||
end else begin
|
||||
q_reg <= D;
|
||||
end
|
||||
|
||||
// Wire q_reg to Q
|
||||
assign Q = q_reg;
|
||||
|
||||
endmodule //End Of Module static_dff
|
||||
|
||||
//-----------------------------------------------------
|
||||
// Design Name : scan_chain_dff
|
||||
// File Name : ff.v
|
||||
// Function : D flip-flop with asyn reset and set
|
||||
// Coder : Xifan TANG
|
||||
//-----------------------------------------------------
|
||||
module sc_dff (
|
||||
/* Global ports go first */
|
||||
input set, // set input
|
||||
input reset, // Reset input
|
||||
input clk, // Clock Input
|
||||
/* Local ports follow */
|
||||
input D, // Data Input
|
||||
output Q, // Q output
|
||||
output Qb // Q output
|
||||
);
|
||||
//------------Internal Variables--------
|
||||
reg q_reg;
|
||||
|
||||
//-------------Code Starts Here---------
|
||||
always @ ( posedge clk or posedge reset or posedge set)
|
||||
if (reset) begin
|
||||
q_reg <= 1'b0;
|
||||
end else if (set) begin
|
||||
q_reg <= 1'b1;
|
||||
end else begin
|
||||
q_reg <= D;
|
||||
end
|
||||
|
||||
// Wire q_reg to Q
|
||||
assign Q = q_reg;
|
||||
assign Qb = ~Q;
|
||||
|
||||
endmodule //End Of Module static_dff
|
||||
|
||||
//-----------------------------------------------------
|
||||
// Design Name : scan_chain_dff compact
|
||||
// File Name : ff.v
|
||||
// Function : Scan-chain D flip-flop without reset and set //Modified to fit Edouards architecture
|
||||
// Coder : Xifan TANG
|
||||
//-----------------------------------------------------
|
||||
module sc_dff_compact (
|
||||
/* Global ports go first */
|
||||
input reset, // Reset input
|
||||
//input set, // set input
|
||||
input clk, // Clock Input
|
||||
/* Local ports follow */
|
||||
input D, // Data Input
|
||||
output Q, // Q output
|
||||
output Qb // Q output
|
||||
);
|
||||
//------------Internal Variables--------
|
||||
reg q_reg;
|
||||
|
||||
//-------------Code Starts Here---------
|
||||
always @ ( posedge clk or posedge reset /*or posedge set*/)
|
||||
if (reset) begin
|
||||
q_reg <= 1'b0;
|
||||
//end else if (set) begin
|
||||
// q_reg <= 1'b1;
|
||||
end else begin
|
||||
q_reg <= D;
|
||||
end
|
||||
/*
|
||||
// Wire q_reg to Q
|
||||
assign Q = q_reg;
|
||||
assign Qb = ~Q;
|
||||
*/
|
||||
|
||||
`ifndef ENABLE_FORMAL_VERIFICATION
|
||||
// Wire q_reg to Q
|
||||
assign Q = q_reg;
|
||||
assign Qb = ~q_reg;
|
||||
`else
|
||||
assign Q = 1'bZ;
|
||||
assign Qb = !Q;
|
||||
`endif
|
||||
|
||||
endmodule //End Of Module static_dff
|
|
@ -0,0 +1,64 @@
|
|||
//-----------------------------------------------------
|
||||
// Design Name : testbench for static_dff
|
||||
// File Name : ff_tb.v
|
||||
// Function : D flip-flop with asyn reset and set
|
||||
// Coder : Xifan TANG
|
||||
//-----------------------------------------------------
|
||||
//----- Time scale: simulation time step and accuracy -----
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
module static_dff_tb;
|
||||
// voltage sources
|
||||
wire set;
|
||||
reg reset;
|
||||
reg clk;
|
||||
reg D;
|
||||
wire Q;
|
||||
// Parameters
|
||||
parameter clk_period = 2; // [ns] a full clock period
|
||||
parameter half_clk_period = clk_period / 2; // [ns] a half clock period
|
||||
parameter d_period = 2 * clk_period; // [ns] two clock period
|
||||
parameter reset_period = 8 * clk_period; // [ns] a full clock period
|
||||
|
||||
// Unit Under Test
|
||||
static_dff U0 (set, reset, clk, D, Q);
|
||||
|
||||
// Voltage stimuli
|
||||
// Reset : enable in the first clock cycle and then disabled
|
||||
initial
|
||||
begin
|
||||
reset = 1'b1;
|
||||
#clk_period reset = ~reset;
|
||||
end
|
||||
always
|
||||
begin
|
||||
#reset_period reset = ~reset;
|
||||
end
|
||||
|
||||
// set : alway disabled
|
||||
assign set = 1'b0;
|
||||
|
||||
// clk: clock generator
|
||||
initial
|
||||
begin
|
||||
clk = 1'b0;
|
||||
end
|
||||
always
|
||||
begin
|
||||
#half_clk_period clk = ~clk;
|
||||
end
|
||||
|
||||
// D: input, flip every two clock cycles
|
||||
initial
|
||||
begin
|
||||
D = 1'b0;
|
||||
end
|
||||
always
|
||||
begin
|
||||
#d_period D = ~D;
|
||||
end
|
||||
|
||||
// Q is an output
|
||||
//
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,16 @@
|
|||
//------ Module: iopad -----//
|
||||
//------ Verilog file: io.v -----//
|
||||
//------ Author: Xifan TANG -----//
|
||||
module iopad(
|
||||
//input zin, // Set output to be Z
|
||||
input outpad, // Data output
|
||||
output inpad, // Data input
|
||||
inout pad, // bi-directional pad
|
||||
input en // enable signal to control direction of iopad
|
||||
//input direction_inv // enable signal to control direction of iopad
|
||||
);
|
||||
//----- when direction enabled, the signal is propagated from pad to din
|
||||
assign inpad = en ? pad : 1'bz;
|
||||
//----- when direction is disabled, the signal is propagated from dout to pad
|
||||
assign pad = en ? 1'bz : outpad;
|
||||
endmodule
|
|
@ -0,0 +1,199 @@
|
|||
//-----------------------------------------------------
|
||||
// Design Name : testbench for logic blocks
|
||||
// File Name : lb_tb.v
|
||||
// Function : Configurable logic block
|
||||
// Coder : Xifan TANG
|
||||
//-----------------------------------------------------
|
||||
//----- Time scale: simulation time step and accuracy -----
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
module lb_tb;
|
||||
// Parameters
|
||||
parameter SIZE_IN = 40; //---- MUX input size
|
||||
parameter SIZE_OUT = 10; //---- MUX input size
|
||||
parameter SIZE_RESERV_BLWL = 49 + 1; //---- MUX input size
|
||||
parameter SIZE_BLWL = 1019 - 310 + 1; //---- MUX input size
|
||||
parameter prog_clk_period = 1; // [ns] half clock period
|
||||
parameter op_clk_period = 1; // [ns] half clock period
|
||||
parameter config_period = 2 * prog_clk_period; // [ns] One full clock period
|
||||
parameter operating_period = SIZE_IN * 2 * op_clk_period; // [ns] One full clock period
|
||||
|
||||
// Ports
|
||||
wire [0:SIZE_IN-1] lb_in;
|
||||
wire [0:SIZE_IN-1] lb_out;
|
||||
wire lb_clk;
|
||||
wire [0:SIZE_RESERV_BLWL-1] reserv_bl;
|
||||
wire [0:SIZE_RESERV_BLWL-1] reserv_wl;
|
||||
wire [0:SIZE_BLWL-1] bl;
|
||||
wire [0:SIZE_BLWL-1] wl;
|
||||
wire prog_EN;
|
||||
wire prog_ENb;
|
||||
wire zin;
|
||||
wire nequalize;
|
||||
wire read;
|
||||
wire clk;
|
||||
wire Reset;
|
||||
wire Set;
|
||||
// Clocks
|
||||
wire prog_clock;
|
||||
wire op_clock;
|
||||
|
||||
// Registered port
|
||||
reg [0:SIZE_IN-1] lb_in_reg;
|
||||
reg [0:SIZE_RESERV_BLWL-1] reserv_bl_reg;
|
||||
reg [0:SIZE_RESERV_BLWL-1] reserv_wl_reg;
|
||||
reg [0:SIZE_BLWL-1] bl_reg;
|
||||
reg [0:SIZE_BLWL-1] wl_reg;
|
||||
reg prog_clock_reg;
|
||||
reg op_clock_reg;
|
||||
|
||||
// Config done signal;
|
||||
reg config_done;
|
||||
// Temp register for rotating shift
|
||||
reg temp;
|
||||
|
||||
// Unit under test
|
||||
grid_1__1_ U0 (
|
||||
zin,
|
||||
nequalize,
|
||||
read,
|
||||
clk,
|
||||
Reset,
|
||||
Set,
|
||||
prog_ENb,
|
||||
prog_EN,
|
||||
// Top inputs
|
||||
lb_in[0], lb_in[4], lb_in[8], lb_in[12], lb_in[16],
|
||||
lb_in[20], lb_in[24], lb_in[28], lb_in[32], lb_in[36],
|
||||
// Top outputs
|
||||
lb_out[0], lb_out[4], lb_out[8],
|
||||
// Right inputs
|
||||
lb_in[1], lb_in[5], lb_in[9], lb_in[13], lb_in[17],
|
||||
lb_in[21], lb_in[25], lb_in[29], lb_in[33], lb_in[37],
|
||||
// Right outputs
|
||||
lb_out[1], lb_out[5], lb_out[9],
|
||||
// Bottom inputs
|
||||
lb_in[2], lb_in[6], lb_in[10], lb_in[14], lb_in[18],
|
||||
lb_in[22], lb_in[26], lb_in[30], lb_in[34], lb_in[38],
|
||||
// Bottom outputs
|
||||
lb_out[2], lb_out[6],
|
||||
// Bottom inputs
|
||||
lb_clk,
|
||||
// left inputs
|
||||
lb_in[3], lb_in[7], lb_in[11], lb_in[15], lb_in[19],
|
||||
lb_in[23], lb_in[27], lb_in[31], lb_in[35], lb_in[39],
|
||||
// left outputs
|
||||
lb_out[3], lb_out[7],
|
||||
reserv_bl, reserv_wl,
|
||||
bl, wl
|
||||
);
|
||||
|
||||
// Task: assign BL and WL values
|
||||
task prog_lb_blwl;
|
||||
begin
|
||||
@(posedge prog_clock);
|
||||
// Rotate left shift
|
||||
temp = reserv_bl_reg[SIZE_RESERV_BLWL-1];
|
||||
//bl_reg = bl_reg >> 1;
|
||||
reserv_bl_reg[1:SIZE_RESERV_BLWL-1] = reserv_bl_reg[0:SIZE_RESERV_BLWL-2];
|
||||
reserv_bl_reg[0] = temp;
|
||||
end
|
||||
endtask
|
||||
|
||||
// Task: assign inputs
|
||||
task op_lb_in;
|
||||
begin
|
||||
@(posedge op_clock);
|
||||
temp = lb_in_reg[SIZE_IN-1];
|
||||
lb_in_reg[1:SIZE_IN-1] = lb_in_reg[0:SIZE_IN-2];
|
||||
lb_in_reg[0] = temp;
|
||||
end
|
||||
endtask
|
||||
|
||||
// Configuration done signal
|
||||
initial
|
||||
begin
|
||||
config_done = 1'b0;
|
||||
end
|
||||
// Enabled during config_period, Disabled during op_period
|
||||
always
|
||||
begin
|
||||
#config_period config_done = ~config_done;
|
||||
#operating_period config_done = ~config_done;
|
||||
end
|
||||
|
||||
// Programming clocks
|
||||
initial
|
||||
begin
|
||||
prog_clock_reg = 1'b0;
|
||||
end
|
||||
always
|
||||
begin
|
||||
#prog_clk_period prog_clock_reg = ~prog_clock_reg;
|
||||
end
|
||||
|
||||
// Operating clocks
|
||||
initial
|
||||
begin
|
||||
op_clock_reg = 1'b0;
|
||||
end
|
||||
always
|
||||
begin
|
||||
#op_clk_period op_clock_reg = ~op_clock_reg;
|
||||
end
|
||||
|
||||
// Programming and Operating clocks
|
||||
assign prog_clock = prog_clock_reg & (~config_done);
|
||||
assign op_clock = op_clock_reg & config_done;
|
||||
|
||||
// Programming Enable signals
|
||||
assign prog_EN = prog_clock & (~config_done);
|
||||
assign prog_ENb = ~prog_EN;
|
||||
|
||||
// Programming phase: BL/WL
|
||||
initial
|
||||
begin
|
||||
// Initialize BL/WL registers
|
||||
reserv_bl_reg = {SIZE_RESERV_BLWL {1'b0}};
|
||||
reserv_bl_reg[0] = 1'b1;
|
||||
reserv_wl_reg = {SIZE_RESERV_BLWL {1'b0}};
|
||||
// Reserved BL/WL
|
||||
bl_reg = {SIZE_BLWL {1'b0}};
|
||||
wl_reg = {SIZE_BLWL {1'b1}};
|
||||
//wl_reg[SIZE_BLWL-1] = 1'b1;
|
||||
end
|
||||
always wait (~config_done) // Only invoked when config_done is 0
|
||||
begin
|
||||
// Propagate input 1 to the output
|
||||
// BL[0] = 1, WL[4] = 1
|
||||
prog_lb_blwl;
|
||||
end
|
||||
|
||||
// Operating Phase
|
||||
initial
|
||||
begin
|
||||
lb_in_reg = {SIZE_IN {1'b0}};
|
||||
lb_in_reg[0] = 1'b1; // Last bit is 1 initially
|
||||
end
|
||||
always wait (config_done) // Only invoked when config_done is 1
|
||||
begin
|
||||
/* Update inputs */
|
||||
op_lb_in;
|
||||
end
|
||||
|
||||
// Wire ports
|
||||
assign lb_in = lb_in_reg;
|
||||
assign reserv_bl = reserv_bl_reg;
|
||||
assign reserv_wl = reserv_wl_reg;
|
||||
assign bl = bl_reg;
|
||||
assign wl = wl_reg;
|
||||
|
||||
// Constant ports
|
||||
assign zin = 1'b0;
|
||||
assign nequalize = 1'b1;
|
||||
assign read = 1'b0;
|
||||
assign clk = op_clock;
|
||||
assign Reset = ~config_done;
|
||||
assign Set = 1'b0;
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,15 @@
|
|||
//-----------------------------------------------------
|
||||
// Design Name : lut6
|
||||
// File Name : lut6.v
|
||||
// Function : 6-input Look Up Table
|
||||
// Coder : Xifan TANG
|
||||
//-----------------------------------------------------
|
||||
module lut6 (
|
||||
input [5:0] in,
|
||||
output out,
|
||||
input [63:0] sram,
|
||||
input [63:0] sram_inv);
|
||||
|
||||
assign out = sram[in];
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,85 @@
|
|||
//-----------------------------------------------------
|
||||
// Design Name : testbench for 2-level SRAM MUX
|
||||
// File Name : mux_tb.v
|
||||
// Function : SRAM-based 2-level MUXes
|
||||
// Coder : Xifan TANG
|
||||
//-----------------------------------------------------
|
||||
//----- Time scale: simulation time step and accuracy -----
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
module cmos_mux2level_tb;
|
||||
// Parameters
|
||||
parameter SIZE_OF_MUX = 50; //---- MUX input size
|
||||
parameter SIZE_OF_SRAM = 16; //---- MUX input size
|
||||
parameter op_clk_period = 1; // [ns] half clock period
|
||||
parameter operating_period = SIZE_OF_MUX * 2 * op_clk_period; // [ns] One full clock period
|
||||
|
||||
// voltage sources
|
||||
wire [0:SIZE_OF_MUX-1] in;
|
||||
wire out;
|
||||
wire [0:SIZE_OF_SRAM-1] sram;
|
||||
wire [0:SIZE_OF_SRAM-1] sram_inv;
|
||||
// clocks
|
||||
wire op_clock;
|
||||
// registered ports
|
||||
reg op_clock_reg;
|
||||
reg [0:SIZE_OF_MUX-1] in_reg;
|
||||
reg [0:SIZE_OF_SRAM-1] sram_reg;
|
||||
reg [0:SIZE_OF_SRAM-1] sram_inv_reg;
|
||||
// Config done signal;
|
||||
reg config_done;
|
||||
// Temp register for rotating shift
|
||||
reg temp;
|
||||
|
||||
// Unit Under Test
|
||||
mux_2level_size50 U0 (in, out, sram, sram_inv);
|
||||
|
||||
// Task: assign inputs
|
||||
task op_mux_input;
|
||||
begin
|
||||
@(posedge op_clock);
|
||||
temp = in_reg[SIZE_OF_MUX-1];
|
||||
in_reg[1:SIZE_OF_MUX-1] = in_reg[0:SIZE_OF_MUX-2];
|
||||
in_reg[0] = temp;
|
||||
end
|
||||
endtask
|
||||
|
||||
// Configuration done signal
|
||||
initial
|
||||
begin
|
||||
config_done = 1'b1;
|
||||
end
|
||||
|
||||
// Operating clocks
|
||||
initial
|
||||
begin
|
||||
op_clock_reg = 1'b0;
|
||||
end
|
||||
always
|
||||
begin
|
||||
#op_clk_period op_clock_reg = ~op_clock_reg;
|
||||
end
|
||||
|
||||
// Programming and Operating clocks
|
||||
assign op_clock = op_clock_reg & config_done;
|
||||
|
||||
// Operating Phase
|
||||
initial
|
||||
begin
|
||||
in_reg = {SIZE_OF_MUX {1'b0}};
|
||||
in_reg[0] = 1'b1; // Last bit is 1 initially
|
||||
end
|
||||
always wait (config_done) // Only invoked when config_done is 1
|
||||
begin
|
||||
/* Update inputs */
|
||||
op_mux_input;
|
||||
end
|
||||
|
||||
// Wire ports
|
||||
assign in = in_reg;
|
||||
assign sram[0:7] = 8'b00010000;
|
||||
assign sram[8:15] = 8'b00010000;
|
||||
assign sram_inv = ~sram;
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
//------ Module: sram6T_blwl -----//
|
||||
//------ Verilog file: sram.v -----//
|
||||
//------ Author: Xifan TANG -----//
|
||||
module sram6T_blwl(
|
||||
//input read,
|
||||
//input nequalize,
|
||||
input din, // Data input
|
||||
output dout, // Data output
|
||||
output doutb, // Data output
|
||||
input bl, // Bit line control signal
|
||||
input wl, // Word line control signal
|
||||
input blb // Inverted Bit line control signal
|
||||
);
|
||||
//----- local variable need to be registered
|
||||
reg a;
|
||||
|
||||
//----- when wl is enabled, we can read in data from bl
|
||||
always @(bl, wl)
|
||||
begin
|
||||
//----- Cases to program internal memory bit
|
||||
//----- case 1: bl = 1, wl = 1, a -> 0
|
||||
if ((1'b1 == bl)&&(1'b1 == wl)) begin
|
||||
a <= 1'b1;
|
||||
end
|
||||
//----- case 2: bl = 0, wl = 1, a -> 0
|
||||
if ((1'b0 == bl)&&(1'b1 == wl)) begin
|
||||
a <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
// dout is short-wired to din
|
||||
assign dout = a;
|
||||
//---- doutb is always opposite to dout
|
||||
assign doutb = ~dout;
|
||||
`ifdef ENABLE_SIGNAL_INITIALIZATION
|
||||
initial begin
|
||||
$deposit(a, $random);
|
||||
end
|
||||
`endif
|
||||
endmodule
|
||||
|
||||
module sram6T_rram(
|
||||
input read,
|
||||
input nequalize,
|
||||
input din, // Data input
|
||||
output dout, // Data output
|
||||
output doutb, // Data output
|
||||
// !!! Port bit position should start from LSB to MSB
|
||||
// Follow this convention for BL/WLs in each module!
|
||||
input [0:2] bl, // Bit line control signal
|
||||
input [0:2] wl// Word line control signal
|
||||
);
|
||||
//----- local variable need to be registered
|
||||
//----- Modeling two RRAMs
|
||||
reg r0, r1;
|
||||
|
||||
always @(bl[0], wl[2])
|
||||
begin
|
||||
//----- Cases to program r0
|
||||
//----- case 1: bl[0] = 1, wl[2] = 1, r0 -> 0
|
||||
if ((1'b1 == bl[0])&&(1'b1 == wl[2])) begin
|
||||
r0 <= 0;
|
||||
end
|
||||
end
|
||||
|
||||
always @(bl[2], wl[0])
|
||||
begin
|
||||
//----- case 2: bl[2] = 1, wl[0] = 1, r0 -> 1
|
||||
if ((1'b1 == bl[2])&&(1'b1 == wl[0])) begin
|
||||
r0 <= 1;
|
||||
end
|
||||
end
|
||||
|
||||
always @(bl[1], wl[2])
|
||||
begin
|
||||
//----- Cases to program r1
|
||||
//----- case 1: bl[1] = 1, wl[2] = 1, r0 -> 0
|
||||
if ((1'b1 == bl[1])&&(1'b1 == wl[2])) begin
|
||||
r1 <= 0;
|
||||
end
|
||||
end
|
||||
|
||||
always @( bl[2], wl[1])
|
||||
begin
|
||||
//----- case 2: bl[2] = 1, wl[1] = 1, r0 -> 1
|
||||
if ((1'b1 == bl[2])&&(1'b1 == wl[1])) begin
|
||||
r1 <= 1;
|
||||
end
|
||||
end
|
||||
|
||||
// dout is r0 AND r1
|
||||
assign dout = r0 | (~r1);
|
||||
|
||||
//---- doutb is always opposite to dout
|
||||
assign doutb = ~dout;
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,88 @@
|
|||
//-----------------------------------------------------
|
||||
// Design Name : testbench for static_dff
|
||||
// File Name : ff_tb.v
|
||||
// Function : D flip-flop with asyn reset and set
|
||||
// Coder : Xifan TANG
|
||||
//-----------------------------------------------------
|
||||
//----- Time scale: simulation time step and accuracy -----
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
module sram6T_rram_tb;
|
||||
// voltage sources
|
||||
wire read;
|
||||
wire nequalize;
|
||||
wire din;
|
||||
wire dout;
|
||||
wire doutb;
|
||||
reg [0:2] bl;
|
||||
reg [0:2] wl;
|
||||
reg prog_clock;
|
||||
|
||||
// Parameters
|
||||
parameter prog_clk_period = 2; // [ns] a full clock period
|
||||
|
||||
// Unit Under Test
|
||||
sram6T_rram U0 (read, nequalize, din, dout, doutb, bl, wl);
|
||||
|
||||
// Voltage stimuli
|
||||
// read : alway disabled
|
||||
assign read = 1'b0;
|
||||
|
||||
// nequalize: always disabled
|
||||
assign nequalize = 1'b1;
|
||||
|
||||
// din: always disabled
|
||||
assign din = 1'b0;
|
||||
|
||||
// Programming clock
|
||||
initial
|
||||
begin
|
||||
prog_clock = 1'b0;
|
||||
end
|
||||
always
|
||||
begin
|
||||
#prog_clk_period prog_clock = ~prog_clock;
|
||||
end
|
||||
|
||||
// Task: assign BL and WL values
|
||||
task prog_blwl;
|
||||
input [0:2] bl_val;
|
||||
input [0:2] wl_val;
|
||||
begin
|
||||
@(posedge prog_clock);
|
||||
bl = bl_val;
|
||||
wl = wl_val;
|
||||
end
|
||||
endtask
|
||||
|
||||
// Test two cases:
|
||||
// 1. Program dout to 0
|
||||
// bl[0] = 1, wl[2] = 1
|
||||
// bl[2] = 1, wl[0] = 1
|
||||
// 2. Program dout to 1
|
||||
// bl[1] = 1, wl[2] = 1
|
||||
// bl[2] = 1, wl[1] = 1
|
||||
initial
|
||||
begin
|
||||
bl = 3'b000;
|
||||
wl = 3'b000;
|
||||
// 1. Program dout to 0
|
||||
// bl[0] = 1, wl[2] = 1
|
||||
prog_blwl(3'b100, 3'b001);
|
||||
// bl[2] = 1, wl[0] = 1
|
||||
prog_blwl(3'b001, 3'b100);
|
||||
// 2. Program dout to 1
|
||||
// bl[1] = 1, wl[2] = 1
|
||||
prog_blwl(3'b010, 3'b001);
|
||||
// bl[2] = 1, wl[1] = 1
|
||||
prog_blwl(3'b100, 3'b010);
|
||||
// 3. Program dout to 0
|
||||
// bl[0] = 1, wl[2] = 1
|
||||
prog_blwl(3'b100, 3'b001);
|
||||
// bl[2] = 1, wl[0] = 1
|
||||
prog_blwl(3'b001, 3'b100);
|
||||
end
|
||||
|
||||
// Outputs are wired to dout and doutb
|
||||
|
||||
endmodule
|
|
@ -0,0 +1,41 @@
|
|||
#!/bin/bash
|
||||
# Example of how to run vpr
|
||||
|
||||
# Set variables
|
||||
# For FPGA-Verilog ONLY
|
||||
benchmark="test_modes"
|
||||
OpenFPGA_path="OPENFPGAPATHKEYWORD"
|
||||
verilog_output_dirname="${benchmark}_Verilog"
|
||||
verilog_output_dirpath="$PWD"
|
||||
tech_file="${OpenFPGA_path}/fpga_flow/tech/PTM_45nm/45nm.xml"
|
||||
# VPR critical inputs
|
||||
template_arch_xml_file="${OpenFPGA_path}/fpga_flow/arch/template/k6_N10_sram_chain_HC_template.xml"
|
||||
arch_xml_file="${OpenFPGA_path}/fpga_flow/arch/generated/k6_N10_sram_chain_HC.xml"
|
||||
blif_file="${OpenFPGA_path}/fpga_flow/benchmarks/Blif/Test_Modes/$benchmark.blif"
|
||||
act_file="${OpenFPGA_path}/fpga_flow/benchmarks/Blif/Test_Modes/$benchmark.act "
|
||||
verilog_reference="${OpenFPGA_path}/fpga_flow/benchmarks/Verilog/Test_Modes/$benchmark.v"
|
||||
vpr_route_chan_width="300"
|
||||
fpga_flow_script="${OpenFPGA_path}/fpga_flow/scripts"
|
||||
ff_path="$vpr_path/VerilogNetlists/ff.v"
|
||||
new_ff_path="$verilog_output_dirpath/$verilog_output_dirname/SRC/ff.v"
|
||||
ff_keyword="GENERATED_DIR_KEYWORD"
|
||||
ff_include_path="$verilog_output_dirpath/$verilog_output_dirname"
|
||||
arch_ff_keyword="FFPATHKEYWORD"
|
||||
|
||||
# Remove previous designs
|
||||
rm -rf $verilog_output_dirpath/$verilog_output_dirname
|
||||
|
||||
mkdir -p ${OpenFPGA_path}/fpga_flow/arch/generated
|
||||
|
||||
cd $fpga_flow_scripts
|
||||
perl rewrite_path_in_file.pl -i $template_arch_xml_file -o $arch_xml_file
|
||||
perl rewrite_path_in_file.pl -i $arch_xml_file -k $arch_ff_keyword $new_ff_path
|
||||
cd -
|
||||
|
||||
# Run VPR
|
||||
echo "./vpr $arch_xml_file $blif_file --full_stats --nodisp --activity_file $act_file --fpga_verilog --fpga_verilog_dir $verilog_output_dirpath/$verilog_output_dirname --fpga_x2p_rename_illegal_port --fpga_bitstream_generator --fpga_verilog_print_top_testbench --fpga_verilog_print_input_blif_testbench --fpga_verilog_include_timing --fpga_verilog_include_signal_init --fpga_verilog_print_formal_verification_top_netlist --fpga_verilog_print_autocheck_top_testbench $verilog_reference --fpga_verilog_print_user_defined_template --route_chan_width $vpr_route_chan_width --fpga_verilog_include_icarus_simulator --fpga_verilog_print_report_timing_tcl --power --tech_properties $tech_file --fpga_verilog_print_sdc_pnr --fpga_verilog_print_sdc_analysis --fpga_x2p_compact_routing_hierarchy #--fpga_verilog_explicit_mapping"
|
||||
./vpr $arch_xml_file $blif_file --full_stats --nodisp --activity_file $act_file --fpga_verilog --fpga_verilog_dir $verilog_output_dirpath/$verilog_output_dirname --fpga_x2p_rename_illegal_port --fpga_bitstream_generator --fpga_verilog_print_top_testbench --fpga_verilog_print_input_blif_testbench --fpga_verilog_include_timing --fpga_verilog_include_signal_init --fpga_verilog_print_formal_verification_top_netlist --fpga_verilog_print_autocheck_top_testbench $verilog_reference --fpga_verilog_print_user_defined_template --route_chan_width $vpr_route_chan_width --fpga_verilog_include_icarus_simulator --fpga_verilog_print_report_timing_tcl --power --tech_properties $tech_file --fpga_verilog_print_sdc_pnr --fpga_verilog_print_sdc_analysis --fpga_x2p_compact_routing_hierarchy #--fpga_verilog_explicit_mapping
|
||||
|
||||
cd $fpga_flow_scripts
|
||||
perl rewrite_path_in_file.pl -i $ff_path -o $new_ff_path -k $ff_keyword $ff_include_path
|
||||
cd -
|
Loading…
Reference in New Issue