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.
{{< otbn_isa base >}}
{{< otbn_isa bignum >}}
The instruction description uses Python-based pseudocode. Commonly used functions are defined once below.
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.
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