RISC-V is an open-source Instruction Set Architecture (ISA) that is revolutionizing hardware design. However, the freedom to implement custom cores brings a massive verification challenge: How do we ensure our custom core actually obeys the RISC-V spec?
RISC-V Processor Verification
Learn how to verify the open-standard RISC-V architecture. From checking simple ADD instructions to verifying complex pipelines and hazards.
Why RISC-V Verification?
The Verification Challenge
Verifying a processor is different from verifying a peripheral (like SPI or I2C). You are not just checking signals;
- Instruction Decoding: Does the core understand every legal opcode?
- Execution: Does `ADD x1, x2, x3` actually put `x2 + x3` into `x1`?
- Hazards: What happens if I use a register immediately after writing to it?
- Privilege Modes: Do exceptions and interrupts work correctly?
Our Learning Path
1. RV32I Basics
Understanding the 32-bit Integer base instruction set: R-Type, I-Type, S-Type, etc.
2. Verification Plan
Developing a strategy: Feature extraction, coverage goals, and corner cases.
3. Stimulus Generation
Using constrained random generation to create valid streams of assembly instructions.
4. Reference Models
Using an Instruction Set Simulator (ISS) like Spike or Whisper as a golden monitor.
Snippet: Validating an ALU Operation
A simple check in a Scoreboard might look like this:
// Simple check inside UVM Scoreboard
virtual function void check_alu(transaction tr);
bit [31:0] expected;
// Golden Reference Logic
case (tr.opcode)
ADD: expected = tr.rs1 + tr.rs2;
SUB: expected = tr.rs1 - tr.rs2;
AND: expected = tr.rs1 & tr.rs2;
OR: expected = tr.rs1 | tr.rs2;
endcase
// Comparison
if (tr.rd_val !== expected) begin
`uvm_error("ALU_FAIL", $sformatf("Op: %s, RS1: %0h, RS2: %0h | Exp: %0h, Act: %0h",
tr.opcode.name(), tr.rs1, tr.rs2, expected, tr.rd_val))
end
endfunction