🔧 Makefile responsibility split¶
📅 Date: 2025-12-13¶
🎯 Problem¶
Previously Makefile.verilator handled both Verilator and Spike. That caused confusion:
- The Verilator Makefile was running Spike
- ENABLE_SPIKE, ENABLE_COMPARE flags were tangled
- Responsibilities were unclear
✅ Solution: split responsibilities¶
Each Makefile is now responsible only for its own job:
┌─────────────────────────────────────────┐
│ Makefile.verilator │
│ └─ Verilator only │
│ ├─ Build (verilate) │
│ ├─ Run RTL simulation │
│ └─ Open waveforms │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ Makefile.spike │
│ └─ Spike only │
│ ├─ Run Spike │
│ ├─ Compare logs │
│ └─ Validate │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ test_manager.py │
│ └─ Orchestration │
│ ├─ Run RTL │
│ ├─ Run validation (optional) │
│ └─ Generate HTML report │
└─────────────────────────────────────────┘
📁 Makefile.verilator — Verilator only¶
Responsibilities:¶
- ✅ Verilator build (verilate)
- ✅ Run RTL simulation
- ✅ Generate waveforms
- ✅ Save logs
Removed:¶
- ❌
run-spiketarget (→ Makefile.spike) - ❌
compare-logstarget (→ Makefile.spike) - ❌
html-reporttarget (→ test_manager.py) - ❌
ENABLE_SPIKEflag - ❌
ENABLE_COMPAREflag - ❌
ENABLE_HTML_REPORTflag
Usage:¶
RTL simulation only (no validation):
Result:
- results/logs/verilator/rv32ui-p-add/commit_trace.log
- results/logs/verilator/rv32ui-p-add/waveform.fst
- results/logs/verilator/rv32ui-p-add/uart_output.log
- Spike does not run ✅
📁 Makefile.spike — Spike only¶
Responsibilities:¶
- ✅ Run Spike
- ✅ Compare RTL and Spike logs
- ✅ Produce diff.log
Targets:¶
run-spike— run Spike golden referencecompare— RTL vs Spike comparisonvalidate— Spike + compare (one command)
Usage:¶
Run Spike:
make -f Makefile.spike run-spike \
TEST_NAME=rv32ui-p-add \
LOG_DIR=results/logs/verilator/rv32ui-p-add
Compare logs:
make -f Makefile.spike compare \
TEST_NAME=rv32ui-p-add \
RTL_LOG=results/logs/verilator/rv32ui-p-add/commit_trace.log \
SPIKE_LOG=results/logs/verilator/rv32ui-p-add/spike_commit.log
Full validation (Spike + compare):
make -f Makefile.spike validate \
TEST_NAME=rv32ui-p-add \
LOG_DIR=results/logs/verilator/rv32ui-p-add \
RTL_LOG=results/logs/verilator/rv32ui-p-add/commit_trace.log
Result:
- results/logs/verilator/rv32ui-p-add/spike_commit.log
- results/logs/verilator/rv32ui-p-add/diff.log
🐍 test_manager.py — orchestration¶
Responsibilities:¶
- ✅ Invoke RTL simulation (Makefile.verilator)
- ✅ Invoke validation (validation_runner.py → Makefile.spike)
- ✅ Generate HTML report
- ✅ Test pass/fail decision
Usage:¶
Test with automatic validation:
What it does:
1. make -f Makefile.verilator run TEST_NAME=rv32ui-p-add (RTL)
2. validation_runner.py --test-name rv32ui-p-add (Spike + compare)
3. Generate HTML report
4. Final result: TEST PASSED - VALIDATED or TEST FAILED
🔄 Workflow examples¶
Scenario 1: RTL simulation only (quick test)¶
When to use: - Quick RTL change checks - Inspecting waveforms - Checking for crashes
Scenario 2: RTL + validation (full test)¶
# Automatic validation via test_manager.py
make -f Makefile.verilator test-run TEST_NAME=rv32ui-p-add
What happens: 1. RTL simulation runs 2. Spike runs automatically 3. Logs are compared 4. HTML report is generated 5. Result: PASSED/FAILED
When to use: - Regression testing - Ensuring test correctness - CI/CD pipelines
Scenario 3: Manual step by step¶
# 1. RTL simulation
make -f Makefile.verilator run TEST_NAME=rv32ui-p-add
# 2. Run Spike
make -f Makefile.spike run-spike \
TEST_NAME=rv32ui-p-add \
LOG_DIR=results/logs/verilator/rv32ui-p-add
# 3. Compare
make -f Makefile.spike compare \
TEST_NAME=rv32ui-p-add \
RTL_LOG=results/logs/verilator/rv32ui-p-add/commit_trace.log \
SPIKE_LOG=results/logs/verilator/rv32ui-p-add/spike_commit.log
When to use: - Debugging - Customizing Spike parameters - Step-by-step control
🎯 Benefits¶
✅ Clear split¶
- Verilator Makefile → Verilator only
- Spike Makefile → Spike only
- test_manager.py → orchestration
✅ Independence¶
- Makefiles are independent of each other
- Run what you need
- Less confusion
✅ Flexibility¶
- RTL only → quick test
- RTL + validation → full test
- Manual steps → debug
✅ Easier maintenance¶
- Each Makefile owns one area
- Changes are localized
- Structure is easy to follow
📚 Command cheat sheet¶
| Goal | Command |
|---|---|
| RTL only | make -f Makefile.verilator run TEST_NAME=... |
| RTL + validation | make -f Makefile.verilator test-run TEST_NAME=... |
| Spike only | make -f Makefile.spike run-spike TEST_NAME=... LOG_DIR=... |
| Spike + compare | make -f Makefile.spike validate TEST_NAME=... LOG_DIR=... RTL_LOG=... |
| Open waveform | make -f Makefile.verilator view TEST_NAME=... |
🔧 Migration guide¶
Old command → new command¶
# OLD (no longer works):
make -f Makefile.verilator run TEST_NAME=rv32ui-p-add \
ENABLE_SPIKE=1 ENABLE_COMPARE=1 ENABLE_HTML_REPORT=1
# NEW:
make -f Makefile.verilator test-run TEST_NAME=rv32ui-p-add
# OLD (removed):
make -f Makefile.verilator run-spike TEST_NAME=rv32ui-p-add
# NEW:
make -f Makefile.spike run-spike \
TEST_NAME=rv32ui-p-add \
LOG_DIR=results/logs/verilator/rv32ui-p-add
# OLD (removed):
make -f Makefile.verilator compare-logs TEST_NAME=rv32ui-p-add
# NEW:
make -f Makefile.spike compare \
TEST_NAME=rv32ui-p-add \
RTL_LOG=results/logs/verilator/rv32ui-p-add/commit_trace.log \
SPIKE_LOG=results/logs/verilator/rv32ui-p-add/spike_commit.log
✅ Fixes¶
1. mkdir error¶
Problem: mkdir: cannot create directory '': No such file or directory
Cause: VERILATOR_LOG was empty when TEST_NAME was unset
Fix:
# OLD:
dirs:
@mkdir -p "$(BUILD_DIR)" "$(OBJ_DIR)" "$(LOG_DIR)" "$(VERILATOR_LOG)"
# NEW:
dirs:
@mkdir -p "$(BUILD_DIR)" "$(OBJ_DIR)" "$(RESULTS_DIR)/logs"
@if [ -n "$(TEST_NAME)" ]; then mkdir -p "$(VERILATOR_LOG)"; fi
2. Mixed responsibilities¶
Problem: Verilator Makefile was also doing Spike work
Fix: - Spike targets removed - Validation moved to test_manager.py - Each Makefile does only its own job
🎉 Conclusion¶
You now have: - ✅ Independent Makefiles - ✅ Clear responsibilities - ✅ Simpler usage - ✅ No mkdir error - ✅ Verilator = Verilator only - ✅ Spike = Spike only - ✅ test_manager.py = orchestration
Clean, modular, and easy to understand 🚀