Simulation of AVC Vectors
Hint
In order to use the simulation features documented in this section you have to install dumpling with the optional SIM extra:
pip install "./dumpling[SIM]"
Dumpling provides CocoTB integration to simulate generated vectors using CocoTB, a python based testbench framework that interacts with an RTL simulator of your choice. CocoTB performs a cosimulation of python coroutine based testbench code with the simulator through the VPI interface. Being an interpreted language, CocoTB is unarguably slower in simulation execution speed than native SystemVerilog testbenches but using Python as the testbench language has the key advantage of faster test development and a huge ecosystem of existing libraries that support the creation of more complex testpatterns.
While some knowledge in using CocoTB is certainly helpful, this section of dumpling’s documentation only tries to showcase how to simulate vectors generated by the dumpling library or vectors parsed from an existing AVC file.
The Setup
Executing a CocoTB testbench requires two key ingredients:
A Makefile that specifies RTL source files to compile, selects the simulator to use and provides additional parameters to the simulation environment.
2. A pythonmodule containing testbenches (python functions anotated with the
cocotb.test decorator) for CocoTB to execute once the Simulator
(e.g. Questasim, Xcelium, Verilator and many more) has started.
A sample Makefiles for simple RTL projects
#Simulator Selection and Arguments
TOPLEVEL_LANG=verilog
SIM=questa
SIM_ARGS= -suppress vsim-3009
#Source File Specification
VERILOG_SOURCES = ../../rtl/fancy_module.sv \
../../rtl/submodule/some_submodule.sv
TOPLEVEL = fancy_module
#Testbench Module
MODULE=my_cocotb_testbenches # The python module (*.py file) that
# contains the various testbenches
#With the Testcase variable we can instruct CocoTB to only execute
#one specific test instead of executing all testbenches found within
#the module
TESTCASE=simulate_avc
#This is the magic line that includes CocoTBs make targets
#It obviously requires CocoTB to be installed
include $(shell cocotb-config --makefiles)/Makefile.sim
CocoTB provides a number of additional Makefile variables that might be usefull for your particular setup. For these additional options we refer to the documentation of CocoTB.
A Sample Makefile for PULP based Projects using Questasim
For larger projects, listing each and every source file in the Makefile might be infeasible. Especially PULP based projects that use the IPApprox IP Dependency management tool would be very cumbersome to use otherwise. However, IPApprox already provides a simulation platform build flow for Questasim. With some additional makefile target and shell magic we can make leverage the existing Questasim libs without the need to manually specify all the required source files:
#Point to the directory of a pre-built RTL platform
#this is the directory were the questasim libs for all
#sub-ips are installed
PLATFORM_INSTALL = pulpissimo/install/modelsim_libs
#Simulator Selection and Arguments
TOPLEVEL_LANG=verilog
SIM=questa
#Add the precompiled libraries as dependencies
LIBS=$(shell find ${PLATFORM_INSTALL}/* -maxdepth 0 -type d -printf "-L %f ")
SIM_ARGS= ${LIBS} #Add your additional args here
#Source File Specification
#Only add the toplevel system verilog source file here
VERILOG_SOURCES = ../../rtl/pulp_chip.sv
TOPLEVEL = pulp_chip
#Register a custom simulation dependency target
CUSTOM_SIM_DEPS=vmap_libs
#Testbench Module
MODULE=my_cocotb_testbenches # The python module (*.py file) that
# contains the various testbenches
#This is the magic line that includes CocoTBs make targets
#It obviously requires CocoTB to be installed
include $(shell cocotb-config --makefiles)/Makefile.sim
#With the Testcase variable we can instruct CocoTB to only execute
#one specific test instead of executing all testbenches found within
#the module
TESTCASE=simulate_avc
#A custom target that maps all pre-compiled libs to the working directory
vmap_libs:
@for lib in $(shell find ${PLATFORM_INSTALL}/* -maxdepth 0 -type d -printf "%f "); do vmap $${lib} ${PLATFORM_INSTALL}/$${lib}; done
.. note::
We only specified the SystemVerilog source for the toplevel module. All other
submodules are defined in the libraries which are automatically mapped by the
``vmap_libs`` target and loaded with the ``LIBS`` variable that we supplied
to the ``SIM_ARGS`` variable.
The Testbench Module
The second of the aforementioned ingredients is a python module that contains CocoTB testbenches. Without going further into the details of how to write CocoTB testbenches, after all that is fairly well documented on their project website, we will show a minimal python module with a single testbench that assigns a number of static values to signals not present in our vector file (e.g. bootmode or chip reset) and provides a clock for clock pins and finally applies each vector of an AVC file to the DUT:
# File <my_cocotb_testbenches.py>
import cocotb
from cocotb.triggers import Timer, FallingEdge
from cocotb.result import TestFailure
from cocotb.clock import Clock
from pathlib import Path
from dumpling.Common.Simulation import CocotbVectorDriver
@cocotb.test()
async def test_avc_vectors(dut):
T_JTAG_PS = int(100e3)
T_APPL_DELAY = T_JTAG_PS * 0.5 # apply with falling edge T/2
T_ACQ_DELAY = T_JTAG_PS * 0.05 # sample T*0.05 before rising edge
clock_wavefun = CocotbVectorDriver.simple_clock_gen_wavefun(T_JTAG_PS, start_high=True, idle_low=True)
apl_wavefun = CocotbVectorDriver.simple_stimuli_appl_wavefun(appl_delay_ps=T_APPL_DELAY, wave_period_ps=T_JTAG_PS)
acq_wavefun = CocotbVectorDriver.simple_response_acq_wavefun(acq_delay_ps=T_ACQ_DELAY, wave_period_ps=T_JTAG_PS)
pins = {
'chip_reset': {'name': 'pad_reset_n', 'default': '0', 'wavefun': apl_wavefun},
'trst': {'name': 'pad_jtag_trst', 'default': '1', 'wavefun': apl_wavefun},
'tms': {'name': 'pad_jtag_tms', 'default': '0', 'wavefun': apl_wavefun},
'tck': {'name': 'pad_jtag_tck', 'default': '0', 'wavefun': clock_wavefun},
'tdi': {'name': 'pad_jtag_tdi', 'default': '0', 'wavefun': apl_wavefun},
'tdo': {'name': 'pad_jtag_tdo', 'default': 'X', 'wavefun': acq_wavefun}
}
driver = CocotbVectorDriver(pins, dut)
# Apply 32kHz reference clock
ref_clock = Clock(dut.pad_xtal_in, 31250, units='ns')
cocotb.fork(ref_clock.start())
# Assign value to signals
dut.pad_bootsel <= 1
dut.pad_fll_bypass <= 1
dut.pad_test_enable <= 0
dut.pad_scan_enable <= 0
# Assert reset
dut.pad_reset_n <= 0
await Timer(1, units='us') #Advance simulation time by 1us
dut.pad_reset_n <= 1
# Apply stimuli parsed from AVC vector file to device under test
passed = await driver.simulate_avc(Path("execute_hello_world.avc"))
if not passed:
raise TestFailure("Missmatch during application of avc file. Check error log above.")
As you can see from the example, applying vectors from an AVC file is fairly
easy. We just await on the completion of the
simulate_avc() coroutine
which will return the value True if there were zero missmatches between
simulated response and expected respone (from your AVC vectors) or False
otherwise.
Note
The CocotbVectorDriver also contains
functions to directly apply vectors generated by the dumpling library
witouth going through the roundabout of writing them to AVC. Just await
on the
apply_vectors()
coroutine supplying it with a list of vectors as argument.
Wavefunctions
If you went throught the above example carefully you noticed that the pin
declaration dictionary contained some the additional wavefun key. When using
dumpling for CocoTB Vector simulation this key is required. The value is a
coroutine function that is supposed to mimic the behavior of the ASIC Testers
Wavetable (thus the name “wavefunction”). Have a look at the docstring of
CocotbVectorDriver for additional
information on the nature of these functions. For now it suffices to say that
these function contain the logic how a pins state character is supposed to map
to a physical waveform or a sequence of signal sampling events. The
CocotbVectorDriver provides a selection
of reasonable default functions (e.g.
simple_clock_gen_wavefun()
) that can be used for most setups. If you are using a more complex wavetable
i.e. you are using X-mode you need to provide your own wavefunction so
CocotbVectorDriver knows how to
translate the vectors to actual waveforms. If you choose the right wavefunction
with the right parameters for stimuli application skew and response acquisition
skew (the little time delays you introduce in your timing ecquations to account
for setup and hold time) it is possible to have the time scale of the RTL
simulation perfectly match the ASIC testers timescale and every stimuli
application and response acquisition event is simulated excatly at the same time
like on the ASIC tester.
Postlayout Simulations
Certain bugs in the hardware might require debugging that goes beyond RTL
simulations. Switching to a Postlayout simulation with CocoTB is fairly easy:
just supply the postlayout netlist as a source file and add the postlayout sim
specific arguments (e.g. loading the standard cell libraries and performing SDF
annotation) to the SIM_ARGS Make Variable.