HoleyBytes ISA Specification
Bytecode format
- Image format is not specified, though ELF is recommended
- All numbers are encoded little-endian
- There is 256 registers, they are represented by a byte
- Immediate values are 8, 16, 32 or 64 bit
Instruction encoding
- Instruction operands are packed (no alignment)
- [opcode, operand 0, operand 1, …]
Instruction parameter types
R
: Register (8 bits)
- Relative program-counter offset immediates:
O
: 32 bit (Si32)
P
: 16 bit (Si16)
- Immediates:
B
: Byte, 8 bit (Xi8)
H
: Half-word, 16 bit (Xi16)
W
: Word, 32 bit (Xi32)
D
: Double-word, 64 bit (Xi64)
A
: Absolute address immediate, 64 bit (Ui64)
Types
- Sin: Signed integer of size n bits (Si8, Si16, Si32, Si64)
- Uin: Unsigned integer of size n bits (Ui8, Ui16, Ui32, Ui64)
- Xin: Sign-agnostic integer of size n bits (Xi8, Xi16, Xi32, Xi64)
- Fln: Floating point number of size n bits (Fl32, Fl64)
Behaviours
- Integer operations are always wrapping, including signed numbers
- Two's complement
- Floats as specified by IEEE 754
Relative addressing
Relative addresses are computed from address of the first byte
of offset in the code. Not from the beginning of current or following instruction.
Zero register
- Register 0
- Cannot be clobbered
- Load always yields 0
Rounding modes
Rounding mode |
Value |
To nearest, ties to even |
0b00 |
Towards 0 (truncate) |
0b01 |
Towards +∞ (up) |
0b10 |
Towards -∞ (down) |
0b11 |
Instructions
#n
: register in parameter n
$n
: for immediate in parameter n
#P ← V
: Set register P to value V
[x]
: Address x
XY
: X bytes from location Y
pc
: Program counter
<XYZ>
: Placeholder
Type(X)
: Cast
Program execution control
Opcode |
Mnemonic |
Action |
0x00 |
UN |
Throw unreachable code exception |
0x01 |
TX |
Terminate execution (eg. on end of program) |
0x02 |
NOP |
Do nothing |
Binary register-immediate ops
- Type
RR<IMM>
- Action:
#0 ← #1 <OP> #2
Addition (+
)
Opcode |
Mnemonic |
Type |
0x03 |
ADD8 |
Xi8 |
0x04 |
ADD16 |
Xi16 |
0x05 |
ADD32 |
Xi32 |
0x06 |
ADD64 |
Xi64 |
Subtraction (-
)
Opcode |
Mnemonic |
Type |
0x07 |
SUB8 |
Xi8 |
0x08 |
SUB16 |
Xi16 |
0x09 |
SUB32 |
Xi32 |
0x0A |
SUB64 |
Xi64 |
Multiplication (*
)
Opcode |
Mnemonic |
Type |
0x0B |
MUL8 |
Xi8 |
0x0C |
MUL16 |
Xi16 |
0x0D |
MUL32 |
Xi32 |
0x0E |
MUL64 |
Xi64 |
Bitwise ops (type: Xi64)
Opcode |
Mnemonic |
Operation |
0x0F |
AND |
Conjunction (&) |
0x10 |
OR |
Disjunction (|) |
0x11 |
XOR |
Non-equivalence (^) |
Unsigned left bitshift (<<
)
Opcode |
Mnemonic |
Type |
0x12 |
SLU8 |
Ui8 |
0x13 |
SLU16 |
Ui16 |
0x14 |
SLU32 |
Ui32 |
0x15 |
SLU64 |
Ui64 |
Unsigned right bitshift (>>
)
Opcode |
Mnemonic |
Type |
0x16 |
SRU8 |
Ui8 |
0x17 |
SRU16 |
Ui16 |
0x18 |
SRU32 |
Ui32 |
0x19 |
SRU64 |
Ui64 |
Signed right bitshift (>>
)
Opcode |
Mnemonic |
Type |
0x1A |
SRS8 |
Si8 |
0x1B |
SRS16 |
Si16 |
0x1C |
SRS32 |
Si32 |
0x1D |
SRS64 |
Si64 |
Comparsion
- Compares two numbers, saves result to register
- Operation:
#0 ← #1 <=> #2
Ordering |
Number |
< |
-1 |
= |
0 |
> |
1 |
Opcode |
Mnemonic |
Type |
0x1E |
CMPU |
Ui64 |
0x1F |
CMPS |
Si64 |
Merged divide-remainder
-
Type RRRR
-
Operation:
#0 ← #2 / #3
#1 ← #2 % #3
-
If dividing by zero:
Opcode |
Mnemonic |
Type |
0x20 |
DIRU8 |
Ui8 |
0x21 |
DIRU16 |
Ui16 |
0x22 |
DIRU32 |
Ui32 |
0x23 |
DIRU64 |
Ui64 |
0x24 |
DIRS8 |
Si8 |
0x25 |
DIRS16 |
Si16 |
0x26 |
DIRS32 |
Si32 |
0x27 |
DIRS64 |
Si64 |
Unary register operations (type: Xi64)
- Type:
RR
- Operation:
#0 ← <OP> #1
Opcode |
Mnemonic |
Operation |
0x28 |
NEG |
Bitwise complement (~ ) |
0x29 |
NOT |
Logical negation (! ) |
Sign extensions
Opcode |
Mnemonic |
Source type |
0x2A |
SXT8 |
Si8 |
0x2B |
SXT16 |
Si16 |
0x2C |
SXT32 |
Si32 |
Binary register-immediate operations
- Type:
RR<IMM>
- Operation:
#0 ← #1 <OP> $2
Addition (+
)
Opcode |
Mnemonic |
Type |
0x2D |
ADDI8 |
Xi8 |
0x2E |
ADDI16 |
Xi16 |
0x2F |
ADDI32 |
Xi32 |
0x30 |
ADDI64 |
Xi64 |
Multiplication (*
)
Opcode |
Mnemonic |
Type |
0x31 |
MULI8 |
Xi8 |
0x32 |
MULI16 |
Xi16 |
0x33 |
MULI32 |
Xi32 |
0x34 |
MULI64 |
Xi64 |
Bitwise ops (type: Xi64)
Opcode |
Mnemonic |
Operation |
0x35 |
ANDI |
Conjunction (&) |
0x36 |
ORI |
Disjunction (|) |
0x37 |
XORI |
Non-equivalence (^) |
Unsigned left bitshift (<<
)
Opcode |
Mnemonic |
Type |
0x38 |
SLUI8 |
Ui8 |
0x39 |
SLUI16 |
Ui16 |
0x3A |
SLUI32 |
Ui32 |
0x3B |
SLUI64 |
Ui64 |
Unsigned right bitshift (>>
)
Opcode |
Mnemonic |
Type |
0x3C |
SRUI8 |
Ui8 |
0x3D |
SRUI16 |
Ui16 |
0x3E |
SRUI32 |
Ui32 |
0x3F |
SRUI64 |
Ui64 |
Signed right bitshift (>>
)
Opcode |
Mnemonic |
Type |
0x40 |
SRSI8 |
Si8 |
0x41 |
SRSI16 |
Si16 |
0x42 |
SRSI32 |
Si32 |
0x43 |
SRSI64 |
Si64 |
Comparsion
- Compares two numbers, saves result to register
- Operation:
#0 ← #1 <=> $2
- Comparsion table same for register-register one
Opcode |
Mnemonic |
Type |
0x44 |
CMPUI |
Ui64 |
0x45 |
CMPSI |
Si64 |
Register copies
Opcode |
Mnemonic |
Operation |
0x46 |
CP |
Copy register value (#0 ← #1 ) |
0x47 |
SWA |
Swap register values (#0 ⇆ #1 ) |
Load immediate
- Load immediate value from code to register
- Type:
R<IMM>
- Operation:
#0 ← $1
Opcode |
Mnemonic |
Type |
0x48 |
LI8 |
Xi8 |
0x49 |
LI16 |
Xi16 |
0x4A |
Li32 |
Xi32 |
0x4B |
Li64 |
Xi64 |
Load relative address
- Compute value from program counter, register value and offset
- Type:
RRO
- Operation:
#0 ← pc + #1 + $2
Memory access operations
- Immediate
$3
specifies size
- If size is greater than register size,
it overflows to adjecent register
(eg. copying 16 bytes to register
r1
copies first 8 bytes to it
and the remaining to r2
)
Absolute addressing
- Type:
RRAH
- Computes address from base register and absolute offset
Opcode |
Mnemonic |
Operation |
0x4D |
LD |
#0 ← $3[#1 + $2] |
0x4E |
ST |
$3[#1 + $2] ← #0 |
Relative addressing
- Type:
RROH
- Computes address from register and offset from program counter
Opcode |
Mnemonic |
Operation |
0x4F |
LDR |
#0 ← $3[pc + #1 + $2] |
0x50 |
STR |
$3[pc + #1 + $2] ← #0 |
Block memory copy
- Type:
RRH
- Copies block of
$3
bytes from memory location on address on #0
to #1
Opcode |
Mnemonic |
Operation |
0x51 |
BMC |
$3[#1] ← $3[x0] |
Block register copy
- Type:
RRB
- Copy block of
$3
registers starting with #0
to #1
- Copying over the 256 registers causes an exception
Opcode |
Mnemonic |
Operation |
0x52 |
BRC |
$3#1 ← $3#0 |
Relative jump
Opcode |
Mnemonic |
Operation |
0x53 |
JMP |
pc ← pc + $0 |
Linking jump
- Operation:
- Save address of following instruction to
#0
#0 ← pc+<instruction size>
- Jump to specified address
Opcode |
Mnemonic |
Instruction type |
Address |
0x54 |
JAL |
RRO (size = 6 B) |
Relative, pc + #1 + $2 |
0x55 |
JALA |
RRA (size = 10 B) |
Absolute, #1 + $2 |
Conditional jump
- Perform comparsion, if operation met, jump to relative address
- Type:
RRP
- Operation:
if #0 <CMP> #1 { pc ← pc + $2 }
Opcode |
Mnemonic |
Condition |
Type |
0x56 |
JEQ |
Equals (= ) |
Xi64 |
0x57 |
JNE |
Not-equals (≠ ) |
Xi64 |
0x58 |
JLTU |
Less-than (< ) |
Ui64 |
0x59 |
JGTU |
Greater-than (> ) |
Ui64 |
0x5A |
JLTS |
Less-than (< ) |
Si64 |
0x5B |
JGTS |
Greater-than (> ) |
Si64 |
Environment traps
- Traps to the environment
- Type:
N
Opcode |
Mnemonic |
Trap type |
0x5C |
ECA |
Environment call |
0x5D |
EBP |
Breakpoint |
Floating point binary operations
- Type:
RRR
- Operation:
#0 ← #1 <OP> #2
Opcode |
Mnemonic |
Operation |
Type |
0x5E |
FADD32 |
Addition (+ ) |
Fl32 |
0x5F |
FADD64 |
Addition (+ ) |
Fl64 |
0x60 |
FSUB32 |
Subtraction (- ) |
Fl32 |
0x61 |
FSUB64 |
Subtraction (- ) |
Fl64 |
0x62 |
FMUL32 |
Multiplication (* ) |
Fl32 |
0x63 |
FMUL64 |
Multiplication (* ) |
Fl64 |
0x64 |
FDIV32 |
Division (/ ) |
Fl32 |
0x65 |
FDIV64 |
Division (/ ) |
Fl64 |
Fused multiply-add
- Type:
RRRR
- Operation:
#0 ← (#1 * #2) + #3
Opcode |
Mnemonic |
Type |
0x66 |
FMA32 |
Fl32 |
0x67 |
FMA64 |
Fl64 |
Comparsions
- Type:
RRR
- Operation:
#0 ← #1 <=> #2
- Comparsion table same as for
CMPx
/CMPxI
- NaN is less-than/greater-than depends on variant
Opcode |
Mnemonic |
Type |
NaN is |
0x6A |
FCMPLT32 |
Fl32 |
< |
0x6B |
FCMPLT64 |
Fl64 |
< |
0x6C |
FCMPGT32 |
Fl32 |
> |
0x6D |
FCMPGT64 |
Fl64 |
> |
Int to float
- Type:
RR
- Converts from
Si64
- Operation:
#0 ← Fl<SIZE>(#1)
Opcode |
Mnemonic |
Type |
0x6E |
ITF32 |
Fl32 |
0x6F |
ITF64 |
Fl64 |
Float to int
- Type:
RRB
- Operation:
#0 ← Si64(#1)
- Immediate
$2
specifies rounding mode
Opcode |
Mnemonic |
Type |
0x70 |
FTI32 |
Fl32 |
0x71 |
FTI64 |
Fl64 |
Fl32 to Fl64
- Type:
RR
- Operation:
#0 ← Fl64(#1)
Opcode |
Mnemonic |
0x72 |
FC32T64 |
Fl64 to Fl32
- Type:
RRB
- Operation:
#0 ← Fl32(#1)
- Immediate
$2
specified rounding mode
Opcode |
Mnemonic |
0x73 |
FC64T32 |
16-bit relative address instruction variants
Opcode |
Mnemonic |
Type |
Variant of |
0x74 |
LRA16 |
RRP |
LRA |
0x75 |
LDR16 |
RRPH |
LDR |
0x76 |
STR16 |
RRPH |
STR |
0x77 |
JMP16 |
P |
JMP |