Up to now the DMA bench has programmed its registers with raw APB writes: reg_write(LEN, 6), reg_write(CTRL, 32'h3). That works for five registers and one bus. It stops working when the block sits in a chip with three thousand registers behind an interconnect, when every test must remember that DONE is cleared by writing 1, and when a check needs to know what a register should read back. The register layer (RAL) solves this with a model of the registers that tests access by name, that knows every field's behaviour, and that keeps its own copy of what it believes the hardware holds.
This part rebuilds the DMA's register traffic on that model. One file, dma_ral_tb.sv, adds a register model of the five DMA registers, an APB adapter, an explicit predictor fed by the APB monitor and a backdoor that reads the RTL directly. Its tests run a whole DMA job by register name, check the reset values, walk a 1 through the writable bits of the registers that allow it, and catch the model believing a write that the DMA ignored.
Explain what a register model buys you, and the three values it juggles: desired, mirrored and the DUT's real value.
Build a model from blocks, registers, fields and maps, compose it into a subsystem model, and keep a generated model as the one source of truth.
Trace one register access from write() through the map, the adapter, the bus, the monitor and the predictor back into the mirror, and say where it can go wrong.
Use the access API (write, read, set, update, mirror, predict, peek, poke) knowing which value each call moves.
Run the built-in register sequences, decide what to exclude, and use the model for coverage, memories, interrupts and chip-scale checks.
# | Topic | What it covers |
|---|---|---|
1 | Why a register model exists and what desired, mirrored and DUT values are; blocks, registers, fields and memories; maps and address math; nested blocks and submaps; build order, locking and generated models; and the frontdoor path end to end, including the moment the mirror lags the bus. | |
2 | The access API call by call, the adapter contract ( | |
3 | The built-in register sequences and their exclusions, register coverage, memories, multiple maps, shadow and alias registers, interrupts through the model, RAL at SoC scale, and an interview set. |
The whole register bench, dma_ral_tb.sv, is listed on The Register Layer: Full Source for EDA Playground. Read the topics in order. The overview gives you the structure and the one diagram everything else hangs on: the path an access takes from the test to the bus and back into the mirror. Register Access then takes each stop on that path apart. Registers in Verification comes last because the built-in sequences and register coverage only make sense once you know what the model believes and why it can be wrong.
Everything in this part runs on dma_ral_tb.sv, which sits next to the block bench in the course's bench folder. It includes dma_tb.sv and brings its own top module, which adds the backdoor interface dma_bd_if and binds it into dma_dut. On EDA Playground, put dma_dut.sv in the design pane, dma_ral_tb.sv in the testbench pane and add dma_tb.sv beside it with the + button; choose UVM 1.2 and a simulator such as Riviera-PRO. The two base files are on The DMA bench: full source.
Test | What it shows |
|---|---|
| A whole DMA job by register name: KEY and LEN written, CTRL started, STATUS and COUNT read, DONE cleared, and KEY's mirror compared with a backdoor peek. |
|
|
|
|
| A LEN write while the DMA is busy: the DUT ignores it, the model believes it, and a mirror check reports the difference. It ends with one UVM_ERROR by design. |
To run it locally with Verilator and the open-source UVM library, point UVM_HOME at the library's src folder and pass the file and a test name to the course's run script:
UVM_HOME=<uvm>/src scripts/tools/uvm-bench/run.sh \
scripts/data/uvm-course/bench/dma_ral_tb.sv +UVM_TESTNAME=dma_ral_job_test