Skip to content

Commit 33ae24a

Browse files
committed
Add advanced verification environment and waveform screenshots
1 parent d08792e commit 33ae24a

37 files changed

Lines changed: 1323 additions & 271 deletions

.github/workflows/regression.yml

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
# ============================================================
2+
# .github/workflows/regression.yml
3+
#
4+
# IMPORTANT: GitHub-hosted runners do NOT have ModelSim/Questa
5+
# installed (commercial licensed tools). This CI workflow does
6+
# the parts that DO work in CI:
7+
# 1. Static checks on the Python tooling
8+
# 2. Sanity-runs regression.py + dashboard.py against the
9+
# sample log committed under reports/sample_uvm_sim_log.txt
10+
# (if present) so reviewers see the dashboard generates.
11+
# 3. Verifies the repo's expected folder structure.
12+
#
13+
# To run the actual SystemVerilog regression in CI you need a
14+
# self-hosted runner with Questa/ModelSim installed. A skeleton
15+
# job for that is included below, gated to never run by default.
16+
# ============================================================
17+
18+
name: regression
19+
20+
on:
21+
push:
22+
branches: [ main, master ]
23+
pull_request:
24+
workflow_dispatch:
25+
26+
jobs:
27+
28+
python-and-structure:
29+
name: Python tooling + repo structure
30+
runs-on: ubuntu-latest
31+
steps:
32+
- name: Checkout
33+
uses: actions/checkout@v4
34+
35+
- name: Setup Python
36+
uses: actions/setup-python@v5
37+
with:
38+
python-version: "3.11"
39+
40+
- name: Install Python deps
41+
run: |
42+
python -m pip install --upgrade pip
43+
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
44+
45+
- name: Compile-check Python
46+
run: |
47+
python -m py_compile tools/regression.py
48+
python -m py_compile tools/dashboard.py
49+
50+
- name: Verify repo structure
51+
run: |
52+
for p in \
53+
rtl/memory_ctrl.sv \
54+
rtl/memory_ctrl_buggy.sv \
55+
tb/simple/tb_top.sv \
56+
tb/simple/mem_test.sv \
57+
tb/uvm/mem_if.sv \
58+
tb/uvm/mem_uvm_pkg.sv \
59+
tb/uvm/tb_top_uvm.sv \
60+
scripts/run_simple.tcl \
61+
scripts/run_uvm.tcl \
62+
scripts/run_uvm_bug.tcl \
63+
tools/regression.py \
64+
tools/dashboard.py \
65+
docs/verification_plan.md \
66+
docs/architecture.md \
67+
README.md
68+
do
69+
test -f "$p" || { echo "MISSING: $p"; exit 1; }
70+
done
71+
echo "All required files present."
72+
73+
- name: Build a synthetic log and exercise the tools
74+
run: |
75+
mkdir -p reports
76+
cat > reports/sample_log.txt <<'EOF'
77+
# UVM_INFO @ 100: top.env.sb [SB] PASS read_chk1_addr0 expected=0x00 actual=0x00
78+
# UVM_INFO @ 200: top.env.sb [SB] PASS read_chk2_addr1 expected=0xa1 actual=0xa1
79+
# UVM_INFO @ 300: top.env.sb [SB] PASS read_chk3_addr7 expected=0x27 actual=0x27
80+
# UVM_INFO @ 400: top.env.cov [COV] COVERAGE_REPORT addr=100.0% op=100.0% data=100.0% cross=100.0% trans=100.0% overall=100.0%
81+
EOF
82+
python tools/regression.py reports/sample_log.txt
83+
python tools/dashboard.py reports/sample_log.txt
84+
test -f reports/dashboard.html
85+
echo "Dashboard HTML generated successfully."
86+
87+
- name: Upload dashboard artifact
88+
uses: actions/upload-artifact@v4
89+
with:
90+
name: dashboard
91+
path: reports/dashboard.html
92+
93+
# ----------------------------------------------------------
94+
# OPTIONAL: real SV regression on a self-hosted runner.
95+
# This job NEVER runs by default. To enable, register a
96+
# self-hosted runner with Questa installed and replace the
97+
# `if: false` guard with `if: github.event_name == ...`.
98+
# ----------------------------------------------------------
99+
sv-simulation-self-hosted:
100+
name: SV regression (self-hosted, optional)
101+
if: false # disabled until you bring your own simulator
102+
runs-on: [self-hosted, questa]
103+
needs: python-and-structure
104+
steps:
105+
- uses: actions/checkout@v4
106+
- name: Run UVM regression
107+
shell: bash
108+
run: |
109+
vsim -c -do scripts/run_uvm.tcl
110+
python tools/regression.py reports/uvm_sim_log.txt
111+
python tools/dashboard.py reports/uvm_sim_log.txt
112+
- uses: actions/upload-artifact@v4
113+
with:
114+
name: uvm-dashboard
115+
path: reports/dashboard.html

.gitignore

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,27 @@
1-
work/
2-
*.wlf
3-
*.vcd
4-
sim_log.txt
5-
report.html
1+
# ModelSim / Questa
2+
work/
63
transcript
4+
vsim.wlf
5+
vsim.dbg
6+
modelsim.ini
7+
*.vstf
8+
*.mti
9+
.qsf.lock
10+
11+
# Simulation outputs
12+
waveform.vcd
13+
*.log
14+
reports/*
15+
!reports/.gitkeep
16+
17+
# Python
18+
__pycache__/
19+
*.pyc
20+
.venv/
21+
venv/
22+
23+
# Editors
24+
.vscode/
25+
.idea/
26+
*.swp
27+
.DS_Store

README.md

Lines changed: 96 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,107 @@
1-
# Memory Controller Verification (SystemVerilog + Python)
1+
# Memory Controller Verification
22

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.
75

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.
916

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
1130

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 |
1336

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.
1738

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)
2340

24-
---
41+
```powershell
42+
cd path\to\memory-ctrl-verification
2543
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
2747
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
3751
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
3955
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.

docs/architecture.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Architecture
2+
3+
## UVM environment
4+
+---------------------------------------------------------+
5+
| tb_top_uvm |
6+
| |
7+
| clk_gen --> clk |
8+
| reset --> rst_n |
9+
| |
10+
| uvm_config_db::set("vif" -> dut_if) |
11+
| run_test("mem_base_test") |
12+
| |
13+
| +---------------------+ +-------------------+ |
14+
| | mem_if |<------>| memory_ctrl / | |
15+
| | (clk,rst_n,we,... | | memory_ctrl_buggy | |
16+
| | tb_valid) | +-------------------+ |
17+
| +----------^----------+ |
18+
+--------------|------------------------------------------+
19+
|
20+
___________________|____________________
21+
| |
22+
23+
24+
## Simple environment (legacy / educational)
25+
## Data flow per transaction
26+
27+
1. Sequence builds a `mem_seq_item` and sends it to the sequencer.
28+
2. Driver pops the item, drives `we/addr/din` and pulses `tb_valid` for one cycle.
29+
3. DUT samples on `posedge clk`. For writes, `mem[addr]` updates. For reads, `dout` is `mem[addr]` combinationally.
30+
4. Monitor samples the interface at `posedge clk + 1ns`, only when `tb_valid==1`. It builds a complete `mem_seq_item` (including `dout`) and broadcasts on its analysis port.
31+
5. Scoreboard updates shadow on writes, checks `dout === shadow_mem[addr]` on reads.
32+
6. Coverage subscriber samples covergroups on the same item.

docs/img/bug_run_dashboard.png

31.1 KB
Loading

docs/img/clean_run_dashboard.png

34.5 KB
Loading

docs/img/waveform_addr7_bug.png

256 KB
Loading

docs/img/waveform_reset.png

297 KB
Loading

docs/results_template.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Results Template
2+
3+
> Copy this file when recording a run. Fill in the brackets.
4+
5+
## Run metadata
6+
- Date / time : `<YYYY-MM-DD HH:MM>`
7+
- Simulator : `<Questa 2023.x / ModelSim Intel Starter / ...>`
8+
- Host OS : `<Windows 11 / Ubuntu 22.04 / ...>`
9+
- Git SHA : `<commit hash>`
10+
- Flow : `<simple | uvm-clean | uvm-bug>`
11+
- Seed : `<value or "default">`
12+
13+
## Test summary
14+
| Metric | Value |
15+
|---------------|-------|
16+
| Total checks | `<N>` |
17+
| Passed | `<N>` |
18+
| Failed | `<N>` |
19+
| Pass rate | `<NN.N%>` |
20+
| UVM_ERROR | `<N>` |
21+
| UVM_FATAL | `<N>` |
22+
23+
## Coverage
24+
| Coverpoint | Coverage |
25+
|-------------------|----------|
26+
| Address | `<NN.N%>` |
27+
| Operation | `<NN.N%>` |
28+
| Data class | `<NN.N%>` |
29+
| Cross addr × op | `<NN.N%>` |
30+
| Address transitions | `<NN.N%>` |
31+
| **Overall** | `<NN.N%>` |
32+
33+
## Failing checks
34+
| # | Test name | Expected | Actual | Notes |
35+
|----|-----------|----------|--------|-------|
36+
| 1 | | | | |
37+
38+
## Notes / observations
39+
40+
- `<free-form text — e.g. "buggy DUT failed at addr 7 as expected, T1–T5 directed all PASS">`

0 commit comments

Comments
 (0)