851 lines
32 KiB
Plaintext
851 lines
32 KiB
Plaintext
|
|
SNES hardware notes
|
|
by Charles MacDonald
|
|
WWW: http://cgfm2.emuviews.com
|
|
|
|
Unpublished work Copyright 2003 Charles MacDonald
|
|
|
|
This document is in a very preliminary state and is subject to change.
|
|
Most everything within has been tested and verified on a SNES but
|
|
please be aware that my testing methods or interpretations of results
|
|
could be flawed. I can't guarantee that everything is 100% accurate.
|
|
|
|
Last updated 09/17/03
|
|
|
|
[09/17/03]
|
|
- Added the cartridge information section.
|
|
- Added some details on the screen layout.
|
|
|
|
[08/27/03]
|
|
- Fixed some typos
|
|
- Added CGRAM information
|
|
- Added notes about valid times to access OAM
|
|
|
|
[08/25/03]
|
|
- Added some sprite information
|
|
|
|
[08/22/03]
|
|
- Added mouse information
|
|
- Added multitap information
|
|
- Changed joypad section
|
|
|
|
[08/20/03]
|
|
- Initial release
|
|
|
|
Table of contents
|
|
|
|
1. Various notes
|
|
2. CGRAM
|
|
3. Sprites
|
|
3. Hardware version registers
|
|
4. I/O hardware
|
|
5. Register reference
|
|
6. Cartridge information
|
|
7. Assistance needed
|
|
8. Credits and acknowledgements
|
|
9. Disclaimer
|
|
|
|
----------------------------------------------------------------------------
|
|
Various notes
|
|
----------------------------------------------------------------------------
|
|
|
|
V-Blank occurance flag
|
|
|
|
- Bit 7 of $4212 is set at line $00E1 and cleared at line $0000 in 224-line
|
|
mode.
|
|
|
|
- Bit 7 of $4212 is set at line $00F0 and cleared at line $0000 in 239-line
|
|
mode.
|
|
|
|
Joypad automatic scanning flag
|
|
|
|
- Bit 0 of $4212 is set at line $00E1 and cleared at line $00E4 in 224-line
|
|
mode.
|
|
|
|
- Bit 0 of $4212 is set at line $00F0 and cleared at line $00F3 in 239-line
|
|
mode.
|
|
|
|
Non-maskable interrupts
|
|
|
|
According to the 65816 manual, the NMI signal is an edge-sensitive input,
|
|
so that only a high to low transition on the NMI pin will cause an interrupt
|
|
to occur. Leaving it high, low, or having a low to high transition has no
|
|
effect. I'm going to assume the PPU normally holds NMI high and brings it
|
|
low to trigger an interrupt.
|
|
|
|
The PPU will pull NMI low at line $00E8 in 224-line mode or line $00F7 in
|
|
239-line mode. It will remain low until either $4210 is read, or a new
|
|
frame starts, at which point the PPU will bring NMI high again.
|
|
|
|
The inverted state of the NMI signal from the PPU can be read through bit 7
|
|
of $4210, where 0= no NMI has been requested, 1= an NMI is pending. After
|
|
reading this register, the PPU resets the NMI signal by pulling it high.
|
|
|
|
Bit 7 of $4200 doesn't affect how the PPU manages NMIs at all, it is just
|
|
a gate between the NMI output of the PPU and the NMI input of the CPU.
|
|
When set, NMIs can be generated. When cleared, the CPU ignores the state of
|
|
the NMI pin.
|
|
|
|
Here are some details of specific situations:
|
|
|
|
When there is a pending NMI, toggling bit 7 of $4200 does not create any
|
|
additional interrupts.
|
|
|
|
Bit 7 of $4210 will be set in the NMI routine when it executes.
|
|
|
|
After the NMI routine finishes, bit 7 will remain set (assuming $4210 wasn't
|
|
read) until the start of the next frame. This will not cause more NMIs to
|
|
occur as they are only triggered by high-to-low transitions, having the NMI
|
|
pin remain low does not do anything.
|
|
|
|
Bit 7 of $4210 reflects the NMI status independantly of bit 7 of $4200.
|
|
|
|
Interlaced display
|
|
|
|
When bit 0 of $2133 is set, the screen becomes interlaced regardless of
|
|
the BG mode setting. When the screen is interlaced, the following applies:
|
|
|
|
- For BG modes 0,1,2,3,4,7 each line of the background is repeated in the
|
|
even and odd frames for single-density interlace. (224 or 239 lines shown)
|
|
|
|
- For BG modes 5,6 each line of the background is unique for the even and
|
|
odd frames for double-density interlace. (448 or 478 lines shown)
|
|
|
|
Screen layout
|
|
|
|
For an NTSC non-interlaced display, each frame consists of 262 lines.
|
|
Depending on the screen height, these lines are divided into the following
|
|
groups:
|
|
|
|
Section 224-line mode 239-line mode
|
|
|
|
Active display 224 239
|
|
Bottom blanking 12 15
|
|
Vertical sync 3 3
|
|
Top blanking 23 5
|
|
Total 262 262
|
|
|
|
Active display is the portion of the screen where graphics are displayed.
|
|
|
|
Bottom blanking is the bottom border after the active display shown at the
|
|
very bottom of the display. Lines are filled with black.
|
|
|
|
Vertical sync is the period between the bottom and top borders which is
|
|
off-screen. Lines are filled with a darker black color than in the blanking
|
|
areas.
|
|
|
|
Top blanking is the border after the vertical sync period shown at the very
|
|
top of the display. Lines are filled with black.
|
|
|
|
----------------------------------------------------------------------------
|
|
CGRAM
|
|
----------------------------------------------------------------------------
|
|
|
|
Overview
|
|
|
|
The PPU has 512 bytes of on-chip RAM called CGRAM which holds palette data.
|
|
CGRAM is divided into 256 2-byte entries that define a single color.
|
|
|
|
Each entry has the following format:
|
|
|
|
MSB LSB
|
|
-bbbbbgggggrrrrr
|
|
|
|
b = Blue component (0=black, 31=bright)
|
|
g = Green component (0=black, 31=bright)
|
|
r = Red component (0=black, 31=bright)
|
|
- = Unused bit.
|
|
|
|
The background can use the first 128 colors in BG modes 0,1,2,5,6, and all
|
|
256 colors in BG modes 3,4,7 when not in direct color mode. Sprites always
|
|
use the latter 128 colors. Specific details about palette use and selection
|
|
for each mode will be described later.
|
|
|
|
The PPU provides several registers for using CGRAM:
|
|
|
|
$2121 - CGRAM address
|
|
$2122 - CGRAM data port (write)
|
|
$213B - CGRAM data port (read)
|
|
|
|
CGRAM access
|
|
|
|
The PPU has a 9-bit address register which gives a byte offset into CGRAM.
|
|
Writing to $2121 loads the CPU data into bits 8-1 of the address register
|
|
and clears bit 0, forcing an even address to be set.
|
|
|
|
Each time $213B is read, the byte at the current offset pointed to by the
|
|
address register is returned to the CPU, and the address register is
|
|
incremented by one.
|
|
|
|
Each time $2122 is written to the address register is incremented by one.
|
|
If the address register is even during a write, the CPU data is stored in
|
|
a latch. If the address register is odd, the latched data becomes the LSB
|
|
and the new data written becomes the MSB of a 16-bit word. This word is
|
|
written to the current address, with bit 0 of the address register ignored.
|
|
|
|
The address register will wrap from $01FF to $0000 due to reading $213B or
|
|
writing to $2122. You can mix reads and writes freely.
|
|
|
|
Valid access times
|
|
|
|
When the screen is forcibly blanked or in the V-Blank period, CGRAM can be
|
|
read and written. I haven't tested access during H-Blank yet.
|
|
|
|
Here are my observations about CGRAM access during the active display
|
|
period:
|
|
|
|
- Writing to CGRAM always results in the last word written to the data port
|
|
being written to address 0,1 regardless of the address register setting.
|
|
You could think of address bits 8-1 as always being fixed to zero during
|
|
this time.
|
|
|
|
- Reading from CGRAM returns a random mix of bytes from CGRAM and data that
|
|
wasn't stored in CGRAM. The address register has no effect on where the
|
|
data comes from.
|
|
|
|
- When the screen is turned on, the previously set value in the address
|
|
register not changed. Following reads or writes with the screen off
|
|
affect the address originally selected.
|
|
|
|
CGRAM access examples
|
|
|
|
Here are some examples of unexpected behavior. Assume CGRAM contains the
|
|
bytes $AA, $BB, $CC, $DD at address $0000 for each test:
|
|
|
|
- Set address to $0000
|
|
- Write $45
|
|
|
|
CGRAM is not updated, and the LSB latch contains $45
|
|
|
|
- Set address to $0000
|
|
- Read $2138
|
|
- Write #$45
|
|
|
|
The bytes $CC, $45 are written to address $0000. $CC was the last value
|
|
in the LSB latch, and a single byte write triggers a write to CGRAM as the
|
|
previous read made the address register odd.
|
|
|
|
----------------------------------------------------------------------------
|
|
Sprites
|
|
----------------------------------------------------------------------------
|
|
|
|
The PPU can manage up to 128 sprites. Sprites use 16-color 8x8 tiles, the
|
|
same as used by the backgrounds. The sprite size can range from 1x1 tiles
|
|
up to 8x8 tiles, with several variations in between.
|
|
|
|
The attributes for each sprite are stored in 544 bytes of on-chip RAM called
|
|
OAM or "Object Attribute Memory". The OAM can be thought of having two
|
|
sections, a 512-byte table that has 128 x 4-byte entries, and a 32-byte
|
|
table used as 128 x 2-bit entries.
|
|
|
|
The PPU provides several registers for sprite control:
|
|
|
|
$2101 - OAM control
|
|
$2102 - OAM address LSB
|
|
$2103 - OAM address MSB
|
|
$2104 - OAM data port (write)
|
|
$2138 - OAM data port (read)
|
|
|
|
The OAM control register defines various aspects about the sprites:
|
|
|
|
D7 : Sprite size, bit 2
|
|
D6 : Sprite size, bit 1
|
|
D5 : Sprite size, bit 0
|
|
D4 : Sprite name offset, bit 1
|
|
D3 : Sprite name offset, bit 0
|
|
D2 : Sprite pattern table base, bit 2
|
|
D1 : Sprite pattern table base, bit 1
|
|
D0 : Sprite pattern table base, bit 0
|
|
|
|
The sprite pattern table is where the tile data for sprites is fetched from.
|
|
The table is 16K in size and can be positioned on 16K boundaries. Bits 2-0
|
|
of this register correspond to bits 16-14 of the VRAM address.
|
|
|
|
As there is only 64K of VRAM, bit 2 has no effect. Pattern data read from
|
|
$10000-$1FFFF is instead read from $00000-$0FFFF due to mirroring.
|
|
|
|
When a sprite has bit 8 of it's name field set so that it reads patterns
|
|
out of the upper 8K of the 16K table (tiles 256-511), bits 4, 3 of this
|
|
register are added to bits 14 and 13 of the VRAM address.
|
|
|
|
If the resulting address is bigger than $10000 then data is read from
|
|
$00000 onwards due to mirroring. The same holds true if the address is
|
|
bigger than $20000, due to wrapping.
|
|
|
|
The sprite sizes are as follows:
|
|
|
|
D7 D6 D5 Small Large
|
|
|
|
0 0 0 8x8 16x16
|
|
0 0 1 8x8 32x32
|
|
0 1 0 8x8 64x64
|
|
0 1 1 16x16 32x32
|
|
1 0 0 16x16 64x64
|
|
1 0 1 32x32 64x64
|
|
1 1 0 16x32 32x64
|
|
1 1 1 16x32 32x32
|
|
|
|
The last two settings are undocumented but appear to function normally.
|
|
|
|
Overview
|
|
|
|
The CPU interface to the OAM appears as a 1024-byte array. Here's a memory
|
|
map:
|
|
|
|
$0000-$01FF : 512 bytes, used as 128 x 4-byte entries
|
|
$0200-$03FF : 32 bytes, mirrored every 32 bytes (so mirrored 16 times)
|
|
|
|
Reading and writing from the mirrored areas are valid.
|
|
|
|
OAM access
|
|
|
|
The PPU has a 10-bit address register which gives a byte offset into OAM.
|
|
Writing to $2102 will load the CPU data into bits 8-1 of the address
|
|
register. Writing to $2103 will load bit 0 of the CPU data into bit 9 of
|
|
the address register. Writing to $2102 or $2103 will clear bit 0 of the
|
|
address register so an even address is always selected. You can write to
|
|
$2102 and $2103 in any order, or write to just one or the other to update
|
|
part or all of the address.
|
|
|
|
Each time $2138 is read, the byte at the current offset pointed to by the
|
|
address register is returned to the CPU, and the address register is
|
|
incremented by one.
|
|
|
|
Each time $2104 is written to the address register is incremented by one.
|
|
If the address register is even during a write, the CPU data is stored in
|
|
a latch. If the address register is odd, the latched data becomes the LSB
|
|
and the new data written becomes the MSB of a 16-bit word. This word is
|
|
written to the current address, with bit 0 of the address register ignored.
|
|
|
|
This only affects writing to offsets $0000-$01FF. The 32 byte table at
|
|
$0200-$03FF will be updated for a write to even or odd addresses. Writes
|
|
to even addresses still update the LSB latch, however.
|
|
|
|
The address register will wrap from $03FF to $0000 due to reading $2138 or
|
|
writing to $2104. You can mix reads and writes freely.
|
|
|
|
Valid access times
|
|
|
|
When the screen is forcibly blanked or in the V-Blank period, OAM can be
|
|
read and written. I haven't tested access during H-Blank yet.
|
|
|
|
It would seem that the address register is used for some internal operation
|
|
during the active display period, which involves incrementing it. Here are
|
|
my observations:
|
|
|
|
- Writing to OAM during this time results in the data being written to
|
|
consecutively larger addresses, starting at a random offset and with
|
|
a random amount of skipped bytes between the data. The address register
|
|
has no effect on where the data goes.
|
|
|
|
- Reading from OAM returns data from consecutively larger addresses,
|
|
starting at a random offset and with a random amount of skipped bytes
|
|
between the data. The address register has no effect on where the data
|
|
goes.
|
|
|
|
- Setting the address register to a known value and waiting a few scanlines
|
|
with the screen turned on results in data being read or written to a
|
|
larger address than the one originally set.
|
|
|
|
- Writing to the address register on the same scanline where a sprite is
|
|
being displayed has no effect on the sprite. I would assume during the
|
|
active display period, the address register can't be updated by the CPU
|
|
as it is being used by the PPU exclusively.
|
|
|
|
OAM access examples
|
|
|
|
Here are some examples of unexpected behavior. Assume OAM contains the
|
|
bytes $AA, $BB, $CC, $DD at address $0000 for each test:
|
|
|
|
- Set address to $0000
|
|
- Write $45
|
|
|
|
OAM is not updated, and the LSB latch contains $45
|
|
|
|
- Set address to $0000
|
|
- Read $2138
|
|
- Write #$45
|
|
|
|
The bytes $CC, $45 are written to address $0000. $CC was the last value
|
|
in the LSB latch, and a single byte write triggers a write to OAM as the
|
|
previous read made the address register odd.
|
|
|
|
- Set address to $0000
|
|
- Write #$12
|
|
- Write #$00 to $2103
|
|
- Write #$34
|
|
|
|
OAM is not updated. The second write only loads the LSB latch as the
|
|
write to $2103 cleared bit 0 of the address register.
|
|
|
|
----------------------------------------------------------------------------
|
|
Hardware version registers
|
|
----------------------------------------------------------------------------
|
|
|
|
Here are the version register return values and chip markings for my
|
|
original model NTSC SNES:
|
|
|
|
Register Value Chip
|
|
|
|
$4210 $01 Nintendo S-CPU 5A22-01
|
|
$213E $01 Nintendo S-PPU1 5C77-01
|
|
$213F $01 Nintendo S-PPU2 5C78-01
|
|
|
|
----------------------------------------------------------------------------
|
|
I/O hardware
|
|
----------------------------------------------------------------------------
|
|
|
|
The SNES has two 7-pin joypad ports. Here's a diagram of the faceplate of
|
|
the SNES to show the pin configuration:
|
|
|
|
1P port 2P port
|
|
(Power light) ( o o o | o o o o ] [ o o o o | o o o )
|
|
7 6 5 4 3 2 1 1 2 3 4 5 6 7
|
|
|
|
Pin # Description S-CPU pin (1P) S-CPU pin (2P)
|
|
|
|
Pin 1 +5V n/a n/a
|
|
Pin 2 Output strobe 35 36
|
|
Pin 3 Output 37 37 (common between both ports)
|
|
Pin 4 Serial input 1 32 28
|
|
Pin 5 Serial input 2 33 27
|
|
Pin 6 Bidirectional 25 26
|
|
Pin 7 Ground n/a n/a
|
|
|
|
Each pin is accessible through the various hardware registers as follows:
|
|
|
|
1P port
|
|
|
|
- Read $4016 to pulse pin 2.
|
|
- Writing to bit 0 of $4016 controls pin 3.
|
|
- Reading bit 0 of $4016 returns data from pin 4.
|
|
- Reading bit 1 of $4016 returns data from pin 5.
|
|
- Pin 6 is connected to bit 6 of $4201 (WRIO) and $4213 (RDIO).
|
|
|
|
2P port
|
|
|
|
- Read $4017 to pulse pin 2.
|
|
- Writing to bit 0 of $4016 controls pin 3.
|
|
- Reading bit 0 of $4017 returns data from pin 4.
|
|
- Reading bit 1 of $4017 returns data from pin 5.
|
|
- Pin 6 is connected to bit 7 of $4201 (WRIO) and $4213 (RDIO).
|
|
|
|
2P pin 6 is also connected to S-PPU2 pin 29. This is most likely the
|
|
external input signal that can be used to latch the H/V counter. A lightgun
|
|
such as the Super Scope or Konami Justifier would use pulse pin 6 of the 2P
|
|
port to make the PPU2 latch the H/V counter when it detects the raster beam.
|
|
|
|
The second serial input from pin 5 and bidirectional pin 6 are unused by
|
|
the joypad and mouse. The Hudson Super Multitap may be the only peripheral
|
|
to use them, see the multitap section for more details.
|
|
|
|
The standard way most peripherals work is to write 1 then 0 to bit 0 of
|
|
$4016 to reset the devices in the 1P and 2P ports. You can then read bit 0
|
|
of $4016 and $4017 multiple times to return data serially, starting with
|
|
the MSB down to the LSB.
|
|
|
|
I/O port
|
|
|
|
The SNES is described as having an 8-bit bidirectional I/O port. I don't
|
|
know if this physically corresponds to the expansion port on the bottom of
|
|
the control deck, or if the CPU just has an I/O port built in and some or
|
|
all of the port pins are used.
|
|
|
|
Writing to $4201 (WRIO) sets the data to be output through the I/O port.
|
|
Any bit that is also set to 1 will allow the corresponding pin to act
|
|
as an input, and data from that pin can be read through $4213 (RDIO).
|
|
|
|
The only uses I know of for the I/O port are as follows:
|
|
|
|
- Any value written to $4201 can be read back through $4213.
|
|
|
|
- As bit 7 of $4201 controls pin 6 of the 2P port, which is also shared with
|
|
the external signal input of the PPU to latch the H/V counter, writing 1
|
|
then 0 to bit 7 of $4201 will latch the H/V counter.
|
|
|
|
While bit 7 is set to 0, the latch will always hold the same value and
|
|
reading $2137 will not change the latched value. If you want to poll
|
|
the H/V counter using $2137, set bit 7 back to 1 for it to work properly.
|
|
|
|
- Pin 6 of the 1P or 2P port is used as an output to control the Hudson
|
|
Super Multitap. See the multitap section for more details.
|
|
|
|
----------------------------------------------------------------------------
|
|
Automatic reading
|
|
----------------------------------------------------------------------------
|
|
|
|
The SNES has a feature to automatically read the four serial input pins
|
|
and store them into a set of registers during V-Blank. This can be done
|
|
without the CPU having to manually write and read $4016 / $4017, saving
|
|
time for other tasks.
|
|
|
|
When bit 0 of $4200 is set, at the start of V-Blank (depending on the screen
|
|
height) the SNES will automatically do the following steps:
|
|
|
|
- Write 1 then 0 to bit 0 of $4016.
|
|
|
|
- Read $4016 and $4017 sixteen times, storing the return values from bits
|
|
0 and 1 into eight registers like so:
|
|
|
|
- 16 bits from bit 0 of $4016 are stored in $4218 (LSB) and $4219 (MSB)
|
|
- 16 bits from bit 1 of $4016 are stored in $421C (LSB) and $421D (MSB)
|
|
- 16 bits from bit 0 of $4017 are stored in $421A (LSB) and $421B (MSB)
|
|
- 16 bits from bit 1 of $4017 are stored in $421E (LSB) and $421F (MSB)
|
|
|
|
This process takes three scanlines to complete. Bit 0 of $4212 shows the
|
|
scanning status, where 1= the SNES is still reading data, 0= the SNES has
|
|
finished or automatic scanning was not enabled.
|
|
|
|
The use I've seen in games and demos is to wait for this bit to be set, and
|
|
then cleared in the NMI handler.
|
|
|
|
----------------------------------------------------------------------------
|
|
Hudson Super Multitap
|
|
----------------------------------------------------------------------------
|
|
|
|
The multitap plugs into the 1P or 2P port. It has four connectors to plug
|
|
additional joypads into, and has a switch for selecting a multiplayer or
|
|
compatability mode.
|
|
|
|
In compatability mode (switch = 2P) the joypad plugged in to connector #1
|
|
works like a standard pad. All remaining connectors are ignored, pin 6
|
|
is ignored in terms of selecting which set of joypad data to return, and
|
|
no extra data is returned in the second serial input.
|
|
|
|
In multiplayer mode (switch = 3P-5P) the first serial input returns data
|
|
from the joypad in connector #1 or #3, and the second serial input returns
|
|
data from the joypad in connector #2 or #4. Pin 6 of the 1P or 2P port
|
|
is used to select connectors #1 and #3 when set to 1, or #2 and #4 when
|
|
set to 0.
|
|
|
|
----------------------------------------------------------------------------
|
|
SNES joypad
|
|
----------------------------------------------------------------------------
|
|
|
|
The SNES joypad uses two 4021 ICs, which are 8-stage static shift registers.
|
|
They are cascaded together to form a 16-bit shift register that stores the
|
|
state of the directional pad and buttons, allowing the SNES to read out
|
|
the state of the joypad serially.
|
|
|
|
The button states will be loaded into the shift register when bit 0 of
|
|
$4016 is set to 1 and then 0. This happens to both control pads as they
|
|
share a common pin. Each time $4016 or $4017 is read, the shift register
|
|
for the 1P or 2P pad advances by one, outputting a bit which can be read
|
|
in bit 0 of $4016 or $4017 respectively.
|
|
|
|
The tail end of the shift register is filled with a one on each shift. After
|
|
the sixteenth time $4016 or $4017 has been read, all consecutive reads will
|
|
return one due to the shift register being completely filled with ones.
|
|
This will go on forever until the shift register is loaded again by writing
|
|
1 then 0 to $4016.
|
|
|
|
If at any time $4016 is left at 1, reading either joypad will always return
|
|
the state of the first input, which is the 'B' button. This won't stop until
|
|
$4016 is set to zero again.
|
|
|
|
Here is the order of button states read out through $4016 or $4017:
|
|
|
|
Read 1 - Button B Read 9 - Button A
|
|
Read 2 - Button Y Read 10 - Button X
|
|
Read 3 - Button Select Read 11 - Button L
|
|
Read 4 - Button Start Read 12 - Button R
|
|
Read 5 - Up Read 13 - '0'
|
|
Read 6 - Down Read 14 - '0'
|
|
Read 7 - Left Read 15 - '0'
|
|
Read 8 - Right Read 16 - '0'
|
|
|
|
All reads after read 16 will return 1.
|
|
|
|
All buttons are 1= pressed, 0= released.
|
|
|
|
If no joypad is plugged in, then zero is always read from $4016 or $4017.
|
|
A game can check if a joypad is connected by seeing if any reads beyond
|
|
the 16th one return '1', otherwise there is no joypad.
|
|
|
|
As far as I can tell, the joypad does not return any data through pin 5
|
|
(which always returns zero) and any setting of pin 6 will not affect the
|
|
joypad operation.
|
|
|
|
----------------------------------------------------------------------------
|
|
SNES mouse
|
|
----------------------------------------------------------------------------
|
|
|
|
The SNES mouse works in a similar fashion to the joypad. It has a custom
|
|
18-pin chip called the "SFM1" which returns data about the mouse status
|
|
serially to the SNES.
|
|
|
|
Writing 1, then 0 to bit 0 of $4016 will reset the SFM1 and subsequent reads
|
|
from $4016 or $4017 (depending on which port the mouse is plugged into) will
|
|
return the mouse state data. Leaving bit 0 of $4016 set to 1 will result
|
|
in zero always being read back.
|
|
|
|
The mouse data is as follows:
|
|
|
|
Read 1 - '0' Read 17 - Y sign
|
|
Read 2 - '0' Read 18 - Y movement bit 6 (?)
|
|
Read 3 - '0' Read 19 - Y movement bit 5
|
|
Read 4 - '0' Read 20 - Y movement bit 4
|
|
Read 5 - '0' Read 21 - Y movement bit 3
|
|
Read 6 - '0' Read 22 - Y movement bit 2
|
|
Read 7 - '0' Read 23 - Y movement bit 1
|
|
Read 8 - '0' Read 24 - Y movement bit 0
|
|
Read 9 - Right button Read 25 - X sign
|
|
Read 10 - Left button Read 26 - X movement bit 6 (?)
|
|
Read 11 - '0' Read 27 - X movement bit 5
|
|
Read 12 - '0' Read 28 - X movement bit 4
|
|
Read 13 - '0' Read 29 - X movement bit 3
|
|
Read 14 - '0' Read 30 - X movement bit 2
|
|
Read 15 - '0' Read 31 - X movement bit 1
|
|
Read 16 - '1' Read 32 - X movement bit 0
|
|
|
|
All reads after read 32 will return 1.
|
|
|
|
The left/right buttons are 1= pressed, 0= released.
|
|
|
|
The Y and X sign are 1= up/left movement, 0= down/right movement. The sign
|
|
bits do not change until the mouse is moved in a opposite direction. So
|
|
moving the mouse up, and leaving it stationary would keep the Y sign bit
|
|
set to 1.
|
|
|
|
The Y and X movement fields indicate how rapidly the mouse was moved in a
|
|
particular direction. This is usually $00-$1F, but extremely rapid movements
|
|
can yield higher values. I haven't been able to get values large enough
|
|
to indicate there is a seventh movement bit, but there may likely be one.
|
|
Both fields are zero when there is no movement.
|
|
|
|
As far as I can tell, the mouse does not return any data through pin 5
|
|
(which always returns zero) and any setting of pin 6 will not affect the
|
|
mouse operation.
|
|
|
|
----------------------------------------------------------------------------
|
|
Register reference
|
|
----------------------------------------------------------------------------
|
|
|
|
$2180 - WRAM data port
|
|
$2181 - WRAM offset (bits 7-0 are offset bits 7-0)
|
|
$2182 - WRAM offset (bits 7-0 are bits 15-8)
|
|
$2183 - WRAM offset (bit 0 is offset bit 16, bits 7-1 are unused)
|
|
|
|
Registers $2181-$2183 define a 17-bit offset in WRAM. Reading or writing
|
|
$2180 will return a byte from or write a byte to WRAM, and automatically
|
|
increment the WRAM offset by one. The offset wraps from $01FFFF to $000000.
|
|
|
|
Reading $2180, $2181, or $2183 returns the last value on the data bus,
|
|
which is usually the last byte of the opcode fetched. For example, this
|
|
value would be $21 for 'lda $2181', or $00 for 'lda [$00]' when the pointer
|
|
at $00 is $2181.
|
|
|
|
----------------------------------------------------------------------------
|
|
Cartridge information
|
|
----------------------------------------------------------------------------
|
|
|
|
Cartridge pinout
|
|
|
|
Solder side Component side
|
|
|
|
MCK - 01 32 - /RAMSEL
|
|
EXPAND - 02 33 - REFRESH
|
|
PA6 - 03 34 - PA7
|
|
/PARD - 04 35 - /PAWR
|
|
<key>
|
|
GND - 05 36 - GND
|
|
A11 - 06 37 - A12
|
|
A10 - 07 38 - A13
|
|
A9 - 08 39 - A14
|
|
A8 - 09 40 - A15
|
|
A7 - 10 41 - A16
|
|
A6 - 11 42 - A17
|
|
A5 - 12 43 - A18
|
|
A4 - 13 44 - A19
|
|
A3 - 14 45 - A20
|
|
A2 - 15 46 - A21
|
|
A1 - 16 47 - A22
|
|
A0 - 17 48 - A23
|
|
/IRQ - 18 49 - /ROMSEL
|
|
D0 - 19 50 - D4
|
|
D1 - 20 51 - D5
|
|
D2 - 21 52 - D6
|
|
D3 - 22 53 - D7
|
|
/RD - 23 54 - /WR
|
|
CIC0 - 24 55 - CIC1
|
|
CIC2 - 25 56 - CIC3
|
|
/RESET - 26 57 - SYSCK
|
|
+5V - 27 58 - +5V
|
|
<key>
|
|
PA0 - 28 59 - PA1
|
|
PA2 - 29 60 - PA3
|
|
PA4 - 30 61 - PA5
|
|
SOUND-L - 31 62 - SOUND-R
|
|
|
|
Pin assignments
|
|
|
|
A23-0 - CPU address bus
|
|
D7-0 - CPU data bus
|
|
/WR - CPU write strobe
|
|
/RD - CPU read strobe
|
|
/IRQ - CPU IRQ input. Allows on-cart hardware to interrupt the CPU.
|
|
/RESET - When the system is reset (power-up or hard reset) this goes low.
|
|
Could be used to reset additional on-cart hardware.
|
|
/RAMSEL - Goes low on accesses to WRAM at the following addresses:
|
|
00-3F:0000-1FFF
|
|
80-BF:0000-1FFF
|
|
7E-7F:0000-FFFF
|
|
/ROMSEL - Goes low on access to cartridge ROM at the following addresses:
|
|
00-3F:8000-FFFF
|
|
40-7D:0000-FFFF
|
|
80-BF:8000-FFFF
|
|
C0-FF:0000-FFFF
|
|
PA7-0 - Address bus for $2100-$21FF range in banks $00-$3F/$80-$BF (B-Bus)
|
|
/PAWR - Write strobe for B-Bus
|
|
/PARD - Read strobe for B-Bus
|
|
MCK - 21.47727 MHz master clock
|
|
SYSCK - Unknown, is an output from the CPU.
|
|
SOUND-L - Audio input to be mixed with left channel output
|
|
SOUND-R - Audio input to be mixed with right channel output
|
|
THROUGH - Connected to pin 24 of the expansion port.
|
|
REFRESH - Unknown, is an output from the CPU also connected to WRAM.
|
|
This is most likely to manage DRAM refresh.
|
|
CIC3-0 - To CIC chip on cartridge
|
|
|
|
Details
|
|
|
|
For more information about the CIC chip, please see the following:
|
|
|
|
- U.S. Patent no. 4,799,635 (NES specific)
|
|
- http://home.freeuk.com/markk/Consoles/SNES_Lockout.txt
|
|
|
|
The only hardware I know of which uses the two sound input pins is the
|
|
Super Gameboy and Super Gameboy 2.
|
|
|
|
The SNES has two address busses, the A-Bus which is used by the CPU, ROM,
|
|
WRAM, etc. and the B-Bus which is used by the PPU1, PPU2, APU I/O ports,
|
|
and WRAM. When the SNES does DMA, it can transfer data from the A-Bus to
|
|
the B-Bus or vice-versa, but not to the same bus. This holds true even
|
|
for WRAM, which is connected to both the A-Bus and B-Bus.
|
|
|
|
I would guess the B-Bus signals are brought out to the cartridge connector
|
|
so any on-cart hardware could map it's own registers within that region,
|
|
allowing for DMA from the A-Bus to it. Exactly what range of B-Bus addresses
|
|
are open for expansion purposes is unknown.
|
|
|
|
Cartridge information
|
|
|
|
Here's some information about several cartridges I've examined:
|
|
|
|
Name: Lagoon
|
|
Board: SHVC-1A3B-12
|
|
Type: LoROM / 16 megabits / 8K SRAM
|
|
|
|
This cartridge has a 74LS139 for address decoding and a 8K SRAM chip.
|
|
|
|
00-1F:8000-FFFF : Program ROM
|
|
20-3F:8000-FFFF : Unmapped
|
|
40-6F:0000-FFFF : Unmapped
|
|
70-7D:0000-FFFF : SRAM
|
|
7E-7F:0000-FFFF : Work RAM
|
|
80-9F:8000-FFFF : Program ROM
|
|
A0-BF:8000-FFFF : Unmapped
|
|
C0-EF:0000-FFFF : Unmapped
|
|
F0-FF:0000-FFFF : SRAM
|
|
|
|
- A23 and A15 are ignored, so banks $80-FF are a mirror of $00-7F.
|
|
- SRAM is mirrored repeatedly in the areas it's assigned to.
|
|
- When accessing an unmapped region, neither the ROM or SRAM are enabled.
|
|
|
|
Name: Pilotwings
|
|
Board: SHVC-1BON-02
|
|
Type: LoROM / 8 megabits / DSP-1
|
|
|
|
This cartridge has a 74LS139 for address decoding and a NEC uPD77C25 DSP
|
|
which Nintendo labels as the "DSP-1" custom chip. It also has a oscillator
|
|
and 74HCU04 to provide a clock signal, but I don't know what speed the DSP
|
|
actually runs at.
|
|
|
|
00-1F:8000-FFFF : Program ROM
|
|
20-2F:8000-FFFF : Unmapped
|
|
30-3F:8000-BFFF : DSP data register (r/w)
|
|
30-3F:C000-FFFF : DSP status register (r/o)
|
|
40-7D:0000-FFFF : Unmapped
|
|
7E-7F:0000-FFFF : Work RAM
|
|
80-9F:8000-FFFF : Program ROM
|
|
A0-AF:8000-FFFF : Unmapped
|
|
80-BF:8000-BFFF : DSP data register (r/w)
|
|
80-BF:C000-FFFF : DSP status register (r/o)
|
|
C0-FF:0000-FFFF : Unmapped
|
|
|
|
- A23 and A15 are ignored, so banks $80-FF are a mirror of $00-7F.
|
|
- DSP pins INT, SCK, /SIEN, /SOEN are all tied to +5V and are unused.
|
|
- When accessing an unmapped region, neither the ROM or DSP are enabled.
|
|
|
|
Name: Killer Instinct
|
|
Board: SHVC-1JON-20
|
|
Type: HiROM / 32 megabits
|
|
|
|
The mask ROM socket on the PCB has the following pin assignments:
|
|
|
|
+---\/---+
|
|
A20 -|01 36|- +5V
|
|
A21 -|02 35|- A23
|
|
A17 -|03 34|- +5V
|
|
A18 -|04 33|- /ROMSEL (ROM /CS)
|
|
A15 -|05 32|- A19
|
|
A12 -|06 31|- A14
|
|
A7 -|07 30|- A13
|
|
A6 -|08 29|- A8
|
|
A5 -|09 28|- A9
|
|
A4 -|10 27|- A11
|
|
A3 -|11 26|- A16
|
|
A2 -|12 25|- A10
|
|
A1 -|13 24|- /RD (ROM /OE)
|
|
A0 -|14 23|- D7
|
|
D0 -|15 22|- D6
|
|
D1 -|16 21|- D5
|
|
D2 -|17 20|- D4
|
|
GND -|18 19|- D3
|
|
+--------+
|
|
|
|
- A22 is unconnected.
|
|
- This game uses a MX23C3201 4096Kx8 mask ROM. I can't find a datasheet for
|
|
this chip, so I'm not sure what pin 35 (A23) is used for. It could be
|
|
an inverted chip select so the ROM is only mapped to banks $40-$7E and
|
|
$C0-$FF, but that's just a guess.
|
|
|
|
----------------------------------------------------------------------------
|
|
Assistance needed
|
|
----------------------------------------------------------------------------
|
|
|
|
If any games have a legitimate use of writing to OAM or reading OAM or CGRAM
|
|
during the active display period, I'd like to hear about the details of how
|
|
the data is used. So far it's been confirmed that Uniracers writes to OAM
|
|
this way, maybe there are others.
|
|
|
|
----------------------------------------------------------------------------
|
|
Credits and acknowlegements
|
|
----------------------------------------------------------------------------
|
|
|
|
- ToToTek Multimedia for the Game Doctor SF7. (www.tototek.com)
|
|
- neviksti for the SNES starter kit. (available at nesdev.parodius.com)
|
|
- John Weidman, CaitSith2, neviksti, for the SNES schematic scans.
|
|
- Gilligan for the SNES documentation.
|
|
- Qwertie for the SNES documentation.
|
|
- anomie for the post about SNES peripherals at the SNES9X development forum,
|
|
pointing out errors, and suggesting tests.
|
|
- Overload for clarifying some details about the mouse.
|
|
- Chris MacDonald for testing and support.
|
|
|
|
----------------------------------------------------------------------------
|
|
Disclaimer
|
|
----------------------------------------------------------------------------
|
|
|
|
If you use any information from this document, please credit me
|
|
(Charles MacDonald) and optionally provide a link to my webpage
|
|
(http://cgfm2.emuviews.com/) so interested parties can access it.
|
|
|
|
The credit text should be present in the accompanying documentation of
|
|
whatever project which used the information, or even in the program
|
|
itself (e.g. an about box).
|
|
|
|
Regarding distribution, you cannot put this document on another
|
|
website, nor link directly to it.
|
|
|