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.

The TrapThem Controller is equipped with a 9-pin D-Sub connector with the following pinout:

Pin Signal CIA Signal (control port 2)
3 Data out CIA 1: Port A / Bit 2 (input)
4 Clock in CIA 1: Port A / Bit 3 (output)
6 Latch in CIA 1: Port A / Bit 4 (output)
7 +5V in

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:

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

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'
    sta tmp         ; bitcounter
    ; --- switch CIA I/Os for game pad use --- 
    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    
    lda CIA1_PRA    ; read data from port a
    ror             ; shift bit 2 to carry
    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

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.

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.