-
Notifications
You must be signed in to change notification settings - Fork 0
basiccpu ISA
The byte order is big-endian.
The ISA has these registers:
r1-r3: scratch registers or arguments to special opcodes
r4-r7: general purpose
ip: instruction pointer
lr: link register
sp: stack pointer (points to top of stack)
st: status register
dl: delay register (controls the IDLE instruction)
At the start of emulation, only ip and sp have guaranteed values; the other registers have indeterminate values. ip = start of bios. sp = highest memory value, aligned to a multiple of 4.
r1-r3 are scratch registers – the called routine is not required to preserve their values. This means that, if the calling routine needs their values after the called routine returns, it needs to move their values to one of the other general purpose registers, or push them onto the stack before calling the routine.
r4-r7 are local variable registers – the called routine must preserve their values. If the called routine changes their values, it must change them back before returning.
r4-r6 are parameter registers. If a routine accepts more than 3 parameters, r4 and r5 should accept the first two arguments, and r6 should point to the remaining arguments.
r1 is the return value register.
An example:
; ... some code ...
dd vectorptr 0 ; declare 4-byte global to 0
; ... some code sets vectorptr to a list of homogenous elements
func1:
; we modify these two non-scratch registers, so we must preserve them:
push r4
push r5
; ... some code ...
; say, r3 = some index
push r3 ; if we need the value of r3 after `get_structure` returns
mov r4, r3 ; set first and only parameter of `get_structure`
call get_structure
; r1 is our return value!
pop r3 ; restore r3
; increment a 1-byte field within the structure
mov r5, r1
add r5, 4 ; skip to some variable in the structure
loadb r2, r5
inc r2
strb r5, r2
; ... some code ...
; restore non-scratch registers - pop reverse order that they were pushed
pop r5
pop r4
ret
; r4 = index in structure vector
; returns r1 = pointer to structure
get_structure:
push r4 ; or use a scratch register instead
; index to element is vectorptr + 10 * r4
load r1, vectorptr
mul r4, 10
add r1, r4
; r1 now contains the return value
pop r4
retBits 31-24: opcode
Bits 23-20: condition bits / predicate bits; will be removed since it’s not valuable to interpretation
Bits 16-13: destination register
Bits 0-15: 16-bit operand / source register
There is overlap between the 16-bit operand and the destination register. Since both fields may be needed for particular instructions, this is a design flaw. This will be fixed once the condition bits are removed.
Privilege: Supervisor
Opcode: 0×00
Operands: none
Halts emulation
Privilege: Supervisor
Opcode: 0×01
Operands: none
Sleeps the number of microseconds in the `dl` register
Privilege: Supervisor
Opcode: 0×03
Operands: none
Clears the interrupt enable bit from the status register, disabling interrupts.
Privilege: Supervisor
Opcode: 0×04
Operands: none
Sets the interrupt enable bit in the status register, enabling interrupts.
Privilege: User
Opcode: 0×10
Operands:
- offset – a 16-bit immediate, or a register (not implemented)
ip = ip + operand
register addressing mode is not implementedPrivilege: User
Opcode: 0×11
Operands: undecided
Privilege: User
Opcode: 0×14
Operands:
- offset – a 16-bit immediate, or a register (not implemented)
ip = ip + operand
sp = sp - 4
stack[sp] = lr
lr = ipregister addressing mode is not implemented
Privilege: User
Opcode: 0×15
Operands: undecided
Privilege: User
Opcode: 0×16
Operands: none
ip = lr
lr = memory[sp]
sp = sp + 4Privilege: Supervisor
Opcode: 0×17
Operands: none
Return from interrupt. Restores the instruction pointer from the stack.
Privilege: User
Opcode: 0×20
Operands:
- destination register
- source: 32-bit immediate or register
destination register = source registeror
destination register = source operandPrivilege: User
Opcode: 0×28
Operands: undecided
Privilege: User
Opcode: 0×29
Operands: undecided
Privilege: User
Opcode: 0×2a
Operands: undecided
Privilege: User
Opcode: 0×30
Operands: undecided
Privilege: User
Opcode: 0×31
Operands: undecided
Privilege: User
Opcode: 0×32
Operands: undecided
Privilege: User
Opcode: 0×39
Operands:
- r1: address of string to copy
- r2: length of string to copy
- memory destination – 32-bit immediate or register (not implemented)
Copies Copies memory[r1] .. memory[r1 + length – 1] to memory[operand]
register mode not implemented
Privilege: User
Opcode: 0×39
Operands: not decided
Privilege: User
Opcode: 0×3a
Operands:
- r1: start of memory address
- r2: number of 24-bit values
- operand: 24-bit value
This is meant to set more efficiently set a contiguous section of video memory to a constant value.
memory[r1 + 3n + 0] = (operand & 0xFF0000) >> 16
memory[r1 + 3n + 1] = (operand & 0x00FF00) >> 8
memory[r1 + 3n + 2] = (operand & 0x0000FF)from n = 0 to r2
Privilege: User
Opcode: 0×3b
Operands:
- r1: start of memory address
- r2: skip interval (the width of the display, e.g. 640)
- r3: length of pixels
- operand: 24-bit value
This is meant to set more efficiently set a contiguous section of video memory to a constant value.
This colors a vertical line of video memory to a constant 24-bit operand.
Privilege: Supervisor
Opcode: 0×40
Operands:
- destination register
- 32-bit immediate
Reads a 32-bit value from a CPU pin into a register
Privilege: Supervisor
Opcode: 0×41
Operands:
- 32-bit immediate
Tells the motherboard to write to a device. It passes the operand to the device. The operand’s meaning is only known to the device and the guest code that called the write.
Privilege: User
Opcode: 0×50
Operands:
- destination register
- 32-bit immediate or source register
destination register = destination register + operand
Privilege: User
Opcode: 0×54
Operands:
- destination register
- 32-bit immediate or source register
destination register = destination register * operand
Privilege: User
Opcode: 0×55
Operands:
- destination register
- 16-bit immediate
destination register = destination register * operand