📄 qsnesdoc.html
字号:
VRAM, it would have to be stored like this:
<PRE>Offset Y-coord. Tile Coord
0 0-7 (0, 0) (8, 0) (16, 0) (24, 0) <Unused--room for 12 more tiles>
512 8-15 (0, 8) (8, 8) (16, 8) (24, 8) <Unused--room for 12 more tiles>
1024 16-23 (0,16) (8,16) (16,16) (24,16) <Unused--room for 12 more tiles>
1536 24-31 (0,24) (8,24) (16,24) (24,24) <Unused></PRE>
In practice, the sprites are interleaved. In other words, when using
32x32 tiles, there would be 3 more sprites stored in that "unused" space.
If the first sprite, shown in the above table, started at offset 0, the
next sprite would start at offset 128 (the <A HREF="#SpriteBasics_CharNum">Character
Number</A>, in <A HREF="#PPUMemoryTypes">OAM</A>, would be 4); the third
sprite would start at offset 256 (Character #8), and the fourth sprite
would start at offset 384 (Character #12). If a fifth sprite was
desired, the pattern would repeat and it would be located at offset 2048
(Character #64).
<P>Similarly, when using 16x16 sprites, there will be 8 sprites interleaved,
and the ninth sprite will have to start after them at offset 1024.
Finally, 64x64 sprites have only two sprites interleaved. It is also
possible to format it such that larger sprites can be interleaved with
smaller sprites, but that is somewhat confusing to try to explain.
<P>In OAM there are two tables which control the position, size, mirroring,
palette, and priority of sprites. This table has room for 128 entries;
thus, the SNES can display up to 128 sprites on the screen at once (although
I think a real SNES will overload and screw up its display when there are
too many large sprites.) The first table has four bytes per sprite,
and is formatted like this:
<PRE>Byte 1 xxxxxxxx x: X coordinate
Byte 2 yyyyyyyy y: Y coordinate
Byte 3 cccccccc c: starting character (tile) number p: palette number
Byte 4 vhoopppc v: vertical flip h: horizontal flip o: priority bits
Note: the 'c' in byte 4 is the MOST significant bit in the 9-bit char #.</PRE>
The second table is 32 bytes and has 2 bits for each sprite (each byte
contains information for 4 sprites.) The lowest significant bits
hold the information for the lower object numbers (for example, the least
significant two bits of the first byte are for object #0.) Bit 0
(and 2, 4, 6) is the size toggle bit (see bits 5-7 of <A HREF="#Reg2101">register
$2101</A>) and bit 1 (3, 5, 7) is the most ignificant bit of the X coordinate.
<P>The vertical and horizontal flips work similarly to flips in the BGs;
the entire sprite is flipped so that the leftmost pixel is swapped with
the rightmost pixel, etc. To see the effect of the priority bits,
see the description of <A HREF="#Reg2105">register $2105</A>. The
palettes start at CG entry 128, so that palette 0 is colors 128 to 143,
and palette 1 consists of colors 144 to 159.
<P><A NAME="SpriteBasics_CharNum"></A>The character number indexes into
an array of 8x8 tiles starting at a base VRAM location selected by bits
0-2 of <A HREF="#Reg2101">register $2101</A>. The byte address in VRAM
where the character data starts can be found using the following calculation:
<BR> address_of_character = (base_location_bits <<
14) + (32 * character_number);
<BR>For example, if base location 1 is selected, and character number 1
is selected, the address will be 16384+32*1 = 16416. Note that the
word address entered into the <A HREF="#Reg2116">VRAM address register</A>
will be half of that, or 8208.
<P>Notice that two or more sprites in the OAM table may have the same character
number; if this is the case, they will look the same except that they can
be mirrored independently and have different palettes.
<P><A NAME="ColorPalettes"></A><FONT SIZE=+1>Color palettes</FONT>
<P>Once the final color value is derived from the character data and 'palette
number' for the sprite or <A HREF="#Terminology">BG</A>, it is indexed
into the <A HREF="#PPUMemoryTypes">CGRAM</A> color palette array.
There are 512 bytes of CGRAM, with each of the 256 colors using two bytes.
Each of the palette entries is formatted like this:
<PRE>?bbbbbgg gggrrrrr ?: Unused and ignored b: Blue intensity
g: Green intensity r: Red intensity</PRE>
(Notice this is backwards to the conventional RGB format.) To upload
palette entries to CGRAM, select the color with register $2121, and then
begin sending the bytes to <A HREF="#Reg2122">register $2122</A>.
<BR>
<CENTER><A NAME="GraphicsFormat"></A><FONT SIZE=+3>The SNES Graphics Format</FONT></CENTER>
<P>All SNES graphics (except in <A HREF="#Terminology">BG</A>1 of Mode
7) are made up of <A HREF="#Terminology">Tiles</A>, also called character
data. The basic tile is 8x8 in size, and larger bitmaps are stored
in the form of two-dimensional arrays of these small tiles. On most
computers, bitmaps are stored in a packed format: the color bits are grouped
together in the same byte (or word, or dword, for high-color displays.)
However, SNES graphics are planar; that is, the each of the color bits
are stored separately. Each color plane of the tile is stored like
this:
<PRE>byte 0: top scanline 01234567
byte 2: 01234567 right
byte 4: left 01234567 side
byte 6: side 01234567 of
byte 8: of 01234567 tile
byte 10: tile 01234567
byte 12: 01234567 Note that left/right and top/bottom can
byte 14: bottom scanline 01234567 be reversed using the BG/sprite flip bits.</PRE>
Planes 0 and 1 are stored first, followed by planes 2 and 3, etc.
As you can see, the bytes in each plane are two bytes apart; the byte "in
between" is the following plane. In other words, byte 0 stores the
first eight pixels of plane 0 and byte 1 stores the first eight pixels
of plane 1. If using more than 4 colors, the pattern repeats; byte
16 stores the first eight pixels of plane 2 and byte 17 stores the first
eight pixels of plane 3.
<P>When the tile is to be displayed on the screen, a bit is taken from
each of the planes to form a 2-, 4-, or 8-bit value to index into the <A HREF="#ColorPalettes">color
palette</A>. The first tile (plane 0) contains the least significant
bit of the color, and the last tile contains the most significant bit.
<P><A NAME="Mode7GrFormat"></A><FONT SIZE=+1>Mode 7 Graphics Representation</FONT>
<P>In Mode 7, both the tile map and the tiles themselves are stored differently.
In fact, the tile data and the graphic data are interleaved. The
first byte (low byte) is an element of the tile map, and the second byte
(high byte) is the color value of a pixel.
<PRE> First Byte Second Byte
Bits 7 6 5 4 3 2 1 0 15 14 13 12 11 10 9 8
Contains Tile Number Graphics data</PRE>
The Mode 7 screen data occupies all of the first 32 KB of VRAM: 16K is
for graphics data, and 16K is for the tile numbers. The tile map
format is simply the tile number with no other information, and takes one
byte. The dimensions of the tile map are 128x128 (=16384 bytes).
Unlike all other screen modes, the graphics data is a packed, linear format
and each color value directly indexes into CGRAM. The tiles are still
8x8 pixels, and thus take 64 bytes per tile. There are 256 characters
in total. The calculation to find which character to display is simply
64 * Tile_Number.
<P>A variation of Mode 7, EXTBG (see bit 6 of register $2133), cuts the
colors down to 128 and uses the most significant color bit as a priority
bit.
<CENTER><A NAME="RegisterReference"></A><FONT SIZE=+3>Register Reference</FONT></CENTER>
<P>This section may not be quite accurate. Please tell me if you
find an error. W means writeable; R means readable. 2b means
the register is one word in size; Db means that it is a one-byte
register that must be written or read twice. In contrast to the Y0shi
Doc, auto-incrementing registers such as <A HREF="#Reg2122">$2122</A> are
not considered Db registers, because they can be written any number of
times (writing one byte will work just as well as writing two, or writing
a hundred.)
<P>Can anyone tell me what is supposed to happen when you read from a write
register?
<CENTER> </CENTER>
<CENTER><A NAME="RegOAM"></A><FONT SIZE=+2>OAM Registers</FONT></CENTER>
<P><A NAME="Reg2101"></A><B><FONT FACE="Lucida Console">Register $2101:
OAM Size (1b/W)</FONT></B>
<PRE>sssnnbbb s: Object size n: name selection b: base selection
Size bit in OAM table: 0 1
Bits of object size: 000 8x8 16x16
001 8x8 32x32
010 8x8 64x64
011 16x16 32x32
100 16x16 64x64
101 32x32 64x64
110,111 Unknown behavior</PRE>
This register selects the location in VRAM where the character data is
stored, and the size of sprites on the screen. The byte location
of the character data can be found by shifting the b (base selection) bits
left by 14. Note that this allows only four different locations in
VRAM to put the sprite data; the high bit of the base selection should
always be zero since only 64K of VRAM can be addressed.
<P>I have no information on the name selection bits.
<P><A NAME="Reg2102"></A><B><FONT FACE="Lucida Console">Register $2102/$2103:
Address for accessing OAM (2b/W)</FONT></B>
<PRE>aaaaaaaa r??????m a: low byte of OAM address
r: OAM priority rotation m: OAM address MSB</PRE>
This register selects the byte location to begin uploading (or downloading)
data to OAM.
<P>I'm sorta guessing, but I think that the priority rotation thing is
applied by SNES games to keep sprites on the screen. That is, when
there are too many sprites on the screen at once I believe the SNES will
turn certain sprites off in order to reduce the load on the PPU.
So I think the SNES takes the "a" bits, shifts them right one and the result
is which sprite to re-activate. In the process another sprite gets
turned off. Another possibility is that it doesn't matter what address
you select, it simply picks any sprite that is off and turns it on, perhaps
simultaneously turning off a sprite that has been on for a while.
<P><A NAME="Reg2104"></A><B><FONT FACE="Lucida Console">Register $2104:
Data write to OAM (1b/W)</FONT></B>
<PRE>dddddddd d: byte to write to VRAM</PRE>
This register writes a byte to OAM. After the byte is stored, the
OAM address is incremented so that the next write or read will be to the
following address.
<P><A NAME="Reg2138"></A><B><FONT FACE="Lucida Console">Register $2138:
Data read from OAM (1b/R)</FONT></B>
<PRE>dddddddd d: byte that was read from OAM</PRE>
After the byte is read, the OAM address is incremented so that the next
write or read will be to the following byte.
<CENTER> </CENTER>
<CENTER><A NAME="RegColor"></A><FONT SIZE=+2>Color Registers</FONT></CENTER>
<P><A NAME="Reg2121"></A><B><FONT FACE="Lucida Console">Register $2121:
Address for accessing CGRAM (1b/W)</FONT></B>
<PRE>aaaaaaaa a: CGRAM word address</PRE>
This register selects the word location (byte address * 2) to begin
uploading (or downloading) data to CGRAM. Click <A HREF="#ColorPalettes">HERE</A>
for more information on color palettes.
<P><A NAME="Reg2122"></A><B><FONT FACE="Lucida Console">Register $2122:
Data write to CGRAM (1b/W)</FONT></B>
<PRE>dddddddd d: byte to write to CGRAM</PRE>
This register writes a byte to CGRAM. After the byte is stored, the
CGRAM address is incremented so that the next write or read will be to
the following byte.
<P><A NAME="Reg213B"></A><B><FONT FACE="Lucida Console">Register $213B:
Data read from CGRAM (1b/R)</FONT></B>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -