lots of work on the interrupt handler

This commit is contained in:
Connor Olding 2018-08-18 16:39:57 +02:00
parent fdf34f3934
commit cb786efd21
6 changed files with 183 additions and 63 deletions

View file

@ -39,7 +39,7 @@ macro CI_WAIT() {
lw t0, CI_STATUS(t9) lw t0, CI_STATUS(t9)
srl t0, t0, 12 // first 12 bits are reserved, so ignore them srl t0, t0, 12 // first 12 bits are reserved, so ignore them
bnez t0,- bnez t0,-
nop // delay slot nop
} }
macro CI_USB_WRITE_WAIT() { macro CI_USB_WRITE_WAIT() {
@ -48,5 +48,5 @@ macro CI_USB_WRITE_WAIT() {
lw t0, CI_USB_COMMAND_STATUS(t9) lw t0, CI_USB_COMMAND_STATUS(t9)
srl t0, t0, 4 // shift out ARM status, leaving WRITE status srl t0, t0, 4 // shift out ARM status, leaving WRITE status
bnez t0,- bnez t0,-
nop // delay slot nop
} }

View file

@ -6,7 +6,6 @@ Drive64Write:
// v0: error code (0 is OK) // v0: error code (0 is OK)
// TODO: a0 should be double-word aligned if used directly with DMA // TODO: a0 should be double-word aligned if used directly with DMA
// assert a0 (RAM address) is word-aligned // assert a0 (RAM address) is word-aligned
andi t9, a0, 3 andi t9, a0, 3
bnezl t9, Drive64WriteExit bnezl t9, Drive64WriteExit
@ -27,19 +26,19 @@ Drive64Write:
andi t6, a0, 0xF andi t6, a0, 0xF
addu t7, a0, a1 // stop flushing around here addu t7, a0, a1 // stop flushing around here
subu t6, a0, t6 // align a0 to data line subu t6, a0, t6 // align a0 to data line
subiu t7, t7, 1 // turn inclusive end-point into exclusive instead
- -
cache 1, 0(t6) // peter says: "Index Writeback Invalidate" cache 1, 0(t6) // data cache Index Writeback Invalidate
addiu t6, 0x10 // (delay slot) += data line size
sltu at, t6, t7 sltu at, t6, t7
bnez at,- bnez at,-
addiu t6, 0x10 // (delay slot) += data line size nop
// AND off the DRAM address // AND off the DRAM address
li t9, 0x007FFFFF // __osPiRawStartDma uses 0x1FFFFFFF? li t9, 0x007FFFFF // __osPiRawStartDma uses 0x1FFFFFFF?
and t1, a0, t9 and t1, a0, t9
// cart address // cart address
move t2, a2 or t2, a2, r0
// set length (needs to be decremented due to DMA quirk) // set length (needs to be decremented due to DMA quirk)
subiu t3, a3, 1 subiu t3, a3, 1
@ -91,16 +90,21 @@ DumpAndWrite:
// v0: error code (0 is OK) // v0: error code (0 is OK)
subiu sp, sp, 0x20 subiu sp, sp, 0x20
sw ra, 0x10(sp) sw ra, 0x10(sp)
// TODO: i think i can just use the a0,a1,a2,a3 slots here? // TODO: can i just use the a0,a1,a2,a3 slots here?
sw s0, 0x14(sp) sw s0, 0x14(sp)
sw s1, 0x18(sp) sw s1, 0x18(sp)
or s0, a2, r0 or s0, a2, r0
jal xxd jal xxd
or s1, a3, r0 or s1, a3, r0
// v0 passthru
bnez v0, DumpAndWriteExit bnez v0, DumpAndWriteExit
lui t0, K_BASE // delay slot
lw t1, K_64DRIVE_MAGIC(t0)
beqz t1, DumpAndWriteExit
ori a0, s0, r0 // delay slot ori a0, s0, r0 // delay slot
jal Drive64Write jal Drive64Write
ori a1, s1, r0 ori a1, s1, r0

View file

@ -2,6 +2,7 @@
// just handling some low-level stuff like interrupts. // just handling some low-level stuff like interrupts.
Start: Start:
mtc0 r0, CP0_Cause // clear cause
lui k0, K_BASE lui k0, K_BASE
// copy our interrupt handlers into place. // copy our interrupt handlers into place.
@ -12,28 +13,49 @@ Start:
ld t3, 0(t1) ld t3, 0(t1)
ld t4, 8(t1) ld t4, 8(t1)
addiu t1, t1, 0x10 addiu t1, t1, 0x10
ld t3, 0(t0) sd t3, 0(t0)
sd t4, 8(t0) sd t4, 8(t0)
addiu t0, t0, 0x10 cache 0x19, 0(t0) // tell data cache to write itself out
cache 0x10, 0(t0) // tell instruction cache it needs to reload
// an instruction cache line is 2 rows, and a data cache line is 1 row, so
// i'm hoping just poking at the start of each row is enough to flush them.
bne t1, t2,- bne t1, t2,-
cache 1, 0(t0) // not sure if this is necessary, but it doesn't hurt. addiu t0, t0, 0x10
// enable SI and PI interrupts. // enable SI and PI interrupts.
lui a0, PIF_BASE lui a0, PIF_BASE
lli t0, 8 lli t0, 8
sw t0, PIF_RAM+0x3C(a0) sw t0, PIF_RAM+0x3C(a0)
// enable CPU interrupts.
mfc0 t1, CP0_Status
ori t1, t1, CP0_STATUS_IM_ALL
mtc0 t1, CP0_Status
// enable even more interrupts.
lui t2, MI_BASE
ori t2, t2, MI_INTR_MASK
lli t0, 0xAAA // LSB to MSB: SP, SI, AI, VI, PI, DP
// by the way, use 0x555 to disable
sw t0, 0(t2)
// it looks like i should be initializing PI_BSD_DOM1_* from
// the ROM header at this point, but i don't know what even does does.
// SP defaults to RSP instruction memory: 0xA4001FF0 // SP defaults to RSP instruction memory: 0xA4001FF0
// we can do better than that. // we can do better than that.
lui sp, K_STACK_INIT_BASE lui sp, K_STACK_INIT_BASE
// SP should always be 8-byte aligned // SP should always be 8-byte aligned
// so that SD and LD instructions don't fail on it. // 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 // we also need 4 empty words for storing
// the 32-bit values of the callee's arguments.
subiu sp, sp, 0x10 subiu sp, sp, 0x10
// TODO: just wipe a portion of RAM? // TODO: just wipe a portion of RAM?
// or just DMA in the IH and our defaults from ROM...
sw r0, K_64DRIVE_MAGIC(k0) sw r0, K_64DRIVE_MAGIC(k0)
sw r0, K_REASON(k0) sw r0, K_REASON(k0)
sw r0, K_IN_MAIN(k0)
Drive64Init: Drive64Init:
lui t9, CI_BASE lui t9, CI_BASE
@ -62,9 +84,24 @@ Drive64Confirmed:
Drive64Done: Drive64Done:
// clear internal exception/interrupt value // delay to empty pipeline?
ori k1, r0, r0 nop
nop
nop
nop
nop
// try out an interrupt:
//sw r0, 0(r0)
mfc0 t1, CP0_Status
ori t1, 2
mtc0 t1, CP0_Status
la t0, WipeRegisters
mtc0 t0, CP0_EPC
j InterruptHandler
nop
WipeRegisters:
// load up most registers with a dummy value for debugging // load up most registers with a dummy value for debugging
lui at, 0xCAFE lui at, 0xCAFE
ori at, r0, 0xBABE ori at, r0, 0xBABE
@ -106,8 +143,8 @@ Drive64Done:
j Main j Main
nop nop
align(0x10) align(0x10) // align to row for cache-poking purposes
_InterruptStart: // for copying purposes _InterruptStart: // label for copying purposes
pushvar base pushvar base
// note that we jump to the handler by jr instead of j // note that we jump to the handler by jr instead of j
@ -140,7 +177,7 @@ InterruptOther:
nops(0x80000200) nops(0x80000200)
pullvar base pullvar base
_InterruptEnd: // for copying purposes _InterruptEnd: // label for copying purposes
InterruptHandler: InterruptHandler:
lui k0, K_BASE lui k0, K_BASE
@ -149,9 +186,9 @@ InterruptHandler:
sd at, K_DUMP+0x08(k0) sd at, K_DUMP+0x08(k0)
// disable interrupts, clear exception and error level bits: // disable interrupts, clear exception and error level bits:
mfc0 at, CP0_Status mfc0 k1, CP0_Status
sw at, K_STATUS(k0) // TODO: restored later addiu at, r0, ~CP0_STATUS_IE
addiu at, r0, 0xFFFC sw k1, K_STATUS(k0)
and k1, k1, at and k1, k1, at
mtc0 k1, CP0_Status mtc0 k1, CP0_Status
@ -159,7 +196,7 @@ InterruptHandler:
sw k1, K_CAUSE(k0) sw k1, K_CAUSE(k0)
// TODO: option to only store clobbered registers // TODO: option to only store clobbered registers
// TODO: option to dump COP1 registers too // TODO: option to dump COP1 registers too (remember to check Status[FR])
sd r0, K_DUMP+0x00(k0) // intentional (it'd be weird if sd r0, K_DUMP+0x00(k0) // intentional (it'd be weird if
// r0 showed as nonzero in memory dumps) // r0 showed as nonzero in memory dumps)
@ -199,30 +236,75 @@ InterruptHandler:
sd t0, K_DUMP+0x100(k0) sd t0, K_DUMP+0x100(k0)
sd t1, K_DUMP+0x108(k0) sd t1, K_DUMP+0x108(k0)
mfc0 k1, CP0_EPC // TODO: check that this is valid?
sw k1, K_EPC(k0)
mfc0 k1, CP0_ErrorPC // TODO: check that this is valid?
sw k1, K_ERRORPC(k0)
mfc0 k1, CP0_BadVAddr
sw k1, K_BADVADDR(k0)
if K_DEBUG {
// prevent recursive interrupts if IHMain somehow causes an interrupt
lw t1, K_IN_MAIN(k0)
bnez t1, IHExit
lli t0, 1
sw t0, K_IN_MAIN(k0)
// be wary, this is a tiny temporary stack! // be wary, this is a tiny temporary stack!
ori sp, k0, K_STACK ori sp, k0, K_STACK
IHMain: // free to modify any GPR from here to IHExit IHMain: // free to modify any GPR from here to IHExit
la a2, IHString macro KDumpString(str) {
lw t1, K_64DRIVE_MAGIC(k0)
beqz t1,+
la a2, {str}
jal Drive64WriteDirect jal Drive64WriteDirect
lli a3, 0x20 //IHString.size lli a3, 0x20 // str.size
+
}
ori a0, k0, K_DUMP KDumpString(KNewline)
lli a1, 0x100 KDumpString(KString0)
ori a0, k0, K_DUMP + 0x80 * 0
lli a1, 0x80
ori a2, k0, K_XXD ori a2, k0, K_XXD
jal DumpAndWrite jal DumpAndWrite
lli a3, 0x400 lli a3, 0x80 * 4
ori a0, k0, K_DUMP KDumpString(KNewline)
addiu a0, a0, 0x100
lli a1, 0x100 ori a0, k0, K_DUMP + 0x80 * 1
lli a1, 0x80
ori a2, k0, K_XXD ori a2, k0, K_XXD
jal DumpAndWrite jal DumpAndWrite
lli a3, 0x400 lli a3, 0x80 * 4
KDumpString(KNewline)
// currently just 0x10 in size: LO and HI registers.
ori a0, k0, K_DUMP + 0x80 * 2
lli a1, 0x10
ori a2, k0, K_XXD
jal DumpAndWrite
lli a3, 0x10 * 4
KDumpString(KNewline)
KDumpString(KString1)
ori a0, k0, K_DUMP + 0x80 * 4
lli a1, 0x80
ori a2, k0, K_XXD
jal DumpAndWrite
lli a3, 0x80 * 4
IHExit: IHExit:
sw r0, K_IN_MAIN(k0)
jal Drive64Write }
lui k0, K_BASE lui k0, K_BASE
ld t0, K_DUMP+0x100(k0) ld t0, K_DUMP+0x100(k0)
@ -261,13 +343,13 @@ IHExit:
ld ra, K_DUMP+0xF8(k0) ld ra, K_DUMP+0xF8(k0)
lw k1, K_CAUSE(k0) lw k1, K_CAUSE(k0)
andi k1, k1, 0x2000 // check if this was a trap exception xori k1, k1, 13 << 2 // check if this was a trap exception
bnez k1, ReturnFromInterrupt
mfc0 k0, CP0_EPC mfc0 k0, CP0_EPC
beqz k1, ReturnFromInterrupt
sw k0, K_EPC(k0)
ReturnFromTrap: ReturnFromTrap:
addiu k0, k0, 4 addiu k0, k0, 4 // TODO: this probably fails with branch delays?
mtc0 k0, CP0_EPC
ReturnFromInterrupt: ReturnFromInterrupt:
// restore interrupts // restore interrupts
@ -275,16 +357,33 @@ ReturnFromInterrupt:
ori k1, k1, 1 ori k1, k1, 1
mtc0 k1, CP0_Status mtc0 k1, CP0_Status
// wait, shouldn't this be ERET? // eret pseudo-code:
rfe //if status & 4 then
jr k0 // jump to ErrorPC
or k1, r0, r0 // clear status & 4
//elseif status & 2 then
// jump to EPC
// clear status & 2
//else
// raise new exception???
//end
eret
// no branch delay for eret
include "debug.asm" include "debug.asm"
align(4) align(4)
IHString: KString0:
db " ~~~ Interrupt Handled ~~~ ", 0 db " ~~ Interrupt Handled ~~", 10, 0
align(4)
KString1:
db " Interrupt States:", 10, 0
align(4)
KNewline:
db 10, 0, 0, 0
dw 0, 0, 0
align(4) align(4)
nops((K_BASE << 16) + 0x10000) nops((K_BASE << 16) + 0x10000)

View file

@ -37,30 +37,14 @@ include "lz.asm"
mfc0 t0, CP0_Count mfc0 t0, CP0_Count
sw t0, BLAH_COUNTS+8(s0) sw t0, BLAH_COUNTS+8(s0)
lui t0, K_BASE
lw t1, K_64DRIVE_MAGIC(t0)
beqz t1, InitVideo
nop // delay slot
// jal Drive64TestWrite
// nop // delay slot
lui a0, BLAH_BASE lui a0, BLAH_BASE
lli a1, 0x20 lli a1, 0x20
ori a2, a0, BLAH_XXD ori a2, a0, BLAH_XXD
jal DumpAndWrite
lli a3, 0x20 * 4 lli a3, 0x20 * 4
jal xxd
nop // delay slot
lui a0, BLAH_BASE // write address
ori a0, a0, BLAH_XXD // (RAM gets copied to SDRAM by routine)
lli a1, 0x20 * 4
jal Drive64Write
nop // delay slot
InitVideo: // currently 80001190 (this comment is likely out of date)
// A4000FC0
InitVideo:
jal LoadRSPBoot jal LoadRSPBoot
nop nop

View file

@ -1,21 +1,32 @@
// settings:
constant K_DEBUG(1) // slows down interrupt handling to enable debug routines
// address stuff:
constant UNCACHED(0xA0000000) constant UNCACHED(0xA0000000)
constant ADDR_MASK(0x1FFFFFFF) constant ADDR_MASK(0x1FFFFFFF)
// "kernel" constants: // "kernel" constants:
constant K_BASE(0x8000) // k0 is set to this. constant K_BASE(0x8000) // k0 is set to this.
constant K_DUMP(0x0400) // we save registers and state here constant K_DUMP(0x0400) // we save registers and state here
// when handling interrupts // when handling interrupts
constant K_REASON(0x0600) constant K_REASON(0x0600)
constant K_CAUSE(0x0604) constant K_CAUSE(0x0604)
constant K_STATUS(0x0608) constant K_STATUS(0x0608)
constant K_EPC(0x060C) constant K_IN_MAIN(0x060C)
constant K_EPC(0x0610)
constant K_ERRORPC(0x0614)
constant K_BADVADDR(0x0618)
constant K_64DRIVE_MAGIC(0x0700) constant K_64DRIVE_MAGIC(0x0700)
constant K_CI_BASE(0x0704) constant K_CI_BASE(0x0704)
constant K_STACK(0xC00 - 8)
constant K_STACK(0x0C00 - 0x10)
constant K_XXD(0x0C00) // size: 0x400 (any larger and you overwrite kernel code) constant K_XXD(0x0C00) // size: 0x400 (any larger and you overwrite kernel code)
constant K_STACK_INIT_BASE(0x803F) // note that this gets subtracted by 8 // note this gets subtracted by 0x10 and the stack grows *backwards.*
// and that the stack grows *backwards.* constant K_STACK_INIT_BASE(0x803F)
// internal interrupt enum: (0 means no known interrupt/exception) // internal interrupt enum: (0 means no known interrupt/exception)
constant K_INT_TLB_REFILL(1) constant K_INT_TLB_REFILL(1)

22
n64.inc
View file

@ -139,6 +139,28 @@ constant CP0_TagHi(29) // reserved
constant CP0_ErrorPC(30) constant CP0_ErrorPC(30)
constant CP0_Reserved_7(31) constant CP0_Reserved_7(31)
constant CP0_STATUS_IE($0001) // Interrupt Enable
constant CP0_STATUS_EXL($0002) // Exception Level
constant CP0_STATUS_ERL($0004) // Error Level
constant CP0_STATUS_IM0($0100) // Interrupt Mask 0 (Software)
constant CP0_STATUS_IM1($0200) // Interrupt Mask 1 (Software)
constant CP0_STATUS_IM2($0400) // Interrupt Mask 2 (External)
constant CP0_STATUS_IM3($0800) // Interrupt Mask 3 (External)
constant CP0_STATUS_IM4($1000) // Interrupt Mask 4 (External)
constant CP0_STATUS_IM5($2000) // Interrupt Mask 5 (External)
constant CP0_STATUS_IM6($4000) // Interrupt Mask 6 (External)
constant CP0_STATUS_IM7($8000) // Interrupt Mask 7 (External)
constant CP0_STATUS_IM_ALL($FF01) // enable all interrupts
constant CP0_CAUSE_IP0($0100) // Interrupt Pending 0 (Software)
constant CP0_CAUSE_IP1($0200) // Interrupt Pending 1 (Software)
constant CP0_CAUSE_IP2($0400) // Interrupt Pending 2 (External)
constant CP0_CAUSE_IP3($0800) // Interrupt Pending 3 (External)
constant CP0_CAUSE_IP4($1000) // Interrupt Pending 4 (External)
constant CP0_CAUSE_IP5($2000) // Interrupt Pending 5 (External)
constant CP0_CAUSE_IP6($4000) // Interrupt Pending 6 (External)
constant CP0_CAUSE_IP7($8000) // Interrupt Pending 7 (External)
// Memory Map // Memory Map
constant RDRAM($A000) // $00000000..$003FFFFF RDRAM Memory 4MB ($00000000..$007FFFFF 8MB With Expansion Pak) constant RDRAM($A000) // $00000000..$003FFFFF RDRAM Memory 4MB ($00000000..$007FFFFF 8MB With Expansion Pak)