In the final part of this 3-post series (Part 1, Part 2), I will show a way of covering enum transitions and conditionally ignoring transitions to and from certain enum values.
For example, in the case of a CPU’s instruction set, you want to make sure that all possible combinations of two consecutive instructions are executed. The most straightforward implementation is to define an enum with all the opcodes, and a transition bin for the opcode:
class instruction;
typedef enum {
ADD, SUB, MUL, DIV, // Arithmetic
AND, OR, XOR, NOT, // Logic
JMP, JZ, JNZ, JLT, JGT, // Jumps
CALL, RET, // Function calls
LOAD, STORE, // Memory access
INT, // Interrupt
NOP // Miscellaneous
} opcode_t;
rand opcode_t opcode;
covergroup instruction_cg();
option.per_instance = 1;
opcode_transitions: coverpoint opcode {
bins opcode_transitions[] = (
ADD, SUB, MUL, DIV, AND, OR, XOR, NOT, JMP, JZ, JNZ, JLT, JGT, CALL, RET, LOAD, STORE, INT, NOP
=>
ADD, SUB, MUL, DIV, AND, OR, XOR, NOT, JMP, JZ, JNZ, JLT, JGT, CALL, RET, LOAD, STORE, INT, NOP
);
}
endgroup
...
endclass
This code accomplishes what we wanted, but what happens if the requirements change? Let’s suppose that several CPU versions must be created. Some of them won’t support the hardware DIV instruction, while others should include the vector arithmetic instructions VADD, VSUB, VMUL, and VDIV.
The way we defined the transition coverage doesn’t allow us to easily implement these changes. In addition, when instructions are added or removed, we have to update the definitions for both the enum and the transition bin. This process can become tedious and error prone as the number of instructions increases.
One possible solution is to add an opcode named INVALID in the enum definition and ignore all transitions to and from it:
class instruction;
typedef enum {
INVALID = -1,
...
} opcode_t;
rand opcode_t opcode;
covergroup instruction_cg();
option.per_instance = 1;
opcode_transitions: coverpoint opcode {
bins opcode_transitions[] = ([INVALID:$] => [INVALID:$]);
ignore_bins ignore_invalid = (INVALID => [INVALID:$]), ([INVALID:$] => INVALID);
}
endgroup
...
endclass
To exclude the DIV instruction from the transition coverage, we can use the conditional operator:
covergroup instruction_cg(bit disable_div);
option.per_instance = 1;
opcode_transitions: coverpoint opcode {
bins opcode_transitions[] = ([INVALID:$] => [INVALID:$]);
ignore_bins ignore_div =
(disable_div ? DIV : INVALID => [INVALID:$]),
([INVALID:$] => disable_div ? DIV : INVALID);
ignore_bins ignore_invalid = (INVALID => [INVALID:$]), ([INVALID:$] => INVALID);
}
endgroup
If disable_div is equal to 1, all transitions to and from DIV are ignored. Otherwise, the ignore_div has the same definition as the ignore_invalid bin. The same technique can be used to conditionally exclude the vector instruction from the coverage.
You can find a complete example below:
class instruction;
typedef enum {
INVALID = -1,
ADD, SUB, MUL, DIV, // Arithmetic
AND, OR, XOR, NOT, // Logic
JMP, JZ, JNZ, JLT, JGT, // Jumps
CALL, RET, // Function calls
LOAD, STORE, // Memory access
INT, // Interrupt
NOP, // Miscellaneous
VADD, VSUB, VMUL, VDIV // Vector arithmetic
} opcode_t;
rand opcode_t opcode;
covergroup instruction_cg(bit disable_div, bit disable_vector);
option.per_instance = 1;
opcode_transitions: coverpoint opcode {
bins opcode_transitions[] = ([INVALID:$] => [INVALID:$]);
ignore_bins ignore_div =
(disable_div ? DIV : INVALID => [INVALID:$]),
([INVALID:$] => disable_div ? DIV : INVALID);
ignore_bins ignore_vector =
([(disable_vector ? VADD : INVALID) : (disable_vector ? VDIV : INVALID)] => [INVALID:$]),
([INVALID:$] => [(disable_vector ? VADD : INVALID) : (disable_vector ? VDIV : INVALID)]);
ignore_bins ignore_invalid = (INVALID => [INVALID:$]), ([INVALID:$] => INVALID);
}
endgroup
function new();
instruction_cg = new(.disable_div(0), .disable_vector(1));
instruction_cg.set_inst_name("instruction_cg");
endfunction
endclass
module test;
initial begin
static instruction instr = new;
repeat (10000) begin
void'(instr.randomize() with { opcode != INVALID; });
instr.instruction_cg.sample();
end
end
endmodule
3 Responses
Nice Article!!
Thank you, Taahir!
very nice indeed, very informative