Super NES Programming/Joypad Input

From Wikibooks, open books for an open world
Jump to navigation Jump to search

Joypads are the SNES' means of input from the user. There can be up to four connected to the system, and there's support for special controllers, too (mouse, Super Scope, etc).

NOTE: This tutorial is a work-in-progress. I'm still relatively new to the SNES, so please feel free to correct any errors in this document.

Joypad Registers[edit | edit source]

To start off, we'll list the registers that we're going to use:

Size Address Official Name Description
Byte $4200 NMITIMEN Counter Enable
Byte $4212 HVBJOY Status Register
Word $4218 CNTRL1L & -H Joypad #1 Status
Word $421a CNTRL2L & -H Joypad #2 Status
Word $421c CNTRL3L & -H Joypad #3 Status
Word $421e CNTRL4L & -H Joypad #4 Status
Byte $4016 Joypad #1 Old-Style Status
Byte $4017 Joypad #2 Old-Style Status

Now, let's look at them in a bit more depth:

$4200 - NMITIMEN - Counter Enable n-vh---j

This register is most likely a bit familiar to you. If you've done any prior SNES coding, you'll recognize that you've probably used this register to enable a VSync interrupt. For joypad input, we must make sure bit 0 ("j") is set. This tells the SNES that we will be polling the other joypad registers.

For reference, the n-vh---j bits which make up the rest of the byte we'll be loading in to register $4200 are as follows:

Bit name Position Description
n 7 Enables/Disables NMI
v 5 Enables/Disables an IRQ on a vertical trigger
h 4 Enables/Disables an IRQ on a horizontal trigger
j 0 The Joypad polling bit

$4212 - HVBJOY - SNES Status Register vh-----j

This register is used to see if certain data is ready to be polled from the SNES. In this case, we only care about bit 0 ("j"). If we poll $4212 and bit 0 is set, then we know that the other SNES joypad registers will contain relevant data. It's usually not so bad if this step is left out, though. In the algorithm I'll be showing later, this check is skipped, but this explanation still exists for completeness.

$4218/9 through $421e/f - Joypad Status Registers hi:bystudlr lo:axlriiii

These are 16-bit registers that return the button and/or type states for each joypad connected to the SNES. $4218 and $4219 contain joypad 1's data, and joypad 2, 3, and 4 follow. The bits are laid out like this:

Bit(s) Description
$4219/b/d/f (hi)
b B Button
y Y Button
s Select Button
t Start Button
u Up D-Pad Button
d Down D-Pad Button
l Left D-Pad Button
r Right D-Pad Button
$4218/a/c/e (lo)
a A Button
x X Button
l L Button
r R Button
iiii Controller Type ID

Most of these are quite self-explanatory. If a corresponding button's bit is set, then that button is pressed. The only semi-confusing part of this is the mysterious "iiii" bits - these determine which kind of controller is connected to the port. Basically, if they read 0000, then it's a standard SNES controller. Otherwise, it's a custom controller type or corrupted data.

$4016 and $4017 - Joypad 1 and 2 Old-Style Status

For these, you'll notice I left out the specific bits of each register. Basically, these work just like reading states from NES. Because of this, I think it's redundant to include that information here, except that bit 0 of $4200 must be clear to do use them this way. These registers can still be useful, though. If you write 0 to $4016, then these two registers can be used to check if joypads 1 and 2 are connected. After writing the 0 (and you only need to write to $4016, not both), reading from the registers will return 0 if not connected, and something else if connected.

Basic Joypad Read Algorithm[edit | edit source]

When you initialize:

.ENUM $80

	Joy1A	db	;B, Y, Select, Start, Up, Down, Left, Right
	Joy1B	db	;A, X, L, R, iiii-ID
.ENDE

	lda #%10000001	; Enable NMI and Auto Joypad read
	sta NMITIMEN   	; Interrupt Enable Flags

In your main game loop (or somewhere appropriate) without checks:

	lda CNTRL1L     ; $4218
	sta Joy1A
	lda CNTRL1H     ; $4219
	sta Joy1B

However, before reading from the Auto Joypad Read registers, the lowest bit of HVBJOY should be tested to be 0, as the reading process takes some time to finish.