This repository has been archived by the owner on Jul 24, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
kernel.asm
552 lines (467 loc) · 14.4 KB
/
kernel.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
// not really a kernel,
// just handling some low-level stuff like interrupts.
Start:
include "init.asm"
// SP defaults to RSP instruction memory: 0xA4001FF0
// we can do better than that.
la sp, K_STACK_INIT
// 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 the callee's argument registers.
subiu sp, sp, 0x10
sd r0, 0(sp)
sd r0, 8(sp)
lui gp, K_BASE
// TODO: just wipe a portion of RAM?
// or just DMA in the ISR and our defaults from ROM...
sw r0, K_64DRIVE_MAGIC(gp)
sw r0, K_REASON(gp)
sw r0, K_UNUSED(gp)
sw r0, K_CONSOLE_AVAILABLE(gp)
sw r0, K_HISTORY(gp)
sw r0, KV_RES(gp)
sw r0, KV_MODE(gp)
sw r0, KV_ORIGIN(gp)
Drive64Init:
lui t9, CI_BASE
lui t2, 0x5544 // "UD" of "UDEV"
lw t1, CI_HW_MAGIC(t9)
ori 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(gp)
sw t9, K_CI_BASE(gp)
// 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
Drive64CheckConsole:
// NOTE: we only check at boot, so disconnecting the console
// while running will cause a ton of lag (timeouts) until reset.
_WriteString(KS_ConsoleConfirmed)
lli t0, 1
beqzl v0, Drive64Done
sw t0, K_CONSOLE_AVAILABLE(gp)
Drive64Done:
// zero out RDRAM from 1 MiB to 4 MiB
// NOTE: this might overwrite the last 4 KiB of ROM that's loaded by 6102?
li t0, 0x80100000
li t1, 0x80400000
-
define x(0)
while {x} < 0x80 {
// sd is roughly the same speed as sw here and saves code size.
sd r0, {x}(t0)
evaluate x({x} + 8)
}
addiu t0, 0x80
bne t0, t1,-
nop
WipeRegisters:
// load up most registers with a dummy value for debugging
lui at, 0xCAFE
ori at, 0xBABE
dsll at, 16
// attempting to use this as an address should trigger an interrupt
ori at, 0xDEAD
dsll at, 16
ori at, 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) // align to row for cache-poking purposes
_InterruptStart: // label 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
Interrupt_TBL_Refill:
la k0, InterruptHandler
jr k0
lli k1, K_INT_TLB_REFILL
nops(0x80000080)
Interrupt_XTLB_Refill:
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: // label for copying purposes
InterruptHandler:
lui k0, K_BASE
sw k1, K_REASON(k0)
sd at, K_DUMP+0x08(k0)
// disable interrupts
mfc0 k1, CP0_Status
addiu at, r0, ~CP0_STATUS_IE
sw k1, K_STATUS(k0)
and k1, k1, at
mtc0 k1, CP0_Status
mfc0 k1, CP0_Cause
sw k1, K_CAUSE(k0)
// TODO: dump COP1 registers too (remember to check Status[FR])
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)
mfc0 k1, CP0_EPC // TODO: check validity?
sw k1, K_EPC(k0)
mfc0 k1, CP0_ErrorPC // TODO: check validity?
sw k1, K_ERRORPC(k0)
mfc0 k1, CP0_BadVAddr
sw k1, K_BADVADDR(k0)
// be wary, this is a tiny temporary stack!
ori sp, k0, K_STACK
ISR_Main: // free to modify any GPR from here to ISR_Exit
KWriteString(KS_Newline)
KWriteString(KS_Handling)
KWriteString(KS_Code)
// handle timer interrupt
lw t0, K_CAUSE(k0)
andi t0, CP0_CAUSE_IP7
beqz t0, ISR_CountDone
nop
KWriteString(KS_Timer)
mtc0 r0, CP0_Compare
ISR_CountDone:
// switch-case on the cause code:
// conveniently, the ExcCode in Cause is already shifted left by 2.
lw t4, K_CAUSE(k0)
la t3, KCodes
andi t4, CP0_CAUSE_CODE
addu t3, t4
lw t4, 0(t3)
jr t4
nop
KCodeDone:
if K_DEBUG {
ori a0, k0, K_XXD
sd r0, 0x1B8(a0)
sd r0, 0x1C0(a0)
sd r0, 0x1C8(a0)
sd r0, 0x1D0(a0)
sd r0, 0x1D8(a0)
sd r0, 0x1E0(a0)
sd r0, 0x1E8(a0)
sd r0, 0x1F0(a0)
sd r0, 0x1F8(a0)
jal DumpRegisters
lli a1, 0x200
KWriteString(KS_Newline)
ori a0, k0, K_XXD
jal Drive64Write
lli a1, 0x200
KWriteString(KS_Newline)
KWriteString(KS_States)
ori a0, k0, K_REASON
lli a1, 0x20
ori a2, k0, K_XXD
jal DumpAndWrite
lli a3, 0x20 * 4
KWriteString(KS_Newline)
}
ISR_Exit:
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, CP0_CAUSE_CODE
xori k1, k1, CP0_CODE_TR << 2 // check if this was a trap exception
bnez k1, ReturnFromInterrupt
mfc0 k0, CP0_EPC
ReturnFromTrap:
addiu k0, k0, 4 // TODO: this probably fails with branch delays?
mtc0 k0, CP0_EPC
ReturnFromInterrupt:
// restore interrupts
mfc0 k1, CP0_Status
ori k1, k1, 1
mtc0 k1, CP0_Status
eret // jump to EPC or ErrorPC depending on Status
// no branch delay for eret
KCode0:
KWriteString(KS_Code0)
K_MI_Loop:
lui a0, MI_BASE
lw s0, MI_INTR(a0)
beqz s0,+
andi t3, s0, MI_INTR_SP // delay slot
bnez t3, K_MI_SP
andi t4, s0, MI_INTR_SI // delay slot
bnez t4, K_MI_SI
andi t3, s0, MI_INTR_AI // delay slot
bnez t3, K_MI_AI
andi t4, s0, MI_INTR_VI // delay slot
bnez t4, K_MI_VI
andi t3, s0, MI_INTR_PI // delay slot
bnez t3, K_MI_PI
andi t4, s0, MI_INTR_DP // delay slot
bnez t4, K_MI_DP
nop
+
j KCodeDone
nop
K_MI_SP:
lli t0, SP_INT_CLR
lui a1, SP_BASE
sw t0, SP_STATUS(a1)
KWriteString(KS_MI_SP)
lw t0, K_HISTORY(k0)
ori t0, MI_INTR_SP
sw t0, K_HISTORY(k0)
j K_MI_Loop
andi s0, ~MI_INTR_SP
K_MI_SI:
lui a1, SI_BASE
sw r0, SI_STATUS(a1)
KWriteString(KS_MI_SI)
lw t0, K_HISTORY(k0)
ori t0, MI_INTR_SI
sw t0, K_HISTORY(k0)
j K_MI_Loop
andi s0, ~MI_INTR_SI
K_MI_AI:
lui a1, AI_BASE
sw r0, AI_STATUS(a1)
KWriteString(KS_MI_AI)
lw t0, K_HISTORY(k0)
ori t0, MI_INTR_AI
sw t0, K_HISTORY(k0)
j K_MI_Loop
andi s0, ~MI_INTR_AI
K_MI_VI:
lw a0, KV_RES(k0)
lw a1, KV_MODE(k0)
jal SetScreenNTSC
lw a2, KV_ORIGIN(k0)
KWriteString(KS_MI_VI)
lw t0, K_HISTORY(k0)
ori t0, MI_INTR_VI
sw t0, K_HISTORY(k0)
j K_MI_Loop
andi s0, ~MI_INTR_VI
K_MI_PI:
lli t0, 0x02
lui a1, PI_BASE
sw t0, PI_STATUS(a1)
KWriteString(KS_MI_PI)
lw t0, K_HISTORY(k0)
ori t0, MI_INTR_PI
sw t0, K_HISTORY(k0)
j K_MI_Loop
andi s0, ~MI_INTR_PI
K_MI_DP:
lli t0, 0x0800
lui a1, MI_BASE
sw t0, MI_INIT_MODE(a1)
KWriteString(KS_MI_DP)
lw t0, K_HISTORY(k0)
ori t0, MI_INTR_DP
sw t0, K_HISTORY(k0)
j K_MI_Loop
andi s0, ~MI_INTR_DP
KCode1:; KWriteString(KS_Code1); j KCodeDone; nop
KCode2:; KWriteString(KS_Code2); j KCodeDone; nop
KCode3:; KWriteString(KS_Code3); j KCodeDone; nop
KCode4:; KWriteString(KS_Code4); j KCodeDone; nop
KCode5:; KWriteString(KS_Code5); j KCodeDone; nop
KCode6:; KWriteString(KS_Code6); j KCodeDone; nop
KCode7:; KWriteString(KS_Code7); j KCodeDone; nop
KCode8:; KWriteString(KS_Code8); j KCodeDone; nop
KCode9:; KWriteString(KS_Code9); j KCodeDone; nop
KCode10:; KWriteString(KS_Code10); j KCodeDone; nop
KCode11:; KWriteString(KS_Code11); j KCodeDone; nop
KCode12:; KWriteString(KS_Code12); j KCodeDone; nop
KCode13:; KWriteString(KS_Code13); j KCodeDone; nop
KCode14:; KWriteString(KS_Code14); j KCodeDone; nop
KCode15:; KWriteString(KS_Code15); j KCodeDone; nop
KCode16:; KWriteString(KS_Code16); j KCodeDone; nop
KCode17:; KWriteString(KS_Code17); j KCodeDone; nop
KCode18:; KWriteString(KS_Code18); j KCodeDone; nop
KCode19:; KWriteString(KS_Code19); j KCodeDone; nop
KCode20:; KWriteString(KS_Code20); j KCodeDone; nop
KCode21:; KWriteString(KS_Code21); j KCodeDone; nop
KCode22:; KWriteString(KS_Code22); j KCodeDone; nop
KCode23:; KWriteString(KS_Code23); j KCodeDone; nop
KCode24:; KWriteString(KS_Code24); j KCodeDone; nop
KCode25:; KWriteString(KS_Code25); j KCodeDone; nop
KCode26:; KWriteString(KS_Code26); j KCodeDone; nop
KCode27:; KWriteString(KS_Code27); j KCodeDone; nop
KCode28:; KWriteString(KS_Code28); j KCodeDone; nop
KCode29:; KWriteString(KS_Code29); j KCodeDone; nop
KCode30:; KWriteString(KS_Code30); j KCodeDone; nop
KCode31:; KWriteString(KS_Code31); j KCodeDone; nop
KCodes:
dw KCode0, KCode1, KCode2, KCode3
dw KCode4, KCode5, KCode6, KCode7
dw KCode8, KCode9, KCode10, KCode11
dw KCode12, KCode13, KCode14, KCode15
dw KCode16, KCode17, KCode18, KCode19
dw KCode20, KCode21, KCode22, KCode23
dw KCode24, KCode25, KCode26, KCode27
dw KCode28, KCode29, KCode30, KCode31
K_SetScreenNTSC:
lui a3, K_BASE
sw a0, KV_RES(a3)
sw a1, KV_MODE(a3)
sw a2, KV_ORIGIN(a3)
// fall-thru
MakeSetScreenNTSC()
include "debug.asm"
if K_DEBUG {
KS(KS_Newline, 10)
KSL(KS_ConsoleConfirmed, "USB debug console detected")
KSL(KS_Handling, " ~~ Handling Interrupt ~~")
KSL(KS_States, " Interrupt States:")
KS(KS_Code, " Interrupt Type: ")
KSL(KS_Code0, "Regular Interrupt")
KSL(KS_Code1, "TLB Modification Exception")
KSL(KS_Code2, "TLB Exception (Load/Fetch)")
KSL(KS_Code3, "TLB Exception (Store)")
KSL(KS_Code4, "Address Error Exception (Load/Fetch)")
KSL(KS_Code5, "Address Error Exception (Store)")
KSL(KS_Code6, "Bus Error Exception (Fetch)")
KSL(KS_Code7, "Bus Error Exception (Load/Store)")
KSL(KS_Code8, "SysCall Exception")
KSL(KS_Code9, "Breakpoint Exception")
KSL(KS_Code10, "Reserved Instruction Exception")
KSL(KS_Code11, "Coprocessor Unusable Exception")
KSL(KS_Code12, "Arithmetic Overflow Exception")
KSL(KS_Code13, "Trap Exception")
KSL(KS_Code14, "RESERVED 14")
KSL(KS_Code15, "Floating Point Exception")
KSL(KS_Code16, "RESERVED 16")
KSL(KS_Code17, "RESERVED 17")
KSL(KS_Code18, "RESERVED 18")
KSL(KS_Code19, "RESERVED 19")
KSL(KS_Code20, "RESERVED 20")
KSL(KS_Code21, "RESERVED 21")
KSL(KS_Code22, "RESERVED 22")
KSL(KS_Code23, "Watch")
KSL(KS_Code24, "RESERVED 24")
KSL(KS_Code25, "RESERVED 25")
KSL(KS_Code26, "RESERVED 26")
KSL(KS_Code27, "RESERVED 27")
KSL(KS_Code28, "RESERVED 28")
KSL(KS_Code29, "RESERVED 29")
KSL(KS_Code30, "RESERVED 30")
KSL(KS_Code31, "RESERVED 31")
KSL(KS_Timer, " * Timer Interrupt")
KSL(KS_MI_SP, " * Signal Processor Interrupt")
KSL(KS_MI_SI, " * Serial Interface Interrupt")
KSL(KS_MI_AI, " * Audio Interface Interrupt")
KSL(KS_MI_VI, " * Video Interface Interrupt")
KSL(KS_MI_PI, " * Peripheral Interface Interrupt")
KSL(KS_MI_DP, " * Display Processor Interrupt")
}
align(4)
nops((K_BASE << 16) + 0x10000)