/
ipl3.s
1541 lines (1387 loc) · 53.4 KB
/
ipl3.s
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
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#include <sys/asm.h>
#include <sys/regdef.h>
#include <PR/R4300.h>
#include <PR/rcp.h>
/* Magic value to multiply the ROM checksum CIC seed by */
#ifdef IPL3_X103
#define ROM_CHECKSUM_MAGIC 0x6C078965
#else
#define ROM_CHECKSUM_MAGIC 0x5D588B65
#endif
#if defined(IPL3_X103)
#define CIC_TYPE 6103
#elif defined(IPL3_X105)
#define CIC_TYPE 6105
#endif
/*
* http://pdf.datasheetcatalog.com/datasheet/oki/MSM5718B70.pdf pg21
*/
#define RASINTERVAL(RowPrecharge, RowSense, RowImpRestore, RowExpRestore) \
((((RowPrecharge) & 0x1F) << 24) | \
(((RowSense) & 0x1F) << 16) | \
(((RowImpRestore) & 0x1F) << 8) | \
(((RowExpRestore) & 0x1F) << 0))
/*
* http://pdf.datasheetcatalog.com/datasheet/oki/MSM5718B70.pdf pg20
*/
#define RDRAM_DELAY(AckWinDelay, ReadDelay, AckDelay, WriteDelay) \
((((AckWinDelay) & 7) << 3 << 24) | \
(((ReadDelay) & 7) << 3 << 16) | \
(((AckDelay) & 3) << 3 << 8) | \
(((WriteDelay) & 7) << 3 << 0))
#define ROT16(x) ((((x) & 0xFFFF0000) >> 16) | (((x) & 0xFFFF) << 16))
#define DEVICE_TYPE(Bank, Row, Col, Bonus, EnhancedSpeed, Version, Type) \
((((Col) & 0xF) << 28) | \
(((Bonus) & 1) << 26) | \
(((EnhancedSpeed) & 1) << 24) | \
(((Bank) & 0xF) << 20) | \
(((Row) & 0xF) << 16) | \
(((Version) & 0xF) << 4) | \
(((Type) & 0xF) << 0))
#define RDRAM_DEVICE_TYPE_ES (1 << 24) /* Enhanced speed */
#define RDRAM_MANUFACTURER_NEC 0x500
#define RI_REFRESH(Banks, Optimize, Enable, Bank, DirtyDelay, CleanDelay) \
((((Banks) & 0x1FFF) << 19) | \
(((Optimize) & 1) << 18) | \
(((Enable) & 1) << 17) | \
(((Bank) & 1) << 16) | \
(((DirtyDelay) & 0xFF) << 8) | \
(((CleanDelay) & 0xFF) << 0))
#define RI_CONFIG_CC_AUTO 0x40
#define RDRAM_MODE_DEVICE_ENABLE 0x02000000 /*DE=1*/
#define RDRAM_MODE_AUTO_SKIP 0x04000000 /*AS=1*/
#define RDRAM_MODE_CC_MULT 0x40000000 /*X2=1*/
#define RDRAM_MODE_CC_ENABLE 0x80000000 /*CE=1*/
#define CC_AUTO 1
#define CC_MANUAL 2
/* IPL3 @ 0xA4000040 (DMEM + 0x40 KSEG1) */
#ifdef IPL3_X105
LEAF(ipl3_entry)
.set noreorder
add t1, sp, zero /* sp is somewhere in a stack at the end of IMEM */
1:
lw t0, -0xFF0(t1)
lw t2, 0x44(t3) /* t3 = DMEM + 0x40, loads from 0xA4000088 */
xor t2, t2, t0
sw t2, -0xFF0(t1)
addi t3, t3, 4
andi t0, t0, 0xfff
bnez t0, 1b
addi t1, t1, 4
lw t0, 0x44(t3)
lw t2, 0x48(t3)
sw t0, -0xFF0(t1)
sw t2, -0xFEC(t1)
bltz ra, ipl3
sw zero, -0xFE8(t1)
.set reorder
END(ipl3_entry)
.set noreorder
.word 0x00000000, 0x00000000
/* 0xA4000088, used by above code */
.word 0x7C1C97C0, 0x9B88F802, 0x05BC16E0, 0x71990080, 0x7511FE14, 0x7C9CB7C0, 0xCD391024, 0x2A2B4FFF
.word 0x40113000, 0x0800046E, 0x3C0BA4B0, 0x01600008, 0x02F3B820
.set reorder
#endif /* IPL3_X105 */
LEAF(ipl3)
MTC0( zero, C0_CAUSE)
MTC0( zero, C0_COUNT)
MTC0( zero, C0_COMPARE)
la t0, PHYS_TO_K1(RI_BASE_REG)
lw t1, (RI_SELECT_REG - RI_BASE_REG)(t0)
.set noreorder
bnez t1, nmi
nop
addiu sp, sp, -0x18
sw s3, 0(sp)
sw s4, 4(sp)
sw s5, 8(sp)
sw s6, 0xC(sp)
sw s7, 0x10(sp)
la t0, PHYS_TO_K1(RI_BASE_REG)
/* writes to RDRAM registers through the global config will be broadcast to all units */
li t2, PHYS_TO_K1(RDRAM_BASE_REG | RDRAM_GLOBAL_CONFIG)
/* write only to the currently selected unit */
li t3, PHYS_TO_K1(RDRAM_BASE_REG)
la t4, PHYS_TO_K1(MI_BASE_REG)
/* set current control to automatic */
ori t1, zero, RI_CONFIG_CC_AUTO
sw t1, (RI_CONFIG_REG - RI_BASE_REG)(t0)
#if defined(IPL3_X103) || defined (IPL3_X106)
/* wait 8800 */
li s1, 8800
#else
/* wait 8000 */
li s1, 8000
#endif
wait_rac:
nop
addi s1, s1, -1
bnez s1, wait_rac
nop
sw zero, (RI_CURRENT_LOAD_REG - RI_BASE_REG)(t0)
/* Enable TX/RX select */
ori t1, zero, 0x10 | 4
sw t1, (RI_SELECT_REG - RI_BASE_REG)(t0)
/* Mode reset, stop active TX/RX disabled */
sw zero, (RI_MODE_REG - RI_BASE_REG)(t0)
/* wait */
li s1, 4
wait_rac1:
nop
addi s1, s1, -1
bnez s1, wait_rac1
nop
/* set standby, stop active TX, stop active RX */
ori t1, zero, 2 | 4 | 8
sw t1, (RI_MODE_REG - RI_BASE_REG)(t0)
#ifndef IPL3_6101
/* wait */
li s1, 32
wait_rdram:
addi s1, s1, -1
bnez s1, wait_rdram
#endif /* !IPL3_6101 */
/*
* Set MI init mode, length 15. This equentially repeats the next written value on the bus for 16 bytes total.
* e.g. for a word write 0xAABBCCDD the write data is extended to 0xAABBCCDDAABBCCDDAABBCCDDAABBCCDD
*
* This is required as the RDRAM delays have yet to be configured, so RDRAM transactions (including register
* read/write) do not behave correctly. For timings to work out when writing the delay register the value must be
* rotated by 16 bits and repeated for the delay register to be set to the correct value under the default delay
* configuration.
*
* https://n64brew.dev/wiki/RDRAM#Reset_Complications
*/
ori t1, zero, MI_SET_INIT | 15
sw t1, (MI_INIT_MODE_REG - MI_BASE_REG)(t4)
/* Set all Delays: AckWin=5, Read=7, Ack=3, Write=1 */
/* This must be the next bus write following setting MI Init mode for the reason explained above */
li t1, ROT16(RDRAM_DELAY(5, 7, 3, 1))
sw t1, (RDRAM_DELAY_REG - RDRAM_BASE_REG)(t2)
/* Set all Refresh Row to 0 */
sw zero, (RDRAM_REF_ROW_REG - RDRAM_BASE_REG)(t2)
/* Move all RDRAMs to physical address 0x2000000 */
li t1, 0x2000000 << 6
sw t1, (RDRAM_DEVICE_ID_REG - RDRAM_BASE_REG)(t2)
#define NumModules t5
#define InitialDeviceID t6
#define InitialRegBase t7
#define FinalDeviceID_1M t8
#define FinalRegBase_1M t9
#define TestAddr_1M s6
#define FinalDeviceID_2M s7
#define FinalRegBase_2M a2
#define TestAddr_2M a3
#define ModuleBitmask_2M s2
#define CCTestAddr s4
move NumModules, zero
move InitialDeviceID, zero
li InitialRegBase, PHYS_TO_K1(RDRAM_BASE_REG)
move FinalDeviceID_1M, zero
li FinalRegBase_1M, PHYS_TO_K1(RDRAM_BASE_REG)
li TestAddr_1M, K1BASE
move FinalDeviceID_2M, zero
li FinalRegBase_2M, PHYS_TO_K1(RDRAM_BASE_REG)
li TestAddr_2M, K1BASE
move ModuleBitmask_2M, zero
li CCTestAddr, K1BASE /* Where in memory to do CC value testing */
addiu sp, sp, -0x48
move s8, sp
/* check RCP silicon version */
lw s0, PHYS_TO_K1(MI_VERSION_REG)
la s1, 0x1010101 /* RSP:01 RDP:01 RAC:01 IO:01 */
bne s0, s1, rcp2
nop
/* RCP 1.0 */
li s0, 1 << 9 /* RCP 1.0 RDRAM regs spacing */
ori s1, t3, (0x2000000 >> 20) << 9
b loop1
nop
rcp2:
/* RCP 2.0 */
li s0, 1 << 10 /* RCP 2.0 RDRAM regs spacing */
ori s1, t3, (0x2000000 >> 20) << 10
/**
* Notes on RDRAM structure:
*
* RDRAMs are divided into:
* Physical chip, which are split into some number of
* Modules, which consist of
* Banks, divided up into
* Rows and Columns
*
* Modules are in one-to-one correspondence with the memory-mapped RDRAM registers.
*
* For RDRAM used by the N64:
* - only the 4MB chips are divided into multiple modules (2x 2MB). Otherwise they contain only one module
* (either 2MB or 1MB)
* - banks are always 1MB large so 2MB modules contain 2 banks and 1MB modules contain a single bank.
* - rows are 0x800 / 2048 bytes large.
*
* Note that above we ignored the 9th bit per byte in each measurement.
*/
/* detect present RDRAM modules and compute the Current Control (CC) value for them */
loop1:
/* set the first responder to the first available device ID */
sw InitialDeviceID, (RDRAM_DEVICE_ID_REG - RDRAM_BASE_REG)(s1)
/* try to find an appropriate CC value for this module */
addiu s5, InitialRegBase, RDRAM_MODE_REG - RDRAM_BASE_REG
jal InitCCValue
nop
/* failed, assume no module */
beqz v0, loop1_break
nop
/* save computed CC value for later */
sw v0, (sp)
/* determine module size by reading the RDRAM device type register */
li t1, MI_SET_RDRAM
sw t1, (MI_INIT_MODE_REG - MI_BASE_REG)(t4)
lw t3, (RDRAM_DEVICE_TYPE_REG - RDRAM_BASE_REG)(InitialRegBase)
li t0, 0xF0FF0000 /* Extracts 3x 4-bit values: Number of column/row/bank address bits for this module */
and t3, t3, t0
sw t3, 4(sp) /* save device type for later */
addi sp, sp, 8
li t1, MI_CLR_RDRAM
sw t1, (MI_INIT_MODE_REG - MI_BASE_REG)(t4)
li t0, DEVICE_TYPE(1, 9, 11, 0, 0, 0, 0) /* BNK=1 , ROW=9 , COL=11 => (1 << 1) * (1 << 9) * (1 << 11) = 2MB */
bne t3, t0, SM
nop
/* 2MB module */
li t0, 0x200000 << 6
add FinalDeviceID_1M, FinalDeviceID_1M, t0
/* Increment 1MB reg base by 2x reg spacing */
add FinalRegBase_1M, FinalRegBase_1M, s0
add FinalRegBase_1M, FinalRegBase_1M, s0
/* Increment test addresses */
li t0, 0x200000 /* 2MB */
add TestAddr_1M, TestAddr_1M, t0
add CCTestAddr, CCTestAddr, t0
/* Only 2MB modules are flagged? */
sll ModuleBitmask_2M, ModuleBitmask_2M, 1
addi ModuleBitmask_2M, ModuleBitmask_2M, 1
b LM
nop
SM:
/* 1MB module */
/* Increment test address */
li t0, 0x100000 /* 1MB */
add CCTestAddr, CCTestAddr, t0
LM:
/* Determine the device manufacturer and set appropriate RAS Interval */
li t0, MI_SET_RDRAM
sw t0, (MI_INIT_MODE_REG - MI_BASE_REG)(t4)
lw t1, (RDRAM_DEVICE_MANUF_REG - RDRAM_BASE_REG)(InitialRegBase)
lw k0, (RDRAM_DEVICE_TYPE_REG - RDRAM_BASE_REG)(InitialRegBase)
li t0, MI_CLR_RDRAM
sw t0, (MI_INIT_MODE_REG - MI_BASE_REG)(t4)
andi t1, t1, 0xFFFF
li t0, RDRAM_MANUFACTURER_NEC /* NEC Manufacturer ID */
bne t1, t0, toshiba
nop
li k1, RDRAM_DEVICE_TYPE_ES
and k0, k0, k1
bnez k0, toshiba
nop
/*other:*/
li t0, RASINTERVAL(16, 28, 10, 4)
sw t0, (RDRAM_RAS_INTERVAL_REG - RDRAM_BASE_REG)(InitialRegBase)
b done_manufacture
toshiba:
li t0, RASINTERVAL(8, 12, 18, 4)
sw t0, (RDRAM_RAS_INTERVAL_REG - RDRAM_BASE_REG)(InitialRegBase)
done_manufacture:
/* Increment device id by 2MB (regardless of whether it was a 2MB or 1MB module? bug? since CCTestAddr goes out of sync) */
li t0, 0x200000 << 6
add InitialDeviceID, InitialDeviceID, t0
/* Increment RDRAM reg base by 2x reg spacing (also regardless of 2MB or 1MB? also bug?) */
add InitialRegBase, InitialRegBase, s0
add InitialRegBase, InitialRegBase, s0
addiu NumModules, NumModules, 1
/* Only try up to 8 modules (either 1M or 2M for possible maximum of 16MB installed memory?) */
sltiu t0, NumModules, 8
bnez t0, loop1
nop
loop1_break:
/* move all modules to their final address space, sorting 2MB modules before 1MB modules */
/* broadcast global mode value and move all modules to address 0x2000000 */
li t0, RDRAM_MODE_CC_MULT | RDRAM_MODE_CC_ENABLE | RDRAM_MODE_AUTO_SKIP
sw t0, (RDRAM_MODE_REG - RDRAM_BASE_REG)(t2)
li t0, 0x2000000 << 6
sw t0, (RDRAM_DEVICE_ID_REG - RDRAM_BASE_REG)(t2)
move sp, s8
move v1, zero
loop2:
lw t1, 4(sp) /* reload saved device type */
li t0, DEVICE_TYPE(0, 9, 11, 0, 0, 0, 0) /* BNK=1 , ROW=9 , COL=11 => (1 << 0) * (1 << 9) * (1 << 11) = 1MB */
bne t1, t0, HM
nop
/* 1MB Module */
/* Set Device ID for first responder */
sw FinalDeviceID_1M, (RDRAM_DEVICE_ID_REG - RDRAM_BASE_REG)(s1)
/* Write optimal CC value (auto) */
addiu s5, FinalRegBase_1M, (RDRAM_MODE_REG - RDRAM_BASE_REG)
lw a0, (sp) /* Reload CC value computed prior */
addi sp, sp, 8
li a1, CC_AUTO
jal WriteCC
nop
/* 4 reads @ (TestAddr_1M) x2 & (TestAddr_1M + 0x80000) x2 */
lw t0, (TestAddr_1M)
li t0, 0x100000 / 2
add t0, t0, TestAddr_1M
lw t1, (t0)
lw t0, (TestAddr_1M)
li t0, 0x100000 / 2
add t0, t0, TestAddr_1M
lw t1, (t0)
/* @bug This should increment FinalDeviceID_1M, all 1MB RDRAMs are mapped to the same location */
li t0, 0x100000 << 6
add InitialDeviceID, InitialDeviceID, t0
/* Increment RDRAM register base by 1x reg spacing */
add FinalRegBase_1M, FinalRegBase_1M, s0
/* Increment test address */
li t0, 0x100000 /* 1MB */
add TestAddr_1M, TestAddr_1M, t0
b loop2_next
HM:
/* 2MB Module */
/* Set Device ID for first responder */
sw FinalDeviceID_2M, (RDRAM_DEVICE_ID_REG - RDRAM_BASE_REG)(s1)
/* Write optimal CC value (auto) */
addiu s5, FinalRegBase_2M, (RDRAM_MODE_REG - RDRAM_BASE_REG)
lw a0, (sp) /* Reload CC value computed prior */
addi sp, sp, 8
li a1, CC_AUTO
jal WriteCC
nop
/* 8 reads */
lw t0, (TestAddr_2M)
li t0, 0x80000*1
add t0, t0, TestAddr_2M
lw t1, (t0)
li t0, 0x80000*2
add t0, t0, TestAddr_2M
lw t1, (t0)
li t0, 0x80000*3
add t0, t0, TestAddr_2M
lw t1, (t0)
lw t0, (TestAddr_2M)
li t0, 0x80000*1
add t0, t0, TestAddr_2M
lw t1, (t0)
li t0, 0x80000*2
add t0, t0, TestAddr_2M
lw t1, (t0)
li t0, 0x80000*3
add t0, t0, TestAddr_2M
lw t1, (t0)
/* Increment Device ID by 2MB */
li t0, 0x200000 << 6
add FinalDeviceID_2M, FinalDeviceID_2M, t0
/* Increment RDRAM reg base by 2x reg spacing */
add FinalRegBase_2M, FinalRegBase_2M, s0
add FinalRegBase_2M, FinalRegBase_2M, s0
/* Increment test address */
li t0, 0x200000 /* 2MB */
add TestAddr_2M, TestAddr_2M, t0
loop2_next:
/* Loop until all detected modules are configured */
addiu v1, v1, 1
slt t0, v1, NumModules
bnez t0, loop2
nop
/* Set RI_REFRESH */
li t2, PHYS_TO_K1(RI_BASE_REG)
sll ModuleBitmask_2M, ModuleBitmask_2M, 19
li t1, RI_REFRESH(0, 1, 1, 0, 54, 52)
or t1, t1, ModuleBitmask_2M /* detected 2MB modules */
sw t1, (RI_REFRESH_REG - RI_BASE_REG)(t2)
lw t1, (RI_REFRESH_REG - RI_BASE_REG)(t2) /* dummy read? */
/* Save computed memory size */
#ifdef IPL3_X105
li t0, PHYS_TO_K1(0x000003F0)
li t1, 0xFFFFFFF
and TestAddr_1M, TestAddr_1M, t1
sw TestAddr_1M, (t0)
#else
li t0, PHYS_TO_K1(0x00000300)
li t1, 0xFFFFFFF
and TestAddr_1M, TestAddr_1M, t1
sw TestAddr_1M, 0x18(t0) /* osMemSize */
#endif
move sp, s8
addiu sp, sp, 0x48
lw s3, 0(sp)
lw s4, 4(sp)
lw s5, 8(sp)
lw s6, 0xC(sp)
lw s7, 0x10(sp)
addiu sp, sp, 0x18
.set reorder
/* Initialize cache (cold reset) */
la t0, K0BASE
addiu t1, t0, ICACHE_SIZE
addiu t1, t1, -ICACHE_LINESIZE
MTC0( zero, C0_TAGLO)
MTC0( zero, C0_TAGHI)
/* Index store tag icache */
1:
CACHE( CACH_PI | C_IST, t0)
.set noreorder
bltu t0, t1, 1b
addiu t0, t0, ICACHE_LINESIZE
.set reorder
la t0, K0BASE
addiu t1, t0, DCACHE_SIZE
addiu t1, t1, -DCACHE_LINESIZE
/* index store tag dcache */
2:
CACHE( CACH_PD | C_IST, t0)
.set noreorder
bltu t0, t1, 2b
addiu t0, t0, DCACHE_LINESIZE
b load_ipl3
nop
.set reorder
nmi:
/* Initialize cache (nmi) */
la t0, K0BASE
addiu t1, t0, ICACHE_SIZE
addiu t1, t1, -ICACHE_LINESIZE
MTC0( zero, C0_TAGLO)
MTC0( zero, C0_TAGHI)
/* index store tag icache */
1:
CACHE( CACH_PI | C_IST, t0)
.set noreorder
bltu t0, t1, 1b
addiu t0, t0, ICACHE_LINESIZE
.set reorder
la t0, K0BASE
addiu t1, t0, DCACHE_SIZE
addiu t1, t1, -DCACHE_LINESIZE
/* index-writeback-invalidate dcache */
2:
CACHE( CACH_PD | C_IWBINV, t0)
.set noreorder
bltu t0, t1, 2b
addiu t0, t0, DCACHE_LINESIZE
.set reorder
load_ipl3:
#ifdef IPL3_X106
mul t4, s6, 0x260BCD5
la t2, PHYS_TO_K1(SP_DMEM_START)
li t3, 0xFFF00000
li t1, 0x100000
and t2, t2, t3
la t0, block17s
addiu t1, t1, -1
and t0, t0, t1
la t3, pifipl3e
and t3, t3, t1
addiu t4, t4, 1
or t0, t0, t2
or t3, t3, t2
la t1, K1BASE
send2:
lw t5, (t0)
xor t5, t5, t4
mul t4, t4, 0x260BCD5
sw t5, (t1)
addiu t0, t0, 4
addiu t1, t1, 4
bltu t0, t3, send2
la t4, K0BASE
/* jump to RDRAM */
jr t4
NOP
END(ipl3)
.set noreorder
/* This is encoded MIPS */
block17s:
.word 0x184A089E, 0x3E5EB772, 0x9D9FE9D2, 0xEAE6B59D, 0x7D834475, 0x215361F2, 0X390BD39E, 0x3D3261E1
.word 0x075D920A, 0xFB461E32, 0x2C6873FA, 0x41A07B32, 0x42536B48, 0xB89A636F, 0X2B57D91A, 0xB050EE82
.word 0x3CB87A0A, 0x199C7CD6, 0xB483C93A, 0xBEBB13E6, 0x93B3831A, 0x8C1F5F51, 0XC4C9235A, 0xC7CD1B4E
.word 0x3C0E25EA, 0x675D63B2, 0x5CAAAB1A, 0xCD6774A2, 0xE17B02CA, 0x9125AA12, 0X57FBB8FA, 0x62088002
.word 0xD3D3F9AA, 0xDE779272, 0xB7C890DA, 0x3A009D62, 0x42DD4EEA, 0xE9A57CC2, 0XC75312BB, 0x9148D332
.word 0xC30BB56A, 0x81BC7932, 0x250F1E92, 0x45588E02, 0x4E64126F, 0xCFB3F7B1, 0X8A5DF87D, 0x6DF0A8E7
.word 0xE4FD5933, 0xB1ACF812, 0x937E5446, 0x733D46F6, 0xA646F21A, 0x5255A277, 0XF8E87E1F, 0x702E1667
.word 0x8F01E4CA, 0x75965EA0, 0x3AD8321B, 0xB096FF87, 0xFE4F41EF, 0xB31A7D37, 0X77BA8FDF, 0x68CAD327
.word 0x1F44388F, 0x1E589D72, 0xAF86AFFB, 0x8BF61849, 0x805A9988, 0xE6E33FF7, 0X861B09BB, 0x4F12AFDD
.word 0x596ACC49, 0x7DF23434, 0xA44D959E, 0x17EF0107, 0xA8318161, 0x7B93AAB7, 0X7D2E735C, 0x8D2DC486
.word 0x7F87780B, 0xBC2E9AD4, 0x31AABB58, 0x5945C9C4, 0x19B4D12C, 0xA2E69556, 0XF1BA0D1C, 0xFAC32146
.word 0x2FE5DC02, 0x11D3D993, 0x58CE3903, 0x8DD2EAB0, 0xEB4298EB, 0x2A5C9012, 0XBECCE6E3, 0xA8310610
.word 0xC09FB78B, 0x0A1E2872, 0x12E35ECA, 0x4AB60364, 0x9774C88A, 0x825832C6, 0XAD2480B9, 0x244FB2C2
.word 0x4E473369, 0x433A9F32, 0x177ED365, 0xBE013422, 0xF600FC42, 0x2B75CD92, 0X435E426E, 0xD371E79E
.word 0xEFCA172C, 0x22351DD2, 0x8AF4A21B, 0x12D688E6, 0x3A94501A, 0x7ADE545A, 0X83AF2C3A, 0xFC5164E8
.word 0xBCFE4844, 0x441800B6, 0x4523C00A, 0xB31B4992, 0x1CA2AA9F, 0x52F49B1E, 0X662F997A, 0x839D291A
.word 0x3B4132FA, 0xE702337E, 0xF3FD21EA, 0x412E7E62, 0xE1AC778A, 0x4F9CCDD0, 0X658BD3DA, 0x25CB35D2
.word 0xB979926A, 0xD6FCC932, 0x81E1E442, 0x067EC732, 0x3CB1A74A, 0x887D8896, 0X0117D976, 0xA5B48A86
.word 0x5359B63E, 0x350DCEF2, 0xEC7D0959, 0x398FDFE2, 0x200B8F0A, 0x8EC0CB52, 0X309F6332, 0x04B78342
.word 0xF1A821EA, 0x2CED1FB2, 0x750D38E5, 0xDA67C0A6, 0x0F3BC134, 0x7CA069EE, 0X1FECB0FA, 0x08E51C02
.word 0xEEC565AA, 0x5A4EBE76, 0x3D71D324, 0xDFA7969E, 0x3066028A, 0x8C78FF0A, 0X9761FEBA, 0xDAC288C2
.word 0xB290A16A, 0xC396753A, 0x975C3ABA, 0x387B9201, 0x80A87642, 0xED28C392, 0X34089876
pifipl3e:
.word 0x00000000
.set reorder
#else /* IPL3_X106 */
#ifdef IPL3_X105
li t2, SP_SET_HALT | SP_CLR_BROKE | SP_CLR_INTR | SP_SET_SSTEP | SP_CLR_INTR_BREAK
sw t2, PHYS_TO_K1(SP_STATUS_REG)
#endif
la t2, PHYS_TO_K1(SP_DMEM_START)
li t3, 0xFFF00000
li t1, 0x100000
and t2, t2, t3
#ifdef IPL3_6101
/* In the 6101 IPL3, these are physical addresses while in every other version they are KSEG1 addresses */
la t0, block17s-0xA0000000
addiu t1, t1, -1
la t3, pifipl3e-0xA0000000
#else
la t0, block17s
addiu t1, t1, -1
la t3, pifipl3e
#endif
and t0, t0, t1
and t3, t3, t1
#ifdef IPL3_X105
/* reset RSP PC */
sw zero, PHYS_TO_K1(SP_PC_REG)
#endif
or t0, t0, t2
or t3, t3, t2
#ifdef IPL3_X105
la t1, PHYS_TO_K1(4)
#else
la t1, PHYS_TO_K1(0)
#endif
/* copy the rest of IPL3 to RDRAM */
send2:
lw t5, (t0)
sw t5, (t1)
addiu t0, t0, 4
addiu t1, t1, 4
bltu t0, t3, send2
#ifdef IPL3_X105
/* start the RSP */
li t2, SP_CLR_HALT | SP_CLR_BROKE | SP_CLR_INTR | SP_CLR_SSTEP | SP_CLR_INTR_BREAK
sw t2, PHYS_TO_K1(SP_STATUS_REG)
la t4, PHYS_TO_K0(0x00000004)
#else
la t4, PHYS_TO_K0(0x00000000)
#endif
/* jump to RDRAM */
jr t4
block17s:
/* the following was copied to RDRAM and jumped to */
li t3, PHYS_TO_K1(PI_DOM1_ADDR2) /* cart base */
cart:
li t2, 0x1FFFFFFF
#ifdef IPL3_7102
li t1, PHYS_TO_K0(0x00000480)
#else
lw t1, 8(t3)
#endif
and t1, t1, t2
#ifdef IPL3_X103
subu t1, t1, 0x100000
#endif
sw t1, PHYS_TO_K1(PI_DRAM_ADDR_REG)
waitread:
lw t0, PHYS_TO_K1(PI_STATUS_REG)
andi t0, PI_STATUS_IO_BUSY
bnez t0, waitread
li t0, 0x1000
add t0, t0, t3
and t0, t0, t2
sw t0, PHYS_TO_K1(PI_CART_ADDR_REG)
li t2, 0x100000
#ifdef IPL3_X103
addiu t2, t2, 3
#else
addiu t2, t2, -1
#endif
sw t2, PHYS_TO_K1(PI_WR_LEN_REG)
waitdma:
#ifdef IPL3_6101
NOP
NOP
NOP
NOP
#endif
#if defined(IPL3_6101) || defined(IPL3_6102_7101)
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
#endif
#ifndef IPL3_X103
NOP
NOP
NOP
NOP
#endif
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
lw t3, PHYS_TO_K1(PI_STATUS_REG)
andi t3, PI_STATUS_DMA_BUSY
bnez t3, waitdma
#ifdef IPL3_X105
/* return the semaphore, notifies the RSP that PI DMA has completed */
sw zero, PHYS_TO_K1(SP_SEMAPHORE_REG)
#endif
li t3, PHYS_TO_K1(PI_DOM1_ADDR2)
/* game entrypoint */
#ifndef IPL3_X103
.set noreorder
#endif
#ifdef IPL3_7102
li a0, PHYS_TO_K0(0x00000480)
#else
lw a0, 8(t3)
#endif
move a1, s6
#ifdef IPL3_X103
subu a0, a0, 0x100000
#else
.set reorder
#endif
addiu sp, sp, -0x20
sw ra, 0x1C(sp)
sw s0, 0x14(sp)
#ifdef IPL3_X105
la s6, PHYS_TO_K1(0x00000200)
#endif
li ra, 0x100000 /* 1MB */
move v1, zero
move t0, zero
move t1, a0
mul v0, a1, ROM_CHECKSUM_MAGIC
addiu v0, v0, 1
move a3, v0
move t2, v0
move t3, v0
move s0, v0
move a2, v0
move t4, v0
li t5, 32
checksum_loop:
lw v0, (t1) /* rom data */
addu v1, a3, v0
move a1, v1
bgeu v1, a3, 1f
addiu t2, t2, 1
1:
andi v1, v0, 0x1F
subu t7, t5, v1
srlv t8, v0, t7
sllv t6, v0, v1
or a0, t6, t8
move a3, a1
xor t3, t3, v0
addu s0, s0, a0
bgeu a2, v0, 2f
xor t9, a3, v0
xor a2, t9, a2
b 3f
2:
xor a2, a2, a0
3:
#ifdef IPL3_X105
lw t7, (s6) /* pifipl3e data below? */
addiu t0, t0, 4
addiu t1, t1, 4
addiu s6, s6, 4
xor t7, v0, t7
addu t4, t7, t4
li t7, PHYS_TO_K1(0x00000300) - 1
and s6, s6, t7
#else
addiu t0, t0, 4
addiu t1, t1, 4
xor t7, v0, s0
addu t4, t7, t4
#endif
bne t0, ra, checksum_loop
#ifndef IPL3_X105
.set noreorder
#endif
#ifdef IPL3_X103
xor t6, a3, t2
addu a3, t6, t3 /* Checksum 1 */
xor t8, s0, a2
addu s0, t8, t4 /* Checksum 2 */
#else
xor t6, a3, t2
xor a3, t6, t3 /* Checksum 1 */
xor t8, s0, a2
xor s0, t8, t4 /* Checksum 2 */
#endif
#ifndef IPL3_X105
.set reorder
#endif
#ifndef IPL3_X105
li t3, PHYS_TO_K1(PI_DOM1_ADDR2)
lw t0, 0x10(t3)
bne a3, t0, checksum_fail
lw t0, 0x14(t3)
bne s0, t0, checksum_fail
bal checksum_OK
checksum_fail:
bal checksum_fail
checksum_OK:
/* Try to read PC, if the read worked the RSP is not running */
lw t1, PHYS_TO_K1(SP_PC_REG)
lw s0, 0x14(sp)
lw ra, 0x1C(sp)
addiu sp, sp, 0x20
/* if the RSP PC is 0, skip */
beqz t1, 1f
/* halt the RSP by forcing it into sstep mode? */
li t2, SP_SET_SSTEP | SP_CLR_HALT
sw t2, PHYS_TO_K1(SP_STATUS_REG)
sw zero, PHYS_TO_K1(SP_PC_REG)
1:
#endif
li t3, SP_SET_HALT | SP_CLR_BROKE | SP_CLR_INTR | SP_CLR_SSTEP | SP_CLR_INTR_BREAK | \
SP_CLR_SIG0 | SP_CLR_SIG1 | SP_CLR_SIG2 | SP_CLR_SIG3 | SP_CLR_SIG4 | SP_CLR_SIG5 | SP_CLR_SIG6 | SP_CLR_SIG7
sw t3, PHYS_TO_K1(SP_STATUS_REG)
li t0, MI_INTR_MASK_CLR_SP | MI_INTR_MASK_CLR_SI | MI_INTR_MASK_CLR_AI | MI_INTR_MASK_CLR_VI | MI_INTR_MASK_CLR_PI | MI_INTR_MASK_CLR_DP; \
sw t0, PHYS_TO_K1(MI_INTR_MASK_REG)
sw zero, PHYS_TO_K1(SI_STATUS_REG)
sw zero, PHYS_TO_K1(AI_STATUS_REG)
li t1, MI_CLR_DP_INTR; \
sw t1, PHYS_TO_K1(MI_INIT_MODE_REG)
li t1, PI_CLR_INTR
sw t1, PHYS_TO_K1(PI_STATUS_REG); \
li t0, PHYS_TO_K1(0x00000300)
#if defined(IPL3_X103) || defined(IPL3_X105)
li t1, CIC_TYPE
sw t1, 0x10(t0) /* osCicType */
sw s4, 0(t0) /* osTvType */
sw s3, 4(t0) /* osRomType */
sw s5, 0xC(t0) /* osResetType */
sw s7, 0x14(t0) /* osVersion */
#else
sw s7, 0x14(t0) /* osVersion */
sw s5, 0xC(t0) /* osResetType */
sw s3, 4(t0) /* osRomType */
sw s4, 0(t0) /* osTvType */
#endif
beqz s3, rom
la t1, PHYS_TO_K1(PI_DOM1_ADDR1)
b 1f
rom:
la t1, PHYS_TO_K1(PI_DOM1_ADDR2)
1:
sw t1, 8(t0) /* osRomBase */
#ifdef IPL3_X105
lw t1, 0xF0(t0)
sw t1, 0x18(t0) /* osMemSize */
li t3, PHYS_TO_K1(PI_DOM1_ADDR2)
lw t0, 0x10(t3)
bne a3, t0, checksum_fail
lw t0, 0x14(t3)
bne s0, t0, checksum_fail
bal checksum_OK
checksum_fail:
bal checksum_fail
checksum_OK:
la t0, PHYS_TO_K1(SP_DMEM_START)
lw s0, 0x14(sp)
lw ra, 0x1c(sp)
addiu sp, sp, 0x20
addi t1, t0, SP_IMEM_END + 1 - SP_DMEM_START
del_spmem:
sw t1, (t0)
addiu t0, t0, 4
bne t0, t1, del_spmem
#else /* IPL3_X105 */
la t0, PHYS_TO_K1(SP_DMEM_START)
addi t1, t0, SP_DMEM_END + 1 - SP_DMEM_START
#ifdef IPL3_X103
li t2, -1
# define CLEAR_VAL t2
#else
# define CLEAR_VAL zero
#endif
del_dmem:
sw CLEAR_VAL, (t0)
addiu t0, t0, 4
bne t0, t1, del_dmem
la t0, PHYS_TO_K1(SP_IMEM_START)
addi t1, t0, SP_IMEM_END + 1 - SP_IMEM_START
del_imem:
sw CLEAR_VAL, (t0)
addiu t0, t0, 4
bne t0, t1, del_imem
#endif /* IPL3_X105 */
game:
#ifdef IPL3_X103
la t2, PHYS_TO_K1(SP_IMEM_START)
li t3, 6103
sw t3, (t2)
#endif
/* Read cart entry point and jump to it */
li t3, PHYS_TO_K1(PI_DOM1_ADDR2)
#ifdef IPL3_7102
.set noreorder; .set reorder
li t1, PHYS_TO_K0(0x00000480)
#else
lw t1, 8(t3)
#endif
#ifdef IPL3_X103
.set noreorder; .set reorder
subu t1, t1, 0x100000
#endif
jr t1
#ifndef IPL3_X105
pifipl3e:
NOP
#endif
END(ipl3)
#ifdef IPL3_X105
.set noreorder
/* This is RSP code */
/* start: */
.word 0x40083800 /* mfc0 $8, SP_SEMAPHORE */ /* acquire the semaphore */
.word 0x400B0800 /* mfc0 $11, SP_DRAM_ADDR */
.word 0xC80C2000 /* lqv $v12[0], ($zero) */
.word 0x8C040040 /* lw $4, 0x40($zero) */
.word 0x00000000 /* nop */
.word 0x00000000 /* nop */
.word 0x40800000 /* mtc0 $zero, SP_MEM_ADDR */ /* DMA 8 bytes to DMEM offset 0 */
.word 0x38030180 /* xori $3, $zero, 0x180 */
.word 0x40830800 /* mtc0 $3, SP_DRAM_ADDR */
.word 0x40801000 /* mtc0 $zero, SP_RD_LEN */
.word 0x3C050020 /* li $5, 0x200000 */ /* wait until PI DMA is done, skip to the end if it times out */
/* acquire_semaphore: */