290 lines
7.1 KiB
NASM
290 lines
7.1 KiB
NASM
// not really a kernel,
|
|
// just handling some low-level stuff like interrupts.
|
|
|
|
Start:
|
|
lui k0, K_BASE
|
|
|
|
// copy our interrupt handlers into place.
|
|
lui t0, 0x8000
|
|
la t1, _InterruptStart
|
|
la t2, _InterruptEnd
|
|
-
|
|
ld t3, 0(t1)
|
|
ld t4, 8(t1)
|
|
addiu t1, t1, 0x10
|
|
ld t3, 0(t0)
|
|
sd t4, 8(t0)
|
|
addiu t0, t0, 0x10
|
|
bne t1, t2,-
|
|
cache 1, 0(t0) // not sure if this is necessary, but it doesn't hurt.
|
|
|
|
// enable SI and PI interrupts.
|
|
lui a0, PIF_BASE
|
|
lli t0, 8
|
|
sw t0, PIF_RAM+0x3C(a0)
|
|
|
|
// SP defaults to RSP instruction memory: 0xA4001FF0
|
|
// we can do better than that.
|
|
lui sp, K_STACK_INIT_BASE
|
|
// SP should always be 8-byte aligned
|
|
// so that SD and LD instructions don't fail on it.
|
|
// we also need 4 empty words for storing the 32-bit values of a0,a1,a2,a3
|
|
subiu sp, sp, 0x10
|
|
|
|
// TODO: just wipe a portion of RAM?
|
|
sw r0, K_64DRIVE_MAGIC(k0)
|
|
sw r0, K_REASON(k0)
|
|
|
|
Drive64Init:
|
|
lui t9, CI_BASE
|
|
lui t2, 0x5544 // "UD" of "UDEV"
|
|
lw t1, CI_HW_MAGIC(t9)
|
|
ori t2, t2, 0x4556 // "EV" of "UDEV"
|
|
|
|
beq t1, t2, Drive64Confirmed
|
|
nop
|
|
|
|
Drive64TryExtended:
|
|
lui t9, CI_BASE_EXTENDED
|
|
lw t1, CI_HW_MAGIC(t9)
|
|
bne t1, t2, Drive64Done
|
|
nop
|
|
|
|
Drive64Confirmed:
|
|
sw t2, K_64DRIVE_MAGIC(k0)
|
|
sw t9, K_CI_BASE(k0)
|
|
|
|
// enable writing to cartROM (SDRAM) for USB writing later
|
|
lli t1, 0xF0
|
|
CI_WAIT() // clobbers t0, requires t9
|
|
sw t1, CI_COMMAND(t9)
|
|
CI_WAIT() // clobbers t0, requires t9
|
|
|
|
Drive64Done:
|
|
|
|
// clear internal exception/interrupt value
|
|
ori k1, r0, r0
|
|
|
|
// load up most registers with a dummy value for debugging
|
|
lui at, 0xCAFE
|
|
ori at, r0, 0xBABE
|
|
dsllv at, 32
|
|
// attempting to use this as an address should trigger an interrupt
|
|
ori at, r0, 0xDEAD
|
|
dsllv at, 16
|
|
ori at, r0, 0xBEEF
|
|
|
|
// k0, k1, sp intentionally absent
|
|
daddu v0, at, r0
|
|
daddu v1, at, r0
|
|
daddu a0, at, r0
|
|
daddu a1, at, r0
|
|
daddu a2, at, r0
|
|
daddu a3, at, r0
|
|
daddu t0, at, r0
|
|
daddu t1, at, r0
|
|
daddu t2, at, r0
|
|
daddu t3, at, r0
|
|
daddu t4, at, r0
|
|
daddu t5, at, r0
|
|
daddu t6, at, r0
|
|
daddu t7, at, r0
|
|
daddu s0, at, r0
|
|
daddu s1, at, r0
|
|
daddu s2, at, r0
|
|
daddu s3, at, r0
|
|
daddu s4, at, r0
|
|
daddu s5, at, r0
|
|
daddu s6, at, r0
|
|
daddu s7, at, r0
|
|
daddu t8, at, r0
|
|
daddu t9, at, r0
|
|
daddu gp, at, r0
|
|
daddu fp, at, r0
|
|
daddu ra, at, r0
|
|
|
|
j Main
|
|
nop
|
|
|
|
align(0x10)
|
|
_InterruptStart: // for copying purposes
|
|
pushvar base
|
|
|
|
// note that we jump to the handler by jr instead of j
|
|
// because we want to change the PC to cached memory,
|
|
// which depends on the higher bits that j cannot change.
|
|
|
|
base 0x80000000
|
|
InterruptTBLRefill:
|
|
la k0, InterruptHandler
|
|
jr k0
|
|
lli k1, K_INT_TLB_REFILL
|
|
|
|
nops(0x80000080)
|
|
InterruptXTLBRefill:
|
|
la k0, InterruptHandler
|
|
jr k0
|
|
lli k1, K_INT_XTLB_REFILL
|
|
|
|
nops(0x80000100)
|
|
InterruptCacheError: // A0000100?
|
|
la k0, InterruptHandler
|
|
jr k0
|
|
lli k1, K_INT_CACHE_ERROR
|
|
|
|
nops(0x80000180)
|
|
InterruptOther:
|
|
la k0, InterruptHandler
|
|
jr k0
|
|
lli k1, K_INT_OTHER
|
|
|
|
nops(0x80000200)
|
|
pullvar base
|
|
_InterruptEnd: // for copying purposes
|
|
|
|
InterruptHandler:
|
|
lui k0, K_BASE
|
|
sw k1, K_REASON(k0)
|
|
|
|
sd at, K_DUMP+0x08(k0)
|
|
|
|
// disable interrupts, clear exception and error level bits:
|
|
mfc0 at, CP0_Status
|
|
sw at, K_STATUS(k0) // TODO: restored later
|
|
addiu at, r0, 0xFFFC
|
|
and k1, k1, at
|
|
mtc0 k1, CP0_Status
|
|
|
|
mfc0 k1, CP0_Cause
|
|
sw k1, K_CAUSE(k0)
|
|
|
|
// TODO: option to only store clobbered registers
|
|
// TODO: option to dump COP1 registers too
|
|
|
|
sd r0, K_DUMP+0x00(k0) // intentional (it'd be weird if
|
|
// r0 showed as nonzero in memory dumps)
|
|
sd v0, K_DUMP+0x10(k0)
|
|
sd v1, K_DUMP+0x18(k0)
|
|
sd a0, K_DUMP+0x20(k0)
|
|
sd a1, K_DUMP+0x28(k0)
|
|
sd a2, K_DUMP+0x30(k0)
|
|
sd a3, K_DUMP+0x38(k0)
|
|
sd t0, K_DUMP+0x40(k0)
|
|
sd t1, K_DUMP+0x48(k0)
|
|
sd t2, K_DUMP+0x50(k0)
|
|
sd t3, K_DUMP+0x58(k0)
|
|
sd t4, K_DUMP+0x60(k0)
|
|
sd t5, K_DUMP+0x68(k0)
|
|
sd t6, K_DUMP+0x70(k0)
|
|
sd t7, K_DUMP+0x78(k0)
|
|
sd s0, K_DUMP+0x80(k0)
|
|
sd s1, K_DUMP+0x88(k0)
|
|
sd s2, K_DUMP+0x90(k0)
|
|
sd s3, K_DUMP+0x98(k0)
|
|
sd s4, K_DUMP+0xA0(k0)
|
|
sd s5, K_DUMP+0xA8(k0)
|
|
sd s6, K_DUMP+0xB0(k0)
|
|
sd s7, K_DUMP+0xB8(k0)
|
|
sd t8, K_DUMP+0xC0(k0)
|
|
sd t9, K_DUMP+0xC8(k0)
|
|
sd k0, K_DUMP+0xD0(k0)
|
|
sd k1, K_DUMP+0xD8(k0)
|
|
sd gp, K_DUMP+0xE0(k0)
|
|
sd sp, K_DUMP+0xE8(k0)
|
|
sd fp, K_DUMP+0xF0(k0)
|
|
sd ra, K_DUMP+0xF8(k0)
|
|
|
|
mfhi t0
|
|
mflo t1
|
|
sd t0, K_DUMP+0x100(k0)
|
|
sd t1, K_DUMP+0x108(k0)
|
|
|
|
// be wary, this is a tiny temporary stack!
|
|
ori sp, k0, K_STACK
|
|
|
|
IHMain: // free to modify any GPR from here to IHExit
|
|
la a2, IHString
|
|
jal Drive64WriteDirect
|
|
lli a3, 0x20 //IHString.size
|
|
|
|
ori a0, k0, K_DUMP
|
|
lli a1, 0x100
|
|
ori a2, k0, K_XXD
|
|
jal DumpAndWrite
|
|
lli a3, 0x400
|
|
|
|
ori a0, k0, K_DUMP
|
|
addiu a0, a0, 0x100
|
|
lli a1, 0x100
|
|
ori a2, k0, K_XXD
|
|
jal DumpAndWrite
|
|
lli a3, 0x400
|
|
|
|
IHExit:
|
|
|
|
jal Drive64Write
|
|
|
|
lui k0, K_BASE
|
|
ld t0, K_DUMP+0x100(k0)
|
|
ld t1, K_DUMP+0x108(k0)
|
|
mthi t0
|
|
mtlo t1
|
|
|
|
ld at, K_DUMP+0x08(k0)
|
|
ld v0, K_DUMP+0x10(k0)
|
|
ld v1, K_DUMP+0x18(k0)
|
|
ld a0, K_DUMP+0x20(k0)
|
|
ld a1, K_DUMP+0x28(k0)
|
|
ld a2, K_DUMP+0x30(k0)
|
|
ld a3, K_DUMP+0x38(k0)
|
|
ld t0, K_DUMP+0x40(k0)
|
|
ld t1, K_DUMP+0x48(k0)
|
|
ld t2, K_DUMP+0x50(k0)
|
|
ld t3, K_DUMP+0x58(k0)
|
|
ld t4, K_DUMP+0x60(k0)
|
|
ld t5, K_DUMP+0x68(k0)
|
|
ld t6, K_DUMP+0x70(k0)
|
|
ld t7, K_DUMP+0x78(k0)
|
|
ld s0, K_DUMP+0x80(k0)
|
|
ld s1, K_DUMP+0x88(k0)
|
|
ld s2, K_DUMP+0x90(k0)
|
|
ld s3, K_DUMP+0x98(k0)
|
|
ld s4, K_DUMP+0xA0(k0)
|
|
ld s5, K_DUMP+0xA8(k0)
|
|
ld s6, K_DUMP+0xB0(k0)
|
|
ld s7, K_DUMP+0xB8(k0)
|
|
ld t8, K_DUMP+0xC0(k0)
|
|
ld t9, K_DUMP+0xC8(k0)
|
|
ld gp, K_DUMP+0xE0(k0)
|
|
ld sp, K_DUMP+0xE8(k0)
|
|
ld fp, K_DUMP+0xF0(k0)
|
|
ld ra, K_DUMP+0xF8(k0)
|
|
|
|
lw k1, K_CAUSE(k0)
|
|
andi k1, k1, 0x2000 // check if this was a trap exception
|
|
mfc0 k0, CP0_EPC
|
|
beqz k1, ReturnFromInterrupt
|
|
sw k0, K_EPC(k0)
|
|
|
|
ReturnFromTrap:
|
|
addiu k0, k0, 4
|
|
|
|
ReturnFromInterrupt:
|
|
// restore interrupts
|
|
mfc0 k1, CP0_Status
|
|
ori k1, k1, 1
|
|
mtc0 k1, CP0_Status
|
|
|
|
// wait, shouldn't this be ERET?
|
|
rfe
|
|
jr k0
|
|
or k1, r0, r0
|
|
|
|
include "debug.asm"
|
|
|
|
align(4)
|
|
IHString:
|
|
db " ~~~ Interrupt Handled ~~~ ", 0
|
|
|
|
align(4)
|
|
nops((K_BASE << 16) + 0x10000)
|