-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathAnomie_regs.log
2892 lines (2151 loc) · 118 KB
/
Anomie_regs.log
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
=============================================================================
Anomie's Register Doc
$Revision: 1157 $
$Date: 2007-07-12 16:39:41 -0400 (Thu, 12 Jul 2007) $
=============================================================================
REGISTERS
=========
Addr rw?fvha Name
bits
Explanation
"Addr" is the address this register is mapped into the SNES memory space.
"Name" is the official and unofficial name of the register
"bits" is either 8 or 16 characters explicating the bitfields in this register.
The flags are:
rw?fvha
||||||+--> '+' if it can be read/written at any time, '-' otherwise
|||||+---> '+' if it can be read/written during H-Blank
||||+----> '+' if it can be read/written during V-Blank
|||+-----> '+' if it can be read/written during force-blank
||+------> Read/Write style: 'b' => byte
|| 'h'/'l' => read/write high/low byte of a word
|| 'w' => word read/write twice (low then high)
|+-------> 'w' if the register is writable for an effect
+--------> 'r' if the register is readable for a value or effect (i.e. not
open bus).
To find the entry for a particular register, search for the register number
(i.e. '2100') at the very beginning of the line. Note that the DMA registers
are combined, so e.g. to find $4300, $4310, $4320, $4330, $4340, $4350, $4360,
or $4370 you'd search for '43x0'.
For most registers (and most undefined bits of readable registers), the
returned value is Open Bus, that is the last value read over the main bus from
the ROM (typically part of the opcode arguments or the indirect base address).
Registers matching $21x4-6 or $21x8-A (where x is 0-2) return the last value
read from any of the PPU1 registers $2134-6, $2138-A, or $213E. This is known
as PPU1 Open Bus. Similarly, PPU2 Open Bus involves reading registers $213B-D
or $213F (NOT $21xB-D though).
Note that it may be possible to write registers anytime even if marked '-', but
until we have proof '-' is a better guess.
--------------------------------------------------------------------------------
rw?fvha
2100 -+b++++ INIDISP - Screen Display
x---bbbb
x = Force blank on when set.
bbbb = Screen brightness, F=max, 0="off".
Note that force blank CAN be disabled mid-scanline. However, this can
result in glitched graphics on that scanline, as the internal rendering
buffers will not have been updated during force blank. Current theory
is that BGs will be glitched for a few tiles (depending on how far in
advance the PPU operates), and OBJ will be glitched for the entire
scanline.
Also, writing this register on the first line of V-Blank (225 or 240,
depending on overscan) when force blank is currently active causes the
OAM Address Reset to occur.
--------------------------------------------------------------------------------
rw?fvha
2101 -+b++?- OBJSEL - Object Size and Chr Address
sssnnbbb
sss = Object size:
000 = 8x8 and 16x16 sprites
001 = 8x8 and 32x32 sprites
010 = 8x8 and 64x64 sprites
011 = 16x16 and 32x32 sprites
100 = 16x16 and 64x64 sprites
101 = 32x32 and 64x64 sprites
110 = 16x32 and 32x64 sprites ('undocumented')
111 = 16x32 and 32x32 sprites ('undocumented')
nn = Name Select
bbb = Name Base Select ( Word Addr >> 13, Byte Addr >> 14)
See the section "SPRITES" below for details.
--------------------------------------------------------------------------------
rw?fvha
2102 -+l++?- OAMADDL - OAM Address low byte
2103 -+h++?- OAMADDH - OAM Address high bit and Obj Priority
p------b aaaaaaaa
p = Obj Priority activation bit
When this bit is set, an Obj other than Sprite 0 may be given
priority. See the section "SPRITES" below for details.
b aaaaaaaa = OAM address
This can be thought of in two ways, depending on your conception of
OAM. If you consider OAM as a 544-byte table, baaaaaaaa is the word
address into that table. If you consider OAM to be a 512-byte table
and a 32-byte table, b is the table selector and aaaaaaaa is the
word address in the table. See the section "SPRITES" below for
details.
The internal OAM address is invalidated when scanlines are being
rendered. This invalidation is deterministic, but we do not know how
it is determined. Thus, the last value written to these registers is
reloaded into the internal OAM address at the beginning of V-Blank if
that occurs outside of a force-blank period. This is known as 'OAM
reset'. 'OAM reset' also occurs on certain writes to $2100.
Writing to either $2102 or $2103 resets the entire internal OAM Address
to the values last written to this register. E.g., if you set $104 to
this register, write 4 bytes, then write $1 to $2103, the internal OAM
address will point to word 4, not word 6.
--------------------------------------------------------------------------------
rw?fvha
2104 -+b++-- OAMDATA - Data for OAM write
dddddddd
Note that OAM writes are done in an odd manner, in particular
the low table of OAM is not affected until the high byte of a
word is written (however, the high table is affected
immediately). Thus, if you set the address, then alternate writes and
reads, OAM will never be affected until you reach the high table!
Similarly, if you set the address to 0, then write 1, 2, read, then
write 3, OAM will end up as "01 02 01 03", rather than "01 02 xx 03" as
you might expect.
Technically, this register CAN be written during H-blank (and probably
mid-scanline as well). However, due to OAM address invalidation the
actual OAM byte written will probably not be what you expect. Note that
writing during force-blank will only work as expected if that
force-blank was begun during V-Blank, or (probably) if $2102/3 have
been reset during that force-blank period.
See the section "SPRITES" below for details.
--------------------------------------------------------------------------------
rw?fvha
2105 -+b+++- BGMODE - BG Mode and Character Size
DCBAemmm
A/B/C/D = BG character size for BG1/BG2/BG3/BG4
If the bit is set, then the BG is made of 16x16 tiles. Otherwise,
8x8 tiles are used. However, note that Modes 5 and 6 always use
16-pixel wide tiles, and Mode 7 always uses 8x8 tiles. See the
section "BACKGROUNDS" below for details.
mmm = BG Mode
e = Mode 1 BG3 priority bit
Mode BG depth OPT Priorities
1 2 3 4 Front -> Back
-=-------=-=-=-=----=---============---
0 2 2 2 2 n 3AB2ab1CD0cd
1 4 4 2 n 3AB2ab1C 0c
* if e set: C3AB2ab1 0c
2 4 4 y 3A 2B 1a 0b
3 8 4 n 3A 2B 1a 0b
4 8 2 y 3A 2B 1a 0b
5 4 2 n 3A 2B 1a 0b
6 4 y 3A 2 1a 0
7 8 n 3 2 1a 0
7+EXTBG 8 7 n 3 2B 1a 0b
"OPT" means "Offset-per-tile mode". For the priorities, numbers
mean sprites with that priority. Letters correspond to BGs (A=1,
B=2, etc), with upper/lower case indicating tile priority 1/0. See
the section "BACKGROUNDS" below for details.
Mode 7's EXTBG mode allows you to enable BG2, which uses the same
tilemap and character data as BG1 but interprets bit 7 of the pixel
data as a priority bit. BG2 also has some oddness to do with some
of the per-BG registers below. See the Mode 7 section under
BACKGROUNDS for details.
--------------------------------------------------------------------------------
rw?fvha
2106 -+b+++- MOSAIC - Screen Pixelation
xxxxDCBA
A/B/C/D = Affect BG1/BG2/BG3/BG4
xxxx = pixel size, 0=1x1, F=16x16
The mosaic filter goes over the BG and covers each x-by-x square
with the upper-left pixel of that square, with the top of the first
row of squares on the 'starting scanline'. If this register is set
during the frame, the 'starting scanline' is the current scanline,
otherwise it is the first visible scanline of the frame. I.e. if
even scanlines are completely red and odd scanlines are completely
blue, setting the xxxx=1 mid-frame will make the rest of the screen
either completely red or completely blue depending on whether you
set xxxx on an even or an odd scanline.
XXX: It seems that writing the same value to this register does not
reset the 'starting scanline', but which changes do reset it?
Note that mosaic is applied after scrolling, but before any clip
windows, color windows, or math. So the XxX block can be partially
clipped, and it can be mathed as normal with a non-mosaiced BG. But
scrolling can't make it partially one color and partially another.
Modes 5-6 should 'double' the expansion factor to expand
half-pixels. This actually makes xxxx=0 have a visible effect,
since the even half-pixels (usually on the subscreen) hide the odd
half-pixels. The same thing happens vertically with interlace mode.
Mode 7, of course, is weird. BG1 mosaics about like normal, as long
as you remember that the Mode 7 transformations have no effect on
the XxX blocks. BG2 uses bit A to control 'vertical mosaic' and bit
B to control 'horizontal mosaic', so you could be expanding over
1xX, Xx1, or XxX blocks. This can get really interesting as BG1
still uses bit A as normal, so you could have the BG1 pixels
expanded XxX with high-priority BG2 pixels expanded 1xX on top of
them.
See the section "BACKGROUNDS" below for details.
--------------------------------------------------------------------------------
rw?fvha
2107 -+b+++- BG1SC - BG1 Tilemap Address and Size
2108 -+b+++- BG2SC - BG2 Tilemap Address and Size
2109 -+b+++- BG3SC - BG3 Tilemap Address and Size
210a -+b+++- BG4SC - BG4 Tilemap Address and Size
aaaaaayx
aaaaaa = Tilemap address in VRAM (Word Addr >> 10, Byte Addr >> 11)
x = Tilemap horizontal mirroring
y = Tilemap veritcal mirroring
All tilemaps are 32x32 tiles. If x and y are both unset, there is
one tilemap at Addr. If x is set, a second tilemap follows the
first that should be considered "to the right of" the first. If y
is set, a second tilemap follows the first that should be
considered "below" the first. If both are set, then a second
follows "to the right", then a third "below", and a fourth "below
and to the right".
See the section "BACKGROUNDS" below for more details.
MoN Note: I changed the "writable during H-Blank" from '?' to '+' due to
the same behavior observed both on a real system and in bsnes.
How the change affects the PPU exactly is something the hardware experts should investigate.
I might try designing an HDMA sequence to toy with this. It may already be known that this
is writeable, as bsnes seems to replicate it well, though i don't know if it's a perfect copy.
That is, whether the value written only takes effect during the next frame or during the
current one.
--------------------------------------------------------------------------------
rw?fvha
210b -+b++?- BG12NBA - BG1 and 2 Chr Address
210c -+b++?- BG34NBA - BG3 and 4 Chr Address
"NBA" stands for "Name Base Address"
bbbbaaaa
aaaa = Base address for BG1/3 (Word Addr >> 12, Byte Addr >> 13)
bbbb = Base address for BG2/4 (Word Addr >> 12, Byte Addr >> 13)
MoN Note: It's interesting that these provide the capability to address
farther than the amount of available VRAM (64K in two 32K chips).
Since VRAM is word addressed, perhaps the designers of the PPU
anticipated being able to use two 64K VRAM chips instead. It's just a
thought. Perhaps word addresses $0000-$7fff were originally intended to
be for tilemaps, and the CHR data would have had the added perk of
being able to reside anywhere.
See the section "BACKGROUNDS" below for details.
--------------------------------------------------------------------------------
rw?fvha
210d -+w+++- BG1HOFS - BG1 Horizontal Scroll
-+w+++- M7HOFS - Mode 7 BG Horizontal Scroll
210e -+w+++- BG1VOFS - BG1 Vertical Scroll
-+w+++- M7VOFS - Mode 7 BG Vertical Scroll
------xx xxxxxxxx
---mmmmm mmmmmmmm
x = The BG offset, 10 bits.
m = The Mode 7 BG offset, 13 bits two's-complement signed.
These are actually two registers in one (or would that be "4 registers
in 2"?). Anyway, writing $210d will write both BG1HOFS which works
exactly like the rest of the BGnxOFS registers below ($210f-$2114), and
M7HOFS which works with the M7* registers ($211b-$2120) instead.
Modes 0-6 use BG1xOFS and ignore M7xOFS, while Mode 7 uses M7xOFS and
ignores BG1HOFS. See the appropriate sections below for details, and
note the different formulas for BG1HOFS versus M7HOFS.
--------------------------------------------------------------------------------
rw?fvha
210f -+w+++- BG2HOFS - BG2 Horizontal Scroll
2110 -+w+++- BG2VOFS - BG2 Vertical Scroll
2111 -+w+++- BG3HOFS - BG3 Horizontal Scroll
2112 -+w+++- BG3VOFS - BG3 Vertical Scroll
2113 -+w+++- BG4HOFS - BG4 Horizontal Scroll
2114 -+w+++- BG4VOFS - BG4 Vertical Scroll
------xx xxxxxxxx
Note that these are "write twice" registers, first the low byte is
written then the high. Current theory is that writes to the register
work like this:
BGnHOFS = (Current<<8) | (Prev&~7) | ((Reg>>8)&7);
Prev = Current;
or
BGnVOFS = (Current<<8) | Prev;
Prev = Current;
Note that there is only one Prev shared by all the BGnxOFS registers.
This is NOT shared with the M7* registers (not even M7xOFS and
BG1xOFS).
x = The BG offset, at most 10 bits (some modes effectively use as few
as 8).
Note that all BGs wrap if you try to go past their edges. Thus, the
maximum offset value in BG Modes 0-6 is 1023, since you have at most 64
tiles (if x/y of BGnSC is set) of 16 pixels each (if the appropriate
bit of BGMODE is set).
Horizontal scrolling scrolls in units of full pixels no matter if we're
rendering a 256-pixel wide screen or a 512-half-pixel wide screen.
However, vertical scrolling will move in half-line increments if
interlace mode is active.
See the section "BACKGROUNDS" below for details.
--------------------------------------------------------------------------------
rw?fvha
2115 -+b++?- VMAINC - Video Port Control
Register name hint: "Video Memory Address Increment"
i---mmjj
i = Address increment mode:
0 => increment after writing $2118/reading $2139
1 => increment after writing $2119/reading $213a
Note that a word write stores low first, then high. Thus, if you're
storing a word value to $2118/9, you'll probably want to set 1
here.
j = Address increment amount. It is expressed in number of words to
increment by (as opposed to by byte.)
00 - Normal increment by 1
01 - Increment by 32
Useful for reading / writing a normal tilemap
when one would like to have the target address
move to the next row upon increment.
10 - Increment by 128
Useful for reading / writing a mode 7 tilemap
when one would like to have the target address
move to the next row upon increment.
11 - Increment by 128
(Note: Same as address increment amount '10' above)
m = Address remapping
00 - Normal
No remapping
01 - 2bpp Full Graphic Mode
Remap addressing aaaaaaaa BBBccccc => aaaaaaaa cccccBBB
10 - 4bpp Full Graphic Mode
Remap addressing aaaaaaaB BBcccccc => aaaaaaac cccccBBB
11 - 8bpp Full Graphic Mode
Remap addressing aaaaaaBB Bccccccc => aaaaaacc cccccBBB
The "remap" modes basically implement address translation. If
$2116/7 are set to 0x0003, then word address 0x0018 will be written
instead, and $2116/7 will be incremented to 0x0004.
What is the point of this? If for some reason a programmer decides
that they want all of the bitplanes for a horizontal row of pixels
stored sequentially, these remapping modes should be used. Remapping
seems to be soley intended for writing CHR data. There doesn't,
however seem to be any point to using it for Mode 7 CHR, as it is
stored quite differently.
Example: A 2bpp variable width font buffer is being generated row
by row. Bitplanes 0 and 1 for the first row of the first tile are
stored as the first word in the buffer. Then, bitplanes 0 and 1 for
the first row of the second tile, all the way up to the 31st
tile. The next 64 bytes would consist of the bitplane 0 and 1 data
for the second rows of each of the tiles. By the time the BBB bits
have filled up and overflowed, we should be ready to draw the next
row of 32 tiles in vram.
To reemphasize, this is catering to programmers that would prefer
to store their source graphics in a different manner than is
typical. It would not seem that is a superior or inferior mechanism,
it's just different. Though, it may make variable width font
generation slightly easier if it is deemed necessary to generate it
vertically, line by line.
--------------------------------------------------------------------------------
rw?fvha
2116 -+l++?- VMADDL - VRAM Address low byte
2117 -+h++?- VMADDH - VRAM Address high byte
aaaaaaaa aaaaaaaa
This sets the address for $2118/9 and $2139/a. Note that this is a word
address, not a byte address!
See the sections "BACKGROUNDS" and "SPRITES" below for details.
--------------------------------------------------------------------------------
rw?fvha
2118 -+l++-- VMDATAL - VRAM Data Write low byte
2119 -+h++-- VMDATAH - VRAM Data Write high byte
xxxxxxxx xxxxxxxx
This writes data to VRAM. The writes take effect immediately(?), even
if no increment is performed. The address is incremented when one of
the two bytes is written; which one depends on the setting of bit 7 of
register $2115. Keep in mind the address translation bits of $2115 as
well.
The interaction between these registers and $2139/a is unknown.
See the sections "BACKGROUNDS" and "SPRITES" below for details.
--------------------------------------------------------------------------------
rw?fvha
211a -+b++?- M7SEL - Mode 7 Settings
rc----yx
r = Playing field size: When clear, the playing field is 1024x1024
pixels (so the tilemap completely fills it). When set, the playing
field is much larger, and the 'empty space' fill is controlled by
bit 6.
c = Empty space fill, when bit 7 is set:
0 = Transparent.
1 = Fill with character 0. Note that the fill is matrix
transformed like all other Mode 7 tiles.
x/y = Horizontal/Vertical mirroring. If the bit is set, flip the
256x256 pixel 'screen' in that direction.
See the section "BACKGROUNDS" below for details.
--------------------------------------------------------------------------------
rw?fvha
211b -+w+++- M7A - Mode 7 Matrix A (also used with $2134/6)
211c -+w+++- M7B - Mode 7 Matrix B (also used with $2134/6)
211d -+w+++- M7C - Mode 7 Matrix C
211e -+w+++- M7D - Mode 7 Matrix D
aaaaaaaa aaaaaaaa
Note that these are "write twice" registers, first the low byte is
written then the high. Current theory is that writes to the register
work like this:
Reg = (Current<<8) | Prev;
Prev = Current;
Note that there is only one Prev shared by all these registers. This
Prev is NOT shared with the BGnxOFS registers, but it IS shared with
the M7xOFS registers.
These set the matrix parameters for Mode 7. The values are an 8-bit
fixed point, i.e. the value should be divided by 256.0 when used in
calculations. See below for more explanation.
The product A*(B>>8) may be read from registers $2134/6. There is
supposedly no important delay. It may not be operative during Mode 7
rendering.
See the section "BACKGROUNDS" below for details.
--------------------------------------------------------------------------------
rw?fvha
211f -+w+++- M7X - Mode 7 Center X
2120 -+w+++- M7Y - Mode 7 Center Y
---xxxxx xxxxxxxx
Note that these are "write twice" registers, like the other M7*
registers. See above for the write semantics. The value is 13 bit
two's-complement signed.
The matrix transformation formula is:
[ X ] [ A B ] [ SX + M7HOFS - CX ] [ CX ]
[ ] = [ ] * [ ] + [ ]
[ Y ] [ C D ] [ SY + M7VOFS - CY ] [ CY ]
Note: SX/SY are screen coordinates. X/Y are coordinates in the playing
field from which the pixel is taken. If $211a bit 7 is clear, the
result is then restricted to 0<=X<=1023 and 0<=Y<=1023. If $211a bits 6
and 7 are both set and X or Y is less than 0 or greater than 1023, use
the low 3 bits of each to choose the pixel from character 0.
The bit-accurate formula seems to be something along the lines of:
#define CLIP(a) (((a)&0x2000)?((a)|~0x3ff):((a)&0x3ff))
X[0,y] = ((A*CLIP(HOFS-CX))&~63)
+ ((B*y)&~63) + ((B*CLIP(VOFS-CY))&~63)
+ (CX<<8)
Y[0,y] = ((C*CLIP(HOFS-CX))&~63)
+ ((D*y)&~63) + ((D*CLIP(VOFS-CY))&~63)
+ (CY<<8)
X[x,y] = X[x-1,y] + A
Y[x,y] = Y[x-1,y] + C
(In all cases, X[] and Y[] are fixed point with 8 bits of fraction)
See the section "BACKGROUNDS" below for details.
--------------------------------------------------------------------------------
rw?fvha
2121 -+b+++- CGADD - CGRAM Address
cccccccc
This sets the word address (i.e. color) which will be affected by $2122
and $213b.
--------------------------------------------------------------------------------
rw?fvha
2122 -+w+++- CGDATA - CGRAM Data write
-bbbbbgg gggrrrrr
This writes to CGRAM, effectively setting the palette colors.
Accesses to CGRAM are handled just like accesses to the low table of
OAM, see $2104 for details.
Note that the color values are stored in BGR order.
--------------------------------------------------------------------------------
rw?fvha
2123 -+b+++- W12SEL - Window Mask Settings for BG1 and BG2
2124 -+b+++- W34SEL - Window Mask Settings for BG3 and BG4
2125 -+b+++- WOBJSEL - Window Mask Settings for OBJ and Color Window
ABCDabcd
c = Enable window 1 for BG1/BG3/OBJ
a = Enable window 2 for BG1/BG3/OBJ
C = Enable window 1 for BG2/BG4/Color
A = Enable window 2 for BG2/BG4/Color
When the bit is set, the corresponding window will affect the
corresponding background (subject to the settings of $212e/f).
d = Window 1 Inversion for BG1/BG3/OBJ
b = Window 2 Inversion for BG1/BG3/OBJ
D = Window 1 Inversion for BG2/BG4/Color
B = Window 2 Inversion for BG2/BG4/Color
When the bit is set, "W" should be replaced by "~W" (not-W) in the
window combination formulae below.
See the section "WINDOWS" below for more details.
--------------------------------------------------------------------------------
rw?fvha
2126 -+b+++- WH0 - Window 1 Left Position
2127 -+b+++- WH1 - Window 1 Right Position
2128 -+b+++- WH2 - Window 2 Left Position
2129 -+b+++- WH3 - Window 2 Right Position
xxxxxxxx
These set the offset of the appropriate edge of the appropriate window.
Note that if the left edge is greater than the right edge, the window
is considered to have no range at all (and thus "W" always is false).
See the section "WINDOWS" below for more details.
--------------------------------------------------------------------------------
rw?fvha
212a -+b+++- WBGLOG - Window mask logic for BGs
212b -+b+++- WOBJLOG - Window mask logic for OBJs and Color Window
44332211 [WBGLOG]
----ccoo [WOBJLOG]
44/33/22/11/oo/cc = Mask logic for BG1/BG2/BG3/BG4/OBJ/Color
This specified the window combination method, using standard
boolean operators:
00 = OR
01 = AND
10 = XOR
11 = XNOR
Consider two variables, W1 and W2, which are true for pixels
between the appropriate left and right bounds as set in
$2126-$2129 and false otherwise. Then, you have the following
possibilities: (replace "W#" with "~W#", depending on the Inversion
settings of $2123-$2125)
Neither window enabled => nothing masked.
One window enabled => Either W1 or W2, as appropriate.
Both windows enabled => W1 op W2, where "op" is as above.
Where the function is true, the BG will be masked.
See the section "WINDOWS" below for more details.
--------------------------------------------------------------------------------
rw?fvha
212c -+b+++- TM - Main Screen Designation
212d -+b+++- TS - Subscreen Designation
---o4321
1/2/3/4/o = Enable BG1/BG2/BG3/BG4/OBJ for display
on the main (or sub) screen.
See the section "BACKGROUNDS" below for details.
--------------------------------------------------------------------------------
rw?fvha
212e -+b+++- TMW - Window Mask Designation for the Main Screen
212f -+b+++- TSW - Window Mask Designation for the Subscreen
---o4321
1/2/3/4/o = Enable window masking for BG1/BG2/BG3/BG4/OBJ on the
main (or sub) screen.
See the section "BACKGROUNDS" below for details.
--------------------------------------------------------------------------------
rw?fvha
2130 -+b+++- CGWSEL - Color Addition Select
ccmm--sd
cc = Clip colors to black before math
00 => Never
01 => Outside Color Window only
10 => Inside Color Window only
11 => Always
mm = Prevent color math
00 => Never
01 => Outside Color Window only
10 => Inside Color Window only
11 => Always
s = Add subscreen (instead of fixed color)
d = Direct color mode for 256-color BGs
See the sections "BACKGROUNDS", "WINDOWS", and "RENDERING THE
SCREEN" below for details.
--------------------------------------------------------------------------------
rw?fvha
2131 -+b+++- CGADSUB - Color math designation
shbo4321
s = Add/subtract select
0 => Add the colors
1 => Subtract the colors
h = Half color math. When set, the result of the color math is
divided by 2 (except when $2130 bit 1 is set and the fixed color is
used, or when color is clipped).
Note from MoN: that part about bit 1 in 2130 seems... contradictory.
4/3/2/1/o/b = Enable color math on BG1/BG2/BG3/BG4/OBJ/Backdrop
See the sections "BACKGROUNDS", "WINDOWS", and "RENDERING THE
SCREEN" below for details.
--------------------------------------------------------------------------------
rw?fvha
2132 -+b+++- COLDATA - Fixed Color Data
bgrccccc
b/g/r = Which color plane(s) to set the intensity for.
ccccc = Color intensity.
So basically, to set an orange you'd do something along the lines of:
LDA #$3f
STA $2132
LDA #$4f
STA $2132
LDA #$80
STA $2132
See the sections "BACKGROUNDS" and "WINDOWS" below for details.
--------------------------------------------------------------------------------
rw?fvha
2133 -+b+++- SETINI - Screen Mode/Video Select
se--poIi
s = "External Sync". Used for superimposing "sfx" graphics, whatever
that means. Usually 0. Not much is known about this bit.
Interestingly, the SPPU1 chip has a pin named "EXTSYNC" (or
not-EXTSYNC, since it has a bar over it) which is tied to Vcc.
e = Mode 7 EXTBG ("Extra BG"). When this bit is set, you may enable
BG2 on Mode 7. BG2 uses the same tile and character data as BG1,
but interprets the high bit of the color data as a priority for the
pixel.
Various sources report additional effects for this bit, possibly
related to bit 7. For example, "Enable the Data Supplied From the
External Lsi.", whatever that means. Of course, maybe that's a
typo and it's supposed to apply to bit 7 instead.
p = Enable pseudo-hires mode. This creates a 512-pixel horizontal
resolution by taking pixels from the subscreen for the
even-numbered pixels (zero based) and from the main screen for the
odd-numbered pixels. Color math behaves just as with Mode 5/6
hires. The interlace bit still has no effect. Mosaic operates as
normal (not like Mode 5/6). The 'subscreen' pixel is clipped (by
windows) when the main-screen pixel to the LEFT is clipped, not
when the one to the RIGHT is clipped as you'd expect. What happens
with pixel column 0 is unknown.
Enabling this bit in Modes 5 or 6 has no effect.
o = Overscan mode. When set, 239 lines will be displayed instead of
the normal 224. This also means V-Blank will occur that
much later, and be shorter. All that happens is that extra lines
get added to the display, and it seems the TV will like to move
the display up 8 pixels. See below for more details.
I = OBJ Interlace. When set regardless of BG mode, the OBJ will be
interlaced (see bit 0 below), and thus will appear half-height.
Note that this only controls whether obj are drawn as normal or
not; the interlace signal is only output to the TV based on bit 0
below.
i = Screen interlace. When set in BG mode 5 (and probably 6), the
effective screen height will be 448 (or 478) pixels, rather than
224 (or 239). When set in any other mode, the screen will just get
a bit jumpy. However, toggling the tilemap each field would
simulate the increased screen height (much like pseudo-hires
simulates hires).
In hardware, setting this bit makes the SNES output a normal
interlace signal rather than always forcing one frame.
See the sections "BACKGROUNDS" and "SPRITES" below for details.
Overscan: The bit only matters at the very end of the frame, if you
change the setting on line 0xE0 before the normal NMI trigger point
then it's the same as if you had it on all frame. Note that this
affects both the NMI trigger point and when HDMA stops for the
frame.
If you turn the bit off at the very beginning of scanline X (for
0xE1<=X<=0xF0), NMI will occur on line X and the last HDMA transfer
will occur on line X-1. However, on my TV at least, the display will
remain in the normal no-overscan position for lines E1-EC, it will
move up only one pixel for line ED, and it will lose vertical sync
for lines EF-F4!
Turning the bit on, only line E1 gives any effect: NMI will occur on
line E2, although the last HDMA will still occur on line E0.
Anything else acts like you left the bit off the whole time. Note,
however, that if you wait too long after the beginning of the
scanline then you will get no effect.
Even if there is no visible effect, the overscan setting still
affects VRAM writes. In particular, executing "LDA #'-' / STA $2118
/ LDA r2133 / STA $2133 / LDA #'+' / STA $2118" during the E1-F0
period will write only + or only - to VRAM, depending on whether the
overscan bit was set to 0 or 1.
--------------------------------------------------------------------------------
rw?fvha
2134 +-l+++? MPYL - Multiplication Result low byte
2135 +-m+++? MPYM - Multiplication Result middle byte
2136 +-h+++? MPYH - Multiplication Result high byte
xxxxxxxx xxxxxxxx xxxxxxxx
This is the 2's compliment product of the 16-bit value written to $211b
and the 8-bit value most recently written to $211c. There is supposedly
no important delay. It may not be operative during Mode 7 rendering.
--------------------------------------------------------------------------------
rw?fvha
2137 --b++++ SLHV - Software Latch for H/V Counter
--------
When read, the H/V counter (as read from $213c and $213d) will be
latched to the current X and Y position if bit 7 of $4201 is set. The
data actually read is open bus.
--------------------------------------------------------------------------------
rw?fvha
2138 +-w++?- OAMDATAREAD* - Data for OAM read
xxxxxxxx
OAM reads are straightforward: the current byte as set in $2102/3 and
incremented by reads from this register and writes to $2104 will be
returned. Note that writes to the lower table are not affected so
logically. See register $2104 and the section "SPRITES" below for
details.
Also, note that OAM address invalidation probably affects the address
read by this register as well.
--------------------------------------------------------------------------------
rw?fvha
2139 +-l++?- VMDATALREAD* - VRAM Data Read low byte
213a +-h++?- VMDATAHREAD* - VRAM Data Read high byte
xxxxxxxx xxxxxxxx
Simply, this reads data from VRAM. The address is incremented when
either $2139 or $213a is read, depending on the setting of bit 7 of
$2115.
Actually, the reading is more complex. When either of these registers
is read, the appropriate byte from a word-sized buffer is returned. A
word from VRAM is loaded into this buffer just *before* the VRAM
address is incremented. The actual data read and the amount of the
increment depend on the low 4 bits of $2115. The effect of this is
that a 'dummy read' is required after setting $2116-7 before you start
getting the actual data.
The interaction between these registers and $2118/9 is unknown.
See the sections "BACKGROUNDS" and "SPRITES" below for details.
--------------------------------------------------------------------------------
rw?fvha
213b +-w++?- CGDATAREAD* - CGRAM Data read
-bbbbbgg gggrrrrr
This reads from CGRAM.
Accesses to CGRAM are handled just like accesses to the low table of
OAM, see $2138 for details.
Note that the color values are stored in BGR order. The '-' bit is PPU2
Open Bus.
--------------------------------------------------------------------------------
rw?fvha
213c +-w++++ OPHCT - Horizontal Scanline Location
213d +-w++++ OPVCT - Vertical Scanline Location
-------x xxxxxxxx
These values are latched by reading $2137 when bit 7 of $4201 is set,
or by clearing-and-setting bit 7 of $4201 either by writing $4201 or by
pin 6 of Controller Port 2 (the latch occurs on the 1->0 transition).
Note that the value read is only 9 bits: bits 1-7 of the high byte are
PPU2 Open Bus. Each register keeps seperate track of whether to
return the low or high byte. The high/low selector is reset to 'low'
when $213f is read (the selector is NOT reset when the counter is
latched).
H Counter values range from 0 to 339, with 22-277 being visible on the
screen. V Counter values range from 0 to 261 in NTSC mode (262 is
possible every other frame when interlace is active) and 0 to 311 in
PAL mode (312 in interlace?), with 1-224 (or 1-239(?) if overscan is
enabled) visible on the screen.
--------------------------------------------------------------------------------
rw?fvha
213e +-b++++ STAT77 - PPU Status Flag and Version
trm-vvvv
t = Time Over Flag. If more than 34 sprite-tiles (e.g. a 16x16
sprite has 2 sprite-tiles) were encountered on a single line, this
flag will be set. The flag is reset at the end of V-Blank. See the
section "SPRITES" below for details.
r = Range Over Flag. If more than 32 sprites were encountered on a
single line, this flag will be set. The flag is reset at the end of
V-Blank. See the section "SPRITES" below for details.
Note that the above two flags are set whether or not OBJ are
actually enabled at the time.
m = "Master/slave mode select". Little is known about this bit.
Current theory is that it indicates the status of the "MASTER" pin
on the S-PPU1 chip, which in the normal SNES is always Gnd. We
always seem to read back 0 here.
vvvv = 5c77 chip version number. So far, we've only encountered version
1.
The '-' bit is PPU1 Open Bus.
--------------------------------------------------------------------------------
rw?fvha
213f +-b++++ STAT78 - PPU Status Flag and Version
fl-pvvvv
f = Interlace Field. This will toggle every V-Blank.
l = External latch flag. When the PPU counters are latched, this
flag gets set. The flag is reset on read, but only when $4201 bit 7
is set.
p = NTSC/Pal Mode. If this is a PAL SNES, this bit will be set,
otherwise it will be clear.
vvvv = 5C78 chip version number. So far, we've encountered at least 2
and 3. Possibly 1 as well.
The '-' bit is PPU2 Open Bus.
Note: as a side effect of reading this register, the high/low byte
selector for $213c/d is reset to 'low'.
--------------------------------------------------------------------------------
rw?fvha
2140 ++b++++ APUIO0 - APU I/O register 0
2141 ++b++++ APUIO1 - APU I/O register 1