Overview
Stages of harness generation
- define tracing macros (if enabled)
- chip reset (based on pnr collateral)
- configuration (based on use_jtag)
- (optional) verify config (use_jtag only)
- main loop
- stream input file data to input pads
- step the global clock
- stream output pad values to output files
Details
Generating the harness is divided into the metaprogramming of 11 specific program components:
- Includes
- trace setup (
--traceonly) - file setup
- jtag setup
- chip init
- chip reset
- chip stalling (
--use-jtagonly) - running configuration
- verifying configuration (
--use-jtagand--verify-configonly) - chip unstalling/reset
- clock switch (
--use-jtagonly) - running test
Includes
This sets up include files used by the harness. All generated test benches will
include verilator's header file (verilated.h) and various standard library
headers (<iostream>, stdint.h, <fstream>, printf.h). The one
dynamically generated include is for the verilator module V{wrapper_name}.h
where wrapper_name corresponds to the name of the top module in the generated
Verilog.
Trace Setup
If --trace is enabled, the harness will append verilated_vcd_c.h to the
include files, as well as some code to setup the tracing logic. In particular,
it calls the verilator function Verilated::traceEverOn(true) to configure
verilator to perform tracing. Then, it sets up a VCD file for verilator to dump
the trace too, configured by the --trace-file-name parameter, and adds the
code to close the trace file during cleanup. It also sets up a time_step
variable used to track the current time step during test execution. Finally,
the next and step macros are redefined to include the required method calls
to dump the current state of the simulation to the trace file for each clock
step.
File Setup
This code handles the opening of fstream objects for the input and output
files specified by the PnR collateral. The --input-chunk-size and
--output-chunk-size parameters specify the size in bits of the data in the
input and output files.
JTAG Setup
If --use-jtag is enabled, the harness includes jtagdriver.h which defines
the interface to the C++ JTAG driver. It also adds an instantiation of the
JTAGDriver object which will be used by the configuration code.
Chip Init
This phase initializes the clk_pad and reset_pad inputs to be zero. If
--use-jtag is enabled, it also calls jtag.init() which initializes the jtag
ports to zero. Then, it calls eval once.
Chip Reset
This phase resets the chip by setting reset_pad to 1, calling eval, setting
reset_pad to 0, and calling eval. If --use-jtag is enabled, it will
reset the chip using the trst_n port, and then bring up the JTAG clock by
setting tck to 1 and stepping twice.
Chip Stalling (--use-jtag only)
If --use-jtag is enabled, this phase will stall the chip by writing 0xF to
the OP_WRITE_STALL register of the JTAG TAP.
Running Configuration
This phase loops over the bitstream and sends the commands to configure the
chip. If --use-jtag is enabled, it will use the JTAGDriver to configure
the chip with the write_config method. Otherwise, it will directly poke the
config_data_in and config_addr_in ports and step the clock twice.
Verifying configuration (--use-jtag and --verify-config only)
If --use-jtag and --verify-config are enabled, this phase will read the
configuration state back (inverse of the configuration phase) to verify that
the chip has been properly configured through the global controller.
Chip Unstalling/Reset
If --use-jtag is enabled, this phase will unstall the chip by writing 0x0
to the OP_WRITE_STALL register of the JTAG TAP.
Otherwise, it sets the reset_in_pad provided by the PnR collateral to 1,
which resets the chip state.
Clock Switch (--use-jtag only)
If --use-jtag is enabled, this phase switches the clock from the test clock
(used for configuration) to the fast clock (used for normal operation). The
JTAGDriver provides a method switch_to_fast.
Running Test
To actually run the test, the harness generates a loop that streams data from
the input files, pokes the values onto the input pads specified by the PnR
collateral, steps the clock, streams the output pad values to the output files,
and steps the clock. This loop runs until any of the input file streams close
(run out of data).