Creating Spypads Using XML Syntax
=================================
Introduction
~~~~~~~~~~~~
**In this tutorial, we will**
- Show the XML Syntax for Global Outputs
- Showcase an example with Spypads
- Modify an existing architecture to incorporate Spypads
- Verify correctness through GTKWave
Through this tutorial, we will show how to create Spypads in OpenFPGA.
Spypads are physical output pins on a FPGA chip through which you can read out internal signals when doing silicon-level debugging. The XML syntax for spypads and other
global signals can be found on our :ref:`circuit_library` documentation page.
To create a spypad, the ``port type`` needs to be set to **output** and ``is_global`` and ``is_io`` need to be set to **true**:
.. code-block:: xml
When the port is syntactically correct, the outputs are independently wired from different instances to separated FPGA outputs and would physically look like :ref:`fig_gpout_ports`
Pre-Built Spypads
~~~~~~~~~~~~~~~~~
An OpenFPGA architecture file that contains spypads and has a task that references it is the `k6_frac_N10_adder_register_scan_chain_depop50_spypad_40nm_openfpga.xml `_
file. We can view ``k6_frac_N10_adder_register_scan_chain_depop50_spypad_40nm_openfpga.xml`` by entering the following command at the root directory of OpenFPGA:
.. code-block:: bash
emacs openfpga_flow/openfpga_arch/k6_frac_N10_adder_register_scan_chain_depop50_spypad_40nm_openfpga.xml
In this architecture file, the output ports of a 6-input Look Up Table (LUT) are defined as spypads using the XML syntax ``is_global`` and ``is_io``. As a result, all of the outputs from the 6-input LUT will be visible in the top-level module. The output ports to the 6-input LUT are declared from **LINE181** to **LINE183** and belong to the ``frac_lut6_spypad`` ``circuit_model`` that begins at **LINE172**.
.. code-block:: xml
LINE181
LINE182
LINE183
The spypads are instantiated in the top-level verilog module ``fpga_top.v``. ``fpga_top.v`` is automatically generated when we run our task from the OpenFPGA root
directory. However, we need to modify the task configuration file to run the **full testbench** instead of the **formal testbench** to view the spypads' waveforms in
GTKWave.
.. note:: To read about the differences between the **formal testbench** and the **full testbench**, please visit our page on testbenches: :ref:`testbench`.
To open the task configuration file, run this command from the root directory of OpenFPGA:
.. code-block:: bash
emacs openfpga_flow/tasks/fpga_verilog/spypad/config/task.conf
The last line of the task configuration file (**LINE44**) sets the **formal testbench** to be the desired testbench. To use the **full testbench**, comment out **LINE44**.
The file will look like this when finished:
.. code-block:: python
:linenos:
:emphasize-lines: 44
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# Configuration file for running experiments
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs
# Each job execute fpga_flow script on combination of architecture & benchmark
# timeout_each_job is timeout for each job
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
[GENERAL]
run_engine=openfpga_shell
power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml
power_analysis = true
spice_output=false
verilog_output=true
timeout_each_job = 20*60
fpga_flow=vpr_blif
[OpenFPGA_SHELL]
openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/example_script.openfpga
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k6_frac_N10_adder_register_scan_chain_depop50_spypad_40nm_openfpga.xml
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
[ARCHITECTURES]
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k6_frac_N10_tileable_adder_register_scan_chain_depop50_spypad_40nm.xml
[BENCHMARKS]
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.blif
# Cannot pass automatically. Need change in .v file to match ports
# When passed, we can replace the and2 benchmark
#bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/test_mode_low/test_mode_low.blif
[SYNTHESIS_PARAM]
bench0_top = and2
bench0_act = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.act
bench0_verilog = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.v
#bench0_top = test_mode_low
#bench0_act = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/test_mode_low/test_mode_low.act
#bench0_verilog = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/test_mode_low/test_mode_low.v
bench0_chan_width = 300
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
end_flow_with_test=
#vpr_fpga_verilog_formal_verification_top_netlist=
Our OpenFPGA task will now run the full testbench. We run the task with the following command from the root directory of OpenFPGA:
.. code-block:: bash
python3 openfpga_flow/scripts/run_fpga_task.py fpga_verilog/spypad --debug --show_thread_logs
.. note:: Python 3.8 or later is required to run this task
We can now see the instantiation of these spypads in ``fpga_top.v`` and ``luts.v``. We will start by viewing ``luts.v`` with the following command:
.. code-block:: bash
emacs openfpga_flow/tasks/fpga_verilog/spypad/latest/k6_frac_N10_tileable_adder_register_scan_chain_depop50_spypad_40nm/and2/MIN_ROUTE_CHAN_WIDTH/SRC/sub_module/luts.verilog
The spypads are coming from the ``frac_lut6_spypad`` circuit model. In ``luts.v``, the ``frac_lut6_spypad`` module is defined around **LINE150** and looks as follows:
.. code-block:: verilog
module frac_lut6_spypad(in,
sram,
sram_inv,
mode,
mode_inv,
lut4_out,
lut5_out,
lut6_out);
//----- INPUT PORTS -----
input [0:5] in;
//----- INPUT PORTS -----
input [0:63] sram;
//----- INPUT PORTS -----
input [0:63] sram_inv;
//----- INPUT PORTS -----
input [0:1] mode;
//----- INPUT PORTS -----
input [0:1] mode_inv;
//----- OUTPUT PORTS -----
output [0:3] lut4_out;
//----- OUTPUT PORTS -----
output [0:1] lut5_out;
//----- OUTPUT PORTS -----
output [0:0] lut6_out;
The ``fpga_top.v`` file has some similarities. We can view the ``fpga_top.v`` file by running the following command:
.. code-block:: bash
emacs openfpga_flow/tasks/fpga_verilog/spypad/latest/k6_frac_N10_tileable_adder_register_scan_chain_depop50_spypad_40nm/and2/MIN_ROUTE_CHAN_WIDTH/SRC/fpga_top.v
If we look at the module definition and ports of ``fpga_top.v`` we should see the following:
.. code-block:: verilog
module fpga_top(pReset,
prog_clk,
TESTEN,
set,
reset,
clk,
gfpga_pad_frac_lut6_spypad_lut4_out,
gfpga_pad_frac_lut6_spypad_lut5_out,
gfpga_pad_frac_lut6_spypad_lut6_out,
gfpga_pad_GPIO_PAD,
ccff_head,
ccff_tail);
//----- GLOBAL PORTS -----
input [0:0] pReset;
//----- GLOBAL PORTS -----
input [0:0] prog_clk;
//----- GLOBAL PORTS -----
input [0:0] TESTEN;
//----- GLOBAL PORTS -----
input [0:0] set;
//----- GLOBAL PORTS -----
input [0:0] reset;
//----- GLOBAL PORTS -----
input [0:0] clk;
//----- GPOUT PORTS -----
output [0:3] gfpga_pad_frac_lut6_spypad_lut4_out;
//----- GPOUT PORTS -----
output [0:1] gfpga_pad_frac_lut6_spypad_lut5_out;
//----- GPOUT PORTS -----
output [0:0] gfpga_pad_frac_lut6_spypad_lut6_out;
//----- GPIO PORTS -----
inout [0:7] gfpga_pad_GPIO_PAD;
//----- INPUT PORTS -----
input [0:0] ccff_head;
//----- OUTPUT PORTS -----
output [0:0] ccff_tail;
Using :ref:`fig_gpout_ports` as a guide, we can relate our task like :numref:`fig_gpout_example`
.. _fig_gpout_example:
.. figure:: ./figures/lut6_Example_Spypad.svg
:scale: 100%
Diagram for ``frac_lut6_spypad``
We can view testbench waveforms with GTKWave by running the following command from the root directory:
.. code-block:: bash
gtkwave openfpga_flow/tasks/fpga_verilog/spypad/latest/k6_frac_N10_tileable_adder_register_scan_chain_depop50_spypad_40nm/and2/MIN_ROUTE_CHAN_WIDTH/and2_formal.vcd &
.. note:: Information on GTKWave can be found on our documentation page located here: :ref:`from_verilog_to_verification`
The waveforms will appear similar to :numref:`fig_spypad_waves`
.. _fig_spypad_waves:
.. figure:: ./figures/spypad_waveforms.png
:scale: 100%
Spypad Waveforms
Building Spypads
~~~~~~~~~~~~~~~~
We will modify the `k6_frac_N10_adder_chain_40nm_openfpga.xml `_ file found in OpenFPGA to expose the **sumout** output from the **ADDF** module. We can start modifying
the file by running the following command:
.. code-block:: bash
emacs openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_40nm_openfpga.xml
Replace **LINE214** with the following:
.. code-block:: xml
**sumout** is now a global output. **sumout** will show up in the ``fpga_top.v`` file and will have waveforms in GTKWave if we run the **full testbench**. To run the
**full testbench**, we have to modify the ``hard_adder`` configuration file:
.. code-block:: bash
emacs openfpga_flow/tasks/fpga_verilog/adder/hard_adder/config/task.conf
Comment out the last line of the file to run the **full testbench**:
.. code-block:: python
#vpr_fpga_verilog_formal_verification_top_netlist=
We now run the task to see our changes:
.. code-block:: bash
python3 openfpga_flow/scripts/run_fpga_task.py fpga_verilog/adder/hard_adder --debug --show_thread_logs
We can view the global ports in ``fpga_top.v`` by running the following command:
.. code-block:: bash
emacs openfpga_flow/tasks/fpga_verilog/adder/hard_adder/run064/k6_frac_N10_tileable_adder_chain_40nm/and2/MIN_ROUTE_CHAN_WIDTH/SRC/fpga_top.v
The ``fpga_top.v`` should have the following in its module definition:
.. code-block:: verilog
module fpga_top(pReset,
prog_clk,
set,
reset,
clk,
gfpga_pad_ADDF_sumout,
gfpga_pad_GPIO_PAD,
ccff_head,
ccff_tail);
//----- GLOBAL PORTS -----
input [0:0] pReset;
//----- GLOBAL PORTS -----
input [0:0] prog_clk;
//----- GLOBAL PORTS -----
input [0:0] set;
//----- GLOBAL PORTS -----
input [0:0] reset;
//----- GLOBAL PORTS -----
input [0:0] clk;
//----- GPOUT PORTS -----
output [0:19] gfpga_pad_ADDF_sumout;
The architecture will now look like :numref:`fig_addf_example`
.. _fig_addf_example:
.. figure:: ./figures/ADDF_Example_Spypad.svg
:scale: 100%
Diagram for ``ADDF``
We can view the waveform by running GTKWave:
.. code-block:: bash
gtkwave openfpga_flow/tasks/fpga_verilog/adder/hard_adder/latest/k6_frac_N10_tileable_adder_chain_40nm/and2/MIN_ROUTE_CHAN_WIDTH/and2_formal.vcd &
The waveform should have some changes to its value. An example of what it may look like is displayed in :numref:`fig_spy_adder`
.. _fig_spy_adder:
.. figure:: ./figures/spyadder_waveform.png
:scale: 100%
Sumout Waveform
Conclusion
~~~~~~~~~~
In this tutorial, we have shown how to build spypads into OpenFPGA Architectures using XML Syntax. If you have any issues, feel free to :ref:`contact` us.