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.
|Address||Control pad port||Purpose|
|$A10003||1||Toggle TH bit; read control pad inputs.|
|$A10009||1||Set TH and input bits to read or write. (0 = read; 1 = write)|
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.
Reading 3 button control pads consists of the following steps:
- Set TH pin to write and all others to read.
- Set TH pin to 1.
- Read inputs for
- Set TH pin to 0.
- Read inputs for START
The following code will perform this function for control pad #1:
moveq #$40,d0 move.b d0,($A10009).l ; TH pin to write, others to read 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.
Reading 6 button control pads is the same as reading 3 button pads, with an additional step for MODE .
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