blob: a369733dd32d0e4c2e80a5d15d114f5049152333 [file] [log] [blame]
# 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