blob: 504dcaa00fdeb36ddef8f8809398f1e27f74307d [file] [log] [blame] [view]
---
title: OpenTitan Big Number Accelerator (OTBN) Instruction Set Architecture
---
This document describes the instruction set for OTBN.
For more details about the processor itself, see the [OTBN Technical Specification]({{< relref "hw/ip/otbn/doc" >}}).
In particular, this document assumes knowledge of the *Processor State* section from that guide.
The instruction set is split into *base* and *big number* subsets.
The base subset (described first) is similar to RISC-V's RV32I instruction set.
It also includes a hardware call stack and hardware loop instructions.
The big number subset is designed to operate on 256b WDRs.
It doesn't include any control flow instructions, and just supports load/store, logical and arithmetic operations.
<!-- Documentation for the instructions in the ISA. Generated from ../data/insns.yml. -->
# Base Instruction Subset
{{< otbn_isa base >}}
# Big Number Instruction Subset
{{< otbn_isa bignum >}}
# Pseudo-Code Functions for BN Instructions
The instruction description uses Python-based pseudocode.
Commonly used functions are defined once below.
<div class="bd-callout bd-callout-warning">
<h5>Note</h5>
This "pseudo-code" is intended to be Python 3, and contains known inconsistencies at the moment.
It will be further refined as we make progress in the implementation of a simulator using this syntax.
</div>
```python3
class Flag(Enum):
C: Bits[1]
M: Bits[1]
L: Bits[1]
Z: Bits[1]
class FlagGroup:
C: Bits[1]
M: Bits[1]
L: Bits[1]
Z: Bits[1]
def set(self, flag: Flag, value: Bits[1]):
assert flag in Flag
if flag == Flag.C:
self.C = value
elif flag == Flag.M:
self.M = value
elif flag == Flag.L:
self.L = value
elif flag == Flag.Z:
self.Z = value
def get(self, flag: Flag):
assert flag in Flag
if flag == Flag.C:
return self.C
elif flag == Flag.M:
return self.M
elif flag == Flag.L:
return self.L
elif flag == Flag.Z:
return self.Z
class ShiftType(Enum):
LSL = 0 # logical shift left
LSR = 1 # logical shift right
class HalfWord(Enum):
LOWER = 0 # lower or less significant half-word
UPPER = 1 # upper or more significant half-word
def DecodeShiftType(st: Bits(1)) -> ShiftType:
if st == 0:
return ShiftType.LSL
elif st == 1:
return ShiftType.LSR
else:
raise UndefinedException()
def DecodeFlagGroup(flag_group: Bits(1)) -> UInt:
if flag_group > 1:
raise UndefinedException()
return UInt(flag_group)
def DecodeFlag(flag: Bits(1)) -> Flag:
if flag == 0:
return ShiftType.C
elif flag == 1:
return ShiftType.M
elif flag == 2:
return ShiftType.L
elif flag == 3:
return ShiftType.Z
else:
raise UndefinedException()
def ShiftReg(reg, shift_type, shift_bytes) -> Bits(N):
if ShiftType == ShiftType.LSL:
return GPR[reg] << shift_bytes << 3
elif ShiftType == ShiftType.LSR:
return GPR[reg] >> shift_bytes >> 3
def AddWithCarry(a: Bits(WLEN), b: Bits(WLEN), carry_in: Bits(1)) -> (Bits(WLEN), FlagGroup):
result: Bits[WLEN+1] = a + b + carry_in
flags_out = FlagGroup()
flags_out.C = result[WLEN]
flags_out.L = result[0]
flags_out.M = result[WLEN-1]
flags_out.Z = (result[WLEN-1:0] == 0)
return (result[WLEN-1:0], flags_out)
def SubtractWithBorrow(a: Bits(WLEN), b: Bits(WLEN), borrow_in: Bits(1)) -> (Bits(WLEN), FlagGroup):
result: Bits[WLEN+1] = a - b - borrow_in
flags_out = FlagGroup()
flags_out.C = result[WLEN]
flags_out.L = result[0]
flags_out.M = result[WLEN-1]
flags_out.Z = (result[WLEN-1:0] == 0)
return (result[WLEN-1:0], flags_out)
def DecodeHalfWordSelect(hwsel: Bits(1)) -> HalfWord:
if hwsel == 0:
return HalfWord.LOWER
elif hwsel == 1:
return HalfWord.UPPER
else:
raise UndefinedException()
def GetHalfWord(reg: integer, hwsel: HalfWord) -> Bits(WLEN/2):
if hwsel == HalfWord.LOWER:
return GPR[reg][WLEN/2-1:0]
elif hwsel == HalfWord.UPPER:
return GPR[reg][WLEN-1:WLEN/2]
def LoadWlenWordFromMemory(byteaddr: integer) -> Bits(WLEN):
wordaddr = byteaddr >> 5
return DMEM[wordaddr]
def StoreWlenWordToMemory(byteaddr: integer, storedata: Bits(WLEN)):
wordaddr = byteaddr >> 5
DMEM[wordaddr] = storedata
```