Copyright Information

Skyarch Instruction Set

Gen Design

Word Size: 32 bit

Instruction Size/Alignment: 4 bytes

Variable Sized Instructions: No

Common Flags/Condition Code Driven

Instruction format

8-bit (LSB) opcode followed 24-bit payload.

LSB First Order

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.

Co-processor Registers are available only if the applicable co-processors are connected.

Map 0: General Purpose

Assembly syntax: rn.

All Registers of the Map are defined. Certain Registers have special meaning:

  • r0 is 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.AliasesDescription
0intctlInterrupt Status Register
1intret1Return for Priority 1 Interrupts
2intret2Return for Priority 2 Interrupts
3intret3Return for Priority 3 Interrupts
4ints0Scratch Register
5ints1Scratch Register
6ints2Scratch Register
7ints3Scratch Register
8intd0Misc Config Register
9intd1Misc Config Register
10intd2Misc Config Register
11intd3Misc Config Register
31inttabInterrupt Table Pointer

Reading or Writing an undefined register causes EX[2]. Writing an invalid value to a defined register causes EX[5]

Interrupt Control (Map 1, Register 0)

Format:

+0-----------------------------31+
|mm00000000000000000000000000000a|
+--------------------------------+

(All bits indicated as 0 must be written with 0)

BitsNameDescription
mPriority MaskInterrupts with priority value > m are blocked
aAbort TriggeredSet to 1 when an Abort (Ex[0]) occurs.

Both fields are set to 0 on startup.

Interrupt Priority

Interrupt Priority is used to ensure that overlapping Interrupts do not interefere. 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 less than m. The behaviour depends on the kind of exception:

  • Synchronous Exceptions (other than Abort) Reset the processor if a = 1, else they set a = 1 and raise Ex[0]
  • Asynchronous Events are discarded
  • IRQs are buffered (up to an implementation-specific capacity until an intret occurs that sets m to be 3) 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.

Format:

+0-----------------------------31+
|mmaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+--------------------------------+
BitsNameDescription
mPriority MaskStores the priority mask before the interrupt
aAddressContains the high 30 bits of the return address

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)

Format:

+0-----------------------------32+
|000aaaaaaaaaaaaaaaaaaaaaaaaaaaaa|
+--------------------------------+

(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:

+0-----------------------------31+
|p0tttttttttttttttttttttttttttttt|
+32----------------------------63+
|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.

Interrupts

The first 16 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 the t flag 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 7: Non-maskable Interrupt - May be raised in response to a priority signal external to the processor that requires immediate resolution. This is handled like an IRQ, but does not obey the i flag.
  • Entries 8-15: Co-processor Unit n Error - The corresponding Coprocessor unit n signals an error after a CPIn instruction (n is Exception number - 4).
  • Entries 5, 6, and 16-31 are reserved.

The remaining entries (32-63), may be allocated as IRQ vectors.

Exceptions are raised regardless of the i bit. The t bit is set to 1 when an exception is raised. It is not modified by any other interrupt (including an NMI) being raised.

If an exception occurs raising EX[0], the processor RESETs.

Map 2: I/O Transfer Registers

Map 2 defines a sequence of input and output shift registers for transfering data to external peripherals.

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.

Register N in Map 4 is defined if Co-processor N is present and enabled.

Reads and writes to an undefined register or a register corresponding to a not-present or disabled coprocessor results in EX[2].

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.

Format:

+0-----------------------------32+
|EEEEEEEE000000000000000000000000|
+--------------------------------+

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.

Bits marked as 0 must not be written with 1.

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. Attempting such a write with a MOV instruction raises EX[2].

Format:

+0-----------------------------32+
|PPPPPPPP000000000000000000000000|
+--------------------------------+

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.

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)
  • IP is initialized to 0xFF00.
  • cpe is set to 0.
  • ictl is set to m=0, a=0

All other registers, including flags, have undefined values.

Instructions

Undefined Instructions

MnemonicOpcodePayload
0--78---------------------31
UND0x00-
UND0xFF-

(The Payload bits are ignored by both instructions)

Timing (Execute Latency): 0 cycles

Exception Order:

  • EX[2] (decode): Unconditionally

Behaviour: Unconditionally raises Invalid Instruction errors

instruction UND():
    Raise(EX[2])

Pause

MnemonicOpcodePayload
0--78---------------------31
PAUSE0x01kkkkkk000000000000000000

Timing (Execute Latency): 0 cycles + k

Behaviour: Delays execution for k cycles, 0-63

instruction PAUSE(k: u6):
    SuspendForClockTicks(k)

Move

MnemonicOpcodePayload
0--78---------------------32
MOV0x02dddddsssss00lccccrmmmm00

Payload Bits Legend:

  • d: Destination Register
  • s: Source Register
  • m: Map
  • r: Direction
  • c: Condition Code (See Jump)
  • l: Latency Control

Timing (Execute Latency): 1+c+t, where:

  • c is 0 if Condition Code is 0, 1 if Condition Code is 15 or Latency Control is 0 and the Condition Check Fails, 2 if Latency Control is 1 or the Condition Code is not 15 and the Condition Check Succeeds
  • t is 0 if Map is 0 or Latency Control is 0 and the Condition Check Fails, 2 if Map is not 0 when Latency Control is 1 or the Condition Check Succeeds.

Behaviour: 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 == 2 or m > 3:
            ValidateConfigurationRegisterValue(d, val);
        WriteRegister(md, d, val);
    else:
        if l:
            if m!=0:
                SuspendForClockTicks(4);
            else:
                SuspendForClockTicks(2);

LD/ST

MnemonicOpcodePayload
0--78---------------------32
ST0x03dddddsssssww0000000000mm
LD0x04dddddsssssww0000000000mm
LDI0x05dddddx00iiiiiiiiiiiiiiii
LRA0x06dddddx00oooooooooooooooo

Payload Bits Legend:

  • s: Source Register
  • d: Destination Register
  • w: Width
  • i: Immediate Value
  • o: Offset
  • q: Scale Quantity
  • m: Update mode
  • x: Sign/Zero Extend

Timing:

  • ST, LD: 4 Cycles, plus Memory Delay
  • LDI, LRA: 1 Cycle

Behaviour:

  • ST: Stores 1 << w bytes from d to [s]
  • LD: Loads 1 << w bytes from [s] into d
  • LDI: Loads an immediate i (sign or zero exteneded) into the first (h=0) 16 bits of d
  • LRA: Loads the address IP + o (o is a signed immediate if x is true, and an unsigned immediate otherwise) into d. IP is taken from the beginning of the next instruction

enum UpdateMode:
    None = 0,
    PostInc = 1,
    /* Illegal = 2 */,
    PreDec = 3,

instruction ST(s: u5, d: u5, w: u2, m: UpdateMode):
    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])

    WriteAlignedMemoryTruncate(addr, val, width);
    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 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);
    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: u15):
    let val = SignExtendOrZeroExtend(i, x) + IP;
    WriteRegister(0,d,val);

Immediate Arithmetic

MnemonicOpcodePayload
0--78---------------------31
ADDI0x08dddddxfhiiiiiiiiiiiiiiii

Timing: 2 Payload Bits Legend:

  • d: Destination Register
  • h: High half
  • x: Extend Sign
  • f: Surpress Flags Modification
  • i: Immediate

Behaviour: Adds a 12-bit zero or sign-extended immediate to d.

ALU Instructions

MnemonicOpcodePayload
0--78---------------------31
ADD0x09dddddaaaaabbbbbfsssssp0c
SUB0x0Adddddaaaaabbbbbfsssssp0c
AND0x0Bdddddaaaaabbbbbfssssspij
OR0x0Cdddddaaaaabbbbbfssssspij
XOR0x0Ddddddaaaaabbbbbfssssspij

Timing: 2

Payload Bits Legend:

  • a: Source Register 1
  • b: Source Register 2
  • d: Destination Register
  • f: Suppress Flags Modification
  • c: Carry in
  • p: Shift Polarity
  • s: Shift Quantity
  • i: Invert op 1
  • j: Invert op 2

Behaviour:

instruction {ADD, SUB}(a: u5, b: u5, d: u5, c: 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 not c:
        SetFlagsRegisterByMask(flags_mask, flags_val);

instruction {AND, OR, XOR}(a: u5, b: u5, d: u5, c: 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: u4;
    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 not c:
        SetFlagsRegisterByMask(flags_mask, flags_val);

Funnel Shifts

MnemonicOpcodePayload
0--78---------------------31
FSL0x0Edddddvvvvvqqqqqfx0wrrrrr
FSR0x0Fdddddvvvvvqqqqqfx0wrrrrr

Timing: 3

Payload Bits Legend:

  • d: Destination Register
  • v: Input Value
  • q: Shift Quantity
  • f: Suppress Flags Modification
  • w: Wrap Quantity
  • r: Shift Remainder (Input value)
  • x: Invert by Sign

Behaviour: 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.

instruction FSL(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;
    
    if w:
        quantity = quantity & 31;
    

    let result = ShiftInLeft(val, remainder, quantity);
    WriteRegister(0, d);

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;
    
    if w:
        quantity = quantity & 31;
    

    let result = ShiftInRight(val, remainder, quantity);
    WriteRegister(0, d);

Branches

MnemonicOpcodePayload
0--78---------------------31
JMP0x10cccclllllooooooooooooooo
JMPR0x11cccclllllrrrrr0000000000
IRET0x12pp0000000000000000000000

Payload Bits Legend:

  • c: Condition Code
  • l: Link Register
  • o: Destination Offset (Bits 2..17)
  • r: Destination Register
  • p: Target Interrupt Priority

Timing: 2+t+l+r where:

  • t is 1 if the branch is taken and 0 if it is not taken
  • l is 1 if Link Register is non-zero and the branch is taken, and 0 otherwise
  • r is 1 for JMPR and 0 for JMP

Behaviour: Jumps to the destination, if the condition is satisfied, saving the return address in l if taken:

  • JMP: The offset is IP + o * 4 where o is a signed offset. IP is the same as the return address and points to the beginning of the next instruction
  • JMPR: The offset is read from r
  • IRET: The offset it read from register p (p!=0) in Map 1. intctl.m is also loaded from p.m and intctl.a is 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);
        IP = curr_ip + disp;

instruction JMPR(c: ConditionCode, l: u5, r: u5):
    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);
        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;
    IP = addr;
    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

MnemonicOpcodePayload
0--78---------------------31
IN0x14dddddpppppppp000000wwwww
OUT0x15ssssspppppppp000000wwwww

Payload Bits Legend:

  • s: Source Transfer Register
  • d: Destination Transfer Register
  • w: Transfer Bit Width
  • p: Port Number

Timing: 7 + Port Delay

Behaviour: 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 register
  • OUT: Shifts bits out of the low bits of the transfer register
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

MnemonicOpcodePayload
0--78---------------------31
LDFLAGS0x18dddddfffff00000000000000
STFLAGS0x19sssssfffff00000000000000
XVP0x1A000000000000000000000000

Payload Bits Legend:

  • s: Source Register
  • d: Destination Register
  • f: Flag modification mask

Timing: 1

Behaviour:

  • LDFLAGS loads the flags bits into the lower 5 bits of d (zero extended)
  • STFLAGS stores the lower 5 bits of s into the flags bits, overwriting only flags set to 1 in f
  • XVP exchanges the v and p flags

The Flags Bits are:

0---4
cvnzp
  • c: Carry
  • v: Signed Overflow
  • n: Negative
  • z: Zero
  • p: Parity
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

MnemonicOpcodePayload
0--78---------------------31
XCHG0x1Caaaaabbbbb00lcccc0000000

Payload Bits Legend:

  • a: Register 1
  • s: Register 2
  • c: Condition Code (See Jump)
  • l: Latency Control

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

MnemonicOpcodePayload
0--78---------------------31
EXT0x1Ddddddsssssx00000000wwwww

Payload Bits Legend:

  • d: Destination
  • s: Source
  • x: Extend Kind (sign/zero)
  • w: Value width

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):
    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);

Random Bits

MnemonicOpcodePayload
0--78---------------------31
RBGEN0x1Edddddeeeee000000000wwwww

Payload Bits Legend:

  • d: Destination
  • e: Status Destination
  • w: Poll width

Behaviour: 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 all previous outputs
  • 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:

+--------------------------------+
|eeeeeeeeeeeeeeeess0000000000000r|
+--------------------------------+
BitNameDescription
eEnthropy AvailableTotal ratio of enthropy available (*2^16)
sStatus CodeStatus code (See Below)
rRepeatableIf set to 1, operation may be retried immediately

The following status code values are used

Status CodeNameDescription
0NORMALNormal status/spurious failure
1UNAVAILRequired minimum enthropy unavailable
2PAUSEGenerator Paused/Errored (Recoverable)
3FAULTUnrecoverable 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

MnemonicOpcodePayload
0--78---------------------31
CPIx0x20+xffffpppppppppppppppppppp
NCPIx0x28+xffffpppppppppppppppppppp
CPIxEF0x30+xffffffpppppppppppppppppp
NCPIxEF0x38+xffffffpppppppppppppppppp

(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)

Timing: 2 + N where:

  • For CPIx and CPIxEF, N is the delay in cycles before the co-processor becomes ready to execute again
  • For NCPIx and NCPIxEF, N is 0.

Payload Bits Legend:

  • f: Co-processor function
  • p: Co-processor instruction payload

Behaviour: 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 payload
  • CPIxEF/NCPIxEF: Allows specifying up to 64 functions with a 18-bit payload (bottom 18-bits of the 20-bit payload)
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);
    if PullCoprocessorException(coproc):
        Raise(Ex[4+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);
    if PullCoprocessorException(coproc):
        Raise(Ex[4+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

MnemonicOpcodePayload
0--78---------------------31
HALT0x40000000000000000000000000
STOP0x41000000000000000000000000

Timing:

  • HALT: 1
  • STOP: N/A

Behaviour: Places the CPU in a low-power state and stops executing

  • HALT: Execution resumes after an NMI, IRQ (if enabled), Unit Error (if sysctl.t=0), or RESET.
  • STOP: Execution resumes after a RESET only. No other interrupts are serviced.
instruction HALT() {
    SetStatus(2);
    WaitForInterrupt();
}
instruction STOP() {
    SetStatus(3);
    ShutdownCpu();
}

!{#copyright}

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

MnemonicOpcodepppppppppppppppppppp
0--34-----------------20
CRMOV0x01dddddsssss0000000000
CRLD0x02dddddsssssww00000000
CRST0x03dddddsssssww00000000
CRLDB0x04dddd0ssssscccc000000
CRSTB0x05dddd0ssssscccc000000

Comparison

MnemonicOpcodepppppppppppppppppppp
0--34-----------------20
CRCMP0x0Fdddddaaaa0bbbb0r00tt

Bits:

  • d: Destination Register
  • a: First working register to compare
  • b: Second working register to compare
  • r: Overwrite Condition Mask
  • t: 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.

MnemonicOpcodepppppppppppppppppppp
0----54---------------18
SHA32SIG0o0020ssssrrrrwwwwvvvv00
SHA32SUM0o0021ssssrrrraaaaeeee00
SHA32CHM0o0022ddddaaaabbbbcccc0m
SHA2IV0o0023ddddiiii0000000l00
SHA2RC0o0024ddddkkkkk000000l00

psABI

Types

C Primitive Sizes

CHAR_BIT is 8.

TypeSize
bool11
short2
int4
long4
long long8
float4
double8
long double8
void*4
intptr_t4
size_t4
intmax_t8
wchar_t4

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)PurposeCallee/Caller Saved
r0Constant 0Constant Register
r1Param/Return RegisterCaller Saved
r2Param/Return RegisterCaller Saved
r3-r10Param RegisterCaller Saved
r11-r14Scratch RegisterCaller Saved
r15Special-Purpose Scratch RegisterCaller Saved
r16-r27Callee Saved RegisterCallee Saved
r28-r29Reserved RegisterCallee Saved/Reserved
r30Stack PointerCallee Saved
r31Return PointerCallee Saved

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.

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.

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. Any chunk which is not present or consists entirely of padding bytes is discarded when passing directly. Then, each chunk in parameter order (with least significant byte first) is passed by allocating the next available register in r1-r10. 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

OSABIConstantDescription
0-63MultipleSee gABI OSABI list
240OSABILOPRIVLowest value of Private Use Area
253OSABIHIPRIVHighest value of the Private Use Area
254OSABIEXTReserved for OSABI extension
255OSABISTANDALONEStandalone/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 NameRelocation NumberSizeValidationValueDescription
R_SKYARCH_NONE00 bitsN/A0Performs no Operation
R_SKYARCH_32132 bitsUnsignedSRelocates against an absolute 32-bit address
R_SKYARCH_PC32232 bitsSignedS-IPRelocates against the 32-bit offset from the current address
R_SKYARCH_LO16316 bitsNoneTRUNC(S)Relocates against the lower 16 bits of an absolute 32-bit address
R_SKYARCH_PC16416 bitsSignedS-IPRelocates against the 16-bit offset from the current address
R_SKYARCH_LOPC16516 bitsNoneTRUNC(S-IP)Relocates against the lower 16 bits of a 32-bit offset from the current address
R_SKYARCH_HI16616 bitsUnsignedS>>16Relocates against the upper 16-bits of an absolute 32-bit address
R_SKYARCH_HIPC16716 bitsSigned(S-IP)>>16Relocates against the upper 16-bits of a 32-bit offset
R_SKYARCH_JMPO816 bitsSigned(S-IP)>>2Relocates 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_PC323264 bitsN/AN/AHints 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_323364 bitsN/AN/AHints 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_PC323496 bitsN/AN/AHints 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/A35-630 bitsN/AN/AReserved 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.

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}


  1. Referred to as _Bool in C since C99 until C23.

Assembly Syntax

Operands

The following operand syntax types are used in instructions

ShortNameDescription
GPRGPR operandA General Purpose Register
IGPRInvertible GPR OperandA potentially inverted gpr operand
SGPRShifted GPR operandA General Purpose Register Left-shifted by a constant
SIGPRShifted Invertible GPR operandA potentially inverted gpr operand Left-shifed by a constant
IORI/O Register operandAn I/O Transfer Register (Map 3)
ANYREGAny RegisterAny Register operand
UIMM16Immediate (unsigned 16-bit)16-bit Immediate operand
SIMM16Immediate (signed 16-bit)16-bit Immediate operand
PCREL16PC Relative Address (16-bit)16-bit offset from IP in bytes
PCREL32PC Relative Address (32-bit)32-bit offset from IP in bytes
OFF17Jump Offset (signed 20-bit)20-bit jump offset in words
UIMM32Immediate (unsigned 32-bit)32-bit immediate operand
SIMM32Immediate (signed 32-bit)32-bit immediate operand
BITWBit WidthWidth of a value in bits
BYTESZByte SizeSize of a value in bytes
ABSIMM2Immediate (unsigned 2-bit)2-bit absolute (non-relocated) immediate
ABSIMM3Immediate (unsigned 3-bit)3-bit absolute (non-relocated) immediate
ABSIMM5Immediate (unsigned 5-bit)5-bit absolute (non-relocated) immediate
ABSIMM6Immediate (unsigned 6-bit)6-bit absolute (non-relocated) immediate
ABSIMM8Immediate (unsigned 8-bit)8-bit absolute (non-relocated) immediate
CCCondition Code NameA condition Code
PRIOInterrupt PriorityAn 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_PC16
  • R_MICRON_LOPC16 (LO <sym>@pcrel)
  • R_MICRON_HIPC16 (HI <sym>@pcrel)

Offsets

The PCREL16 and OFF15 values are special cases of immediates. PCREL16 is identical to a SIMM16 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: 8
  • half: 16
  • word: 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: 1
  • async: 2
  • irq: 3

Condition Code

Condition Codes appear only in mnemonics, and use the following 1 or 2 character short forms:

Short FormCondition NameNumberCanonical
NVNever0Yes
CCarry1Yes
BBelow1No
ZZero2Yes
EQEqual2No
OOverflow3Yes
CECarry/Equal4Yes
BEBelow or Equal4No
LTLess5Yes
LELess or Equal6Yes
NNegative7Yes
SSigned7No
PPositive8Yes
NSNot Signed8No
GTGreater Than9Yes
NLENot Less or Equal9No
GEGreater or Equal10Yes
NLTNot Less10No
AAbove11Yes
NBENot Below or Equal11No
NCENot Carry or Equal11No
NONot Overflow12Yes
NZNot Zero13Yes
NENot Equal13No
NCNot Carry14Yes
NBNot Below14No
AEAbove or Equal14No
ALAlways15Yes

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. c is as if defined CC <c> and x is as if defined ABSIMM2 <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 x if defined in the Mnemonic.
  • Special Payload Encoding: A list of variable assignments of the form <var>=<val> where var is an encoding variable defined for the opcode in the ISA Spec, and val is 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 variable P refers 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 .instr directive). 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

MnemonicOperandsOpcodeSpecial Payload EncodingCanonical
UND-0x00P=0Yes

PAUSE

MnemonicOperandsOpcodeSpecial Payload EncodingCanonical
PAUSEABSIMM6 <k>0x01N/AYes
NOP-0x01k=0No

MOV

MnemonicOperandsOpcodeSpecial Payload EncodingCanonical
MOV<c>GPR <d>, GPR <s>0x02m=0, r=0, l=0Yes
MOV<c>GPR <d>, ANYREG <s>0x02m=MAP(s), r=0, l=0Yes
MOV<c>ANYREG <d>, GPR <s>0x02m=MAP(d), r=1, l=0Yes
MOVGPR <d>, GPR <s>0x02m=0, r=0, l=0, c=15No
MOVGPR <d>, ANYREG <s>0x02m=MAP(s), r=0, l=0, c=15No
MOVANYREG <d>, GPR <s>0x02m=MAP(d), r=1, l=0, c=15No
MOVL<c>GPR <d>, GPR <s>0x02m=0, r=0, l=1Yes
MOVL<c>GPR <d>, ANYREG <s>0x02m=MAP(s), r=0, l=1Yes
MOVL<c>ANYREG <d>, GPR <s>0x02m=MAP(d), r=1, l=1Yes

LD/ST

MnemonicOperandsOpcodeSpecial Payload EncodingCanonical
LDGPR <d>, GPR <s>, BYTESZ <w>0x03p=0Yes
STGPR <d>, GPR <s>, BYTESZ <w>0x04p=0Yes
LDGPR <d>, GPR <s>0x03p=0,w=4No
STGPR <d>, GPR <s>0x04p=0,w=4No
PUSHGPR <d>, GPR <s>, BYTESZ <w>0x04p=1Yes
POPGPR <d>, GPR <s>, BYTESZ <w>0x03p=1Yes
PUSHGPR <d>, GPR <s>0x04p=1,w=4No
POPGPR <d>, GPR <s>0x03p=1,w=4No
PUSHGPR <s>0x04p=1,w=4,d=30No
POPGPR <d>0x03p=1,w=4,d=30No

Load/Add Immediates

MnemonicOperandsOpcodeSpecial Payload EncodingCanonical
LDIGPR <d>, SIMM16 <i>0x05x=1Yes
LDIUGPR <d>, UIMM16 <i>0x05x=0Yes
LRAGPR <d>, PCREL16 <i>0x06x=1Yes
LRAUGPR <d>, UPCREL16 <i>0x06x=0Yes
ADDIGPR <d>, SIMM16 <i>0x08x=1,f=1,h=0Yes
ADDIFGPR <d>, SIMM16 <i>0x08x=1,f=0,h=0Yes
ADDIUGPR <d>, UIMM16 <i>0x08x=0,f=1,h=0Yes
ADDIHGPR <d>, UIMM16 <i>0x08x=0,f=1,h=1Yes
ADDIHGPR <d>, SIMM16 <i>0x08x=0,f=1,h=1No
ADDIUFGPR <d>, UIMM16 <i>0x08x=0,f=0,h=0Yes
ADDIHFGPR <d>, UIMM16 <i>0x08x=0,f=0,h=1Yes
ADDIHFGPR <d>, SIMM16 <i>0x08x=0,f=0,h=1No
INCGPR <d>0x08x=0,f=1,h=0,i=1No
DECGPR <d>0x08x=1,f=1,h=0,i=0xFFFFNo

Arithmetic Ops

MnemonicOperandsOpcodeSpecial Payload EncodingCanonical
ADDGPR <d>, SGPR <a> << <s>, GPR <b>0x09f=1,p=0Yes
ADDGPR <d>, GPR <a>, SGPR <b> << <s>0x09f=1,p=1Yes
ADDGPR <d>, GPR <a>, GPR <b>0x09f=1,p=0,s=0No
ADDFGPR <d>, SGPR <a> << <s>, GPR <b>0x09f=0,p=0Yes
ADDFGPR <d>, GPR <a>, SGPR <b> << <s>0x09f=0,p=1Yes
ADDFGPR <d>, GPR <a>, GPR <b>0x09f=0,p=0,s=0No
SUBGPR <d>, SGPR <a> << <s>, GPR <b>0x0Af=1,p=0Yes
SUBGPR <d>, GPR <a>, SGPR <b> << <s>0x0Af=1,p=1Yes
SUBGPR <d>, GPR <a>, GPR <b>0x0Af=1,p=0,s=0No
SUBFGPR <d>, SGPR <a> << <s>, GPR <b>0x0Af=0,p=0Yes
SUBFGPR <d>, GPR <a>, SGPR <b> << <s>0x0Af=0,p=1Yes
SUBFGPR <d>, GPR <a>, GPR <b>0x0Af=0,p=0,s=0No
CMPSGPR <a> << <s>, GPR <b>0x0Af=0,p=0,d=0No
CMPGPR <a>, SGPR <b> << <s>0x0Af=0,p=1,d=0No
CMPGPR <a>, GPR <b>0x0Af=0,p=0,s=0,d=0No
SHLGPR <d>, GPR <a>, ABSIMM5 <s>0x09f=1,p=0,b=0No
SHLFGPR <d>, GPR <a>, ABSIMM5 <s>0x09f=2,p=0,b=0No

Logic Ops

MnemonicOperandsOpcodeSpecial Payload EncodingCanonical
ANDGPR <d>, SIGPR <i> <a> << <s>, IGPR <j> <b>0x0Bf=1,p=0Yes
ANDGPR <d>, IGPR <i> <a>, SIGPR <j><b> << <s>0x0Bf=1,p=1Yes
ANDGPR <d>, IGPR <i> <a>, GPR <j> <b>0x0Bf=1,p=0,s=0No
ANDFGPR <d>, SIGPR <i> <a> << <s>, IGPR <j> <b>0x0Bf=0,p=0Yes
ANDFGPR <d>, IGPR <i> <a>, SIGPR <j><b> << <s>0x0Bf=0,p=1Yes
ANDFGPR <d>, IGPR <i> <a>, GPR <j> <b>0x0Bf=0,p=0,s=0No
ORGPR <d>, SIGPR <i> <a> << <s>, IGPR <j> <b>0x0Cf=1,p=0Yes
ORGPR <d>, IGPR <i> <a>, SIGPR <j><b> << <s>0x0Cf=1,p=1Yes
ORGPR <d>, IGPR <i> <a>, GPR <j> <b>0x0Cf=1,p=0,s=0No
ORFGPR <d>, SIGPR <i> <a> << <s>, IGPR <j> <b>0x0Cf=0,p=0Yes
ORFGPR <d>, IGPR <i> <a>, SIGPR <j><b> << <s>0x0Cf=0,p=1Yes
ORFGPR <d>, IGPR <i> <a>, GPR <j> <b>0x0Cf=0,p=0,s=0No
XORGPR <d>, SIGPR <i> <a> << <s>, IGPR <j> <b>0x0Df=1,p=0Yes
XORGPR <d>, IGPR <i> <a>, SIGPR <j><b> << <s>0x0Df=1,p=1Yes
XORGPR <d>, IGPR <i> <a>, GPR <j> <b>0x0Df=1,p=0,s=0No
XORFGPR <d>, SIGPR <i> <a> << <s>, IGPR <j> <b>0x0Df=0,p=0Yes
XORFGPR <d>, IGPR <i> <a>, SIGPR <j><b> << <s>0x0Df=0,p=1Yes
XORFGPR <d>, IGPR <i> <a>, GPR <j> <b>0x0Df=0,p=0,s=0No
TESTSIGPR <i> <a> << <s>, IGPR <j> <b>0x0Bf=1,p=0,d=0No
TESTIGPR <i> <a>, SIGPR <j><b> << <s>0x0Bf=1,p=1,d=0No
TESTIGPR <i> <a>, GPR <j> <b>0x0Bf=1,p=0,s=0,d=0No

Shifts

MnemonicOperandsOpcodeSpecial Payload EncodingCanonical
BSLGPR <d>, GPR <v>, GPR <q>, GPR <r>0x0Ew=0, x=0,c=1Yes
BSLWGPR <d>, GPR <v>, GPR <q>, GPR <r>0x0Ew=1, x=0, c=1Yes
BSLFGPR <d>, GPR <v>, GPR <q>, GPR <r>0x0Ew=0,x=0,f=0Yes
BSLWFGPR <d>, GPR <v>, GPR <q>, GPR <r>0x0Ew=1,x=0,f=0Yes
XBSLGPR <d>, GPR <v>, GPR <q>, GPR <r>0x0Ew=0, x=1,c=1Yes
XBSLWGPR <d>, GPR <v>, GPR <q>, GPR <r>0x0Ew=1, x=1, c=1Yes
XBSLFGPR <d>, GPR <v>, GPR <q>, GPR <r>0x0Ew=0,x=1,f=0Yes
XBSLWFGPR <d>, GPR <v>, GPR <q>, GPR <r>0x0Ew=1,x=1,f=0Yes
SHLGPR <d>, GPR <v>, GPR <q>0x0Ew=0,x=0,c=1,r=0No
SHLWGPR <d>, GPR <v>, GPR <q>0x0Ew=1,x=0,c=1,r=0No
SHLFGPR <d>, GPR <v>, GPR <q>0x0Ew=0,x=0,f=0,r=0No
SHLWFGPR <d>, GPR <v>, GPR <q>0x0Ew=1,x=0,f=0,r=0No
ROLGPR <d>, GPR <v>, GPR <q>0x0Ew=1,x=0,c=1,r=vNo
ROLFGPR <d>, GPR <v>, GPR <q>0x0Ew=1,x=0,f=0,r=vNo
BSRGPR <d>, GPR <v>, GPR <q>, GPR <r>0x0Fw=0, x=0,c=1Yes
BSRWGPR <d>, GPR <v>, GPR <q>, GPR <r>0x0Fw=1, x=0, c=1Yes
BSRFGPR <d>, GPR <v>, GPR <q>, GPR <r>0x0Fw=0,x=0,f=0Yes
BSRWFGPR <d>, GPR <v>, GPR <q>, GPR <r>0x0Fw=1,x=0,f=0Yes
XBSRGPR <d>, GPR <v>, GPR <q>, GPR <r>0x0Fw=0, x=1,c=1Yes
XBSRWGPR <d>, GPR <v>, GPR <q>, GPR <r>0x0Fw=1, x=1, c=1Yes
XBSRFGPR <d>, GPR <v>, GPR <q>, GPR <r>0x0Fw=0,x=1,f=0Yes
XBSRWFGPR <d>, GPR <v>, GPR <q>, GPR <r>0x0Fw=1,x=1,f=0Yes
SHRGPR <d>, GPR <v>, GPR <q>0x0Fw=0,x=0,c=1,r=0No
SHRWGPR <d>, GPR <v>, GPR <q>0x0Fw=1,x=0,c=1,r=0No
SHRFGPR <d>, GPR <v>, GPR <q>0x0Fw=0,x=0,f=0,r=0No
SHRWFGPR <d>, GPR <v>, GPR <q>0x0Fw=1,x=0,f=0,r=0No
RORGPR <d>, GPR <v>, GPR <q>0x0Fw=1,x=0,c=1,r=vNo
ROLRCGPR <d>, GPR <v>, GPR <q>0x0Fw=1,x=0,f=0,r=vNo
SARGPR <d>, GPR <v>, GPR <q>0x0Fw=0,x=1,c=1,r=0No
SARWGPR <d>, GPR <v>, GPR <q>0x0Fw=1,x=1,c=1,r=0No
SARFGPR <d>, GPR <v>, GPR <q>0x0Fw=0,x=1,f=0,r=0No
SARWFGPR <d>, GPR <v>, GPR <q>0x0Fw=1,x=1,f=0,r=0No

Branches

MnemonicOperandsOpcodeSpecial Payload EncodingCanonical
JL<c>GPR <l>, OFF15 <o>0x10-Yes
JLR<c>GPR <l>, GPR <r>0x11-Yes
JMP<c>OFF15 <o>0x10l=0No
JMPR<c>GPR <r>0x11l=0No
JMPOFF15 <o>0x10l=0,c=15No
JMPRGPR <r>0x11l=0,c=15No
CALLGPR <l>, OFF16 <o>0x10c=15No
CALLRGPR <l>, GPR <r>0x11c=15No
CALLOFF16 <o>0x10l=31,c=15No
CALLRGPR <r>0x11l=31,c=15No
IRETPRIO <p>0x12-Yes

I/O Transfers

MnemonicOperandsOpcodeSpecial Payload EncodingCanonical
INIOR <d>, ABSIMM8 <p>, BITW <w>0x14-Yes
OUTIOR <s>, ABSIMM8 <p>, BITW <w>0x15-Yes

Flags Manipulation

MnemonicOperandsOpcodeSpecial Payload EncodingCanonical
LDFLAGSGPR <d>, ABSIMM5 <f>0x18-Yes
LDFLAGSGPR <d>0x18f=0x1FNo
STFLAGSGPR <s>, ABSIMM5 <f>0x19-Yes
STFLAGSGPR <s>0x19f=0x1FNo
XVP-0x1A-Yes

Exchange Register Contents

MnemonicOperandsOpcodeSpecial Payload EncodingCanonical
XCHG<c>GPR <a>, GPR <b>0x1Cl=0Yes
XCHGL<c>GPR <a>, GPR <b>0x1Cl=1Yes
XCHGGPR <a>, GPR <b>0x1Cc=15,l=1No

Extend Register Contents

MnemonicOperandsOpcodeSpecial Payload EncodingCanonical
EXTSGPR <d>, GPR <s>, BITW <w>0x1Dx=1Yes
EXTZGPR <d>, GPR <s>, BITW <w>0x1Dx=0Yes

Random Bit Generation

MnemonicOperandsOpcodeSpecial Payload EncodingCanonical
RBGENGPR <d>, GPR <e>, BITW <w>0x1E-Yes
RBGENGPR <d>, BITW <w>0x1Ee=0No
RBGENGPR <d>, GPR <e>0x1Ew=0No
RBGENGPR <d>0x1Ee=0,w=0No

Coprocessor Invocations

MnemonicOperandsOpcodeSpecial Payload EncodingCanonical
CPI<x>ABSIMM4 <f>, VPAYLOAD20 <p>0x20+x-Yes
CPI<x>EFABSIMM6 <f>, VPAYLOAD18 <p>0x28+x-Yes
NCPI<x>ABSIMM4 <f>, VPAYLOAD20 <p>0x30+x-Yes
NCPI<x>EFABSIMM6 <f>, VPAYLOAD20 <p>0x38+x-Yes

Stop/Halt

MnemonicOperandsOpcodeSpecial Payload EncodingCanonical
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).

Contributors