OTBN DV document
- Verify the OTBN processor by running dynamic simulations with a SV/UVM based testbench
- These simulations are grouped in tests listed in the DV plan below.
- Close code and functional coverage on the IP and all of its sub-modules
- Verify TileLink device protocol compliance with an SVA based testbench
OTBN, the OpenTitan Big Number accelerator, is a cryptographic accelerator. For detailed information on OTBN design features, see the OTBN HWIP technical specification.
OTBN testing makes use of a DPI-based model called
This is shown in the block diagram.
The dotted interfaces in the
otbn block are bound in by the model to access internal signals (register file and memory contents).
Top level testbench
The top-level testbench is located at
This instantiates the OTBN DUT module
OTBN has the following interfaces:
- A Clock and reset interface
- A TileLink interface. OTBN is a TL device, which expects to communicate with a TL host. In the OpenTitan SoC, this will be the Ibex core.
- An idle signal,
- Two interrupts
- An alert interface
The idle and interrupt signals are modelled with the basic
As well as instantiating OTBN, the testbench also instantiates an
This module wraps an ISS (instruction set simulator) subprocess and performs checks to make sure that OTBN behaves the same as the ISS.
The model communicates with the testbench through an
otbn_model_if interface, which is monitored by the
otbn_model_agent, described below.
OTBN model agent
The model agent is instantiated by the testbench to monitor the OTBN model.
It is a passive agent (essentially just a monitor): the inputs to the model are set in
The monitor for the agent generates transactions when it sees a start signal or a done signal.
The start signal is important because we “cheat” and pull it out of the DUT. To make sure that the processor is starting when we expect, we check start transactions against TL writes in the scoreboard.
The main reference model for OTBN is the instruction set simulator (ISS), which is run as a subprocess by DPI code inside
This Python-based simulator can be found at
When testing OTBN, we are careful to distinguish between
- behaviour that can be triggered by particular instruction streams
- behaviour that is triggered by particular external stimuli (register writes; surprise resets etc.)
Testing lots of different instruction streams doesn’t really use the UVM machinery, so we have a “pre-DV” phase of testing that generates constrained-random instruction streams (as ELF binaries) and runs a simple block-level simulation on each to check that the RTL matches the model. The idea is that this is much quicker for designers to use to smoke-test proposed changes, and can be run with Verilator, so it doesn’t require an EDA tool licence. This pre-DV phase cannot drive sign-off, but it does use much of the same tooling.
Once we are running full DV tests, we re-use this work, by using the same collection of randomised instruction streams and randomly picking from them for most of the sequences.
At the moment, the full DV tests create binaries on the fly by running
This results in one or more ELF files in a directory, which the simulation then picks from at random.
The pre-DV testing doesn’t address external stimuli like resets or TileLink-based register accesses. These are driven by specialised test sequences, described below.
The test sequences can be found in
The basic test sequence (
otbn_base_vseq) loads the instruction stream from a randomly chosen binary (see above), configures OTBN and then lets it run to completion.
More specialized sequences include things like multiple runs, register accesses during operation (which should fail) and memory corruption. We also check things like the correct operation of the interrupt registers.
TODO: Functional coverage points are not yet defined.
Much of the checking for these tests is actually performed in
otbn_core_model, which ensures that the RTL and ISS have the same behaviour.
However, the scoreboard does have some checks, to ensure that interrupt and idle signals are high at the expected times.
Core TLUL protocol assertions are checked by binding the TL-UL protocol checker into the design.
Outputs are also checked for
'X values by assertions in the design RTL.
The design RTL contains other assertions defined by the designers, which will be checked in simulation (and won’t have been checked by the pre-DV Verilator simulations).
otbn_idle_checker checks that the
idle_o output correctly matches the running state that you’d expect, based on writes to the
CMD register and responses that will appear in the
Building and running tests
Tests can be run with
The link gives details of the tool’s features and command line arguments.
To run a basic smoke test, go to the top of the repository and run:
$ util/dvsim/dvsim.py hw/ip/otbn/dv/uvm/otbn_sim_cfg.hjson -i otbn_smoke
Smoke test, running a single fixed binary
This runs the binary from otbn/dv/smoke/smoke_test.s, which is designed to check most of the implemented instructions. The unchanging binary should mean this basic test is particularly appropriate for CI.
Run a single randomly-chosen binary
This test drives the main bulk of OTBN testing. It picks a random binary from a pre-generated set and runs it, comparing against the model. We'll run this with a large number of seeds and use functional coverage to track when verification of the internals of the core is done.
Sometimes enable the "done" interrupt to check that it and the error interrupt work correctly.
Verify the reset values as indicated in the RAL specification.
Verify accessibility of CSRs as indicated in the RAL specification.
Verify no aliasing within individual bits of a CSR.
Verify no aliasing within the CSR address space.
Verify random reset during CSR/memory access.
Verify accessibility of all memories in the design.
Verify partial-accessibility of all memories in the design.
Run two binaries, resetting the first at an arbitrary time
Running another binary after a sudden and unexpected reset via the rst_ni signal will check that all state is properly re-initialized after a reset. We'd expect X-propagation checks to catch most problems like this, but an explicit reset sequence also adds the relevant FSM/toggle coverage.
Inject ECC errors into DMEM and IMEM and expect an alert
Run sequences back-to-back
This runs several sequences back-to-back, without resets between them. This should catch initialisation problems where not all state is cleared between programs when there's no reset.
Run multiple sequences back-to-back while making invalid TL accesses at the same time.
Verify common intr_test CSRs that allows SW to mock-inject interrupts.
Access out of bounds address and verify correctness of response / behavior
Drive unsupported requests via TL interface and verify correctness of response / behavior. Below error cases are tested
Drive back-to-back requests without waiting for response to ensure there is one transaction outstanding within the TL device. Also, verify one outstanding when back- to-back accesses are made to the same address.
Access CSR with one or more bytes of data For read, expect to return all word value of the CSR For write, enabling bytes should cover all CSR valid fields