Rupert Swarbrick | 83c6aef | 2020-11-19 13:02:58 +0000 | [diff] [blame] | 1 | --- |
| 2 | title: OpenTitan Big Number Accelerator (OTBN) Instruction Set Architecture |
| 3 | --- |
| 4 | |
| 5 | This document describes the instruction set for OTBN. |
Philipp Wagner | 07494a3 | 2021-03-18 15:59:57 +0000 | [diff] [blame] | 6 | For more details about the processor itself, see the [OTBN Technical Specification]({{< relref "." >}}). |
Rupert Swarbrick | 83c6aef | 2020-11-19 13:02:58 +0000 | [diff] [blame] | 7 | In particular, this document assumes knowledge of the *Processor State* section from that guide. |
| 8 | |
| 9 | The instruction set is split into *base* and *big number* subsets. |
| 10 | The base subset (described first) is similar to RISC-V's RV32I instruction set. |
| 11 | It also includes a hardware call stack and hardware loop instructions. |
| 12 | The big number subset is designed to operate on 256b WDRs. |
| 13 | It doesn't include any control flow instructions, and just supports load/store, logical and arithmetic operations. |
| 14 | |
Rupert Swarbrick | bd3d9ea | 2021-01-19 12:36:33 +0000 | [diff] [blame] | 15 | In the instruction documentation that follows, each instruction has a syntax example. |
| 16 | For example, the `SW` instruction has syntax: |
| 17 | ``` |
| 18 | SW <grs2>, <offset>(<grs1>) |
| 19 | ``` |
| 20 | This means that it takes three operands, called `grs2`, `offset` and `grs1`. |
| 21 | These operands are further documented in a table. |
| 22 | Immediate operands like `offset` show their valid range of values. |
| 23 | |
Rupert Swarbrick | bd3d9ea | 2021-01-19 12:36:33 +0000 | [diff] [blame] | 24 | Below the table of operands is an encoding table. |
| 25 | This shows how the 32 bits of the instruction word are filled in. |
| 26 | Ranges of bits that map to an operand are named (in capitals) and those names are used in the operand table. |
| 27 | For example, the `SW` instruction's `offset` operand is split across two ranges of bits (31:25 and 11:7) called `OFF_1` and `OFF_0`, respectively. |
| 28 | |
Rupert Swarbrick | b4142bc | 2021-02-19 17:21:23 +0000 | [diff] [blame] | 29 | # Pseudo-code for operation descriptions |
| 30 | |
| 31 | Each instruction has an Operation section. |
| 32 | This is written in a Python-like pseudo-code, generated from the instruction set simulator (which can be found at `hw/ip/otbn/dv/otbnsim`). |
| 33 | The code is generated from Python, but there are some extra changes made to aid readability. |
| 34 | |
| 35 | All instruction operands are considered to be in scope and have integer values. |
| 36 | These values come from the encoded bits in the instruction and the operand table for the instruction describes exactly how they are decoded. |
| 37 | Some operands are encoded PC-relative. |
| 38 | Such an operand has its absolute value (an address) when it appears in the Operation section. |
| 39 | |
| 40 | Some state updates are represented as an assignment, but take effect at the end of the instruction. |
| 41 | This includes register updates or jumps and branches (updating the PC). |
| 42 | To denote this, we use the ⇐ symbol, reminiscent of Verilog's non-blocking assignment. |
| 43 | |
| 44 | The program counter (PC) is represented as a variable called `PC`. |
| 45 | |
| 46 | Machine registers are accessed with an array syntax. |
| 47 | These arrays are: |
| 48 | |
| 49 | - `GPRs`: General purpose registers |
| 50 | - `WDRs`: Wide data registers |
| 51 | - `CSRs`: Control and status registers |
| 52 | - `WSRs`: Wide special purpose registers |
| 53 | |
| 54 | Accesses to these arrays are as unsigned integers. |
| 55 | The instruction descriptions are written to ensure that any value written to a register is representable. |
| 56 | For example, a write to `GPRs[2]` will always have a non-negative value less than `1 << 32`. |
| 57 | |
| 58 | Memory accesses are represented as function calls. |
| 59 | This is because the memory can be accessed on either the narrow or the wide side, which isn't easy to represent with an array syntax. |
| 60 | Memory loads are represented as `DMEM.load_u32(addr)`, `DMEM.load_u256(addr)`. |
| 61 | Memory stores are represented as `DMEM.store_u32(addr, value)` and `DMEM.store_u256(addr, value)`. |
| 62 | In all cases, memory values are interpreted as unsigned integers and, as for register accesses, the instruction descriptions are written to ensure that any value stored to memory is representable. |
| 63 | |
Rupert Swarbrick | 6e287c3 | 2021-08-09 08:07:29 +0100 | [diff] [blame] | 64 | Some instructions can stall for one or more cycles (those instructions that access memory, CSRs or WSRs). |
| 65 | To represent this precisely in the pseudo-code, and the simulator reference model, such instructions execute a `yield` statement to stall the processor for a cycle. |
| 66 | |
Rupert Swarbrick | b4142bc | 2021-02-19 17:21:23 +0000 | [diff] [blame] | 67 | There are a few other helper functions, defined here to avoid having to inline their bodies into each instruction. |
| 68 | ```python3 |
| 69 | def from_2s_complement(n: int) -> int: |
| 70 | '''Interpret the bits of unsigned integer n as a 32-bit signed integer''' |
| 71 | assert 0 <= n < (1 << 32) |
| 72 | return n if n < (1 << 31) else n - (1 << 32) |
| 73 | |
| 74 | |
| 75 | def to_2s_complement(n: int) -> int: |
| 76 | '''Interpret the bits of signed integer n as a 32-bit unsigned integer''' |
| 77 | assert -(1 << 31) <= n < (1 << 31) |
| 78 | return (1 << 32) + n if n < 0 else n |
Rupert Swarbrick | 3c5d764 | 2021-02-22 11:38:52 +0000 | [diff] [blame] | 79 | |
| 80 | def logical_byte_shift(value: int, shift_type: int, shift_bytes: int) -> int: |
| 81 | '''Logical shift value by shift_bytes to the left or right. |
| 82 | |
| 83 | value should be an unsigned 256-bit value. shift_type should be 0 (shift |
| 84 | left) or 1 (shift right), matching the encoding of the big number |
| 85 | instructions. shift_bytes should be a non-negative number of bytes to shift |
| 86 | by. |
| 87 | |
| 88 | Returns an unsigned 256-bit value, truncating on an overflowing left shift. |
| 89 | |
| 90 | ''' |
| 91 | mask256 = (1 << 256) - 1 |
| 92 | assert 0 <= value <= mask256 |
| 93 | assert 0 <= shift_type <= 1 |
| 94 | assert 0 <= shift_bytes |
| 95 | |
| 96 | shift_bits = 8 * shift_bytes |
| 97 | shifted = value << shift_bits if shift_type == 0 else value >> shift_bits |
| 98 | return shifted & mask256 |
Rupert Swarbrick | 98cc051 | 2021-02-22 12:48:34 +0000 | [diff] [blame] | 99 | |
| 100 | def extract_quarter_word(value: int, qwsel: int) -> int: |
| 101 | '''Extract a 64-bit quarter word from a 256-bit value.''' |
| 102 | assert 0 <= value < (1 << 256) |
| 103 | assert 0 <= qwsel <= 3 |
| 104 | return (value >> (qwsel * 64)) & ((1 << 64) - 1) |
Rupert Swarbrick | b4142bc | 2021-02-19 17:21:23 +0000 | [diff] [blame] | 105 | ``` |
| 106 | |
Rupert Swarbrick | 77cc4b3 | 2021-09-20 12:18:18 +0100 | [diff] [blame] | 107 | # Errors |
| 108 | |
| 109 | OTBN can detect various errors when it is operating. |
| 110 | For details about OTBN's approach to error handling, see the [Errors section]({{< relref ".#design-details-errors" >}}) of the Technical Specification. |
| 111 | The instruction descriptions below describe any software errors that executing the instruction can cause. |
| 112 | These errors are listed explicitly and also appear in the pseudo-code description, where the code sets a bit in the `ERR_BITS` register with a call to `state.stop_at_end_of_cycle()`. |
| 113 | |
| 114 | Other errors are possible at runtime. |
| 115 | Specifically, any instruction that reads from a GPR or WDR might detect a register integrity error. |
| 116 | In this case, OTBN will set the `REG_INTG_VIOLATION` bit. |
| 117 | Similarly, an instruction that loads from memory might detect a DMEM integrity error. |
| 118 | In this case, OTBN will set the `DMEM_INTG_VIOLATION` bit. |
| 119 | |
| 120 | TODO: |
| 121 | Specify interactions between these fatal errors and any other errors. |
| 122 | In particular, how do they interact with instructions that could cause other errors as well? |
| 123 | |
Rupert Swarbrick | 83c6aef | 2020-11-19 13:02:58 +0000 | [diff] [blame] | 124 | <!-- Documentation for the instructions in the ISA. Generated from ../data/insns.yml. --> |
| 125 | # Base Instruction Subset |
| 126 | |
| 127 | {{< otbn_isa base >}} |
| 128 | |
| 129 | # Big Number Instruction Subset |
| 130 | |
| 131 | {{< otbn_isa bignum >}} |