|  | # OTBN functional coverage | 
|  |  | 
|  | We distinguish between *architectural* and *micro-architectural* functional coverage. | 
|  | The idea is that the points that go into architectural coverage are those that a DV engineer could derive by reading the block specification. | 
|  | The points that go into micro-architectural coverage are those that require knowledge of the block's micro-architecture. | 
|  | Some of these will come from DV engineers; others from the block's designers. | 
|  | These two views are complementary and will probably duplicate coverage points. | 
|  | For example, an architectural coverage point might be "the processor executed `ADDI` and the result overflowed". | 
|  | This might overlap with something like "the `overflow` signal in the ALU was true when adding". | 
|  |  | 
|  | # Block-based coverage | 
|  |  | 
|  | ## Call stack | 
|  |  | 
|  | The [call stack](../README.md#call-stack) is exposed as a special register behind `x1`. | 
|  | It has a bounded depth of 8 elements. | 
|  | We expect to see the following events: | 
|  |  | 
|  | - Push to the call stack | 
|  | - Pop from the call stack | 
|  | - Push and pop from the call stack on a single instruction | 
|  | - An instruction with multiple reads from `x1` | 
|  |  | 
|  | All four of these events should be crossed with the three states of the call stack: empty, partially full, and full. | 
|  |  | 
|  | > Coverage for these points is tracked in the `call_stack_cg` covergroup. | 
|  | > We track all possible combinations of push/pop flags (8 possibilities) in `flags_cp`. | 
|  | > The 3 different fullness states are tracked as `fullness_cp`. | 
|  | > These are then crossed to give `flags_fullness_cross`. | 
|  |  | 
|  | ## Loop stack | 
|  |  | 
|  | The [loop stack](../README.md#loop-stack) is accessed by executing `LOOP` and `LOOPI` instructions. | 
|  | Events concerning the start of loops are tracked at those instructions, but we can't track things like loop completion there. | 
|  |  | 
|  | > Coverage for these points is tracked with cover properties in the `otbn_loop_if` interface. | 
|  |  | 
|  | We expect to: | 
|  | - Complete a loop. | 
|  | Tracked as `LoopEnd_C`. | 
|  | - Complete the last loop on the stack (emptying it) after the stack has been full. | 
|  | Tracked as `FullToEmpty_C`. | 
|  | - Complete a loop with one instruction and an iteration count of one. | 
|  | Tracked as `ShortestLoop_C`. | 
|  | - Complete a loop with the maximal number of iterations. | 
|  | Obviously, this isn't a reasonable thing to do for real in a test (there's a 32-bit iteration counter!). | 
|  | The testbench will have to force a signal to skip past some iterations. | 
|  | Tracked as `MaximalLoop_C`. | 
|  | - Run through a "badly nested" loop, where the body contains the final instruction from an outer loop (checking that we don't wrongly skip back). | 
|  | Tracked as `BadNestingEnd_C` and `BadNestingMiddle_C`. | 
|  | - Jump into a loop body from outside. | 
|  | Tracked as `JumpIntoLoop_C`. | 
|  | - Jump/branch to the final instruction of a loop | 
|  | Tracked as `JumpToLoopEnd_C`. | 
|  |  | 
|  | ## CSRs and WSRs | 
|  |  | 
|  | Accesses to CSRs and WSRs are tracked in the coverage for the instructions that access them. | 
|  | See [CSRRS](#csrrs) and [CSRRW](#csrrw) for CSRs; [BN.WSRR](#bnwsrr) and [BN.WSRW](#bnwsrw) for WSRs. | 
|  |  | 
|  | ## Random numbers | 
|  |  | 
|  | Random numbers are exposed to OTBN code through the `RND` and `URND` CSRs and WSRs. | 
|  | A new random number can be prefetched for `RND` with the `RND_PREFETCH` CSR. | 
|  |  | 
|  | We track uses of each of these CSRs and WSRs in the instructions that access them. | 
|  | See [CSRRS](#csrrs) and [CSRRW](#csrrw) for CSRs; [BN.WSRR](#bnwsrr) and [BN.WSRW](#bnwsrw) for WSRs. | 
|  | However, we also want to see some interactions between `RND` and `RND_PREFETCH`. | 
|  | These are all tracked with cover properties in `otbn_rnd_if.sv`. | 
|  |  | 
|  | Specifically, we expect to see: | 
|  |  | 
|  | - An read of `RND` (either CSR or WSR) before any write to `RND_PREFETCH`. | 
|  | This is tracked with the `RndWithNoPrefetch_C` cover property. | 
|  | - Two consecutive writes to `RND_PREFETCH` without a random value arriving between. | 
|  | This is tracked with the `PrefetchPrefetch_C` cover property. | 
|  | - Two consecutive writes to `RND_PREFETCH`, where a random value arrives between them. | 
|  | This is tracked with the `FullPrefetch_C` cover property. | 
|  | - A write to `RND_PREFETCH` followed by a read from `RND` after the random value has arrived. | 
|  | This is tracked with the `FullRead_C` cover property. | 
|  | - A write to `RND_PREFETCH` followed by a read from `RND` before the random value has arrived. | 
|  | This is tracked with the `PrefetchingRead_C` cover property. | 
|  |  | 
|  |  | 
|  |  | 
|  | ## Flags | 
|  |  | 
|  | Each flag in each flag group should be set to one from zero by some instruction. | 
|  | Similarly, each flag in each flag group should be cleared to zero from one by some instruction. | 
|  |  | 
|  | > These events are tracked in `flag_write_cg`. | 
|  | > This is called from `on_insn()` once for each flag group that is being written. | 
|  | > The covergroup contains eight coverpoints (for each flag set and cleared). | 
|  | > These are then crossed with the flag group. | 
|  |  | 
|  | ## Instruction counter | 
|  |  | 
|  | See the instruction counter saturate. | 
|  |  | 
|  | > This is tracked in the `insn_cnt_if` interface with the `InsnCntSaturated_C` cover property. | 
|  |  | 
|  | ## Key sideload interface | 
|  |  | 
|  | We expect to see reads from this interface (both when a key is present and when it is not). | 
|  | The coverage for these reads is tracked in the [BN.WSRR](#bnwsrr) instruction which does the reading. | 
|  |  | 
|  | ## Integrity protection | 
|  |  | 
|  | The contents of IMEM and DMEM, the register file, and other pieces of internal state are protected by ECC integrity bits. | 
|  | We want to see errors/alerts caused by corrupting each of these pieces of state. | 
|  | Rather than tracking this with functional coverage, we rely on testplan entries. | 
|  |  | 
|  | See the `mem_integrity` and `internal_integrity` entries in the testplan for more details. | 
|  |  | 
|  | ## Lifecycle escalation | 
|  |  | 
|  | The lifecycle controller can send a "lifecycle escalation" signal to tell OTBN to clear its internal state and to raise its own fatal error. | 
|  |  | 
|  | We expect to see this happen. | 
|  | However, we don't track coverage for this explicitly since it's handled at the testplan level (with the `lc_escalation` testpoint). | 
|  |  | 
|  | ## Error promotion | 
|  |  | 
|  | If the `CTRL.software_errs_fatal` field is set then a software error which would normally trigger a recoverable alert will trigger a fatal alert. | 
|  | We expect to see each software error triggered and upgraded to a fatal alert. | 
|  |  | 
|  | This is tracked in the `promoted_err_cg` covergroup. | 
|  |  | 
|  | Note that we already track seeing each software error triggered (but not upgraded) with the coverage for `ERR_BITS` in the [external CSRs](#ext-csrs) section below. | 
|  |  | 
|  | ## Scratchpad memory | 
|  |  | 
|  | A portion of DMEM is inaccessible from the bus. | 
|  | We want to see accesses (read and write) to both endpoints of the inaccessible portion of DMEM when OTBN is in an idle state (so would otherwise allow them). | 
|  | These are tracked in the `addr_cp` coverpoint in `scratchpad_writes_cg`. | 
|  |  | 
|  | We also want to see a successful write to the top word of accessible DMEM. | 
|  | We don't track that explicitly, since it is covered by the `otbn_mem_walk` test. | 
|  |  | 
|  | ## External (bus-accessible) CSRs {#ext-csrs} | 
|  |  | 
|  | The OTBN block exposes functionality to a bus host through bus-accessible CSRs. | 
|  | Behavior of some CSRs depends on [OTBN's operational state](../../README.md#design-details-operational-states). | 
|  |  | 
|  | For every CSR (no matter its access restrictions), we want to see an attempt to read it and an attempt to write it. | 
|  | The CSRs are tracked in covergroups based on the CSR name, with the format: `ext_csr_<name>_cg`. | 
|  | Each has an `access_type_cp` coverpoint which will track read and write attempts. | 
|  |  | 
|  | If writes to the CSR behave differently depending on the operational state, we cross attempts to write with the operational state. | 
|  | For CSRs like `CMD`, which have an immediate effect, this is easy to handle. | 
|  | For CSRs that need a follow-up read to check their value, this is handled with the `ext_csr_wr_operational_state_cg` covergroup. | 
|  | We track the last write state for a CSR and then sample that covergroup when the value is read back. | 
|  |  | 
|  | ### CMD | 
|  |  | 
|  | Coverage is tracked in the `ext_csr_cmd_cg` covergroup. | 
|  |  | 
|  | We want to see all valid commands (plus at least one invalid command) being written in each operational state. | 
|  | This ensures commands are ignored as expected when OTBN is busy or locked. | 
|  | It also ensures that bad commands are ignored as expected. | 
|  |  | 
|  | The `cmd_cp` bin covers the different types of commands. | 
|  | It is crossed with the operational state in `cmd_state_cross`. | 
|  | We check that we see a read (as well as a write) with the `access_type_cp` coverpoint. | 
|  |  | 
|  | ### CTRL | 
|  |  | 
|  | Coverage is tracked in the `ext_csr_ctrl_cg` covergroup. | 
|  |  | 
|  | We expect to see this written with each of zero and one in the idle state (where it should take an effect). | 
|  | This is tracked in `value_cp`. | 
|  |  | 
|  | We check that we see a read (as well as a write) with the `access_type_cp` coverpoint. | 
|  |  | 
|  | We expect to see this written in each operational state, tracked with the `ext_csr_wr_operational_state_cg` covergroup. | 
|  |  | 
|  | We also want to see this be set back to zero after an operation has run with it set to one, then trigger a software error. | 
|  | This ensures that we can indeed disable the fatal error promotion mechanism. | 
|  |  | 
|  | **TODO: This part is not currently tracked.** | 
|  |  | 
|  | ### STATUS | 
|  |  | 
|  | Coverage is tracked in the `ext_csr_status_cg` covergroup. | 
|  |  | 
|  | We want to see a read of all valid status codes. | 
|  | This is tracked in `status_cp`. | 
|  | We check that we see a write (as well as a read) with the `access_type_cp` coverpoint. | 
|  |  | 
|  | ### ERR_BITS | 
|  |  | 
|  | Coverage is tracked in the `ext_csr_err_bits_cg` covergroup. | 
|  |  | 
|  | We want to see that every valid bit is read at least once. | 
|  | This is tracked in coverpoints with names of the form `err_bits_<errcode>_cp`. | 
|  | We also want to see a read in each operational state. | 
|  | This is tracked in `state_cp`. | 
|  |  | 
|  | We want to see a write to this register in each operational state when it was previously nonzero. | 
|  | This checks that the clearing behaviour works properly. | 
|  | We don't have to follow up with another read because we've got continuous checks that the RTL value of this register matches the ISS. | 
|  | This is tracked in `clear_state_cross`. | 
|  |  | 
|  | We want to see both reads and writes. | 
|  | This is tracked in `access_type_cp`. | 
|  |  | 
|  | ### FATAL\_ALERT_CAUSE | 
|  |  | 
|  | Coverage is tracked in the `ext_csr_fatal_alert_cause_cg` covergroup. | 
|  |  | 
|  | We want to see that every valid bit is read at least once. | 
|  | This is tracked in coverpoints with names of the form `fatal_alert_cause_<errcode>_cp`. | 
|  | We also want to see a read in each operational state. | 
|  | This is tracked in `state_cp`. | 
|  |  | 
|  | We check that we see a write (as well as a read) with the `access_type_cp` coverpoint. | 
|  |  | 
|  | ### INSN_CNT | 
|  |  | 
|  | Coverage is tracked in the `ext_csr_insn_cnt_cg` covergroup. | 
|  |  | 
|  | We want to see a read returning a zero and a non-zero value. | 
|  | This is tracked in `insn_cnt_cp`. | 
|  | We also want to see a read in every operational state. | 
|  | This is tracked in `state_cp`. | 
|  |  | 
|  | We want to see a write to this register in each operational state when it was previously nonzero. | 
|  | This checks that the clearing behaviour works properly. | 
|  | We don't have to follow up with another read because we've got continuous checks that the RTL value of this register matches the ISS. | 
|  | This is tracked in `clear_state_cross`. | 
|  |  | 
|  | ### LOAD_CHECKSUM | 
|  |  | 
|  | We want to see a write to the register (that changes its value), followed by an update caused by writing to memory, finally followed by a read of the register value. | 
|  | This is tracked in the `ext_csr_load_checksum_wur_cg` covergroup. | 
|  |  | 
|  | We also want to see a write in every operational state, followed by a read before the next write. | 
|  | This is tracked in the `ext_csr_wr_operational_state_cg` covergroup. | 
|  |  | 
|  | # Instruction-based coverage | 
|  |  | 
|  | As a processor, much of OTBN's coverage points are described in terms of instructions being executed. | 
|  | Because OTBN doesn't have a complicated multi-stage pipeline or any real exception handling, we don't track much temporal information (such as sequences of instructions). | 
|  |  | 
|  | As well as instruction-specific coverage points detailed below, we include a requirement that each instruction is executed at least once. | 
|  |  | 
|  | For any instruction with one or more immediate fields, we require "toggle coverage" for those fields. | 
|  | That is, we expect to see execution with each bit of each immediate field being zero and one. | 
|  | 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`. | 
|  | > 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. | 
|  | > This also implies toggle coverage for both signed and unsigned fields. | 
|  | > For unsigned fields of width `N`, the extremal values are `0` and `(1 << N) - 1`, represented by the bits `'0` and `'1` respectively. | 
|  | > For signed fields of width `N+1`, the extremal values are `-(1 << N)` and `(1 << N) - 1`. | 
|  | > These are represented by `{1'b1, {N{1'b0}}}` and `{1'b0, {N{1'b1}}}`: again, these toggle all the bits. | 
|  | > For example, `beq` uses the `B` schema, which then maps to the `enc_b_cg` covergroup. | 
|  | > This encoding schema's `OFF` field is tracked with the `off_cp` coverpoint. | 
|  | > Finally, the relevant cross is called `off_cross`. | 
|  |  | 
|  | 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`. | 
|  | > 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 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). | 
|  | For example, `BN.ADD` can write to each of the flags `C`, `M`, `L` and `Z`. | 
|  | This paragraph implies eight coverage points (four flags times two values) for that instruction. | 
|  |  | 
|  | > Again, the code to track this is split by encoding schema in `otbn_env_cov`. | 
|  | > The trace interface takes a copy of flag write data. | 
|  | > It doesn't bother storing the flag write flags, since these are implied by the instruction anyway. | 
|  | > There is a coverage coverpoint tracking both values for each of the flags that can be written. | 
|  | > This is then crossed with the instruction mnemonic. | 
|  | > For example, the coverpoint for the C flag (bit zero) in the `bnaf` encoding used by `BN.ADD` is called `flags_00_cp`. | 
|  | > Some instructions only write the `M`, `L` and `Z` flags. | 
|  | > These are found in the `bna`, `bnan`, `bnaqs` and `bnaqw` encoding groups. | 
|  | > For these instructions, we only track bits `1`, `2` and `3` of the flags structure. | 
|  |  | 
|  | For any instruction that can cause multiple errors in a single cycle, we expect to see each possible combination of errors. | 
|  | This is described in more detail in the per-instruction text below. | 
|  | If an instruction below doesn't describe triggering multiple errors, that means we don't think it's possible. | 
|  |  | 
|  | ## ADD | 
|  |  | 
|  | This instruction uses the `R` encoding schema, with covergroup `enc_r_cg`. | 
|  | The instruction-specific covergroup is `insn_addsub_cg` (also used for `SUB`). | 
|  |  | 
|  | - Cross the three possible signs (negative, zero, positive) for each input operand (giving 9 points). | 
|  | Tracked as `sign_a_sign_b_cross`. | 
|  |  | 
|  | ## ADDI | 
|  |  | 
|  | This instruction uses the `I` encoding schema, with covergroup `enc_i_cg`. | 
|  | The instruction-specific covergroup is `insn_addi_cg`. | 
|  |  | 
|  | - Cross the three possible signs (negative, zero, positive) for each input operand (giving 9 points). | 
|  | Tracked as `sign_cross`. | 
|  |  | 
|  | ## LUI | 
|  |  | 
|  | This instruction uses the `U` encoding schema, with covergroup `enc_u_cg`. | 
|  | There are no further coverage points. | 
|  |  | 
|  | ## SUB | 
|  |  | 
|  | This instruction uses the `R` encoding schema, with covergroup `enc_r_cg`. | 
|  | The instruction-specific covergroup is `insn_addsub_cg`. | 
|  |  | 
|  | - Cross the three possible signs (negative, zero, positive) for each input operand (giving 9 points). | 
|  | Tracked as `sign_a_sign_b_cross`. | 
|  |  | 
|  | ## SLL | 
|  |  | 
|  | This instruction uses the `R` encoding schema, with covergroup `enc_r_cg`. | 
|  | The instruction-specific covergroup is `insn_sll_cg`. | 
|  |  | 
|  | - A shift of a nonzero value by zero. | 
|  | Tracked as `nz_by_z_cp`. | 
|  | - A shift of a value by `0x1f` which leaves the top bit set. | 
|  | Tracked as `shift15_cp`. | 
|  |  | 
|  | ## SLLI | 
|  |  | 
|  | This instruction uses the `Is` encoding schema, with covergroup `enc_is_cg`. | 
|  | The instruction-specific covergroup is `insn_slli_cg`. | 
|  |  | 
|  | - A shift of a nonzero value by zero. | 
|  | Tracked as `nz_by_z_cp`. | 
|  | - A shift of a value by `0x1f` which leaves the top bit set. | 
|  | Tracked as `shift15_cp`. | 
|  |  | 
|  | ## SRL | 
|  |  | 
|  | This instruction uses the `R` encoding schema, with covergroup `enc_r_cg`. | 
|  | The instruction-specific covergroup is `insn_srl_cg`. | 
|  |  | 
|  | - A shift of a nonzero value by zero. | 
|  | Tracked as `nz_by_z_cp`. | 
|  | - A shift of a value by `0x1f` which leaves the bottom bit set. | 
|  | Tracked as `shift15_cp`. | 
|  | Note that this point also checks that we're performing a logical, rather than arithmetic, right shift. | 
|  |  | 
|  | ## SRLI | 
|  |  | 
|  | This instruction uses the `Is` encoding schema, with covergroup `enc_is_cg`. | 
|  | The instruction-specific covergroup is `insn_srli_cg`. | 
|  |  | 
|  | - A shift of a nonzero value by zero. | 
|  | Tracked as `nz_by_z_cp`. | 
|  | - A shift of a value by `0x1f` which leaves the bottom bit set. | 
|  | Tracked as `shift15_cp`. | 
|  | Note that this point also checks that we're performing a logical, rather than arithmetic, right shift. | 
|  |  | 
|  | ## SRA | 
|  |  | 
|  | This instruction uses the `R` encoding schema, with covergroup `enc_r_cg`. | 
|  | The instruction-specific covergroup is `insn_sra_cg`. | 
|  |  | 
|  | - A shift of a nonzero value by zero. | 
|  | Tracked as `nz_by_z_cp`. | 
|  | - A shift of a value by `0x1f` which leaves the bottom bit set. | 
|  | Tracked as `shift15_cp`. | 
|  | Note that this point also checks that we're performing an arithmetic, rather than logical, right shift. | 
|  |  | 
|  | ## SRAI | 
|  |  | 
|  | This instruction uses the `Is` encoding schema, with covergroup `enc_is_cg`. | 
|  | The instruction-specific covergroup is `insn_srai_cg`. | 
|  |  | 
|  | - A shift of a nonzero value by zero. | 
|  | Tracked as `nz_by_z_cp`. | 
|  | - A shift of a value by `0x1f` which leaves the bottom bit set. | 
|  | Tracked as `shift15_cp`. | 
|  | Note that this point also checks that we're performing an arithmetic, rather than logical, right shift. | 
|  |  | 
|  | ## AND | 
|  |  | 
|  | This instruction uses the `R` encoding schema, with covergroup `enc_r_cg`. | 
|  | The instruction-specific covergroup is `insn_log_binop_cg` (shared with other logical binary operations). | 
|  |  | 
|  | - Toggle coverage of the output result, not to `x0` (to ensure we're not just AND'ing things with zero) | 
|  | Tracked as `write_data_XXXXX_cross`, where `XXXXX` is the base-2 representation of the bit being checked. | 
|  |  | 
|  | ## ANDI | 
|  |  | 
|  | This instruction uses the `I` encoding schema, with covergroup `enc_i_cg`. | 
|  | The instruction-specific covergroup is `insn_log_binop_cg` (shared with other logical binary operations). | 
|  |  | 
|  | - Toggle coverage of the output result, not to `x0` (to ensure we're not just AND'ing things with zero) | 
|  | Tracked as `write_data_XXXXX_cross`, where `XXXXX` is the base-2 representation of the bit being checked. | 
|  |  | 
|  | ## OR | 
|  |  | 
|  | This instruction uses the `R` encoding schema, with covergroup `enc_r_cg`. | 
|  | The instruction-specific covergroup is `insn_log_binop_cg` (shared with other logical binary operations). | 
|  |  | 
|  | - Toggle coverage of the output result, not to `x0` (to ensure we're not just OR'ing things with `'1`) | 
|  | Tracked as `write_data_XXXXX_cross`, where `XXXXX` is the base-2 representation of the bit being checked. | 
|  |  | 
|  | ## ORI | 
|  |  | 
|  | This instruction uses the `I` encoding schema, with covergroup `enc_i_cg`. | 
|  | The instruction-specific covergroup is `insn_log_binop_cg` (shared with other logical binary operations). | 
|  |  | 
|  | - Toggle coverage of the output result, not to `x0` (to ensure we're not just OR'ing things with `'1`) | 
|  | Tracked as `write_data_XXXXX_cross`, where `XXXXX` is the base-2 representation of the bit being checked. | 
|  |  | 
|  | ## XOR | 
|  |  | 
|  | This instruction uses the `R` encoding schema, with covergroup `enc_r_cg`. | 
|  | The instruction-specific covergroup is `insn_log_binop_cg` (shared with other logical binary operations). | 
|  |  | 
|  | - Toggle coverage of the output result, not to `x0` (to ensure we're not just XOR'ing things with zero) | 
|  | Tracked as `write_data_XXXXX_cross`, where `XXXXX` is the base-2 representation of the bit being checked. | 
|  |  | 
|  | ## XORI | 
|  |  | 
|  | This instruction uses the `I` encoding schema, with covergroup `enc_i_cg`. | 
|  | The instruction-specific covergroup is `insn_log_binop_cg` (shared with other logical binary operations). | 
|  |  | 
|  | - Toggle coverage of the output result, not to `x0` (to ensure we're not just XOR'ing things with zero) | 
|  | Tracked as `write_data_XXXXX_cross`, where `XXXXX` is the base-2 representation of the bit being checked. | 
|  |  | 
|  | ## LW | 
|  |  | 
|  | This instruction uses the `I` encoding schema, with covergroup `enc_i_cg`. | 
|  | The instruction-specific covergroup is `insn_xw_cg` (shared with `SW`). | 
|  |  | 
|  | - Load from a valid address, where `<grs1>` is above the top of memory and a negative `<offset>` brings the load address in range. | 
|  | Tracked as `oob_base_neg_off_cross`. | 
|  | - Load from a valid address, where `<grs1>` is negative and a positive `<offset>` brings the load address in range. | 
|  | Tracked as `neg_base_pos_off_cross`. | 
|  | - Load from address zero. | 
|  | Tracked as `addr0_cross`. | 
|  | - Load from the top word of memory | 
|  | Tracked as `top_addr_cross`. | 
|  | - Load from an invalid address (aligned but above the top of memory) | 
|  | Tracked as `oob_addr_cross`. | 
|  | - Load from a calculated negative invalid address (aligned but unsigned address exceeds the top of memory) | 
|  | Tracked as `oob_addr_neg_cross`. | 
|  | - Load from a "barely invalid" address (just above the top of memory) | 
|  | Tracked as `barely_oob_addr_cross`. | 
|  | - Misaligned address tracking. | 
|  | Track loads from addresses that are in range for the size of the memory. | 
|  | Cross the different values modulo 4 for `grs1` and `offset`. | 
|  | Tracked as `align_cross`. | 
|  |  | 
|  | It is possible for LW to trigger multiple errors in a single cycle. | 
|  | The possible errors are: underflow call stack, invalid DMEM address, and overflow call stack. | 
|  | It's not possible to under- and overflow the call stack in a single cycle. | 
|  | Similarly, if we underflow the call stack, we won't have an address at all (valid or otherwise). | 
|  | This leaves a single combination to check: | 
|  |  | 
|  | - Overflow the call stack when loading from an invalid address. | 
|  | Tracked as `overflow_cs_invalid_addr_cp`. | 
|  |  | 
|  | ## SW | 
|  |  | 
|  | This instruction uses the `I` encoding schema, with covergroup `enc_s_cg`. | 
|  | The instruction-specific covergroup is `insn_xw_cg` (shared with `LW`). | 
|  |  | 
|  | - Store to a valid address, where `<grs1>` is above the top of memory and a negative `<offset>` brings the load address in range. | 
|  | Tracked as `oob_base_neg_off_cross`. | 
|  | - Store to a valid address, where `<grs1>` is negative and a positive `<offset>` brings the load address in range. | 
|  | Tracked as `neg_base_pos_off_cross`. | 
|  | - Store to address zero | 
|  | Tracked as `addr0_cross`. | 
|  | - Store to the top word of memory | 
|  | Tracked as `top_addr_cross`. | 
|  | - Store to an invalid address (aligned but above the top of memory) | 
|  | Tracked as `oob_addr_cross`. | 
|  | - Store to a calculated negative invalid address (aligned but unsigned address exceeds the top of memory) | 
|  | Tracked as `oob_addr_neg_cross`. | 
|  | - Store to a "barely invalid" address (aligned but overlapping the top of memory) | 
|  | Tracked as `barely_oob_addr_cross`. | 
|  | - Misaligned address tracking. | 
|  | Track stores from addresses that are in range for the size of the memory. | 
|  | Cross the different values modulo 4 for `grs1` and `offset`. | 
|  | Tracked as `align_cross`. | 
|  |  | 
|  | It is possible for SW to trigger multiple errors in a single cycle. | 
|  | The possible errors are: underflow call stack and invalid DMEM address. | 
|  | These can happen together, giving a single combination to check: | 
|  |  | 
|  | - Underflow the call stack when reading the value to be stored and try to write it to an invalid address. | 
|  | Tracked as `underflow_cs_invalid_addr_cp`. | 
|  |  | 
|  | ## BEQ | 
|  |  | 
|  | This instruction uses the `B` encoding schema, with covergroup `enc_b_cg`. | 
|  | The instruction-specific covergroup is `insn_bxx_cg` (shared with `BNE`). | 
|  |  | 
|  | All points should be crossed with branch taken / branch not taken. | 
|  |  | 
|  | - See each branch direction (forwards, backwards, current address). | 
|  | Tracked as `eq_dir_cross`. | 
|  | - Branch to a misaligned address (offset not a multiple of 4) | 
|  | PC is always 4-bit aligned and offset is a multiple of 2 by definition. | 
|  | Therefore the only misalignment would be by setting the second bit of the offset to 1. | 
|  | Offset alignment is tracked in `eq_offset_align_cross`. | 
|  | - Branch forwards to an invalid address, above the top of memory | 
|  | Tracked as `eq_oob_cross`. | 
|  | - Branch backwards to an invalid address (wrapping past zero) | 
|  | Tracked as `eq_neg_cross`. | 
|  | - Branch instruction at end of a loop. | 
|  | Tracked as `eq_at_loop_end_cross` (which also crosses with whether the branch was taken or not). | 
|  |  | 
|  | The "branch to current address" item is problematic if we want to take the branch. | 
|  | Probably we need some tests with short timeouts to handle this properly. | 
|  |  | 
|  | It is possible for BEQ to trigger multiple errors in a single cycle. | 
|  | The possible errors are: underflow call stack, bad target address, and branch at end of loop. | 
|  | Since the target address check only triggers if the branch is taken, which requires a value for comparison, it's not possible to underflow the call stack and see a bad target address at the same time. | 
|  | This leaves two possible combinations: | 
|  |  | 
|  | - Underflow the call stack in a branch at the end of a loop. | 
|  | Tracked as `underflow_at_loop_end_cross`. | 
|  | - Take a branch to an invalid address where the branch instruction is at the end of a loop. | 
|  | Tracked as `bad_addr_at_loop_end_cross`. | 
|  |  | 
|  | ## BNE | 
|  |  | 
|  | This instruction uses the `B` encoding schema, with covergroup `enc_b_cg`. | 
|  | The instruction-specific covergroup is `insn_bxx_cg` (shared with `BEQ`). | 
|  |  | 
|  | All points should be crossed with branch taken / branch not taken. | 
|  |  | 
|  | - See each branch direction (forwards, backwards, current address). | 
|  | Tracked as `eq_dir_cross`. | 
|  | - Branch to a misaligned address (offset not a multiple of 4) | 
|  | PC is always 4-bit aligned and offset is a multiple of 2 by definition. | 
|  | Therefore the only misalignment would be by setting the second bit of the offset to 1. | 
|  | Offset alignment is tracked in `eq_offset_align_cross`. | 
|  | - Branch forwards to an invalid address, above the top of memory | 
|  | Tracked as `eq_oob_cross`. | 
|  | - Branch backwards to an invalid address (wrapping past zero) | 
|  | Tracked as `eq_neg_cross`. | 
|  | - Branch instruction at end of a loop. | 
|  | Tracked as `eq_at_loop_end_cross` (which also crosses with whether the branch was taken or not). | 
|  |  | 
|  | The "branch to current address" item is problematic if we want to take the branch. | 
|  | Probably we need some tests with short timeouts to handle this properly. | 
|  |  | 
|  | It is possible for BNE to trigger multiple errors in a single cycle. | 
|  | The possible errors are: underflow call stack, bad target address, and branch at end of loop. | 
|  | Since the target address check only triggers if the branch is taken, which requires a value for comparison, it's not possible to underflow the call stack and see a bad target address at the same time. | 
|  | This leaves two possible combinations: | 
|  |  | 
|  | - Underflow the call stack in a branch at the end of a loop. | 
|  | Tracked as `underflow_at_loop_end_cross`. | 
|  | - Take a branch to an invalid address where the branch instruction is at the end of a loop. | 
|  | Tracked as `bad_addr_at_loop_end_cross`. | 
|  |  | 
|  | ## JAL | 
|  |  | 
|  | This instruction uses the `J` encoding schema, with covergroup `enc_j_cg`. | 
|  | The instruction-specific covergroup is `insn_jal_cg`. | 
|  |  | 
|  | - See each jump direction (forwards, backwards, current address). | 
|  | Tracked as `dir_cp`. | 
|  | - Jump to a misaligned address (offset not a multiple of 4) | 
|  | Offset alignments are tracked in `offset_align_cp`. | 
|  | - Jump forwards to an invalid address, above the top of memory | 
|  | Tracked as `oob_cp`. | 
|  | - Jump backwards to an invalid address (wrapping past zero) | 
|  | Tracked as `neg_cp`. | 
|  | - Jump when the current PC is the top word in IMEM. | 
|  | Tracked as `from_top_cp`. | 
|  | - Jump instruction at end of a loop. | 
|  | Tracked as `at_loop_end_cp`. | 
|  |  | 
|  | Note that the "jump to current address" item won't be a problem to test since it will quickly overflow the call stack. | 
|  |  | 
|  | It is possible for JAL to trigger multiple errors in a single cycle. | 
|  | The possible errors are: overflow call stack, bad target address, and jump at end of loop. | 
|  | All four combinations are possible: | 
|  |  | 
|  | - Overflow call stack when jumping to an invalid address. | 
|  | Tracked as `overflow_and_invalid_addr_cp`. | 
|  | - Overflow call stack from a jump at the end of a loop. | 
|  | Tracked as `overflow_at_loop_end_cp`. | 
|  | - Jump to an invalid address from the end of a loop. | 
|  | Tracked as `invalid_addr_at_loop_end_cp`. | 
|  | - Overflow call stack when jumping to an invalid address from the end of a loop. | 
|  | Tracked as `overflow_and_invalid_addr_at_loop_end_cp`. | 
|  |  | 
|  | ## JALR | 
|  |  | 
|  | This instruction uses the `I` encoding schema, with covergroup `enc_i_cg`. | 
|  | The instruction-specific covergroup is `insn_jalr_cg`. | 
|  |  | 
|  | - See each jump offset (forwards, backwards, zero). | 
|  | Tracked as `off_dir_cp`. | 
|  | - Jump with a misaligned base address which `<offset>` aligns. | 
|  | Pairs of base address / offset alignments tracked in `align_cross`. | 
|  | - Jump with a large base address which wraps to a valid address by adding a positive `<offset>`. | 
|  | Tracked as `pos_wrap_cp`. | 
|  | - Jump with a base address just above top of IMEM but with a negative `<offset>` to give a valid target. | 
|  | Tracked as `sub_cp`. | 
|  | - Jump with a negative offset, wrapping to give an invalid target. | 
|  | Tracked as `neg_wrap_cp`. | 
|  | - Jump to an aligned address above top of IMEM. | 
|  | Tracked as `oob_cp`. | 
|  | - Jump to current address. | 
|  | Tracked as `self_cp`. | 
|  | - Jump when the current PC is the top word in IMEM. | 
|  | Tracked as `from_top_cp`. | 
|  | - Jump instruction at end of a loop. | 
|  | Tracked as `at_loop_end_cp`. | 
|  |  | 
|  | Note that the "jump to current address" item won't be a problem to test since it will quickly over- or underflow the call stack, provided `<grd>` and `<grs1>` aren't both `x1`. | 
|  |  | 
|  | It is possible for JALR to trigger multiple errors in a single cycle. | 
|  | The possible errors are: underflow call stack, overflow call stack, bad target address, and jump at end of loop. | 
|  | If we underflow the call stack, we can't also overflow it, nor do we have a target address. | 
|  | This means the only error that can occur in combination with underflowing the call stack is a jump at the end of a loop. | 
|  | Otherwise, all other combinations are possible. | 
|  |  | 
|  | - Underflow call stack in a jump instruction at the end of a loop. | 
|  | Tracked as `underflow_at_loop_end_cp`. | 
|  | - Overflow call stack when jumping to an invalid address. | 
|  | Tracked as `overflow_and_bad_addr_cp`. | 
|  | - Overflow call stack from a jump at the end of a loop. | 
|  | Tracked as `overflow_at_loop_end_cp`. | 
|  | - Jump to an invalid address from the end of a loop. | 
|  | Tracked as `bad_addr_at_loop_end_cp`. | 
|  | - Overflow call stack when jumping to an invalid address from the end of a loop. | 
|  | Tracked as `overflow_and_bad_addr_at_loop_end_cp`. | 
|  |  | 
|  | ## CSRRS | 
|  |  | 
|  | This instruction uses the `I` encoding schema, with covergroup `enc_i_cg`. | 
|  | The instruction-specific covergroup is `insn_csrrs_cg`. | 
|  |  | 
|  | - Write with a non-zero `bits_to_set` to each valid CSR. | 
|  | - Write to an invalid CSR. | 
|  |  | 
|  | These points are tracked with `csr_cross` in `insn_csrrs_cg`. | 
|  | It crosses `csr_cp` (which tracks each valid CSR, plus an invalid CSR) with `bits_to_set_cp` (which tracks whether `bits_to_set` is nonzero). | 
|  |  | 
|  | It is possible for CSRRS to trigger multiple errors in a single cycle. | 
|  | The possible errors are: underflow call stack, overflow call stack, and invalid CSR. | 
|  | It's not possible to under- and overflow the call stack in a single cycle. | 
|  | The other two combinations are possible: | 
|  |  | 
|  | - Underflow the call stack and access an invalid CSR | 
|  | Tracked as `underflow_with_bad_csr_cp`. | 
|  | - Overflow the call stack and access an invalid CSR | 
|  | Tracked as `overflow_with_bad_csr_cp`. | 
|  |  | 
|  | ## CSRRW | 
|  |  | 
|  | This instruction uses the `I` encoding schema, with covergroup `enc_i_cg`. | 
|  | The instruction-specific covergroup is `insn_csrrw_cg`. | 
|  |  | 
|  | - Write to every valid CSR with a `<grd>` other than `x0`. | 
|  | - Write to every valid CSR with `<grd>` equal to `x0`. | 
|  | - Write to an invalid CSR. | 
|  |  | 
|  | These points are tracked with `csr_cross` in `insn_csrrw_cg`. | 
|  | It crosses `csr_cp` (which tracks each valid CSR, plus an invalid CSR) with `grd_cp_to_set_cp` (which tracks whether `grd` is equal to `x0`. | 
|  |  | 
|  | It is possible for CSRRW to trigger multiple errors in a single cycle. | 
|  | The possible errors are: underflow call stack, overflow call stack, and invalid CSR. | 
|  | It's not possible to under- and overflow the call stack in a single cycle. | 
|  | The other two combinations are possible: | 
|  |  | 
|  | - Underflow the call stack and access an invalid CSR | 
|  | Tracked as `underflow_with_bad_csr_cp`. | 
|  | - Overflow the call stack and access an invalid CSR | 
|  | Tracked as `overflow_with_bad_csr_cp`. | 
|  |  | 
|  | ## ECALL | 
|  |  | 
|  | This instruction uses the `I` encoding schema, but with every field set to a fixed value. | 
|  | Encoding-level coverpoints are tracked in covergroup `enc_ecall_cg`. | 
|  |  | 
|  | No special coverage points for this instruction. | 
|  |  | 
|  | ## LOOP | 
|  |  | 
|  | This instruction uses the `loop` encoding schema, with covergroup `enc_loop_cg`. | 
|  | The instruction-specific covergroup is `insn_loop_cg`. | 
|  |  | 
|  | - Loop with a zero iteration count (causing an error) | 
|  | Tracked as the `'0` bin of `iterations_cp`. | 
|  | - Loop with a count of `'1` (the maximal value) | 
|  | Tracked as the `'1` bin of `iterations_cp`. | 
|  | - Loop when the loop end address would be above the top of memory. | 
|  | Tracked as `oob_end_addr_cp`. | 
|  | - Loop when the loop stack is full, causing an overflow. | 
|  | Tracked as `loop_stack_fullness_cp`. | 
|  | - Loop at the end of a loop. | 
|  | Tracked as `at_loop_end_cp`. | 
|  | - Duplicate loop end address, matching top of stack | 
|  | Tracked as `duplicate_loop_end_cp`. | 
|  |  | 
|  | It is possible for LOOP to trigger multiple errors in a single cycle. | 
|  | The possible errors are: underflow call stack, zero loop count, and loop at end of loop. | 
|  | It's not possible to underflow the call stack and see a zero loop count (because if we underflow the call stack, we have no loop count), so we get two pairs: | 
|  |  | 
|  | - Underflow the call stack and loop at the end of a loop. | 
|  | Tracked as `underflow_at_loop_end_cp`. | 
|  | - Loop with a zero loop count at the end of a loop. | 
|  | Tracked as `zero_count_at_loop_end_cp`. | 
|  |  | 
|  | ## LOOPI | 
|  |  | 
|  | This instruction uses the `loopi` encoding schema, with covergroup `enc_loopi_cg`. | 
|  | The instruction-specific covergroup is `insn_loopi_cg`. | 
|  |  | 
|  | - Loop with a zero iteration count (causing an error) | 
|  | This is tracked in `enc_loopi_cg` with the `'0` bin of `iterations_cp`. | 
|  | - Loop when the loop end address would be above the top of memory. | 
|  | Tracked as `oob_end_addr_cp`. | 
|  | - Loop when the loop stack is full, causing an overflow. | 
|  | Tracked as `loop_stack_fullness_cp`. | 
|  | - Loop at the end of a loop. | 
|  | Tracked as `at_loop_end_cp`. | 
|  | - Duplicate loop end address, matching top of stack | 
|  | Tracked as `duplicate_loop_end_cp`. | 
|  |  | 
|  | It is possible for LOOPI to trigger multiple errors in a single cycle. | 
|  | The possible errors are: zero loop count and loop at end of loop. | 
|  | These can happen together: | 
|  |  | 
|  | - Loop with a zero loop count at the end of a loop. | 
|  | Tracked as `zero_count_at_loop_end_cp`. | 
|  |  | 
|  | ## BN.ADD | 
|  |  | 
|  | This instruction uses the `bnaf` encoding schema, with covergroup `enc_bnaf_cg`. | 
|  | There is no instruction-specific covergroup. | 
|  |  | 
|  | - Extremal values of shift for both directions where the shifted value is nonzero. | 
|  | This is tracked in `enc_bnaf_cg` as `st_sb_nz_shifted_cross`. | 
|  | - A nonzero right shift with a value in `wrs2` whose top bit is set | 
|  | This is tracked in `enc_bnaf_cg` as `srl_cross`. | 
|  |  | 
|  | ## BN.ADDC | 
|  |  | 
|  | This instruction uses the `bnaf` encoding schema, with covergroup `enc_bnaf_cg`. | 
|  | The instruction-specific covergroup is `insn_bn_addc_cg`. | 
|  |  | 
|  | - Extremal values of shift for both directions where the shifted value is nonzero | 
|  | This is tracked in `enc_bnaf_cg` as `st_sb_nz_shifted_cross`. | 
|  | - A nonzero right shift with a value in `wrs2` whose top bit is set | 
|  | This is tracked in `enc_bnaf_cg` as `srl_cross`. | 
|  | - Execute with both values of the carry flag for both flag groups (to make sure things are wired through properly) | 
|  | Tracked as `carry_cross`. | 
|  |  | 
|  | ## BN.ADDI | 
|  |  | 
|  | This instruction uses the `bnai` encoding schema, with covergroup `enc_bnai_cg`. | 
|  | There is no instruction-specific covergroup. | 
|  |  | 
|  | No special coverage. | 
|  |  | 
|  | ## BN.ADDM | 
|  |  | 
|  | This instruction uses the `bnam` encoding schema, with covergroup `enc_bnam_cg`. | 
|  | The instruction-specific covergroup is `insn_bn_addm_cg`. | 
|  |  | 
|  | - Execute with the two extreme values of `MOD` (zero and all ones) | 
|  | Tracked as `mod_cp`. | 
|  | - Don't perform a subtraction (because the sum is less than `MOD`) when `MOD` is nonzero. | 
|  | Tracked as `sum_lt_cp`. | 
|  | - A calculation where the sum exactly equals a nonzero `MOD` | 
|  | Tracked as `sum_eq_cp`. | 
|  | - A calculation where the sum is greater than a nonzero `MOD`. | 
|  | Tracked as `sum_gt_cp`. | 
|  | - Perform a subtraction where the sum is at least twice a nonzero value of `MOD`. | 
|  | Tracked as `sum_gt2_cp`. | 
|  | - A calculation where the intermediate sum is greater than `2^256-1`, crossed with whether the subtraction of `MOD` results in a value that will wrap. | 
|  | Tracked as `overflow_wrap_cross`. | 
|  |  | 
|  | ## BN.MULQACC | 
|  |  | 
|  | This instruction uses the `bnaq` encoding schema, with covergroup `enc_bnaq_cg`. | 
|  | The instruction-specific covergroup is `insn_bn_mulqaccx_cg` (shared with the other `BN.MULQACC*` instructions). | 
|  |  | 
|  | - Cross `wrs1_qwsel` with `wrs2_qwsel` to make sure they are applied to the right inputs | 
|  | This is tracked in `enc_bnaq_cg` as `qwsel_cross`. | 
|  | - See the accumulator overflow | 
|  | This is tracked in `insn_bnmulqaccx_cg` as `overflow_cross`. | 
|  |  | 
|  | ## BN.MULQACC.WO | 
|  |  | 
|  | This instruction uses the `bnaq` encoding schema, with an extra field not present in `bn.mulqacc`. | 
|  | Encoding-level coverpoints are tracked in covergroup `enc_bnaqw_cg`. | 
|  | The instruction-specific covergroup is `insn_bn_mulqaccx_cg` (shared with the other `BN.MULQACC*` instructions). | 
|  |  | 
|  | - Cross `wrs1_qwsel` with `wrs2_qwsel` to make sure they are applied to the right inputs | 
|  | This is tracked in `enc_bnaqw_cg` as `qwsel_cross`. | 
|  | - See the accumulator overflow | 
|  | This is tracked in `insn_bnmulqaccx_cg` as `overflow_cross`. | 
|  |  | 
|  | ## BN.MULQACC.SO | 
|  |  | 
|  | This instruction uses the `bnaq` encoding schema, with an extra field not present in `bn.mulqacc`. | 
|  | Encoding-level coverpoints are tracked in covergroup `enc_bnaqs_cg`. | 
|  | The instruction-specific covergroup is `insn_bn_mulqaccx_cg` (shared with the other `BN.MULQACC*` instructions). | 
|  |  | 
|  | - Cross `wrs1_qwsel` with `wrs2_qwsel` to make sure they are applied to the right inputs | 
|  | This is tracked in `enc_bnaqs_cg` as `qwsel_cross`. | 
|  | - See the accumulator overflow | 
|  | This is tracked in `insn_bnmulqaccx_cg` as `overflow_cross`. | 
|  | - Cross the generic flag updates with `wrd_hwsel`, since the flag changes are different in the two modes. | 
|  | This is tracked in `enc_bnaqs_cg` as `flags_01_cross`, `flags_10_cross` and `flags_11_cross`. | 
|  |  | 
|  | ## BN.SUB | 
|  |  | 
|  | This instruction uses the `bnaf` encoding schema, with covergroup `enc_bnaf_cg`. | 
|  | There is no instruction-specific covergroup. | 
|  |  | 
|  | - Extremal values of shift for both directions where the shifted value is nonzero | 
|  | This is tracked in `enc_bnaf_cg` as `st_sb_nz_shifted_cross`. | 
|  | - A nonzero right shift with a value in `wrs2` whose top bit is set | 
|  | This is tracked in `enc_bnaf_cg` as `srl_cross`. | 
|  |  | 
|  | ## BN.SUBB | 
|  |  | 
|  | This instruction uses the `bnaf` encoding schema, with covergroup `enc_bnaf_cg`. | 
|  | The instruction-specific covergroup is `insn_bn_subcmpb_cg`. | 
|  |  | 
|  | - Extremal values of shift for both directions where the shifted value is nonzero | 
|  | This is tracked in `enc_bnaf_cg` as `st_sb_nz_shifted_cross`. | 
|  | - A nonzero right shift with a value in `wrs2` whose top bit is set | 
|  | This is tracked in `enc_bnaf_cg` as `srl_cross`. | 
|  | - Execute with both values of the carry flag for both flag groups (to make sure things are wired through properly) | 
|  | Tracked as `fg_carry_flag_cross`. | 
|  |  | 
|  | ## BN.SUBI | 
|  |  | 
|  | This instruction uses the `bnai` encoding schema, with covergroup `enc_bnai_cg`. | 
|  | There is no instruction-specific covergroup. | 
|  |  | 
|  | No special coverage. | 
|  |  | 
|  | ## BN.SUBM | 
|  |  | 
|  | This instruction uses the `bnam` encoding schema, with covergroup `enc_bnam_cg`. | 
|  | The instruction-specific covergroup is `insn_bn_subm_cg`. | 
|  |  | 
|  | - Execute with the two extreme values of `MOD` (zero and all ones) | 
|  | Tracked as `mod_cp`. | 
|  | - A non-negative intermediate result with a nonzero `MOD` (so `MOD` is not added). | 
|  | Tracked as `diff_nonneg_cp`. | 
|  | - An intermediate result that exactly equals a nonzero `-MOD`. | 
|  | Tracked as `diff_minus_mod_cp`. | 
|  | - A negative intermediate result with a nonzero `MOD`, so `MOD` is added and the result is positive. | 
|  | Tracked as `diff_neg_cp`. | 
|  | - A very negative intermediate result with a nonzero `MOD` (so `MOD` is added, but the top bit is still set) | 
|  | Tracked as `diff_neg2_cp`. | 
|  |  | 
|  | ## BN.AND | 
|  |  | 
|  | This instruction uses the `bna` encoding schema, with covergroup `enc_bna_cg`. | 
|  | There is no instruction-specific covergroup. | 
|  |  | 
|  | - Extremal values of shift for both directions where the shifted value is nonzero | 
|  | Tracked in `enc_bna_cg` as `st_sb_nz_shifted_cross`. | 
|  | - Toggle coverage of the output result (to ensure we're not just AND'ing things with zero) | 
|  | Tracked in `enc_bna_cg` as `wrd_XXXXXXXX_cross`, where `XXXXXXXX` is the base-2 representation of the bit being checked. | 
|  |  | 
|  | ## BN.OR | 
|  |  | 
|  | This instruction uses the `bna` encoding schema, with covergroup `enc_bna_cg`. | 
|  | There is no instruction-specific covergroup. | 
|  |  | 
|  | - Extremal values of shift for both directions where the shifted value is nonzero | 
|  | Tracked in `enc_bna_cg` as `st_sb_nz_shifted_cross`. | 
|  | - Toggle coverage of the output result (to ensure we're not just OR'ing things with zero) | 
|  | Tracked in `enc_bna_cg` as `wrd_XXXXXXXX_cross`, where `XXXXXXXX` is the base-2 representation of the bit being checked. | 
|  |  | 
|  | ## BN.NOT | 
|  |  | 
|  | This instruction uses the `bnan` encoding schema, with covergroup `enc_bnan_cg`. | 
|  | There is no instruction-specific covergroup. | 
|  |  | 
|  | - Extremal values of shift for both directions where the shifted value is nonzero | 
|  | Tracked in `enc_bnan_cg` as `st_sb_nz_shifted_cross`. | 
|  | - Toggle coverage of the output result (to ensure nothing gets clamped) | 
|  | Tracked in `enc_bnan_cg` as `wrd_XXXXXXXX_cp`, where `XXXXXXXX` is the base-2 representation of the bit being checked. | 
|  |  | 
|  | ## BN.XOR | 
|  |  | 
|  | This instruction uses the `bna` encoding schema, with covergroup `enc_bna_cg`. | 
|  | There is no instruction-specific covergroup. | 
|  |  | 
|  | - Extremal values of shift for both directions where the shifted value is nonzero | 
|  | Tracked in `enc_bna_cg` as `st_sb_nz_shifted_cross`. | 
|  | - Toggle coverage of the output result (to ensure we're not just XOR'ing things with zero) | 
|  | Tracked in `enc_bna_cg` as `wrd_XXXXXXXX_cross`, where `XXXXXXXX` is the base-2 representation of the bit being checked. | 
|  |  | 
|  | ## BN.RSHI | 
|  |  | 
|  | This instruction uses the `bnr` encoding schema, with covergroup `enc_bnr_cg`. | 
|  | There is no instruction-specific covergroup. | 
|  |  | 
|  | No special coverage. | 
|  |  | 
|  | ## BN.SEL | 
|  |  | 
|  | This instruction uses the `bns` encoding schema, with covergroup `enc_bns_cg`. | 
|  | There is no instruction-specific covergroup. | 
|  |  | 
|  | - Cross flag group, flag and flag value (2 times 4 times 2 points) | 
|  | Tracked in `enc_bns_cg` as `flag_cross`. | 
|  |  | 
|  | ## BN.CMP | 
|  |  | 
|  | This instruction uses the `bnc` encoding schema, with covergroup `enc_bnc_cg`. | 
|  | There is no instruction-specific covergroup. | 
|  |  | 
|  | - Extremal values of shift for both directions where the shifted value is nonzero | 
|  | Tracked in `enc_bnc_cg` as `st_sb_nz_shifted_cross`. | 
|  | - A nonzero right shift with a value in `wrs2` whose top bit is set | 
|  | Tracked in `enc_bnc_cg` as `srl_cross`. | 
|  |  | 
|  | ## BN.CMPB | 
|  |  | 
|  | This instruction uses the `bnc` encoding schema, with covergroup `enc_bnc_cg`. | 
|  | The instruction-specific covergroup is `insn_bn_subcmpb_cg`. | 
|  |  | 
|  | - Extremal values of shift for both directions where the shifted value is nonzero | 
|  | Tracked in `enc_bnc_cg` as `st_sb_nz_shifted_cross`. | 
|  | - A nonzero right shift with a value in `wrs2` whose top bit is set | 
|  | Tracked in `enc_bnc_cg` as `srl_cross`. | 
|  | - Execute with both values of the carry flag for both flag groups (to make sure things are wired through properly) | 
|  | Tracked as `fg_carry_flag_cross`. | 
|  |  | 
|  | ## BN.LID | 
|  |  | 
|  | This instruction uses the `bnxid` encoding schema, with covergroup `enc_bnxid_cg`. | 
|  | The instruction-specific covergroup is `insn_bn_xid_cg` (shared with `BN.SID`). | 
|  |  | 
|  | - Load from a valid address, where `grs1` is above the top of memory and a negative `offset` brings the load address in range. | 
|  | Tracked as `oob_base_neg_off_cross`. | 
|  | - Load from a valid address, where `grs1` is negative and a positive `offset` brings the load address in range. | 
|  | Tracked as `neg_base_pos_off_cross`. | 
|  | - Load from address zero | 
|  | Tracked as `addr0_cross`. | 
|  | - Load from the top word of memory | 
|  | Tracked as `top_addr_cross`. | 
|  | - Load from an invalid address (aligned but above the top of memory) | 
|  | Tracked as `oob_addr_cross`. | 
|  | - Load from a calculated negative invalid address (aligned but unsigned address exceeds the top of memory) | 
|  | Tracked as `oob_addr_neg_cross`. | 
|  | - Misaligned address tracking. | 
|  | Track loads from addresses that are in range for the size of the memory. | 
|  | We track all possible alignments of the sum as `addr_align_cross`. | 
|  | The reason for not tracking offset and register value misalignments separately is because the offset would always be shifted by 5 bits, which makes it always aligned. | 
|  | - See an invalid instruction with both increments specified | 
|  | Tracked in `enc_bnxid_cg` as a bin of `incd_inc1_cross`. | 
|  | - See `grd` greater than 31, giving an illegal instruction error | 
|  | Tracked as `bigb_cross`. | 
|  | - Cross the three types of GPR for `grd` with `grd_inc` | 
|  | Tracked in `enc_bnxid_cg` as `grx_incd_cross`. | 
|  | - Cross the three types of GPR for `grs1` with `grd_inc` | 
|  | Tracked in `enc_bnxid_cg` as `grs1_inc1_cross`. | 
|  |  | 
|  | It is possible for BN.LID to trigger multiple errors in a single cycle. | 
|  | The possible errors are: underflow call stack (for `grs1`), underflow call stack (for `grd`), both increments set, invalid WDR index and bad data address. | 
|  | If we underflow the call stack for `grs1`, there's no architectural address, so that can't happen at the same time as a bad data address. | 
|  | Similarly, if we underflow the call stack for `grd`, there's no WDR index, so that can't cause an invalid WDR index. | 
|  | However, every other combination is possible. | 
|  | Binning together the two underflows unless it makes a difference to the possible behaviour gives the following list: | 
|  |  | 
|  | - Underflow call stack and set both increments. | 
|  | Tracked as `underflow_and_inc_both_cross`. | 
|  | - Underflow call stack for `grs1` and have a bad WDR index in `*grd`. | 
|  | Tracked as `underflow_and_badb_cross`. | 
|  | - Underflow call stack for `grd` and compute a bad address from `*grs1`. | 
|  | Tracked as `underflow_and_bad_addr_cross`. | 
|  | - Set both increments and have a bad WDR index. | 
|  | Tracked as `inc_both_and_bad_wdr_cross`. | 
|  | - Set both increments and load from a bad address. | 
|  | Tracked as `inc_both_and_bad_addr_cross`. | 
|  | - Have a bad WDR index when loading from a bad address. | 
|  | Tracked as `bad_wdr_and_bad_addr_cross`. | 
|  | - Underflow call stack for `grs1`, setting both increments and have a bad WDR index in `*grd`. | 
|  | Tracked as `underflow_and_inc_both_and_bad_wdr_cross`. | 
|  | - Underflow call stack for `grd`, setting both increments and compute a bad address from `*grs1`. | 
|  | Tracked as `underflow_and_inc_both_and_bad_addr_cross`. | 
|  | - Set both increments and have both a bad WDR index and a bad address. | 
|  | Tracked as `inc_both_and_bad_wdr_and_bad_addr_cross`. | 
|  |  | 
|  | ## BN.SID | 
|  |  | 
|  | This instruction uses the `bnxid` encoding schema, with covergroup `enc_bnxid_cg`. | 
|  | The instruction-specific covergroup is `insn_bn_xid_cg` (shared with `BN.LID`). | 
|  |  | 
|  | - Store to a valid address, where `grs1` is above the top of memory and a negative `offset` brings the load address in range. | 
|  | Tracked as `oob_base_neg_off_cross`. | 
|  | - Store to a valid address, where `grs1` is negative and a positive `offset` brings the load address in range. | 
|  | Tracked as `neg_base_pos_off_cross`. | 
|  | - Store to address zero | 
|  | Tracked as `addr0_cross`. | 
|  | - Store to the top word of memory | 
|  | Tracked as `top_addr_cross`. | 
|  | - Store to an invalid address (aligned but above the top of memory) | 
|  | Tracked as `oob_addr_cross`. | 
|  | - Store to a calculated negative invalid address (aligned but unsigned address exceeds the top of memory) | 
|  | Tracked as `oob_addr_neg_cross`. | 
|  | - Misaligned address tracking. | 
|  | Track stores to addresses that are in range for the size of the memory. | 
|  | We track all possible alignments of the sum as `addr_align_cross`. | 
|  | The reason for not tracking offset and register value misalignments separately is because the offset would always be shifted by 5 bits, which makes it always aligned. | 
|  | - See an invalid instruction with both increments specified | 
|  | Tracked in `enc_bnxid_cg` as a bin of `incd_inc1_cross`. | 
|  | - See `grd` greater than 31, giving an illegal instruction error | 
|  | Tracked as `bigb_cross`. | 
|  | - Cross the three types of GPR for `grs2` with `grs2_inc` | 
|  | Tracked in `enc_bnxid_cg` as `grx_incd_cross`. | 
|  | - Cross the three types of GPR for `grs1` with `grd_inc` | 
|  | Tracked in `enc_bnxid_cg` as `grs1_inc1_cross`. | 
|  |  | 
|  | It is possible for BN.SID to trigger multiple errors in a single cycle. | 
|  | The possible errors are: underflow call stack (for `grs1`), underflow call stack (for `grs2`), both increments set, invalid WDR index and bad data address. | 
|  | If we underflow the call stack for `grs1`, there's no architectural address, so that can't happen at the same time as a bad data address. | 
|  | Similarly, if we underflow the call stack for `grs2`, there's no WDR index, so that can't cause an invalid WDR index. | 
|  | However, every other combination is possible. | 
|  | Binning together the two underflows unless it makes a difference to the possible behaviour gives the following list: | 
|  |  | 
|  | - Underflow call stack and set both increments. | 
|  | Tracked as `underflow_and_inc_both_cross`. | 
|  | - Underflow call stack for `grs1` and have a bad WDR index in `*grs2`. | 
|  | Tracked as `underflow_and_badb_cross`. | 
|  | - Underflow call stack for `grs2` and compute a bad address from `*grs1`. | 
|  | Tracked as `underflow_and_bad_addr_cross`. | 
|  | - Set both increments and have a bad WDR index. | 
|  | Tracked as `inc_both_and_bad_wdr_cross`. | 
|  | - Set both increments and store to a bad address. | 
|  | Tracked as `inc_both_and_bad_addr_cross`. | 
|  | - Have a bad WDR index when storing to a bad address. | 
|  | Tracked as `bad_wdr_and_bad_addr_cross`. | 
|  | - Underflow call stack for `grs1`, setting both increments and have a bad WDR index in `*grs2`. | 
|  | Tracked as `underflow_and_inc_both_and_bad_wdr_cross`. | 
|  | - Underflow call stack for `grs2`, setting both increments and compute a bad address from `*grs1`. | 
|  | Tracked as `underflow_and_inc_both_and_bad_addr_cross`. | 
|  | - Set both increments and have both a bad WDR index and a bad address. | 
|  | Tracked as `inc_both_and_bad_wdr_and_bad_addr_cross`. | 
|  |  | 
|  | ## BN.MOV | 
|  |  | 
|  | This instruction uses the `bnmov` encoding schema, with covergroup `enc_bnmov_cg`. | 
|  | There is no instruction-specific covergroup. | 
|  |  | 
|  | No special coverage otherwise. | 
|  |  | 
|  | ## BN.MOVR | 
|  |  | 
|  | This instruction uses the `bnmovr` encoding schema, with covergroup `enc_bnmovr_cg`. | 
|  | The instruction-specific covergroup is `insn_bn_movr_cg`. | 
|  |  | 
|  | - See an invalid instruction with both increments specified | 
|  | Tracked in `enc_bnmovr_cg` as a bin of `incd_inc1_cross`. | 
|  | - Since MOVR signals an error if either of its source registers has a value greater than 31, cross whether the input register value at `grd` is greater than 31 with whether the register value at `grs` is greater than 31 | 
|  | Tracked in `enc_bnmovr_cg` as `big_gpr_cross`. | 
|  |  | 
|  | It is possible for BN.MOVR to trigger multiple errors in a single cycle. | 
|  | The possible errors are: underflow call stack (for `grs`), underflow call stack (for `grd`), both increments set, invalid WDR index (from `*grs`) and invalid WDR index (from `*grd`). | 
|  | If we underflow the call stack for `grs`, there's no WDR index from `*grs`, so it's not also possible to see an invalid WDR index from that. | 
|  | Similarly, if we underflow the call stack for `grd` then there's no WDR index from `*grd`, so it's not also possible to see an invalid WDR index from that. | 
|  | Binning together the two underflows and WDR indices unless it makes a difference to the possible behaviour gives the following list: | 
|  |  | 
|  | - Underflow call stack and set both increments. | 
|  | Tracked as `underflow_and_inc_both_cp`. | 
|  | - Underflow call stack for `grs` and have a bad WDR index in `*grd`. | 
|  | Tracked as `underflow_and_bad_grd_cp`. | 
|  | - Underflow call stack for `grd` and have a bad WDR index in `*grs`. | 
|  | Tracked as `underflow_and_bad_grs_cp`. | 
|  | - Set both increments and have a bad WDR index. | 
|  | Tracked as `inc_both_and_bad_wdr_cp`. | 
|  | - Underflow call stack for `grs`, setting both increments and have a bad WDR index in `*grd`. | 
|  | Tracked as `underflow_grs_and_inc_both_and_bad_wdr_cp`. | 
|  | - Underflow call stack for `grd`, setting both increments and have a bad WDR index in `*grs`. | 
|  | Tracked as `underflow_grd_and_inc_both_and_bad_wdr_cp`. | 
|  |  | 
|  | ## BN.WSRR | 
|  |  | 
|  | This instruction uses the `bnwcsr` encoding schema, with covergroup `enc_wcsr_cg`. | 
|  | There is no instruction-specific covergroup. | 
|  |  | 
|  | - Read from each valid WSR and an invalid WSR. | 
|  | Tracked with `wsr_cross` in `enc_wcsr_cg`. | 
|  | - Read from each key sideload WSR, getting a valid response. | 
|  | Tracked as part of `key_avail_cross` in `insn_bn_wsrr_cg`. | 
|  | - Read from each key sideload WSR, getting a KEY_INVALID error. | 
|  | Tracked as part of `key_avail_cross` in `insn_bn_wsrr_cg`. | 
|  |  | 
|  | These points are tracked with `wsr_cross` in `enc_wcsr_cg`. | 
|  |  | 
|  | ## BN.WSRW | 
|  |  | 
|  | This instruction uses the `bnwcsr` encoding schema, with covergroup `enc_wcsr_cg`. | 
|  | There is no instruction-specific covergroup. | 
|  |  | 
|  | - Write to each valid WSR, including read-only WSRs. | 
|  | - Write to an invalid WSR | 
|  |  | 
|  | These points are tracked with `wsr_cross` in `enc_wcsr_cg`. |