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}