All work

Case study · Design verification

How a strict scoreboard caught 3 real RTL bugs

Verification of a burst-capable AXI4 slave using SystemVerilog and UVM. The testbench predicts every beat exactly, so when the RTL got something wrong, it had nowhere to hide.

  • 3RTL bugs found
  • 14SystemVerilog assertions
  • 100%functional coverage
  • 8tests on Cadence Xcelium
  • SystemVerilog
  • UVM
  • AXI4
  • SVA
  • Cadence Xcelium

The design under test

An AXI4 slave in front of a 128-byte, byte-addressable memory. It accepts FIXED, INCR and WRAP bursts of 1–16 beats, with 1-, 2- or 4-byte beats and per-byte write strobes, handles one outstanding transaction per direction, and checks AXI3-style WID against AWID. Anything illegal (an out-of-range address, an illegal size, a reserved burst type) must come back as DECERR.

The testbench

UVM testbench: a sequencer and driver stimulate the AXI4 slave, a monitor feeds a reference-model scoreboard and coverage, and 14 assertions sit on the interface axi_env axi_agent sequencer driver monitor DUT axi_slave axi_if · 14 SVA scoreboard ref model · per-beat coverage covergroups + cross 3 RTL bugs found 8 tests · Xcelium
Stimulus flows from the sequencer through the driver into the DUT; a passive monitor rebuilds every burst and feeds the scoreboard and coverage.
ComponentRole
DriverMaster BFM: clocking-block handshakes, random BREADY/RREADY backpressure, reset abort
MonitorPassively rebuilds every burst from bus handshakes, so checking never trusts the driver
Reference model + scoreboardGolden byte-accurate memory; checks RDATA, RRESP, RID, RLAST, BRESP and BID on every beat
CoverageBurst type × size × length cross, alignment, strobe shape, responses
Interface assertions14 SVA properties: handshake rules, payload stability, reset behavior, no X

Strategy: predict every beat, exactly

  • No “either answer is fine” checks. The scoreboard's golden memory predicts the exact response and data for every beat. Loose checking is precisely what had masked the first bug.
  • Random for the legal space, directed for the corners. Constrained-random bursts cover every type, size and length. Directed sequences inject what the constraints deliberately exclude: out-of-range addresses, illegal sizes, reserved burst types, bursts that run off the end of memory, a mismatched WID and an early WLAST.
  • Assertions for what transactions can't show. The 14 interface assertions cover handshake rules, payload stability while stalled, VALID retraction, reset behavior and X-propagation.
  • A silent pass is not a pass. A test that observes zero transactions fails by design.

Three bugs, found and reproduced

The RTL is deliberately left unfixed in the repo, so each bug can be reproduced live with make bugs. The log lines below are real output from Cadence Xcelium.

Bug #1

The error response arrives one beat late

Symptom
A read burst that runs past the end of memory hits address 0x80 on beat 2 but returns OKAY; DECERR only shows up a beat later. A write burst whose final beat is the first illegal one gets an OKAY write response.
Root cause
The error flag is set with a non-blocking assignment and read back in the same always_ff evaluation, so the response logic sees the previous value, not the one just computed.
How it was caught
Tightening the scoreboard to expect the exact response on every beat, plus directed bursts built to turn illegal mid-burst. Bursts that are illegal from beat 0 return DECERR correctly, so only this case exposes it.
Fix direction
Compute the error for the current beat combinationally, or register the response one cycle later. Never read an NBA-updated flag in the block that wrote it.
UVM_ERROR axi_scoreboard.sv(119) [AXI_SCB] RRESP mismatch beat2 exp=DECERR got=0 (addr=0x80 len=3 size=2 burst=AXI_BURST_INCR)
UVM_ERROR axi_scoreboard.sv(77)  [AXI_SCB] BRESP mismatch exp=DECERR got=0 (addr=0x74 len=3 size=2 burst=AXI_BURST_INCR wid_mm=0 wlast_mm=0)

Bug #2

The write FSM deadlocks on an early WLAST

Symptom
When a master ends a write burst one beat early, the slave never returns a write response. No BVALID, no recovery: the write channel is locked.
Root cause
An early WLAST only sets the error flag. The write FSM still waits for the beat counter to reach AWLEN+1, so it never moves on to the response state.
How it was caught
A directed early-WLAST test with a 20 µs watchdog, backed by the scoreboard's zero-transaction guard, which refuses to call a burst that never completed a pass.
Fix direction
Treat WLAST as the burst terminator: on an early WLAST, go straight to the response state with an error response.
UVM_ERROR axi_tests.sv(208) [BUG2_HANG] DUT hung after early WLAST: write FSM ignored WLAST and never returned BRESP (axi_slave.sv WR_DATA state)
UVM_ERROR axi_scoreboard.sv(151) [AXI_SCB] No transactions observed - the test drove nothing; a silent pass is not a pass

Bug #3

A rejected burst still writes to memory

Symptom
A burst whose WID doesn't match AWID correctly gets DECERR, but its data is written to memory anyway.
Root cause
The memory write is gated only by the per-beat size, burst and address checks, never by the WID mismatch detected on the same beat.
How it was caught
The reference model predicted the whole burst would be rejected and kept the memory's reset value; the readback returned the “rejected” data instead. Constrained-random WRAP bursts with an unaligned start address independently exposed the same commit-on-error behavior.
Fix direction
Qualify the memory write with the accumulated per-beat error, or buffer the burst and commit it only once it's confirmed clean.
UVM_ERROR axi_scoreboard.sv(126) [AXI_SCB] RDATA mismatch beat0 addr=0x40 exp=0x0c0c0c0c got=0xc1d00000
UVM_ERROR axi_scoreboard.sv(126) [AXI_SCB] RDATA mismatch beat1 addr=0x44 exp=0x0c0c0c0c got=0xc1d00001
...

The tests

TestWhat it verifiesResult
axi_smoke_testDirected 4-beat INCR write and readbackPass
axi_random_test400 constrained-random bursts across every burst type, size and length, with random strobes and backpressurePass
axi_backpressure_testBursty multi-cycle BREADY/RREADY stalls that stress the stability assertionsPass
axi_b2b_testZero-idle back-to-back write/read pairsPass
axi_reset_testReset in the middle of a write burst, then clean traffic after recoveryPass
axi_error_testOut-of-range addresses, illegal sizes, reserved bursts, bursts crossing the end of memoryFinds Bug #1
axi_wid_testA WID ≠ AWID burst, then readbackFinds Bug #3
axi_early_wlast_testThe master ends a write burst one beat earlyFinds Bug #2

Results

  • The five regression tests end with zero UVM errors.
  • The three bug-hunting tests fail on purpose, each with its documented signature, so every bug stays reproducible.
  • 100% functional coverage via constrained-random and directed error-injection stimulus, with 14 interface assertions watching every handshake.