this defines the IRRE
(v1.5) specification.
The Irrelevant Utility Architecture (IRRE) is a capable, general-purpose machine with a minimalist design that is easy to work with while also being well suited for a variety of computational tasks.
It derives many aspects of its architecture design from the REGULAR architecture, notably most of its registers and instruction encoding, and some of its instruction set. For example, IRRE adds several control flow instructions and has different semantics for the load and store instructions. However, IRRE contains many breaking changes to the REGULAR specification and is neither forwards nor backwards compatible with REGULAR. Despite that, since both architectures share many aspects, porting from REGULAR to IRRE should be fairly straightforward.
The little-endian, 32-bit architecture boasts 37 scalar registers, of which 32 (all but 5 special registers) are available for general purpose use. The instruction set is cleanly designed to simplify unambiguous decoding, and it is kept deliberately minimal to facilitate different programming styles, reduce implementation complexity, and allow for expansion in the future.
IRRE exposes 37, 32-bit registers to the programmer. The first 32 of these are named sequentially from r0
to r31
, all of which are identical and may be used interchangeably and as the argument to any instruction where appropriate.
In addition to these are 5 special registers, comprising a program counter, pc
, a return address or link register lr
, two special temporaries ad
and at
, and a stack pointer, sp
.
Registers r0
to r31
are encoded using 0x00
to 0x1f
, pc
is 0x20
, lr
is 0x21
, ad
is 0x22
, at
is 0x23
, and sp
is 0x24
.
All registers can be read and operated on by instructions; such operations are functionally identical on all registers. However, note that writing to pc
can alter program flow.
To simplify function calls for control flow using a execution stack, it is recommended to implement the interprocedural application binary interface (ABI) as follows:
[WIP]
Each IRRE instruction is 32 bits wide. The first byte encodes the opcode, while the remaining three bytes encode register information or immediate values. Register information is encoded in a single byte corresponding to the index of the register in the order specified in the registers section.
For the purposes of instruction encoding, op is the numerical value of the opcode identifying the instruction, rA, rB, rC, … are registers (not necessarily distinct) with the letters standing in for the register's number, and v0, v1, ... are immediate constants embedded in the instruction.
The following are possible encodings for the types of instructions that IRRE supports:
Bit | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Use | op | ignored |
Bit | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Use | op | A | ignored |
Bit | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Use | op | v0 |
Bit | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Use | op | A | v0 |
Bit | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Use | op | A | B | ignored |
Bit | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Use | op | A | B | v0 |
Bit | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Use | op | A | v0 | v1 |
Bit | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Use | op | A | B | C |
The bits of each component of these instructions are laid out so that the lower bits of their numerical value corresponds to lower bit numbers for the instruction as a whole.
Name | Encoding | Description |
---|---|---|
nop |
0x00 | Perform no operation. |
add |
0x01 rA rB rC | Perform an unsigned 32-bit addition of the values contained in rB and rC and store the result in rA. |
sub |
0x02 rA rB rC | Perform an unsigned 32-bit subtraction of the value contained in rC from the value contained in rB and store the result in rA. |
and |
0x03 rA rB rC | Perform a logical AND operation of the values contained in rB and rC and store the result of the operation in rA. |
orr |
0x04 rA rB rC | Perform a logical OR operation of the values contained in rB and rC and store the result of the operation in rA. |
xor |
0x05 rA rB rC | Perform a logical XOR operation of the values contained in rB and rC and store the result of the operation in rA. |
not |
0x06 rA rB | Perform a logical NOT of the value contained in rB and store the result in rA. |
lsh |
0x07 rA rB rC | Logically shift the value in rB by the number of bits represented by the signed quantity in rC. If this value is positive, shift the value contained in rB left by this many bits; if it is negative the shift will be to the right by the absolute value of the value in rC. In both instances newly vacated bits will be zeroed. If the value in rC is outside of the range (-32, 32) the result is undefined. |
ash |
0x08 rA rB rC | Arithmetically shift the value in rB by the number of bits represented by the signed quantity in rC. If this value is positive, shift the value contained in rB left by this many bits; if it is negative the shift will be to the right by the absolute value of the value in rC. Newly vacated bits will be zeroed in the former case and be a duplicate of the most significant bit in the latter. If the value in rC is outside of the range (-32, 32) the result is undefined. |
tcu |
0x09 rA rB rC | Subtract the unsigned value stored in rC from the unsigned value stored in rB with arbitrary precision and store the sign of the result in rA. |
tcs |
0x0a rA rB rC | Subtract the signed value stored in rC from the signed value stored in rB with arbitrary precision and store the sign of the result in rA. |
set |
0x0b rA v0 | Store the 16-bit unsigned value v0 into rA. |
mov |
0x0c rA rB | Copy the value from rB into rA. |
ldw |
0x0d rA rB v0 | Read a 32-bit word from the memory address referred to by rB, signed offset by v0, and store the value into rA. If the address is not word-aligned, the result is implementation-defined. |
stw |
0x0e rA rB v0 | Store the value in rA as a 32-bit value at the memory address referred to by rB, signed offset by v0. If the address is not word-aligned, the result is implementation-defined. |
ldb |
0x0f rA rB v0 | Read a byte from the memory address referred to by rB, signed offset by v0, and store the value into rA. |
stb |
0x10 rA rB v0 | Store the lower 8 bits of rA at the memory address referred to by rB, signed offset by v0. |
jmi |
0x20 v0 | Unconditionally branch to the 24-bit unsigned address in v0. |
jmp |
0x21 rA | Unconditionally branch to the 32-bit unsigned address in rA. |
bve |
0x24 rA rB v0 | Conditionally branch to the 32-bit unsigned address in rA if the value in rB is equal to the value v0 . |
bvn |
0x25 rA rB v0 | Conditionally branch to the 32-bit unsigned address in rA if the value in rB is not equal to the value v0 . |
cal |
0x2a rA | Store the address of the following instruction in lr then branch to the 32-bit unsigned address in rA. |
ret |
0x2b | Branch to the 32-bit unsigned address in lr , then set lr to 0 . If lr already contains 0 , the behavior is implementation-defined. |
mul |
0x30 rA rB rC | Perform an unsigned 32-bit multiplication of the values contained in rB and rC and store the result in rA. |
div |
0x31 rA rB rC | Perform an unsigned 32-bit integer division of the value contained in rB by the value contained in rC and store the result in rA. |
mod |
0x31 rA rB rC | Perform an unsigned 32-bit integer modulus of the value contained in rB over the value contained in rC and store the result in rA. |
sia |
0x40 rA v0 v1 | Left logical shift v0 by v1 bits, then add that quantity to the value stored in rA. If v1 is outside the range (0, 32), the result is undefined. |
sup |
0x41 rA v0 | Store the 16-bit unsigned value v0 into the upper 16 bits rA, leaving the lower 16 bits untouched. |
sxt |
0x42 rA rB | Copy the value from rB into rA, with sign extension. |
seq |
0x43 rA rB v0 | Set rA to 1 if the value in rB is euqal to the value v0 , otherwise set rA to 0 . |
int |
0xf0 v0 | Raise an interrupt with the 24-bit unsigned code in v0. |
snd |
0xfd rA rB rC | Send command in rB to the device identifier in rA with argument in rC . Result is stored in rC . If the device does not exist, the behavior is implementation defined. |
hlt |
0xff | Halt execution. |
To complement this somewhat limited set, most assemblers implement more complex psuedoinstructions built on top of these base instructions by taking advantage of the special temporary registers.