CPU

The CPU has the following properties:

General Purpose Registers

The CPU contains 16 64-bit general purpose registers (R0 to RF) used as integer, floating pointer or address registers.

Special Purpose 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 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

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

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:

  1. if the operation is a privileged instruction, then the segment must be privileged.
  2. if the operation is a read/write/execute, then source segment (the segment IP points to) must have the corresponding access right over the destination segment; valid also for software interrupts (hardware interrupts are not checked).
  3. if the operation is execute:
    1. the first instruction after the jump must be a jump target.
    2. if the jump is from one segment to another segment, the jump target must be public, otherwise it can be public or private.

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 Stack

The CPU contains two stacks for security reasons:

  1. the return address stack is used to store return information after a call or interrupt instruction.
  2. the data stack is used to store procedure data.

Both stacks grow downwards.

Atomic Execution

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

Exceptions

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

Instruction Set

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  
(C) 2007 Achilleas Margaritis