AON Timer DV Document
Goals
- DV
- Verify the always-on timer (AON Timer) by running dynamic simulations with a SV/UVM based testbench
- Develop and run all tests based on the testplan below towards closing code and functional coverage on the IP and all of its sub-modules
- FPV
- Verify TileLink device protocol compliance with an SVA based testbench
Current status
Design features
The AON timer is documented in the AON Timer HWIP technical specification.
Testbench architecture
The testbench is based on the CIP testbench architecture.
Block diagram
Top-level testbench
The block’s testbench is located at hw/ip/aon_timer/dv/tb/tb.sv
.
It instantiates the aon_timer
DUT module, defined at hw/ip/aon_timer/rtl/aon_timer.sv
.
In addition, it instantiates the following interfaces, connects them to the DUT and registers their handles in uvm_config_db
:
- A clock and reset interface for the fast clock
- A clock and reset interface for the AON clock
- A TileLink host interface The AON timer exposes a TL device. Here, the testbench is acting as the host CPU; in the OpenTitan SoC, this will be the Ibex core.
- Two interrupts (wakeup timer; watchdog bark) in the fast clock domain
- Two interrupts (wakeup timer; watchdog bite) in the AON clock domain
- The sleep mode input
- The core interface (see below).
The interrupts and sleep mode input are modelled with the basic pins_if
interface.
The AON timer uses three clock domains (async
, clk_i
and clk_aon_i
), with synchronisation logic between them.
The following diagram shows the different inputs and outputs for the module and in which clock domain each resides.
To model this accurately without having to precisely model the timing of the synchronisation logic, the testbench is split into two pieces.
The first piece has a precise model of the AON timer core and checks that the DUT respects it.
The second piece has an approximate timing model and checks forwarding between the async, fast and slow clock domains.
These pieces are connected through a bound-in interface, which observes signals on the aon_timer_core
instance.
This core interface is bound into the design as u_core_if
and is used to passively monitor the signals coming in and out of the AON Timer Core block in this diagram.
TileLink agent
In order to communicate through the register interface, the testbench uses the tl_agent that is instantiated in the CIP base environment. This is also used by generic test sequences to exercise the register interface.
UVM RAL Model
The aon_timer
RAL model is created with the ralgen
FuseSoC generator script automatically when the simulation is at the build stage.
It can be created manually by invoking regtool
.
Running
util/regtool.py -s -t . hw/ip/aon_timer/data/aon_timer.hjson
will generate aon_timer_ral_pkg.core
and aon_timer_ral_pkg.sv
in the current directory.
Stimulus strategy
We want to see timers expire without waiting too long, but we also want to check the counter for large values. To get this right, we normally set up tests as follows:
- Pick a threshold value
- Pick a start count slightly below the threshold value
Occasionally, we’ll pick a start count above the threshold value, to make sure nothing triggers when it shouldn’t. To ensure that we check wrap-around behaviour and see toggles on counter bits, we are careful to pick threshold values more often if they are near zero, the maximum value, or powers of two.
Since the two timers are essentially independent, we use two test sequences, driving them separately.
Test sequences
The test sequences can be found in hw/ip/aon_timer/dv/env/seq_lib
.
The basic test virtual sequence aon_timer_base_vseq
configures the block in a valid initial state, but doesn’t enable either timer.
This is used as a base class for automated tests like the CSR tests.
The smoke sequence initializes both timers and starts them with random threshold values configured. After that it waits until an interrupt is seen and clears everything before shutting down.
The lock sequence tries to change the configuration of the watchdog timer while it is locked by software.
Stress sequence tries to change all configurations while running.
Functional coverage
To ensure high quality constrained random stimulus, it is necessary to develop a functional coverage model. The following cover points have been developed to prove that the test intent has been adequately met.
prescale_cp
: Includes possible values for the prescale register of wakeup timer.
bark_thold_cp
: Includes bark threshold configurations of watchdog timer.
bite_thold_cp
: Includes bite threshold configurations of watchdog timer.
wkup_thold_cp
: Includes threshold configurations of wakeup timer.
wkup_cause_cp
: Makes sure if we ever clear the wakeup interrupt by writing to WKUP_CAUSE
register.
wdog_regwen_cp
: Makes sure if the locking feature of watchdog timer is enabled in any test.
pause_in_sleep_cp
: Makes sure if the pause in sleep mode feature of watchdog timer is enabled in any test.
Self-checking strategy
Scoreboard
As described earlier in this document, the self-checking strategy is in two parts. The first part of the strategy is to track the domain crossing logic and check that values propagate across unmodified and reasonably quickly. This does not include precise modelling for the CDC timing.
The second part of the self-checking logic looks at the configuration registers of the timers. After calculating the amount of clock cycles, it starts checking for an interrupt from either wake-up timer or watchdog timer. Here, there is a single clock domain (the AON clock) and easily predictable behaviour. The scoreboard contains an exact model of how the interrupts generated from this specific configuration.
Putting the two parts of the scoreboard together gives a full checker for the block. An incoming configuration write will be tracked (with slightly flexible timing) through the CDC logic by the first part of the scoreboard. Once it takes effect in the core, the second part of the scoreboard will check that things behave correctly. Finally, outputs (in the form of configuration register updates or interrupts) will be tracked by the first part of the scoreboard as they go back through the CDC logic and, eventually, make it out to the top-level.
Assertions
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.
Building and running tests
Tests can be run with dvsim.py
.
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/aon_timer/dv/aon_timer_sim_cfg.hjson -i aon_timer_smoke
Testplan
Testpoints
Milestone | Name | Tests | Description |
---|---|---|---|
V1 | smoke | aon_timer_smoke | Smoke test initializes and starts AON Timer according to the programmers guide. Stimulus:
Checks:
|
V1 | csr_hw_reset | aon_timer_csr_hw_reset | Verify the reset values as indicated in the RAL specification.
|
V1 | csr_rw | aon_timer_csr_rw | Verify accessibility of CSRs as indicated in the RAL specification.
|
V1 | csr_bit_bash | aon_timer_csr_bit_bash | Verify no aliasing within individual bits of a CSR.
|
V1 | csr_aliasing | aon_timer_csr_aliasing | Verify no aliasing within the CSR address space.
|
V1 | csr_mem_rw_with_rand_reset | aon_timer_csr_mem_rw_with_rand_reset | Verify random reset during CSR/memory access.
|
V1 | regwen_csr_and_corresponding_lockable_csr | aon_timer_csr_rw aon_timer_csr_aliasing | Verify regwen CSR and its corresponding lockable CSRs.
Note:
This is only applicable if the block contains regwen and locakable CSRs. |
V1 | mem_walk | aon_timer_mem_walk | Verify accessibility of all memories in the design.
|
V1 | mem_partial_access | aon_timer_mem_partial_access | Verify partial-accessibility of all memories in the design.
|
V2 | prescaler | aon_timer_prescaler | Switch prescaler value at random times without locking configuration registers of watchdog timer. Stimulus:
Checks:
|
V2 | jump | aon_timer_jump | Change threshold values and prescaler value on random times without locking configuration registers of watchdog timer. Stimulus:
Checks:
|
V2 | stress_all | aon_timer_stress_all | This runs random sequences in succession. Randomly chooses from the following sequences:
|
V2 | intr_test | aon_timer_intr_test | Verify common intr_test CSRs that allows SW to mock-inject interrupts.
|
V2 | tl_d_oob_addr_access | aon_timer_tl_errors | Access out of bounds address and verify correctness of response / behavior |
V2 | tl_d_illegal_access | aon_timer_tl_errors | Drive unsupported requests via TL interface and verify correctness of response / behavior. Below error cases are tested bases on the [TLUL spec]({{< relref "hw/ip/tlul/doc/_index.md#explicit-error-cases" >}})
|
V2 | tl_d_outstanding_access | aon_timer_csr_hw_reset aon_timer_csr_rw aon_timer_csr_aliasing aon_timer_same_csr_outstanding | 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. |
V2 | tl_d_partial_access | aon_timer_csr_hw_reset aon_timer_csr_rw aon_timer_csr_aliasing aon_timer_same_csr_outstanding | 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. |
V2S | tl_intg_err | aon_timer_tl_intg_err aon_timer_sec_cm | Verify that the data integrity check violation generates an alert.
|
V2S | sec_cm_bus_integrity | Verify the countermeasure(s) BUS.INTEGRITY. | |
V3 | stress_all_with_rand_reset | aon_timer_stress_all_with_rand_reset | This test runs 3 parallel threads - stress_all, tl_errors and random reset. After reset is asserted, the test will read and check all valid CSR registers. |
Covergroups
Name | Description |
---|---|
regwen_val_when_new_value_written_cg | Cover each lockable reg field with these 2 cases:
This is only applicable if the block contains regwen and locakable CSRs. |
timer_cfg_cg | Includes possible values of all registers of AON timer. For 32b registers, bins are introduced in order to simplfy coverage. Maximum and minimum values are collected in a separate bin to guarantee that they are checked. 32 separate bins are auto-generated in order to distrubute values evenly. |
tl_errors_cg | Cover the following error cases on TL-UL bus:
|
tl_intg_err_cg | Cover all kinds of integrity errors (command, data or both) and cover number of error bits on each integrity check. Cover the kinds of integrity errors with byte enabled write on memory if applicable: Some memories store the integrity values. When there is a subword write, design re-calculate the integrity with full word data and update integrity in the memory. This coverage ensures that memory byte write has been issued and the related design logic has been verfied. |