RSM offers 30 general-purpose 64-bit integer registers and 30 64-bit floating-point registers. Instructions are 32 bits wide, fixed size. PC and jump- & branch destinations are expressed in #instructions rather than bytes.
Most instructions accept register number or immediate value as their last argument. See Instruction Encoding for more details.
Name | Inputs | Output | Semantics |
---|---|---|---|
copy | ABu | reg | RA = Bu -- aka "move" |
copyv | ABv | reg | RA = instr[...]; PC+=Bu |
load | ABCs | reg | RA = mem[RB + Cs : 8] |
load4u | ABCs | reg | RA = mem[RB + Cs : 4] -- zero-extend i32 to i64 |
load4s | ABCs | reg | RA = mem[RB + Cs : 4] -- sign-extend i32 to i64 |
load2u | ABCs | reg | RA = mem[RB + Cs : 2] -- zero-extend i16 to i64 |
load2s | ABCs | reg | RA = mem[RB + Cs : 2] -- sign-extend i16 to i64 |
load1u | ABCs | reg | RA = mem[RB + Cs : 1] -- zero-extend i8 to i64 |
load1s | ABCs | reg | RA = mem[RB + Cs : 1] -- sign-extend i8 to i64 |
store | ABCs | mem | mem[RB + Cs : 8] = RA |
store4 | ABCs | mem | mem[RB + Cs : 4] = RA -- wrap i64 to i32 |
store2 | ABCs | mem | mem[RB + Cs : 2] = RA -- wrap i64 to i16 |
store1 | ABCs | mem | mem[RB + Cs : 1] = RA -- wrap i64 to i8 |
add | ABCu | reg | RA = RB + Cu -- wrap on overflow |
sub | ABCu | reg | RA = RB - Cu -- wrap on overflow |
mul | ABCu | reg | RA = RB * Cu -- wrap on overflow |
adds | ABCs | reg | RA = RB + Cs -- panic on overflow |
subs | ABCs | reg | RA = RB - Cs -- panic on overflow |
muls | ABCs | reg | RA = RB * Cs -- panic on overflow |
div | ABCu | reg | RA = RB / Cu |
mod | ABCu | reg | RA = RB % Cu |
and | ABCu | reg | RA = RB & Cu |
or | ABCu | reg | RA = RB | Cu |
xor | ABCu | reg | RA = RB ^ Cu |
shl | ABCu | reg | RA = RB << Cu |
shrs | ABCu | reg | RA = RB >> Cu -- sign-replicating (arithmetic) |
shru | ABCu | reg | RA = RB >> Cu -- zero-replicating (logical) |
binv | ABu | reg | RA = ~Bu -- bitwise complement, invert bits |
not | ABu | reg | RA = !Bu -- boolean negation |
eq | ABCu | reg | RA = RB == Cu |
neq | ABCu | reg | RA = RB != Cu |
ltu | ABCu | reg | RA = RB < Cu |
lts | ABCs | reg | RA = RB < Cs |
lteu | ABCu | reg | RA = RB <= Cu |
ltes | ABCs | reg | RA = RB <= Cs |
gtu | ABCu | reg | RA = RB > Cu |
gts | ABCs | reg | RA = RB > Cs |
gteu | ABCu | reg | RA = RB >= Cu |
gtes | ABCs | reg | RA = RB >= Cs |
if | ABs | – | if RA!=0 PC += Bs |
ifz | ABs | – | if RA==0 PC += Bs |
call | Au | – | R0...R7 = push(PC); PC=Au |
jump | Au | – | PC = Au |
ret | _ | – | PC = pop() |
tspawn | Au | – | R0 = spawn_task(pc=Au, args=R0...R7) |
syscall | Au | – | R0...R7 = syscall(code=Au, args=R0...R18) |
write | ABCDs | reg | RA = write dstaddr=RB size=RC fd=Ds |
read | ABCDu | reg | RA = read srcaddr=RB size=RC fd=Du |
mcopy | ABCu | mem | mem[RA:Cu] = mem[RB:Cu] |
mcmp | ABCDu | reg | RA = mem[RB:Du] <> mem[RC:Du] |
stkmem | As | – | SP = maybe_split_or_join_stack(); SP += As |
Instructions are fixed-size, 32 bits wide, little endian.
PC and jump- & branch destinations are expressed in #instructions rather than bytes.
There is room for 256 operations and 32+32 (int+fp) registers (8 bit OP, 5 bit reg)
Most instructions accept reg or immediate (i
bit is set) as last argument.
┌───────────────┬─────────┬─────────┬─────────┬─┬───────────────┐
bit │3 3 2 2 2 2 2 2│2 2 2 2 1│1 1 1 1 1│1 1 1 1 │ │ │
│1 0 9 8 7 6 5 4│3 2 1 0 9│8 7 6 5 4│3 2 1 0 9│8│7 6 5 4 3 2 1 0│
├───────────────┼─────────┼─────────┼─────────┼─┼───────────────┤
ABCD │ D (8) │ C (5) │ B (5) │ A (5) │i│ OP (8) │
├───────────────┴─────────┼─────────┼─────────┼─┼───────────────┤
ABCw │ C (13) │ B (5) │ A (5) │i│ OP (8) │
├─────────────────────────┴─────────┼─────────┼─┼───────────────┤
ABw │ B (18) │ A (5) │i│ OP (8) │
├───────────────────────────────────┴─────────┼─┼───────────────┤
Aw │ A (23) │i│ OP (8) │
└─────────────────────────────────────────────┴─┴───────────────┘
Min Max Min Max
Au 0 8,388,607 As -4,194,304 4,194,303
Bu 0 262,143 Bs -131,072 131,071
Cu 0 8,191 Cs -4,096 4,095
Du 0 255 Ds -128 127
Encoding | Arguments |
---|---|
_ | (none) |
A | R(A) |
Au | R(A) or immediate unsigned value |
As | R(A) or immediate signed value |
ABv | R(A), with Bu immediate trailing u32 values |
AB | R(A), R(B) |
ABu | R(A), R(B) or immediate unsigned value |
ABs | R(A), R(B) or immediate signed value |
ABC | R(A), R(B), R(C) |
ABCu | R(A), R(B), R(C) or immediate unsigned value |
ABCs | R(A), R(B), R(C) or immediate signed value |
ABCD | R(A), R(B), R(C), R(D) |
ABCDu | R(A), R(B), R(C), R(D) or immediate unsigned value |
ABCDs | R(A), R(B), R(C), R(D) or immediate signed value |
Callee-owned (caller-saved, temporary) registers. Caller needs to save these before a call (if caller uses them.) Callee can freely use these registers.
R0…R7 1st…8th integer argument/return value
F0…F7 1st…8th floating-point argument/return value
R8…R18 General purpose
F8…F18 General purpose
Caller-owned (callee-saved, long-lived) registers. Caller does not need to save these registers. Callee using these must save and later restore their values before returning.
R19…R29 General purpose
F19…F29 General purpose
SP (R31) Stack pointer
CTX (R30) Context (like AAPCS platform reg and Go's G)
SP (R31) Stack pointer
- (F30) Reserved (unused)
FPSR (F31) Floating-point status