It is 11 pm, your interview is on Thursday, and you want to know for certain whether a factory override placed after super.build_phase() still takes effect. You could reason about it from memory, or you could run it. Most engineers preparing for interviews no longer have a simulator licence outside work, and work machines are the wrong place to experiment with interview code. So where do you run UVM tonight, for free, and how far can you trust what comes back?
EDA Playground is a free website that puts commercial and open-source simulators behind a browser editor. Think of it as a shared lab bench: you bring the design and the testbench, it supplies the instruments, and you leave with the log. It offers the UVM library pre-installed, in several versions, so a testbench that includes uvm_macros.svh and imports uvm_pkg compiles with no setup.
Two things make it the right tool for this course. Every listing marked as a complete program, and the whole DMA bench, runs there unchanged. And because you can switch simulators with one drop-down, it is also the quickest way to see that a testbench which passes on one simulator can behave differently on another, which is an interview topic in its own right.
Open EDA Playground and sign in with a free account. The commercial simulators are available only to signed-in users.
Copy the two files from The DMA bench: full source. Paste dma_dut.sv into the editor tab named design.sv and dma_tb.sv into the tab named testbench.sv. dma_tb.sv is long, so that page lists it in three parts: paste them one after another into the same tab. The names matter less than the split: the testbench file includes the UVM macros and holds the top module.
Under Languages & Libraries, keep SystemVerilog/Verilog and set UVM / OVM to UVM 1.2.
Under Tools & Simulators, choose Aldec Riviera-PRO. Other simulators work too; Riviera is the course's reference choice because it is reliably available.
In Run Options, add +UVM_TESTNAME=dma_smoke_test. Change the name to run dma_rand_test, dma_truncate_test, dma_drain_test or dma_timeout_test from the same files.
Press Run, and read the log from the bottom up: the report summary first, then the scoreboard line, then anything marked ERROR or FATAL.
The top module calls run_test("dma_smoke_test"), but +UVM_TESTNAME beats the argument of run_test: UVM reads the plusarg and builds that test through the factory instead. This is how a real regression runs hundreds of tests from one compiled image. If the name is misspelt, or the test class forgot its registration macro, the factory has nothing to build and the run stops with an INVTST fatal at time 0.
Every UVM run ends with a report summary that counts messages by severity, and that summary is the verdict. These lines are from the course's own runs of the bench (Verilator with the open-source UVM library). Riviera-PRO prints the same messages with its own file paths, and with different random values:
+UVM_TESTNAME=dma_rand_test
UVM_INFO dma_tb.sv(731) @ 0: uvm_test_top [JOB] key=90fdd8fd len=10 irq_en=1
UVM_INFO dma_tb.sv(731) @ 645000: uvm_test_top [JOB] key=0e564b57 len=1 irq_en=1
UVM_INFO dma_tb.sv(731) @ 885000: uvm_test_top [JOB] key=5a1793f4 len=3 irq_en=1
UVM_INFO dma_tb.sv(411) @ 1305000: uvm_test_top.env.sb [SB] 14 words matched, 0 mismatched
--- UVM Report Summary ---
** Report counts by severity
UVM_ERROR : 0
UVM_FATAL : 0The header: UVM_INFO dma_tb.sv(731) @ 645000: uvm_test_top [JOB] is severity, source line, time, the reporting component's full path, and the message ID in brackets. The ID is what you filter on.
The times are in ps for this bench (its timescale is 1ns/1ps), so @ 645000 is 645 ns.
14 words matched is 10 + 1 + 3, the three random lengths. A summary of zero errors is a pass only if the scoreboard compared something.
The summary also lists UVM_INFO and UVM_WARNING counts and a count per message ID. Regression scripts usually grep for the UVM_ERROR and UVM_FATAL lines.
Now run dma_timeout_test. It waits for an interrupt that is never enabled, and a built-in timeout ends it instead of letting it hang:
UVM_FATAL uvm_phase_hopper.svh(598) @ 20000000: reporter [PH_TIMEOUT] Explicit timeout of 20000000 hit, indicating a probable testbench issue
UVM_FATAL : 1Other UVM versions and simulators report this from a different source file, but the PH_TIMEOUT ID is the same. Grep for IDs, never for file names.
What you see | Usual cause | Fix |
|---|---|---|
| No UVM library selected | Set UVM / OVM to UVM 1.2 |
| Typo, or the class lacks | Check the spelling and the macro |
| The config_db path in | Compare the |
The run ends at time 0 and the scoreboard reports | No objection was raised in the run phase | Raise one before the first wait |
| The test waits for something that never happens | Find the wait; the timeout only stops the bleeding |
Passes on one simulator, fails on another | A race or non-standard code | Look for same-edge drive and sample, and tool-specific syntax |
Every complete listing in the course, including the whole DMA bench, is compiled and run before it is published, with Verilator 5.048 and the open-source UVM library from the Accellera 1800.2-2020 line (the CHIPS Alliance build for Verilator, release 2020.3.2). The logs you see in lessons come from those runs. Short fragments are marked // snippet and are never shown with invented output.
Knowing what that flow can and cannot prove is the same judgement you need for any sign-off flow, so it is worth being precise.
The course's check proves | It does not prove |
|---|---|
The code compiles, elaborates and runs on a real simulator | That it behaves identically on every simulator: scheduling and randomization differ |
The logged values and match counts are real | Coverage: covergroups are not run in this flow, so covergroup listings are marked |
The code works with the IEEE 1800.2 library | That it works with UVM 1.2: that half is EDA Playground's job |
Front-door register and data paths behave | DPI-based features, because the flow builds with |
This is why the course writes every listing to the subset that both UVM 1.2 and IEEE 1800.2 accept, which UVM 1.2 vs IEEE 1800.2 at a glance spells out. Verilator checks the 1800.2 side, EDA Playground with UVM 1.2 checks the other, and code that uses only the common subset passes both.
While the DMA bench was being built, a random test failed on two jobs out of three. The DMA reported ERR because every packet arrived one word short, yet the sequence had generated every item and the driver had called item_done for each one. The cause was a race. The APB driver finished the GO write on a clock edge, and in the same time step the stream driver woke up and waited on its own interface's clocking block. Two clocking blocks on the same clock edge fire in an order the language leaves undefined, so the stream driver caught the current edge instead of the next one and believed the DUT had taken a beat it never saw.
A different simulator, or the same one after an unrelated edit, could order those events the other way and pass. That is the real lesson of running on more than one tool: a pass on one simulator proves the code can work, not that it is free of races. The fix, now in the bench, is that every driver waits on the one shared event @(posedge clk) and drives with nonblocking assignments, while monitors sample through a #1step clocking block. The first testbench lesson shows those two rules in the interfaces.
dma_smoke_test on EDA Playground and the summary shows UVM_ERROR : 0 and UVM_FATAL : 0, but you see no [SB] line at all. Is it a pass?No. The scoreboard prints its match count in report_phase, so a missing [SB] line means the scoreboard never reached that phase or was never built (for example, the env was edited, or a fatal ended the run before reporting). A zero-error summary with no evidence of checking is exactly the green-but-checking-nothing test the course warns about.
starting_phase and passes the course's Verilator check. Is it portable?Not necessarily. The open-source library the course uses keeps some UVM 1.2 names as compatibility features even though IEEE 1800.2 removed them from the standard, so passing there does not prove the code is standard 1800.2. Another 1800.2 library may reject it. The course avoids such names and uses get_starting_phase() or set_automatic_phase_objection() instead.
Next: the last page of Start here, UVM 1.2 vs IEEE 1800.2 at a glance, lists the differences that change code and interview answers, and the subset this course writes to.