Verification on this project follows two complementary paths that are kept deliberately independent. The second exists to check the first, and it has already earned its place.
Path 1 — the official suite (SystemVerilog + UVM)
Directed testbenches per peripheral, each paired with SystemVerilog Assertions covering design-intent, protocol/interface, and performance properties, plus a UVM environment for the AXI4 bus. Functional and code coverage are collected in Vivado xsim and exported as HTML reports, driven by test plans tracked per peripheral. This is the verification evidence formally submitted to the competition jury.
Path 2 — the independent cross-check (cocotb)
A second, Python-based pass that deliberately uses
third-party open-source reference models
(cocotbext-i2c, cocotbext-uart) instead of our own
hand-written ones.
The reason is specific. If the same engineer writes both the RTL and the model that checks it, a misunderstanding of the protocol gets written into both — and the testbench then confirms the bug instead of catching it. Swapping in a model nobody on the team wrote breaks that symmetry. This path is not a substitute for the official suite; it is a check against it.
It caught a real bug
The I2C master was not generating a genuine I2C START condition — and our own directed testbench passed anyway, because the hand-written slave model checking it shared the same incorrect assumption.
The cocotb cross-check, using a reference slave model written by someone with no knowledge of our RTL, failed immediately. This is the exact failure mode the second path was built to expose, and it is the strongest argument we have for keeping it.
Independent ISA checking
Instruction-level correctness is additionally checked against the spike RISC-V ISA simulator with a checker script and directed/basic ISA test suites — so core behaviour is compared against a reference implementation rather than against our own expectations.