TrapThem Controller
The TrapThem Controller is a Super Nintendo Entertainment System (SNES) game controller modified for connecting to a control port of a Commodore 64. Basically it is the 8-player SNES adapter of Wolfram Sang, stripped down to just one controller.
You can buy a controller here: poly.play webshop
Hardware
The TrapThem Controller is equipped with a 9-pin D-Sub connector with the following pinout:
Pin | Signal | CIA Signal (control port 2) |
---|---|---|
1 | — | |
2 | — | |
3 | Data out | CIA 1: Port A / Bit 2 (input) |
4 | Clock in | CIA 1: Port A / Bit 3 (output) |
5 | — | |
6 | Latch in | CIA 1: Port A / Bit 4 (output) |
7 | +5V in | |
8 | GND | |
9 | — |
The TrapThem controller works best in control port 2, because it interferes with keyboard scanning if connected to control port 1, so the following description and examples assume that it is plugged into control port 2.
You can also build your own TrapThem controller. Simply get a SNES controller (they can be found very cheap online), cut the original connector and solder on a 9 pin D-Sub female connector. The pinout (and the protocol specification) of the SNES connector can be found here: https://www.gamefaqs.com/snes/916396-super-nintendo/faqs/5395
Software
This code assumes that the TrapThem controller is connected to control port 2.
The controller itself also works in control port 1, but keyboard operation is disturbed in this case (some keys don't work), so this is not recommended.
The ACME assembler was used for the following code snippets.
The code needs two variables 'tmp' and 'pad' that must be defined by you:
; Temp variable in zero page tmp = $02 ; This 16-bit variable stores the button states of the controller. 'pad' stores the lower 8 bits, ; 'pad+1' the rest (if more than 8 bits are read). pad !word 0
These definitions just make the code nicer. If you want you can of course replace them with the numbers.
CIA1_PRA = $DC00 CIA1_DDRA = $DC02
To read the contoller, load the number of bits that you want to read to A and call the routine 'tt_ctrl_read'.
; ================================================================= ; =========== Read TrapThem Controller (control port 2) =========== ; Input: A: Number of bits to read from controller ; Output: Variable 'pad' (16-bits): Button states (low-active) ; Uses zero page variable 'tmp' ; tt_ctrl_read sta tmp ; bitcounter ; --- switch CIA I/Os for game pad use --- sei lda #$18 sta CIA1_DDRA ; pa 2 = input, pa 3-4 = output ; generate "latch" pulse to freeze button status and get first bit ; and set "clock" signal high. lda #$18 sta CIA1_PRA lda #$08 sta CIA1_PRA ttc_bitloop lda CIA1_PRA ; read data from port a ror ; shift bit 2 to carry ror ror rol pad ; and shift it into 'pad' rol pad+1 ; generate "clock" low-pulse to get next bit from pad lda #$00 sta CIA1_PRA lda #$08 sta CIA1_PRA dec tmp bne ttc_bitloop ; --- switch CIA back to normal for keyboard scan --- lda #$FF sta CIA1_DDRA cli rts
This code disables interrupts, configures CIA I/O ports, reads the controller, restores default I/O port state and finally enables interrupts again. If you want to call this code from within an interrupt routine, you probably have to modify this, i.e. remove the sei/cli.
Example usage
Reading all 12 buttons
To read all 12 available buttons, set A to 12 and call the reading function:
lda #12 jsr tt_ctrl_read
Now 'pad' contains the button states in the lower 12 bits (8 bits in the byte 'pad' and 4 bits in the byte 'pad + 1'.
Please note that the bits are low-active, i.e. the bit is '0' if the button is pressed and '1' if not.
Bit | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
TrapThem button names | x | x | x | x | 4 | 3 | Select | Start | Up | Down | Left | Right | 2 | 1 | L | R |
SNES button names | x | x | x | x | B | Y | Select | Start | Up | Down | Left | Right | A | X | L | R |
pad+1 | pad |
Reading only 8 buttons
You can also read less then 12 buttons if you don't need them all. For example by reading just 8 bits you get the cursor keys, start, select and the two buttons '4' (B) and '3' (Y) and only have to evaluate the lower byte of 'pad'.
lda #8 jsr tt_ctrl_read
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
TrapThem button names | 4 | 3 | Select | Start | Up | Down | Left | Right |
SNES button names | B | Y | Select | Start | Up | Down | Left | Right |
Detecting a connected TrapThem controller
It is also possible to detect if there is a TrapThem controller connected or not with the same function by reading 20 bits.
This exploits the fact that the SNES controller, if reading more than the 12 bits, sends a '1' for bits 12..15 and '0' for all following bits.
So read 20 bits and if the last 8 bits are $F0 a controller is connected.
lda #20 jsr tt_ctrl_read lda #$F0 cmp pad beq controller_detected ; else no controller connected
Test program
Download a small test program to test your TrapThem controller.