| # Copyright lowRISC contributors. |
| # Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| # SPDX-License-Identifier: Apache-2.0 |
| |
| # Definitions for the base group of instructions. See insns.yml for |
| # the detailed format. |
| |
| - mnemonic: add |
| rv32i: true |
| synopsis: Add |
| operands: [grd, grs1, grs2] |
| encoding: |
| scheme: R |
| mapping: |
| funct7: b0000000 |
| rs2: grs2 |
| rs1: grs1 |
| funct3: b000 |
| rd: grd |
| opcode: b01100 |
| 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 |
| synopsis: Add Immediate |
| operands: [grd, grs1, imm] |
| encoding: |
| scheme: I |
| mapping: |
| imm: imm |
| rs1: grs1 |
| 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 |
| synopsis: Load Upper Immediate |
| operands: |
| - grd |
| - name: imm |
| type: uimm |
| encoding: |
| scheme: U |
| mapping: |
| 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 |
| synopsis: Subtract |
| operands: [grd, grs1, grs2] |
| encoding: |
| scheme: R |
| mapping: |
| funct7: b0100000 |
| rs2: grs2 |
| rs1: grs1 |
| funct3: b000 |
| rd: grd |
| opcode: b01100 |
| errs: *enc-r-errors |
| |
| - mnemonic: sll |
| rv32i: true |
| synopsis: Logical left shift |
| operands: [grd, grs1, grs2] |
| encoding: |
| scheme: R |
| mapping: |
| funct7: b0000000 |
| rs2: grs2 |
| rs1: grs1 |
| funct3: b001 |
| rd: grd |
| opcode: b01100 |
| errs: *enc-r-errors |
| |
| - mnemonic: slli |
| rv32i: true |
| synopsis: Logical left shift with Immediate |
| operands: |
| - grd |
| - grs1 |
| - &shamt-operand |
| name: shamt |
| type: uimm |
| encoding: |
| scheme: Is |
| mapping: |
| arithmetic: b0 |
| shamt: shamt |
| rs1: grs1 |
| funct3: b001 |
| rd: grd |
| opcode: b00100 |
| errs: *enc-i-errors |
| |
| - mnemonic: srl |
| rv32i: true |
| synopsis: Logical right shift |
| operands: [grd, grs1, grs2] |
| encoding: |
| scheme: R |
| mapping: |
| funct7: b0000000 |
| rs2: grs2 |
| rs1: grs1 |
| funct3: b101 |
| rd: grd |
| opcode: b01100 |
| errs: *enc-r-errors |
| |
| - mnemonic: srli |
| rv32i: true |
| synopsis: Logical right shift with Immediate |
| operands: |
| - grd |
| - grs1 |
| - *shamt-operand |
| encoding: |
| scheme: Is |
| mapping: |
| arithmetic: b0 |
| shamt: shamt |
| rs1: grs1 |
| funct3: b101 |
| rd: grd |
| opcode: b00100 |
| errs: *enc-i-errors |
| |
| - mnemonic: sra |
| rv32i: true |
| synopsis: Arithmetic right shift |
| operands: [grd, grs1, grs2] |
| encoding: |
| scheme: R |
| mapping: |
| funct7: b0100000 |
| rs2: grs2 |
| rs1: grs1 |
| funct3: b101 |
| rd: grd |
| opcode: b01100 |
| errs: *enc-r-errors |
| |
| - mnemonic: srai |
| rv32i: true |
| synopsis: Arithmetic right shift with Immediate |
| operands: |
| - grd |
| - grs1 |
| - *shamt-operand |
| encoding: |
| scheme: Is |
| mapping: |
| arithmetic: b1 |
| shamt: shamt |
| rs1: grs1 |
| funct3: b101 |
| rd: grd |
| opcode: b00100 |
| errs: *enc-i-errors |
| |
| - mnemonic: and |
| rv32i: true |
| synopsis: Bitwise AND |
| operands: [grd, grs1, grs2] |
| encoding: |
| scheme: R |
| mapping: |
| funct7: b0000000 |
| rs2: grs2 |
| rs1: grs1 |
| funct3: b111 |
| rd: grd |
| opcode: b01100 |
| errs: *enc-r-errors |
| |
| - mnemonic: andi |
| rv32i: true |
| synopsis: Bitwise AND with Immediate |
| operands: [grd, grs1, imm] |
| encoding: |
| scheme: I |
| mapping: |
| imm: imm |
| rs1: grs1 |
| funct3: b111 |
| rd: grd |
| opcode: b00100 |
| errs: *enc-i-errors |
| |
| - mnemonic: or |
| rv32i: true |
| synopsis: Bitwise OR |
| operands: [grd, grs1, grs2] |
| encoding: |
| scheme: R |
| mapping: |
| funct7: b0000000 |
| rs2: grs2 |
| rs1: grs1 |
| funct3: b110 |
| rd: grd |
| opcode: b01100 |
| errs: *enc-r-errors |
| |
| - mnemonic: ori |
| rv32i: true |
| synopsis: Bitwise OR with Immediate |
| operands: [grd, grs1, imm] |
| encoding: |
| scheme: I |
| mapping: |
| imm: imm |
| rs1: grs1 |
| funct3: b110 |
| rd: grd |
| opcode: b00100 |
| errs: *enc-i-errors |
| |
| - mnemonic: xor |
| rv32i: true |
| synopsis: Bitwise XOR |
| operands: [grd, grs1, grs2] |
| encoding: |
| scheme: R |
| mapping: |
| funct7: b0000000 |
| rs2: grs2 |
| rs1: grs1 |
| funct3: b100 |
| rd: grd |
| opcode: b01100 |
| errs: *enc-r-errors |
| |
| - mnemonic: xori |
| rv32i: true |
| synopsis: Bitwise XOR with Immediate |
| operands: [grd, grs1, imm] |
| encoding: |
| scheme: I |
| mapping: |
| imm: imm |
| rs1: grs1 |
| funct3: b100 |
| rd: grd |
| opcode: b00100 |
| errs: *enc-i-errors |
| |
| - mnemonic: lw |
| rv32i: true |
| synopsis: Load Word |
| operands: |
| - grd |
| - name: offset |
| abbrev: "off" |
| - grs1 |
| syntax: <grd>, <offset>(<grs1>) |
| encoding: |
| scheme: I |
| mapping: |
| imm: offset |
| rs1: grs1 |
| funct3: b010 |
| rd: grd |
| opcode: b00000 |
| doc: | |
| Loads a 32b word from address `offset + grs1` in data memory, writing the result to `grd`. |
| 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] |
| bytes: 4 |
| iflow: |
| - to: [grd] |
| from: [dmem] |
| |
| - mnemonic: sw |
| rv32i: true |
| synopsis: Store Word |
| operands: |
| - grs2 |
| - name: offset |
| abbrev: "off" |
| - grs1 |
| syntax: <grs2>, <offset>(<grs1>) |
| encoding: |
| scheme: S |
| mapping: |
| imm: offset |
| rs2: grs2 |
| rs1: grs1 |
| funct3: b010 |
| opcode: b01000 |
| doc: | |
| 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] |
| bytes: 4 |
| iflow: |
| - to: [dmem] |
| from: [grs2] |
| |
| - mnemonic: beq |
| rv32i: true |
| synopsis: Branch Equal |
| operands: &beq-operands |
| - grs1 |
| - grs2 |
| - &branch-offset-operand |
| name: offset |
| abbrev: "off" |
| pc-rel: true |
| type: simm<<1 |
| straight-line: false |
| encoding: |
| scheme: B |
| mapping: |
| imm: offset |
| rs2: grs2 |
| 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 |
| synopsis: Branch Not Equal |
| operands: *beq-operands |
| straight-line: false |
| encoding: |
| scheme: B |
| mapping: |
| imm: offset |
| rs2: grs2 |
| rs1: grs1 |
| funct3: b001 |
| opcode: b11000 |
| errs: *branch-errors |
| |
| - mnemonic: jal |
| rv32i: true |
| synopsis: Jump And Link |
| operands: |
| - grd |
| - *branch-offset-operand |
| straight-line: false |
| doc: | |
| The JAL instruction has the same behavior as in RV32I, jumping by the given offset and writing `PC+4` as a link address to the destination register. |
| |
| 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: |
| imm: offset |
| rd: grd |
| opcode: b11011 |
| |
| - mnemonic: jalr |
| rv32i: true |
| synopsis: Jump And Link Register |
| operands: [grd, grs1, offset] |
| straight-line: false |
| doc: | |
| The JALR instruction has the same behavior as in RV32I, jumping by `<grs1> + <offset>` and writing `PC+4` as a link address to the destination register. |
| |
| OTBN has a hardware managed call stack, accessed through `x1`, which should be used when calling and returning from subroutines. |
| To return from a subroutine, use `jalr x0, x1, 0`. |
| 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: |
| imm: offset |
| rs1: grs1 |
| funct3: b000 |
| rd: grd |
| opcode: b11001 |
| iflow: |
| - to: [grd] |
| from: [] |
| |
| - mnemonic: csrrs |
| rv32i: true |
| synopsis: Atomic Read and Set bits in CSR |
| operands: [grd, csr, grs1] |
| doc: | |
| Reads the value of the CSR `csr`, and writes it to the destination GPR `grd`. |
| The initial value in `grs1` is treated as a bit mask that specifies bits to be set in the CSR. |
| Any bit that is high in `grs1` will cause the corresponding bit to be set in the CSR, if that CSR bit is writable. |
| 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: |
| imm: csr |
| rs1: grs1 |
| funct3: b010 |
| rd: grd |
| opcode: b11100 |
| lsu: |
| type: csr |
| target: [csr] |
| iflow: |
| - to: [grd] |
| from: [] |
| - test: |
| - csr == 0x7c0 |
| to: [fg0-all] |
| from: [fg0-all, grs1] |
| - test: |
| - csr == 0x7c0 |
| to: [grd] |
| from: [fg0-all] |
| - test: |
| - csr == 0x7c1 |
| to: [fg1-all] |
| from: [fg1-all, grs1] |
| - test: |
| - csr == 0x7c1 |
| to: [grd] |
| from: [fg1-all] |
| - test: |
| - csr == 0x7c8 |
| to: [fg0-all, fg1-all] |
| from: [fg0-all, fg1-all, grs1] |
| - test: |
| - csr == 0x7c8 |
| to: [grd] |
| from: [fg0-all, fg1-all] |
| - test: |
| - csr >= 0x7d0 |
| - csr <= 0x7d8 |
| to: [mod] |
| from: [mod, grs1] |
| - test: |
| - csr >= 0x7d0 |
| - csr <= 0x7d8 |
| to: [grd] |
| from: [mod] |
| |
| - mnemonic: csrrw |
| rv32i: true |
| synopsis: Atomic Read/Write CSR |
| operands: [grd, csr, grs1] |
| doc: | |
| Atomically swaps values in the CSR `csr` with the value in the GPR `grs1`. |
| Reads the old value of the CSR, and writes it to the GPR `grd`. |
| Writes the initial value in `grs1` to the CSR `csr`. |
| 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: |
| imm: csr |
| rs1: grs1 |
| funct3: b001 |
| rd: grd |
| opcode: b11100 |
| lsu: |
| type: csr |
| target: [csr] |
| iflow: |
| - to: [grd] |
| from: [] |
| - test: |
| - grd != 0 |
| - csr == 0x7c0 |
| to: [fg0-all] |
| from: [grs1] |
| - test: |
| - grd != 0 |
| - csr == 0x7c0 |
| to: [grd] |
| from: [fg0-all] |
| - test: |
| - grd != 0 |
| - csr == 0x7c1 |
| to: [fg1-all] |
| from: [grs1] |
| - test: |
| - grd != 0 |
| - csr == 0x7c1 |
| to: [grd] |
| from: [fg1-all] |
| - test: |
| - grd != 0 |
| - csr == 0x7c8 |
| to: [fg0-all, fg1-all] |
| from: [grs1] |
| - test: |
| - grd != 0 |
| - csr == 0x7c8 |
| to: [grd] |
| from: [fg0-all, fg1-all] |
| - test: |
| - grd != 0 |
| - csr >= 0x7d0 |
| - csr <= 0x7d8 |
| to: [mod] |
| from: [mod, grs1] |
| - test: |
| - grd != 0 |
| - csr >= 0x7d0 |
| - csr <= 0x7d8 |
| to: [grd] |
| from: [mod] |
| |
| - mnemonic: ecall |
| rv32i: true |
| synopsis: Environment Call |
| operands: [] |
| straight-line: false |
| doc: | |
| Triggers the `done` interrupt to indicate completion of the operation. |
| errs: [] |
| encoding: |
| scheme: I |
| mapping: |
| imm: b000000000000 |
| rs1: b00000 |
| funct3: b000 |
| rd: b00000 |
| opcode: b11100 |
| |
| - mnemonic: loop |
| synopsis: Loop (indirect) |
| operands: |
| - name: grs |
| doc: Name of the GPR containing the number of iterations |
| - &bodysize-operand |
| name: bodysize |
| abbrev: sz |
| type: uimm+1 |
| doc: Number of instructions in the loop body |
| straight-line: false |
| doc: | |
| Repeats a sequence of code multiple times. |
| The number of iterations is read from `grs`, treated as an unsigned value. |
| The number of instructions in the loop is given in the `bodysize` immediate. |
| |
| The `LOOP` instruction doesn't support a zero iteration count. |
| If the value in `grs` is zero, OTBN stops, setting bit `loop` in `ERR_BITS`. |
| Starting a loop pushes an entry on to the [loop stack](../#loop-stack). |
| If the stack is already full, OTBN stops, setting bit `loop` in `ERR_BITS`. |
| |
| `LOOP`, `LOOPI`, jump and branch instructions are all permitted inside a loop but may not appear as the last instruction in a loop. |
| 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: |
| bodysize: bodysize |
| grs: grs |
| |
| - mnemonic: loopi |
| synopsis: Loop Immediate |
| operands: |
| - name: iterations |
| type: uimm |
| doc: Number of iterations |
| - *bodysize-operand |
| straight-line: false |
| doc: | |
| Repeats a sequence of code multiple times. |
| The number of iterations is given in the `iterations` immediate. |
| The number of instructions in the loop is given in the `bodysize` immediate. |
| |
| The `LOOPI` instruction doesn't support a zero iteration count. |
| If the value of `iterations` is zero, OTBN stops with the `ErrCodeLoop` error. |
| Starting a loop pushes an entry on to the [loop stack](../#loop-stack). |
| If the stack is already full, OTBN stops, setting bit `loop` in `ERR_BITS`. |
| |
| `LOOP`, `LOOPI`, jump and branch instructions are all permitted inside a loop but may not appear as the last instruction in a loop. |
| OTBN will stop on that instruction, setting bit `loop` in `ERR_BITS`. |
| |
| For more information on how to correctly use `LOOPI` see [loop nesting](../#loop-nesting). |
| encoding: |
| scheme: loopi |
| mapping: |
| bodysize: bodysize |
| iterations: iterations |
| errs: |
| - A `LOOP` error if `iterations` is zero. |
| - *loop-at-end |
| |
| - mnemonic: nop |
| synopsis: No Operation |
| rv32i: true |
| operands: [] |
| doc: A pseudo-operation that has no effect. |
| literal-pseudo-op: |
| - ADDI x0, x0, 0 |
| |
| - mnemonic: li |
| synopsis: Load Immediate |
| rv32i: true |
| operands: [grd, imm] |
| doc: | |
| Loads a 32b signed immediate value into a GPR. This uses ADDI and LUI, |
| expanding to one or two instructions, depending on the immediate (small |
| non-negative immediates or immediates with all lower bits zero can be |
| loaded with just ADDI or LUI, respectively; general immediates need a LUI |
| followed by an ADDI). |
| python-pseudo-op: true |
| |
| - mnemonic: la |
| synopsis: Load absolute address |
| rv32i: true |
| operands: [grd, imm] |
| doc: | |
| Loads an address given by a symbol into a GPR. This is represented |
| as a LUI and an ADDI. |
| python-pseudo-op: true |
| |
| - mnemonic: ret |
| synopsis: Return from subroutine |
| rv32i: true |
| operands: [] |
| straight-line: false |
| literal-pseudo-op: |
| - JALR x0, x1, 0 |
| |
| # Implement the de-facto UNIMP RISC-V instruction alias according to |
| # https://github.com/riscv/riscv-asm-manual/blob/master/riscv-asm.md |
| # OTBN does not support the cycle CSR (0xC00), hence the illegal instruction |
| # exception stems from the missing CSR instead of writing to a read-only, but |
| # the end result is the same. |
| - mnemonic: unimp |
| synopsis: Illegal instruction |
| rv32i: true |
| operands: [] |
| doc: | |
| Triggers an illegal instruction error and aborts the program execution. |
| Commonly used in code which is meant to be unreachable. |
| literal-pseudo-op: |
| # 0xC00 is the "cycle" RISC-V CSR. |
| - CSRRW x0, 0xC00, x0 |