diff --git a/kernel.asm b/kernel.asm new file mode 100644 index 0000000..cbfd59b --- /dev/null +++ b/kernel.asm @@ -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) diff --git a/main.asm b/main.asm index 6db04d2..40c7013 100644 --- a/main.asm +++ b/main.asm @@ -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!) diff --git a/main.inc b/main.inc index 6391be5..35af654 100644 --- a/main.inc +++ b/main.inc @@ -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 - diff --git a/n64.inc b/n64.inc index 2be051d..905ae7e 100644 --- a/n64.inc +++ b/n64.inc @@ -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)