-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathf3dex3.s
More file actions
3851 lines (3603 loc) · 180 KB
/
f3dex3.s
File metadata and controls
3851 lines (3603 loc) · 180 KB
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
.rsp
.include "rsp/rsp_defs.inc"
.include "rsp/gbi.inc"
// This file assumes DATA_FILE and CODE_FILE are set on the command line
.if version() < 110
.error "armips 0.11 or newer is required"
.endif
// Sign-extends the immediate using addi. ori would zero-extend.
.macro li, reg, imm
addi reg, $zero, imm
.endmacro
.macro move, dst, src
ori dst, src, 0
.endmacro
// Prohibit macros involving slt; this silently clobbers $1. You can of course
// manually write the slt and branch instructions if you want this behavior.
.macro blt, ra, rb, lbl
.error "blt is a macro using slt, and silently clobbers $1!"
.endmacro
.macro bgt, ra, rb, lbl
.error "bgt is a macro using slt, and silently clobbers $1!"
.endmacro
.macro ble, ra, rb, lbl
.error "ble is a macro using slt, and silently clobbers $1!"
.endmacro
.macro bge, ra, rb, lbl
.error "bge is a macro using slt, and silently clobbers $1!"
.endmacro
// This version doesn't depend on $v0 to be vZero, which it often is not in
// F3DEX3, and also doesn't get corrupted if $vco is set / consume $vco which
// may be needed for a subsequent instruction.
.macro vcopy, dst, src
vor dst, src, src
.endmacro
// Using $v31 instead of dst as the source because $v31 doesn't change, whereas
// dst might have been modified 2 or 3 cycles ago, causing a stall.
.macro vclr, dst
vxor dst, $v31, $v31
.endmacro
// Also using $v31 for the dummy args here to avoid stalls. dst was once written
// in vanilla tri code just before reading (should have been $v29), leading to
// stalls!
ACC_UPPER equ 0
ACC_MIDDLE equ 1
ACC_LOWER equ 2
.macro vreadacc, dst, N
vsar dst, $v31, $v31[N]
.endmacro
//
// Profiling configurations. To make space for the profiling features, if any of
// the profiling configurations are enabled, G_LIGHTTORDP and !G_SHADING_SMOOTH
// are removed, i.e. G_LIGHTTORDP behaves as a no-op and all tris are smooth
// shaded.
//
// Profiling Configuration A
// perfCounterA:
// cycles RSP spent processing vertex commands (incl. vertex DMAs)
// perfCounterB:
// upper 16 bits: fetched DL command count
// lower 16 bits: DL command count
// perfCounterC:
// cycles RSP was stalled because RDP FIFO was full
// perfCounterD:
// cycles RSP spent processing triangle commands, not including FIFO stalls
.if CFG_PROFILING_A
.if CFG_PROFILING_B || CFG_PROFILING_C
.error "At most one CFG_PROFILING_ option can be enabled at a time"
.endif
ENABLE_PROFILING equ 1
COUNTER_A_UPPER_VERTEX_COUNT equ 0
COUNTER_C_FIFO_FULL equ 1
// Profiling Configuration B
// perfCounterA:
// upper 16 bits: vertex count
// lower 16 bits: lit vertex count
// perfCounterB:
// upper 18 bits: tris culled by occlusion plane count
// lower 14 bits: clipped (input) tris count
// perfCounterC:
// upper 18 bits: overlay (all 0-4) load count
// lower 14 bits: overlay 2 (lighting) load count
// perfCounterD:
// upper 18 bits: overlay 3 (clipping) load count
// lower 14 bits: overlay 4 (misc) load count
.elseif CFG_PROFILING_B
.if CFG_PROFILING_C
.error "At most one CFG_PROFILING_ option can be enabled at a time"
.endif
ENABLE_PROFILING equ 1
COUNTER_A_UPPER_VERTEX_COUNT equ 1
COUNTER_C_FIFO_FULL equ 0
// Profiling Configuration C
// perfCounterA:
// cycles RSP believes it was running (this ucode only)
// perfCounterB:
// upper 16 bits: samples GCLK was alive (sampled once per DL command count)
// lower 16 bits: DL command count
// perfCounterC:
// upper 18 bits: small RDP command count (all RDP cmds except tris)
// lower 14 bits: matrix loads count
// perfCounterD:
// cycles RSP was stalled waiting for miscellaneous DMAs to finish
.elseif CFG_PROFILING_C
ENABLE_PROFILING equ 1
COUNTER_A_UPPER_VERTEX_COUNT equ 0
COUNTER_C_FIFO_FULL equ 0
// Default (extra profiling disabled)
// perfCounterA:
// upper 16 bits: vertex count
// lower 16 bits: RDP/out tri count
// perfCounterB:
// upper 18 bits: RSP/in tri count
// lower 14 bits: tex/fill rect count
// perfCounterC:
// cycles RSP was stalled because RDP FIFO was full
// perfCounterD:
// unused/zero
.else
ENABLE_PROFILING equ 0
COUNTER_A_UPPER_VERTEX_COUNT equ 1
COUNTER_C_FIFO_FULL equ 1
.endif
CFG_DEBUG_NORMALS equ 0 // Can manually enable here
// Only raise a warning in base modes; in profiling modes, addresses will be off
.macro warn_if_base, warntext
.if !ENABLE_PROFILING
.warning warntext
.endif
.endmacro
.macro align_with_warning, alignment, warntext
.if (. & (alignment - 1))
warn_if_base warntext
.endif
.align alignment
.endmacro
/*
There are two different memory spaces for the overlays: (a) IMEM and (b) the
microcode file (which, plus an offset, is also the location in DRAM).
A label marks both an IMEM addresses and a file address, but evaluating the
label in an integer context (e.g. in a branch) gives the IMEM address.
`orga(your_label)` gets the file address of the label, and `.orga` sets the
file address.
`.headersize`, as well as the value after `.create`, sets the difference
between IMEM addresses and file addresses, so you can set the IMEM address
with `.headersize desired_imem_addr - orga()`.
In IMEM, the whole microcode is organized as (each row is the same address):
0x80 space | |
for boot code Overlay 0 Overlay 1
(End (More cmd
start task) handlers)
(initialization) | |
Rest command handlers
Vertex start
All tri write cmds
Overlay 2 Overlay 3 Overlay 4
(Basic lighting) (Clipping, (Advanced
rare cmds) lighting)
Main vertex write
DMA code
In the file, the microcode is organized as:
start (file addr 0x0 = IMEM 0x1080)
Many command handlers
Overlay 3
Vertex and tri handlers
DMA code (end of this = IMEM 0x2000 = file 0xF80)
Overlay 0
Overlay 1
Overlay 2
Overlay 4
*/
////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////// DMEM //////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// RSP DMEM
.create DATA_FILE, 0x0000
/*
Matrices are stored and used in a transposed format compared to how they are
normally written in mathematics. For the integer part:
00 02 04 06 typical Xscl Rot Rot 0
08 0A 0C 0E use: Rot Yscl Rot 0
10 12 14 16 Rot Rot Zscl 0
18 1A 1C 1E Xpos Ypos Zpos 1
The fractional part comes next and is in the same format.
Applying this transformation is done by multiplying a row vector times the
matrix, like:
X Y Z 1 * Xscl Rot Rot 0 = NewX NewY NewZ 1
Rot Yscl Rot 0
Rot Rot Zscl 0
Xpos Ypos Zpos 1
In C, the matrix is accessed as matrix[row][col], and the vector is vector[row].
*/
// 0x0000-0x0040: model matrix
mMatrix:
.fill 0x40
// 0x0040-0x0080: view * projection matrix
vpMatrix:
.fill 0x40
// model * (view * projection) matrix
mvpMatrix:
.fill 0x40
.if . != 0x00C0
.error "Scissor and othermode must be at 0x00C0 for S2DEX"
.endif
// scissor (four 12-bit values)
scissorUpLeft: // the command byte is included since the command word is copied verbatim
.dw (G_SETSCISSOR << 24) | (( 0 * 4) << 12) | (( 0 * 4) << 0)
scissorBottomRight:
.dw ((320 * 4) << 12) | ((240 * 4) << 0)
// othermode
otherMode0: // command byte included, same as above
.dw (G_RDPSETOTHERMODE << 24) | (0x080CFF)
otherMode1:
.dw 0x00000000
// These two words are texrectState in S2DEX, so it can clobber them.
textureSettings1:
.dw 0x00000000 // first word, has command byte, level, tile, and on
textureSettings2:
.dw 0xFFFFFFFF // second word, has s and t scale
// This word is rdpHalf1Val in S2DEX, so it can clobber it.
fogFactor:
.dw 0x00000000
activeClipPlanes:
.dh CLIP_SCAL_NPXY | CLIP_CAMPLANE // Normal tri write, set to zero when clipping
// displaylist stack length
displayListStackLength:
.db 0x00 // starts at 0, increments by 4 for each "return address" pushed onto the stack
unused1:
.db 0
// viewport
viewport:
.fill 16
// Current RDP fifo output position
rdpFifoPos:
.fill 4
matrixStackPtr:
.dw 0x00000000
// segment table
segmentTable:
.fill (4 * 16) // 16 DRAM pointers
// displaylist stack
displayListStack:
// ucode text (shared with DL stack)
.ascii ID_STR, 0x0A
endIdStr:
.if endIdStr < 0x180
.fill (0x180 - endIdStr)
.elseif endIdStr > 0x180
.error "ID_STR is too long"
.align 16 // to suppress subsequent errors
.endif
endSharedDMEM:
.if . != 0x180
.error "endSharedDMEM at incorrect address, matters for G_LOAD_UCODE / S2DEX"
.endif
// constants for register $v31
.if (. & 15) != 0
.error "Wrong alignment for v31value"
.endif
v31Value:
// v31 must go from lowest to highest (signed) values for vcc patterns.
// Also relies on the fact that $v31[0h] is -4,-4,-4,-4, 4, 4, 4, 4.
.dh -4 // used in clipping, vtx write for Newton-Raphson reciprocal
.dh -1 // used often
.dh 0 // used often
.dh 2 // used as clip ratio (vtx write, clipping) and in clipping
.dh 4 // used for same Newton-Raphsons, occlusion plane scaling
.dh 0x4000 // used in tri write, texgen
.dh 0x7F00 // used in fog
.dh 0x7FFF // used often
/*
Quick note on Newton-Raphson:
https://en.wikipedia.org/wiki/Division_algorithm#Newton%E2%80%93Raphson_division
Given input D, we want to find the reciprocal R. The base formula for refining
the estimate of R is R_new = R*(2 - D*R). However, since the RSP reciprocal
instruction moves the radix point 1 to the left, the result has to be multiplied
by 2. So it's 2*R*(2 - D*2*R) = R*(4 - 4*D*R) = R*(1*4 + D*R*-4). This is where
the 4 and -4 come from. For tri write, the result needs to be multiplied by 4
for subpixels, so it's 16 and -16.
*/
cameraWorldPos:
.skip 6
tempTriRA:
.skip 2 // Overwritten as part of camera world position, used as temp
lightBufferLookat:
.skip 8 // s8 X0, Y0, Z0, dummy, X1, Y1, Z1, dummy
lightBufferMain:
.skip (G_MAX_LIGHTS * lightSize)
lightBufferAmbient:
.skip 8 // just colors for ambient light
ltBufOfs equ (lightBufferMain - altBase)
occlusionPlaneEdgeCoeffs:
/*
See cpu/occlusionplane.c for more information.
Vertex is in occlusion region if all five equations below are true:
4 * screenX[s13.2] * c0[s0.15] - 0.5 * screenY[s13.2] < c4[s14.1]
4 * screenY[s13.2] * c1[s0.15] - 0.5 * screenX[s13.2] < c5[s14.1]
4 * screenX[s13.2] * c2[s0.15] + 0.5 * screenY[s13.2] < c6[s14.1]
4 * screenY[s13.2] * c3[s0.15] + 0.5 * screenX[s13.2] < c7[s14.1]
clamp_to_0.s15(clipX[s15.16] * kx[s0.15])
+ clamp_to_0.s15(clipY[s15.16] * ky[s0.15])
+ clamp_to_0.s15(clipZ[s15.16] * kz[s0.15])
>= kc[s0.15]
*/
.dh 0x0000 // c0
.dh 0x0000 // c1
.dh 0x0000 // c2
.dh 0x0000 // c3
.dh 0x8000 // c4
.dh 0x8000 // c5
.dh 0x8000 // c6
.dh 0x8000 // c7
occlusionPlaneMidCoeffs:
.dh 0x0000 // kx
.dh 0x0000 // ky
.dh 0x0000 // kz
.dh 0x7FFF // kc
// Alternate base address because vector load offsets can't reach all of DMEM.
// altBaseReg permanently points here.
.if (. & 15) != 0
.error "Wrong alignment for altBase"
.endif
altBase:
// constants for register vTRC
.if (. & 15) != 0
.error "Wrong alignment for vTRCValue"
.endif
vTRCValue:
decalFixMult equ 0x0400
decalFixOff equ (-(decalFixMult / 2))
.dh vertexBuffer // around 0x300; for converting vertex index to address
.dh vtxSize << 7 // 0x1300; it's not 0x2600 because vertex indices are *2
.dh 0x7E00 // vertex index mask for snake
.dh decalFixMult // defined above
.dh decalFixOff // negative
.dh 0x0020 // used in tri write and vtx addr manip
.dh 0x0100 // used several times in tri write
.dh 0x1000 // some multiplier in tri write, vtx addr manip
.macro set_vcc_11110001
vge $v29, vTRC, vTRC[0]
.endmacro
.if (vertexBuffer <= 0x0100 || decalFixMult < vertexBuffer)
.error "VCC pattern for vTRC corrupted"
.endif
vTRC_VB equ vTRC[0] // Vertex Buffer
vTRC_VS equ vTRC[1] // Vertex Size
vTRC_7E00 equ vTRC[2]
vTRC_DM equ vTRC[3] // Decal Multiplier
vTRC_DO equ vTRC[4] // Decal Offset
vTRC_0020 equ vTRC[5]
vTRC_0100 equ vTRC[6]
vTRC_1000 equ vTRC[7]
vTRC_0100_addr equ (vTRCValue + 2 * 6)
.if (. & 15) != 0
.error "Wrong alignment for fxParams"
.endif
fxParams:
// First 8 values here loaded with lqv.
aoAmbientFactor:
.dh 0xFFFF
aoDirectionalFactor:
.dh 0xA000
aoPointFactor:
.dh 0x0000
perspNorm:
.dh 0xFFFF
texgenLinearCoeffs:
.dh 0x44D3
.dh 0x6CB3
fresnelScale:
.dh 0x0000
fresnelOffset:
.dh 0x0000
attrOffsetST:
.dh 0x0100
.dh 0xFF00
alphaCompareCullMode:
.db 0x00 // 0 = disabled, 1 = cull if all < thresh, -1 = cull if all >= thresh
alphaCompareCullThresh:
.db 0x00 // Alpha threshold, 00 - FF
lastMatDLPhyAddr:
.dw 0
.if (. - fxParams) != 0x1A
.error "Update fxParams MWO in GBI"
.endif
packedNormalsMaskConstant:
.db 0xF8 // When read, materialCullMode has been zeroed, so read as 0xF800
materialCullMode:
.db 0
geometryModeLabel:
.dw 0x00000000
movewordTable:
.dh fxParams // G_MW_FX
.dh numLightsxSize - 3 // G_MW_NUMLIGHT; writes numLightsxSize and pointLightFlag, zeroes dirLightsXfrmValid
packedNormalsConstants:
.if (. & 3) != 0
.error "Alignment broken for packed normals constants in movewordTable"
.endif
.dh 0x2008 // For packed normals; unused in movewordTable
.if (segmentTable & 0xFF00) != 0
.error "Packed normals constants relies on first byte of segmentTable addr being 0"
.endif
.dh segmentTable // G_MW_SEGMENT
.dh fogFactor // G_MW_FOG
.dh lightBufferMain // G_MW_LIGHTCOL
// First half of RDP value for split commands. Also used as temp storage for
// tri vertices during tri commands.
rdpHalf1Val:
.fill 4
movememTable:
.dh mMatrix // G_MV_MMTX
.dh tempMatrix // G_MV_TEMPMTX0 multiply temp matrix (model)
.dh vpMatrix // G_MV_VPMTX
.dh tempMatrix // G_MV_TEMPMTX1 multiply temp matrix (view*projection)
.dh viewport // G_MV_VIEWPORT
.dh cameraWorldPos // G_MV_LIGHT
afterMovememRaTable:
.dh run_next_DL_command
.dh G_MTX_multiply_end
clipCondShifts:
.db (31 - CLIP_SCAL_NY_SHIFT) // Constants for clipping algorithm
.db (31 - CLIP_SCAL_PY_SHIFT)
.db (31 - CLIP_SCAL_NX_SHIFT)
.db (31 - CLIP_SCAL_PX_SHIFT)
.db (31 - CLIP_CAMPLANE_SHIFT)
mvpValid:
.db 0 // Nonzero if the MVP matrix is valid, 0 if it needs to be recomputed.
dirLightsXfrmValid:
.db 0 // Nonzero if transformed directional lights are valid.
unused2:
.db 0
pointLightFlag:
.db 0 // Sign bit set if there are point lights.
numLightsxSize:
.db 0 // lightSize * number of lights
.macro miniTableEntry, addr
.if addr < 0x1000 || addr >= 0x1400
.error "Handler address out of range!"
.endif
.db (addr - 0x1000) >> 2
.endmacro
// RDP/Immediate Command Mini Table
// 1 byte per entry, after << 2 points to an addr in first 1/4 of IMEM
miniTableEntry G_FLUSH_handler
miniTableEntry G_MEMSET_handler
miniTableEntry G_DMA_IO_handler
miniTableEntry G_TEXTURE_handler
miniTableEntry G_POPMTX_handler
miniTableEntry G_GEOMETRYMODE_handler
miniTableEntry G_MTX_handler
miniTableEntry G_MOVEWORD_handler
miniTableEntry G_MOVEMEM_handler
miniTableEntry G_LOAD_UCODE_handler
miniTableEntry G_DL_handler
miniTableEntry G_ENDDL_handler
miniTableEntry G_SPNOOP_handler
miniTableEntry G_RDPHALF_1_handler
miniTableEntry G_SETOTHERMODE_L_handler
miniTableEntry G_SETOTHERMODE_H_handler
miniTableEntry G_TEXRECT_handler // G_TEXRECT
miniTableEntry G_TEXRECT_handler // G_TEXRECTFLIP
miniTableEntry G_RDP_handler // G_RDPLOADSYNC
miniTableEntry G_RDP_handler // G_RDPPIPESYNC
miniTableEntry G_RDP_handler // G_RDPTILESYNC
miniTableEntry G_RDP_handler // G_RDPFULLSYNC
miniTableEntry G_RDP_handler // G_SETKEYGB
miniTableEntry G_RDP_handler // G_SETKEYR
miniTableEntry G_RDP_handler // G_SETCONVERT
miniTableEntry G_SETSCISSOR_handler
miniTableEntry G_RDP_handler // G_SETPRIMDEPTH
miniTableEntry G_RDPSETOTHERMODE_handler
miniTableEntry load_cmds_handler // G_LOADTLUT
miniTableEntry G_RDPHALF_2_handler
miniTableEntry G_RDP_handler // G_SETTILESIZE
miniTableEntry load_cmds_handler // G_LOADBLOCK
miniTableEntry load_cmds_handler // G_LOADTILE
miniTableEntry G_RDP_handler // G_SETTILE
miniTableEntry G_RDP_handler // G_FILLRECT
miniTableEntry G_RDP_handler // G_SETFILLCOLOR
miniTableEntry G_RDP_handler // G_SETFOGCOLOR
miniTableEntry G_RDP_handler // G_SETBLENDCOLOR
miniTableEntry G_RDP_handler // G_SETPRIMCOLOR
miniTableEntry G_RDP_handler // G_SETENVCOLOR
miniTableEntry G_RDP_handler // G_SETCOMBINE
miniTableEntry G_SETxIMG_handler // G_SETTIMG
miniTableEntry G_SETxIMG_handler // G_SETZIMG
miniTableEntry G_SETxIMG_handler // G_SETCIMG
cmdMiniTable:
miniTableEntry G_RDP_handler // G_NOOP
miniTableEntry G_VTX_handler
miniTableEntry G_MODIFYVTX_handler
miniTableEntry G_CULLDL_handler
miniTableEntry G_BRANCH_WZ_handler
miniTableEntry G_TRI1_handler
miniTableEntry G_TRI2_handler
miniTableEntry G_QUAD_handler
miniTableEntry G_TRISNAKE_handler
miniTableEntry G_SPNOOP_handler // no command mapped to 0x09
miniTableEntry G_LIGHTTORDP_handler
miniTableEntry G_RELSEGMENT_handler
// The maximum number of generated vertices in a clip polygon. In reality, this
// is equal to MAX_CLIP_POLY_VERTS, but for testing we can change them separately.
// In case you're wondering if it's possible to have a 7-vertex polygon where all
// 7 verts are generated, it looks like this (X = generated vertex):
// ___----=>
// +---------------__X----X _-^
// | __--^^ X^
// | __--^^ _-^|
// _X^^^ _-^ |
// C | _-^ |
// ^X _-^ |
// |\ _-^ |
// +-X--_X^---------------+
// V^
MAX_CLIP_GEN_VERTS equ 7
// Normally, each clip plane can cut off a "tip" of a polygon, turning one vert
// into two. (It can also cut off more of the polygon and remove additional verts,
// but the maximum is one more vert per clip plane.) So with 5 clip planes, we
// could have a maximum of 8 verts in the final polygon. However, the verts
// generated by the no-nearclipping plane will always be at infinity, so they
// will always get replaced by generated verts from one of the other clip planes.
// Put another way, if there are 8 verts in the final polygon, there are 8 edges,
// which are portions of the 3 original edges plus portions of 5 edges along the
// 5 clip planes. But the edge portion along the no-nearclipping plane is at
// infinity, so that edge can't be on screen. So an actual polygon can contain
// up to 7 verts. However, we are relying on 8 verts for circular addressing,
// and the current implementation temporarily inserts a vertex when moving from
// on to offscreen, so it can be 8 valid vertices momentarily.
CLIP_POLY_VERTS equ 8
CLIP_POLY_SIZE_BYTES equ CLIP_POLY_VERTS * 2
CLIP_TEMP_VERTS_SIZE_BYTES equ (MAX_CLIP_GEN_VERTS * vtxSize)
VERTEX_BUFFER_SIZE_BYTES equ (G_MAX_VERTS * vtxSize)
RDP_CMD_BUFSIZE equ 0xB0
RDP_CMD_BUFSIZE_EXCESS equ 0xB0 // Maximum size of an RDP triangle command
RDP_CMD_BUFSIZE_TOTAL equ (RDP_CMD_BUFSIZE + RDP_CMD_BUFSIZE_EXCESS)
INPUT_BUFFER_CMDS equ 21
INPUT_BUFFER_SIZE_BYTES equ (INPUT_BUFFER_CMDS * 8)
OSTASK_ORIG_SIZE equ 0x40 // First CLIP_POLY_SIZE_BYTES (0x10) of this is clipPoly.
END_VARIABLE_LEN_DMEM equ (0x1000 - OSTASK_ORIG_SIZE - INPUT_BUFFER_SIZE_BYTES - (2 * RDP_CMD_BUFSIZE_TOTAL) - CLIP_TEMP_VERTS_SIZE_BYTES - VERTEX_BUFFER_SIZE_BYTES)
startFreeDmem:
.org END_VARIABLE_LEN_DMEM
endFreeDmem:
// Main vertex buffer in RSP internal format
vertexBuffer:
.skip VERTEX_BUFFER_SIZE_BYTES
// Space for temporary verts for clipping code, and reused for other things
clipTempVerts:
yieldOrigV1Addr:
.skip 2 // Needs to be saved over yield
// Round up to 0x8
.org ((clipTempVerts + 0x7) & 0xFF8)
texrectState:
.skip 8 // Only needs to be saved over texrect, half1, half2; but yield can happen
.if . > yieldDataFooter
// Need to fit everything through here in yield buffer
.error "Too much being stored in yieldable DMEM"
.endif
// Round up to 0x10
.org ((texrectState + 0xF) & 0xFF0)
tempMatrix:
.skip 0x40
.if . > (clipTempVerts + CLIP_TEMP_VERTS_SIZE_BYTES)
.error "Too much in clipTempVerts"
.endif
.org (clipTempVerts + CLIP_TEMP_VERTS_SIZE_BYTES)
clipTempVertsEnd:
// First RDP Command Buffer
rdpCmdBuffer1:
.skip RDP_CMD_BUFSIZE
.if (. & 8) != 8
.error "RDP command buffer alignment to 8 assumption broken"
.endif
rdpCmdBuffer1End:
.skip 8
rdpCmdBuffer1EndPlus1Word:
// This is so that we can temporarily store vector regs here with lqv/sqv
.skip RDP_CMD_BUFSIZE_EXCESS - 8
// Second RDP Command Buffer
rdpCmdBuffer2:
.skip RDP_CMD_BUFSIZE
.if (. & 8) != 8
.error "RDP command buffer alignment to 8 assumption broken"
.endif
rdpCmdBuffer2End:
.skip 8
rdpCmdBuffer2EndPlus1Word:
.skip RDP_CMD_BUFSIZE_EXCESS - 8
// Input buffer. After RDP cmd buffers so it can be vector addressed from end.
inputBuffer:
.skip INPUT_BUFFER_SIZE_BYTES
inputBufferEnd:
inputBufferEndSgn equ (-(0x1000 - inputBufferEnd)) // Underflow DMEM address
// 0x0FC0-0x1000: OSTask; 0x0FC0-0x0FD0: clipPoly
OSTask:
clipPoly: // This is here for alignment and vector addressing, see rsp_defs.inc
clipPolySgn equ (-(0x1000 - clipPoly)) // Underflow DMEM address
.skip CLIP_POLY_SIZE_BYTES
// rest of OSTask
.skip (OSTASK_ORIG_SIZE - CLIP_POLY_SIZE_BYTES)
.if . != 0x1000
.error "DMEM organization incorrect"
.endif
.close // DATA_FILE
// See rsp_defs.inc about why these are not used and we can reuse them.
startCounterTime equ (OSTask + OSTask_ucode_size)
xfrmLookatDirs equ -(0x1000 - (OSTask + OSTask_ucode_data)) // and OSTask_ucode_data_size
dumpDmemBuffer equ (OSTask + OSTask_yield_data_size) // CFG_PROFILING_B only
startFifoStallTime equ dumpDmemBuffer // CFG_PROFILING_A only
memsetBufferStart equ ((vertexBuffer + 0xF) & 0xFF0)
memsetBufferMaxEnd equ (rdpCmdBuffer1 & 0xFF0)
memsetBufferMaxSize equ (memsetBufferMaxEnd - memsetBufferStart)
memsetBufferSize equ (memsetBufferMaxSize > 0x800 ? 0x800 : memsetBufferMaxSize)
////////////////////////////////////////////////////////////////////////////////
/////////////////////////////// Register Naming ////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/*
Scalar regs:
Tri write Clip walk Clip VW Vtx write ltbasic ltadv V/L init Cmd dispatch
$zero ---------------------------------- Hardwired zero ------------------------------------------
$1 v1 texptr clipIdx <------------- vtxLeft ------------------------------> temp, init 0
$2 v2 shdptr <---------- clipAlloc -------> <----- lbPostAo laPtr temp
$3 v3 shdflg clipTempVtx <------------- vLoopRet ---------> laVtxLeft temp
$4 <--------------- origV1Addr -------------> <----- lbFakeAmb laSpecFres
$5 ------------------------------------- vGeomMid ---------------------------------------------
$6 v1flag temp <---------- clipPtrs --------> <-- lbTexgenOrRet laSTKept
$7 v2flag tile clipWalkCount <----------- fogFlag ----------> laPacked mtx valid cmd byte
$8 v3flag clipLastVtx <------------- outVtx2 ----------> laSpecular outVtx2
$9 xp texenab <----- curLight ---------> viLtFlag
$10 -------------------------------------- temp2 -----------------------------------------------
$11 --------------------------------------- temp -----------------------------------------------
$12 ----------------------------------- perfCounterD -------------------------------------------
$13 ------------------------------------ altBaseReg --------------------------------------------
$14 geom mode <-------------------------- inVtx ------------------------------->
$15 <------------ outVtxBase ---------------------------->
$16 ----------------------------------- flatV1Offset -------------------------------------------
$17
$18
$19 temp clipCurVtx <------------- outVtx1 ----------> laL2A <--------- dmaLen
$20 temp clipMaskShift clipVOnscr <-- flagsV1 ----------> laTexgen <--------- dmemAddr
$21 <----- clipMaskIdx / clipDrawPtr -------> <----- ambLight ambLight ovlInitClock
$22 ---------------------------------- rdpCmdBufEndP1 ------------------------------------------
$23 ----------------------------------- rdpCmdBufPtr -------------------------------------------
$24 temp clipWalkPhase clipVOffscr <- flagsV2 ----------> fp temp <--------- cmd_w1_dram
$25 cmd_w0 --------------------------------> <----- lbAfter <--------- cmd_w0
$26 ------------------------------------ taskDataPtr -------------------------------------------
$27 ---------------------------------- inputBufferPos ------------------------------------------
$28 ----------------------------------- perfCounterA -------------------------------------------
$29 ----------------------------------- perfCounterB -------------------------------------------
$30 ----------------------------------- perfCounterC -------------------------------------------
$ra return address, command handler address, sometimes sign bit is flag ------------------------
*/
// Global scalar regs:
vGeomMid equ $5 // Middle two bytes of geometry mode in lower 16 bits
perfCounterD equ $12 // Performance counter D (functions depend on config)
altBaseReg equ $13 // Alternate base address register for vector loads
rdpCmdBufEndP1 equ $22 // Pointer to one command word past "end" (middle) of RDP command buf
rdpCmdBufPtr equ $23 // RDP command buffer current DMEM pointer
taskDataPtr equ $26 // Task data (display list) DRAM pointer
inputBufferPos equ $27 // DMEM position within display list input buffer, relative to end
perfCounterA equ $28 // Performance counter A (functions depend on config)
perfCounterB equ $29 // Performance counter B (functions depend on config)
perfCounterC equ $30 // Performance counter C (functions depend on config)
// Tri write:
origV1Addr equ $4 // Original / current vertex 1 address
flatV1Offset equ $16 // Offset +'d to vtx 1 addr for flat shading. 0 except in clipping.
// Vertex init:
viLtFlag equ $9 // Holds pointLightFlag or dirLightsXfrmValid
// Vertex write:
vtxLeft equ $1 // Number of vertices left to process * 0x10
vLoopRet equ $3 // Return address at end of vtx loop = top of loop or misc lighting
fogFlag equ $7 // 8 if fog enabled, else 0
outVtx2 equ $8 // Pointer to second or dummy (= outVtx1) transformed vert
inVtx equ $14 // Pointer to loaded vertex to transform; < 0 means from clipping.
outVtxBase equ $15 // Pointer to vertex buffer to store transformed verts
outVtx1 equ $19 // Pointer to first transformed vert
flagsV1 equ $20 // Clip flags for vertex 1
flagsV2 equ $24 // Clip flags for vertex 2
// Lighting basic:
lbPostAo equ $2 // Address to return to after AO
lbFakeAmb equ $4 // Pointer to ambient light or to 8 bytes of zeros if AO enabled
lbTexgenOrRet equ $6 // ltbasic_texgen as negative if texgen, else vtx_return_from_lighting
curLight equ $9 // Current light pointer with offset
ambLight equ $21 // Ambient (top) light pointer with offset
lbAfter equ $25 // Address to return to after main lighting loop (vertex or extras)
// Lighting advanced:
laPtr equ $2 // Pointer to current vertex pair being lit
laVtxLeft equ $3 // Count of vertices left * 0x10
laSpecFres equ $4 // Nonzero if doing ltadv_normal_to_vertex for specular or Fresnel
laSTKept equ $6 // Texture coords of vertex 1 kept through processing
laPacked equ $7 // Nonzero if packed normals enabled
laSpecular equ $8 // Sign bit set if specular enabled
laL2A equ $19 // Nonzero if light-to-alpha (cel shading) enabled
laTexgen equ $20 // Nonzero if texgen enabled
// Clipping across walk - vertex write - tri write:
clipAlloc equ $2 // Whether each temp vtx is in use, during VW
clipPtrs equ $6 // On-off-gen vtx ptrs for each subdivision, during VW
clipMaskIdx equ $21 // Selects clipping plane / mask index, 4 -> 0
clipDrawPtr equ $21 // Pointer to output clip polygon during tri draw
clipVOnsc equ $20 // Onscreen vertex, only during setup for vtx write
clipVOffsc equ $24 // Offscreen vertex, only during setup for vtx write
// Clip walk only:
clipIdx equ $1 // Current index within polygon memory, 0 -> E
clipTempVtx equ $3 // Allocated temporary vertex address
clipWalkCount equ $7 // How many steps taken around polygon; if too many, timeout
clipLastVtx equ $8 // Last vertex address on polygon
clipCurVtx equ $19 // Current vertex address on polygon
clipMaskShift equ $20 // Amount to left shift clip flags to put current condition bit in sign bit
clipWalkPhase equ $24 // Current action on walk: e.g. looking for onscreen-to-offscreen transition
// Misc:
nextRA equ $10 // Address to return to after overlay load
dmaLen equ $19 // DMA length in bytes minus 1
dmemAddr equ $20 // DMA address in DMEM or IMEM. Also = rdpCmdBufPtr - rdpCmdBufEndP1 for flush_rdp_buffer
ovlInitClock equ $21 // Temp for profiling. Share register with values not kept across ovl load.
cmd_w1_dram equ $24 // DL command word 1, which is also DMA DRAM addr
cmd_w0 equ $25 // DL command word 0, also holds next tris info
// Global vector regs:
// TODO can maybe get rid of vZero
vZero equ $v0 // All elements = 0; NOT global, only in tri write and clip. Mtx in vtx.
vTRC equ $v1 // Triangle Constants; NOT global, only in tri write and clip. Mtx in vtx.
vOne equ $v28 // All elements = 1; global
// $v29: permanent temp register, also write results here to discard
// $v30: vtx / lt = sSTO + persp norm + more lighting params; tri write = snake saved index
// $v31: Global constant vector register
// Vertex / lighting vector regs:
// Prefixes: v = vector register, vp = vertex pair, s = vertex store,
// l = basic lighting, a = advanced lighting
// Sadly, "vp" stands for vertex pair, view*projection matrix, and viewport
vMTX0I equ $v0 // Matrix rows int/frac; MVP normally, or M in ltadv
vMTX1I equ $v1
vMTX2I equ $v2
vMTX3I equ $v3
vMTX0F equ $v4
vMTX1F equ $v5
vMTX2F equ $v6
vMTX3F equ $v7
vTemp1 equ $v8 // Temporaries, used by lighting (along with some vp regs)
vTemp2 equ $v9
vKept1 equ $v10 // Kept across lighting
vKept2 equ $v11
vpMdl equ $v12 // Vertex pair model space position
vpClpF equ $v13 // Vertex pair clip space position frac
vpClpI equ $v14 // Vertex pair clip space position int
vpScrF equ $v15 // Vertex pair screen space position frac
vpScrI equ $v16 // Vertex pair screen space position int
vpST equ $v17 // Vertex pair ST texture coordinates
vpRGBA equ $v18 // Vertex pair color
vpLtTot equ $v19 // Vertex pair total light
vpNrmlX equ $v20 // Vertex pair normal X (elems 3, 7)
vpNrmlY equ $v21 // Vertex pair normal Y (elems 3, 7)
vpNrmlZ equ $v22 // Vertex pair normal Z (elems 3, 7)
vLTC equ $v23 // Lighting constants - first light dir, constants for packed normals
vPerm1 equ $v24 // Regs loaded in vtx_constants_for_clip and permanently kept through vtx/lt
vPerm2 equ $v25
vPerm3 equ $v26
vPerm4 equ $v27
// Lighting temporaries. Lighting also modifies vpNrmlX:Y:Z, vpLtTot, vpRGBA, and
// in texgen vpST. Only the two regs in the comments below and vKept1 are kept.
.if CFG_NO_OCCLUSION_PLANE
// vpClpI:F are kept, vpMdl is free to use as temp
lDOT equ vpMdl // lighting DOT product
lCOL equ vKept2 // lighting total light COLor
.else
// vpMdl is kept, these are free to use as temps
lDOT equ vpClpF
lCOL equ vpClpI
.endif
lDTC equ vTemp1 // lighting DoT Clamped
lVCI equ vTemp2 // lighting Vertex Color In
lDIR equ vpRGBA // lighting transformed light DIRection
// Kept
.if CFG_NO_OCCLUSION_PLANE
sCLZ equ vKept1 // vtx_store Clamped Z. Does have to be kept even though in instan_lt_vs_45 b/c need rest of lt temps at start of texgen (and advanced lighting).
sOCS equ $v29 // Does not exist
.else
sOCS equ vKept1 // vtx_store Occlusion State
sCLZ equ vpClpF // Not a kept in this config
.endif
// Common vertex temporaries
sRTF equ vTemp1 // vtx_store Reciprocal Temp Frac
sRTI equ vTemp2 // vtx_store Reciprocal Temp Int
sFOG equ lCOL // lCOL -> sFOG in lt epilogue with NOC, else sFOG -> lCOL in lt prologue
// Misc temps used by both
.if CFG_NO_OCCLUSION_PLANE
s1WI equ vpNrmlX // vtx_store 1/W Int
s1WF equ vpLtTot // vtx_store 1/W Frac
sSCI equ sFOG // vtx_store Scaled Clipping Int
sSCF equ vpMdl // vtx_store Scaled Clipping Frac
sTCL equ sCLZ // vtx_store Temp CoLor
.else
s1WI equ vpMdl
s1WF equ vpNrmlX
sSCI equ vpScrI
sSCF equ vpScrF
sTCL equ vpLtTot
.endif
// Misc temps used by only one
.if CFG_NO_OCCLUSION_PLANE
sST2 equ vpScrI // vtx_store ST coordinates copy 2
sOTM equ $v29 // Does not exist
.else
sST2 equ $v29 // Does not exist
sOTM equ vpRGBA // vtx_store Occlusion Temporary
.endif
// Permanently kept through vertex/lighting
.if CFG_NO_OCCLUSION_PLANE
sVPS equ vPerm1 // vtx_store ViewPort Scale
sVPO equ vPerm2 // vtx_store ViewPort Offset
sFGM equ vPerm3 // vtx_store FoG Mask
sO03 equ $v29 // Does not exist
sO47 equ $v29
sOCM equ $v29
sOPM equ $v29
.else
// These are temps, not permanents, on this codepath
sVPS equ vpScrI // Temp, not permament, on this codepath
sVPO equ vpScrF // Temp, not permament, on this codepath
sFGM equ $v29 // Does not exist
sO03 equ vPerm1 // vtx_store Occlusion plane edge coefficients 0-3
sO47 equ vPerm2 // vtx_store Occlusion plane edge coefficients 4-7
sOCM equ vPerm3 // vtx_store Occlusion plane Mid coefficients
sOPM equ vKept2 // vtx_store Occlusion Plus Minus. Loaded in vtx_after_lt_setup not vtx_constants_for_clip b/c clobbered by lighting.
.endif
sSTS equ vPerm4
// ltadv:
aPNScl equ $v8 // ltadv Packed Normals Scales = (1<<0),(1<<5),(1<<11),XX, repeat
aNrmSc equ $v9 // ltadv Normals Scale = [0h:1h] scale to normalize all normals; elems 2,3,6,7 used for point light factors
aDOT equ $v10 // ltadv Dot product = normals dot direction; also briefly light dir
aLen2I equ $v11 // ltadv Length 2quared Int part
// Uses vpMdl = $v12
vpWrlF equ $v13 // vertex pair World position Frac part
vpWrlI equ $v14 // vertex pair World position Int part
aDPosF equ $v15 // ltadv Delta Position Frac part
aDPosI equ $v16 // ltadv Delta Position Int part
aOAFrs equ $v17 // ltadv Offset Alpha (elem 3,7) and Fresnel (elem 0,4)
// Uses vpRGBA, vpLtTot, vpNrmlX, vpNrmlY, vpNrmlZ = $v18, $v19, $v20, $v21, $v22
aParam equ $v23 // ltadv Parameters = AO, texgen, and Fresnel params
aAOF2 equ aDOT // Version of aAOF in init, can't be aDPosI/F or vpMdl there
aPLFcI equ aLen2I // ltadv Point Light Factor Int part
aLen2F equ vpMdl // ltadv Length 2quared Frac part
aPLFcF equ vpMdl // ltadv Point Light Factor Frac part
aLTC equ vpMdl // ltadv Light Color
aClOut equ vpWrlF // ltadv Color Out
aAlOut equ vpWrlI // ltadv Alpha Out
aDIR equ aDPosF // ltadv Direction = normalize(light or cam - vertex)
aDotSc equ aDPosF // ltadv Dot product Scale factor
aLkDt0 equ aDPosF // ltadv Lookat Dot product 0 for texgen
aLenF equ aDPosI // ltadv Length Frac part
aAOF equ aDPosI // ltadv Ambient Occlusion Factor
aProj equ aDPosI // ltadv Projection
aLkDt1 equ aDPosI // ltadv Lookat Dot product 1 for texgen
// vpST equ aOAFrs // ST used in texgen
vpWNrm equ vpNrmlX // vertex pair World space Normals
aRcpLn equ $v29 // ltadv Reciprocal of Length
aLenI equ $v29 // ltadv Length Int part
// Temp storage after rdpCmdBufEndP1. There is 0xA8 of space here which will
// always be free during vtx load or clipping.
tempVpRGBA equ 0x00 // Only used during loop
tempXfrmLt equ tempVpRGBA // ltbasic only used during init
tempVtx1ST equ tempVpRGBA // ltadv only during init
tempAmbient equ 0x10 // ltbasic set during init, used during loop
tempClipPtrs equ tempAmbient // set during clipping, kept through vtx write
tempPrevInvalVtxStart equ 0x20
tempPrevInvalVtx equ (tempPrevInvalVtxStart + vtxSize) // 0x46; fog writes here
tempPrevInvalVtxEnd equ (tempPrevInvalVtx + vtxSize) // 0x6C; rest of vtx writes here
.if tempPrevInvalVtxEnd > (RDP_CMD_BUFSIZE_EXCESS - 8)
.error "Too much temp storage used!"
.endif
////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////// IMEM //////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// RSP IMEM
.create CODE_FILE, 0x00001080
// Initialization routines
// Everything up until ovl01_end will get overwritten by ovl1