The CPU has the following properties:
The CPU contains 16 64-bit general purpose registers (R0 to RF) used as integer, floating pointer or address registers.
The CPU contains the following special purpose registers:
Index | Name | Size(bits) | Description |
0 | IP | 32 | instruction pointer; linear address; default = 0 |
1 | RP | 32 | return-address stack pointer; linear address; default = 0 |
2 | SP | 32 | data stack pointer; linear address; default = 0 |
3 | PT | 32 | page table; physical address; default = 0 |
4 | IT | 32 | interrupt table; physical address; default = 0 |
5 | ST | 32 | segment table; physical address; default = 0 |
6 | AT | 32 | access table; physical address; default = 0 |
7 | SR | 32 | status register |
The following table describes the status register:
Bits | Description |
0 | numeric flag (carry/overflow); 0 = not set, 1 = set; default = 0 |
1 | equals flag; 0 = not set, 1 = set; default = 0 |
2 | less than flag; 0 = not set, 1 = set; default = 0 |
3 | greater than flag; 0 = not set, 1 = set; default = 0 |
4 | paging flag; 0 = disabled, 1 = enabled; default = 0 |
5 | interrupts flag; 0 = disabled, 1 = enabled; default = 0 |
6 | protection flag; 0 = disabled, 1 = enabled; default = 0 |
7 | jump flag; 0 = no jump, 1 = jump in progress; default = 0 |
8 | interrupt execution flag; 0 = no interrupt, 1 = interrupt in progress; default = 0 |
9-31 | reserved |
Paging is enabled if the paging bit of the status register is set. The CPU uses a two-level page table and 4K pages. Each level contains 1024 32-bit entries. Each entry has the following format:
Bits | Description |
0 | 0 = page not present, 1 = page present |
1 | 0 = un-cacheable page, 1 = cacheable page |
2-11 | reserved |
12-31 | 20 most significant bits of the physical address of the page table/page |
Protection is enabled if the protection bit of the status register is set. If protection is enabled, then the CPU uses the Segment Table register and the Access Table register to define memory segments (through the segment table) and their access rights between them (through the access table).
The Segment Table (ST) register contains the physical address of the segment table. It contains a variable number (0 to 2^29-1 entries) of 64-bit entries . Each entry has the following format:
Bits | Description |
0 | 0 = non-privileged segment, 1 = privileged segment |
1 | reserved |
2-31 | 30 most significant bits of segment base; linear address |
32-33 | reserved |
33-63 | 30 most significant bits of segment limit; size in bytes |
The last entry of the table must have all bits set.
The purpose of the Segment Table is to segment the 32-bit flat address space into memory regions as well as define which region of memory can use the privileged instructions.
The Access Table (AT) register contains the physical address of the access table. It contains a variable number (0 to 2^29-1) of 64-bit entries. Each entry has the following format:
Bits | Description |
0 | 0 = not readable by segment B, 1 = readable by segment B |
1 | 0 = not writable by segment B, 1 = writable by segment B |
2 | 0 = not executable by segment B, 1 = executable by segment B |
3-31 | segment A |
0 | 0 = not readable by segment A, 1 = readable by segment A |
1 | 0 = not writable by segment A, 1 = writable by segment A |
2 | 0 = not executable by segment A, 1 = executable by segment A |
36-63 | segment B |
The last entry of the table must have all bits set.
The purpose of the Access Table register is to define the access rights between two segments.
The CPU contains a special cache used for quickly locating the relevant information. This cache is named the Protection Lookaside Buffer.
The following invariant is maintained by the CPU at all times:
Any violation of the above will result in a security exception.
The protection model allows for a very fine-grained security model while maintaining the 32-bit flat address space. Typically, operating systems should setup a few entries for both tables in order to host the kernel, drivers, libraries, application code/data (read/write, read/only) and the data/return-address stacks; these entries might be held entirely in the PLB, thus not hampering performance.
The CPU contains two stacks for security reasons:
Both stacks grow downwards.
An atomic load instruction causes the source memory location to be reserved.
An atomic store instruction completes successfully only if the memory reservation (previously reserved with an atomic load) is valid at the time of the store.
There is only one address reservation at each given point in time; a new atomic reservation overwrites any previous ones.
A memory reservation is cancelled if another thread/process/cpu completes a successful atomic store before the current store at the same or overlapping memory address.
The following code shows an example of an atomic increment operation:
atomic_increment:
jt private ;make sure the jump is valid
ldxd r0, ffff0000h ;atomic load; reserve address
ldp r1, 1 ;load increment
add r0, r1 ;increment
stxd r0, ffff0000h ;atomic store
jmpc equal, atomic_increment ;repeat if atomic store failed
The following table describes the CPUs exceptions:
Index | Description |
0 | division by 0 |
1 | page fault |
2 | invalid opcode |
3 | debug trap |
4 | security exception |
Integer arithmetic instructions use two's complement for calculations. Arithmetic operations are unsigned/signed integer, unless explicitly noted.
The following table shows the available instructions:
Byte 0 | Parameters (Description) |
Example | Code | Flags | Description | Priv |
0 | - | nop | - | - | no operation | |
bits 0-3: left operand (register) bits 4-7: right operand (register) |
add R0, R1 | R0 += R1 | NF | addition | ||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
addf R0, R1 | R0 += R1 | float addition | |||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
sub R0, R1 | R0 -= R1 | NF | subtraction | ||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
subf R0, R1 | R0 -= R1 | float subtraction | |||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
mul R0, R1 | R0 *= R1 | NF | multiplication | ||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
muli R0, R1 | R0 *= R1 | NF | signed multiplication | ||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
mulf R0, R1 | R0 *= R1 | float multiplication | |||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
div R0, R1 | R0 = R0 / R1 R1 = R0 % R2 |
NF | division | ||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
divi R0, R1 | R0 = R0 / R1 R1 = R0 % R2 |
NF | signed division | ||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
divf R0, R1 | R0 = R0 / R1 | float division | |||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
modf R0, R1 | R0 = R0 % R1 | float remainder | |||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
shl R0, R1 | R0 <<= R1 | shift left | |||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
shr R0, R1 | R0 >>= R1 | shift right | |||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
and R0, R1 | R0 &= 1 | bitwise AND | |||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
or R0, R1 | R0 |= 1 | bitwise OR | |||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
xor R0, R1 | R0 ^= 1 | bitwise XOR | |||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
not R0, R1 | R0 = ~R1 | bitwise NOT | |||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
cuf R0, R1 | unsigned(R0) = float(R1) | convert unsigned integer to float | |||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
cif R0, R1 | integer(R0) = float(R1) | convert signed integer to float | |||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
cfu R0, R1 | float(R0) = unsigned(R1) | convert float to unsigned integer | |||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
cfi R0, R1 | float(R0) = integer(R1) | convert float to signed integer | |||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
mov R0, R1 | R0 = R1 | register value data transfer | |||
bits 0-3: left operand (register) bits 4-7: right operand (sp. register) |
movsr R0, SR | R0 = SR | copy value of special purpose register to register | |||
bits 0-3: left operand (sp. register) bits 4-7: right operand (register) |
movrs SR, R0 | SR = R0 | copy value of register to special purpose register | yes | ||
bits 0-3: left operand (register) bits 4-7: right operand (4-bit value) |
ldp R0, 8 | R0 = 1 << 3 | load register from power of 2 | |||
bits 0-3: left operand (register) bits 8-15: right operand (8-bit value) |
ldvb R0, FFh | R0 = FFFFFFFFFFFFFFFFh | load register from immediate 8-bit value; extend most-significant bit | |||
bits 0-3: left operand (register) bits 8-23: right operand (16-bit value) |
ldvw R0, FFFFh | R0 = FFFFFFFFFFFFFFFFh | load register from immediate 16-bit value; extend most-significant bit | |||
bits 0-3: left operand (register) bits 8-39: right operand (32-bit value) |
ldvd R0, FFFFFFFFh | R0 = FFFFFFFFFFFFFFFFh | load register from immediate 32-bit value; extend most-significant bit | |||
bits 0-3: left operand (register) bits 8-71: right operand (64-bit value) |
ldvq R0, FFFFFFFFFFFFFFFFh | R0 = FFFFFFFFFFFFFFFFh | load register from immediate 64-bit value | |||
bits 0-3: left operand (register) bits 8-39: right operand (address) |
ldb R0, [0001000h] | R0 = [00010000h] | load register from 8-bit value from address from immediate operand; extend most-significant bit | |||
bits 0-3: left operand (register) bits 8-39: right operand (address) |
ldw R0, [0001000h] | R0 = [00010000h] | load register from 16-bit value from address from immediate operand; extend most-significant bit | |||
bits 0-3: left operand (register) bits 8-39: right operand (address) |
ldd R0, [0001000h] | R0 = [00010000h] | load register from 32-bit value from address from immediate operand; extend most-significant bit | |||
bits 0-3: left operand (register) bits 8-39: right operand (address) |
ldq R0, [0001000h] | R0 = [00010000h] | load register from 64-bit value from address from immediate operand | |||
bits 0-3: left operand (register) bits 8-39: right operand (address) |
ldxb R0, [0001000h] | R0 = [00010000h] | load register from 8-bit value from address from immediate operand; extend most-significant bit; reserve address for atomic operation | |||
bits 0-3: left operand (register) bits 8-39: right operand (address) |
ldxw R0, [0001000h] | R0 = [00010000h] | load register from 16-bit value from address from immediate operand; extend most-significant bit; reserve address for atomic operation | |||
bits 0-3: left operand (register) bits 8-39: right operand (address) |
ldxd R0, [0001000h] | R0 = [00010000h] | load register from 32-bit value from address from immediate operand; extend most-significant bit; reserve address for atomic operation | |||
bits 0-3: left operand (register) bits 8-39: right operand (address) |
ldxq R0, [0001000h] | R0 = [00010000h] | load register from 64-bit value from address from immediate operand; reserve address for atomic operation | |||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
ldrb R0, [R1] | R0 = [R1] | load register from 8-bit value from address from register operand; extend most-significant bit | |||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
ldrw R0, [R1] | R0 = [R1] | load register from 16-bit value from address from register operand; extend most-significant bit | |||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
ldrd R0, [R1] | R0 = [R1] | load register from 32-bit value from address from register operand; extend most-significant bit | |||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
ldrq R0, [R1] | R0 = [R1] | load register from 64-bit value from address from register operand | |||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
ldrxb R0, [R1] | R0 = [R1] | load register from 8-bit value from address from register operand; extend most-significant bit; reserve address for atomic operation | |||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
ldrxw R0, [R1] | R0 = [R1] | load register from 16-bit value from address from register operand; extend most-significant bit; reserve address for atomic operation | |||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
ldrxd R0, [R1] | R0 = [R1] | load register from 32-bit value from address from register operand; extend most-significant bit; reserve address for atomic operation | |||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
ldrxq R0, [R1] | R0 = [R1] | load register from 64-bit value from address from register operand; reserve address for atomic operation | |||
bits 4-7: operand (register) | ldcpu [R1] | - | loads the CPU context from address from register operand. | yes | ||
bits 4-7: right operand (register) bits 8-39: left operand (address) |
stb [0001000h], R1 | [0001000h] = R1 | store the 8 least significant bits of register to address from immediate operand | |||
bits 4-7: right operand (register) bits 8-39: left operand (address) |
stw [0001000h], R1 | [0001000h] = R1 | store the 16 least significant bits of register to address from immediate operand | |||
bits 4-7: right operand (register) bits 8-39: left operand (address) |
std [0001000h], R1 | [0001000h] = R1 | store the 32 least significant bits of register to address from immediate operand | |||
bits 4-7: right operand (register) bits 8-39: left operand (address) |
stq [0001000h], R1 | [0001000h] = R1 | store the register to address from immediate operand | |||
bits 4-7: right operand (register) bits 8-39: left operand (address) |
stxb [0001000h], R1 | [0001000h] = R1 | EF | store the 8 least significant bits of register to address from immediate operand; atomic operation; EF contains the result of transaction | ||
bits 4-7: right operand (register) bits 8-39: left operand (address) |
stxw [0001000h], R1 | [0001000h] = R1 | EF | store the 16 least significant bits of register to address from immediate operand; EF contains the result of transaction | ||
bits 4-7: right operand (register) bits 8-39: left operand (address) |
stxd [0001000h], R1 | [0001000h] = R1 | EF | store the 32 least significant bits of register to address from immediate operand; EF contains the result of transaction | ||
bits 4-7: right operand (register) bits 8-39: left operand (address) |
stxq [0001000h], R1 | [0001000h] = R1 | EF | store the register to address from immediate operand; EF contains the result of transaction | ||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
strb [R0], R1 | [R0] = R1 | store the 8 least significant bits of register to address from register operand | |||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
strw [R0], R1 | [R0] = R1 | store the 16 least significant bits of register to address from register operand | |||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
strd [R0], R1 | [R0] = R1 | store the 32 least significant bits of register to address from register operand | |||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
strq [R0], R1 | [R0] = R1 | store register to address from register operand | |||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
strxb [R0], R1 | [R0] = R1 | EF | store the 8 least significant bits of register to address from register operand; atomic operation; EF contains the result of transaction | ||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
strxw [R0], R1 | [R0] = R1 | EF | store the 16 least significant bits of register to address from register operand; atomic operation; EF contains the result of transaction | ||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
strxd [R0], R1 | [R0] = R1 | EF | store the 32 least significant bits of register to address from register operand; atomic operation; EF contains the result of transaction | ||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
strxq [R0], R1 | [R0] = R1 | EF | store register to address from register operand; atomic operation; EF contains the result of transaction | ||
bits 4-7: operand (register) | pushb R1 | SP -= 1, [SP] = R1 | push the 8 least significant bits of register to the stack | |||
bits 0-3: operand (register) | stcpu [R0] | - | stores the CPU context to the address from register operand. The general purpose registers are stored first , then the special purpose registers; all registers are stored in the order specified by their index. | |||
bits 4-7: operand (register) | pushw R1 | SP -= 2, [SP] = R1 | push the 16 least significant bits of register to the stack | |||
bits 4-7: operand (register) | pushd R1 | SP -= 4, [SP] = R1 | push the 32 least significant bits of register to the stack | |||
bits 4-7: operand (register) | pushq R1 | SP -= 8, [SP] = R1 | push the 64 least significant bits of register to the stack | |||
bits 0-3: operand (register) | popb R0 | R0 = [SP], SP += 1 | pop 8 bits from the stack;extend most-significant bit | |||
bits 0-3: operand (register) | popw R0 | R0 = [SP], SP += 2 | pop 16 bits from the stack;extend most-significant bit | |||
bits 0-3: operand (register) | popd R0 | R0 = [SP], SP += 4 | pop 32 bits from the stack;extend most-significant bit | |||
bits 0-3: operand (register) | popq R0 | R0 = [SP], SP += 8 | pop 64 bits from the stack;extend most-significant bit | |||
- | jt private | JF = 0 | private jump target | |||
- | jt public | JF = 0 | public jump target | |||
bits 0-31: destination address | jmp 00010000h | IP = 0001000h, JF = 1 | jump to address from immediate operand | |||
bit 4 : C flag bit 5 : E flag bit 6 : L flag bit 7 : G flag bits 8-39: destination address |
jmpc C|E|L|G, 00010000h | if C == 0 or (E == EF and L == LF and G == GF) then {IP = 0001000h, JF = 1} | conditional jump to address from immediate operand | |||
bits 0-3: operand (register) | jmpr R0 | IP = R0 | jump to address from register operand | |||
bits 0-3: operand (register) bit 4 : C flag bit 5 : E flag bit 6 : L flag bit 7 : G flag |
jmpcr R0 | if C == 0 or (E == EF and L == LF and G == GF) then {IP = R0, JF = 1} | conditional jump to address from register operand | |||
bits 0-31: destination address | call 00010000h | push IP + 5 in return-address stack, IP = 00010000h, JF = 1 | invoke subroutine at address from immediate operand | |||
bits 0-3: operand (register) | callr R0 | push IP + 2 in return-address stack, IP = R0, JF = 1 | invoke subroutine at address from register operand | |||
bits 0-7: interrupt value | int 3 | push SR, IP + 2 in return-address stack, IP = IT[3] | software interrupt from immediate operand | |||
bits 0-3: operand (register) | intr R0 | push SR, IP + 2 in return-address stack, IP = IT[R0] | software interrupt from register operand | |||
- | ret | pop IP from return-address stack; also pop SR from return-address stack if there is an interrupt in progress. | return from call/interrupt | |||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
cmp R0, R1 | EF = R0 == R1 LF = R0 < R1 GF = R0 > R1 |
EF, LF, GF | compare unsigned integers | ||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
cmpi R0, R1 | EF = R0 == R1 LF = R0 < R1 GF = R0 > R1 |
EF, LF, GF | compare integers | ||
bits 0-3: left operand (register) bits 4-7: right operand (register) |
cmpf R0, R1 | EF = R0 == R1 LF = R0 < R1 GF = R0 > R1 |
EF, LF, GF | compare floats |