-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathBank $80.asm
8369 lines (7553 loc) · 387 KB
/
Bank $80.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
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
;;; $8000: Debug constants ;;;
{
$80:8000 dw 0000 ; Skip NTSC/PAL and SRAM mapping check ($85F6)
$80:8002 dw 0000 ; Demo recorder ($90:E759)
$80:8004 dw 0000 ; Debug mode, written to $05D1 on boot
$80:8006 dw 0000 ; Debug scrolling ($82:8B44)
$80:8008 dw 0000 ; Disable audio ($8028)
}
;;; $800A..8110: APU upload ;;;
{
;;; $800A: Upload to APU (hardcoded parameter) ;;;
{
;; Parameter:
;; [[S] + 1] + 1: APU data pointer ($CF:8000)
$80:800A A3 02 LDA $02,s [$7E:1FFE] ;\
$80:800C 85 04 STA $04 [$7E:0004] ;|
$80:800E A3 01 LDA $01,s [$7E:1FFD] ;} $03 = (return address)
$80:8010 85 03 STA $03 [$7E:0003] ;/
$80:8012 18 CLC ;\
$80:8013 69 03 00 ADC #$0003 ;} (Return address) += 3
$80:8016 83 01 STA $01,s [$7E:1FFD] ;/
$80:8018 A0 01 00 LDY #$0001 ;\
$80:801B B7 03 LDA [$03],y[$80:845D] ;|
$80:801D 85 00 STA $00 [$7E:0000] ;|
$80:801F C8 INY ;} $00 = [[$03] + 1] (APU data pointer)
$80:8020 B7 03 LDA [$03],y[$80:845E] ;|
$80:8022 85 01 STA $01 [$7E:0001] ;/
}
;;; $8024: Upload to APU (from [$00]) (external) ;;;
{
;; Parameter
;; $00: APU data pointer
$80:8024 20 28 80 JSR $8028 [$80:8028] ; Upload to APU
$80:8027 6B RTL
}
;;; $8028: Upload to APU (from [$00]) ;;;
{
;; Parameter
;; $00: APU data pointer
$80:8028 AF 08 80 80 LDA $808008[$80:8008] ;\
$80:802C F0 01 BEQ $01 [$802F] ;} If [$80:8008] != 0:
$80:802E 60 RTS ; Return
$80:802F 08 PHP
$80:8030 8B PHB
$80:8031 C2 30 REP #$30
$80:8033 A9 FF FF LDA #$FFFF ;\
$80:8036 8F 17 06 00 STA $000617[$7E:0617] ;} Uploading to APU flag = FFFFh
$80:803A E2 20 SEP #$20
$80:803C C2 10 REP #$10
$80:803E A9 FF LDA #$FF ;\
$80:8040 8F 40 21 00 STA $002140 ;} APU IO 0 = FFh (request APU upload)
$80:8044 A4 00 LDY $00 [$7E:0000] ;\
$80:8046 A5 02 LDA $02 [$7E:0002] ;|
$80:8048 48 PHA ;} DB:Y = (APU data pointer)
$80:8049 AB PLB ;/
$80:804A C2 30 REP #$30
$80:804C 20 59 80 JSR $8059 [$80:8059] ; Send APU data
$80:804F A9 00 00 LDA #$0000 ;\
$80:8052 8F 17 06 00 STA $000617[$7E:0617] ;} Uploading to APU flag = 0
$80:8056 AB PLB
$80:8057 28 PLP
$80:8058 60 RTS
}
;;; $8059: Send APU data ;;;
{
;; Parameters:
;; DB:Y: APU data pointer
; Data format:
; ssss dddd [xx xx...] (data block 0)
; ssss dddd [xx xx...] (data block 1)
; ...
; 0000 aaaa
; Where:
; s = data block size in bytes
; d = destination address
; x = data
; a = entry address. Ignored by SPC engine after first APU transfer
; The xx data can cross bank boundaries, but the data block entries otherwise can't (i.e. s, d, a and 0000) unless they're word-aligned
; Wait until APU sets APU IO 0..1 = AAh BBh
; Kick = CCh
; For each data block:
; APU IO 2..3 = destination address
; APU IO 1 = 1 (arbitrary non-zero value)
; APU IO 0 = kick
; Wait until APU echoes kick back through APU IO 0
; Index = 0
; For each data byte
; APU IO 1 = data byte
; APU IO 0 = index
; Wait until APU echoes index back through APU IO 0
; Increment index
; Increment index (and again if resulting in 0)
; Kick = index
; Send entry address through APU IO 2..3
; APU IO 1 = 0
; APU IO 0 = kick
; (Optionally wait until APU echoes kick back through APU IO 0)
$80:8059 08 PHP
$80:805A C2 30 REP #$30
$80:805C A9 00 30 LDA #$3000 ;\
$80:805F 8F 41 06 00 STA $000641[$7E:0641] ;|
;|
$80:8063 A9 AA BB LDA #$BBAA ;|
$80:8066 CF 40 21 00 CMP $002140 ;|
$80:806A F0 0D BEQ $0D [$8079] ;} Wait until [APU IO 0..1] = AAh BBh
$80:806C AF 41 06 00 LDA $000641[$7E:0641] ;|
$80:8070 3A DEC A ;|
$80:8071 8F 41 06 00 STA $000641[$7E:0641] ;|
$80:8075 D0 EC BNE $EC [$8063] ;/
$80:8077 80 FE BRA $FE [$8077] ; If exceeded 3000h attempts: crash
$80:8079 E2 20 SEP #$20
$80:807B A9 CC LDA #$CC ; Kick = CCh
$80:807D 80 2F BRA $2F [$80AE] ; Go to BRANCH_PROCESS_DATA_BLOCK
; BRANCH_UPLOAD_DATA_BLOCK
$80:807F B9 00 00 LDA $0000,y[$CF:8004] ;\
$80:8082 20 03 81 JSR $8103 [$80:8103] ;} Data = [[Y++]]
$80:8085 EB XBA ;/
$80:8086 A9 00 LDA #$00 ; Index = 0
$80:8088 80 0F BRA $0F [$8099] ; Go to BRANCH_UPLOAD_DATA
; LOOP_NEXT_DATA
$80:808A EB XBA ;\
$80:808B B9 00 00 LDA $0000,y[$CF:8005] ;|
$80:808E 20 03 81 JSR $8103 [$80:8103] ;} Data = [[Y++]]
$80:8091 EB XBA ;/
$80:8092 CF 40 21 00 CMP $002140 ;\
$80:8096 D0 FA BNE $FA [$8092] ;} Wait until APU IO 0 echoes
$80:8098 1A INC A ; Increment index
; BRANCH_UPLOAD_DATA
$80:8099 C2 20 REP #$20
$80:809B 8F 40 21 00 STA $002140 ; APU IO 0..1 = [index] [data]
$80:809F E2 20 SEP #$20
$80:80A1 CA DEX ; Decrement X (block size)
$80:80A2 D0 E6 BNE $E6 [$808A] ; If [X] != 0: go to LOOP_NEXT_DATA
$80:80A4 CF 40 21 00 CMP $002140 ;\
$80:80A8 D0 FA BNE $FA [$80A4] ;} Wait until APU IO 0 echoes
$80:80AA 69 03 ADC #$03 ; Kick = [index] + 4
$80:80AC F0 FC BEQ $FC [$80AA] ; Ensure kick != 0
; BRANCH_PROCESS_DATA_BLOCK
$80:80AE 48 PHA
$80:80AF C2 20 REP #$20
$80:80B1 B9 00 00 LDA $0000,y[$CF:8000] ;\
$80:80B4 20 00 81 JSR $8100 [$80:8100] ;} X = [[Y]] (block size)
$80:80B7 AA TAX ;} Y += 2
$80:80B8 B9 00 00 LDA $0000,y[$CF:8002] ;\
$80:80BB 20 00 81 JSR $8100 [$80:8100] ;} APU IO 2..3 = [[Y]] (destination address)
$80:80BE 8F 42 21 00 STA $002142 ;} Y += 2
$80:80C2 E2 20 SEP #$20
$80:80C4 E0 01 00 CPX #$0001 ;\
$80:80C7 A9 00 LDA #$00 ;|
$80:80C9 2A ROL A ;} If block size = 0: APU IO 1 = 0 (EOF), else APU IO 1 = 1 (arbitrary non-zero value)
$80:80CA 8F 41 21 00 STA $002141 ;/
$80:80CE 69 7F ADC #$7F ; Set overflow if block size != 0, else clear overflow
$80:80D0 68 PLA ;\
$80:80D1 8F 40 21 00 STA $002140 ;} APU IO 0 = kick
$80:80D5 DA PHX
$80:80D6 A2 00 10 LDX #$1000 ;\
;|
$80:80D9 CA DEX ;} Wait until APU IO 0 echoes
$80:80DA F0 16 BEQ $16 [$80F2] ;} If exceeded 1000h attempts: return
$80:80DC CF 40 21 00 CMP $002140 ;|
$80:80E0 D0 F7 BNE $F7 [$80D9] ;/
$80:80E2 FA PLX
$80:80E3 70 9A BVS $9A [$807F] ; If block size != 0: go to BRANCH_UPLOAD_DATA_BLOCK
$80:80E5 E2 20 SEP #$20
$80:80E7 9C 41 21 STZ $2141 ;\
$80:80EA 9C 42 21 STZ $2142 ;} These stores have no effect (because DB is set to some hirom bank), but there's also no reason to do these stores anyway
$80:80ED 9C 43 21 STZ $2143 ;/
$80:80F0 28 PLP
$80:80F1 60 RTS ; Return
$80:80F2 E2 20 SEP #$20
$80:80F4 9C 41 21 STZ $2141
$80:80F7 9C 42 21 STZ $2142
$80:80FA 9C 43 21 STZ $2143
$80:80FD FA PLX
$80:80FE 28 PLP
$80:80FF 60 RTS
}
;;; $8100: Increment Y twice, bank overflow check ;;;
{
;; Parameters:
;; DB:Y: Pointer
;; $02: Bank mirror
;; Returns:
;; DB:Y: Pointer incremented twice (Y wraps around from $8000 if bank overflows)
;; $02: Bank mirror incremented if needed
; Fails to increment Y a second time if the first increment overflows the bank
$80:8100 C8 INY ; Increment Y
$80:8101 F0 04 BEQ $04 [$8107] ; If [Y] = 0: go to handle bank overflow
}
;;; $8103: Increment Y, bank overflow check ;;;
{
;; Parameters:
;; DB:Y: Pointer
;; $02: Bank mirror
;; Returns:
;; DB:Y: Pointer incremented twice (Y wraps around from $8000 if bank overflows)
;; $02: Bank mirror incremented if needed
$80:8103 C8 INY ; Increment Y
$80:8104 F0 01 BEQ $01 [$8107] ; If [Y] = 0: go to handle bank overflow
$80:8106 60 RTS
}
;;; $8107: Handle bank overflow ;;;
{
;; Parameters:
;; $02: Bank
;; Returns:
;; Y: $8000
;; DB/$02: Incremented bank
$80:8107 E6 02 INC $02 [$7E:0002] ; Increment $02
$80:8109 D4 01 PEI ($01) [$D080] ;\
$80:810B AB PLB ;} DB = [$02]
$80:810C AB PLB ;/
$80:810D A0 00 80 LDY #$8000 ; Y = 8000h
$80:8110 60 RTS
}
}
;;; $8111: Generate random number ;;;
{
;; Returns:
;; A: New random number
; r(t+1) = r(t) * 5 + 0x111 (roughly; if the adding of x * 100h causes overflow, then a further 1 is added)
$80:8111 E2 20 SEP #$20
$80:8113 AD E5 05 LDA $05E5 [$7E:05E5] ;\
$80:8116 8D 02 42 STA $4202 ;|
$80:8119 A9 05 LDA #$05 ;|
$80:811B 8D 03 42 STA $4203 ;|
$80:811E EA NOP ;} A = [random number low] * 5
$80:811F C2 20 REP #$20 ;|
$80:8121 AD 16 42 LDA $4216 ;|
$80:8124 48 PHA ;/
$80:8125 E2 20 SEP #$20
$80:8127 AD E6 05 LDA $05E6 [$7E:05E6] ;\
$80:812A 8D 02 42 STA $4202 ;|
$80:812D A9 05 LDA #$05 ;|
$80:812F 8D 03 42 STA $4203 ;|
$80:8132 EB XBA ;|
$80:8133 EA NOP ;|
$80:8134 AD 16 42 LDA $4216 ;} A += ([random number high] * 5 + 1) * 100h
$80:8137 38 SEC ;|
$80:8138 63 02 ADC $02,s [$7E:1FFB] ;|
$80:813A 83 02 STA $02,s [$7E:1FFB] ;|
$80:813C C2 20 REP #$20 ;|
$80:813E 68 PLA ;/
$80:813F 69 11 00 ADC #$0011 ;\
$80:8142 8D E5 05 STA $05E5 [$7E:05E5] ;} Random number = [A] + 11h
$80:8145 6B RTL
}
;;; $8146: Update held input ;;;
{
;; Parameter:
;; A: Timed held input timer reset value ("timed held input" is input held for [A] + 1 frames)
; Called by:
; $82:90E8: Game state Fh (paused, map and item screens) with A = 3
; Held input is [$8B] & ![$8F]: the input pressed, but not newly
$80:8146 08 PHP
$80:8147 8B PHB
$80:8148 C2 30 REP #$30
$80:814A DA PHX
$80:814B 4B PHK ;\
$80:814C AB PLB ;} DB = $80
$80:814D 8D DD 05 STA $05DD [$7E:05DD] ; Timed held input timer reset value = [A]
$80:8150 A5 8B LDA $8B [$7E:008B] ;\
$80:8152 85 12 STA $12 [$7E:0012] ;|
$80:8154 A5 8F LDA $8F [$7E:008F] ;|
$80:8156 14 12 TRB $12 [$7E:0012] ;|
$80:8158 A5 12 LDA $12 [$7E:0012] ;} If held input != [previous held input]: go to BRANCH_UNHELD
$80:815A CD D9 05 CMP $05D9 [$7E:05D9] ;|
$80:815D 8D D9 05 STA $05D9 [$7E:05D9] ; } Previous held input = held input
$80:8160 D0 13 BNE $13 [$8175] ;/
$80:8162 CE DB 05 DEC $05DB [$7E:05DB] ; Decrement timed held input timer
$80:8165 10 14 BPL $14 [$817B] ; If [timed held input timer] >= 0: go to BRANCH_POSITIVE
$80:8167 9C DB 05 STZ $05DB [$7E:05DB] ; Timed held input timer = 0
$80:816A AE DF 05 LDX $05DF [$7E:05DF] ;\
$80:816D 8E E3 05 STX $05E3 [$7E:05E3] ;} Previous timed held input = [timed held input]
$80:8170 8D DF 05 STA $05DF [$7E:05DF] ; Timed held input = [held input]
$80:8173 80 09 BRA $09 [$817E] ; Go to BRANCH_RETURN
; BRANCH_UNHELD
$80:8175 AD DD 05 LDA $05DD [$7E:05DD] ;\
$80:8178 8D DB 05 STA $05DB [$7E:05DB] ;} Timed held input timer = [timed held input timer reset value]
; BRANCH_POSITIVE
$80:817B 9C DF 05 STZ $05DF [$7E:05DF] ; Timed held input = 0
; BRANCH_RETURN
$80:817E AD DF 05 LDA $05DF [$7E:05DF] ;\
$80:8181 4D E3 05 EOR $05E3 [$7E:05E3] ;|
$80:8184 2D DF 05 AND $05DF [$7E:05DF] ;} Newly held down timed held input = newly held down timed held input
$80:8187 8D E1 05 STA $05E1 [$7E:05E1] ;/
$80:818A FA PLX
$80:818B AB PLB
$80:818C 28 PLP
$80:818D 6B RTL
}
;;; $818E: Change bit index to byte index and bitmask ;;;
{
;; Parameter:
;; A: Bit index, 8000h bit is forbidden
;; Returns:
;; A/X: Byte index ([A] >> 3)
;; $05E7: Bitmask (1 << ([A] & 7))
; Called mostly by PLMs
$80:818E AA TAX ;\
$80:818F 10 01 BPL $01 [$8192] ;} If [A] & 8000h != 0:
$80:8191 00 BRK ; Crash
$80:8192 9C E7 05 STZ $05E7 [$7E:05E7] ;\
$80:8195 48 PHA ;|
$80:8196 29 07 00 AND #$0007 ;|
$80:8199 38 SEC ;|
;} Bitmask = 1 << ([A] & 7)
$80:819A 2E E7 05 ROL $05E7 [$7E:05E7] ;|
$80:819D 3A DEC A ;|
$80:819E 10 FA BPL $FA [$819A] ;|
$80:81A0 68 PLA ;/
$80:81A1 4A LSR A ;\
$80:81A2 4A LSR A ;|
$80:81A3 4A LSR A ;} X = A = [A] >> 3
$80:81A4 AA TAX ;/
$80:81A5 6B RTL
}
;;; $81A6: Set boss bits in A for current area ;;;
{
;; Parameter:
;; A: Boss bits
;; 1: Area boss (Kraid, Phantoon, Draygon, both Ridleys)
;; 2: Area mini-boss (Spore Spawn, Botwoon, Crocomire, Mother Brain)
;; 4: Area torizo (Bomb Torizo, Golden Torizo)
$80:81A6 DA PHX
$80:81A7 5A PHY
$80:81A8 08 PHP
$80:81A9 E2 20 SEP #$20
$80:81AB 8D E7 05 STA $05E7 [$7E:05E7]
$80:81AE AE 9F 07 LDX $079F [$7E:079F]
$80:81B1 BF 28 D8 7E LDA $7ED828,x[$7E:D82E]
$80:81B5 0D E7 05 ORA $05E7 [$7E:05E7]
$80:81B8 9F 28 D8 7E STA $7ED828,x[$7E:D82E]
$80:81BC 28 PLP
$80:81BD 7A PLY
$80:81BE FA PLX
$80:81BF 6B RTL
}
;;; $81C0: Unused. Clear boss bits in A for current area ;;;
{
;; Parameter:
;; A: Boss bits
;; 1: Area boss (Kraid, Phantoon, Draygon, both Ridleys)
;; 2: Area mini-boss (Spore Spawn, Botwoon, Crocomire, Mother Brain)
;; 4: Area torizo (Bomb Torizo, Golden Torizo)
$80:81C0 DA PHX
$80:81C1 5A PHY
$80:81C2 08 PHP
$80:81C3 E2 20 SEP #$20
$80:81C5 49 FF EOR #$FF
$80:81C7 8D E7 05 STA $05E7 [$7E:05E7]
$80:81CA AE 9F 07 LDX $079F [$7E:079F]
$80:81CD BF 28 D8 7E LDA $7ED828,x[$7E:D828]
$80:81D1 2D E7 05 AND $05E7 [$7E:05E7]
$80:81D4 9F 28 D8 7E STA $7ED828,x[$7E:D828]
$80:81D8 28 PLP
$80:81D9 7A PLY
$80:81DA FA PLX
$80:81DB 6B RTL
}
;;; $81DC: Checks if the boss bits for the current area match any bits in A ;;;
{
;; Parameter:
;; A: Boss bits
;; 1: Area boss (Kraid, Phantoon, Draygon, both Ridleys)
;; 2: Area mini-boss (Spore Spawn, Botwoon, Crocomire, Mother Brain)
;; 4: Area torizo (Bomb Torizo, Golden Torizo)
;; Returns:
;; A/carry: Set if there's a match
$80:81DC DA PHX
$80:81DD 5A PHY
$80:81DE 08 PHP
$80:81DF E2 20 SEP #$20
$80:81E1 8D E7 05 STA $05E7 [$7E:05E7]
$80:81E4 AE 9F 07 LDX $079F [$7E:079F]
$80:81E7 BF 28 D8 7E LDA $7ED828,x[$7E:D82E]
$80:81EB 2D E7 05 AND $05E7 [$7E:05E7]
$80:81EE D0 05 BNE $05 [$81F5]
$80:81F0 28 PLP
$80:81F1 7A PLY
$80:81F2 FA PLX
$80:81F3 18 CLC
$80:81F4 6B RTL
$80:81F5 28 PLP
$80:81F6 7A PLY
$80:81F7 FA PLX
$80:81F8 38 SEC
$80:81F9 6B RTL
}
;;; $81FA: Mark event [A] ;;;
{
;; Parameter:
;; A: Event number
;; 0: Zebes is awake
;; 1: Shitroid ate sidehopper
;; 2: Mother Brain's glass is destroyed
;; 3: Zebetite destroyed bit 0 (true if 1 or 3 zebetites are destroyed)
;; 4: Zebetite destroyed bit 1 (true if 2 or 3 zebetites are destroyed)
;; 5: Zebetite destroyed bit 2 (true if all 4 zebetites are destroyed)
;; 6: Phantoon statue is grey
;; 7: Ridley statue is grey
;; 8: Draygon statue is grey
;; 9: Kraid statue is grey
;; Ah: Entrance to Tourian is unlocked
;; Bh: Maridia noobtube is broken
;; Ch: Lower Norfair chozo has lowered the acid
;; Dh: Shaktool cleared a path
;; Eh: Zebes timebomb set
;; Fh: Critters escaped
;; 10h: 1st metroid hall cleared
;; 11h: 1st metroid shaft cleared
;; 12h: 2nd metroid hall cleared
;; 13h: 2nd metroid shaft cleared
;; 14h: Unused
;; 15h: Outran speed booster lavaquake
$80:81FA DA PHX
$80:81FB 5A PHY
$80:81FC 08 PHP
$80:81FD C2 30 REP #$30
$80:81FF 22 8E 81 80 JSL $80818E[$80:818E]
$80:8203 BF 20 D8 7E LDA $7ED820,x[$7E:D820]
$80:8207 0D E7 05 ORA $05E7 [$7E:05E7]
$80:820A 9F 20 D8 7E STA $7ED820,x[$7E:D820]
$80:820E 28 PLP
$80:820F 7A PLY
$80:8210 FA PLX
$80:8211 6B RTL
}
;;; $8212: Unmark event [A] ;;;
{
;; Parameter:
;; A: Event number
; Called by:
; $A6:FCCB: Mark/unmark zebetite destroyed counter event
$80:8212 DA PHX
$80:8213 5A PHY
$80:8214 08 PHP
$80:8215 C2 30 REP #$30
$80:8217 22 8E 81 80 JSL $80818E[$80:818E]
$80:821B AD E7 05 LDA $05E7 [$7E:05E7]
$80:821E 49 FF FF EOR #$FFFF
$80:8221 8D E7 05 STA $05E7 [$7E:05E7]
$80:8224 BF 20 D8 7E LDA $7ED820,x[$7E:D820]
$80:8228 2D E7 05 AND $05E7 [$7E:05E7]
$80:822B 9F 20 D8 7E STA $7ED820,x[$7E:D820]
$80:822F 28 PLP
$80:8230 7A PLY
$80:8231 FA PLX
$80:8232 6B RTL
}
;;; $8233: Checks event [A] has happened ;;;
{
;; Parameter:
;; A: Event number
;; Returns:
;; Carry: Set if the event is marked
; Note that Tourian entrance statue FX routine $88:DCCB assumes this routine returns A = 0 when carry clear is returned
$80:8233 DA PHX
$80:8234 5A PHY
$80:8235 08 PHP
$80:8236 C2 30 REP #$30
$80:8238 22 8E 81 80 JSL $80818E[$80:818E]
$80:823C BF 20 D8 7E LDA $7ED820,x[$7E:D821]
$80:8240 2D E7 05 AND $05E7 [$7E:05E7]
$80:8243 D0 05 BNE $05 [$824A]
$80:8245 28 PLP
$80:8246 7A PLY
$80:8247 FA PLX
$80:8248 18 CLC
$80:8249 6B RTL
$80:824A 28 PLP
$80:824B 7A PLY
$80:824C FA PLX
$80:824D 38 SEC
$80:824E 6B RTL
}
;;; $824F: Write 'supermetroid' to SRAM ;;;
{
; Called by:
; $8B:E797: Cinematic function - post-credits - scroll item percentage down
; $70:1FE0..1FEB = 'supermetroid' (game completed)
$80:824F DA PHX
$80:8250 A2 0A 00 LDX #$000A
$80:8253 BF B9 82 80 LDA $8082B9,x[$80:82C3]
$80:8257 9F E0 1F 70 STA $701FE0,x[$70:1FEA]
$80:825B CA DEX
$80:825C CA DEX
$80:825D 10 F4 BPL $F4 [$8253]
$80:825F FA PLX
$80:8260 6B RTL
}
;;; $8261: Determine number of demo sets ;;;
{
$80:8261 DA PHX
$80:8262 A9 03 00 LDA #$0003 ;\
$80:8265 8D 59 1F STA $1F59 [$7E:1F59] ;} Number of demo sets = 3
$80:8268 A9 00 00 LDA #$0000 ;\
$80:826B 22 85 80 81 JSL $818085[$81:8085] ;} Load SRAM slot A
$80:826F 90 23 BCC $23 [$8294] ; If not corrupt, go to BRANCH_NON_CORRUPT
$80:8271 A9 01 00 LDA #$0001 ;\
$80:8274 22 85 80 81 JSL $818085[$81:8085] ;} Load SRAM slot B
$80:8278 90 1A BCC $1A [$8294] ; If not corrupt, go to BRANCH_NON_CORRUPT
$80:827A A9 02 00 LDA #$0002 ;\
$80:827D 22 85 80 81 JSL $818085[$81:8085] ;} Load SRAM slot C
$80:8281 90 11 BCC $11 [$8294] ; If not corrupt, go to BRANCH_NON_CORRUPT
$80:8283 A2 0A 00 LDX #$000A ;\
;|
$80:8286 BF AD 82 80 LDA $8082AD,x[$80:949A];|
$80:828A 9F E0 1F 70 STA $701FE0,x[$70:31CD];} $70:1FE0..1FEB = 'madadameyohn' (game not completed)
$80:828E CA DEX ;|
$80:828F CA DEX ;|
$80:8290 10 F4 BPL $F4 [$8286] ;/
$80:8292 FA PLX
$80:8293 6B RTL ; Return
; BRANCH_NON_CORRUPT
$80:8294 A2 0A 00 LDX #$000A ;\
;|
$80:8297 BF E0 1F 70 LDA $701FE0,x[$70:1FEA];|
$80:829B DF B9 82 80 CMP $8082B9,x[$80:82C3];|
$80:829F D0 0A BNE $0A [$82AB] ;} If [$70:1FE0..1FEB] = 'supermetroid' (game completed):
;|
$80:82A1 CA DEX ;|
$80:82A2 CA DEX ;|
$80:82A3 10 F2 BPL $F2 [$8297] ;/
$80:82A5 A9 04 00 LDA #$0004 ;\
$80:82A8 8D 59 1F STA $1F59 [$7E:1F59] ;} Number of demo sets = 4
$80:82AB FA PLX
$80:82AC 6B RTL
$80:82AD db 6D, 61, 64, 61, 64, 61, 6D, 65, 79, 6F, 68, 6E ; madadameyohn
$80:82B9 db 73, 75, 70, 65, 72, 6D, 65, 74, 72, 6F, 69, 64 ; supermetroid
}
;;; $82C5: Wait until the end of a v-blank ;;;
{
$80:82C5 48 PHA
$80:82C6 08 PHP
$80:82C7 E2 20 SEP #$20
$80:82C9 AD 12 42 LDA $4212 ;\
$80:82CC 10 FB BPL $FB [$82C9] ;} Wait until v-blank is active
$80:82CE AD 12 42 LDA $4212 ;\
$80:82D1 30 FB BMI $FB [$82CE] ;} Wait until v-blank has finished
$80:82D3 28 PLP
$80:82D4 68 PLA
$80:82D5 6B RTL
}
;;; $82D6: $05F1 = [A] * [Y] (16-bit unsigned multiplication) ;;;
{
;; Parameters:
;; A: Multiplicand
;; Y: Multiplicand
;; Returns:
;; $05F1..F4: 32-bit result
; Called by:
; $94:84D6: Samus block collision reaction - horizontal - slope - non-square
; $94:ACFE: Handle grapple beam swinging movement
; $9B:CA65: Propel Samus from grapple swing
; $A0:C449: Enemy block collision reaction - horizontal - slope - non-square
; $A3:E8A5: Adjust enemy X velocity for slopes
; Exactly 1060 master cycles (78% of a scanline) (1250 if using slowrom).
; Can be inaccurate.
; Let:
; [A] = a + b * 100h
; [Y] = c + d * 100h
; Then:
; [A] * [Y] = (a + b * 100h) (c + d * 100h)
; = ac + (bc + ad) * 100h + bd * 10000h
; However, (bc + ad) can overflow 10000h (e.g. C0h * C0h + C0h * C0h = 12000h)
; and the carry isn't propagated to the calculation of bd (instruction $832D should be removed).
$80:82D6 DA PHX
$80:82D7 8D E9 05 STA $05E9 [$7E:05E9] ; Let $05E9 = a + b * 100h
$80:82DA 8C EB 05 STY $05EB [$7E:05EB] ; Let $05EB = c + d * 100h
$80:82DD 9C F1 05 STZ $05F1 [$7E:05F1] ;\
$80:82E0 9C F3 05 STZ $05F3 [$7E:05F3] ;} Result = 0
$80:82E3 E2 10 SEP #$10
$80:82E5 AC EB 05 LDY $05EB [$7E:05EB] ;\
$80:82E8 8C 02 42 STY $4202 ;|
$80:82EB AC E9 05 LDY $05E9 [$7E:05E9] ;|
$80:82EE 8C 03 42 STY $4203 ;|
$80:82F1 EA NOP ;} Result = ac
$80:82F2 EA NOP ;|
$80:82F3 EA NOP ;|
$80:82F4 AD 16 42 LDA $4216 ;|
$80:82F7 8D F1 05 STA $05F1 [$7E:05F1] ;/
$80:82FA AC EA 05 LDY $05EA [$7E:05EA] ;\
$80:82FD 8C 03 42 STY $4203 ;|
$80:8300 EA NOP ;|
$80:8301 AD F2 05 LDA $05F2 [$7E:05F2] ;} Result += bc * 100h
$80:8304 18 CLC ;|
$80:8305 6D 16 42 ADC $4216 ;|
$80:8308 8D F2 05 STA $05F2 [$7E:05F2] ;/
$80:830B AC EC 05 LDY $05EC [$7E:05EC] ;\
$80:830E 8C 02 42 STY $4202 ;|
$80:8311 AC E9 05 LDY $05E9 [$7E:05E9] ;|
$80:8314 8C 03 42 STY $4203 ;|
$80:8317 EA NOP ;} Result += ad * 100h
$80:8318 AD F2 05 LDA $05F2 [$7E:05F2] ;|
$80:831B 18 CLC ;|
$80:831C 6D 16 42 ADC $4216 ;|
$80:831F 8D F2 05 STA $05F2 [$7E:05F2] ;/
$80:8322 AC EA 05 LDY $05EA [$7E:05EA] ;\
$80:8325 8C 03 42 STY $4203 ;|
$80:8328 EA NOP ;|
$80:8329 EA NOP ;|
$80:832A AD F3 05 LDA $05F3 [$7E:05F3] ;} Result += bd * 10000h
$80:832D 18 CLC ;|
$80:832E 6D 16 42 ADC $4216 ;|
$80:8331 8D F3 05 STA $05F3 [$7E:05F3] ;/
$80:8334 C2 30 REP #$30
$80:8336 FA PLX
$80:8337 6B RTL
}
;;; $8338: Wait for NMI ;;;
{
$80:8338 08 PHP
$80:8339 8B PHB
$80:833A 4B PHK ;\
$80:833B AB PLB ;} DB = $80
$80:833C E2 30 SEP #$30
$80:833E A9 01 LDA #$01 ;\
$80:8340 8D B4 05 STA $05B4 [$7E:05B4] ;} NMI request flag = 1
$80:8343 AD B4 05 LDA $05B4 [$7E:05B4] ;\
$80:8346 D0 FB BNE $FB [$8343] ;} Wait until NMI request acknowledged
$80:8348 AB PLB
$80:8349 28 PLP
$80:834A 6B RTL
}
;;; $834B: Enable NMI ;;;
{
$80:834B 08 PHP
$80:834C 8B PHB
$80:834D 4B PHK
$80:834E AB PLB
$80:834F E2 20 SEP #$20
$80:8351 A5 84 LDA $84 [$7E:0084]
$80:8353 09 80 ORA #$80
$80:8355 8D 00 42 STA $4200
$80:8358 85 84 STA $84 [$7E:0084]
$80:835A AB PLB
$80:835B 28 PLP
$80:835C 6B RTL
}
;;; $835D: Disable NMI ;;;
{
$80:835D 08 PHP
$80:835E 8B PHB
$80:835F 4B PHK
$80:8360 AB PLB
$80:8361 E2 20 SEP #$20
$80:8363 A5 84 LDA $84 [$7E:0084]
$80:8365 29 7F AND #$7F
$80:8367 8D 00 42 STA $4200
$80:836A 85 84 STA $84 [$7E:0084]
$80:836C AB PLB
$80:836D 28 PLP
$80:836E 6B RTL
}
;;; $836F: Set force blank and wait for NMI ;;;
{
; Called by:
; $B032: Unused. Set up rotating mode 7 background
; $81:8D0F: (Debug) game over menu - index 0: fade out and configure graphics for menu
; $81:944E: File select menu - index 0: title sequence to main - fade out and configure graphics
; $81:94EE: File select menu - index 5/13h: fade out from main
; $81:AF83: File select map - index Eh: room select map to loading game data - wait
; $A7:C1FB: Unpause hook - Kraid is dead
; $A7:C24E: Unpause hook - Kraid is alive
; $A7:C2A0: Unpause hook - Kraid is sinking
; Note that setting force blank allows PPU writes even if NMI execution spills into the next frame's drawing period,
; so you can set up large VRAM transfers before calling this
$80:836F 08 PHP
$80:8370 8B PHB
$80:8371 4B PHK
$80:8372 AB PLB
$80:8373 E2 20 SEP #$20
$80:8375 A5 51 LDA $51 [$7E:0051]
$80:8377 09 80 ORA #$80
$80:8379 85 51 STA $51 [$7E:0051]
$80:837B 22 38 83 80 JSL $808338[$80:8338]
$80:837F AB PLB
$80:8380 28 PLP
$80:8381 6B RTL
}
;;; $8382: Clear force blank and wait for NMI ;;;
{
; Called by:
; $B032: Unused. Set up rotating mode 7 background
; $81:8D6D: Debug game over menu - index 1: initialise
; $81:91A4: Game over menu - index 1: initialise
; $81:9ED6: File select menu - index 2: title sequence to main - initialise
; $A7:C24E: Unpause hook - Kraid is alive
$80:8382 08 PHP
$80:8383 8B PHB
$80:8384 4B PHK
$80:8385 AB PLB
$80:8386 E2 20 SEP #$20
$80:8388 A5 51 LDA $51 [$7E:0051]
$80:838A 29 7F AND #$7F
$80:838C 85 51 STA $51 [$7E:0051]
$80:838E 22 38 83 80 JSL $808338[$80:8338]
$80:8392 AB PLB
$80:8393 28 PLP
$80:8394 6B RTL
}
;;; $8395: Unused. Update CGRAM ;;;
{
; This routine is subsumed by $933A (update OAM & CGRAM)
$80:8395 08 PHP
$80:8396 E2 10 SEP #$10
$80:8398 C2 20 REP #$20
$80:839A A9 00 22 LDA #$2200
$80:839D 8D 10 43 STA $4310
$80:83A0 A9 00 C0 LDA #$C000
$80:83A3 8D 12 43 STA $4312
$80:83A6 A2 7E LDX #$7E
$80:83A8 8E 14 43 STX $4314
$80:83AB A9 00 02 LDA #$0200
$80:83AE 8D 15 43 STA $4315
$80:83B1 A2 00 LDX #$00
$80:83B3 8E 21 21 STX $2121
$80:83B6 A2 02 LDX #$02
$80:83B8 8E 0B 42 STX $420B
$80:83BB 28 PLP
$80:83BC 6B RTL
}
;;; $83BD: Unused. Write [Y] bytes of [A] to $00:0000 + [X] - 8-bit ;;;
{
;; Parameters:
;; A: Fill value
;; X: Destination address. Range $0000..1FFF for WRAM writes
;; Y: Size
$80:83BD 08 PHP
$80:83BE 8B PHB
$80:83BF 4B PHK
$80:83C0 AB PLB
$80:83C1 E2 20 SEP #$20
$80:83C3 C2 10 REP #$10
$80:83C5 9F 00 00 00 STA $000000,x
$80:83C9 E8 INX
$80:83CA 88 DEY
$80:83CB D0 F8 BNE $F8 [$83C5]
$80:83CD AB PLB
$80:83CE 28 PLP
$80:83CF 6B RTL
}
;;; $83D0: Unused. Write [Y] bytes of [A] to $00:0000 + [X] - 16-bit ;;;
{
;; Parameters:
;; A: Fill value
;; X: Destination address. Range $0000..1FFF for WRAM writes
;; Y: Size
$80:83D0 08 PHP
$80:83D1 8B PHB
$80:83D2 4B PHK
$80:83D3 AB PLB
$80:83D4 C2 30 REP #$30
$80:83D6 9F 00 00 00 STA $000000,x
$80:83DA E8 INX
$80:83DB E8 INX
$80:83DC 88 DEY
$80:83DD 88 DEY
$80:83DE D0 F6 BNE $F6 [$83D6]
$80:83E0 AB PLB
$80:83E1 28 PLP
$80:83E2 6B RTL
}
;;; $83E3: Unused. Write [Y] bytes of [A] to $7E:0000 + [X] - 8-bit ;;;
{
;; Parameters:
;; A: Fill value
;; X: Destination address
;; Y: Size
$80:83E3 08 PHP
$80:83E4 8B PHB
$80:83E5 4B PHK
$80:83E6 AB PLB
$80:83E7 E2 20 SEP #$20
$80:83E9 C2 10 REP #$10
$80:83EB 9F 00 00 7E STA $7E0000,x
$80:83EF E8 INX
$80:83F0 88 DEY
$80:83F1 D0 F8 BNE $F8 [$83EB]
$80:83F3 AB PLB
$80:83F4 28 PLP
$80:83F5 6B RTL
}
;;; $83F6: Write [Y] bytes of [A] to $7E:0000 + [X] - 16-bit ;;;
{
;; Parameters:
;; A: Fill value
;; X: Destination address
;; Y: Size
; Called by:
; $88B4: Unused. Clear high RAM
; $88EB: Write 800h bytes of [A] to $7E:3000
; $88FE: Write 800h bytes of [A] to $7E:4000
; $88FE: Write 800h bytes of [A] to $7E:6000
; $82:81DD: Set up PPU for gameplay
; $8B:8000: Set up PPU for title sequence
; $8B:80DA: Set up PPU for intro
$80:83F6 08 PHP
$80:83F7 8B PHB
$80:83F8 4B PHK
$80:83F9 AB PLB
$80:83FA C2 30 REP #$30
$80:83FC 9F 00 00 7E STA $7E0000,x[$7E:3000]
$80:8400 E8 INX
$80:8401 E8 INX
$80:8402 88 DEY
$80:8403 88 DEY
$80:8404 D0 F6 BNE $F6 [$83FC]
$80:8406 AB PLB
$80:8407 28 PLP
$80:8408 6B RTL
}
;;; $8409: Write [Y] bytes of [A] to $7F:0000 + [X] - 16-bit ;;;
{
;; Parameters:
;; A: Fill value
;; X: Destination address
;; Y: Size
; Called by
; $88B4: Unused. Clear high RAM
$80:8409 08 PHP
$80:840A 8B PHB
$80:840B 4B PHK
$80:840C AB PLB
$80:840D C2 30 REP #$30
$80:840F 9F 00 00 7F STA $7F0000,x[$7F:11ED]
$80:8413 E8 INX
$80:8414 E8 INX
$80:8415 88 DEY
$80:8416 88 DEY
$80:8417 D0 F6 BNE $F6 [$840F]
$80:8419 AB PLB
$80:841A 28 PLP
$80:841B 6B RTL
}
;;; $841C: Boot ;;;
{
; Most SNES games don't randomly wait 3 frames before running initialisation
; Best wild guess is that they might have had some kind of dev hardware thingy attached somewhere that boot-up had to wait for
$80:841C 78 SEI ; Disable IRQ
$80:841D 18 CLC ;\
$80:841E FB XCE ;} Enable native mode
$80:841F 5C 23 84 80 JML $808423[$80:8423] ; Execute in bank $80 (FastROM)
$80:8423 E2 20 SEP #$20
$80:8425 A9 01 LDA #$01 ;\
$80:8427 8D 0D 42 STA $420D ;} Enable FastROM
$80:842A 85 86 STA $86 [$7E:0086] ;/
$80:842C C2 30 REP #$30
$80:842E A2 FF 1F LDX #$1FFF ;\
$80:8431 9A TXS ;} Allocate stack memory
$80:8432 A9 00 00 LDA #$0000 ;\
$80:8435 5B TCD ;} Clear direct page
$80:8436 4B PHK ;\
$80:8437 AB PLB ;} DB = $80
$80:8438 E2 30 SEP #$30
$80:843A A2 04 LDX #$04 ;\
;|
$80:843C AD 12 42 LDA $4212 ;|
$80:843F 10 FB BPL $FB [$843C] ;|
;} Wait the remainder of this frame and 3 more frames
$80:8441 AD 12 42 LDA $4212 ;|
$80:8444 30 FB BMI $FB [$8441] ;|
$80:8446 CA DEX ;|
$80:8447 D0 F3 BNE $F3 [$843C] ;/
$80:8449 C2 30 REP #$30
$80:844B A2 FE 1F LDX #$1FFE ;\
;|
$80:844E 9E 00 00 STZ $0000,x[$7E:1FFE] ;|
$80:8451 CA DEX ;} Clear $0000..1FFF
$80:8452 CA DEX ;|
$80:8453 10 F9 BPL $F9 [$844E] ;/
$80:8455 22 46 91 8B JSL $8B9146[$8B:9146] ; Initialise IO registers and display Nintendo logo
$80:8459 22 0A 80 80 JSL $80800A[$80:800A] ;\
$80:845D dl CF8000 ;} Upload SPC engine to APU
$80:8460 80 20 BRA $20 [$8482] ; Go to common boot section
}
;;; $8462: Soft reset ;;;
{
; Called by:
; $9459: Read controller input. Also a debug branch
; $81:9003: Debug game over menu - index 3: main
; $81:90FE: Game over menu - index 7: fade out into soft reset