|
1 | | -# Memory Controller Verification (SystemVerilog + Python) |
| 1 | +# Memory Controller Verification |
2 | 2 |
|
3 | | -A compact, **self-checking** SystemVerilog testbench for an 8-location × 8-bit |
4 | | -SRAM memory controller. Directed tests, 50-op constrained-random stimulus, |
5 | | -ModelSim TCL automation, and a Python regression tool that emits an HTML |
6 | | -report. Built as a one-day HAV/DV sprint project. |
| 3 | +Two-tier SystemVerilog verification of an 8-location × 8-bit SRAM controller. |
| 4 | +Built as a hardware-verification portfolio project for HAV / DV internships. |
7 | 5 |
|
8 | | ---- |
| 6 | +- **Simple flow** (`tb/simple/`) — original task-based testbench. Runs on free |
| 7 | + ModelSim Intel Starter Edition. Great for showing the basics. |
| 8 | +- **UVM flow** (`tb/uvm/`) — full UVM environment with sequencer, driver, |
| 9 | + monitor, scoreboard, functional coverage. Requires Questa or any |
| 10 | + UVM-capable simulator. |
| 11 | +- **Bug demo** — a buggy DUT (`rtl/memory_ctrl_buggy.sv`) demonstrates the |
| 12 | + scoreboard catching a real failure end-to-end. |
| 13 | +- **Python tooling** — `regression.py` parses logs and produces a CI-friendly |
| 14 | + exit code; `dashboard.py` produces `reports/dashboard.html` summarising |
| 15 | + pass/fail and coverage. |
9 | 16 |
|
10 | | -## Project overview |
| 17 | +## Folder structure |
| 18 | +├── rtl/ # DUTs (clean + buggy) |
| 19 | +├── tb/ |
| 20 | +│ ├── simple/ # Original task-based testbench |
| 21 | +│ └── uvm/ # UVM environment |
| 22 | +├── scripts/ # TCL + PowerShell automation |
| 23 | +├── tools/ # Python regression + dashboard |
| 24 | +├── reports/ # Generated logs + HTML report (gitignored) |
| 25 | +├── docs/ # Verification plan, architecture, results template |
| 26 | +├── .github/workflows/ # CI (Python checks; SV needs self-hosted runner) |
| 27 | +├── requirements.txt |
| 28 | +└── README.md |
| 29 | +## Simulator requirements |
11 | 30 |
|
12 | | -The DUT is a tiny SRAM controller: |
| 31 | +| Flow | Simulator | |
| 32 | +|-----------------|---------------------------------------------| |
| 33 | +| Simple | ModelSim Intel Starter (free) **or** Questa | |
| 34 | +| UVM | Questa / Riviera-PRO / VCS / Xcelium | |
| 35 | +| UVM bug demo | same as UVM | |
13 | 36 |
|
14 | | -- 8 locations × 8 bits |
15 | | -- Synchronous write, combinational read |
16 | | -- Active-low reset clears memory to `0x00` |
| 37 | +Free ModelSim Intel Starter does not ship `uvm_pkg`, so the UVM flow needs Questa. |
17 | 38 |
|
18 | | -The testbench maintains a **shadow memory array** that mirrors every write. |
19 | | -After every read it asserts `dout === shadow_mem[addr]` and prints a |
20 | | -machine-parseable `PASS`/`FAIL` line. `regression.py` parses those lines, |
21 | | -renders a terminal table, writes `report.html`, and exits with a non-zero |
22 | | -status on any failure. |
| 39 | +## Run commands (PowerShell, from repo root) |
23 | 40 |
|
24 | | ---- |
| 41 | +```powershell |
| 42 | +cd path\to\memory-ctrl-verification |
25 | 43 |
|
26 | | -## File list |
| 44 | +# 1) Simple flow (original) |
| 45 | +vsim -c -do scripts/run_simple.tcl |
| 46 | +python tools/regression.py reports/simple_sim_log.txt |
27 | 47 |
|
28 | | -| File | Purpose | |
29 | | -| ------------------- | ----------------------------------------------------------- | |
30 | | -| `memory_ctrl.sv` | RTL DUT (supports `+define+INJECT_BUG` for debug practice) | |
31 | | -| `tb_top.sv` | Testbench top: clock, reset, DUT instance, VCD dump | |
32 | | -| `mem_test.sv` | Directed + random tests, helper tasks (SV-include file) | |
33 | | -| `run_sim.tcl` | Clean ModelSim flow — all tests should PASS | |
34 | | -| `run_bug_sim.tcl` | Buggy flow (`+define+INJECT_BUG`) — expected failures | |
35 | | -| `regression.py` | Log parser → terminal table + `report.html` | |
36 | | -| `README.md` | This file | |
| 48 | +# 2) UVM clean run — should be all PASS |
| 49 | +vsim -c -do scripts/run_uvm.tcl |
| 50 | +python tools/regression.py reports/uvm_sim_log.txt |
37 | 51 |
|
38 | | ---- |
| 52 | +# 3) UVM bug demo — should fail at addr 7 |
| 53 | +vsim -c -do scripts/run_uvm_bug.tcl |
| 54 | +python tools/regression.py reports/uvm_bug_log.txt |
39 | 55 |
|
40 | | -## Architecture (ASCII) |
| 56 | +# 4) HTML dashboard summarising both UVM runs |
| 57 | +python tools/dashboard.py reports/uvm_sim_log.txt reports/uvm_bug_log.txt |
| 58 | +
|
| 59 | +# 5) Clean build artefacts |
| 60 | +powershell -ExecutionPolicy Bypass -File scripts/clean.ps1 |
| 61 | +``` |
| 62 | + |
| 63 | +(Linux/macOS: same commands, swap `python` for `python3` and the cleanup line for `rm -rf work transcript reports/*.txt waveform.vcd`.) |
| 64 | + |
| 65 | +## How the bug demo works |
| 66 | + |
| 67 | +`rtl/memory_ctrl_buggy.sv` corrupts writes to address 7 only — it stores |
| 68 | +`din ^ 0xFF` instead of `din`. The clean run touches every address and |
| 69 | +every data class so the bug is **guaranteed** to be hit: |
| 70 | +- the directed sequence's boundary phase writes 0x00 and 0xFF to all 8 addresses, |
| 71 | +- the random sequence (≥100 transactions) hits addr 7 multiple times. |
| 72 | + |
| 73 | +The scoreboard records each FAIL with `expected=0xXX actual=0xYY`; the |
| 74 | +dashboard surfaces the offending checks under "Failing checks". |
| 75 | + |
| 76 | +## Screenshots |
| 77 | + |
| 78 | +docs/img/clean_run_dashboard.png ← the PASS dashboard |
| 79 | +docs/img/bug_run_dashboard.png ← the FAIL dashboard with addr-7 fails |
| 80 | +docs/img/waveform_reset.png ← waveform showing clean reset |
| 81 | +docs/img/waveform_addr7_bug.png ← waveform highlighting the corrupted write |
| 82 | + |
| 83 | +## What this project demonstrates |
| 84 | + |
| 85 | +- SystemVerilog RTL (synchronous write / combinational read / async reset). |
| 86 | +- A self-checking testbench with a shadow-memory reference model. |
| 87 | +- Full UVM architecture: sequencer/driver/monitor/scoreboard/coverage/agent/env/test. |
| 88 | +- Constrained-random stimulus and directed corner cases. |
| 89 | +- Functional coverage with covergroups, cross coverage, and transition coverage. |
| 90 | +- TCL automation, log parsing, HTML reporting. |
| 91 | +- A reproducible bug-injection / detection / fix loop. |
| 92 | + |
| 93 | +## Interview talking points |
| 94 | + |
| 95 | +- **"Walk me through your scoreboard."** Analysis-imp subscriber, shadow memory updated on writes, equality check on reads, prints regex-parseable PASS/FAIL. |
| 96 | +- **"Why both directed and random?"** Directed tests prove specific requirements (reset, overwrite, all-addresses). Random tests explore unexpected combinations — that's how the bug demo finds the addr-7 corruption it wasn't told to look for. |
| 97 | +- **"What's the role of `tb_valid`?"** TB-only signal pulsed by the driver so the monitor only emits transactions that the test actually scheduled. Avoids false reads being scored when the bus is idle. |
| 98 | +- **"How did you separate the buggy DUT?"** Same ports, different module name (`memory_ctrl_buggy`). `tb_top_uvm` selects via `` `ifdef USE_BUGGY_DUT ``; the bug-run TCL adds `+define+USE_BUGGY_DUT` and compiles the buggy file. |
| 99 | +- **"What's the difference between your env and full UVM?"** The pieces are real UVM components — agent/env/test/scoreboard/coverage. What I'd add next: register-abstraction layer (RAL), virtual sequencer, layered tests, coverage closure tracking across runs. |
| 100 | + |
| 101 | +## Troubleshooting |
| 102 | + |
| 103 | +- **`Error: (vlog-2163) ... 'uvm_pkg' could not be found`** — your simulator doesn't have UVM. Use Questa or recompile UVM source against ModelSim manually. |
| 104 | +- **`# ** Error (suppressible): ... 'uvm_macros.svh' not found`** — `+incdir+tb/uvm` is missing from `vlog`. Use the provided TCL script. |
| 105 | +- **Dashboard says "Log file not found"** — run the corresponding TCL script before `dashboard.py`. |
| 106 | +- **All UVM reads PASS but `regression.py` exits 1** — there's a stray `UVM_ERROR` somewhere; open the log and search for `UVM_ERROR`. |
| 107 | +- **Self-hosted CI never runs** — the SV job in `regression.yml` is gated by `if: false`. Flip it after registering a runner. |
0 commit comments