start work on interrupt handler; refactor

This commit is contained in:
Connor Olding 2018-08-17 08:02:25 +02:00
parent d05169fcbc
commit ab2896cec6
4 changed files with 339 additions and 58 deletions

260
kernel.asm Normal file
View file

@ -0,0 +1,260 @@
// 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.
subiu sp, sp, 8
// TODO: just wipe a portion of RAM?
sw r0, K_64DRIVE_MAGIC(k0)
sw r0, K_REASON(k0)
Drive64Init:
lui gp, CI_BASE
lui t2, 0x5544 // "UD" of "UDEV"
lw t1, CI_HW_MAGIC(gp)
ori t2, t2, 0x4556 // "EV" of "UDEV"
beq t1, t2, Drive64Confirmed
nop
Drive64TryExtended:
lui gp, CI_BASE_EXTENDED
lw t1, CI_HW_MAGIC(gp)
bne t1, t2, Drive64Done
nop
Drive64Confirmed:
sw t2, K_64DRIVE_MAGIC(k0)
sw gp, K_CI_BASE(k0)
// enable writing to cartROM (SDRAM) for USB writing later
lli t1, 0xF0
CI_WAIT()
sw t1, CI_COMMAND(gp) // send our command
CI_WAIT()
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)
// free to modify any GPR here
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
nops((K_BASE << 16) + 0x10000)

View file

@ -18,68 +18,28 @@ insert "6102.bin"
include "main.inc"
Start:
N64_INIT() // enable interrupts
include "kernel.asm"
// SP defaults to RSP instruction memory: 0xA4001FF0
// we can do better than that.
lui sp, BLAH_BASE
// SP should always be 8-byte aligned
// so that SD and LD instructions don't fail on it.
subiu sp, sp, 8
nops(0x80010000)
Main:
lui t0, K_BASE
lw gp, K_CI_BASE(t0)
lui s0, BLAH_BASE
Drive64Init:
lui gp, CI_BASE
lui t2, 0x5544 // "UD" of "UDEV"
lw t1, CI_HW_MAGIC(gp)
ori t2, t2, 0x4556 // "EV" of "UDEV"
beq t1, t2, Drive64Confirmed
nop // delay slot
Drive64TryExtended:
lui gp, CI_BASE_EXTENDED
lw t1, CI_HW_MAGIC(gp)
bne t1, t2, Main
nop // delay slot
Drive64Confirmed:
sw t2, BLAH_CONFIRMED(s0)
sw gp, BLAH_CI_BASE(s0)
// enable writing to cartROM (SDRAM) for USB writing later
lli t1, 0xF0
CI_WAIT()
sw t1, CI_COMMAND(gp) // send our command
CI_WAIT()
Main:
if 0 {
mfc0 t0, 0x9 // move cycle Count register from COP 0
mfc0 t0, CP0_Count
mfc0 t1, CP0_Status+0
sw t0, BLAH_COUNTS+0(s0)
mfc0 t0, 0x9 // move cycle Count register from COP 0
sw t0, BLAH_COUNTS+4(s0)
// seems like 41 half-cycles between the two mfc0's, rarely 42?
} else {
mfc0 t0, 0x9
mfc0 t1, 0x9
sw t0, BLAH_COUNTS+0(s0)
sw t1, BLAH_COUNTS+4(s0)
// seems like 22 half-cycles between the two mfc0's
}
// what is our stack pointer set to, anyway?
sw sp, 0xC(s0)
sw t1, 8(s0)
// decompress our picture
include "lz.asm"
mfc0 t0, 0x9
mfc0 t0, CP0_Count
sw t0, BLAH_COUNTS+8(s0)
lw t1, BLAH_CONFIRMED(s0)
lui t0, K_BASE
lw t1, K_64DRIVE_MAGIC(t0)
beqz t1, InitVideo
nop // delay slot
@ -112,7 +72,7 @@ InitVideo: // currently 80001190 (this comment is likely out of date)
jal SetupScreen
nop
mfc0 t0, 0x9 // move cycle Count register from COP 0
mfc0 t0, CP0_Count
sw t0, BLAH_COUNTS+0xC(s0)
MainLoop:
@ -175,7 +135,7 @@ PushVideoTask:
sw t5, 0x14(a0)
sw t6, 0x18(a0)
sw t7, 0x1C(a0)
li t0, VIDEO_STACK & ADDR_MASK // ?
li t0, VIDEO_STACK & ADDR_MASK // used for DList calls and returns?
li t1, VIDEO_STACK_SIZE
li t2, VIDEO_BUFFER & ADDR_MASK
li t3, (VIDEO_BUFFER & ADDR_MASK) + VIDEO_BUFFER_SIZE // end pointer (not size!)

View file

@ -1,13 +1,32 @@
constant UNCACHED(0xA0000000)
constant ADDR_MASK(0x1FFFFFFF)
// "kernel" constants:
constant K_BASE(0x8000) // k0 is set to this.
constant K_DUMP(0x0400) // we save registers and state here
// when handling interrupts
constant K_REASON(0x0600)
constant K_CAUSE(0x0604)
constant K_STATUS(0x0608)
constant K_EPC(0x060C)
constant K_64DRIVE_MAGIC(0x0800)
constant K_CI_BASE(0x0804)
constant K_STACK_INIT_BASE(0x803F) // note that this gets subtracted by 8
// and that the stack grows *backwards.*
// internal interrupt enum: (0 means no known interrupt/exception)
constant K_INT_TLB_REFILL(1)
constant K_INT_XTLB_REFILL(2)
constant K_INT_CACHE_ERROR(3)
constant K_INT_OTHER(4)
constant BLAH_BASE(0x803F)
constant BLAH_CONFIRMED(0x0000)
constant BLAH_CI_BASE(0x0004)
constant BLAH_COUNTS(0x0010)
constant BLAH_SP_TASK(0x0040)
constant BLAH_DLIST_JUMPER(0x0080)
constant BLAH_XXD(0x0100)
constant VIDEO_BUFFER(0x80100000)
constant VIDEO_BUFFER_SIZE(640 * 480 * 4)
constant VIDEO_STACK(VIDEO_BUFFER + VIDEO_BUFFER_SIZE)
@ -15,6 +34,12 @@ constant VIDEO_STACK_SIZE(0x400)
constant VIDEO_YIELD(VIDEO_STACK + VIDEO_STACK_SIZE)
constant VIDEO_YIELD_SIZE(0xC00)
macro nops(new_pc) {
while (pc() < {new_pc}) {
nop
}
}
macro PI_WAIT() {
lui t5, PI_BASE
-

40
n64.inc
View file

@ -1,4 +1,4 @@
// via krom
// by krom, edited by notwa
//=============
// N64 Include
@ -66,9 +66,11 @@ constant k0(26)
constant k1(27)
constant gp(28)
constant sp(29)
constant s8(30)
constant fp(30)
constant ra(31)
constant s8(30) // alias of fp
// N64 MIPS 4300 CP1 Floating Point Unit (FPU) Registers (COP1)
constant f0(0)
constant f1(1)
@ -103,6 +105,40 @@ constant f29(29)
constant f30(30)
constant f31(31)
// Coprocessor 0 registers
constant CP0_Index(0)
constant CP0_Random(1)
constant CP0_EntryLo0(2)
constant CP0_EntryLo1(3)
constant CP0_Context(4)
constant CP0_PageMask(5)
constant CP0_Wired(6)
constant CP0_Reserved_1(7)
constant CP0_BadVAddr(8)
constant CP0_Count(9)
constant CP0_EntryHi(10)
constant CP0_Compare(11)
constant CP0_Status(12)
constant CP0_Cause(13)
constant CP0_EPC(14)
constant CP0_PRid(15)
constant CP0_Config(16)
constant CP0_LLAddr(17)
constant CP0_WatchLo(18)
constant CP0_WatchHi(19)
constant CP0_XContext(20)
constant CP0_Reserved_2(21)
constant CP0_Reserved_3(22)
constant CP0_Reserved_4(23)
constant CP0_Reserved_5(24)
constant CP0_Reserved_6(25)
constant CP0_PErr(26) // unused
constant CP0_CacheErr(27) // unused
constant CP0_TagLo(28)
constant CP0_TagHi(29) // reserved
constant CP0_ErrorPC(30)
constant CP0_Reserved_7(31)
// Memory Map
constant RDRAM($A000) // $00000000..$003FFFFF RDRAM Memory 4MB ($00000000..$007FFFFF 8MB With Expansion Pak)