[otbn,doc] Annotate instructions with the errors they can cause

Signed-off-by: Rupert Swarbrick <rswarbrick@lowrisc.org>
diff --git a/hw/ip/otbn/data/base-insns.yml b/hw/ip/otbn/data/base-insns.yml
index 5ff9d2a..f0c0205 100644
--- a/hw/ip/otbn/data/base-insns.yml
+++ b/hw/ip/otbn/data/base-insns.yml
@@ -18,9 +18,9 @@
       funct3: b000
       rd: grd
       opcode: b01100
-  errs:
-    - A `CALL_STACK` error from using `x1` as GRS1 or GRS2 when the call stack is empty.
-    - A `CALL_STACK` error from using `x1` as GRD when the call stack is full.
+  errs: &enc-r-errors
+    - &grs12-call-stack A `CALL_STACK` error from using `x1` as `grs1` or `grs2` when the call stack is empty.
+    - &grd12-call-stack A `CALL_STACK` error from using `x1` as `grd` when the call stack is full and neither `grs1` nor `grs2` is `x1`.
 
 - mnemonic: addi
   rv32i: true
@@ -34,6 +34,9 @@
       funct3: b000
       rd: grd
       opcode: b00100
+  errs: &enc-i-errors
+    - &grs1-call-stack A `CALL_STACK` error from using `x1` as `grs1` when the call stack is empty.
+    - &grd1-call-stack A `CALL_STACK` error from using `x1` as `grd` when the call stack is full and `grs1` is not `x1`.
 
 - mnemonic: lui
   rv32i: true
@@ -48,6 +51,8 @@
       imm: imm
       rd: grd
       opcode: b01101
+  errs:
+    - &grd-call-stack A `CALL_STACK` error from using `x1` as `grd` when the call stack is full.
 
 - mnemonic: sub
   rv32i: true
@@ -62,6 +67,7 @@
       funct3: b000
       rd: grd
       opcode: b01100
+  errs: *enc-r-errors
 
 - mnemonic: sll
   rv32i: true
@@ -76,6 +82,7 @@
       funct3: b001
       rd: grd
       opcode: b01100
+  errs: *enc-r-errors
 
 - mnemonic: slli
   rv32i: true
@@ -95,6 +102,7 @@
       funct3: b001
       rd: grd
       opcode: b00100
+  errs: *enc-i-errors
 
 - mnemonic: srl
   rv32i: true
@@ -109,6 +117,7 @@
       funct3: b101
       rd: grd
       opcode: b01100
+  errs: *enc-r-errors
 
 - mnemonic: srli
   rv32i: true
@@ -126,6 +135,7 @@
       funct3: b101
       rd: grd
       opcode: b00100
+  errs: *enc-i-errors
 
 - mnemonic: sra
   rv32i: true
@@ -140,6 +150,7 @@
       funct3: b101
       rd: grd
       opcode: b01100
+  errs: *enc-r-errors
 
 - mnemonic: srai
   rv32i: true
@@ -157,6 +168,7 @@
       funct3: b101
       rd: grd
       opcode: b00100
+  errs: *enc-i-errors
 
 - mnemonic: and
   rv32i: true
@@ -171,6 +183,7 @@
       funct3: b111
       rd: grd
       opcode: b01100
+  errs: *enc-r-errors
 
 - mnemonic: andi
   rv32i: true
@@ -184,6 +197,7 @@
       funct3: b111
       rd: grd
       opcode: b00100
+  errs: *enc-i-errors
 
 - mnemonic: or
   rv32i: true
@@ -198,6 +212,7 @@
       funct3: b110
       rd: grd
       opcode: b01100
+  errs: *enc-r-errors
 
 - mnemonic: ori
   rv32i: true
@@ -211,6 +226,7 @@
       funct3: b110
       rd: grd
       opcode: b00100
+  errs: *enc-i-errors
 
 - mnemonic: xor
   rv32i: true
@@ -225,6 +241,7 @@
       funct3: b100
       rd: grd
       opcode: b01100
+  errs: *enc-r-errors
 
 - mnemonic: xori
   rv32i: true
@@ -238,6 +255,7 @@
       funct3: b100
       rd: grd
       opcode: b00100
+  errs: *enc-i-errors
 
 - mnemonic: lw
   rv32i: true
@@ -261,6 +279,10 @@
     Unaligned loads are not supported.
     Any address that is unaligned or is above the top of memory will result in an error (setting bit `bad_data_addr` in `ERR_BITS`).
     This instruction takes 2 cycles.
+  errs:
+    - *grs1-call-stack
+    - &data-addr A `BAD_DATA_ADDR` error if the computed address is not a valid 4-byte aligned DMEM address.
+    - *grd1-call-stack
   lsu:
     type: mem-load
     target: [offset, grs1]
@@ -287,6 +309,9 @@
     Stores a 32b word in `grs2` to address `offset + grs1` in data memory.
     Unaligned stores are not supported.
     Any address that is unaligned or is above the top of memory will result in an error (setting bit `bad_data_addr` in `ERR_BITS`).
+  errs:
+    - *grs12-call-stack
+    - *data-addr
   lsu:
     type: mem-store
     target: [offset, grs1]
@@ -312,6 +337,10 @@
       rs1: grs1
       funct3: b000
       opcode: b11000
+  errs: &branch-errors
+    - *grs12-call-stack
+    - A `BAD_INSN_ADDR` error if the branch is taken and the computed address is not a valid PC.
+    - &loop-at-end A `LOOP` error if this instruction appears as the last instruction of a loop body.
 
 - mnemonic: bne
   rv32i: true
@@ -326,6 +355,7 @@
       rs1: grs1
       funct3: b001
       opcode: b11000
+  errs: *branch-errors
 
 - mnemonic: jal
   rv32i: true
@@ -339,6 +369,10 @@
 
     OTBN has a hardware managed call stack, accessed through `x1`, which should be used when calling subroutines.
     Do so by using `x1` as the link register: `jal x1, <offset>`.
+  errs:
+    - *grd-call-stack
+    - &jump-bad-addr A `BAD_INSN_ADDR` error if the computed address is not a valid PC.
+    - *loop-at-end
   encoding:
     scheme: J
     mapping:
@@ -359,6 +393,11 @@
     This pops a link address from the call stack and branches to it.
     To call a subroutine through a function pointer, use `jalr x1, <grs1>, 0`.
     This jumps to the address in `<grs1>` and pushes the link address onto the call stack.
+  errs:
+    - *grs1-call-stack
+    - *grd1-call-stack
+    - *jump-bad-addr
+    - *loop-at-end
   encoding:
     scheme: I
     mapping:
@@ -379,6 +418,9 @@
     Other bits in the CSR are unaffected (though CSRs might have side effects when written).
 
     If `csr` isn't the index of a valid CSR, this results in an error (setting bit `illegal_insn` in `ERR_BITS`).
+  errs:
+    - *grs1-call-stack
+    - &bad-csr An `ILLEGAL_INSN` error if `csr` doesn't name a valid CSR.
   encoding:
     scheme: I
     mapping:
@@ -402,6 +444,10 @@
     If `grd == x0` the instruction does not read the CSR or cause any read-related side-effects.
 
     If `csr` isn't the index of a valid CSR, this results in an error (setting bit `illegal_insn` in `ERR_BITS`).
+  errs:
+    - *grs1-call-stack
+    - *grd1-call-stack
+    - *bad-csr
   encoding:
     scheme: I
     mapping:
@@ -456,6 +502,10 @@
     OTBN will stop on that instruction, setting bit `loop` in `ERR_BITS`.
 
     For more information on how to correctly use `LOOP` see [loop nesting](../#loop-nesting).
+  errs:
+    - &grs-call-stack A `CALL_STACK` error from using `x1` as `grs` when the call stack is empty.
+    - A `LOOP` error if the value in `grs` is zero.
+    - *loop-at-end
   encoding:
     scheme: loop
     mapping:
@@ -489,6 +539,9 @@
     mapping:
       bodysize: bodysize
       iterations: iterations
+  errs:
+    - A `LOOP` error if `iterations` is zero.
+    - *loop-at-end
 
 - mnemonic: nop
   synopsis: No Operation
diff --git a/hw/ip/otbn/data/bignum-insns.yml b/hw/ip/otbn/data/bignum-insns.yml
index 7c0286c..db67e7d 100644
--- a/hw/ip/otbn/data/bignum-insns.yml
+++ b/hw/ip/otbn/data/bignum-insns.yml
@@ -37,6 +37,7 @@
     Adds two WDR values, writes the result to the destination WDR and updates
     flags. The content of the second source WDR can be shifted by an unsigned
     immediate before it is consumed by the operation.
+  errs: []
   encoding:
     scheme: bnaf
     mapping:
@@ -57,6 +58,7 @@
     destination WDR, and updates the flags. The content of the second source
     WDR can be shifted by an unsigned immediate before it is consumed by the
     operation.
+  errs: []
   encoding:
     scheme: bnaf
     mapping:
@@ -84,6 +86,7 @@
   doc: |
     Adds a zero-extended unsigned immediate to the value of a WDR, writes the
     result to the destination WDR, and updates the flags.
+  errs: []
   encoding:
     scheme: bnai
     mapping:
@@ -108,6 +111,7 @@
     The intermediate result is small enough if both inputs are less than `MOD`.
 
     Flags are not used or saved.
+  errs: []
   encoding:
     scheme: bnam
     mapping:
@@ -168,6 +172,7 @@
     Multiplies two `WLEN/4` WDR values, shifts the product by `acc_shift_imm` bits, and adds the result to the accumulator.
 
     For versions of the instruction with writeback, see `BN.MULQACC.WO` and `BN.MULQACC.SO`.
+  errs: []
   encoding:
     scheme: bnaq
     mapping:
@@ -201,6 +206,7 @@
   doc: |
     Multiplies two `WLEN/4` WDR values, shifts the product by `acc_shift_imm` bits, and adds the result to the accumulator.
     Writes the resulting accumulator to `wrd`.
+  errs: []
   encoding:
     scheme: bnaq
     mapping:
@@ -251,6 +257,7 @@
     If `wrd_hwsel` is one (so the instruction is updating the upper half-word of `wrd`), it updates the `M` and `Z` flags and leaves `L` unchanged.
     The `M` flag is set iff the top bit of the shifted-out result is zero.
     The `Z` flag is left unchanged if the shifted-out result is zero and cleared if not.
+  errs: []
   encoding:
     scheme: bnaq
     mapping:
@@ -281,6 +288,7 @@
   doc: |
     Subtracts the second WDR value from the first one, writes the result to the destination WDR and updates flags.
     The content of the second source WDR can be shifted by an unsigned immediate before it is consumed by the operation.
+  errs: []
   encoding:
     scheme: bnaf
     mapping:
@@ -325,6 +333,7 @@
   doc: |
     Subtracts a zero-extended unsigned immediate from the value of a WDR,
     writes the result to the destination WDR, and updates the flags.
+  errs: []
   encoding:
     scheme: bnai
     mapping:
@@ -349,6 +358,7 @@
     This is guaranteed if both inputs are less than `MOD`.
 
     Flags are not used or saved.
+  errs: []
   encoding:
     scheme: bnam
     mapping:
@@ -377,6 +387,7 @@
     Takes the values stored in registers referenced by `wrs1` and `wrs2` and stores the result in the register referenced by `wrd`.
     The content of the second source register can be shifted by an immediate before it is consumed by the operation.
     The M, L and Z flags in flag group `flag_group` are updated with the result of the operation.
+  errs: []
   encoding:
     scheme: bna
     mapping:
@@ -397,6 +408,7 @@
     Takes the values stored in WDRs referenced by `wrs1` and `wrs2` and stores the result in the WDR referenced by `wrd`.
     The content of the second source WDR can be shifted by an immediate before it is consumed by the operation.
     The M, L and Z flags in flag group `flag_group` are updated with the result of the operation.
+  errs: []
   encoding:
     scheme: bna
     mapping:
@@ -424,6 +436,7 @@
     Negates the value in `wrs` and stores the result in the register referenced by `wrd`.
     The source value can be shifted by an immediate before it is consumed by the operation.
     The M, L and Z flags in flag group `flag_group` are updated with the result of the operation.
+  errs: []
   encoding:
     scheme: bnan
     mapping:
@@ -443,6 +456,7 @@
     Takes the values stored in WDRs referenced by `wrs1` and `wrs2` and stores the result in the WDR referenced by `wrd`.
     The content of the second source WDR can be shifted by an immediate before it is consumed by the operation.
     The M, L and Z flags in flag group `flag_group` are updated with the result of the operation.
+  errs: []
   encoding:
     scheme: bna
     mapping:
@@ -472,6 +486,7 @@
   doc: |
     Concatenates the content of WDRs referenced by `wrs1` and `wrs2` (`wrs1` forms the upper part), shifts it right by an immediate value and truncates to WLEN bit.
     The result is stored in the WDR referenced by `wrd`.
+  errs: []
   encoding:
     scheme: bnr
     mapping:
@@ -503,6 +518,7 @@
     <wrd>, <wrs1>, <wrs2>, [FG<flag_group>.]<flag>
   doc: |
     Returns in the destination WDR the value of the first source WDR if the flag in the chosen flag group is set, otherwise returns the value of the second source WDR.
+  errs: []
   encoding:
     scheme: bns
     mapping:
@@ -527,6 +543,7 @@
   doc: |
     Subtracts the second WDR value from the first one and updates flags.
     This instruction is identical to BN.SUB, except that no result register is written.
+  errs: []
   encoding:
     scheme: bnc
     mapping:
@@ -544,6 +561,7 @@
   doc: |
     Subtracts the second WDR value from the first one and updates flags.
     This instruction is identical to BN.SUBB, except that no result register is written.
+  errs: []
   encoding:
     scheme: bnc
     mapping:
@@ -607,6 +625,11 @@
     type: mem-load
     target: [offset, grs1]
     bytes: 32
+  errs:
+    - A `CALL_STACK` error from using `x1` as `grs1` or `grd` when the call stack is empty.
+    - An `ILLEGAL_INSN` error if both `grd_inc` and `grs1_inc` are set.
+    - An `ILLEGAL_INSN` error if the value in GPR `grd` is greater than 31.
+    - &data-addr A `BAD_DATA_ADDR` error if the computed address is not a valid DMEM address aligned to WLEN bits.
   encoding:
     scheme: bnxid
     mapping:
@@ -661,6 +684,11 @@
     The memory address must be aligned to WLEN bits.
     Any address that is unaligned or is above the top of memory results in an error (setting bit `bad_data_addr` in `ERR_BITS`).
     Any `*grs2` value greater than 31 before executing the instruction results in an error (setting bit `illegal_insn` in `ERR_BITS`) and no store or optional increment occurring.
+  errs:
+    - A `CALL_STACK` error from using `x1` as `grs1` or `grs2` when the call stack is empty.
+    - An `ILLEGAL_INSN` error if both `grs1_inc` and `grs2_inc` are set.
+    - An `ILLEGAL_INSN` error if the value in GPR `grs2` is greater than 31.
+    - *data-addr
   lsu:
     type: mem-store
     target: [offset, grs1]
@@ -683,6 +711,7 @@
     mapping:
       src: wrs
       dst: wrd
+  errs: []
 
 - mnemonic: bn.movr
   synopsis: Copy content between WDRs (register-indirect addressing)
@@ -717,6 +746,10 @@
     - If `grs_inc` is set, `grs` is updated to be `*grs + 1`.
 
     Any `*grd` or `*grs` value greater than 31 results in an error (setting bit `illegal_insn` in `ERR_BITS`)
+  errs:
+    - A `CALL_STACK` error from using `x1` as `grs` or `grd` when the call stack is empty.
+    - An `ILLEGAL_INSN` error if either the value in GPR `grd` or the value in GPR `grs` is greater than 31.
+    - An `ILLEGAL_INSN` error if both `grs_inc` and `grd_inc` are set.
   encoding:
     scheme: bnmovr
     mapping:
@@ -735,6 +768,8 @@
   doc: |
     Reads a WSR to a WDR.
     If `wsr` isn't the index of a valid WSR, this results in an error (setting bit `illegal_insn` in `ERR_BITS`).
+  errs:
+    - &bad-wsr An `ILLEGAL_INSN` error if `wsr` doesn't name a valid WSR.
   encoding:
     scheme: wcsr
     mapping:
@@ -757,6 +792,8 @@
   doc: |
     Writes a WDR to a WSR.
     If `wsr` isn't the index of a valid WSR, this results in an error (setting bit `illegal_insn` in `ERR_BITS`).
+  errs:
+    - *bad-wsr
   encoding:
     scheme: wcsr
     mapping:
diff --git a/hw/ip/otbn/util/yaml_to_doc.py b/hw/ip/otbn/util/yaml_to_doc.py
index 1460f6c..6ef8bd3 100755
--- a/hw/ip/otbn/util/yaml_to_doc.py
+++ b/hw/ip/otbn/util/yaml_to_doc.py
@@ -275,9 +275,9 @@
     if insn.errs is not None:
         parts.append(subhead + 'Errors\n')
         if not insn.errs:
-            parts.append('{} cannot cause any synchronous errors.\n'.format(mnem))
+            parts.append('{} cannot cause any software errors.\n'.format(mnem))
         else:
-            parts.append('{} might cause the following synchronous errors:\n'
+            parts.append('{} might cause the following software errors:\n'
                          .format(mnem))
             for desc in insn.errs:
                 parts.append('- {}\n'.format(desc))