Actions

Sega Mega Drive/Control pad inputs

From Sega Retro

Control pad inputs are received through the Sega Mega Drive's two 9-pin ports on the front of the console. Reading control pad inputs must be done in stages, since there aren't enough pins to transmit all inputs at the same time. The control pad contains a multiplexer which is controlled by writing to special memory locations.

Registers

Address Control pad port Purpose
$A10003 1 Toggle TH bit; read control pad inputs.
$A10005 2
$A10009 1 Set TH and input bits to read or write. (0 = read; 1 = write)
$A1000B 2

Reading control pad inputs typically consists of using $A10009/$A1000B to set TH to write and the other bits to read. The full range of control pad inputs can then be read by repeatedly toggling the TH bit through $A10003/$A10005. Every time the TH bit is switched between 0 and 1, the content of the other bits changes. There are 8 possible states for the register, after which it returns to the start. The counter also resets after 1.5ms, so that extra buttons aren't accidentally read by games that don't support them.

TH state Data
1
7
6
5
4
3
2
1
0

0
TH
C
B
Right
Left
Down
Up
0
7
6
5
4
3
2
1
0

0
TH
Start
A
0
0
Down
Up
1
7
6
5
4
3
2
1
0

0
TH
C
B
Right
Left
Down
Up
0
7
6
5
4
3
2
1
0

0
TH
Start
A
0
0
0
0
1
7
6
5
4
3
2
1
0

0
TH
C
B
X
Y
Z
Mode
0
7
6
5
4
3
2
1
0

0
TH
Start
A
1
1
1
1
1
7
6
5
4
3
2
1
0

0
TH
C
B
Right
Left
Down
Up
0
7
6
5
4
3
2
1
0

0
TH
Start
A
0
0
Down
Up

3 button control pads

Reading 3 button control pads consists of the following steps:

  • Set TH pin to output and all others to input.
  • Set TH pin to 1.
  • Read inputs for UpDownLeftRightBC
  • Set TH pin to 0.
  • Read inputs for AStart

The following code will perform this function for control pad #1:

moveq	#$40,d0
move.b	d0,($A10009).l	; TH pin to output, others to input
move.b	d0,($A10003).l	; TH to 1
nop
nop
move.b	($A10003).l,d0
andi.b	#$3F,d0		; d0 = 00CBRLDU
moveq	#0,d1
move.b	#0,($A10003).l	; TH to 0
nop
nop
move.b	($A10003).l,d1
andi.b	#$30,d1		; d1 = 00SA0000
lsl.b	#2,d1		; d1 = SA000000
or.b	d1,d0		; d0 = SACBRLDU

This leaves the current state of control pad #1 in the register d0. To do the same with pad #2, replace $A10009 with $A1000B and $A10003 with $A10005.

6 button control pads

Reading 6 button control pads is the same as reading 3 button pads, with an additional step for XYZMode.

The following code assumes the code for a 3 button pad has already run:

moveq	#0,d1
move.b	#$40,($A10003).l ; TH to 1
nop
nop
move.b	#0,($A10003).l	; TH to 0
nop
nop
move.b	#$40,($A10003).l ; TH to 1
nop
nop
move.b	($A10003).l,d1
move.b	#0,($A10003).l	; TH to 0
andi.w	#$F,d1		; d1 = 0000MXYZ
lsl.w	#8,d1		; d1 = 0000MXYZ00000000
or.w	d1,d0		; d0 = 0000MXYZSACBRLDU