A 4×4 INT8 output-stationary MAC array in SystemVerilog, verified with a from-scratch UVM 1.2 environment — constrained-random stimulus, reference-model scoreboard, SVA, functional coverage, and Python-driven regression.
This project grew out of a computer architecture course where I implemented a 5-stage pipelined MIPS processor. What hooked me wasn't the design itself, but the quantitative side: measuring how hazards change execution time across instruction streams, and how cache configurations shift hit/miss behavior. I wanted to keep going in that direction, but as an exchange-bound student I couldn't commit to a multi-semester lab internship. After consulting with over ten professors on what a single semester could realistically produce, the consistent advice was: build one complete, self-contained artifact.
So the design (DUT) is deliberately small — the point is the verification infrastructure on top of it. Roughly 60% of the effort goes into the UVM environment: verification planning, constrained-random sequences, a scoreboard against a Python golden model, assertions, coverage closure, and seed-swept regression. Design verification is, at its core, the same thing I enjoyed in that course — quantitatively confirming how a system behaves.
mac-array-dv/
├── rtl/ # mac_pe.sv, ctrl.sv, mac_array_4x4.sv, mac_if.sv (~140 lines total)
├── tb_uvm/ # agent, driver, monitor, scoreboard, sequences, env, test
├── sva/ # protocol / data-integrity assertions
├── regress/ # Python regression scripts + seed management + summaries
├── docs/
│ ├── verification_plan.md # feature → coverage → assertion mapping
│ ├── coverage_report/ # screenshots + numbers
│ └── bug_log.md # bug reports (incl. injected-bug hunt)
└── README.md
- Vivado 2020.2
xsim(UVM 1.2 built in — no extra installs), simulation only - Python 3 for the golden model and regression driver
- CI (GitHub Actions): Verilator lint of
rtl/clean and with each injected-bug hook, plus 65 pytest cases over the golden model — the checks that need no simulator licence
- W1 — repo bootstrap, verification plan skeleton, SV toy + "Hello UVM" pass on xsim
- W2 —
mac_pe.sv+ directed self-checking TB: 36 sign/boundary corners + 1000 randoms, 1073 checks PASS - W3 — 4×4 array + control FSM: 50 golden-model tiles PASS (M0)
- Phase 1 — valid/ready protocol + 9 SVA bound into the DUT; injected-bug assertion violation captured (M1,
docs/coverage_report/m1_sva_violation.txt) - Phase 2 — UVM 1.2 env from scratch: agent (sequencer/driver/monitor), reference-model scoreboard, constrained-random with corner-weighted
dist, smoke/random/corner tests (M2) - Phase 3 — functional coverage (native covergroups and Python bin-counting), 20-seed Python regression, injected-bug hunt (M3,
docs/bug_log.md) - Phase 4 — final packaging
| Metric | Value |
|---|---|
| Regression | 52/52 runs PASS (smoke + corner + 50 random seeds × 20 tiles, ~1000 tiles) |
| Functional coverage | 25/25 Python bins (100%) aggregated across the sweep; SV cg_vals reaches 100% per run, cg_tile closes across the suite (K = 64 comes from the directed corner tiles, not from any single random run) |
| Assertions | 11 SVA — protocol, state, reset, and one datapath check that recomputes the accumulator from the spec; 0 violations on clean RTL |
| Golden-model cross-checks | 3 independent layers: SVA / SV scoreboard / Python post-sim recompute |
| Injected-bug hunt | 5/5 caught — SVA first on 3 (protocol/state), scoreboard first on 2 (value-domain), each within the first tiles (bug_log.md) |
| Verification plan | 9 features → 2 SV covergroups (+25 Python bins) → 11 assertions (verification_plan.md) |
| Known gaps | Documented, not hidden — see verification_plan.md §7. An audit of this environment found assertion A8 passing vacuously; the driver was reworked so the stall it checks actually occurs, and the monitor now fails the test if it doesn't. |
constrained-random sequences ──> driver ──> DUT (4×4 MAC array) <── 9 SVA (bind, sees acc/en/clr)
│
monitor (posedge sampling)
├──> scoreboard: SV reference model (in-sim)
├──> covergroups: values × sign cross, K bins
└──> txn dump ──> Python golden model cross-check + coverage bins (post-sim)
default disable iff and $past/$stable unsupported in properties → per-property disable + hand-rolled sample registers; UVM lib needs xelab -timescale; -testplusarg quoting on Windows.