Rewriting every block test at chip level doubles the work and weakens the schedule: the DMA register model already knows every offset, and the interconnect already has its protocol assertions. Reuse carries that collateral up; regression decides how often the carried load runs. Its one job is the economics: what is reused unchanged, what is wrapped, and how the nightly budget is split so the list from the previous lesson actually executes.
Three reuse moves cover nearly everything. The register model climbs unchanged: the same register description that proved the DMA bench drives the chip-level register sweeps, with the APB addresses rebased to 0x4000_0000 and the alias images excluded by rule. The virtual sequencer moves up one floor: block sequences become chip sequences coordinated across the CPU model, the SBR driver and the interrupt handler, which is the layered-sequence pattern the UVM course teaches. Interface assertions travel with bind: protocol checkers attach to integration boundaries — the AXI crossing, the APB bridge, the stream links — without touching the IP, flagging 4 KB crossings, identifier mix-ups and PREADY or PSLVERR violations in every test for free.
Regression then spends a fixed nightly budget, and the split follows failure cost. Fast sweeps — connectivity, map, registers — run on every change because they finish in microseconds of simulated time and catch wiring bugs. The boot and DMA tests run nightly because the boot alone costs about 1.2 million simulated cycles, which at the illustrative speed below is four minutes of wall clock. Gate-level and power-aware runs are weekly: each typically costs many times the RTL run and only pays when the netlist or the power intent changed. The script below prices the RTL split from the 12.581 ms boot total, converting simulated time into wall-clock time with an illustrative simulation speed (5,000 cycles per second, a teaching value, not a benchmark), so the schedule quotes numbers, not adjectives.
# Nightly regression budget. Simulated time comes from the boot flow; the
# simulation speed is ILLUSTRATIVE (whole chip, firmware running, no waveform dump).
SPEED = 5000 # clk_sys-equivalent cycles simulated per wall-clock second
CYCLES_PER_US = 96 # clk_sys at 96 MHz
NIGHT_S = 8 * 3600
def cycles(us):
return round(us * CYCLES_PER_US)
BOOT = cycles(12580.917) # full boot, boot flow table
# 40 register accesses: 24 DMA or SBR registers at 125 ns, 16 clk_per registers at 281.25 ns
SWEEP = cycles(24 * 0.125 + 16 * 0.28125)
DMA = cycles(0.625 + 0.875 + 0.750) # 5 reads, 7 writes, 64-word job
POWER_WALK = cycles(1000.0) # illustrative: 17 us of hardware sequences plus software
def night(boots, sweeps=200, dmas=100, walks=10):
total = boots * BOOT + sweeps * SWEEP + dmas * DMA + walks * POWER_WALK
return total / SPEED # wall-clock seconds
plan = night(boots=20)
print(f"boot {BOOT} cycles = {BOOT / SPEED:.0f} s; nightly plan {plan / 60:.0f} min")
assert BOOT == 1207768, BOOT
assert plan < NIGHT_S # the night holds the plan
assert night(boots=150) > NIGHT_S # the check can fail: too many full boots overrun it
room = int((NIGHT_S * SPEED - 200 * SWEEP - 100 * DMA - 10 * POWER_WALK) // BOOT)
assert 20 < room < 150, room
print(f"PASS: nightly plan {plan / 60:.0f} min of 480; the night holds {room} full boots")Each reused item names its source revision: the register model, the sequence library, the bound checkers.
The regression table quotes simulated-time cost per group and the trigger — every change, nightly, weekly.
Signoff consumes the regression record plus waiver evidence, never a bare pass count; residual risk is written down.
When a regression goes red, bisect by level before debugging the failure: rerun the block benches for the touched IP, then the subsystem, then the chip. A red chip test with green blocks is an integration bug by elimination, usually the wiring the change touched. Triage by signature — group the failures by first-failing group — so one broken decoder does not file ten separate bugs. For the method see the regression strategy and triage lessons linked below.
The IP is owned by its author and often reused; bind attaches verification at the integration point without forcing a fork of the source, so updates to the IP never collide with the integrator's checks.