CLKMGR DV document
Goals
- DV
- Verify all CLKMGR IP features 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.
- Verify clock gating assertions.
Current status
Design features
The detailed information on CLKMGR design features is at CLKMGR HWIP technical specification.
Testbench architecture
CLKMGR testbench has been constructed based on the CIP testbench architecture.
Block diagram
Top level testbench
Top level testbench is located at hw/ip/clkmgr/dv/tb.sv
.
It instantiates the CLKMGR DUT module hw/top_earlgrey/ip/clkmgr/rtl/autogen/clkmgr.sv
.
In addition, it instantiates the following interfaces, connects them to the DUT and sets their handle into uvm_config_db
:
- Clock and reset interface
- TileLink host interface
- CLKMGR IOs:
hw/ip/clkmgr/dv/env/clkmgr_if.sv
The Devmode (pins_if
) interface should be connected once the RTL adds support for it.
Common DV utility components
The following utilities provide generic helper tasks and functions to perform activities that are common across the project:
Global types & methods
All common types and methods defined at the package level can be found in
clkmgr_env_pkg
. Some of them in use are:
localparam int NUM_PERI = 4;
localparam int NUM_TRANS = 5;
localparam int NUM_ALERTS = 2;
typedef logic [NUM_PERI-1:0] peri_enables_t;
typedef logic [NUM_TRANS-1:0] hintables_t;
typedef virtual clkmgr_if clkmgr_vif;
typedef virtual clk_rst_if clk_rst_vif;
typedef enum int {PeriDiv4, PeriDiv2, PeriIo, PeriUsb} peri_e;
typedef enum int {TransAes, TransHmac, TransKmac, TransOtbnIoDiv4, TransOtbnMain} trans_e;
TL_agent
CLKMGR testbench instantiates (already handled in CIP base env) tl_agent which provides the ability to drive and independently monitor random traffic via TL host interface into CLKMGR device.
UVM RAL Model
The CLKMGR 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
:
Stimulus strategy
This module is rather simple: the stimulus is just the external pins and the CSR updates. There are a couple stages for synchronization of the CSR updates for clock gating controls, but scanmode is used asynchronously. These go to the clock gating latches. The external pins controlling the external clock selection need no synchronization. The tests randomize the inputs and issue CSR updates affecting the specific functions being tested.
Test sequences
All test sequences reside in hw/ip/clkmgr/dv/env/seq_lib
.
The clkmgr_base_vseq
virtual sequence is extended from cip_base_vseq
and serves as a starting point.
All test sequences are extended from clkmgr_base_vseq
.
It provides commonly used handles, variables, functions and tasks that the test sequences can use or call.
Some of the most commonly used tasks / functions are as follows:
clkmgr_init
: Sets the frequencies of the various clocks.control_ip_clocks
: Turns on or off the input clocks based on the various clock enable and status ports to and from thepwrmgr
IP.
The sequence clkmgr_peri_vseq
randomizes the stimuli that drive the four peripheral clocks.
These clocks are mutually independent so they are tested in parallel.
They depend on the clk_enables
CSR, which has a dedicated enable for each peripheral clock, the pwrmgr’s <clk>_ip_clk_en
which has a dedicated bit controlling io
, main
, and usb
clocks, and scanmode_i
which is used asynchronously and also controls all.
The sequence runs a number of iterations, each randomizing all the above.
The sequence clkmgr_trans_vseq
randomizes the stimuli that drive the five transactional unit clocks.
These are also mutually independent so they are tested in parallel.
They depend on the clk_hints
CSR, which has a separate bit for each, <clk>_ip_clk_en
and scanmode_i
as in the peripheral clocks.
They also depend on the idle_i
input, which also has a separate bit for each unit.
Any unit’s idle_i
bit is clear when the unit is currently busy, and prevents its clock to be turned off until it becomes idle.
The sequence clkmgr_extclk_vseq
randomizes the stimuli that drive the external clock selection.
The selection is controlled by software if the extclk_ctrl.sel
CSR is prim_mubi_pkg::MuBi4True
, provided the lc_hw_debug_en_i
input is also set to lc_ctrl_pkg::On
.
Alternatively, the external clock is selected by the life cycle controller if the lc_ctrl_byp_req_i
input is lc_ctrl_pkg::On
.
When the external clock is selected and scanmode_i
is not set to prim_mubi_pkg::MuBi4True
, the clock dividers for the clk_io_div2 and clk_io_div4 output clocks are stepped down:
- If
lc_ctrl_byp_req_i
is on, or - If
extclk_ctrl.hi_speed_sel
CSR isprim_mubi_pkg::MuBi4True
, when the selection is enabled by software.
The sequence clkmgr_frequency_vseq
randomly programs the frequency measurement for each clock so its measurement is either okay, slow, or fast.
It checks the recoverable alerts trigger as expected when a measurement is not okay.
Functional coverage
To ensure high quality constrained random stimulus, it is necessary to develop a functional coverage model. The following covergroups have been developed to prove that the test intent has been adequately met:
- Covergroups for inputs to each software gated peripheral clock.
These are wrapped in class
clkmgr_peri_cg_wrap
and instantiated inclkmgr_env_cov
. - Covergroups for inputs to each transactional gated unit clock.
These are wrapped in class
clkmgr_trans_cg_wrap
and instantiated inclkmgr_env_cov
. - Covergroups for the outcome of each clock measurement.
These are wrapped in class
freq_measure_cg_wrap
and instantiated inclkmgr_env_cov
. - Covergroup for the external clock selection logic:
extclk_cg
inclkmgr_env_cov
.
See more detailed description at hw/ip/clkmgr/data/clkmgr_testplan.hjson
.
Self-checking strategy
Most of the checking is done using SVA for input to output, or CSR update to output behavior. Some of the CLKMGR outputs are gated clocks, which are controlled by both synchronous logic and asynchronous enables. These asynchronous enables become synchronous because of the SVA semantics. This is fine since the assertions allow some cycles for the expected behavior to occur.
Scoreboard
The clkmgr_scoreboard
combines CSR updates and signals from the clkmgr vif to instrument some checks and coverage collection.
The CSR updates are determined using the TLUL analysis port.
The output clocks can be separated into two groups: peripheral ip clocks and transactional unit clocks.
Please refer to the Test sequences section above.
The clock gating logic is pretty similar across units in each group.
For each peripheral and transactional clock the scoreboard samples their coverage based on clocking blocks instantiated in clkmgr_if
.
The external clock control signals with the AST are checked in the scoreboard itself. This involves checking that
- Transitions in the
lc_clk_byp_req
input are followed by corresponding transitions in theio_clk_byp_req
output.- Transitions in the
all_clk_byp_req
output correspond to theextclk_ctrl
CSR and thelc_hw_debug_en
input.
- Transitions in the
The jitter_en_o
output is checked to match the jitter_enable
CSR.
Assertions
- Pwrmgr enable-status assertions: Interface
clkmgr_pwrmgr_sva_if
contains concurrent SVA that checks that edges of the various ip_clk_en are followed by corresponding edges of their clk_status. The clocks checked aremain
,io
, andusb
. - Gated clock assertions: Interface
clkmgr_gated_clock_sva_if
contains concurrent SVA that checks each gated clock is either running or stopped based on their control logic. There is one assertion for each of the four peripheral clock and five hintable clocks. - Clock divider assertions: Interface
clkmgr_div_sva_if
contains concurrent SVA that checks theio_div2
andio_div4
clocks are running at nominal frequency, or are divided by two each in response to theextclk
logic. - TLUL assertions:
clkmgr_bind.sv
binds thetlul_assert
assertions to the IP to ensure TileLink interface protocol compliance. - Unknown checks on DUT outputs: The RTL has assertions to ensure all outputs are initialized to known values after coming out of reset.
Building and running tests
We are using our in-house developed regression tool for building and running our tests and regressions. Please take a look at the link for detailed information on the usage, capabilities, features and known issues. Here’s how to run a smoke test:
$ $REPO_TOP/util/dvsim/dvsim.py $REPO_TOP/hw/ip/clkmgr/dv/clkmgr_sim_cfg.hjson -i clkmgr_smoke
Testplan
Testpoints
Milestone | Name | Tests | Description |
---|---|---|---|
V1 | smoke | clkmgr_smoke | Smoke test disabling peripheral and transactional clocks.
Stimulus:
Checks:
|
V1 | csr_hw_reset | clkmgr_csr_hw_reset | Verify the reset values as indicated in the RAL specification.
|
V1 | csr_rw | clkmgr_csr_rw | Verify accessibility of CSRs as indicated in the RAL specification.
|
V1 | csr_bit_bash | clkmgr_csr_bit_bash | Verify no aliasing within individual bits of a CSR.
|
V1 | csr_aliasing | clkmgr_csr_aliasing | Verify no aliasing within the CSR address space.
|
V1 | csr_mem_rw_with_rand_reset | clkmgr_csr_mem_rw_with_rand_reset | Verify random reset during CSR/memory access.
|
V1 | regwen_csr_and_corresponding_lockable_csr | clkmgr_csr_rw clkmgr_csr_aliasing | Verify regwen CSR and its corresponding lockable CSRs.
Note:
This is only applicable if the block contains regwen and locakable CSRs. |
V2 | peri_enables | clkmgr_peri | Peripheral clocks are disabled if its This test runs multiple rounds, and on each one it randomizes
Checks:
|
V2 | trans_enables | clkmgr_trans | Transactional unit clocks are disabled if they are not busy and
their CSR
Checks:
|
V2 | extclk | clkmgr_extclk | Tests the functionality of enabling external clocks.
Stimulus:
Checks: Clock divider checks are done with SVA assertions.
|
V2 | clk_status | clkmgr_clk_status | This tests the three The Stimulus:
Check:
|
V2 | jitter | clkmgr_smoke | This tests the jitter functionality. The jitter functionality is implemented by the AST block, but
controlled by the Stimulus:
Check:
|
V2 | frequency | clkmgr_frequency | This tests the frequency counters measured count functionality. These counters compute the number of cycles of some clock relative to the aon timer. It should trigger a recoverable alert when the count is not in the expected interval. This tests programs counts for each counter, with intervals set to trigger correct, fast, and slow counts. Stimulus:
Check:
|
V2 | frequency_timeout | clkmgr_frequency_timeout | This tests the frequency counters timeout functionality. These counters compute the number of cycles of some clock relative
to the aon timer. It should trigger a recoverable alert when there
is no valid measurement when enabled, leading to a timeout. This is
separate from the Stimulus:
Check:
|
V2 | frequency_overflow | clkmgr_frequency | This tests the overflow feature in prim_clock_meas. This needs to modify the state of the counter to trigger the feature. Stimulus:
Check:
|
V2 | stress_all | clkmgr_stress_all | This runs random sequences in succession. Randomly chooses from the following sequences:
|
V2 | intr_test | clkmgr_intr_test | Verify common intr_test CSRs that allows SW to mock-inject interrupts.
|
V2 | alert_test | clkmgr_alert_test | Verify common
|
V2 | tl_d_oob_addr_access | clkmgr_tl_errors | Access out of bounds address and verify correctness of response / behavior |
V2 | tl_d_illegal_access | clkmgr_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 | clkmgr_csr_hw_reset clkmgr_csr_rw clkmgr_csr_aliasing clkmgr_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 | clkmgr_csr_hw_reset clkmgr_csr_rw clkmgr_csr_aliasing clkmgr_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 | clkmgr_tl_intg_err clkmgr_sec_cm | Verify that the data integrity check violation generates an alert.
|
V2S | shadow_reg_update_error | clkmgr_shadow_reg_errors | Verify shadowed registers' update error.
|
V2S | shadow_reg_read_clear_staged_value | clkmgr_shadow_reg_errors | Verify reading a shadowed register will clear its staged value.
|
V2S | shadow_reg_storage_error | clkmgr_shadow_reg_errors | Verify shadowed registers' storage error.
|
V2S | shadowed_reset_glitch | clkmgr_shadow_reg_errors | Verify toggle shadowed_rst_n pin can trigger storage error.
|
V2S | shadow_reg_update_error_with_csr_rw | clkmgr_shadow_reg_errors_with_csr_rw | Run shadow_reg_update_error sequence in parallel with csr_rw sequence.
|
V2S | sec_cm_bus_integrity | clkmgr_tl_intg_err | Verify the countermeasure(s) BUS.INTEGRITY. This entry is covered by tl_access_test. |
V2S | sec_cm_meas_clk_bkgn_chk | clkmgr_frequency | Verify the countermeasure(s) MEAS.CLK.BKGN_CHK.
|
V2S | sec_cm_timeout_clk_bkgn_chk | clkmgr_frequency_timeout | Verify the countermeasure(s) TIMEOUT.CLK.BKGN_CHK.
|
V2S | sec_cm_meas_config_shadow | clkmgr_shadow_reg_errors | Verify the countermeasure(s) MEAS.CONFIG.SHADOW. This is covered by shadow_reg_errors_tests (https://github.com/lowRISC/opentitan/blob/master/ hw/dv/tools/dvsim/testplans/shadow_reg_errors_testplan.hjson) |
V2S | sec_cm_idle_intersig_mubi | clkmgr_idle_intersig_mubi | Verify the countermeasure(s) IDLE.INTERSIG.MUBI. It uses true_strict and false_loose. Stimulus: Use same sequence as trans_enables test. Randomize dut.idle_i ports with illegal values. Check:
|
V2S | sec_cm_lc_ctrl_intersig_mubi | clkmgr_lc_ctrl_intersig_mubi | Verify the countermeasure(s) LC_CTRL.INTERSIG.MUBI. It compares to lc_ctrl_pkg::On only. Use clkmgr_extclk test as in testplan.extclk but randomize dut.lc_hw_debug_en_i s.t. all 16 values can be generated with equal priority. Checks: When dut sees invalid values of lc_hw_debug_en_i, all_clk_byp_req should not be asserted. Covered by assertion checker. |
V2S | sec_cm_lc_ctrl_clk_handshake_intersig_mubi | clkmgr_lc_clk_byp_req_intersig_mubi | Verify the countermeasure(s) LC_CTRL_CLK_HANDSHAKE.INTERSIG.MUBI. It compared to lc_ctrl_pkg::On only. Use clkmgr_extclk test but randomize lc_clk_byp_req s.t. all 16 values can be generated with equal priority. lc_clk_byp_req drives dut.lc_clk_byp_req_i in the test. Checks: When dut sees invalid values of lc_clk_byp_req_i, io_clk_byp_req_o should not be asserted. Covered by assertion checker. |
V2S | sec_cm_clk_handshake_intersig_mubi | clkmgr_clk_handshake_intersig_mubi | Verify the countermeasure(s) CLK_HANDSHAKE.INTERSIG.MUBI. It uses true_strict. Use clkmgr_extclk test. Upon receiving [io|all]_clk_byp_req_o from dut, assert invalid [io|all]_clk_byp_ack values to dut. Check: all_clk_byp_ack is copied to CLKGMR.EXTCLK_STATUS as is. So read extclk status and compare. io_clk_byp_ack is evaluated with step_down_acks_syn. When both are true, lc_clk_byp_req is assigned to lc_clk_byp_ack. Covered by assertion checker. |
V2S | sec_cm_div_intersig_mubi | clkmgr_div_intersig_mubi | Verify the countermeasure(s) DIV.INTERSIG.MUBI. use true_strict. Use clkmgr_extclk test. Before, test drive dut.div_step_down_req_i with 'true', sends invalid values. Check: dut should ignore invalid req values. Covered by assertion checker. |
V2S | sec_cm_jitter_config_mubi | clkmgr_csr_rw | Verify the countermeasure(s) JITTER.CONFIG.MUBI. use false_strict. This doesn't do any function in the dut but indicating jittery clock is enabled. So it can be covered by default csr test. |
V2S | sec_cm_idle_ctr_redun | clkmgr_sec_cm | Verify the countermeasure(s) IDLE.CTR.REDUN. This is triggered by common cm primitives (SecCmPrimCount). Check: read check CLKMGR.FATAL_ERR_CODE.IDLE_CNT == 1 |
V2S | sec_cm_meas_config_regwen | clkmgr_csr_rw | Verify the countermeasure(s) MEAS.CONFIG.REGWEN. This is covered by auto csr test. |
V2S | sec_cm_clk_ctrl_config_regwen | clkmgr_csr_rw | Verify the countermeasure(s) CLK_CTRL.CONFIG.REGWEN. This is covered by auto csr test. |
V2S | prim_count_check | clkmgr_sec_cm | Verify that violating prim_count counter properties generate a fatal alert. Stimulus:
Checks:
|
V3 | stress_all_with_rand_reset | clkmgr_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 |
---|---|
extclk_cg | Collects coverage for the external clock selection. The external clock selection depends on the |
freq_measure_cg | Collects coverage for the frequency measurement counters. The relevant information is whether it got an okay, slow, or fast measurement, or a timeout. |
peri_cg | Collects coverage for each peripheral clock. The peripheral clocks depend on a bit in the clk_enables CSR, the ip_clk_en input from pwrmgr, and the scanmode input. This collects the cross of them for each peripheral. FIXME This is collected in an array, one instance for each clock, but the dvsim coverage flow doesn't yet support arrays. |
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. |
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. |
trans_cg | Collects coverage for each transactional unit clock. The transactional unit clocks depend on a bit in the clk_hints CSR, the ip_clk_en input from pwrmgr, the respective idle input bit from the unit, and the scanmode input. This collects the cross of them for each transactional unit. FIXME This is collected in an array, one instance for each clock, but the dvsim coverage flow doesn't yet support arrays. |