forked from captainsouthbird/smb3
-
Notifications
You must be signed in to change notification settings - Fork 7
/
smb3.asm
5002 lines (4045 loc) · 242 KB
/
smb3.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
.db "NES", $1a ;identification of the iNES header
.db 16 ;number of 16KB PRG-ROM pages
.db 16 ;number of 8KB CHR-ROM pages
.db $40|0 ;mapper 4 and mirroring
.dsb 9, $00 ;clear the remaining bytes
; Verifies:
; \$[0-9A-F][0-9A-F][0-9A-F][0-9A-F]
; Translators:
;
; Standard S&R on any address found via:
; [BJ].. \$[0-9A-F][0-9A-F][0-9A-F][0-9A-F]
;
; Then do the following for address label fixing:
; (^\s*.*\s*); (PRG005_[0-9A-F][0-9A-F][0-9A-F][0-9A-F]) --> \n\2:\n\1 (Labels from comment to beginning of line)
; ^(\s*[BJ].. PRG005_[0-9A-F][0-9A-F][0-9A-F][0-9A-F]).* --> \1\n (Formatting linebreak after B.. J..)
; \s*;.* --> (nothing) (Cleans off remaining address constants)
; Handy pseudo instructions... only make sense in the context of CMPing a number...
.macro BLT _1
BCC _1 ; A < CMP (unsigned)
.endm
.macro BGE _1
BCS _1 ; A >= CMP (unsigned)
.endm
.macro BLS _1
BMI _1 ; A < CMP (signed)
.endm
.macro BGS _1
BPL _1 ; A >= CMP (signed)
.endm
.macro NEG ; RegEx S&R "EOR #\$ff.*\n.*ADD #\$01" -> "NEG"
EOR #$ff
CLC
ADC #$01
.endm
.macro ABS_LDA _1
.byte $AD, <_1, $00
.endm
.macro ABS_LDA_X _1
.byte $BD, <_1, $00
.endm
.macro ABS_STA _1
.byte $8D, <_1, $00
.endm
.macro ABS_STA_X _1
.byte $9D, <_1, $00
.endm
.macro ABS_LDY _1
.byte $AC, <_1, $00
.endm
.macro ABS_LDY_X _1
.byte $BC, <_1, $00
.endm
.macro ABS_STY _1
.byte $8C, <_1, $00
.endm
.macro ABS_LDX _1
.byte $AE, <_1, $00
.endm
.macro ABS_STX _1
.byte $8E, <_1, $00
.endm
.macro ABS_SBC _1
.byte $ED, <_1, $00
.endm
.macro ABS_SBC_X _1
.byte $FD, <_1, $00
.endm
.macro ABS_ADC _1
.byte $6D, <_1, $00
.endm
.macro ABS_ADC_X _1
.byte $7D, <_1, $00
.endm
.macro ABS_INC _1
.byte $EE, <_1, $00
.endm
.macro ABS_INC_X _1
.byte $FE, <_1, $00
.endm
.macro ABS_ORA _1
.byte $0D, <_1, $00
.endm
; This is used in video update streams; since the video address register
; takes the address high-then-low (contrary to 6502's normal low-then-high),
; this allows a 16-bit value but "corrects" it to the proper endianness.
.macro DBYT _1
.byte (_1 & $FF00) >> 8
.byte (_1 & $00FF)
.endm
; These are flags related to a video update stream value
VU_VERT = $80 ; Update in vertical (+32B) mode instead of horizontal (+1B) mode
VU_REPEAT = $40 ; Repeat following value several times instead of several raw values
; Pads bytes to align to nearest 64 byte boundary for DMC samples
; SB: This would be useful for your own works, but I can't use
; it in the natively disassembly since the assembler pads zeroes
; instead of $FF values... just FYI!
;
; Usage example:
;
; .LabelPriorToDMC: DMCAlign .LabelPriorToDMC
.macro DMCAlign _1
.dsb ((_1 + $3F) & $FFC0) - _1
.endm
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; PPU I/O regs (CPU side)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; PPU_CTL1:
; 0-1: Name table address, changes between the four name tables at $2000 (0), $2400 (1), $2800 (2) and $2C00 (3).
; 2: Clear, PPU incs by 1 ("horizontal"); Set, PPU incs by 32 ("vertical")
; 3: Which pattern table holds for sprites; 0 for PT1 ($0000) or 1 for PT2 ($1000)
; 4: Which pattern table holds for BG; 0 for PT1 ($0000) or 1 for PT2 ($1000)
; 5: Set to use 8x16 sprites instead of 8x8
; 7: Set to generate VBlank NMIs
PPU_CTL1 = $2000 ; Write only
; PPU_CTL2:
; 0: Clear for color, set for mono
; 1: Clear to clip 8 left pixels of BG
; 2: Clear to clip 8 left pixels of sprites
; 3: If clear, BG hidden
; 4: If clear, sprites hidden
; 5-7: BG color in mono mode, "color intensity" in color mode (??)
PPU_CTL2 = $2001 ; Write only
; PPU_STAT:
; 4: if set, can write to VRAM, else writes ignored
; 5: if set, sprite overflow occurred on scanline
; 6: Set if any non-transparent pixel of sprite 0 is overlapping a non-transparent pixel of BG
; 7: VBlank is occurring (cleared after read)
PPU_STAT = $2002
; Sprites: 256 bytes, each sprite takes 4, so 64 sprites total
; Only 8 sprites per scanline, sprite 0 is drawn on top (thus highest priority)
; PPU_SPR_ADDR / PPU_SPR_DATA
; * Byte 0 - Stores the y-coordinate of the top left of the sprite minus 1.
; * Byte 1 - Index number of the sprite in the pattern tables.
; * Byte 2 - Stores the attributes of the sprite.
; * Bits 0-1 - Most significant two bits of the colour. (Or "palette" 0-3)
; * Bit 5 - Indicates whether this sprite has priority over the background.
; * Bit 6 - Indicates whether to flip the sprite horizontally.
; * Bit 7 - Indicates whether to flip the sprite vertically.
; * Byte 3 - X coordinate
PPU_SPR_ADDR = $2003 ; Set address sprite data
PPU_SPR_DATA = $2004 ; Read or write this sprite byte
PPU_SCROLL = $2005 ; Scroll register; read PPU_STAT, then write horiz/vert scroll
PPU_VRAM_ADDR = $2006 ; VRAM address (first write is high, next write is low)
PPU_VRAM_DATA = $2007 ; Data to read/write at this address
; Note that all transparent colors ($3F04, $3F08, $3F0C, $3F10, $3F14, $3F18 and $3F1C) are mirrored from 3F00
PPU_BG_PAL = $3F00 ; 3F00-3F0F
PPU_SPR_PAL = $3F10 ; 3F10-3F1F
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; SOUND I/O regs
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; $4000(rct1)/$4004(rct2)/$400C(noise) bits
; ---------------------------------------
; 0-3 volume / envelope decay rate
; 4 envelope decay disable
; 5 length counter clock disable / envelope decay looping enable
; 6-7 duty cycle type (unused on noise channel)
; Duty cycles:
; 00 = a weak, grainy tone. (12.5% Duty), 01 = a solid mid-strength tone. (25% Duty),
; 10 = a strong, full tone (50% Duty), 11 = sounds a lot like 01 (25% Duty negated)
PAPU_CTL1 = $4000 ; pAPU Pulse 1 Control Register.
PAPU_CTL2 = $4004 ; pAPU Pulse 2 Control Register.
PAPU_NCTL1 = $400C ; pAPU Noise Control Register 1.
; $4008(tri) bits
; ---------------
; 0-6 linear counter load register
; 7 length counter clock disable / linear counter start
PAPU_TCR1 = $4008 ; pAPU Triangle Control Register 1.
; $4001(rct1)/$4005(rct2) bits
; --------------------------
; 0-2 right shift amount
; 3 decrease / increase (1/0) wavelength
; 4-6 sweep update rate
; 7 sweep enable
PAPU_RAMP1 = $4001 ; pAPU Pulse 1 Ramp Control Register.
PAPU_RAMP2 = $4005 ; pAPU Pulse 2 Ramp Control Register.
; $4002(rct1)/$4006(rct2)/$400A(Tri) bits
; -------------------------------------
; 0-7 8 LSB of wavelength
PAPU_FT1 = $4002 ; pAPU Pulse 1 Fine Tune (FT) Register.
PAPU_FT2 = $4006 ; pAPU Pulse 2 Fine Tune (FT) Register.
PAPU_TFREQ1 = $400A ; pAPU Triangle Frequency Register 1.
; $400E(noise) bits
; -----------------
; 0-3 playback sample rate
; 4-6 unused
; 7 random number type generation
PAPU_NFREQ1 = $400E ; pAPU Noise Frequency Register 1.
; $4003(rct1)/$4007(rct2)/$400B(tri)/$400F(noise) bits
; --------------------------------------------------
; 0-2 3 MS bits of wavelength (unused on noise channel) (the "high" frequency)
; 3-7 length of tone
PAPU_CT1 = $4003 ; pAPU Pulse 1 Coarse Tune (CT) Register.
PAPU_CT2 = $4007 ; pAPU Pulse 2 Coarse Tune (CT) Register.
PAPU_TFREQ2 = $400B ; pAPU Triangle Frequency Register 2.
PAPU_NFREQ2 = $400F ; pAPU Noise Frequency Register 2.
; $4010 - DMC Play mode and DMA frequency
; Bits 0-3:
; f period
; ----------
; 0 $1AC
; 1 $17C
; 2 $154
; 3 $140
; 4 $11E
; 5 $0FE
; 6 $0E2
; 7 $0D6
; 8 $0BE
; 9 $0A0
; A $08E
; B $080
; C $06A
; D $054
; E $048
; F $036
; Bits 6-7: this is the playback mode.
; 00 - play DMC sample until length counter reaches 0 (see $4013)
; x1 - loop the DMC sample (x = immaterial)
; 10 - play DMC sample until length counter reaches 0, then generate a CPU
PAPU_MODCTL = $4010 ; pAPU Delta Modulation Control Register.
PAPU_MODDA = $4011 ; pAPU Delta Modulation D/A Register.
PAPU_MODADDR = $4012 ; pAPU Delta Modulation Address Register.
PAPU_MODLEN = $4013 ; pAPU Delta Modulation Data Length Register.
; read
; ----
; 0 rectangle wave channel 1 length counter status
; 1 rectangle wave channel 2 length counter status
; 2 triangle wave channel length counter status
; 3 noise channel length counter status
; 4 DMC is currently enabled (playing a stream of samples)
; 5 unknown
; 6 frame IRQ status (active when set)
; 7 DMC's IRQ status (active when set)
;
; write
; -----
; 0 rectangle wave channel 1 enable
; 1 rectangle wave channel 2 enable
; 2 triangle wave channel enable
; 3 noise channel enable
; 4 enable/disable DMC (1=start/continue playing a sample;0=stop playing)
; 5-7 unknown
PAPU_EN = $4015 ; R/W pAPU Sound Enable
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; OTHER I/O regs
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SPR_DMA = $4014 ; Sprite DMA Register -- DMA from CPU memory at $100 x n to SPR-RAM (256 bytes)
; Read / Write Joypad 1/2:
; * Bit 0 - Reads data from joypad or causes joypad strobe
; when writing.
; * Bit 3 - Indicates whether Zapper is pointing at a sprite.
; * Bit 4 - Cleared when Zapper trigger is released.
; Only bit 0 is involved in writing.
JOYPAD = $4016
; Frame counter control
; Changes the frame counter that changes updates on sound; any write resets
; the frame counter, good for synchronizing sound with VBlank etc.
; 0 4, 0,1,2,3, 0,1,2,3,..., etc.
; 1 0,1,2,3,4, 0,1,2,3,4,..., etc.
; bit 6 - enable frame IRQs (when zero)
; bit 7 - 0 = 60 IRQs a frame / 1 = 48 IRQs a frame (obviously need bit 6 clear to use)
; Interestingly, both of the above are clear on bootup, meaning IRQs are being generated,
; but the 6502 ignores NMIs on startup; also, need to read from $4015 (PAPU_EN) to acknowledge
; the interrupt, otherwise it holds the status on!
FRAMECTR_CTL = $4017
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; MMC3 regs
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; MMC3_COMMAND:
; Bits 0-2 - Command number:
; * 0 - Swap two 1 KB VROM banks at PPU $0000.
; * 1 - Swap two 1 KB VROM banks at PPU $0800.
; * 2 - Swap one 1 KB VROM bank at PPU $1000.
; * 3 - Swap one 1 KB VROM bank at PPU $1400.
; * 4 - Swap one 1 KB VROM bank at PPU $1800.
; * 5 - Swap one 1 KB VROM bank at PPU $1C00.
; * 6 - Swap PRG-ROM bank at either $8000 or $C000 based on bit 6.
; * 7 - Swap PRG-ROM bank at either $A000
;
; Bit 6 - If 0, enables swapping at $8000 and $A000, otherwise enables
; swapping at $C000 and $A000. (NOTE: This is what SMB3 uses, so we only
; have defs for this mode!)
;
; Bit 7 - If 1, causes addresses for commands 0-5 to be the exclusive-or
; of the address stated and $1000.
; Note that bit 6 is set on all of these consistently since SMB3 uses the PRG switch this way
MMC3_2K_TO_PPU_0000 = %01000000 ; 0
MMC3_2K_TO_PPU_0800 = %01000001 ; 1
MMC3_1K_TO_PPU_1000 = %01000010 ; 2
MMC3_1K_TO_PPU_1400 = %01000011 ; 3
MMC3_1K_TO_PPU_1800 = %01000100 ; 4
MMC3_1K_TO_PPU_1C00 = %01000101 ; 5
MMC3_8K_TO_PRG_C000 = %01000110 ; 6
MMC3_8K_TO_PRG_A000 = %01000111 ; 7
MMC3_PPU_XOR_1000 = %10000000
MMC3_COMMAND = $8000 ; consult ref
MMC3_PAGE = $8001 ; page number to MMC3_COMMAND
MMC3_MIRROR = $A000 ; bit 0 clear is horizontal mirroring, bit 0 set is vertical mirroring
MMC3_SRAM_EN = $A001 ; bit 7 set to enable SRAM at $6000-$7FFF
MMC3_IRQCNT = $C000 ; Countdown to an IRQ
MMC3_IRQLATCH = $C001 ; Store a temp val to be copied to MMC3_IRQCNT later
MMC3_IRQDISABLE = $E000 ; Disables IRQ generation and copies MMC3_IRQLATCH to MMC3_IRQCNT
MMC3_IRQENABLE = $E001 ; Enables IRQ generation
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; SMB3 RAM DEFS
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; (.*?)\s*=.*?;
; \t\1:\t\t.dsb 1\t;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ZERO PAGE RAM COMMON
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Common use zero page RAM. Bytes in $75-$F3 are context-dependent
.enum $00
; For clarification, none of the other "Temp" vars are damaged by NMI,
; the NMI does employ Temp_Var1-3, and restores them when it's done.
Temp_Var1: .dsb 1 ; Temporary storage variable (protected from damage by NMI)
Temp_Var2: .dsb 1 ; Temporary storage variable (protected from damage by NMI)
Temp_Var3: .dsb 1 ; Temporary storage variable (protected from damage by NMI)
Temp_Var4: .dsb 1 ; Temporary storage variable
Temp_Var5: .dsb 1 ; Temporary storage variable
Temp_Var6: .dsb 1 ; Temporary storage variable
Temp_Var7: .dsb 1 ; Temporary storage variable
Temp_Var8: .dsb 1 ; Temporary storage variable
Temp_Var9: .dsb 1 ; Temporary storage variable
Temp_Var10: .dsb 1 ; Temporary storage variable
Temp_Var11: .dsb 1 ; Temporary storage variable
Temp_Var12: .dsb 1 ; Temporary storage variable
Temp_Var13: .dsb 1 ; Temporary storage variable
Temp_Var14: .dsb 1 ; Temporary storage variable
Temp_Var15: .dsb 1 ; Temporary storage variable
Temp_Var16: .dsb 1 ; Temporary storage variable
VBlank_Tick: .dsb 1 ; can be used for timing, or knowing when an NMI just fired off
.dsb 1 ; $11 unused
Horz_Scroll_Hi: .dsb 1 ; Provides a "High" byte for horizontally scrolling, or could be phrased as "current screen"
PPU_CTL1_Mod: ; NOT DURING GAMEPLAY, this is used as an additional modifier to PPU_CTL1
Vert_Scroll_Hi: .dsb 1 ; Provides a "High" byte for vertically scrolling (only used during vertical levels!)
Level_ExitToMap: .dsb 1 ; When non-zero, kicks back to map (OR to event when Player_FallToKing or Player_RescuePrincess is nonzero!)
Counter_1: .dsb 1 ; This value simply increments every frame, used for timing various things
PPU_CTL2_Copy: .dsb 1 ; Essentially a copy of PPU_CTL2, which updates it as well, though the sprite/BG visibility setting is usually (always?) forced on
PAD_A = $80
PAD_B = $40
PAD_SELECT = $20
PAD_START = $10
PAD_UP = $08
PAD_DOWN = $04
PAD_LEFT = $02
PAD_RIGHT = $01
Pad_Holding: .dsb 1 ; Active player's inputs (i.e. 1P or 2P, whoever's playing) buttons being held in (continuous)
Pad_Input: .dsb 1 ; Active player's inputs (i.e. 1P or 2P, whoever's playing) buttons newly pressed only (one shot)
Roulette_RowIdx: .dsb 1 ; Roulette Bonus Game only obviously
; Pal_Force_Set12:
; This overrides the normal palette routine of selecting by Level_Tileset and
; loading the color sets PalSel_Tile_Colors/PalSel_Obj_Colors. Setting
; Pal_Force_Set12 to a non-zero value will select as the index instead of
; Level_Tileset, and then it will copy the first two sets of 16 colors from
; the palette data as bg / sprite colors. FIXME is this used though??
Pal_Force_Set12: .dsb 1
PlantInfest_ACnt: .dsb 1 ; Plant infestation level animation counter
VBlank_TickEn: .dsb 1 ; Enables the VBlank_Tick decrement and typically other things like joypad reading
Map_Enter2PFlag: .dsb 1 ; If $00, entering level, otherwise set if entering 2P VS mode
Map_EnterViaID: .dsb 1 ; Overrides whatever spot on the map you entered with something special (see Map_DoEnterViaID)
.dsb 1 ; $1F unused
; $20 has a lot of different uses on the World Map...
Map_EnterLevelFX: ; When entering a level on the map, dictates the status of the entry (0=None, 1=Boxing in, 2=Boxing out [J only]) NOTE: Overlap/reuse
Map_IntBoxErase: ; Used for determining where in erasing the "World X" intro box we are NOTE: Overlap/reuse
Map_ClearLevelFXCnt: ; Counter for "clear level" FX occurring (1-6: Poof, 7-9: Flip) ("poof"/"panel flip") NOTE: Overlap/reuse
Map_ScrollOddEven: .dsb 1 ; Toggles odd/even column as it scrolls
.dsb 1 ; $21 unused
Level_Width: .dsb 1 ; Width of current level, in screens (0 = don't move at all, max is 15H/16V)
; In horizontal "typical" levels, Scroll_ColumnR/L are a column and
; levels are rendered in vertical stripes by these start points
Scroll_ColumnR: .dsb 1 ; ($23) Current tile column (every 16px) of right side of screen (non-vertical level style ONLY)
Scroll_ColumnL: .dsb 1 ; ($24) Current tile column (every 16px) of left side of screen (non-vertical level style ONLY)
.base $23 ; NOTE, the following two are also $23/$24
; In vertical style levels, Scroll_VOffsetT/B are an offset into the
; visible tile grid, and levels are rendered in horizontal strips
Scroll_VOffsetT: .dsb 1 ; ($23) Current tile offset (every 16px) of top of screen (vertical level style ONLY)
Scroll_VOffsetB: .dsb 1 ; ($24) Current tile offset (every 16px) of bottom of screen (vertical level style ONLY)
Scroll_ColorStrip: .dsb 54 ; $25-$5A This stores a strip of just the upper 2 bits of a tile ($00, $40, $80, $C0) to produce attribute info
Scroll_LastDir: .dsb 1 ; 0=screen last moved right (or up, if vertical), 1=screen last moved left (or down, if vertical)
Scroll_RightUpd: ; Indicates every 8 pixels update going to the right, or $FF if screen moves left
Scroll_VertUpd: .dsb 1 ; Indicates every 8 pixels update up or down, in vertical levels
Scroll_LeftUpd: .dsb 1 ; Indicates every 8 pixels update going to the left, or $FF if screen moves right
; Prepares to perform a Video_Update when possible, indexes the "Video_Upd_Table"
; in PRG030 OR Video_Upd_Table2 in PRG025 (whichever is currently in context)
; Also resets the graphics buffer afterward, since the RAM buffer is
; constantly being called to possibly perform its own updates after this value
; resets to zero.
Graphics_Queue: .dsb 1
.dsb 1 ; $5F unused
.dsb 1 ; $60 unused
Level_LayPtr_AddrL: .dsb 1 ; Low byte of address to tile layout (ORIGINAL stored in Level_LayPtrOrig_AddrL)
Level_LayPtr_AddrH: .dsb 1 ; High byte of address to tile layout (ORIGINAL stored in Level_LayPtrOrig_AddrH)
; Typical use pair at $63/$64
Map_Tile_AddrL: .dsb 1 ; Low byte of tile address
Map_Tile_AddrH: .dsb 1 ; High byte of tile address
.base $63 ; NOTE, the following two are also $63/$64, bonus game context
BonusText_BaseL: .dsb 1 ; Instruction text base address low
BonusText_BaseH: .dsb 1 ; Instruction text base address high
Level_ObjPtr_AddrL: .dsb 1 ; Low byte of address to object set (ORIGINAL stored in Level_ObjPtrOrig_AddrL)
Level_ObjPtr_AddrH: .dsb 1 ; High byte of address to object set (ORIGINAL stored in Level_ObjPtrOrig_AddrH)
.dsb 1 ; $67 unused
.dsb 1 ; $68 unused
Video_Upd_AddrL: .dsb 1 ; Video_Misc_Updates routine uses this as an address, low byte
Video_Upd_AddrH: .dsb 1 ; Video_Misc_Updates routine uses this as an address, hi byte
Music_Base_L: .dsb 1 ; Current music segment base address low byte
Music_Base_H: .dsb 1 ; Current music segment base address high byte
Sound_Sqr_FreqL: .dsb 1 ; Calculated square wave frequency for Note On (low byte)
Sound_Sqr_FreqH: .dsb 1 ; Calculated square wave frequency for Note On (high byte)
Sound_Map_EntrV: .dsb 1 ; Current index into the volume ramp-down table used exclusively for the "level enter" sound
Sound_Map_EntV2: .dsb 1 ; Same as Sound_Map_EntrV, only for the second track
Music_PatchAdrL: .dsb 1 ; Music current patch address low byte
Music_PatchAdrH: .dsb 1 ; Music current patch address high byte
Sound_Map_Off: .dsb 1 ; Current "offset" within a map sound effect
.pad $74
; NOTE: $75 - $F3 are context specific; see contexts below
.base $F4
Scroll_OddEven: .dsb 1 ; 0 or 1, depending on what part of 8 pixels has crossed (need better description)
Controller1Press: .dsb 1 ; Player 1's controller "pressed this frame only" (see Controller1 for values)
Controller2Press: .dsb 1 ; Player 2's controller "pressed this frame only" (see Controller2 for values)
Controller1: .dsb 1 ; Player 1's controller inputs -- R01 L02 D04 U08 S10 E20 B40 A80
Controller2: .dsb 1 ; Player 2's controller inputs -- R01 L02 D04 U08 S10 E20 B40 A80
.dsb 1 ; $F9 unused
.dsb 1 ; $FA unused
.dsb 1 ; $FB unused
Vert_Scroll: .dsb 1 ; Vertical scroll of name table; typically at $EF (239, basically showing the bottom half)
Horz_Scroll: .dsb 1 ; Horizontal scroll of name table
.dsb 1 ; $FE unused
PPU_CTL1_Copy: .dsb 1 ; Holds PPU_CTL1 register data
.pad $100
; NOTE: CONTEXT -- Page 0 RAM changes meaning depending on the "context", i.e. what state
; of the game we're currently in! This means that variables are defined with overlapping
; addresses, and care must be taken to use the correct labels depending on the code!
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ZERO PAGE RAM: TITLE SCREEN / ENDING CONTEXT
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.base $75 ; $75-$F3 is available for this context-dependent situation
; Title screen "objects", which includes Mario, Luigi, and the assortment of other things
; The following are the offsets from any of the object arrays:
; 0 = Mario, 1 = Luigi, 2 = Starman, 3 = Mushroom, 4 = Super Leaf, 5 = Goomba, 6 = Buzzy Beatle, 7 = Koopa shell
; Note that some of this is used for the engine (especially in the Princess's chamber) but some of it is
; different (especially during the montage) so consider the overlapped variables in the next section
Title_XPosHi: .dsb 8 ; $75-$7C "High" part of the extended precision X position for all objects
Title_YPosHi: .dsb 8 ; $7D-$84 "High" part of the extended precision X position for all objects
Title_ObjX: .dsb 8 ; $85-$8C Title screen object X positions
Title_ObjY: .dsb 8 ; $8D-$94 Title screen object Y positions
Title_ObjXVel: .dsb 8 ; $95-$9C X velocities of title screen objects (4.4FP)
Title_ObjYVel: .dsb 8 ; $9D-$A3 Y velocities of title screen objects
Title_XPosFrac: .dsb 8 ; $A5-$AC X position extended precision of objects (provides 4-bit fixed point)
Title_YPosFrac: .dsb 8 ; $AD-$B4 Y position extended precision of objects (provides 4-bit fixed point)
Title_ObjYVelChng: .dsb 2 ; $B5-$B6 Mario / Luigi change in Y velocity flag
Title_ObjMLFlags: .dsb 2 ; $B7-$B8 Mario / Luigi Sprite flags
Title_ObjMLMoveDir: .dsb 1 ; 0 = No move, 1 = Left, 2 = Right
.dsb 1 ; $BA unused
Title_ObjMLAnimFrame: .dsb 2 ; $BB-$BC Mario / Luigi animation frame
Title_ObjMLDirTicks: .dsb 2 ; $BD-$BE Mario / Luigi animation ticks
Title_ObjMLSprite: .dsb 2 ; $BF-$C0 Mario / Luigi next sprite to display
Title_ObjMLPower: .dsb 2 ; $C1-$C2 Mario / Luigi current powerup (0 = Small, 1 = Big, 2 = Leaf)
Title_ObjMLSprRAMOff: .dsb 2 ; $C3-$C4 Mario / Luigi Defines a Sprite_RAM offset for Mario / Luigi
Title_ObjMLSprVis: .dsb 2 ; $C5-$C6 Mario / Luigi sprite sliver visibility bits (generated by Title_MLDetermineSpriteVis)
Title_ObjMLTailTick: .dsb 2 ; $C7-$C8 Mario / Luigi tail wagging tick
Title_ObjMLHold: .dsb 2 ; $C9-$CA Mario / Luigi holding something flag (when non-zero)
Title_ObjMLBonkTick: .dsb 2 ; $CB-$CC Mario / Luigi use "bonked" frame while > 0
Title_ObjMLKickTick: .dsb 2 ; $CD-$CE Mario / Luigi use kicking frame while > 0
Title_ObjMPowerDown: .dsb 1 ; Mario power down animation counter
Title_ObjMLStop: .dsb 1 ; Flag used briefly to "hold" Mario/Luigi from moving so they get a "running start"
Title_CurMLIndex: .dsb 1 ; 0 for Mario, 1 for Luigi
Title_ObjFlags: .dsb 6 ; $D2-$D7 Minor objects' sprite flags
Title_ObjStates: .dsb 6 ; $D8-$DD Title screen array of states for the individual objects (NOT including Mario/Luigi)
Title_State: .dsb 1 ; 00 = Prior to red curtain rise, 01 = Rising curtain...
Title_ResetCnt: .dsb 1 ; Title reset counter -- when on the menu, once this hits zero, the title sequence restarts
Title_ResetCnt2: .dsb 1 ; when this goes to zero, it decrements Title_ResetCnt
Title_ResetTrig: .dsb 1 ; when non-zero, resets title screen
Title_UnusedFlag: .dsb 1 ; doesn't seem to do anything useful but not do the "skip" state if Player presses START early on the title screen
Title_Ticker: .dsb 1 ; Tick counter for title screen intro "movie"
Title_MActScriptPos: .dsb 1 ; Offset within Mario's action script
Title_LActScriptPos: .dsb 1 ; Offset within Luigi's action script
Title_MActScriptDelay: .dsb 1 ; Mario's action script delay until next event
Title_LActScriptDelay: .dsb 1 ; Luigi's action script delay until next event
Title_MActScriptDirSet: .dsb 1 ; Mario's action script Buffer for last queue command (sets respective "Title_ObjMLDir" variable)
Title_LActScriptDirSet: .dsb 1 ; Luigi's action script Buffer for last queue command (sets respective "Title_ObjMLDir" variable)
Title_ObjMLDir: .dsb 2 ; $EA-$EB Mario / Luigi vector direction bitfield (1 = Left, 2 = Right, 4 = Down, 8 = Up, $10 = Sprite behind BG, $80 = Tail wagging)
Title_ObjMLQueue: .dsb 2 ; $EC-$ED Mario / Luigi queue to do something ($04 = Luigi's rebound off Mario, $10 = Kick shell, $20 = Begin carrying, $40 = Clear carry/bonk, do kick)
Title_EventIndex: .dsb 1 ; Title background event index (dynamic jump index for events on the title
Title_EventGrafX: .dsb 1 ; Title background current graphic index to load (loads items from Video_Upd_Table2 in PRG025)
Title_ObjInitIdx: .dsb 1 ; Current title screen "event" ID during the intro scene with Mario and Luigi
Title_ObjInitDly: .dsb 1 ; Timer count before next object init
Title_3GlowFlag: .dsb 1 ; When non-zero, begins the "glowing" effect for the big '3'
Title_3GlowIndex: .dsb 1 ; Index into an array of colors to cause the big '3' on the title screen to glow
.pad $F5
; Ending-specific vars -- NOTE that Ending system uses some of the Title Screen code, so these variables overlap some of the above
; Basically don't assume anything here is free space without consulting above as well...
.base $75
Ending2_PicState: .dsb 1 ; Ending part 2 picture loader state
Ending2_ClearLen: .dsb 1 ; Length of clear run
Ending2_ClearPat: .dsb 1 ; Pattern to clear the screen with
Ending2_PicVRAMH: .dsb 1 ; Ending part 2 picture VRAM Hi
Ending2_PicVRAML: .dsb 1 ; Ending part 2 picture VRAM Hi
Ending2_QCmdEnd: .dsb 1 ; Ending2_QueueCmd is incremented to this point
Ending2_FadeTimer: .dsb 1 ; Timer which controls the speed of the fade between worlds
Ending2_QueueCmd: .dsb 1 ; incremented after posting, up to Ending2_QCmdEnd
Ending2_TimerH: .dsb 1 ; Ending part 2 timer "high" part
Ending2_TimerL: .dsb 1 ; Ending part 2 timer "low" part
Ending2_CurWorld: .dsb 1 ; Current world we're showing (8 = THE END)
.base $D2
Ending_Timer: .dsb 2 ; $D2-$D3 Twin ending timers, generally one for Mario and one for Princess
EndText_Timer: .dsb 1 ; Timer used for the ending text display
Ending_State: .dsb 1 ; Current state value for initial part of ending (the princess, prior to curtain)
EndText_VL: .dsb 1 ; Princess speech VRAM Address Low
EndText_VH: .dsb 1 ; Princess speech VRAM Address High
EndText_CPos: .dsb 1 ; Princess speech Character Position
EndText_State: .dsb 1 ; Princess speech state variable
.base $F4
Ending2_IntCmd: .dsb 1 ; used during ending to buffer out the ending picture data on the interrupt. Triggers "Do_Ending2_IntCmd" in PRG024 in interrupt context.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ZERO PAGE RAM: WORLD MAP CONTEXT
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.base $75 ; $75-$F3 is available for this context-dependent situation
World_Map_Y: .dsb 2 ; $75-$76 (Mario/Luigi) Y pixel coordinate position of Mario on world map
World_Map_XHi: .dsb 2 ; $77-$78 (Mario/Luigi) X pixel (hi byte) coordinate position of Mario on world map
World_Map_X: .dsb 2 ; $79-$7A (Mario/Luigi) X pixel (lo byte) coordinate position of Mario on world map
World_Map_Move: .dsb 2 ; $7B-$7C (Mario/Luigi) Movement left in specified direction (even numbers only!)
World_Map_Dir: .dsb 2 ; $7D-$7E (Mario/Luigi) Specified travel direction (8=Up, 4=Down, 2=Left, 1=Right)
Map_UnusedPlayerVal: .dsb 2 ; $7F-$80 (Mario/Luigi) Set for each Player to $20 when returning to map, but apparently unused otherwise!
.dsb 1 ; $81 unused
.dsb 1 ; $82 unused
.dsb 1 ; $83 unused
Map_UnusedPlayerVal2: .dsb 2 ; $84-$85 (Mario/Luigi) Apparently unused at all, but backed up and persisted on the world map
; All the WarpWind vars are shared with the HandTrap; they share code, too...
Map_WWOrHT_Y: .dsb 1 ; Warp Whistle wind or Hand Trap Y position
Map_HandTrap_XHi: .dsb 1 ; Hand Trap X Hi (most vars are shared with warp wind, but technically not this one!)
Map_WWOrHT_X: .dsb 1 ; Warp Whistle wind or Hand Trap X position
Map_WWOrHT_Cnt: .dsb 1 ; Warp Whistle wind or Hand Trap counter
Map_WWOrHT_Dir: .dsb 1 ; Direction the Warp Whistle wind travels (0 = right, 1 = left)
; Double use
Map_WarpWind_FX: ; 1 - 4 is the warp whistle effect
Map_StarFX_State: .dsb 1 ; 0 - 2 NOTE: Shared with Map_WarpWind_FX
World_Map_Twirl: .dsb 1 ; If set, Mario is "twirling"
.dsb 1 ; $8D unused
; When Player is "skidding" backward (from death or "twirling" from game over continuation)
Map_Skid_DeltaY: .dsb 1 ; Delta applied directly to Y
Map_Skid_DeltaFracY: .dsb 1 ; Fractional delta Y
Map_Skid_FracY: .dsb 1 ; Fractional Y accumulator
.dsb 1 ; $91 unused
Map_Skid_DeltaX: .dsb 1 ; Delta applied directly to X
Map_Skid_DeltaFracX: .dsb 1 ; Fractional delta X
Map_Skid_FracX: .dsb 1 ; Fractional X accumulator
Map_Skid_FracCarry: .dsb 1 ; Fractional carry over accumulator (I think?)
Map_Skid_Count: .dsb 1 ; Just a ticker controlling the display frame of the twirl
Map_Skid_Counter: .dsb 1
; Map_Skid_TravDirs -- specifies which way Player must "twirl" to get to the destination
; Bit 0 Set = Player must travel to the right versus the left
; Bit 1 Set = Player must travel downward versus upward
Map_Skid_TravDirs: .dsb 1
.dsb 1 ; $99 unused
.dsb 1 ; $9A unused
Map_StarsX: .dsb 8 ; $9B-$A2 During World Intro, X position of each star
Map_StarsY: .dsb 8 ; $A3-$AA During World Intro, Y position of each star
Map_StarsOutRad: .dsb 1 ; During World Intro, stars take off radius (0 = smallest, increments for larger)
.dsb 1 ; $AC unused
.dsb 1 ; $AD unused
.dsb 1 ; $AE unused
Map_StarsXSteps: .dsb 1 ; During World Intro, number of "steps" remaining in the X position adjustment
Map_StarsRadCnt: .dsb 1 ; During World Intro, adds $70 per display frame and adds 1 to the radius when it overflows
Map_StarsCenterX: .dsb 1 ; During World Intro, X center of stars
Map_StarsCenterY: .dsb 1 ; During World Intro, Y center of stars
Map_StarsDeltaR: .dsb 1 ; During World Intro, delta to the star radii
Map_StarsConst9: .dsb 1 ; During World Intro, ... Constant 9?
.dsb 1 ; $B5 unused
Map_StarsAnimCnt: .dsb 1 ; During World Intro, a simple counter that adds 32 per frame and toggles Map_StarsFrame when it overflows
Map_StarsFrame: .dsb 1 ; During World Intro, "frame" of stars (0/1)
Map_StarsPattern: .dsb 1 ; During World Intro, stars current VROM pattern
Map_StarsLandRad: .dsb 1 ; During World Intro, stars landing radius (0 = largest, increments for smaller)
Map_StarsYSteps: .dsb 1 ; During World Intro, number of "steps" remaining in the Y position adjustment
.dsb 1 ; $BB unused
Map_StarsRadius: .dsb 8 ; $BC-$C3 During World Intro, each star's "radius" position (each radius position is 0-31)
Map_StarsState: .dsb 1 ; 0 = Stars coming out from center, 1 = Stars moving in towards Player start
Map_SkidBack: .dsb 1 ; Player is skidding back (Map_Player_SkidBack stores whether they skidded on their last turn at all)
.dsb 1 ; $C6 unused
Map_UnusedGOFlag: .dsb 1 ; Set at map initialization or if Player gets Game Over and selects CONTINUE/END, no apparent purpose
.dsb 1 ; $C8 unused
.dsb 1 ; $C9 unused
.dsb 1 ; $CA unused
.dsb 1 ; $CB unused
Map_Intro_CurStripe: .dsb 1 ; Current stripe of the "World X" intro box to be erased (0 - 7)
Map_Intro_NTOff: .dsb 1 ; Offset into nametable for erasing the "World X" intro box
Map_Intro_ATOff: .dsb 1 ; Offset into the attribute table for erasing the "World X" intro box
Map_Airship_DC: .dsb 1 ; set to 1 when the Airship knows where it's going
Map_Airship_DY: .dsb 1 ; Airship delta between current and target Y coordinate
Map_Airship_YNib: .dsb 1 ; Map_Airship_DY shifts out its lower 4 bits as upper 4 bits to this value
Map_Airship_YAcc: .dsb 1 ; Additional Y accumulator when traveling
Map_Airship_DXHi: .dsb 1 ; Airship delta between current and target X Hi coordinate
Map_Airship_DX: .dsb 1 ; Airship delta between current and target X coordinate
Map_Airship_XNib: .dsb 1 ; Map_Airship_DXHi/Map_Airship_DX shifts out its lower 4 bits as upper 4 bits to this value
Map_Airship_Dir: .dsb 1 ; Airship horizontal travel direction in bit 0, vertical direction in bit 1
Map_HideObj: .dsb 1 ; used for completion)
MapPoof_Y: .dsb 1 ; When using a power-up, "poof" appears at this Y coordinate
MapPoof_X: .dsb 1 ; When using a power-up, "poof" appears at this X coordinate
Map_UseItem: .dsb 1 ; Flag to signal that item is to be used
.dsb 10 ; $DB-$E4 unused
World_Map_Tile: .dsb 1 ; Current tile index Mario is standing on
.dsb 1 ; $E6 unused
.dsb 1 ; $E7 unused
.dsb 1 ; $E8 unused
Scroll_Temp: .dsb 1 ; Scroll hold value
.dsb 1 ; $EA unused
.dsb 1 ; $EB unused
Player_WalkFrame: .dsb 1 ; relative, not the same as Player_Frame
.dsb 7 ; $ED-$F3 unused
.pad $F4
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ZERO PAGE RAM: BONUS GAME CONTEXT (see PRG022 for lots more info)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.base $75 ; $75-$F3 is available for this context-dependent situation
.dsb 22 ; $75-$8A unused
BonusCoins_State: .dsb 1
.dsb 59 ; $8C-$C6 unused
BonusDie_Y: .dsb 1 ; UNUSED Bonus Game Die (1-6) Y position
BonusDie_X: .dsb 1 ; UNUSED Bonus Game Die (1-6) X position
BonusDie_YVel: .dsb 1 ; UNUSED Bonus Game Die Y Velocity (when it departs)
BonusDie_YVelFrac: .dsb 1 ; UNUSED Bonus Game Die Y Velocity fractional accumulator
.dsb 41 ; $CB-$F3 unused
.pad $F4
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ZERO PAGE RAM: 2P VS CONTEXT
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.base $75 ; $75-$F3 is available for this context-dependent situation
Vs_State: .dsb 1 ; 2P Vs Mode state
Vs_IsPaused: .dsb 1 ; If set, 2P Vs is paused
.dsb 125 ; $77-$F3 unused
.pad $F4
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ZERO PAGE RAM: GAMEPLAY CONTEXT
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.base $75 ; $75-$F3 is available for this context-dependent situation
; There's a consistent difference of $12 between X and Y; this consistent distancing is meant to be maintained, so leave it alone!
Player_XHi: .dsb 1 ; Player X Hi
Objects_XHi: .dsb 8 ; $76-$7D Other object's X Hi positions
.dsb 1 ; $7E unused
; Reuse of $7F
CineKing_DialogState: ; Toad & King Cinematic: When 1, we're doing the text versus the dialog box itself
; NOTE!! This object var is OBJECT SLOT 0 - 4 ONLY!
Objects_Var4: .dsb 5 ; $7F-$83 Generic variable 4 for objects SLOT 0 - 4 ONLY
; Pipe_PlayerX/Y variables in use when traveling through pipes
Pipe_PlayerX: .dsb 1 ; Stores Player's X when they went into pipe (non-transit)
Pipe_PlayerY: .dsb 1 ; Stores Player's Y when they went into pipe (non-transit, aligned to nearest 16, minus 1)
.base $84 ; NOTE, the following two are also $84/$85
; Otherwise, they are replaced with a lookup address
Level_GndLUT_Addr: .dsb 2
.dsb 1 ; $86 unused
Player_YHi: .dsb 1 ; Player Y Hi
Objects_YHi: .dsb 8 ; $88-$8F Other object's Y Hi positions
Player_X: .dsb 1 ; Player X
Objects_X: .dsb 8 ; $91-$98 Other object's X positions
.dsb 1 ; $99 unused
; Reuse of $9A
CineKing_Var: ; General variable
Objects_Var5: .dsb 8 ; $9A-$A1 Generic variable 5 for objects
Player_Y: .dsb 1 ; Player Y
Objects_Y: .dsb 8 ; $A3-$A9 Other object's Y positions
Player_SpriteX: .dsb 1 ; Player's sprite X
Objects_SpriteX: .dsb 8 ; $AC-$B3 Other object's sprite X positions
Player_SpriteY: .dsb 1 ; Player's sprite Y
Objects_SpriteY: .dsb 8 ; $B5-$BC Other object's sprite Y positions
; WARNING: The distance between Player/Objects_XVel and Player/Objects_YVel must be same as Player/Objects_X/YVelFrac!
Player_XVel: .dsb 1 ; Player's X Velocity (negative values to the left) (max value is $38)
Objects_XVel: .dsb 8 ; $BE-$C5 Other object's X velocities
Objects_VarBSS: .dsb 7 ; $C6-$CC OBJECT SLOTS 0 - 5 ONLY ... uncleared var??
SlotIndexBackup: .dsb 1 ; Used as a backup for the slot index (e.g. current object, current score, etc.)
Player_HaltGame: .dsb 1 ; Player is halting game (e.g. dying, shrinking/growing, etc.)
; WARNING: The distance between Player/Objects_XVel and Player/Objects_YVel must be same as Player/Objects_X/YVelFrac!
Player_YVel: .dsb 1 ; Player's Y Velocity (negative values upward)
Objects_YVel: .dsb 8 ; $D0-$D7 Other object's Y velocities
Player_InAir: .dsb 1 ; When set, Player is in the air
; Reuse of $D9
CineKing_Frame2: ; Used only by the World 6 King (Seal juggling a crown, the crown's frame)
; Objects_DetStat:
; Object's detection bits:
; $01-hit wall right
; $02-hit wall left
; $04-hit ground
; $08-hit ceiling
; $80-object touching "32 pixel partition" floor (if active)
Objects_DetStat: .dsb 8 ; $D9-$E0 on screen
Player_SprWorkL: .dsb 1 ; Sprite work address low
Player_SprWorkH: .dsb 1 ; Sprite work address high
.dsb 1 ; $E3 unused
Level_TileOff: .dsb 1 ; Tile mem offset
Level_Tile: .dsb 1 ; Temporary holding point for a detected tile index
Player_Slopes: .dsb 3 ; for sloped levels only (3 bytes allocated, but only one actually used)
; *NOTE: Code at PRG030_9EDB clears Player_Slopes+1 and Player_Slopes+2, but these are never used!
.dsb 1 ; $E9 unused
.dsb 1 ; $EA unused
Player_XStart: .dsb 1 ; Set to Player's original starting X position (also used to check if level has initialized)
.dsb 1 ; $EC unused
; Player_Suit -- Player's active powerup (see also: Player_QueueSuit)
PLAYERSUIT_SMALL = 0
PLAYERSUIT_BIG = 1
PLAYERSUIT_FIRE = 2
PLAYERSUIT_RACCOON = 3
PLAYERSUIT_FROG = 4
PLAYERSUIT_TANOOKI = 5
PLAYERSUIT_HAMMER = 6
PLAYERSUIT_SUPERSUITBEGIN = PLAYERSUIT_FROG ; Marker for when "Super Suits" begin
PLAYERSUIT_LAST = PLAYERSUIT_HAMMER ; Marker for "last" suit (Debug cycler needs it)
Player_Suit: .dsb 1
Player_Frame: .dsb 1 ; Player display frame
Player_FlipBits: .dsb 1 ; Set to $00 for Player to face left, Set to $40 for Player to face right
Player_WagCount: .dsb 1 ; after wagging raccoon tail, until this hits zero, holding 'A' keeps your fall rate low
Player_IsDying: .dsb 1 ; 0 = Not dying, 1 = Dying, 2 = Dropped off screen, 3 = Death due to TIME UP
.dsb 1 ; $F2 unused
Obj01_Flag: .dsb 1 ; Not sure what Obj01 is!! This blocks its left/right handler logic.
.pad $F4
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; $1xx LOW STACK VARIABLES
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; These are actually "bottom" of the stack; I don't think this is normally recommended.
; but this is probably to keep them "safe" from other RAM clearing routines, since they directly effect the IRQ.
; The debug flag in particular is pretty precariously placed, and under some kind of heavy call stack, seems like
; there's risk it could be set by accident... but I guess this never happens... ?
.base $0100
Update_Select: .dsb 1 ; Changes which path of "update routines" are selected; $00 = ??, $20 = Title Screen, $40 = Spade Game, $80 = Vertical level, $A0 = 32 pixel partition, $C0 = Normal
Raster_Effect: .dsb 1 ; $00 is standard status bar, $20 is title/ending, $40 = 32 pixel partition, $60 = Spade Bonus Game (3 sliding rows), $80 is nothing (e.g. as in 2P versus), $A0 = ???
.base $0160
Debug_Flag: .dsb 1 ; Set to $80 by the debug menu, enables debug functionality like power level cycling and not dying from time over
; Main NES SRAM begin
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; $2xx SPRITE RAM
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.base $0200
; \$02([0-9A-F][0-9A-F])
; Sprite_RAM+$\1
; Sprite memory is laid out in four bytes:
; Byte 0 - Stores the y-coordinate of the top left of the sprite minus 1.
; Byte 1 - Index number of the sprite in the pattern tables.
; Byte 2 - Stores the attributes of the sprite.
; * Bits 0-1 - Most significant two bits of the colour.
; * Bit 5 - Indicates whether this sprite has priority over the background.
; * Bit 6 - Indicates whether to flip the sprite horizontally.
; * Bit 7 - Indicates whether to flip the sprite vertically.
; Byte 3 - X coordinate
Sprite_RAM: .dsb 256 ; $0200 - $02FF; This is where sprite memory is stored locally prior to being DMA'ed
; Relevant flags
SPR_PAL0 = %00000000
SPR_PAL1 = %00000001
SPR_PAL2 = %00000010
SPR_PAL3 = %00000011
SPR_BEHINDBG = %00100000
SPR_HFLIP = %01000000
SPR_VFLIP = %10000000
.pad $0300
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; $03xx RAM (Largely graphics updating / control)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.base $0300
Graphics_BufCnt: .dsb 1 ; first byte holds current position within buffer (Graphics_Buffer+) to store info
Graphics_Buffer: .dsb 107 ; $0301-$036B Simple (and small!) delayed write buffer; uses same format as Video_Upd_Table in PRG030, get format info there
TileChng_VRAM_H: .dsb 1 ; High part of VRAM address to change
TileChng_VRAM_L: .dsb 1 ; Low part of VRAM address to change
TileChng_Pats: .dsb 4 ; $036E-$0371 The four patterns required to change a tile (for Level_ChgTileEvent)
Level_SizeOrig: .dsb 1 ; Holds original size (width or height) of level (in screens)
Level_PipeExitDir: .dsb 1 ; Direction Player is going to exit from a pipe (1 = Up, 2 = Down, 3 = Right, 4 = Left, 5 = In-level Transit)
Level_7VertCopy: .dsb 1 ; Just seems to be an unmaintained copy of Level_7Vertical from level load, but that's it
Level_PipeNotExit: .dsb 1 ; If set, pipes do NOT exit to map (i.e. as in pipe junctions)
Level_PauseFlag: .dsb 1 ; Set to 0 when not paused, or 1 when paused
Level_SkipStatusBarUpd: .dsb 1 ; When set, skips updating the status bar for one frame (priority graphics buffer changes I think)
Raster_State: .dsb 1 ; This variable's meaning depends on the Raster_Effect in use; typically 0 is first pass, then more for further scanlines
.dsb 7 ; $0379-$037F unused
Scroll_ToVRAMHi: .dsb 1 ; High byte for when pushing a column of tile data to VRAM (Set to $20, Name Table 0, after scroll update)
; $381 dual use
Scroll_LastCol8: ; Last 8x8 block column that was updated (non-vertical level ONLY)
Scroll_LastOff8: .dsb 1 ; Last 8x8 block offset that was updated (vertical level style ONLY)