Copyright Information
Skyarch Instruction Set
Gen Design
Word Size: 32 bit
Memory Load/Store Order: Little Endian
Instruction Size/Alignment: 4 bytes
Variable Sized Instructions: No
Common Flags/Condition Code Driven
Instruction format
8-bit opcode in lowest byte, 24-bit payload in upper three bytes.
Bit order is notated as MSB-first, e.g. “31 down to 0”. In memory, data and instructions should be stored in little endian, so the instruction will be in the first/lowest address, followed by the three payload bytes.
Registers
Register Maps
There are 8 maps of registers:
- Map 0: General Purpose
- Map 1: System Configuration
- Map 2: I/O Transfer Registers
- Map 3: Information
- Map 4: Coprocessor Control
- Maps 8-15: Co-processor Registers.
There are 32 registers of each type. Except for Map 0, not all registers may be defined.
Map 0: General Purpose
Assembly syntax: rn.
All Registers of the Map are defined. Certain Registers have special meaning:
r0is the zero-register. It reads as zero, and writes are ignored.
Map 1: Interrupt Support
Assembly syntax: intn or alias.
Refer to the following table of defined registers. Some registers define a specific format
| Regno. | Aliases | Description |
|---|---|---|
| 0 | intctl | Interrupt Status Register |
| 1 | intret1 | Return for Priority 1 Interrupts |
| 2 | intret2 | Return for Priority 2 Interrupts |
| 3 | intret3 | Return for Priority 3 Interrupts |
| 4 | ints0 | Scratch Register |
| 5 | ints1 | Scratch Register |
| 6 | ints2 | Scratch Register |
| 7 | ints3 | Scratch Register |
| 8 | intd0 | Misc Config Register |
| 9 | intd1 | Misc Config Register |
| 10 | intd2 | Misc Config Register |
| 11 | intd3 | Misc Config Register |
| 31 | inttab | Interrupt Table Pointer |
Reading or Writing an undefined register causes EX[2]. Writing an invalid value to a defined register causes EX[4]
Interrupt Control (Map 1, Register 0)
+31-----------------------------0+
|r00000000000000000000000000000mm|
+--------------------------------+
(All bits indicated as 0 must be written with 0)
| Bits | Name | Description |
|---|---|---|
r | Abort Triggered | Set to 1 when an Abort (Ex[0]) occurs. |
m | Priority Mask | Interrupts with priority value > m are blocked |
Both fields are set to 0 on startup.
Interrupt Priority
Interrupt Priority is used to ensure that overlapping Interrupts do not interfere. There are 4 Priority levels, numbered in descending order of priority (0 is the highest priority, 3 is the lowest priority)
- Priority 0: Abort (Ex[0])
- Priority 1: Synchronous Exceptions (Ex[1], Ex[2], Ex[3], Ex[4])
- Priority 2: Asynchronous High Priority Event (Ex[7], EX[8-15])
- Priority 3: IRQs
An interrupt/trap is blocked when the priority level is greater than m. The behaviour depends on the kind of exception:
- Synchronous Exceptions (other than Abort) Reset the processor if
r = 1, else they setr = 1and raiseEx[0] - Asynchronous Events are discarded
- IRQs are buffered (up to an implementation-specific capacity until an
intretoccurs that setsmto be3) or are discarded.
Interrupt Return Registers
Each priority of interrupt (other than priority 0) has a distinct return register, labeled intretn where n is the priority value, which corresponds to Register n in map 1. Aborts are not recoverable, so no return register is provided.
+31-----------------------------0+
|aaaaaaaaaaaaaaaaaaaaaaaaaaaaaamm|
+--------------------------------+
| Bits | Name | Description |
|---|---|---|
a | Address | Contains the high 30 bits of the return address |
m | Priority Mask | Stores the priority mask before the interrupt |
Interrupt Scratch/Config Registers
Registers 4 through 11 in Map 1 are unused, freely writable registers, labeled intsn for registers 4+n and intdn for registers 8+n.
The register intsn is intended for use as a scratch register for interrupts with priority n (used during the interrupt procedure) and intdn i intended for use as a data/configuration register for such interrupts (written by the program and read during each interrupt invocation).
Interrupt/Exception Table (Map 1, Register 31)
+31-----------------------------0+
|aaaaaaaaaaaaaaaaaaaaaaaaaaaaa000|
+--------------------------------+
(All bits indicated as 0 must be written with 0)
Bits a contain the 29 most significant bits of an 8-byte aligned address which points to the interrupt table. 512 bytes starting from this address refer to 64 8-byte entries of the interrupt table, which use the following format, in LSB-first order using little-endian byte encoding:
+31-----------------------------0+
|tttttttttttttttttttttttttttttt0p|
+63----------------------------32+
|00000000000000000000000000000000|
+--------------------------------+
The t bits are the 30 most significant bits of the address to transfer control to when the specified interrupt occurs.
The p bit must be set for all interrupt vectors that are present and valid to execute. If the CPU tries to execute a not-present interrupt vector, EX[4] is raised.
All bits indicated as 0 must be 0 when the vector is read from memory, or EX[4] is raised.
Interrupts
The first 32 interrupt entries are reserved for hardware exceptions, these interrupts are allocated as follows (and the nth entry in this list is designated elsewise as EX[n]):
- Entry
0: Exception Handling Fault - an exception is raised when thetflag is set. - Entry
1: Bus Fault - accessing memory in a particular manner causes an error, or attempts to access memory that doesn’t exist. - Entry
2: Invalid Instruction - An instruction that is executed is an unknown opcode, reserved, malformed, or invalid - Entry
3: Unaligned Branch Target - an indirect branch is unaligned. - Entry
4: Consistency - An invalid system control structure was loaded from memory, or an invalid value was written to a system register. - Entry
5: Debug Trap - Allows software-level debugging via the BREAKP instruction. - Entry
7: PIRQ - May be raised in response to a priority signal external to the processor that requires immediate resolution. This is handled like an IRQ, but uses priority 2 instead of priority 3. - Entries
8-15: Co-processor UnitnError - The corresponding Coprocessor unitnsignals an error after aCPIninstruction (nis Exception number - 4). - Entries
6and16-31are reserved.
The remaining entries (32-63), may be allocated as IRQ vectors.
Interrupt Checking
Interrupts are performed as follows:
subrountine TryInterruptProcessor(iv: u8, pri: u2):
let intctl: u32 = ReadRegister(1, 0);
if (intctl & 3) < pri:
return;
let addr: u32 = ReadRegister(1, 31) + (iv << 3);
let retreg = IP | intctl & 3;
if pri > 0:
WriteRegister(1, pri, retreg);
let iaddr = ReadMemory(addr);
let rest = ReadMemory(addr + 4);
CheckAndRaise(EX[2]);
if (iaddr & 1) == 0:
return;
if rest != 0 or (iaddr & 2) != 0:
Raise(EX[4]);
let addr = iaddr & ~3;
IP = addr;
IL.valid = false;
return;
subroutine InterruptProcessor(iv: u6, pri: u2):
let intctl: u32 = ReadRegister(1, 0);
if (intctl & 3) < pri:
if pri == 1:
if (intctl & 0x80000000) != 0:
ResetProcessor();
else:
WriteRegister(1, 0, 0x80000000);
InterruptProcessor(0, 0);
return;
else:
return;
let addr: u32 = ReadRegister(1, 31) + (iv << 3);
let retreg = IP | intctl & 3;
if pri > 0:
WriteRegister(1, pri, retreg);
let iaddr = ReadMemory(addr);
let rest = ReadMemory(addr + 4);
CheckAndRaise(EX[2]);
if rest != 0 or (iaddr & 2) != 0:
Raise(EX[4]);
if (iaddr & 1) == 0:
Raise(EX[4]);
let addr = iaddr & ~3;
IP = addr;
IL.valid = false;
return;
subroutine Raise(EX[n]: Except):
CancelCurrentInstruction();
InterruptProcessor(n, 1);
return;
subroutine CheckAndRaise(EX[n]: Except):
if AsynchronousExceptionPending(EX[n]):
Raise(EX[n]);
ClearPendingException(EX[n]);
return;
subroutine CheckAsync():
if AsynchronousExceptionPending(EX[7]):
InterruptProcessor(7, 2);
ClearPendingException(EX[7]);
let cpe = ReadRegister(4, 30);
for n in 0..8:
if (cpe & (1 << n)) != 0 and AsynchronousExceptionPending(EX[8+n]):
InterruptProcessor(8+n, 2);
ClearPendingException(EX[8+n]);
let irq, hasirq = PullPendingIrq();
if hasirq:
InterruptProcessor(32+irq, 3);
The processor behaves as if CheckAsync() is called after each instruction finishes writing to all memory and all registers.
Map 2: I/O Transfer Registers
Assembly Syntax: ion.
Map 2 defines a sequence of input and output shift registers for transfering data to external peripherals.
All Registers are defined and have no implied meaning.
Map 3: Information Registers
The Information Registers Map is a Read Only Map that contains information about the CPU. All Registers Presently Read 0. Writes are illegal and raise EX[2]
Map 4: Coprocessor Control
Each Co-processor has a 32-bit control word, which is defined by the Coprocessor.
Assembly Syntax: cpn or alias.
Register N (N < 8) in Map 4 is defined if Co-processor N is present and enabled. Additionally, Register 30 is the coprocessor enable (cpe) register, and Register 31 is the coprocessor present (cpp) register.
Reads and writes to an undefined register or a register corresponding to a not-present or disabled coprocessor results in EX[2]. Writing to cpp results in EX[2].
Where a MOV instruction writes to Register N (N < 8) in this map, the following guarantees are made about the ordering of surrounding instructions:
- The
MOVinstruction will not begin executing until any Coprocessor Invocation instruction that references coprocessor N and occurs before it have been fully written-back, - Any Coprocessor Invocation instruction that references coprocessor N and occurs after it will not begin executing until the
MOVinstruction has been fully written-back
A coprocessor may enforce arbitrary validity requirements on writes to its corresponding control register. Violations of these constraints generates a coprocessor error.
Map 4, Register 30: Coprocessor Enable
The Coprocessor Enable register allows the system software to control what coprocessors are operating and usable from the CPU.
+31-----------------------------0+
|000000000000000000000000EEEEEEEE|
+--------------------------------+
The bits marked E may be set by the program when the corresponding bit of Register 31 is set.
Setting the nth bit to 1 enables the coprocessor and setting it to 0 disables it.
A bit may only be written with 1 if the corresponding bit in cpp is 1. If a write violates this rule, EX[4] is raised. Bits marked as 0 can never be written with a 1.
Where a MOV instruction writes to this register the following guarantees are made about the ordering of surrounding instructions:
- The
MOVinstruction will not begin executing until all off the following instructions that occur before it have been fully written-back:- Any
MOVinstruction that references a register in this map, other than an access to this register,cpp, or any undefined register, - Any
MOVinstruction that reads from a register in Maps 8-16 that does not refer to a not-present, - Any coprocessor invocation instruction that does not refer to a not-present coprocessor,
- Any
- Any of the following instructions that occur after the
MOVinstruction will not begin executing until theMOVinstruction has been fully written-back:- Any
MOVinstruction that references a register in this map, other than this register,cpp, or any undefined register, - Any
MOVinstruction that accesses a register in Maps 8-16 that does not refer to a not-present coprocessor, - Any coprocessor invocation instruction that does not refer to a not-present coprocessor.
- Any
Map 4, Register 31: Coprocessor Present
The Coprocessor Enable register allows the system software to determine what coprocessors are connected to the CPU. This register is read-only and cannot be written from the CPU.
+31-----------------------------0+
|000000000000000000000000PPPPPPPP|
+--------------------------------+
The nth bit is set to 1 if the nth coprocessor is present. Note that it is not guaranteed that the set of enabled coprocessors is contiguous or that the set of enabled coprocessors begins at 0.
Map 8-15: Co-processor Maps
Co-processors connected to the system may expose up to 32 registers each. Registers in map N are only defined if the coprocessor co-processor (Co-processor N-8) is enabled.
Writing to a register in map 8+N with cpe[bit N] clear raises Ex[2]. Violating a validity constraint enforced by the coprocessor may raise an asynchronous coprocessor error.
Reset State
On Reset (either hardware initiated, or initiated by an exception raised in an abort status), the CPU is initialized to the following state:
- It is executing (Status = 0)
IPis initialized to 0xFF00.cpeis set to0.ictlis set tom=0, a=0r0is0.
All other registers, including flags, have undefined values. An undefined value means that any independent read from the register may return an unpredictable result. Undefined values are cleared when the register is written to, even if the register is assigned to itself.
Instructions
Undefined Instructions
| Mnemonic | Opcode | Payload |
|---|---|---|
7------0 | 31---------------------8 | |
| UND | 00000000 | - |
| UND | 11111111 | - |
(The Payload bits are ignored by both instructions)
EX[2]: Unconditionally
Unconditionally raises Invalid Instruction errors
instruction UND():
Raise(EX[2])
Pause
| Mnemonic | Opcode | Payload |
|---|---|---|
7------0 | 31---------------------8 | |
| PAUSE | 00000001 | 000000000000000000kkkkkk |
k: Total pause time
Ex[2]: If any reserved (fixed) bit is set to an invalid value.
Delays execution for k clock cycles, 0-63,
Any instruction that follows a PAUSE instruction will not begin executing until the k cycles have elapsed since the PAUSE instruction completed execution.
instruction PAUSE(k: u6):
SuspendForClockTicks(k)
Move
| Mnemonic | Opcode | Payload |
|---|---|---|
7------0 | 31---------------------8 | |
| MOV | 00000010 | 00mmmmrl0sssss0ccccddddd |
m: Mapr: Directionl: Latency Controls: Source Registerc: Condition Code (See Jump)d: Destination Register
Ex[2]: If any reserved (fixed) bit is set to an invalid valueEx[2]: If an undefined register map is referenced by the instructionEx[2]: If an undefined register in a map other than map 0 is referenced by the instructionEx[2]: If a read-only register in a map other than map 0 is referenced by the instructionEx[5]: If an invalid value is written to a register outside of map 0
Copies data between general purpose registers and to/from general purpose registers into other registers.
instruction MOV(d: u5, s: u5, m: u2, dir: u1, c: ConditionCode, l: bool):
if m!=0:
if dir==0:
ValidateRegisterReadable(m,d);
else:
ValidateRegisterWritable(m,d);
if CheckCondition(flags, c):
let ms, md: u2;
if dir==1:
md = m;
ms = 0;
else:
ms = m;
md = 0;
if md==3:
Raise(EX[2]);
let val: u32;
val = ReadRegister(ms, s);
if md == 1 or m > 3:
ValidateConfigurationRegisterValue(d, val);
WriteRegister(md, d, val);
LD/ST
| Mnemonic | Opcode | Payload |
|---|---|---|
7------0 | 31---------------------8 | |
ST | 00000011 | rrmm00000000wwsssssddddd |
LD | 00000100 | rrmm00000000wwsssssddddd |
LDI | 00000101 | iiiiiiiiiiiiiiii00xddddd |
LRA | 00000110 | oooooooooooooooo00xddddd |
r: Orderingm: Update modew: Widths: Source Registerx: Set sign bits (Higher half)i: Immediate Valueo: Offsetd: Destination Register
Ex[2]: If any reserved (fixed) bit is set to an invalid valueST:Ex[2]: Ifdis0.LD:Ex[2]: Ifsis0.ST,LD:Ex[2]: Ifw=3.ST:Ex[2]: Ifr = 1LD:Ex[2]: Ifr = 2ST:Ex[1]: Ifdis not aligned to2 ^ wbytesLD:Ex[1]: Ifdis not aligned to2 ^ wbytes.ST,LD:Ex[1]: If accessing memory causes a bus error
ST: Stores1 << wbytes fromdto[s]LD: Loads1 << wbytes from[s]intodLDI: Loads an immediatei(sign or zero extened) into the first (h=0) 16 bits ofdLRA: Loads the addressIP + o(ois a signed immediate ifxis true, and an unsigned immediate otherwise) intod.IPis taken from the beginning of the next instruction
Every ST, STIC, or STICW instruction that modifies a given memory region will become visible on every core of the system in the same order.
enum Ordering:
Relaxed = 0,
Acquire = 1,
Release = 2,
SeqCst = 3,
enum UpdateMode:
None = 0,
PostInc = 1,
/* Illegal = 2 */,
PreDec = 3,
instruction ST(s: u5, d: u5, w: u2 r: Ordering, m: UpdateMode):
if r==1:
Raise(EX[2])
if m == 2:
Raise(EX[2])
if d==0:
Raise(EX[2]);
let val = ReadRegister(0,s);
let addr: u32;
let width = 2 << w;
if (m&2)== 2:
addr = ReadRegister(0, d) - width;
else:
addr = ReadRegister(0, d);
if width == 8:
Raise(EX[2]);
if addr & (width - 1):
Raise(EX[1])
SynchronizeMemoryAccordingToStore(r, addr);
WriteAlignedMemoryTruncate(addr, val, width);
CheckAndRaisePending(EX[1]);
let new_addr: u32;
if m == 1:
new_addr = addr + width;
if m != 0:
WriteRegister(0, d, new_addr);
instruction LD(s: u5, d: u5,w: u2, p: u2):
if r==2:
Raise(EX[2])
if s==0:
Raise(EX[2])
let width = 2 << w;
if width == 8:
Raise(EX[2]);
let addr: u32;
if (m&2)== 2:
addr = ReadRegister(0, s) - width;
else:
addr = ReadRegister(0, s);
if addr & (width - 1):
Raise(Ex[1])
let val = ReadAlignedMemoryZeroExtend(addr, w+1);
CheckAndRaisePending(EX[1]);
SynchronizeMemoryAccordingToLoad(r, addr);
WriteRegister(0,d,val);
let new_addr: u32;
if m == 1:
new_addr = addr + width;
if m != 0:
WriteRegister(0, s, new_addr);
instruction LRA(d: u5, x: bool, i: u16):
let val = SignExtendOrZeroExtend(i, x) + IP;
WriteRegister(0,d,val);
Immediate Arithmetic
| Mnemonic | Opcode | Payload |
|---|---|---|
7------0 | 31---------------------8 | |
ADDI | 00001000 | iiiiiiiiiiiiiiiihfxddddd |
i: Immediateh: High halff: Enable Flags Modificationx: Set sign bits (upper bits)d: Destination Register
Ex[2]: Ifhandxare both set.
Sets P, N, and Z according to the result. Sets V and C according to the computation (signed overflow and carry)
Adds a 16-bit zero or sign-extended immediate to d.
instruction ADDI(d: u5, x: bool, f: bool, h: bool, i: u16):
let imm: u32;
if h and x:
Raise(Ex[2]);
if h:
imm = ZeroExtend(i, 32) << 16;
else if x:
imm = SignExtend(i, 32);
else:
imm = ZeroExtend(i, 32);
let r = ReadRegister(0,d);
let result, flags_val = r + imm;
WriteRegister(0, d, result);
if f:
flags = flags_val;
ALU Instructions
| Mnemonic | Opcode | Payload |
|---|---|---|
7------0 | 31---------------------8 | |
ADD | 00001001 | c0psssssfbbbbbaaaaaddddd |
SUB | 00001010 | c0psssssfbbbbbaaaaaddddd |
AND | 00001011 | jipsssssfbbbbbaaaaaddddd |
OR | 00001100 | jipsssssfbbbbbaaaaaddddd |
XOR | 00001101 | jipsssssfbbbbbaaaaaddddd |
c: Carry inj: Invert op 2i: Invert op 1p: Shift Polaritys: Shift Quantityf: Enable Flags Modificationb: Source Register 2a: Source Register 1d: Destination Register
Ex[2]: If any reserved (fixed) bit is set to an invalid value.
ADD/SUB: SetsP,N, andZaccording to the result. SetsVandCaccording to the computation (signed overflow and carry)AND/OR/XOR: SetsP,N, andZaccording to the result.VandCare set to unspecified values.
Computes the ALU corresponding ALU operation between the values in GPRs b and a, writing the result to GPR d. The operand corresponding to p is first shifted left by s (p=1 shifts a, p=0 shifts b)
ADD: The result isa + b. Ifcis set, the carry flag is also added in.SUB: The result isa - b. Ifcis set, the carry flag is borrowed by the subtraction.AND: The result is(i)a & (j)b,ais inverted before being shifted ifiis set, andbis inverted before being shifted ifjis set.OR: The result is(i)a | (j)b,ais inverted before being shifted ifiis set, andbis inverted before being shifted ifjis set.XOR: The result is(i)a ^ (j)b,ais inverted before being shifted ifiis set, andbis inverted before being shifted ifjis set.
instruction {ADD, SUB}(a: u5, b: u5, d: u5, f: bool, s: u5, p: bool, c: bool):
let src1, src2: u32;
if p:
src1 = ReadRegister(0, a) << s;
src2 = ReadRegister(0,b);
else:
src1 = ReadRegister(0, a);
src2 = ReadRegister(0,b) << s;
let dest: u32;
let flags_val, flags_mask: u4;
switch (instruction):
case ADD:
dest, flags_val = src1 + src2 + (flags.c & c);
flags_mask = 0xF;
case SUB:
dest, flags_val = src1 - src2 + (~flags.c & c);
flags_mask = 0xF;
if f:
flags = flags_val & flags_mask | nondeterministic() & ~flags_mask;
instruction {AND, OR, XOR}(a: u5, b: u5, d: u5, f: bool, s: u5, p: bool, i: bool, j: bool):
let src1, src2: u32;
if p:
src1 = ReadRegister(0, a) << s;
src2 = ReadRegister(0,b);
else:
src1 = ReadRegister(0, a);
src2 = ReadRegister(0,b) << s;
let val1, val2: u32;
if i:
val1 = ~src1;
else:
val1 = src1;
if j:
val2 = ~src2;
else:
val2 = src2;
let dest: u32;
let flags_val, flags_mask: u5;
switch (instruction):
case AND:
dest = val1 & val2;
flags_val = LogicCondition(dest);
flags_mask = 0x3;
case OR:
dest = val1 | val2;
flags_val = LogicCondition(dest);
flags_mask = 0x3;
case XOR:
dest = val1 ^ val2;
flags_val = LogicCondition(dest);
flags_mask = 0x3;
if f:
flags = flags_val & flags_mask | nondeterministic() & ~flags_mask;
Funnel Shifts
| Mnemonic | Opcode | Payload |
|---|---|---|
7------0 | 31---------------------8 | |
FSL | 00001110 | rrrrrw0xfqqqqqvvvvvddddd |
FSR | 00001111 | rrrrrw0xfqqqqqvvvvvddddd |
r: Shift Remainder (Input value)w: Wrap Quantityx: Invert by Signf: Enable Flags Modificationq: Shift Quantityv: Input Valued: Destination Register
Ex[2]: If any reserved (fixed) bit is set to an invalid value.
Sets P, Z, and N according to the result. Sets C if any 1 bit was shifted out of v. Sets V if q is greater than 32 (regardless of w)
Shifts v by q and places the value in d, filling the shifted in bits with bits taken from the corresponding high bits of r. q wraps at 32 if w is set. If w is clear, excess shift quanities shift r in fully first.
FSL:vis shifted left byqFSR:vis shifted right byq
instruction FSL(d: u5, v: u5, q: u5, f: bool, x: bool, w: bool, r: u5):
let val = ReadRegister(0, v);
let quantity = ReadRegister(0, q);
let remainder = ReadRegister(0, r);
if x & SignBitOf(val):
remainder = ~remainder;
let overflow: u5;
if quantity >= 32:
overflow = 2;
else:
overflow = 0;
if w:
quantity = quantity & 31;
let result, out = ShiftInLeft(val, remainder, quantity);
WriteRegister(0, d);
let carry: u5;
if out != 0:
carry = 1;
else
carry = 0;
if quantity
let flags_val = LogicCondition(result) | carry | overflow;
if f:
flags = flags_val;
instruction FSR(d: u5, v: u5, q: u5, c: bool, x: bool, w: bool, r: u5):
let val = ReadRegister(0, v);
let quantity = ReadRegister(0, q);
let remainder = ReadRegister(0, r);
if x & SignBitOf(val):
remainder = ~remainder;
let overflow: u5;
if quantity >= 32:
overflow = 2;
else:
overflow = 0;
if w:
quantity = quantity & 31;
let result, out = ShiftInRight(val, remainder, quantity);
WriteRegister(0, d);
let carry: u5;
if out != 0:
carry = 1;
else
carry = 0;
if quantity
let flags_val = LogicCondition(result) | carry | overflow;
if f:
flags = flags_val;
Branches
| Mnemonic | Opcode | Payload |
|---|---|---|
7------0 | 31---------------------8 | |
JMP | 00010000 | ooooooooooooooocccclllll |
JMPR | 00010001 | 000000000rrrrr0cccclllll |
IRET | 00010010 | 000000000000pp0000000000 |
o: Destination Offset (Bits 2..17)r: Destination Registerc: Condition Codel: Link Registerp: Target Interrupt Priority
Ex[2]: If any reserved (fixed) bit is set to an invalid valueIRET:Ex[2]: ifp = 0JMPR:Ex[2]: Ifr = 0JMPR:Ex[3]: If the destination address is not 4 byte aligned (even if the branch is not taken)Ex[1]: If fetching the next instruction at the destination causes a bus error, if the branch is taken
Jumps to the destination, if the condition is satisfied, saving the return address in l if taken:
JMP: The offset isIP + o * 4whereois a signed offset.IPis the same as the return address and points to the beginning of the next instructionJMPR: The offset is read fromrIRET: The offset it read from registerp(p!=0) in Map 1.intctl.mis also loaded fromp.mandintctl.ais cleared
instruction JMP(c: ConditionCode, l: u5, o: u15):
let disp = SignExtend(o) << 2;
let curr_ip = IP;
if CheckCondition(flags, c):
if l != 0:
WriteRegister(0,l, curr_ip);
let dest_ip = curr_ip + disp;
if not CheckBranchTarget(dest_ip):
Raise(Ex[1])
IP = dest_ip;
instruction JMPR(c: ConditionCode, l: u5, r: u5):
if r == 0:
Raise(Ex[2]);
let addr = ReadRegister(0,r);
if addr & 3 != 0:
Raise(EX[3]);
let curr_ip = IP;
if CheckCondition(flags, c):
if l != 0:
WriteRegister(0,l, curr_ip);
if not CheckBranchTarget(addr):
Raise(Ex[1])
IP = addr;
instruction IRET(p: u2):
if p == 0:
Raise(Ex[2]);
let reg = p as u5;
let val = ReadRegister(1, reg);
let addr = val & !3;
if not CheckBranchTarget(dest_ip):
Raise(Ex[1])
IP = addr;
IL.valid = false;
WriteRegister(1, 0, val & 3);
Condition Code
JMP, JMPR, and MOV all use a 4-bit condition code to encode the branch condition. This includes conditions for “Always” and “Never”.
enum ConditionCode is u4:
Never = 0,
Carry = 1,
Zero = 2,
Overflow = 3,
CarryOrEqual = 4,
SignedLess = 5,
SignedLessOrEq = 6,
Negative = 7,
Positive = 8,
SignedGreater = 9,
SignedGreaterOrEq = 10,
Above = 11,
NotOverflow = 12,
NotZero = 13,
NotCarry = 14,
Always = 15
function CheckCondition(flags: u32, cc: ConditionCode) is bool:
switch (cc):
case Never:
return false;
case Carry:
return (flags & c) != 0;
case Zero:
return (flags & z) != 0;
case Overflow:
return (flags & v) != 0;
case CarryOrEqual:
return (flags & c|z) != 0;
case SignedLess:
return (((flags & v) != 0) == ((flags & n) != 0)) and (flags & z) == 0;
case SignedLessOrEq:
return (((flags & v) != 0) == ((flags & n) != 0)) or (flags & z) != 0;
case Negative:
return (flags & n) != 0;
case Positive:
return (flags & n) == 0;
case SignedGreater:
return not ((((flags & v) != 0) == ((flags & n) != 0)) or (flags & z) != 0);
case SignedGreaterOrEq:
return not ((((flags & v) != 0) == ((flags & n) != 0)) and (flags & z) == 0);
case Above:
return (flags & c|z) == 0;
case NotOverflow:
return (flags & v) == 0;
case NotZero:
return (flags & z) == 0;
case NotCarry:
return (flags & c) == 0;
case Always:
return true;
I/O Transfers
| Mnemonic | Opcode | Payload |
|---|---|---|
7------0 | 31---------------------8 | |
IN | 00010100 | wwwww000000ppppppppddddd |
OUT | 00010101 | wwwww000000ppppppppsssss |
- w: Transfer Bit Width
- p: Port Number
- d: Destination Transfer Register
- s: Source Transfer Register
Ex[2]: If any reserved (fixed bit) is set to an invalid value
Shift w (in 1..=32, mod 32) bits in an io transfer register in or out to an I/O Port. w=0 = 32
IN: Shifts bits into the high bits of the transfer registerOUT: Shifts bits out of the low bits of the transfer register
Any IN or OUT instruction will not begin executing on a CPU until all IN or OUT instructions that occur before it have been fully written back. Additionally
- Any
OUTinstruction does not begin executing until allLDinstructions that occur before it have been fully written back, and allSTinstructions that occur before it have fully written to main memory - Any
LDorSTinstruction does not begin executing until anyINinstruction that occurs before it has been fully written back
instruction IN(s: u5, p: u8, w: u5):
let val = RotateRight(ReadBitsFromPort(p,w),ExtendWidth(w));
let regval = ReadRegister(2, s);
let resval, bitsout = ShiftRightInOut(regval, val, ExtendWidth(w));
WriteRegister(2,s, resval);
instruction OUT(s: u5, p: u8, w: u5):
let regval = ReadRegister(2, s);
let resval, bitsout = ShiftRightInOut(regval, 0, ExtendWidth(w));
WriteRegister(2,s, resval);
WriteBitsToPort(p, ExtendWidth(w), bitsout);
function ExtendWidth(w: u5) is u6:
if w==0:
return 0x20;
else:
w;
Flags Manipulation
| Mnemonic | Opcode | Payload |
|---|---|---|
7------0 | 31---------------------8 | |
LDFLAGS | 00011000 | 00000000000000fffffddddd |
STFLAGS | 00011001 | 00000000000000fffffsssss |
XVP | 00011010 | 000000000000000000000000 |
- f: Flag modification mask
- d: Destination Register
- s: Source Register
Ex[2]: If any reserved (fixed) bit is set to an invalid value.
LDFLAGSloads the flags bits into the lower 5 bits ofd(zero extended)STFLAGSstores the lower 5 bits ofsinto the flags bits, overwriting only flags set to 1 infXVPexchanges the v and p flags
The flags bits are, in order
4---0 |
|---|
pznvc |
p: Parityz: Zeron: Negativev: Signed Overflowc: Carry
instruction LDFL(d: u5, f: u5):
let val = ZeroExtend(flags & f);
WriteRegister(0,d, val);
instruction STFL(s: u5, f: u5)
let val = ReadRegister(0, s);
flags = (val & f) | (flags & ~f);
instruct XVP():
let temp = flags.p;
flags.p = flags.v;
flags.v = temp;
Exchange Register Contents
| Mnemonic | Opcode | Payload |
|---|---|---|
7------0 | 31---------------------8 | |
XCHG | 00011100 | 000000000bbbbblccccaaaaa |
b: Register 2l: Latency Controlc: Condition Code (See Jump)a: Register 1
Ex[2]: If any reserved (fixed) bit is set to an invalid value.
Exchanges GPR values a and b, if the condition check succeeds.
instruction XCHG(a: u5, b: u5, l: bool, c: ConditionCode):
let val1 = ReadRegister(0, a);
let val2 = ReadRegister(0, b);
if CheckCondtion(flags, c):
WriteRegister(0, a, val2);
WriteRegister(0, b, val1);
Extend Register Contents
| Mnemonic | Opcode | Payload |
|---|---|---|
7------0 | 31---------------------8 | |
EXT | 00011101 | wwwww00000000xsssssddddd |
w: Value widthx: Extend Kind (sign/zero)s: Sourced: Destination
Ex[2]: If any reserved (fixed) bit is set to an invalid valueEx[2]: Ifw = 0.
Masks only the lower w bits of a register, and extends it according to x
enum ExtKind:
Sign = 0,
Zero = 1
instruction EXT(dest: u5, src: u5, x: ExtKind, w: u5):
if w==0:
Raise(Ex[2])
let val = ReadRegister(0, src) & (1 << w)-1;
let res: u32;
switch(x):
case Sign:
res = SignExtend(val, w);
case Zero:
res = val;
WriteRegister(0, dest, res);
Swap Byte order
| Mnemonic | Opcode | Payload |
|---|---|---|
7------0 | 31---------------------8 | |
BSWAP | 00011110 | 000000000000000sssssddddd |
s: Source operandd: Destination Operand
Ex[2]: If any reserved (fixed) bit is set to an invalid value
Swaps the order of bytes from the source value.
instruction BSWAP(s: u5, d: u5):
let sval: u32 = ReadRegister(0, s);
let rval: u32;
rval[8:0] = sval[32:24];
rval[16:8] = sval[24:16];
rval[24:16] = sval[16:8];
rval[32:24] = sval[8:0];
WriteRegister(0, d);
Random Bits
| Mnemonic | Opcode | Payload |
|---|---|---|
7------0 | 31---------------------8 | |
RBGEN | 00011111 | wwwww000100000eeeeeddddd |
w: Poll widthe: Status Destinationd: Destination
Ex[2]: If any reserved (fixed) bit is set to an invalid value
Polls a hardware random bit generator. If successful, writes w (in 1..=32, mod 32) random bits to d and clears flags.z. If unsuccesful, writes 0 to d and sets flags.z. In all cases, the current status of the RBG is stored to e. (TODO: Write out status format). Note that flags.z is only set depending on success/failure. In particular, a successful poll that results in all 0s (Approximately a 2^-(w+1) chance) will still clear flags.z.
The Random Bit Generator polled by the instruction shall have at least the following properties:
- Each complete output from the instruction is independant from other outputs on any core
- Each output from the instruction is distinct from all other outputs, with
2^-((w)/2)probability of collision. - If this instruction is used to generate at least 128 bits of randomness, which is then processed by a Cryptographic Hash Function, the resulting output shall have at least 64 bits of enthropy.
instruction RBGEN(d: u5, e: u5, w: u5):
let valid, result, status = PollRand(ExtendWidth(w));
WriteRegister(0, e, status);
if valid:
WriteRegister(0, d, result);
flags.z = 0;
else:
WriteRegister(0, d, 0);
flags.z = 1;
Status format:
+31-----------------------------0+
|r0000000000000sseeeeeeeeeeeeeeee|
+--------------------------------+
| Bit | Name | Description |
|---|---|---|
r | Repeatable | If set to 1, operation may be retried immediately |
s | Status Code | Status code (See Below) |
e | Enthropy Available | Total ratio of enthropy available (*2^16) |
The following status code values are used
| Status Code | Name | Description |
|---|---|---|
| 0 | NORMAL | Normal status/spurious failure |
| 1 | UNAVAIL | Required minimum enthropy unavailable |
| 2 | PAUSE | Generator Paused/Errored (Recoverable) |
| 3 | FAULT | Unrecoverable Generator Error |
The CPU shall ensure that it automatically attempts a reset of the Random Bit Generator after reporting a PAUSE status in finite time. In the case of a FAULT status, the Generator is only reset after a RESET.
Invoke Coprocessor Unit
| Mnemonic | Opcode | Payload |
|---|---|---|
7------0 | 31---------------------8 | |
CPIx | 00100xxx | ppppppppppppppppppppffff |
NCPIx | 00101xxx | ppppppppppppppppppppffff |
CPIxEF | 00110xxx | ppppppppppppppppppffffff |
NCPIxEF | 00111xxx | ppppppppppppppppppffffff |
(x is a value from 0 to 7, representing the co-processor number to invoke, for example, CPI0 has opcode 0x20 and NCPI7 has opcode 0x2F)
p: Co-processor instruction payloadf: Co-processor function
- CPIx, CPIxEF,
Ex[8+x]: If executing the instruction raises a coprocessor error
Executes the specified Coprocessor function with the specified payload
CPIx/CPIxEF: Waits for the Co-processor to finish all operations, and raises the appropriate unit error if the Coprocessor reports it,NCPIx/NCPIxEF: Finishes immediately.CPIx/NCPIx: Allows specifying up to 16 functions with a 20-bit payloadCPIxEF/NCPIxEF: Allows specifying up to 64 functions with a 18-bit payload (bottom 18-bits of the 20-bit payload)
If a CPIx or CPIxEF instruction begins execution on a core, the following guarantees are made:
- Any
CPIx,CPIxEF,NCPIx, orNCPIxEFinstruction (for the samex) that occurs after will not begin executing until theCPIxorCPIxEFand allNCPIxandNCPIxEFinstructions that occur before theCPIxorCPIxEFhave been fully written back, and - Any
MOVinstruction that loads from a register in map8+xwill not begin executing until theCPIxorCPIxEFand allNCPIxandNCPIxEFinstructions that occur before theCPIxorCPIxEFhave been fully written back.
instruction {CPI0, CPI1, CPI2, CPI3}(f: u4, p: u20):
let coproc: u4;
switch (instruction):
case CPI0:
coproc = 0;
case CPI1:
coproc = 1;
case CPI2:
coproc = 2;
case CPI3:
coproc = 3;
if not IsCoprocessorEnabled(coproc):
Raise(EX[3]);
ExecuteCoprocessorInstruction(coproc, f, p);
WaitOnCoprocessor(coproc);
CheckAndRaisePending(EX[8+coproc]);
instruction {CPI0EF, CPI1EF, CPI2EF, CPI3EF}(f: u6, p: u18):
let coproc: u4;
switch (instruction):
case CPI0EF:
coproc = 0;
case CPI1EF:
coproc = 1;
case CPI2EF:
coproc = 2;
case CPI3EF:
coproc = 3;
if not IsCoprocessorEnabled(coproc):
Raise(EX[3]);
ExecuteCoprocessorInstruction(coproc, f, p);
WaitOnCoprocessor(coproc);
CheckAndRaisePending(EX[8+coproc]);
instruction {NCPI0, NCPI1, NCPI2, NCPI3}(f: u4, p: u20):
let coproc: u4;
switch (instruction):
case NCPI0:
coproc = 0;
case NCPI1:
coproc = 1;
case NCPI2:
coproc = 2;
case NCPI3:
coproc = 3;
if not IsCoprocessorEnabled(coproc):
Raise(EX[3]);
ExecuteCoprocessorInstruction(coproc, f, p);
instruction {NCPI0EF, NCPI1EF, NCPI2EF, NCPI3EF}(f: u6, p: u18):
let coproc: u4;
switch (instruction):
case NCPI0EF:
coproc = 0;
case NCPI1EF:
coproc = 1;
case NCPI2EF:
coproc = 2;
case NCPI3EF:
coproc = 3;
if not IsCoprocessorEnabled(coproc):
Raise(EX[3]);
ExecuteCoprocessorInstruction(coproc, f, p);
Halt/Stop CPU
| Mnemonic | Opcode | Payload |
|---|---|---|
7------0 | 31---------------------8 | |
HALT | 01000000 | 0000000000000000000000mm |
Places the CPU in a low-power state and stops executing.
The CPU responds to interrupts as though ictl.m was set temporarily to m. The CPU resumes execution after receiving an interrupt that is valid at priority m (if m=0 then the CPU will never resume execution).
Ex[2]: If any reserved (fixed) bit is set to an invalid value
The HALT instruction will not begin executing until instructions that occur before it have been fully written back, and no instructions that occur after it will begin executing until the HALT instruction is fully written back.
instruction HALT(m: u2) {
let saved_ictl: u32 = ReadRegister(1, 0);
WriteRegister(1, 0, ZeroExtend(m) | (saved_ictl & (1 << 31)));
if m != 0:
SetStatus(2);
WaitForInterrupt();
WriteRegister(1, 0, saved_ictl);
else:
SetStatus(3);
ShutdownCpu();
}
Debugging Hint
| Mnemonic | Opcode | Payload |
|---|---|---|
7------0 | 31---------------------8 | |
BREAKP | 01000001 | 000000000000000000000000 |
Ex[2]If any undefined bit is set.Ex[5]: If a handler forEx[5]is present and priority 1 exceptions are not masked by intctl.
Hints that a debugger attached to the machine should take control of execution at this point. If a handler for Ex[5] is present and priority 1 interrupts are not masked, raises that exception, with a return address pointing to the next instruction.
instruction BREAKP():
if CpuDebuggerPresent():
BreakToDebugger();
TryInterruptCpu(5, 1);
Interlocked instructions
| Mnemonic | Opcode | Payload |
|---|---|---|
7------0 | 31---------------------8 | |
FENCE | 01001000 | rr0000000000000000000000 |
STIC | 01001011 | rr0000001000wwsssssddddd |
LDIL | 01001100 | rr0000000000wwsssssddddd |
STICW | 01001101 | rr0000001bbbbbsssssddddd |
LDILW | 01001110 | rr0000000bbbbbsssssddddd |
r: Atomic Orderingw: Widthb: Second source/destination registers: Source Registerd: Destination Register
STIL,STILW:EX[1]: Ifdis unalignedLDIL,LDILW:EX[1]: Ifsis unalignedSTIL,STILW:EX[2]: Ifd = 0LDIL,LDILW:EX[2]: Ifs = 0EX[1]: If a bus fault occursEX[2]: Ifw = 3FENCE:EX[2]: ifr = 0LDIL,LDILW:EX[2]: ifr = 2STIC,STICW:EX[2]: ifr = 1
STICandSTICWsetzif the validation check fails. In this case, no memory write or synchronization occurs. All other flags are set to undefined values.
FENCE: Serializes memory between processors according tor.STIC: Storescompleting interlocked sequence ond. On success, thezflag is clear, and the store is guaranteed to be visible to any LDIL or LDILW instruction that is completed by a successful STIC instruction. It is also guaranteed that any ST instruction on any thread that was not observed by the LDIL instruction will not be overwritten by the STIC instruction.LDIL: Load fromsintod, starting an interlocked sequence onswithIL.width = wSTICW: Stores the 8-byte value inb:sintod, completing interlocked sequence ond. On success, thezflag is clear, and the store is guaranteed to be visible to any LDIL or LDILW instruction that is completed by a successful STIC instruction. It is also guaranteed that any ST instruction on any thread that was not observed by the LDILW instruction will not be overwritten by the STICW instruction.LDILW: Loads fromsinto an 8-byte value inb:d, starting an interlocked sequence onswithIL.width = 3
Each a core acts as though it stores the following additional state:
- Whether or not a valid interlocked transaction is occur (
IL.valid) - The address of the most recently begun interlocked transaction (
IL.addr) ifIL.validis true - The width of the most recently begun interlocked transaction (
IL.width)
The validity of an interlocked transaction on a core is reset when any of the following occurs:
- An
STICorSTICWinstruction completes execution, whether or not it was successful or failed - An interrupt or exception occurs
- The
iretinstruction is issued - If transaction is invalidated by a memory write on any core that violates the guarantees of any subsequent
STICorSTICWinstruction.
An STIC instruction fails (sets z = 1 and does not modify any memory) if:
IL.validis falseIL.addrrefers to a different address than theSTICinstructionIL.widthrefers to a different width than theSTICinstruction
An STICW instruction fails (sets z = 1 and does not modify any memory) if:
IL.validis falseIL.addrrefers to a different address than theSTICWinstructionIL.widthis not 3.
An STIC or STICW instruction does not modify any memory if it fails. It is unspecified whether the write access check is performed.
On a multicore system, any instruction that synchronizes memory according to the Acquire or SeqCst order guarantees that the instruction will not write back its result until, for each value loaded by any of the following instructions, all memory accesses visible to the corresponding store instruction will be observed by any instruction that occurs after that instruction:
- For
FENCE: AnyLD,LDIL, orLDILWinstruction that preceeds it - For
LD,LDIL, orLDILW: That instruction.
On a multicore system, any instruction that synchronizes memory according to the Release or SeqCst order guarantees that the write will not be observed by any core until all memory operations that occur before it have completed and become visible to the instruction:
- For
FENCE; AnyST,STIC, orSTICWinstruction that occurs after it - For
ST,STIC, orSTICW: That insttruction.
On a multicore system, any instruction that synchronizes memory according to the SeqCst order guarantees that all cores will observe the same order of memory effects caused by all such instructions.
instruction FENCE(r: Ordering):
if r == Relaxed:
Raise(EX[2]);
SynchronizeMemoryAccordingToFence(r);
instruction STIC(d: u5, s: u5, w: u2, r: Ordering):
if r == Acquire:
Raise(EX[2]);
if w == 3:
Raise(EX[2]);
let dest = ReadRegister(0, d);
if dest & (1 << w)-1 != 0:
Raise(EX[1]);
let failed: u5;
let value = ReadRegister(0, s);
if not IL.valid or IL.addr != dest or IL.width != w:
failed = 8;
else:
failed = TryInterlockedMemoryWrite(dest, w, value);
CheckAndRaisePending(EX[1]);
IL.valid = false;
flags = failed | nondeterministic() & ~8;
instruction STICW(d: u5, s: u5, b: u5, r: Ordering):
if r == Acquire:
Raise(EX[2]);
let dest = ReadRegister(0, d);
if dest & 7 != 0:
Raise(EX[1]);
let failed: u5;
let value = ReadRegister(0, s);
let value_hi = ReadRegister(0, b);
SynchronizeMemoryAccordingToWrites(r);
if not IL.valid or IL.addr != dest or IL.width != 3:
failed = 8;
else:
failed = TryInterlockedMemoryWriteWide(dest, value, value_hi);
CheckAndRaisePending(EX[1]);
IL.valid = false;
flags = failed | nondeterministic() & ~8;
instruction LDIL(d: u5, s: u5, w: u2, r: Ordering):
if r == Release:
Raise(EX[2]);
if w == 3:
Raise(EX[2]);
let src = ReadRegister(0, s);
if src & (1 << w)-1 != 0:
Raise(EX[1]);
let value = InterlockedMemoryRead(src, w);
CheckAndRaisePending(EX[1]);
IL.valid = true;
IL.addr = src;
IL.width = w;
WriteRegister(0, d, value);
instruction LDILW(d: u5, s: u5, b: u5, r: Ordering):
if r == Release:
Raise(EX[2]);
if w == 3:
Raise(EX[2]);
let src = ReadRegister(0, s);
if src & (1 << w)-1 != 0:
Raise(EX[1]);
let value, value_hi = InterlockedMemoryReadWide(src);
CheckAndRaisePending(EX[1]);
IL.valid = true;
IL.addr = src;
IL.width = 3;
WriteRegister(0, d, value);
WriteRegister(0, b, value_hi);
Cryptographic Instructions
Working Registers
The first 16 registers of the Co-processor register set are working registers. Working Registers are available to all operations.
Registers 16-31 are scratch registers. These can be accessed by MOV, CRMOV, CRLD, and CRST, and by CRADD, CRSUB, CROR, CRXOR, CRAND, and CRANDN.
Functions
Copy/Load
| Mnemonic | Opcode | pppppppppppppppppppp |
|---|---|---|
0--3 | 4-----------------20 | |
CRMOV | 0x01 | dddddsssss0000000000 |
CRLD | 0x02 | dddddsssssww00000000 |
CRST | 0x03 | dddddsssssww00000000 |
CRLDB | 0x04 | dddd0ssssscccc000000 |
CRSTB | 0x05 | dddd0ssssscccc000000 |
Comparison
| Mnemonic | Opcode | pppppppppppppppppppp |
|---|---|---|
0--3 | 4-----------------20 | |
CRCMP | 0x0F | dddddaaaa0bbbb0r00tt |
Bits:
d: Destination Registera: First working register to compareb: Second working register to comparer: Overwrite Condition Maskt: Test (0: Equals, 1: Similarity, 2: Difference, 3: Not Equal)
Behaviour: Tests a and b according to t, modifying d accordingly. If r is set, d is set to the result. If r is clear, d is set to the result anded with the current value of d. For test 0, the result is all 1s if they are equal, and all 0s if they are different. For Test 1, sets the nth bit to 1 if and only if that bit is the same between a and b. For Test 2, sets the nth bit to 1 if and only if that bit is different between a and b. For test 3, the result is all 1s if the values are different.
This instruction is guaranteed to have consistent timing regardless of the input values of d, a, or b.
| Mnemonic | Opcode | pppppppppppppppppppp |
|---|---|---|
0----5 | 4---------------18 | |
SHA32SIG | 0o0020 | ssssrrrrwwwwvvvv00 |
SHA32SUM | 0o0021 | ssssrrrraaaaeeee00 |
SHA32CHM | 0o0022 | ddddaaaabbbbcccc0m |
SHA2IV | 0o0023 | ddddiiii0000000l00 |
SHA2RC | 0o0024 | ddddkkkkk000000l00 |
psABI
Types
C Primitive Sizes
CHAR_BIT is 8.
| Type | Size |
|---|---|
bool1 | 1 |
short | 2 |
int | 4 |
long | 4 |
long long | 8 |
float | 4 |
double | 8 |
long double | 8 |
void* | 4 |
intptr_t | 4 |
size_t | 4 |
intmax_t | 8 |
wchar_t | 4 |
Char Types
char is unsigned by default.
Primitive Alignment
The Size and alignment of align_max_t are both 4. Each primitive less than or equal to 4 bytes in size is aligned to its size, rounded up to the next power of two bytes.
Each primitive that is greater than 4 bytes in size are aligned to 4 bytes. This includes _BitInt(N) types.
Floating Point Formats
float matches the IEEE754 binary32 format.
double and long double both match the IEEE754 binary64 format.
Registers
In Map 0, Registers r1-r15 are callee saved and are not preserved accross prodecure calls. Registers r16-r31 are caller saved and must be restored to their values at entry by the function. r0 is a constant 0 register and cannot be modified.
r15 is recommended for use by code patterns that use a register to compute a value for immediate use. The Assembler may make use of this register implicitly to assemble certain psuedo-instructions.
Map 1 and 4 Registers should not be modified by toolchains, except through explicit arrangement with the program. The precise values of Map 1 Registers should not be relied upon.
Registers in Map 2 and Maps 8-15 are callee saved and are not preserved accross procedure calls.
r1 and r2 are used to return values up to 8 bytes in size. Registers r1 through r10 are used to pass up to 10 parameters.
Register Overview
| Register(s) | Purpose | Callee/Caller Saved |
|---|---|---|
r0 | Constant 0 | Constant Register |
r1 | Param/Return Register | Caller Saved |
r2 | Param/Return Register | Caller Saved |
r3-r10 | Param Register | Caller Saved |
r11-r14 | Scratch Register | Caller Saved |
r15 | Special-Purpose Scratch Register | Caller Saved |
r16-r27 | Callee Saved Register | Callee Saved |
r28-r29 | Reserved Register | Callee Saved/Reserved |
r30 | Stack Pointer | Callee Saved |
r31 | Return Pointer | Callee Saved |
Stack, Link Register, Reserved Registers
Map 0 Registers r28, r29, r30, and r31 are reserved for special use, within the caller saved regions.
r28 and r29 are not used by this ABI, but may be used by future versions or by individual machines/systems/programs as a special registers. If modified by software complying with this ABI, it must be restored before returning from the current procedure or entering another procedure, unless it is modified in cooperation with the definition of the register.
Note
It is recommended for r28 to be used as a Thread Pointer on a multicore system.
r30 is reserved to be the stack pointer. Before entering a procedure, it must refer to a memory address which points to the end of a memory region that is available for the procedure to use to store its own variables and parameters. The Address must be aligned to 4 bytes, and must be mutable. Additionally, the memory region immediately following the pointers may be required to hold parameters passed on the stack. The stack grows downwards, away from the end of the region allocated for the stack. Any region of memory between the address in r30 up to the end of the stack shall be preserved by compliant software, unless mutated via a pointer. All memory below the stack pointer in the allocated memory region may be freely clobbered at any point (including by an interrupt handler) and must not be relied upon in any particular value.
r31 is reserved to be the standard link register. Upon entry to any procedure, r31 shall contain the address to return to upon exit.
Note
While r31 remains caller saved, every function call that isn’t a tailcall will necessarily modify this register and require the register to be spilled to memory. The exception is if the function does not expect to return (but such functions may require this regardless, to support unwinding).
Parameter Passing/Return Convention
When passing or returning values, each value is classified as follows:
- Primitive Values,
- Non Trivial Aggregates
Non-Trivial Aggregates are types with an alignment greater than 4, or a class type C++ with one of the following special member functions being non-trivial, and which is not trivially relocatable:
- Copy or Move (Since C++11) Constructor,
- Destructor.
All types that are not Non-Trivial Aggregates, and only have fields or elements of Primitive types (recursively) are Primitive Values.
Each parameter/return value in order is assigned a passing mode: _ If the paramater/return value is larger than 8 bytes in size, it is passed/returned in memory, _ If the parameter/return value is a Non-Trivial Aggregate, it is passed/returned in memory, * Otherwise, it is passed directly/returned.
If the return value is returned in memory, an implicit first parameter is inserted, which is a pointer to storage suitable for placing the entire return value. This pointer is then returned in r1.
A parameter passed in memory is replaced with a single 4 byte value passed directly, which points to the memory used to pass the value.
After replacement, values passed/returned directly are divided into up to 2 4-byte chunks, with the final chunk filled with padding bytes after the value, as necessary. Any chunk which is not present or consists entirely of padding bytes is discarded when passing directly - however, the whole value must still be < 8 bytes long>. Then, each chunk in parameter order (with least significant byte first) is passed by allocating the next available register in r1-r10. Any registers that partially consist of padding have the value extended from the previous scalar value occupying the register. If the padding follows an unsigned integer (other than bool), unsigned fixed point type, or a floating-point type, the padding is filled with zero bytes. If the padding follows a signed integer or signed fixed point value, it is zeroed if any other values are passed in the same register or sign extended if no other values are passed. When bool is passed (including inside a structure), the entire byte is set to a copy of the first bit, then any following padding is set as if the value was an 8-bit signed integer.
If any chunk of a parameter cannot be allocated a register, the entire value is pushed to the stack in Right to Left Order (with the Leftmost parameter occupying the least significant address). The most significant address of the parameter area is 4 byte aligned, and up to 3 bytes are inserted after the leftmost parameter to align the stack to 4 bytes. Padding is inserted between parameters to align each parameter to the smaller of their size rounded up to the next power of 2, and 4 bytes.
Note that alignment requirements are not considered for this step (e.g. a char[3] array will get padded to 4 bytes) Once the first parameter is passed on the stack, no further parameters are passed in registers.
Each returned chunk of the return value is returned in the first available register of r1 and r2.
Floating point co-processor
The Use of a hardware floating-point coprocessor to compile floating-point operations is permitted. Due to variability in machine allocations, the co-processor used for floating-point operations is not specified herein, and must be specified by the appropriate machine supplement or toolchain configuration options. Use of a particular co-processor number with hardware floating-point operations is not compatible with a system that does not have a floating-point co-processor in the appropriate slot.
Regardless of the use of a floating-point co-processor, floating-point values are not passed using floating-point registers, and are still passed using general purpose parameter registers when <= 8 bytes in size.
ELF Files
OSABI
The following OSABI values are defined
| OSABI | Constant | Description |
|---|---|---|
0-63 | Multiple | See gABI OSABI list |
240 | OSABILOPRIV | Lowest value of Private Use Area |
253 | OSABIHIPRIV | Highest value of the Private Use Area |
254 | OSABIEXT | Reserved for OSABI extension |
255 | OSABISTANDALONE | Standalone/Freestanding target |
OSABISTANDALONE may be used by any program that conforms with this ABI and does not use a host operating system. The OS-specific ranges are unspecified.
An object file that conforms to this ABI may not use any value in *_LOOS through *_HIOS for the respective fields in the ELF file.
OSABIEXT is reserved for future use for an extension of the EI_OSABI field.
The values between OSABILOPRIV and OSABIHIPRIV (inclusive) are reserved for private use. Object files and toolchains may use these constants for any purpose. Such object files and toolchains should not be considered portable and may not be arbitrarily combined.
Relocations
| Relocation Name | Relocation Number | Size | Validation | Value | Description |
|---|---|---|---|---|---|
| R_SKYARCH_NONE | 0 | 0 bits | N/A | 0 | Performs no Operation |
| R_SKYARCH_32 | 1 | 32 bits | Unsigned | S | Relocates against an absolute 32-bit address |
| R_SKYARCH_PC32 | 2 | 32 bits | Signed | S-IP | Relocates against the 32-bit offset from the current address |
| R_SKYARCH_LO16 | 3 | 16 bits | None | TRUNC(S) | Relocates against the lower 16 bits of an absolute 32-bit address |
| R_SKYARCH_PC16 | 4 | 16 bits | Signed | S-IP | Relocates against the 16-bit offset from the current address |
| R_SKYARCH_LOPC16 | 5 | 16 bits | None | TRUNC(S-IP) | Relocates against the lower 16 bits of a 32-bit offset from the current address |
| R_SKYARCH_HI16 | 6 | 16 bits | Unsigned | S>>16 | Relocates against the upper 16-bits of an absolute 32-bit address |
| R_SKYARCH_HIPC16 | 7 | 16 bits | Signed | (S-IP)>>16 | Relocates against the upper 16-bits of a 32-bit offset |
| R_SKYARCH_JMPO | 8 | 16 bits | Signed | (S-IP)>>2 | Relocates against the aligned 17 bit offset suitable for a jump instruction, writing the top bits to the upper 15 bits of the word |
| R_SKYARCH_RELAX16_PC32 | 32 | 64 bits | N/A | N/A | Hints that a link editor or other tool may convert a pointed to code sequence that loads a 32-bit pc relative offset into one that loads a 16-bit pcrelative offset |
| R_SKYARCH_RELAX16_32 | 33 | 64 bits | N/A | N/A | Hints that a link editor or other tool may convert a pointed-to code sequence that loads a 32-bit absolute address into one that loads a 16-bit absolute address, or a 16-bit offset |
| R_SKYARCH_RELAXJMPOFF_PC32 | 34 | 96 bits | N/A | N/A | Hints that a link editor or other tool may convert a pointed-to code sequence that loads and jumps to a 32-bit pc relative address into one that performs a direct jump to a 17-bit aligned offset from the resulting instruction |
| N/A | 35-63 | 0 bits | N/A | N/A | Reserved for future relaxation hints and must be ignored by link editors. Must not be generated by toolchains |
Variables:
- S: The Address of the symbol being relocated
- IP: The instruction pointer at the end of the relocation.
Link Relaxations
Toolchains (including assemblers and compilers) may emit certain code sequences to generate a load of a symbol address that may not be representable as a 16-bit address or offset, or a jump to an address that may not be representable as a 20-bit instruction offset. When doing so, the toolchain may emit relaxations into the object file’s relocation table, pointing to the beginning of the relaxable code sequence, which are operative hints to link editors that the code sequences can be contracted to a smaller (usually single instruction) code sequence.
Toolchains are not required to emit relaxations, and link editors are not required to make use of them. Any link relaxation is a hint and may be ignored and toolchains MUST NOT rely on them being processed for emitting correctly relocated code.
Certain specific code sequences are supported, and it is undefined behaviour to apply a relaxation to an ill-formed code sequence. Link Editors are not required to check for invalid code sequences, and are not required to preserve the behaviour of an invalid code sequence where a link relaxation is applied. It is further not required that the link editor check that relocations pointing into the relaxed code sequence refers to the same symbol as the
R_MICRON_RELAX16_PC32 and R_MICRON_RELAX16_32
R_MICRON_RELAX16_PC32 and R_MICRON_RELAX16_32 hint that a 2 instruction long code sequence loads an address, either by loading an absolute relocated address, or by loading a relocated offset and adding it to the instruction pointer at the end of the code sequence, and may be relaxed to a single instruction that loads the same address. Note that the link editor is not required to preserve the kind of relocation indicated in the relaxation - the PC32 vs. 32 refers to the manner of address loading (PC Relative vs. Absolute). The Link editor may emit either an absolute 16-bit address, or a 16-bit offset, where the resulting value loaded is the address of the appropriate symbol.
The below code sequences are written in assembly, with unrelocated machine code adjacent. <val>+REG refers to the value of <val> with the register number REG added. IE. if REG is r11, then 0x00+REG is 0x0B, and if REG is r31, then 0x40+REG is 0x5F.
REG is any GPR that is the same in both instructions
The following code sequence is supported for R_MICRON_RELAX16_PC32(sym),
LRAU REG, R_MICRON_LOPC16(sym)-4 # 0x06 0x00+REG 0x00 0x00
ADDIH REG, R_MICRON_HIPC16(sym) # 0x08 0x40+REG 0x00 0x00
The following code sequence is supported for R_MICRON_RELAX16_32(sym)
LDI REG, R_MICRON_LO16(sym) # 0x05 0x00+REG 0x00 0x00
ADDIH REG, R_MICRON_HI16(sym) # 0x08 0x40+REG 0x00 0x00
The two resulting instructions that can be emitted by the link editor, if eligible, are below. If both are eligible, the link editor may choose which code sequence to emit.
# Code Sequence 1
LRA REG, R_MICRON_PC16(sym) # 0x06 0x00+REG 0x00 0x00
# Code Sequence 2
LDI REG, R_MICRON_LO16(sym) # 0x05 0x00+REG 0x00 0x00
R_MICRON_RELAXJMPOFF_PC32
R_MICRON_RELAXJMPOFF_PC32 hints that the 3 instruction sequence it is applied to has the effective behaviour of loading the address of the specified symbol into an otherwise unused scratch register and jumping to that address.
The following code sequence is supported, where REG is any regster and CC is any Condition COde
LDI REG, R_MICRON_LO16(sym) # 0x05 0x00+REG 0x00 0x00
ADDIH REG, R_MICRON_HI16(sym) # 0x08 0x40+REG 0x00 0x00
JMPR{CC} REG
The following resulting code sequence may be emitted by the link editor, if eligible.
JMP{CC} R_MICRON_JUMPO(sym)
Note that is it is not guaranteed that the value of REG is preserved by the relaxation. Thus code following the relaxed code sequence must treat REG as having an undefined value.
!{#copyright}
-
Referred to as
_Boolin C since C99 until C23. ↩
Assembly Syntax
Operands
The following operand syntax types are used in instructions
| Short | Name | Description |
|---|---|---|
GPR | GPR operand | A General Purpose Register |
IGPR | Invertible GPR Operand | A potentially inverted gpr operand |
SGPR | Shifted GPR operand | A General Purpose Register Left-shifted by a constant |
SIGPR | Shifted Invertible GPR operand | A potentially inverted gpr operand Left-shifed by a constant |
IOR | I/O Register operand | An I/O Transfer Register (Map 3) |
ANYREG | Any Register | Any Register operand |
UIMM16 | Immediate (unsigned 16-bit) | 16-bit Immediate operand |
SIMM16 | Immediate (signed 16-bit) | 16-bit Immediate Operand |
SIMM17 | Immediate (signed 17-bit) | 17-bit Immediate operand |
PCREL17 | PC Relative Address (16-bit) | 16-bit offset from IP in bytes |
PCREL32 | PC Relative Address (32-bit) | 32-bit offset from IP in bytes |
OFF17 | Jump Offset (signed 20-bit) | 20-bit jump offset in words |
UIMM32 | Immediate (unsigned 32-bit) | 32-bit immediate operand |
SIMM32 | Immediate (signed 32-bit) | 32-bit immediate operand |
BITW | Bit Width | Width of a value in bits |
BYTESZ | Byte Size | Size of a value in bytes |
ABSIMM2 | Immediate (unsigned 2-bit) | 2-bit absolute (non-relocated) immediate |
ABSIMM3 | Immediate (unsigned 3-bit) | 3-bit absolute (non-relocated) immediate |
ABSIMM5 | Immediate (unsigned 5-bit) | 5-bit absolute (non-relocated) immediate |
ABSIMM6 | Immediate (unsigned 6-bit) | 6-bit absolute (non-relocated) immediate |
ABSIMM8 | Immediate (unsigned 8-bit) | 8-bit absolute (non-relocated) immediate |
CC | Condition Code Name | A condition Code |
PRIO | Interrupt Priority | An interrupt priority level |
GPR operands
A GPR operand is written as r followed by the index number of the register.
Shifted GPR
A Shifted GPR operand is written as GPR << ABSIMM5.
A shifted GPR operand produces two variables. The Operand Specification is written as <GPR> << <ABS>
Invertible GPRs
An invertible GPR is written as either GPR (non-inverted) or ~GPR (inverted). An IGPR produces two variables. The Operand Specification is written as <INV> <GPR>.
A Shifted invertible GPR operand is written the same as GPR << ABSIMM5, except that GPR may be inverted. An SIGPR produces three variables, written as <INV> <GPR> << <ABS>
I/O Register Operand
An I/O Register Operand is written as io followed by the index number of the register.
Any Register
A Register in any map is either a GPR operand, and I/O Register operand, a system configuration register, a system information register, or a coprocessor register.
An interrupt register may be written as intrN or an alias name.
Registers 1-3 may be written as intretN, Registers 4-7 are written intdN where N=r%4, Registers 8-11 are written intsN where N=r%4.
A system information register is written as info followed by the index number of the register.
A coprocessor register is written as co followed by the coprocessor number between 0 and 3, followed by r, followed by the register number.
If the Assembler is aware of the particular coprocessor expected in a given coprocessor slot, it may use the alias name provided by the Coprocessor’s Assembly Supplement.
For example, if the Assembler is aware of the presence of a FPU (according to <float-coproc.md>) in slot 0, it may alias f0 as co0r0.
Immediates
Immediate operands take an integer or a symbol. n-bit Unsigned Immediates require an unsigned quantity in [0,2^n). Signed Immediates require a signed quantity in [-2^(n-1), 2^(n-1)).
Other than Absolute Immediates (like ABSIMM6), immediate operands can have symbols. Unless specified with the @pcrel modifier, Immediate operands always treat symbols as absolute address in relocations. The relocation requires that the address fits in the specified size of immediate (a link error occurs if it does not). using the special modifiers HI and LO allows you to instead specify the lower or upper 16-bits of the symbol.
Unless modified, immediate relocations uses (given the appropriate n):
R_MICRON_<n>R_MICRON_LO16(LO <sym>)R_MICRON_HI16(HI <sym>)
With the @pcrel modifier (or for PCREL16, see below), the relocation uses (given the appropriate n):
R_MICRON_PC16R_MICRON_LOPC16(LO <sym>@pcrel)R_MICRON_HIPC16(HI <sym>@pcrel)
SIMM17 stores only the lower 16 bits of the immediate to the field. The 17th bit is occupied by the sign, which is stored otherwise.
Offsets
The PCREL17 and OFF15 values are special cases of immediates.
PCREL17 is identical to a SIMM17 relocation, except that it defaults to resolving the specified symbol using a pc-relative relocation.
OFF15 is a 15-bit immediate that resolves a 17-bit pc-relative relocation or a 17-bit signed integer offset, and discards the lower two bits to encode the instruction. It has two constraints, in addition to the constraints that would apply to a 22-bit signed immediate:
- Absolute Expressions must be divisible by 4, and
- Relocation Expressions must produce a 4-byte aligned quantity. The Assembler may error if a misalignment is reliably detected (for example, a 3-byte offset from a symbol known to be 4-byte aligned).
OFF15 uses R_MICRON_JMPOFF relocation.
Sizes/Widths
A size or width expression is an absolute immediate that encodes a size (in bytes) or a width (in bits).
A BITW operand is a 5-bit unsigned absolute immediate that can take on any value between 1 and 32. 32 is encoded as 0. As a special case, the following synthetic constants are defined for BITW operands with the following values:
byte: 8half: 16word: 32.
A BYTESZ operand is a 2-bit immediate with a special encoding of lg(sz) where sz is the real size in bytes. The value must be a power of 2 less than 8. The same synthetic constants are defined above to be 1, 2, and 4 respectively.
Interrupt Priorities
An interrupt priority is a priority level for the IRET instruction. It may be written as an ABSIMM2 or one of the following keywords. A value of 0 assembles, but is an illegal instruction at runtime.
trap: 1async: 2irq: 3
Condition Code
Condition Codes appear only in mnemonics, and use the following 1 or 2 character short forms:
| Short Form | Condition Name | Number | Canonical |
|---|---|---|---|
NV | Never | 0 | Yes |
C | Carry | 1 | Yes |
B | Below | 1 | No |
Z | Zero | 2 | Yes |
EQ | Equal | 2 | No |
O | Overflow | 3 | Yes |
CE | Carry/Equal | 4 | Yes |
BE | Below or Equal | 4 | No |
LT | Less | 5 | Yes |
LE | Less or Equal | 6 | Yes |
N | Negative | 7 | Yes |
S | Signed | 7 | No |
P | Positive | 8 | Yes |
NS | Not Signed | 8 | No |
GT | Greater Than | 9 | Yes |
NLE | Not Less or Equal | 9 | No |
GE | Greater or Equal | 10 | Yes |
NLT | Not Less | 10 | No |
A | Above | 11 | Yes |
NBE | Not Below or Equal | 11 | No |
NCE | Not Carry or Equal | 11 | No |
NO | Not Overflow | 12 | Yes |
NZ | Not Zero | 13 | Yes |
NE | Not Equal | 13 | No |
NC | Not Carry | 14 | Yes |
NB | Not Below | 14 | No |
AE | Above or Equal | 14 | No |
AL | Always | 15 | Yes |
Instruction Syntax
The following charts describes how assemblers should interpret and assemble given instruction syntax forms and mnemonics.
Each Chart has the following information:
- Mnemonic: The name of the instruction, which should be interpreted case-insentively. The special variables
<c>and<x>may be written here.cis as if definedCC <c>andxis as if definedABSIMM2 <x>. - Operands: A list of operands written as the Short ID followed by a variable in
<>(e.g.GPR <d>) - Opcode: The Opcode of the instruction. This may reference the special variable
xif defined in the Mnemonic. - Special Payload Encoding: A list of variable assignments of the form
<var>=<val>wherevaris an encoding variable defined for the opcode in the ISA Spec, andvalis either an integer expression or a variable. Implicitly the name of each encoding variable that is defined as a syntax variable in the Mnemonic or the Operands list is assigned to the value of that syntax variable. The special encoding variablePrefers to the entire 24-bit payload (where its contents are undefined/ignored) - Canonical: Describes whether or not the instruction specification is canonical Canonical Specifications are the primary (or only) way to describe a particular encoding (without a
.instrdirective). Non-canonical encodings may describe a more efficient way to write or read a particular encoding, or may be useful in niche circumstances. Disassemblers and machine-code generators (such as assembly printing from a compiler) should prefer the canonical specification if it has no context otherwise.
UND
| Mnemonic | Operands | Opcode | Special Payload Encoding | Canonical |
|---|---|---|---|---|
UND | - | 0x00 | P=0 | Yes |
PAUSE
| Mnemonic | Operands | Opcode | Special Payload Encoding | Canonical |
|---|---|---|---|---|
PAUSE | ABSIMM6 <k> | 0x01 | N/A | Yes |
NOP | - | 0x01 | k=0 | No |
MOV
| Mnemonic | Operands | Opcode | Special Payload Encoding | Canonical |
|---|---|---|---|---|
MOV<c> | GPR <d>, GPR <s> | 0x02 | m=0, r=0, l=0 | Yes |
MOV<c> | GPR <d>, ANYREG <s> | 0x02 | m=MAP(s), r=0, l=0 | Yes |
MOV<c> | ANYREG <d>, GPR <s> | 0x02 | m=MAP(d), r=1, l=0 | Yes |
MOV | GPR <d>, GPR <s> | 0x02 | m=0, r=0, l=0, c=15 | No |
MOV | GPR <d>, ANYREG <s> | 0x02 | m=MAP(s), r=0, l=0, c=15 | No |
MOV | ANYREG <d>, GPR <s> | 0x02 | m=MAP(d), r=1, l=0, c=15 | No |
MOVL<c> | GPR <d>, GPR <s> | 0x02 | m=0, r=0, l=1 | Yes |
MOVL<c> | GPR <d>, ANYREG <s> | 0x02 | m=MAP(s), r=0, l=1 | Yes |
MOVL<c> | ANYREG <d>, GPR <s> | 0x02 | m=MAP(d), r=1, l=1 | Yes |
LD/ST
| Mnemonic | Operands | Opcode | Special Payload Encoding | Canonical |
|---|---|---|---|---|
LD | GPR <d>, GPR <s>, BYTESZ <w> | 0x03 | p=0 | Yes |
ST | GPR <d>, GPR <s>, BYTESZ <w> | 0x04 | p=0 | Yes |
LD | GPR <d>, GPR <s> | 0x03 | p=0,w=4 | No |
ST | GPR <d>, GPR <s> | 0x04 | p=0,w=4 | No |
PUSH | GPR <d>, GPR <s>, BYTESZ <w> | 0x04 | p=1 | Yes |
POP | GPR <d>, GPR <s>, BYTESZ <w> | 0x03 | p=1 | Yes |
PUSH | GPR <d>, GPR <s> | 0x04 | p=1,w=4 | No |
POP | GPR <d>, GPR <s> | 0x03 | p=1,w=4 | No |
PUSH | GPR <s> | 0x04 | p=1,w=4,d=30 | No |
POP | GPR <d> | 0x03 | p=1,w=4,d=30 | No |
Load/Add Immediates
| Mnemonic | Operands | Opcode | Special Payload Encoding | Canonical |
|---|---|---|---|---|
LDI | GPR <d>, SIMM17 <x:i> | 0x05 | Yes | |
LDIU | GPR <d>, UIMM17 <i> | 0x05 | x=0 | Yes |
LRA | GPR <d>, PCREL17 <x:i> | 0x06 | Yes | |
LRAU | GPR <d>, UPCREL16 <i> | 0x06 | x=0 | Yes |
ADDI | GPR <d>, SIMM17 <x:i> | 0x08 | f=1,h=0 | Yes |
ADDIF | GPR <d>, SIMM17 <x:i> | 0x08 | f=0,h=0 | Yes |
ADDIU | GPR <d>, UIMM16 <i> | 0x08 | x=0,f=1,h=0 | Yes |
ADDIH | GPR <d>, UIMM16 <i> | 0x08 | x=0,f=1,h=1 | Yes |
ADDIH | GPR <d>, SIMM16 <i> | 0x08 | x=0,f=1,h=1 | No |
ADDIUF | GPR <d>, UIMM16 <i> | 0x08 | x=0,f=0,h=0 | Yes |
ADDIHF | GPR <d>, UIMM16 <i> | 0x08 | x=0,f=0,h=1 | Yes |
ADDIHF | GPR <d>, SIMM16 <i> | 0x08 | x=0,f=0,h=1 | No |
INC | GPR <d> | 0x08 | x=0,f=1,h=0,i=1 | No |
DEC | GPR <d> | 0x08 | x=1,f=1,h=0,i=0xFFFF | No |
Arithmetic Ops
| Mnemonic | Operands | Opcode | Special Payload Encoding | Canonical |
|---|---|---|---|---|
ADD | GPR <d>, SGPR <a> << <s>, GPR <b> | 0x09 | f=1,p=0 | Yes |
ADD | GPR <d>, GPR <a>, SGPR <b> << <s> | 0x09 | f=1,p=1 | Yes |
ADD | GPR <d>, GPR <a>, GPR <b> | 0x09 | f=1,p=0,s=0 | No |
ADDF | GPR <d>, SGPR <a> << <s>, GPR <b> | 0x09 | f=0,p=0 | Yes |
ADDF | GPR <d>, GPR <a>, SGPR <b> << <s> | 0x09 | f=0,p=1 | Yes |
ADDF | GPR <d>, GPR <a>, GPR <b> | 0x09 | f=0,p=0,s=0 | No |
SUB | GPR <d>, SGPR <a> << <s>, GPR <b> | 0x0A | f=1,p=0 | Yes |
SUB | GPR <d>, GPR <a>, SGPR <b> << <s> | 0x0A | f=1,p=1 | Yes |
SUB | GPR <d>, GPR <a>, GPR <b> | 0x0A | f=1,p=0,s=0 | No |
SUBF | GPR <d>, SGPR <a> << <s>, GPR <b> | 0x0A | f=0,p=0 | Yes |
SUBF | GPR <d>, GPR <a>, SGPR <b> << <s> | 0x0A | f=0,p=1 | Yes |
SUBF | GPR <d>, GPR <a>, GPR <b> | 0x0A | f=0,p=0,s=0 | No |
CMP | SGPR <a> << <s>, GPR <b> | 0x0A | f=0,p=0,d=0 | No |
CMP | GPR <a>, SGPR <b> << <s> | 0x0A | f=0,p=1,d=0 | No |
CMP | GPR <a>, GPR <b> | 0x0A | f=0,p=0,s=0,d=0 | No |
SHL | GPR <d>, GPR <a>, ABSIMM5 <s> | 0x09 | f=1,p=0,b=0 | No |
SHLF | GPR <d>, GPR <a>, ABSIMM5 <s> | 0x09 | f=2,p=0,b=0 | No |
Logic Ops
| Mnemonic | Operands | Opcode | Special Payload Encoding | Canonical |
|---|---|---|---|---|
AND | GPR <d>, SIGPR <i> <a> << <s>, IGPR <j> <b> | 0x0B | f=1,p=0 | Yes |
AND | GPR <d>, IGPR <i> <a>, SIGPR <j><b> << <s> | 0x0B | f=1,p=1 | Yes |
AND | GPR <d>, IGPR <i> <a>, GPR <j> <b> | 0x0B | f=1,p=0,s=0 | No |
ANDF | GPR <d>, SIGPR <i> <a> << <s>, IGPR <j> <b> | 0x0B | f=0,p=0 | Yes |
ANDF | GPR <d>, IGPR <i> <a>, SIGPR <j><b> << <s> | 0x0B | f=0,p=1 | Yes |
ANDF | GPR <d>, IGPR <i> <a>, GPR <j> <b> | 0x0B | f=0,p=0,s=0 | No |
OR | GPR <d>, SIGPR <i> <a> << <s>, IGPR <j> <b> | 0x0C | f=1,p=0 | Yes |
OR | GPR <d>, IGPR <i> <a>, SIGPR <j><b> << <s> | 0x0C | f=1,p=1 | Yes |
OR | GPR <d>, IGPR <i> <a>, GPR <j> <b> | 0x0C | f=1,p=0,s=0 | No |
ORF | GPR <d>, SIGPR <i> <a> << <s>, IGPR <j> <b> | 0x0C | f=0,p=0 | Yes |
ORF | GPR <d>, IGPR <i> <a>, SIGPR <j><b> << <s> | 0x0C | f=0,p=1 | Yes |
ORF | GPR <d>, IGPR <i> <a>, GPR <j> <b> | 0x0C | f=0,p=0,s=0 | No |
XOR | GPR <d>, SIGPR <i> <a> << <s>, IGPR <j> <b> | 0x0D | f=1,p=0 | Yes |
XOR | GPR <d>, IGPR <i> <a>, SIGPR <j><b> << <s> | 0x0D | f=1,p=1 | Yes |
XOR | GPR <d>, IGPR <i> <a>, GPR <j> <b> | 0x0D | f=1,p=0,s=0 | No |
XORF | GPR <d>, SIGPR <i> <a> << <s>, IGPR <j> <b> | 0x0D | f=0,p=0 | Yes |
XORF | GPR <d>, IGPR <i> <a>, SIGPR <j><b> << <s> | 0x0D | f=0,p=1 | Yes |
XORF | GPR <d>, IGPR <i> <a>, GPR <j> <b> | 0x0D | f=0,p=0,s=0 | No |
TEST | SIGPR <i> <a> << <s>, IGPR <j> <b> | 0x0B | f=1,p=0,d=0 | No |
TEST | IGPR <i> <a>, SIGPR <j><b> << <s> | 0x0B | f=1,p=1,d=0 | No |
TEST | IGPR <i> <a>, GPR <j> <b> | 0x0B | f=1,p=0,s=0,d=0 | No |
Shifts
| Mnemonic | Operands | Opcode | Special Payload Encoding | Canonical |
|---|---|---|---|---|
BSL | GPR <d>, GPR <v>, GPR <q>, GPR <r> | 0x0E | w=0, x=0,c=1 | Yes |
BSLW | GPR <d>, GPR <v>, GPR <q>, GPR <r> | 0x0E | w=1, x=0, c=1 | Yes |
BSLF | GPR <d>, GPR <v>, GPR <q>, GPR <r> | 0x0E | w=0,x=0,f=0 | Yes |
BSLWF | GPR <d>, GPR <v>, GPR <q>, GPR <r> | 0x0E | w=1,x=0,f=0 | Yes |
XBSL | GPR <d>, GPR <v>, GPR <q>, GPR <r> | 0x0E | w=0, x=1,c=1 | Yes |
XBSLW | GPR <d>, GPR <v>, GPR <q>, GPR <r> | 0x0E | w=1, x=1, c=1 | Yes |
XBSLF | GPR <d>, GPR <v>, GPR <q>, GPR <r> | 0x0E | w=0,x=1,f=0 | Yes |
XBSLWF | GPR <d>, GPR <v>, GPR <q>, GPR <r> | 0x0E | w=1,x=1,f=0 | Yes |
SHL | GPR <d>, GPR <v>, GPR <q> | 0x0E | w=0,x=0,c=1,r=0 | No |
SHLW | GPR <d>, GPR <v>, GPR <q> | 0x0E | w=1,x=0,c=1,r=0 | No |
SHLF | GPR <d>, GPR <v>, GPR <q> | 0x0E | w=0,x=0,f=0,r=0 | No |
SHLWF | GPR <d>, GPR <v>, GPR <q> | 0x0E | w=1,x=0,f=0,r=0 | No |
ROL | GPR <d>, GPR <v>, GPR <q> | 0x0E | w=1,x=0,c=1,r=v | No |
ROLF | GPR <d>, GPR <v>, GPR <q> | 0x0E | w=1,x=0,f=0,r=v | No |
BSR | GPR <d>, GPR <v>, GPR <q>, GPR <r> | 0x0F | w=0, x=0,c=1 | Yes |
BSRW | GPR <d>, GPR <v>, GPR <q>, GPR <r> | 0x0F | w=1, x=0, c=1 | Yes |
BSRF | GPR <d>, GPR <v>, GPR <q>, GPR <r> | 0x0F | w=0,x=0,f=0 | Yes |
BSRWF | GPR <d>, GPR <v>, GPR <q>, GPR <r> | 0x0F | w=1,x=0,f=0 | Yes |
XBSR | GPR <d>, GPR <v>, GPR <q>, GPR <r> | 0x0F | w=0, x=1,c=1 | Yes |
XBSRW | GPR <d>, GPR <v>, GPR <q>, GPR <r> | 0x0F | w=1, x=1, c=1 | Yes |
XBSRF | GPR <d>, GPR <v>, GPR <q>, GPR <r> | 0x0F | w=0,x=1,f=0 | Yes |
XBSRWF | GPR <d>, GPR <v>, GPR <q>, GPR <r> | 0x0F | w=1,x=1,f=0 | Yes |
SHR | GPR <d>, GPR <v>, GPR <q> | 0x0F | w=0,x=0,c=1,r=0 | No |
SHRW | GPR <d>, GPR <v>, GPR <q> | 0x0F | w=1,x=0,c=1,r=0 | No |
SHRF | GPR <d>, GPR <v>, GPR <q> | 0x0F | w=0,x=0,f=0,r=0 | No |
SHRWF | GPR <d>, GPR <v>, GPR <q> | 0x0F | w=1,x=0,f=0,r=0 | No |
ROR | GPR <d>, GPR <v>, GPR <q> | 0x0F | w=1,x=0,c=1,r=v | No |
ROLRC | GPR <d>, GPR <v>, GPR <q> | 0x0F | w=1,x=0,f=0,r=v | No |
SAR | GPR <d>, GPR <v>, GPR <q> | 0x0F | w=0,x=1,c=1,r=0 | No |
SARW | GPR <d>, GPR <v>, GPR <q> | 0x0F | w=1,x=1,c=1,r=0 | No |
SARF | GPR <d>, GPR <v>, GPR <q> | 0x0F | w=0,x=1,f=0,r=0 | No |
SARWF | GPR <d>, GPR <v>, GPR <q> | 0x0F | w=1,x=1,f=0,r=0 | No |
Branches
| Mnemonic | Operands | Opcode | Special Payload Encoding | Canonical |
|---|---|---|---|---|
JL<c> | GPR <l>, OFF15 <o> | 0x10 | - | Yes |
JLR<c> | GPR <l>, GPR <r> | 0x11 | - | Yes |
JMP<c> | OFF15 <o> | 0x10 | l=0 | No |
JMPR<c> | GPR <r> | 0x11 | l=0 | No |
JMP | OFF15 <o> | 0x10 | l=0,c=15 | No |
JMPR | GPR <r> | 0x11 | l=0,c=15 | No |
CALL | GPR <l>, OFF16 <o> | 0x10 | c=15 | No |
CALLR | GPR <l>, GPR <r> | 0x11 | c=15 | No |
CALL | OFF16 <o> | 0x10 | l=31,c=15 | No |
CALLR | GPR <r> | 0x11 | l=31,c=15 | No |
IRET | PRIO <p> | 0x12 | - | Yes |
I/O Transfers
| Mnemonic | Operands | Opcode | Special Payload Encoding | Canonical |
|---|---|---|---|---|
IN | IOR <d>, ABSIMM8 <p>, BITW <w> | 0x14 | - | Yes |
OUT | IOR <s>, ABSIMM8 <p>, BITW <w> | 0x15 | - | Yes |
Flags Manipulation
| Mnemonic | Operands | Opcode | Special Payload Encoding | Canonical |
|---|---|---|---|---|
LDFLAGS | GPR <d>, ABSIMM5 <f> | 0x18 | - | Yes |
LDFLAGS | GPR <d> | 0x18 | f=0x1F | No |
STFLAGS | GPR <s>, ABSIMM5 <f> | 0x19 | - | Yes |
STFLAGS | GPR <s> | 0x19 | f=0x1F | No |
XVP | - | 0x1A | - | Yes |
Exchange Register Contents
| Mnemonic | Operands | Opcode | Special Payload Encoding | Canonical |
|---|---|---|---|---|
XCHG<c> | GPR <a>, GPR <b> | 0x1C | l=0 | Yes |
XCHGL<c> | GPR <a>, GPR <b> | 0x1C | l=1 | Yes |
XCHG | GPR <a>, GPR <b> | 0x1C | c=15,l=1 | No |
Extend Register Contents
| Mnemonic | Operands | Opcode | Special Payload Encoding | Canonical |
|---|---|---|---|---|
EXTS | GPR <d>, GPR <s>, BITW <w> | 0x1D | x=1 | Yes |
EXTZ | GPR <d>, GPR <s>, BITW <w> | 0x1D | x=0 | Yes |
Random Bit Generation
| Mnemonic | Operands | Opcode | Special Payload Encoding | Canonical |
|---|---|---|---|---|
RBGEN | GPR <d>, GPR <e>, BITW <w> | 0x1E | - | Yes |
RBGEN | GPR <d>, BITW <w> | 0x1E | e=0 | No |
RBGEN | GPR <d>, GPR <e> | 0x1E | w=0 | No |
RBGEN | GPR <d> | 0x1E | e=0,w=0 | No |
Coprocessor Invocations
| Mnemonic | Operands | Opcode | Special Payload Encoding | Canonical |
|---|---|---|---|---|
CPI<x> | ABSIMM4 <f>, VPAYLOAD20 <p> | 0x20+x | - | Yes |
CPI<x>EF | ABSIMM6 <f>, VPAYLOAD18 <p> | 0x28+x | - | Yes |
NCPI<x> | ABSIMM4 <f>, VPAYLOAD20 <p> | 0x30+x | - | Yes |
NCPI<x>EF | ABSIMM6 <f>, VPAYLOAD20 <p> | 0x38+x | - | Yes |
Stop/Halt
| Mnemonic | Operands | Opcode | Special Payload Encoding | Canonical |
|---|---|---|---|---|
HLT | - | 0x40 | - | Yes |
STP | - | 0x41 | - | Yes |
Psuedo-instructions
Certain Menmonics assembly to a special sequence of instructions and to a link relaxation. These are expressed using macro assembly syntax, but are expected to be treated as intrinsics.
LDIW
.macro ldiw GPR <reg>, UIMM32 <val>
; Emits R_SKYARCH_RELAX16_32 if `val` is a symbol
ldiu <reg>, <val>@LO
addih <reg>, <val>@HI
.endmacro
.macro ldiw GPR <reg>, SIMM32 <val>
; Emits R_SKYARCH_RELAX16_32 if `val` is a symbol
ldiu <reg>, <val>@LO
addih <reg>, <val>@HI
.endmacro
May be converted to either ldi <reg>, <val> if the value is known to be in range
LRAW
Loads a wide relative address
.macro lraw GPR <reg>, PCREL32 <val>
; Emits R_SKYARCH_RELAX16_PC32 if `val` is a symbol
lrau <reg>, <val>@LO
addih <reg>, <val>@HI
.endmacro
may be converted to lra <reg>, val if the value is known to be in range
JMPW/JLW/CALLW
.macro jl<cc>w GPR <link>, PCREL32 <val>, GPR <scratch>=r15
; Emits R_SKYARCH_RELAXJMPOFF_PC32 if `val` is a symbol
lraw <scratch>, <val>
jlr<cc> <link>, <scratch>
.endmacro
.macro jlw GPR <link>, PCREL32 <val>, GPR <scratch>=r15
jlalw <link>, <val>, <scratch>
.endmacro
.macro jmp<cc>w PCREL32 <val>, GPR <scratch>=r15
jl<cc>w r0, <val>, <scratch>
.endmacro
.macro jmpw PCREL32 <val>, GPR <scratch>=r15
jlw r0, <val>, <scratch>
.endmacro
.macro callw PCREL32, GPR <scratch>=r15
jlw r31, <val>, <scratch>
.endmacro
May be converted to jl<cc> (as appropriate) if val is known to be in range.
The value of <scratch> after the psuedo-instruction completes is unspecified (may not have been modified, or may be loaded with any value).