Skip to content
jslick edited this page Mar 23, 2012 · 9 revisions

basiccpu ISA

Architecture

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.

Calling conventions

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
    ret

General encoding scheme

Bits 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.

Opcodes

CPU modes & misc

HALT

Privilege: Supervisor
Opcode: 0×00
Operands: none
Halts emulation

IDLE

Privilege: Supervisor
Opcode: 0×01
Operands: none
Sleeps the number of microseconds in the `dl` register

CLI

Privilege: Supervisor
Opcode: 0×03
Operands: none
Clears the interrupt enable bit from the status register, disabling interrupts.

STI

Privilege: Supervisor
Opcode: 0×04
Operands: none
Sets the interrupt enable bit in the status register, enabling interrupts.

Control Flow

JMP

Privilege: User
Opcode: 0×10
Operands:

  • offset – a 16-bit immediate, or a register (not implemented)
ip = ip + operand
register addressing mode is not implemented

LNGJMP (not implemented)

Privilege: User
Opcode: 0×11
Operands: undecided

CALL

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 = ip

register addressing mode is not implemented

LNGCALL (not implemented)

Privilege: User
Opcode: 0×15
Operands: undecided

RET

Privilege: User
Opcode: 0×16
Operands: none

ip = lr
lr = memory[sp]
sp = sp + 4

RTI

Privilege: Supervisor
Opcode: 0×17
Operands: none
Return from interrupt. Restores the instruction pointer from the stack.

Register operations

MOV

Privilege: User
Opcode: 0×20
Operands:

  • destination register
  • source: 32-bit immediate or register
destination register = source register

or

destination register = source operand

Memory operations

LOAD (not implemented)

Privilege: User
Opcode: 0×28
Operands: undecided

LOADW (not implemented)

Privilege: User
Opcode: 0×29
Operands: undecided

LOADB (not implemented)

Privilege: User
Opcode: 0×2a
Operands: undecided

STORE (not implemented)

Privilege: User
Opcode: 0×30
Operands: undecided

STOREW (not implemented)

Privilege: User
Opcode: 0×31
Operands: undecided

STOREB (not implemented)

Privilege: User
Opcode: 0×32
Operands: undecided

MEMCPY

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

MEMSET (not implemented)

Privilege: User
Opcode: 0×39
Operands: not decided

CLRSET

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

CLRSETV

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.

Input / Output

READ

Privilege: Supervisor
Opcode: 0×40
Operands:

  • destination register
  • 32-bit immediate

Reads a 32-bit value from a CPU pin into a register

WRITE

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.

Math

ADD

Privilege: User
Opcode: 0×50
Operands:

  • destination register
  • 32-bit immediate or source register
    destination register = destination register + operand

MUL

Privilege: User
Opcode: 0×54
Operands:

  • destination register
  • 32-bit immediate or source register
    destination register = destination register * operand

MULW

Privilege: User
Opcode: 0×55
Operands:

  • destination register
  • 16-bit immediate
    destination register = destination register * operand