| Feature | Test Scenario | Coverage Goal |
|---|---|---|
| ALU Arithmetic | Directed tests for every opcode (ADD, SUB, AND, OR, XOR, SLT, SLTU). Random operands (0, -1, MaxInt, MinInt, Alt bits). |
100% Opcode Coverpoint 100% Toggle on Result |
| Control Flow | Branches: BEQ, BNE, BLT, BGE. Force taken/not-taken
paths. Jumps: JAL, JALR with random offsets. |
100% Branch Direction Cross: Opcode x Taken/NotTaken |
| Data Hazards | RAW (Read-After-Write) with separation 0 (back-to-back), 1, and 2 cycles. Mix ALU-to-ALU, Load-to-ALU. |
Cross: SourceReg == PrevDestReg |
| Load/Store | Byte, Half, Word access. aligned and misaligned (if
supported). Write-Read-Check consistency. |
Address range partitions (Low, Mid, High) |
| Privileged | Illegal instruction decoding (trigger Exception). ECALL/EBREAK handling. |
100% Exception Code coverage |
Verification Plan
A processor is a complex state machine. Your plan needs to cover arithmetic correctness, pipeline hazards, and illegal opcodes.
Detailed Test Plan
Functional Coverage Model
A robust SystemVerilog coverage model should include:
covergroup rv32i_cov;
// 1. Opcode Coverage
cp_opcode: coverpoint instr_pkt.opcode {
bins r_type = {OP_ADD, OP_SUB, OP_SLL, ...};
bins i_type = {OP_ADDI, OP_LB, OP_LH, ...};
bins b_type = {OP_BEQ, OP_BNE, ...};
}
// 2. Hazard Coverage (History)
// Did we use x1 immediately after writing to it?
cp_raw_hazard: coverpoint (prev_rd == curr_rs1) && (prev_rd != 0) {
bins hazard_hit = {1};
}
// 3. Register Usage
cp_rs1: coverpoint instr_pkt.rs1;
cp_rs2: coverpoint instr_pkt.rs2;
cp_rd: coverpoint instr_pkt.rd;
// Cross: Did we see every register used with every opcode?
cross cp_opcode, cp_rd;
endgroup