37 KiB
Fall 2026 DV Onboarding Test Plan
NOTE: THIS IS A TEMPLATE FOR YOU TO FOLLOW. THIS IS NOT A COMPREHENSIVE TESTPLAN. YOU NEED TO EXTEND IT.
Document information
| Field | Value |
|---|---|
| Verification engineer | Dylan Benzi, benziboy, dbenzi3 |
| Plan revision | Initial |
| Date | 2026-09-26 |
Revision history
| Revision | Date | Changes |
|---|---|---|
| Initial | 2026-09-26 | Initial planned tests |
| Final | YYYY-MM-DD |
1. Functional tests
Functional-test summary
Implemented ISA to test
- ADD
- ADDI
- SUB
- LW
- SW
- BEQ
- SLL
- SRL
- EBREAK
| Test ID | Test name | Functionality being tested | Expected result | Status |
|---|---|---|---|---|
| 1.1 | add overflow | add two regs causing an overflow | overflow discarded | Planned |
| 1.2 | addi overflow | add imm to reg causing an overflow | overflow discarded | Planned |
| 1.3 | addi negative | add negative imm | imm is subtracted | Planned |
| 1.4 | add typical | add two regs | regs added properly | Planned |
| 1.5 | addi typical | add imm to reg | imm added properly | Planned |
| 1.6 | addi negative overflow | add negative numbers causing an overflow | negative overflow wrap around | Planned |
| 1.7 | sub overflow | subtract two regs causing an overflow | negative overflow wrap around | Planned |
| 1.8 | sub typical | subtract two regs | regs subtracted properly | Planned |
| 1.9 | sll oob | shift left by larger than 2^5 bits | left shift constrainted to 2^5 | Planned |
| 1.10 | srl oob | shift right by larger than 2^5 bits | right shift constrainted to 2^5 | Planned |
| 1.11 | sll zero | shift left by zero bits | no shift | Planned |
| 1.12 | srl zero | shift right by zero bits | no shift | Planned |
| 1.13 | sll one | shift left by one bit | logical left shift by one bit | Planned |
| 1.14 | srl one | shift right by one bit | logical right shift by one bit | Planned |
| 1.15 | sll typical | shift left by <2^5 bits | correct logical left shift | Planned |
| 1.16 | srl typical | shift right by <2^5 bits | correct logical right shift | Planned |
| 1.17 | lw zero offset | lw with zero offset | zero offset computed | Planned |
| 1.18 | sw zero offset | sw with zero offset | zero offset computed + stored | Planned |
| 1.19 | lw positive | lw with positive offset | correct offset computed | Planned |
| 1.20 | sw positive | sw with positive offset | correct offset computed + stored | Planned |
| 1.21 | lw negative | lw with negative offset | correct offset computed | Planned |
| 1.22 | sw negative | sw with negative offset | correct offset computed + stored | Planned |
| 1.23 | lw x0 | lw into x0 reg | write discarded, x0 remains 0 | Planned |
| 1.24 | beq x0 | beq with both regs as x0 | take branch | Planned |
| 1.25 | beq not taken | beq with non-equal regs | branch not taken | Planned |
| 1.26 | beq typical | beq with equal regs | branch taken | Planned |
| 1.27 | ebreak immediately | ebreak as first instruction | halt CPU | Planned |
Functional-test details
1.1 — add overflow
Functionality: add two registers together that would cause an overflow
Initial state:
- Registers: x1 = 0xFFFFFFFF, x2 = 0xFFFFFFFF
- Data memory: none
- Other setup: none
Program:
prog = '{
// asm_instr(.op(...), .rd(...), .rs1(...), .rs2(...), .imm(...)),
asm_instr(.op(OP_ADDI), .rd(1), .rs1(0), .imm(-1)),
asm_instr(.op(OP_ADDI), .rd(2), .rs1(0), .imm(-1)),
asm_instr(.op(OP_ADD), .rd(2), .rs1(1), .rs2(2)),
EBREAK_WORD
};
Expected result:
| Register or memory word | Expected value | Calculation or explanation |
|---|---|---|
x2 |
32'hFFFFFFFE |
0xFFFFFFFF + 0xFFFFFFFF = 0x(1)FFFFFFFE, the leading 1 is truncated |
Pass criteria: 3 cycle operation
Final result:
1.2 — addi overflow
Functionality: add an immediate to a register that would cause an overflow
Initial state:
- Registers: x1 = 0xFFFFFFFF
- Data memory: none
- Other setup: none
Program:
prog = '{
// asm_instr(.op(...), .rd(...), .rs1(...), .rs2(...), .imm(...)),
asm_instr(.op(OP_ADDI), .rd(1), .rs1(0), .imm(-1)),
asm_instr(.op(OP_ADDI), .rd(1), .rs1(1), .imm(1)),
EBREAK_WORD
};
Expected result:
| Register or memory word | Expected value | Calculation or explanation |
|---|---|---|
x1 |
32'h00000000 |
0xFFFFFFFF + 0x1 = 0x(1)00000000, the leading 1 is truncated |
Pass criteria: 2 cycle operation
Final result:
1.3 — addi negative
Functionality: adds a negative value to a register using addi, effectively subtracting from that register
Initial state:
- Registers: x1 = 0x1
- Data memory: none
- Other setup: none
Program:
prog = '{
// asm_instr(.op(...), .rd(...), .rs1(...), .rs2(...), .imm(...)),
asm_instr(.op(OP_ADDI), .rd(1), .rs1(0), .imm(1)),
asm_instr(.op(OP_ADDI), .rd(1), .rs1(1), .imm(-1)),
EBREAK_WORD
};
Expected result:
| Register or memory word | Expected value | Calculation or explanation |
|---|---|---|
x1 |
32'h0 |
0x1 - 0x1 = 0x0 |
Pass criteria: 2 cycle operation
Final result:
1.4 — add typical
Functionality: add two registers with values that will not cause an overflow
Initial state:
- Registers: x1 = 0x123, x2 = 0x123
- Data memory: none
- Other setup: none
Program:
prog = '{
// asm_instr(.op(...), .rd(...), .rs1(...), .rs2(...), .imm(...)),
asm_instr(.op(OP_ADDI), .rd(1), .rs1(0), .imm(0x123)),
asm_instr(.op(OP_ADDI), .rd(2), .rs1(0), .imm(0x123)),
asm_instr(.op(OP_ADD), .rd(2), .rs1(1), .rs2(2)),
EBREAK_WORD
};
Expected result:
| Register or memory word | Expected value | Calculation or explanation |
|---|---|---|
x2 |
32'h246 |
0x123 + 0x123 = 0x246 |
Pass criteria: 3 cycle operation
Final result:
1.5 — addi typical
Functionality: addi with immediate added to register without causing an overflow
Initial state:
- Registers: none
- Data memory: none
- Other setup: none
Program:
prog = '{
// asm_instr(.op(...), .rd(...), .rs1(...), .rs2(...), .imm(...)),
asm_instr(.op(OP_ADDI), .rd(1), .rs1(0), .imm(0x123)),
EBREAK_WORD
};
Expected result:
| Register or memory word | Expected value | Calculation or explanation |
|---|---|---|
x1 |
32'h123 |
0x0 + 0x123 = 0x123 |
Pass criteria: 1 cycle operation
Final result:
1.6 — addi negative overflow
Functionality: addi with a negative number causes an overflow wrap around to the register
Initial state:
- Registers: x1 = 0x0
- Data memory: none
- Other setup: none
Program:
prog = '{
// asm_instr(.op(...), .rd(...), .rs1(...), .rs2(...), .imm(...)),
asm_instr(.op(OP_ADDI), .rd(1), .rs1(0), .imm(-1)),
EBREAK_WORD
};
Expected result:
| Register or memory word | Expected value | Calculation or explanation |
|---|---|---|
x1 |
32'hFFFFFFFF |
0x0 - 0x1 = 0xFFFFFFFF, overflow back to full reg |
Pass criteria: 1 cycle operation
Final result:
1.7 — sub overflow
Functionality: sub registers that would cause an overflow wrap around
Initial state:
- Registers: x1 = 0x1
- Data memory: none
- Other setup: none
Program:
prog = '{
// asm_instr(.op(...), .rd(...), .rs1(...), .rs2(...), .imm(...)),
asm_instr(.op(OP_ADDI), .rd(1), .rs1(0), .imm(1)),
asm_instr(.op(OP_SUB), .rd(1), .rs1(0), .rs2(1)),
EBREAK_WORD
};
Expected result:
| Register or memory word | Expected value | Calculation or explanation |
|---|---|---|
x1 |
32'hFFFFFFFF |
0x0 - 0x1 = 0xFFFFFFFF overflow wrap around |
Pass criteria: 2 cycle operation
Final result:
1.8 — sub typical
Functionality: sub two registers without causing an overflow
Initial state:
- Registers: x1 = 0x123, x2 = 0x23
- Data memory: none
- Other setup: none
Program:
prog = '{
// asm_instr(.op(...), .rd(...), .rs1(...), .rs2(...), .imm(...)),
asm_instr(.op(OP_ADDI), .rd(1), .rs1(0), .imm(0x123)),
asm_instr(.op(OP_ADDI), .rd(2), .rs1(0), .imm(0x23)),
asm_instr(.op(OP_SUB), .rd(2), .rs1(1), .rs2(2)),
EBREAK_WORD
};
Expected result:
| Register or memory word | Expected value | Calculation or explanation |
|---|---|---|
x2 |
32'h100 |
0x123 - 0x23 = 0x100 |
Pass criteria: 3 cycle operation
Final result:
1.9 — srl oob
Functionality: srl masks to bottom 5 bits of data only, cannot shift more than 31
Initial state:
- Registers: x1 = 0xFFFFFFFF, x2 = 0x20
- Data memory: none
- Other setup: none
Program:
prog = '{
// asm_instr(.op(...), .rd(...), .rs1(...), .rs2(...), .imm(...)),
asm_instr(.op(OP_ADDI), .rd(1), .rs1(0), .imm(-1)),
asm_instr(.op(OP_ADDI), .rd(2), .rs1(0), .imm(32)),
asm_instr(.op(OP_SRL), .rd(1), .rs1(1), .rs2(2)),
EBREAK_WORD
};
Expected result:
| Register or memory word | Expected value | Calculation or explanation |
|---|---|---|
x1 |
32'hFFFFFFFF |
0x20 == 2^5 => no shift |
Pass criteria: 3 cycle operation
Final result:
1.10 — sll oob
Functionality: sll masks to bottom 5 bits of data only, cannot shift more than 31
Initial state:
- Registers: x1 = 0xFFFFFFFF, x2 = 0x20
- Data memory: none
- Other setup: none
Program:
prog = '{
// asm_instr(.op(...), .rd(...), .rs1(...), .rs2(...), .imm(...)),
asm_instr(.op(OP_ADDI), .rd(1), .rs1(0), .imm(-1)),
asm_instr(.op(OP_ADDI), .rd(2), .rs1(0), .imm(32)),
asm_instr(.op(OP_SLL), .rd(1), .rs1(1), .rs2(2)),
EBREAK_WORD
};
Expected result:
| Register or memory word | Expected value | Calculation or explanation |
|---|---|---|
x1 |
32'hFFFFFFFF |
0x20 == 2^5 => no shift |
Pass criteria: 3 cycle operation
Final result:
1.11 — sll zero
Functionality: sll with zero, causing no shift
Initial state:
- Registers: x1 = 0xFFFFFFFF
- Data memory: none
- Other setup: none
Program:
prog = '{
// asm_instr(.op(...), .rd(...), .rs1(...), .rs2(...), .imm(...)),
asm_instr(.op(OP_ADDI), .rd(1), .rs1(0), .imm(-1)),
asm_instr(.op(OP_SLL), .rd(1), .rs1(1), .rs2(0)),
EBREAK_WORD
};
Expected result:
| Register or memory word | Expected value | Calculation or explanation |
|---|---|---|
x1 |
32'hFFFFFFFF |
0xFFFFFFFF << 0x0 = 0xFFFFFFFF |
Pass criteria: 2 cycle operation
Final result:
1.12 — srl zero
Functionality: srl with zero, causing no shift
Initial state:
- Registers: x1 = 0xFFFFFFFF
- Data memory: none
- Other setup: none
Program:
prog = '{
// asm_instr(.op(...), .rd(...), .rs1(...), .rs2(...), .imm(...)),
asm_instr(.op(OP_ADDI), .rd(1), .rs1(0), .imm(-1)),
asm_instr(.op(OP_SRL), .rd(1), .rs1(1), .rs2(0)),
EBREAK_WORD
};
Expected result:
| Register or memory word | Expected value | Calculation or explanation |
|---|---|---|
x1 |
32'hFFFFFFFF |
0xFFFFFFFF << 0x0 = 0xFFFFFFFF |
Pass criteria: 2 cycle operation
Final result:
1.13 — sll one
Functionality: sll with one, causing a shift once to the left
Initial state:
- Registers: x1 = 0xFFFFFFFF, x2 = 0x1
- Data memory: none
- Other setup: none
Program:
prog = '{
// asm_instr(.op(...), .rd(...), .rs1(...), .rs2(...), .imm(...)),
asm_instr(.op(OP_ADDI), .rd(1), .rs1(0), .imm(-1)),
asm_instr(.op(OP_ADDI), .rd(2), .rs1(0), .imm(1)),
asm_instr(.op(OP_SLL), .rd(1), .rs1(1), .rs2(2)),
EBREAK_WORD
};
Expected result:
| Register or memory word | Expected value | Calculation or explanation |
|---|---|---|
x1 |
32'hFFFFFFFE |
0xFFFFFFFF << 0x1 = 0xFFFFFFFE |
Pass criteria: 3 cycle operation
Final result:
1.14 — srl one
Functionality: srl with one, causing a shift once to the right
Initial state:
- Registers: x1 = 0xFFFFFFFF, x2 = 1
- Data memory: none
- Other setup: none
Program:
prog = '{
// asm_instr(.op(...), .rd(...), .rs1(...), .rs2(...), .imm(...)),
asm_instr(.op(OP_ADDI), .rd(1), .rs1(0), .imm(-1)),
asm_instr(.op(OP_ADDI), .rd(2), .rs1(0), .imm(1)),
asm_instr(.op(OP_SRL), .rd(1), .rs1(1), .rs2(2)),
EBREAK_WORD
};
Expected result:
| Register or memory word | Expected value | Calculation or explanation |
|---|---|---|
x1 |
32'h7FFFFFFF |
0xFFFFFFFF >> 0x1 = 0x7FFFFFFF |
Pass criteria: 3 cycle operation
Final result:
1.15 — sll typical
Functionality: sll with a shift greater than 1 and less than 2^5
Initial state:
- Registers: x1 = 0xFFFFFFFF, x2 = 0x4
- Data memory: none
- Other setup: none
Program:
prog = '{
// asm_instr(.op(...), .rd(...), .rs1(...), .rs2(...), .imm(...)),
asm_instr(.op(OP_ADDI), .rd(1), .rs1(0), .imm(-1)),
asm_instr(.op(OP_ADDI), .rd(2), .rs1(0), .imm(4)),
asm_instr(.op(OP_SLL), .rd(1), .rs1(1), .rs2(2)),
EBREAK_WORD
};
Expected result:
| Register or memory word | Expected value | Calculation or explanation |
|---|---|---|
x1 |
32'hFFFFFFF0 |
0xFFFFFFFF << 0x4 = 0xFFFFFFF0 |
Pass criteria: 3 cycle operation
Final result:
1.16 — srl typical
Functionality: srl with a shift greater than 1 and less than 2^5
Initial state:
- Registers: x1 = 0xFFFFFFFF, x2 = 0x4
- Data memory: none
- Other setup: none
Program:
prog = '{
// asm_instr(.op(...), .rd(...), .rs1(...), .rs2(...), .imm(...)),
asm_instr(.op(OP_ADDI), .rd(1), .rs1(0), .imm(-1)),
asm_instr(.op(OP_ADDI), .rd(2), .rs1(0), .imm(4)),
asm_instr(.op(OP_SRL), .rd(1), .rs1(1), .rs2(2)),
EBREAK_WORD
};
Expected result:
| Register or memory word | Expected value | Calculation or explanation |
|---|---|---|
x1 |
32'h0FFFFFFF |
0xFFFFFFFF >> 0x4 = 0x0FFFFFFF |
Pass criteria: 3 cycle operation
Final result:
1.17 — lw zero offset
Functionality: lw with zero offset, loading in the register rs1
Initial state:
- Registers: none
- Data memory: dmem[0] = 0xFFFFFFFF
- Other setup: none
Program:
prog = '{
// asm_instr(.op(...), .rd(...), .rs1(...), .rs2(...), .imm(...)),
asm_instr(.op(OP_LW), .rd(1), .rs1(0), .imm(0)),
EBREAK_WORD
};
Expected result:
| Register or memory word | Expected value | Calculation or explanation |
|---|---|---|
x1 |
32'hFFFFFFFF |
x1 = M[0] => 0xFFFFFFFF |
Pass criteria: 2 cycle operation
Final result:
1.18 — sw zero offset
Functionality: sw with zero offset, storing in memory addr of rs1
Initial state:
- Registers: x1 = 0xFFFFFFFF
- Data memory: none
- Other setup: none
Program:
prog = '{
// asm_instr(.op(...), .rd(...), .rs1(...), .rs2(...), .imm(...)),
asm_instr(.op(OP_ADDI), .rd(1), .rs1(0), .imm(-1)),
asm_instr(.op(OP_SW), .rs1(0), .rs2(1), .imm(0)),
EBREAK_WORD
};
Expected result:
| Register or memory word | Expected value | Calculation or explanation |
|---|---|---|
dmem[0] |
32'hFFFFFFFF |
M[0] = x1 => 0xFFFFFFFF |
Pass criteria: 2 cycle operation
Final result:
1.19 — lw positive
Functionality: lw with a positive offset
Initial state:
- Registers: none
- Data memory: dmem[1] = 0xFFFFFFFF
- Other setup: none
Program:
prog = '{
// asm_instr(.op(...), .rd(...), .rs1(...), .rs2(...), .imm(...)),
asm_instr(.op(OP_LW), .rd(1), .rs1(0), .imm(4)),
EBREAK_WORD
};
Expected result:
| Register or memory word | Expected value | Calculation or explanation |
|---|---|---|
x1 |
32'hFFFFFFFF |
x1 = dmem[1] => 0xFFFFFFFF |
Pass criteria: 2 cycle operation
Final result:
1.20 — sw positive
Functionality: sw with a positive offset
Initial state:
- Registers: x1 = 0xFFFFFFFF
- Data memory: none
- Other setup: none
Program:
prog = '{
// asm_instr(.op(...), .rd(...), .rs1(...), .rs2(...), .imm(...)),
asm_instr(.op(OP_ADDI), .rd(1), .rs1(0), .imm(-1)),
asm_instr(.op(OP_SW), .rs1(0), .rs2(1), .imm(4)),
EBREAK_WORD
};
Expected result:
| Register or memory word | Expected value | Calculation or explanation |
|---|---|---|
dmem[1] |
32'hFFFFFFFF |
dmem[1] = x1 => 0xFFFFFFFF |
Pass criteria: 2 cycle operation
Final result:
1.21 — lw negative
Functionality: lw with a negative offset
Initial state:
- Registers: none
- Data memory: dmem[1023] = 0xFFFFFFFF
- Other setup: none
Program:
prog = '{
// asm_instr(.op(...), .rd(...), .rs1(...), .rs2(...), .imm(...)),
asm_instr(.op(OP_LW), .rd(1), .rs1(0), .imm(-1)),
EBREAK_WORD
};
Expected result:
| Register or memory word | Expected value | Calculation or explanation |
|---|---|---|
x1 |
32'hFFFFFFFF |
x1 = dmem[1023] => 0xFFFFFFFF |
Pass criteria: 2 cycle operation
Final result:
1.22 — sw negative
Functionality: sw with a negative offset
Initial state:
- Registers: x1 = 0xFFFFFFFF
- Data memory: none
- Other setup: none
Program:
prog = '{
// asm_instr(.op(...), .rd(...), .rs1(...), .rs2(...), .imm(...)),
asm_instr(.op(OP_ADDI), .rd(1), .rs1(0), .imm(-1)),
asm_instr(.op(OP_SW), .rs1(0), .rs2(1), .imm(-1)),
EBREAK_WORD
};
Expected result:
| Register or memory word | Expected value | Calculation or explanation |
|---|---|---|
dmem[1023] |
32'hFFFFFFFF |
dmem[1023] = x1 => 0xFFFFFFFF |
Pass criteria: 2 cycle operation
Final result:
1.23 — lw x0
Functionality: attempt to lw into x0 register
Initial state:
- Registers: none
- Data memory: dmem[0] = 0xFFFFFFFF
- Other setup: none
Program:
prog = '{
// asm_instr(.op(...), .rd(...), .rs1(...), .rs2(...), .imm(...)),
asm_instr(.op(OP_LW), .rd(0), .rs1(0), .imm(0)),
EBREAK_WORD
};
Expected result:
| Register or memory word | Expected value | Calculation or explanation |
|---|---|---|
x0 |
32'h0 |
x0 is to always remain 0 |
Pass criteria: 2 cycle operation
Final result:
1.24 — beq x0
Functionality: beq with both sources as x0
Initial state:
- Registers: none
- Data memory: none
- Other setup: none
Program:
prog = '{
// asm_instr(.op(...), .rd(...), .rs1(...), .rs2(...), .imm(...)),
asm_instr(.op(OP_BEQ), .rs1(0), .rs2(0), .imm(8)),
asm_instr(.op(OP_ADDI), .rd(1), .rs1(0), .imm(1)),
asm_instr(.op(OP_ADDI), .rd(1), .rs1(0), .imm(2)),
EBREAK_WORD
};
Expected result:
| Register or memory word | Expected value | Calculation or explanation |
|---|---|---|
x1 |
32'h2 |
skip ADDI x1, x0, 1, and run ADDI x1, x0, 2 |
Pass criteria: 2 cycle operation
Final result:
1.25 — beq not taken
Functionality: beq on two non-equal registers
Initial state:
- Registers: x1 = 0xFFFFFFFF
- Data memory: none
- Other setup: none
Program:
prog = '{
// asm_instr(.op(...), .rd(...), .rs1(...), .rs2(...), .imm(...)),
asm_instr(.op(OP_ADDI), .rd(1), .rs1(0), .imm(-1)),
asm_instr(.op(OP_BEQ), .rs1(0), .rs2(1), .imm(8)),
asm_instr(.op(OP_ADDI), .rd(2), .rs1(0), .imm(-1)),
EBREAK_WORD
};
Expected result:
| Register or memory word | Expected value | Calculation or explanation |
|---|---|---|
x2 |
32'hFFFFFFFF |
do not skip to EBREAK, and run ADDI x2, x0, -1 |
Pass criteria: 3 cycle operation
Final result:
1.26 — beq typical
Functionality: beq on two equal registers that are not x0
Initial state:
- Registers: x1 = 0xFFFFFFFF, x2 = 0xFFFFFFFF
- Data memory: none
- Other setup: none
Program:
prog = '{
// asm_instr(.op(...), .rd(...), .rs1(...), .rs2(...), .imm(...)),
asm_instr(.op(OP_ADDI), .rd(1), .rs1(0), .imm(-1)),
asm_instr(.op(OP_ADDI), .rd(2), .rs1(0), .imm(-1)),
asm_instr(.op(OP_BEQ), .rs1(1), .rs2(2), .imm(8)),
asm_instr(.op(OP_ADDI), .rd(3), .rs1(0), .imm(1)),
asm_instr(.op(OP_ADDI), .rd(3), .rs1(0), .imm(2)),
EBREAK_WORD
};
Expected result:
| Register or memory word | Expected value | Calculation or explanation |
|---|---|---|
x3 |
32'h2 |
skip ADDI x3, x0, 1, and run ADDI x3, x0, 2 |
Pass criteria: 4 cycle operation
Final result:
1.27 — ebreak immediately
Functionality: ebreak as first instruction, subsequent instructions not run
Initial state:
- Registers: none
- Data memory: none
- Other setup: none
Program:
prog = '{
// asm_instr(.op(...), .rd(...), .rs1(...), .rs2(...), .imm(...)),
EBREAK_WORD,
asm_instr(.op(OP_ADDI), .rd(1), .rs1(0), .imm(-1))
};
Expected result:
| Register or memory word | Expected value | Calculation or explanation |
|---|---|---|
x1 |
32'h0 |
ebreak before ADDI instruction |
Pass criteria: ebreak takes one cycle, other instructions not run
Final result:
2. Constrained-random tests
Instruction constraints
| Constraint | Provided, partial, or open | Behavior and purpose | Final implementation summary |
|---|---|---|---|
c_opcode |
Provided | use only opcodes implemented | No member change |
c_reg_bias |
Provided | encourage more reg-reg collisions, test x0 r/w | No member change |
c_imm_range |
Partial | use only immediates that fit into instruction | separate imm_range for I/S and B types |
c_mem_align |
Open | force word immediates to be multiples of 4 | mask/discard 2 LSBs for lw/sw |
c_imm_unused |
Provided | set imm to zero if not used in instr | No member change |
c_branch_target |
Partial | keep the target within the program mem | % 4, ≥ 4, <prog len |
c_no_branch_at_end |
Provided | prevent branching at the end of the program | No member change |
c_branch_taken_bias |
Open | bias rs1/rs2 to being equal values to eachother | weight rs1/rs2 values to encourage equal values |
External-port constraints
| Constraint | Provided, partial, or open | Behavior and purpose | Final implementation summary |
|---|---|---|---|
c_align |
Provided | word align instr | No member change |
c_valid_window |
Partial | ensure addr is inside register file | restrict to 32 entries |
c_reg_read_only |
Provided | do not write to reg via port | No member change |
c_data_corners |
Open | bias towards specific data values to test | all 1s, all 0s, checkerboard, etc |
Random-program test
| Item | Plan |
|---|---|
| Number of programs per seed | 50 |
| Program-length range | 2 ≤ len ≤ 50 |
| Information logged for reproduction | Numeric SVSEED, iteration, and complete generated program |
Implementation outline:
// Write the intended loop and lifecycle using seqr.gen_program(...).
int min_len = 2;
int max_len = 50;
int random_progs = 50;
int max_cycles = 2000;
int dmem_words = 16;
for (int i = 0; i < random_progs; i++) begin
int len = $urandom_range(min_len, max_len);
string name = $sformatf("random_gen_%0d_len_%0d", i, len);
sb.set_test(name);
drv.reset_task();
seqr.gen_program(len);
seqr.wait_for_empty();
repeat (2) @(cpu_if.cb);
drv.run_program(max_cycles);
if (drv.last_run_completed) begin
readback(2, REG_COUNT);
readback(1, dmem_words);
end else begin
$display($stime, " TB: Skipping %s readback after CPU timeout\n", name);
drv.reset_task();
end
end
3. Assertions
Assertion summary
| Assertion ID/name | Behavior checked | When it is sampled/disabled | Activating test |
|---|---|---|---|
3.1 / X0_REMAINS_0 |
x0 = 0 | posedge clk | lw_x0 |
3.2 / HALT_PULSE |
halt pulses high then low | after ebreak | ebreak_immediately |
3.1 — X0_REMAINS_0
Timing requirement in words: on every clock pulse, check that x0 is 0
X0_REMAINS_0:
assert property (@(posedge clk) disable iff (rst)
dut.register_crossbar[0] == 32'b0)
else assertion_fail("x0 is nonzero");
Evidence that it detects a violation:
3.2 — HALT_PULSE
Timing requirement in words: halt pulses after ebreak
HALT_PULSE:
assert property (@(posedge clk) disable iff (rst)
cpu_if.cpu_halted |=> !cpu_if.cpu_halted)
else assertion_fail("halt did not pulse correctly");
Evidence that it detects a violation:
4. Encrypted CPU Bug Hunt
Random discovery
| Field | Evidence |
|---|---|
| Discovery command | make bug_hunt SEED=random |
Numeric SVSEED |
|
| Failing iteration | |
| First failure message | |
| Reproduction command | make bug_hunt SEED=________ |
| Reproduces consistently? | Yes / No |
Original failing program:
prog = '{
// Paste original generated sequence
EBREAK_WORD
};
Expected vs. actual
| Instruction / event | Expected | Actual | Cycle/time |
|---|---|---|---|
First architectural divergence:
Minimization
Minimized reproducer:
prog = '{
// Smallest sequence that still fails
EBREAK_WORD
};
Waveform evidence
Include a screenshot showing the offending instruction and the first incorrect architectural result.
Conclusion
Trigger:
Expected behavior:
Observed behavior:
Behavioral characterization: