[otbn,dv] Add "toggle" coverage for source register operands
Signed-off-by: Rupert Swarbrick <rswarbrick@lowrisc.org>
diff --git a/hw/ip/otbn/doc/dv/index.md b/hw/ip/otbn/doc/dv/index.md
index f7d1803..a58e042 100644
--- a/hw/ip/otbn/doc/dv/index.md
+++ b/hw/ip/otbn/doc/dv/index.md
@@ -141,7 +141,7 @@
We also expect to see each field with values `'0` and `'1` (all zeros and all ones).
If the field is treated as a signed number, we also expect to see it with the extremal values for its range (just the MSB set, for the most negative value; all but the MSB set, for the most positive value).
-> The code to track this is split by encoding-schema in `otbn_env_cov`.
+> The code to track this is split by encoding schema in `otbn_env_cov`.
> Each instruction listed below will specify its encoding schema.
> Each encoding schema then has its own covergroup.
> Rather than tracking toggle coverage as described above, we just track extremal values in a coverpoint.
@@ -156,16 +156,25 @@
For any instruction that reads from or writes to a GPR, we expect to see that operand equal to `x0`, `x1` and an arbitrary register in the range `x2 .. x31`.
We don't have any particular coverage requirements for WDRs (since all of them work essentially the same).
-> As for immediates, the code to track this is split by encoding-schema in `otbn_env_cov`.
+> As for immediates, the code to track this is split by encoding schema in `otbn_env_cov`.
> Each register field gets a coverpoint with the same name, defined with the `DEF_GPR_CP` helper macro.
> If the encoding schema has more than one instruction, the coverpoint is then crossed with the mnemonic, using the `DEF_MNEM_CROSS` helper macro.
> For example, `add` is in the `enc_bnr_cg` covergroup.
> This encoding schema's `GRD` field is tracked with the `grd_cp` coverpoint.
> Finally, the relevant cross is called `grd_cross`.
-For any source GPR, we require "toggle coverage" for its value.
-For example, `ADD` reads from its `<grs1>` operand.
+For any source GPR or WDR, we require "toggle coverage" for its value.
+For example, `ADD` reads from its `grs1` operand.
We want to see each of the 32 bits of that operand set and unset (giving 64 coverage points).
+Similarly, `BN.ADD` reads from its `wrs1` operand.
+We want to see each of the 256 bits of that operand set and unset (giving 512 coverage points).
+
+> Again, the code to track this is split by encoding schema in `otbn_env_cov`.
+> The trace interface takes a copy of GPR and WDR read data.
+> The relevant register read data are then passed to the encoding schema's covergroup in the `on_insn` method.
+> To avoid extremely repetitive code, the actual coverpoints and crosses are defined with the help of macros.
+> The coverpoints are named with the base-2 expansion of the bit in question.
+> For example, the cross in the `enc_bnr_cg` that tracks whether we've seen both values of bit 12 for the `grs1` operand is called `grs1_01100_cross` (since 12 is `5'b01100`).
If an instruction can generate flag changes, we expect to see each flag that the instruction can change being both set and cleared by the instruction.
This needn't be crossed with the two flag groups (that's tracked separately in the "Flags" block above).
diff --git a/hw/ip/otbn/dv/uvm/env/otbn_env_cov.sv b/hw/ip/otbn/dv/uvm/env/otbn_env_cov.sv
index e1262e9..59a0234 100644
--- a/hw/ip/otbn/dv/uvm/env/otbn_env_cov.sv
+++ b/hw/ip/otbn/dv/uvm/env/otbn_env_cov.sv
@@ -97,8 +97,100 @@
`define DEF_GPR_CP(NAME, BITS) \
NAME: coverpoint insn_data[BITS] `GPR_BIN_TYPES
+ // Macros for tracking "toggle coverage" of some bitfield. Use one of the DEF_*_TOGGLE_COV macros
+ // to define a coverpoint for each bit of the bitfield.
+ //
+ // The implementation uses macros to expand in powers of 2. The trick is that BIN_IDX will grow to
+ // give the base-2 representation of the index of the bit we're looking at. For example, the
+ // expansion of DEF_GPR_TOGGLE_COV(NAME, x) ends up with 32 calls to _DEF_TOGGLE_COV_1:
+ //
+ // _DEF_TOGGLE_COV_1(NAME, x, 5, 00000)
+ // ...
+ // _DEF_TOGGLE_COV_1(NAME, x, 5, 11111)
+ //
+ // This, in turn, expands to
+ //
+ // NAME_00000_cp: coverpoint x[5'b00000];
+ // ...
+ // NAME_11111_cp: coverpoint x[5'b11111];
+ //
+ // to track the 32 bits in x.
+ //
+`define _DEF_TOGGLE_COV_1(BASE, BITS, IDXW, BIN_IDX) \
+ BASE``_``BIN_IDX``_cp: coverpoint BITS[IDXW 'b BIN_IDX];
+`define _DEF_TOGGLE_COV_2(BASE, BITS, IDXW, BIN_IDX) \
+ `_DEF_TOGGLE_COV_1(BASE, BITS, IDXW, BIN_IDX``0) \
+ `_DEF_TOGGLE_COV_1(BASE, BITS, IDXW, BIN_IDX``1)
+`define _DEF_TOGGLE_COV_4(BASE, BITS, IDXW, BIN_IDX) \
+ `_DEF_TOGGLE_COV_2(BASE, BITS, IDXW, BIN_IDX``0) \
+ `_DEF_TOGGLE_COV_2(BASE, BITS, IDXW, BIN_IDX``1)
+`define _DEF_TOGGLE_COV_8(BASE, BITS, IDXW, BIN_IDX) \
+ `_DEF_TOGGLE_COV_4(BASE, BITS, IDXW, BIN_IDX``0) \
+ `_DEF_TOGGLE_COV_4(BASE, BITS, IDXW, BIN_IDX``1)
+`define _DEF_TOGGLE_COV_16(BASE, BITS, IDXW, BIN_IDX) \
+ `_DEF_TOGGLE_COV_8(BASE, BITS, IDXW, BIN_IDX``0) \
+ `_DEF_TOGGLE_COV_8(BASE, BITS, IDXW, BIN_IDX``1)
+`define _DEF_TOGGLE_COV_32(BASE, BITS, IDXW, BIN_IDX) \
+ `_DEF_TOGGLE_COV_16(BASE, BITS, IDXW, BIN_IDX``0) \
+ `_DEF_TOGGLE_COV_16(BASE, BITS, IDXW, BIN_IDX``1)
+`define _DEF_TOGGLE_COV_64(BASE, BITS, IDXW, BIN_IDX) \
+ `_DEF_TOGGLE_COV_32(BASE, BITS, IDXW, BIN_IDX``0) \
+ `_DEF_TOGGLE_COV_32(BASE, BITS, IDXW, BIN_IDX``1)
+`define _DEF_TOGGLE_COV_128(BASE, BITS, IDXW, BIN_IDX) \
+ `_DEF_TOGGLE_COV_64(BASE, BITS, IDXW, BIN_IDX``0) \
+ `_DEF_TOGGLE_COV_64(BASE, BITS, IDXW, BIN_IDX``1)
+
+`define DEF_GPR_TOGGLE_COV(BASE, BITS) \
+ `_DEF_TOGGLE_COV_16(BASE, BITS, 5, 0) \
+ `_DEF_TOGGLE_COV_16(BASE, BITS, 5, 1)
+`define DEF_WDR_TOGGLE_COV(BASE, BITS) \
+ `_DEF_TOGGLE_COV_128(BASE, BITS, 8, 0) \
+ `_DEF_TOGGLE_COV_128(BASE, BITS, 8, 1)
+
+ // Macros to allow crossing the "toggle" coverpoints defined by the previous macros with the
+ // mnemonic coverpoint for some encoding schema. These work just as above and the entry points to
+ // use are DEF_*_TOGGLE_CROSS.
+ //
+ // The DEF_*_TOGGLE_COV macros above define coverpoints with names like XXX_BBBB_cp. These macros
+ // define crosses with names XXX_BBBB_cross.
+`define _DEF_TOGGLE_CROSS_1(BASE, BIN_IDX) \
+ BASE``_``BIN_IDX``_cross: cross BASE``_``BIN_IDX``_cp, mnemonic_cp;
+`define _DEF_TOGGLE_CROSS_2(BASE, BIN_IDX) \
+ `_DEF_TOGGLE_CROSS_1(BASE, BIN_IDX``0) \
+ `_DEF_TOGGLE_CROSS_1(BASE, BIN_IDX``1)
+`define _DEF_TOGGLE_CROSS_4(BASE, BIN_IDX) \
+ `_DEF_TOGGLE_CROSS_2(BASE, BIN_IDX``0) \
+ `_DEF_TOGGLE_CROSS_2(BASE, BIN_IDX``1)
+`define _DEF_TOGGLE_CROSS_8(BASE, BIN_IDX) \
+ `_DEF_TOGGLE_CROSS_4(BASE, BIN_IDX``0) \
+ `_DEF_TOGGLE_CROSS_4(BASE, BIN_IDX``1)
+`define _DEF_TOGGLE_CROSS_16(BASE, BIN_IDX) \
+ `_DEF_TOGGLE_CROSS_8(BASE, BIN_IDX``0) \
+ `_DEF_TOGGLE_CROSS_8(BASE, BIN_IDX``1)
+`define _DEF_TOGGLE_CROSS_32(BASE, BIN_IDX) \
+ `_DEF_TOGGLE_CROSS_16(BASE, BIN_IDX``0) \
+ `_DEF_TOGGLE_CROSS_16(BASE, BIN_IDX``1)
+`define _DEF_TOGGLE_CROSS_64(BASE, BIN_IDX) \
+ `_DEF_TOGGLE_CROSS_32(BASE, BIN_IDX``0) \
+ `_DEF_TOGGLE_CROSS_32(BASE, BIN_IDX``1)
+`define _DEF_TOGGLE_CROSS_128(BASE, BIN_IDX) \
+ `_DEF_TOGGLE_CROSS_64(BASE, BIN_IDX``0) \
+ `_DEF_TOGGLE_CROSS_64(BASE, BIN_IDX``1)
+
+`define DEF_GPR_TOGGLE_CROSS(BASE) \
+ `_DEF_TOGGLE_CROSS_16(BASE, 0) \
+ `_DEF_TOGGLE_CROSS_16(BASE, 1)
+`define DEF_WDR_TOGGLE_CROSS(BASE) \
+ `_DEF_TOGGLE_CROSS_128(BASE, 0) \
+ `_DEF_TOGGLE_CROSS_128(BASE, 1)
+
// Per-encoding covergroups
- covergroup enc_bna_cg with function sample(mnem_str_t mnemonic, logic [31:0] insn_data);
+ covergroup enc_bna_cg
+ with function sample(mnem_str_t mnemonic,
+ logic [31:0] insn_data,
+ logic [255:0] wdr_operand_a,
+ logic [255:0] wdr_operand_b);
+
// Used for bna and bnaf encodings (which have the same operand layout: the only difference is
// in the layout of the fixed bits)
mnemonic_cp: coverpoint mnemonic {
@@ -115,13 +207,21 @@
sb_cp: coverpoint insn_data[29:25] { bins extremes[] = {'0, '1}; }
st_cp: coverpoint insn_data[30];
fg_cp: coverpoint insn_data[31];
-
`DEF_MNEM_CROSS(sb)
`DEF_MNEM_CROSS(st)
`DEF_MNEM_CROSS(fg)
+
+ `DEF_WDR_TOGGLE_COV(wrs1, wdr_operand_a)
+ `DEF_WDR_TOGGLE_COV(wrs2, wdr_operand_b)
+ `DEF_WDR_TOGGLE_CROSS(wrs1)
+ `DEF_WDR_TOGGLE_CROSS(wrs2)
endgroup
- covergroup enc_bnai_cg with function sample(mnem_str_t mnemonic, logic [31:0] insn_data);
+ covergroup enc_bnai_cg
+ with function sample(mnem_str_t mnemonic,
+ logic [31:0] insn_data,
+ logic [255:0] wdr_operand_a);
+
mnemonic_cp: coverpoint mnemonic {
`DEF_MNEM_BIN(mnem_bn_addi);
`DEF_MNEM_BIN(mnem_bn_subi);
@@ -130,21 +230,36 @@
imm_cp: coverpoint insn_data[29:20] { bins extremes[] = {'0, '1}; }
fg_cp: coverpoint insn_data[31];
-
`DEF_MNEM_CROSS(imm)
`DEF_MNEM_CROSS(fg)
+
+ `DEF_WDR_TOGGLE_COV(wrs, wdr_operand_a)
+ `DEF_WDR_TOGGLE_CROSS(wrs)
endgroup
- covergroup enc_bnam_cg with function sample(mnem_str_t mnemonic, logic [31:0] insn_data);
+ covergroup enc_bnam_cg
+ with function sample(mnem_str_t mnemonic,
+ logic [31:0] insn_data,
+ logic [255:0] wdr_operand_a,
+ logic [255:0] wdr_operand_b);
+
mnemonic_cp: coverpoint mnemonic {
`DEF_MNEM_BIN(mnem_bn_addm);
`DEF_MNEM_BIN(mnem_bn_subm);
illegal_bins other = default;
}
+ `DEF_WDR_TOGGLE_COV(wrs1, wdr_operand_a)
+ `DEF_WDR_TOGGLE_COV(wrs2, wdr_operand_b)
+ `DEF_WDR_TOGGLE_CROSS(wrs1)
+ `DEF_WDR_TOGGLE_CROSS(wrs2)
endgroup
- covergroup enc_bnan_cg with function sample(mnem_str_t mnemonic, logic [31:0] insn_data);
+ covergroup enc_bnan_cg
+ with function sample(mnem_str_t mnemonic,
+ logic [31:0] insn_data,
+ logic [255:0] wdr_operand_a);
+
mnemonic_cp: coverpoint mnemonic {
`DEF_MNEM_BIN(mnem_bn_not);
illegal_bins other = default;
@@ -153,9 +268,16 @@
sb_cp: coverpoint insn_data[29:25] { bins extremes[] = {'0, '1}; }
st_cp: coverpoint insn_data[30];
fg_cp: coverpoint insn_data[31];
+
+ `DEF_WDR_TOGGLE_COV(wrs, wdr_operand_a)
endgroup
- covergroup enc_bnaq_cg with function sample(mnem_str_t mnemonic, logic [31:0] insn_data);
+ covergroup enc_bnaq_cg
+ with function sample(mnem_str_t mnemonic,
+ logic [31:0] insn_data,
+ logic [255:0] wdr_operand_a,
+ logic [255:0] wdr_operand_b);
+
// Used for BN.MULQACC
mnemonic_cp: coverpoint mnemonic {
`DEF_MNEM_BIN(mnem_bn_mulqacc);
@@ -166,9 +288,17 @@
shift_cp: coverpoint insn_data[14:13] { bins extremes[] = {'0, '1}; }
q1_cp: coverpoint insn_data[26:25] { bins extremes[] = {'0, '1}; }
q2_cp: coverpoint insn_data[28:27] { bins extremes[] = {'0, '1}; }
+
+ `DEF_WDR_TOGGLE_COV(wrs1, wdr_operand_a)
+ `DEF_WDR_TOGGLE_COV(wrs2, wdr_operand_b)
endgroup
- covergroup enc_bnaqs_cg with function sample(mnem_str_t mnemonic, logic [31:0] insn_data);
+ covergroup enc_bnaqs_cg
+ with function sample(mnem_str_t mnemonic,
+ logic [31:0] insn_data,
+ logic [255:0] wdr_operand_a,
+ logic [255:0] wdr_operand_b);
+
// Used for BN.MULQACC.SO
mnemonic_cp: coverpoint mnemonic {
`DEF_MNEM_BIN(mnem_bn_mulqacc_so);
@@ -181,9 +311,17 @@
q2_cp: coverpoint insn_data[28:27] { bins extremes[] = {'0, '1}; }
dh_cp: coverpoint insn_data[29];
fg_cp: coverpoint insn_data[31];
+
+ `DEF_WDR_TOGGLE_COV(wrs1, wdr_operand_a)
+ `DEF_WDR_TOGGLE_COV(wrs2, wdr_operand_b)
endgroup
- covergroup enc_bnaqw_cg with function sample(mnem_str_t mnemonic, logic [31:0] insn_data);
+ covergroup enc_bnaqw_cg
+ with function sample(mnem_str_t mnemonic,
+ logic [31:0] insn_data,
+ logic [255:0] wdr_operand_a,
+ logic [255:0] wdr_operand_b);
+
// Used for BN.MULQACC.WO
mnemonic_cp: coverpoint mnemonic {
`DEF_MNEM_BIN(mnem_bn_mulqacc_wo);
@@ -195,9 +333,17 @@
q1_cp: coverpoint insn_data[26:25] { bins extremes[] = {'0, '1}; }
q2_cp: coverpoint insn_data[28:27] { bins extremes[] = {'0, '1}; }
fg_cp: coverpoint insn_data[31];
+
+ `DEF_WDR_TOGGLE_COV(wrs1, wdr_operand_a)
+ `DEF_WDR_TOGGLE_COV(wrs2, wdr_operand_b)
endgroup
- covergroup enc_bnc_cg with function sample(mnem_str_t mnemonic, logic [31:0] insn_data);
+ covergroup enc_bnc_cg
+ with function sample(mnem_str_t mnemonic,
+ logic [31:0] insn_data,
+ logic [255:0] wdr_operand_a,
+ logic [255:0] wdr_operand_b);
+
mnemonic_cp: coverpoint mnemonic {
`DEF_MNEM_BIN(mnem_bn_cmp);
`DEF_MNEM_BIN(mnem_bn_cmpb);
@@ -207,21 +353,35 @@
sb_cp: coverpoint insn_data[29:25] { bins extremes[] = {'0, '1}; }
st_cp: coverpoint insn_data[30];
fg_cp: coverpoint insn_data[31];
-
`DEF_MNEM_CROSS(sb)
`DEF_MNEM_CROSS(st)
`DEF_MNEM_CROSS(fg)
+
+ `DEF_WDR_TOGGLE_COV(wrs1, wdr_operand_a)
+ `DEF_WDR_TOGGLE_COV(wrs2, wdr_operand_b)
+ `DEF_WDR_TOGGLE_CROSS(wrs1)
+ `DEF_WDR_TOGGLE_CROSS(wrs2)
endgroup
- covergroup enc_bnmov_cg with function sample(mnem_str_t mnemonic, logic [31:0] insn_data);
+ covergroup enc_bnmov_cg
+ with function sample(mnem_str_t mnemonic,
+ logic [31:0] insn_data,
+ logic [255:0] wdr_operand_a);
+
mnemonic_cp: coverpoint mnemonic {
`DEF_MNEM_BIN(mnem_bn_mov);
illegal_bins other = default;
}
+ `DEF_WDR_TOGGLE_COV(wrs, wdr_operand_a)
endgroup
- covergroup enc_bnmovr_cg with function sample(mnem_str_t mnemonic, logic [31:0] insn_data);
+ covergroup enc_bnmovr_cg
+ with function sample(mnem_str_t mnemonic,
+ logic [31:0] insn_data,
+ logic [31:0] gpr_operand_a,
+ logic [31:0] gpr_operand_b);
+
mnemonic_cp: coverpoint mnemonic {
`DEF_MNEM_BIN(mnem_bn_movr);
illegal_bins other = default;
@@ -233,18 +393,34 @@
`DEF_GPR_CP(grs_cp, 19:15)
`DEF_GPR_CP(grd_cp, 24:20)
`DEF_MNEM_CROSS2(grs, grd)
+
+ `DEF_GPR_TOGGLE_COV(grs, gpr_operand_a)
+ `DEF_GPR_TOGGLE_COV(grd, gpr_operand_b)
endgroup
- covergroup enc_bnr_cg with function sample(mnem_str_t mnemonic, logic [31:0] insn_data);
+ covergroup enc_bnr_cg
+ with function sample(mnem_str_t mnemonic,
+ logic [31:0] insn_data,
+ logic [255:0] wdr_operand_a,
+ logic [255:0] wdr_operand_b);
+
mnemonic_cp: coverpoint mnemonic {
`DEF_MNEM_BIN(mnem_bn_rshi);
illegal_bins other = default;
}
imm_cp: coverpoint {insn_data[31:25], insn_data[14]} { bins extremes[] = {'0, '1}; }
+
+ `DEF_WDR_TOGGLE_COV(wrs1, wdr_operand_a)
+ `DEF_WDR_TOGGLE_COV(wrs2, wdr_operand_b)
endgroup
- covergroup enc_bns_cg with function sample(mnem_str_t mnemonic, logic [31:0] insn_data);
+ covergroup enc_bns_cg
+ with function sample(mnem_str_t mnemonic,
+ logic [31:0] insn_data,
+ logic [255:0] wdr_operand_a,
+ logic [255:0] wdr_operand_b);
+
mnemonic_cp: coverpoint mnemonic {
`DEF_MNEM_BIN(mnem_bn_sel);
illegal_bins other = default;
@@ -252,9 +428,17 @@
flag_cp: coverpoint insn_data[26:25] { bins extremes[] = {'0, '1}; }
fg_cp: coverpoint insn_data[31];
+
+ `DEF_WDR_TOGGLE_COV(wrs1, wdr_operand_a)
+ `DEF_WDR_TOGGLE_COV(wrs2, wdr_operand_b)
endgroup
- covergroup enc_bnxid_cg with function sample(mnem_str_t mnemonic, logic [31:0] insn_data);
+ covergroup enc_bnxid_cg
+ with function sample(mnem_str_t mnemonic,
+ logic [31:0] insn_data,
+ logic [31:0] gpr_operand_a,
+ logic [31:0] gpr_operand_b);
+
mnemonic_cp: coverpoint mnemonic {
`DEF_MNEM_BIN(mnem_bn_lid);
`DEF_MNEM_BIN(mnem_bn_sid);
@@ -264,20 +448,28 @@
incd_cp: coverpoint insn_data[7];
inc1_cp: coverpoint insn_data[8];
off_cp: coverpoint {insn_data[31:25], insn_data[11:9]} { bins extremes[] = {'0, '1}; }
+ `DEF_MNEM_CROSS(incd)
+ `DEF_MNEM_CROSS(inc1)
+ `DEF_MNEM_CROSS(off)
`DEF_GPR_CP(grs1_cp, 19:15)
// Note: Bits 24:20 are called grd for BN.LID or grs2 for BN.SID, but both are a GPR, so can be
// tracked the same here.
`DEF_GPR_CP(grx_cp, 24:20)
-
- `DEF_MNEM_CROSS(incd)
- `DEF_MNEM_CROSS(inc1)
- `DEF_MNEM_CROSS(off)
-
`DEF_MNEM_CROSS2(grs1, grx)
+
+ `DEF_GPR_TOGGLE_COV(grs1, gpr_operand_a)
+ `DEF_GPR_TOGGLE_COV(grs2, gpr_operand_b)
+ `DEF_GPR_TOGGLE_CROSS(grs1)
+ `DEF_GPR_TOGGLE_CROSS(grs2)
endgroup
- covergroup enc_b_cg with function sample(mnem_str_t mnemonic, logic [31:0] insn_data);
+ covergroup enc_b_cg
+ with function sample(mnem_str_t mnemonic,
+ logic [31:0] insn_data,
+ logic [31:0] gpr_operand_a,
+ logic [31:0] gpr_operand_b);
+
mnemonic_cp: coverpoint mnemonic {
`DEF_MNEM_BIN(mnem_beq);
`DEF_MNEM_BIN(mnem_bne);
@@ -287,13 +479,16 @@
off_cp: coverpoint {insn_data[31], insn_data[7], insn_data[30:25], insn_data[11:8]} {
bins extremes[] = {12'h800, 12'h7ff};
}
+ `DEF_MNEM_CROSS(off)
`DEF_GPR_CP(grs1_cp, 19:15)
`DEF_GPR_CP(grs2_cp, 24:20)
-
- `DEF_MNEM_CROSS(off)
-
`DEF_MNEM_CROSS2(grs1, grs2)
+
+ `DEF_GPR_TOGGLE_COV(grs1, gpr_operand_a)
+ `DEF_GPR_TOGGLE_COV(grs2, gpr_operand_b)
+ `DEF_GPR_TOGGLE_CROSS(grs1)
+ `DEF_GPR_TOGGLE_CROSS(grs2)
endgroup
covergroup enc_fixed_cg with function sample(mnem_str_t mnemonic, logic [31:0] insn_data);
@@ -304,7 +499,11 @@
}
endgroup
- covergroup enc_i_cg with function sample(mnem_str_t mnemonic, logic [31:0] insn_data);
+ covergroup enc_i_cg
+ with function sample(mnem_str_t mnemonic,
+ logic [31:0] insn_data,
+ logic [31:0] gpr_operand_a);
+
mnemonic_cp: coverpoint mnemonic {
`DEF_MNEM_BIN(mnem_addi);
`DEF_MNEM_BIN(mnem_andi);
@@ -318,16 +517,21 @@
}
imm_cp: coverpoint insn_data[31:20] { bins extremes[] = {12'h800, 12'h7ff}; }
+ `DEF_MNEM_CROSS(imm)
`DEF_GPR_CP(grd_cp, 11:7)
`DEF_GPR_CP(grs1_cp, 19:15)
-
- `DEF_MNEM_CROSS(imm)
-
`DEF_MNEM_CROSS2(grd, grs1)
+
+ `DEF_GPR_TOGGLE_COV(grs1, gpr_operand_a)
+ `DEF_GPR_TOGGLE_CROSS(grs1)
endgroup
- covergroup enc_is_cg with function sample(mnem_str_t mnemonic, logic [31:0] insn_data);
+ covergroup enc_is_cg
+ with function sample(mnem_str_t mnemonic,
+ logic [31:0] insn_data,
+ logic [31:0] gpr_operand_a);
+
// Instructions with the Is encoding
mnemonic_cp: coverpoint mnemonic {
`DEF_MNEM_BIN(mnem_slli);
@@ -337,13 +541,14 @@
}
shamt_cp: coverpoint insn_data[24:20] { bins extremes[] = {'0, '1}; }
+ `DEF_MNEM_CROSS(shamt)
`DEF_GPR_CP(grd_cp, 11:7)
`DEF_GPR_CP(grs1_cp, 19:15)
-
- `DEF_MNEM_CROSS(shamt)
-
`DEF_MNEM_CROSS2(grd, grs1)
+
+ `DEF_GPR_TOGGLE_COV(grs1, gpr_operand_a)
+ `DEF_GPR_TOGGLE_CROSS(grs1)
endgroup
covergroup enc_j_cg with function sample(mnem_str_t mnemonic, logic [31:0] insn_data);
@@ -357,7 +562,11 @@
`DEF_GPR_CP(grd_cp, 11:7)
endgroup
- covergroup enc_loop_cg with function sample(mnem_str_t mnemonic, logic [31:0] insn_data);
+ covergroup enc_loop_cg
+ with function sample(mnem_str_t mnemonic,
+ logic [31:0] insn_data,
+ logic [31:0] gpr_operand_a);
+
// Used for LOOP encoding (just the LOOP instruction)
mnemonic_cp: coverpoint mnemonic {
`DEF_MNEM_BIN(mnem_loop);
@@ -367,6 +576,8 @@
sz_cp: coverpoint insn_data[31:20] { bins extremes[] = {'0, '1}; }
`DEF_GPR_CP(grs_cp, 19:15)
+
+ `DEF_GPR_TOGGLE_COV(grs, gpr_operand_a)
endgroup
covergroup enc_loopi_cg with function sample(mnem_str_t mnemonic, logic [31:0] insn_data);
@@ -380,7 +591,12 @@
iterations_cp: coverpoint {insn_data[19:15], insn_data[11:7]} { bins extremes[] = {'0, '1}; }
endgroup
- covergroup enc_r_cg with function sample(mnem_str_t mnemonic, logic [31:0] insn_data);
+ covergroup enc_r_cg
+ with function sample(mnem_str_t mnemonic,
+ logic [31:0] insn_data,
+ logic [31:0] gpr_operand_a,
+ logic [31:0] gpr_operand_b);
+
mnemonic_cp: coverpoint mnemonic {
`DEF_MNEM_BIN(mnem_add);
`DEF_MNEM_BIN(mnem_sub);
@@ -396,11 +612,20 @@
`DEF_GPR_CP(grd_cp, 11:7)
`DEF_GPR_CP(grs1_cp, 19:15)
`DEF_GPR_CP(grs2_cp, 24:20)
-
`DEF_MNEM_CROSS3(grd, grs1, grs2)
+
+ `DEF_GPR_TOGGLE_COV(grs1, gpr_operand_a)
+ `DEF_GPR_TOGGLE_COV(grs2, gpr_operand_b)
+ `DEF_GPR_TOGGLE_CROSS(grs1)
+ `DEF_GPR_TOGGLE_CROSS(grs2)
endgroup
- covergroup enc_s_cg with function sample(mnem_str_t mnemonic, logic [31:0] insn_data);
+ covergroup enc_s_cg
+ with function sample(mnem_str_t mnemonic,
+ logic [31:0] insn_data,
+ logic [31:0] gpr_operand_a,
+ logic [31:0] gpr_operand_b);
+
mnemonic_cp: coverpoint mnemonic {
`DEF_MNEM_BIN(mnem_sw);
illegal_bins other = default;
@@ -413,6 +638,9 @@
`DEF_GPR_CP(grs1_cp, 19:15)
`DEF_GPR_CP(grs2_cp, 24:20)
`DEF_MNEM_CROSS2(grs1, grs2)
+
+ `DEF_GPR_TOGGLE_COV(grs1, gpr_operand_a)
+ `DEF_GPR_TOGGLE_COV(grs2, gpr_operand_b)
endgroup
covergroup enc_u_cg with function sample(mnem_str_t mnemonic, logic [31:0] insn_data);
@@ -551,31 +779,56 @@
// Every instruction mnemonic should have an associated encoding schema.
encoding = insn_encodings[mnem];
case (encoding)
- "bna", "bnaf": enc_bna_cg.sample(mnem, insn_data);
- "bnai": enc_bnai_cg.sample(mnem, insn_data);
- "bnam": enc_bnam_cg.sample(mnem, insn_data);
- "bnan": enc_bnan_cg.sample(mnem, insn_data);
- "bnaq": enc_bnaq_cg.sample(mnem, insn_data);
- "bnaqw": enc_bnaqw_cg.sample(mnem, insn_data);
- "bnaqs": enc_bnaqs_cg.sample(mnem, insn_data);
- "bnc": enc_bnc_cg.sample(mnem, insn_data);
- "bnmov": enc_bnmov_cg.sample(mnem, insn_data);
- "bnmovr": enc_bnmovr_cg.sample(mnem, insn_data);
- "bnr": enc_bnr_cg.sample(mnem, insn_data);
- "bns": enc_bns_cg.sample(mnem, insn_data);
- "bnxid": enc_bnxid_cg.sample(mnem, insn_data);
- "B": enc_b_cg.sample(mnem, insn_data);
- "fixed": enc_fixed_cg.sample(mnem, insn_data);
- "I": enc_i_cg.sample(mnem, insn_data);
- "Is": enc_is_cg.sample(mnem, insn_data);
- "J": enc_j_cg.sample(mnem, insn_data);
- "loop": enc_loop_cg.sample(mnem, insn_data);
- "loopi": enc_loopi_cg.sample(mnem, insn_data);
- "R": enc_r_cg.sample(mnem, insn_data);
- "S": enc_s_cg.sample(mnem, insn_data);
- "U": enc_u_cg.sample(mnem, insn_data);
- "wcsr": enc_wcsr_cg.sample(mnem, insn_data);
- default: `DV_CHECK_FATAL(0, "Unknown encoding")
+ "bna", "bnaf":
+ enc_bna_cg.sample(mnem, insn_data, rtl_item.wdr_operand_a, rtl_item.wdr_operand_b);
+ "bnai":
+ enc_bnai_cg.sample(mnem, insn_data, rtl_item.wdr_operand_a);
+ "bnam":
+ enc_bnam_cg.sample(mnem, insn_data, rtl_item.wdr_operand_a, rtl_item.wdr_operand_b);
+ "bnan":
+ enc_bnan_cg.sample(mnem, insn_data, rtl_item.wdr_operand_a);
+ "bnaq":
+ enc_bnaq_cg.sample(mnem, insn_data, rtl_item.wdr_operand_a, rtl_item.wdr_operand_b);
+ "bnaqw":
+ enc_bnaqw_cg.sample(mnem, insn_data, rtl_item.wdr_operand_a, rtl_item.wdr_operand_b);
+ "bnaqs":
+ enc_bnaqs_cg.sample(mnem, insn_data, rtl_item.wdr_operand_a, rtl_item.wdr_operand_b);
+ "bnc":
+ enc_bnc_cg.sample(mnem, insn_data, rtl_item.wdr_operand_a, rtl_item.wdr_operand_b);
+ "bnmov":
+ enc_bnmov_cg.sample(mnem, insn_data, rtl_item.wdr_operand_a);
+ "bnmovr":
+ enc_bnmovr_cg.sample(mnem, insn_data, rtl_item.gpr_operand_a, rtl_item.gpr_operand_b);
+ "bnr":
+ enc_bnr_cg.sample(mnem, insn_data, rtl_item.wdr_operand_a, rtl_item.wdr_operand_b);
+ "bns":
+ enc_bns_cg.sample(mnem, insn_data, rtl_item.wdr_operand_a, rtl_item.wdr_operand_b);
+ "bnxid":
+ enc_bnxid_cg.sample(mnem, insn_data, rtl_item.gpr_operand_a, rtl_item.gpr_operand_b);
+ "B":
+ enc_b_cg.sample(mnem, insn_data, rtl_item.gpr_operand_a, rtl_item.gpr_operand_b);
+ "fixed":
+ enc_fixed_cg.sample(mnem, insn_data);
+ "I":
+ enc_i_cg.sample(mnem, insn_data, rtl_item.gpr_operand_a);
+ "Is":
+ enc_is_cg.sample(mnem, insn_data, rtl_item.gpr_operand_a);
+ "J":
+ enc_j_cg.sample(mnem, insn_data);
+ "loop":
+ enc_loop_cg.sample(mnem, insn_data, rtl_item.gpr_operand_a);
+ "loopi":
+ enc_loopi_cg.sample(mnem, insn_data);
+ "R":
+ enc_r_cg.sample(mnem, insn_data, rtl_item.gpr_operand_a, rtl_item.gpr_operand_b);
+ "S":
+ enc_s_cg.sample(mnem, insn_data, rtl_item.gpr_operand_a, rtl_item.gpr_operand_b);
+ "U":
+ enc_u_cg.sample(mnem, insn_data);
+ "wcsr":
+ enc_wcsr_cg.sample(mnem, insn_data);
+ default:
+ `DV_CHECK_FATAL(0, "Unknown encoding")
endcase
endfunction
@@ -585,5 +838,25 @@
`undef DEF_MNEM_CROSS3
`undef GPR_BIN_TYPES
`undef DEF_GPR_CP
+`undef _DEF_TOGGLE_COV_1
+`undef _DEF_TOGGLE_COV_2
+`undef _DEF_TOGGLE_COV_4
+`undef _DEF_TOGGLE_COV_8
+`undef _DEF_TOGGLE_COV_16
+`undef _DEF_TOGGLE_COV_32
+`undef _DEF_TOGGLE_COV_64
+`undef _DEF_TOGGLE_COV_128
+`undef DEF_GPR_TOGGLE_COV
+`undef DEF_WDR_TOGGLE_COV
+`undef _DEF_TOGGLE_CROSS_1
+`undef _DEF_TOGGLE_CROSS_2
+`undef _DEF_TOGGLE_CROSS_4
+`undef _DEF_TOGGLE_CROSS_8
+`undef _DEF_TOGGLE_CROSS_16
+`undef _DEF_TOGGLE_CROSS_32
+`undef _DEF_TOGGLE_CROSS_64
+`undef _DEF_TOGGLE_CROSS_128
+`undef DEF_GPR_TOGGLE_CROSS
+`undef DEF_WDR_TOGGLE_CROSS
endclass
diff --git a/hw/ip/otbn/dv/uvm/env/otbn_trace_item.sv b/hw/ip/otbn/dv/uvm/env/otbn_trace_item.sv
index 4460635..e2e7404 100644
--- a/hw/ip/otbn/dv/uvm/env/otbn_trace_item.sv
+++ b/hw/ip/otbn/dv/uvm/env/otbn_trace_item.sv
@@ -7,9 +7,21 @@
logic [31:0] insn_addr;
logic [31:0] insn_data;
+ // GPR operand data
+ logic [31:0] gpr_operand_a;
+ logic [31:0] gpr_operand_b;
+
+ // WDR operand data
+ logic [255:0] wdr_operand_a;
+ logic [255:0] wdr_operand_b;
+
`uvm_object_utils_begin(otbn_trace_item)
- `uvm_field_int (insn_addr, UVM_DEFAULT)
- `uvm_field_int (insn_data, UVM_DEFAULT)
+ `uvm_field_int (insn_addr, UVM_DEFAULT | UVM_HEX)
+ `uvm_field_int (insn_data, UVM_DEFAULT | UVM_HEX)
+ `uvm_field_int (gpr_operand_a, UVM_DEFAULT | UVM_HEX)
+ `uvm_field_int (gpr_operand_b, UVM_DEFAULT | UVM_HEX)
+ `uvm_field_int (wdr_operand_a, UVM_DEFAULT | UVM_HEX)
+ `uvm_field_int (wdr_operand_b, UVM_DEFAULT | UVM_HEX)
`uvm_object_utils_end
`uvm_object_new
diff --git a/hw/ip/otbn/dv/uvm/env/otbn_trace_monitor.sv b/hw/ip/otbn/dv/uvm/env/otbn_trace_monitor.sv
index a221896..ef234d6 100644
--- a/hw/ip/otbn/dv/uvm/env/otbn_trace_monitor.sv
+++ b/hw/ip/otbn/dv/uvm/env/otbn_trace_monitor.sv
@@ -27,6 +27,10 @@
item = otbn_trace_item::type_id::create("item");
item.insn_addr = cfg.trace_vif.insn_addr;
item.insn_data = cfg.trace_vif.insn_data;
+ item.gpr_operand_a = cfg.trace_vif.rf_base_rd_data_a;
+ item.gpr_operand_b = cfg.trace_vif.rf_base_rd_data_b;
+ item.wdr_operand_a = cfg.trace_vif.rf_bignum_rd_data_a;
+ item.wdr_operand_b = cfg.trace_vif.rf_bignum_rd_data_b;
analysis_port.write(item);
end
end