2 ; This library speaks the SNES protocol to the SNES controller
7 ; Serial Data: input (high-z), normally driven low
9 ; Note: at 18MHz, 6us = 108 clock cycles
10 ; We can probably poll the SNES controller WAY faster than it was originally
11 ; intended to be polled. Play around with values in the burn_clock loop
14 ; (Standard) Communication Timeline
15 ; 0us - If serial data is low, Data latch raised
16 ; 6us - Check that Serial data is high
17 ; 12us - Data latch dropped. Controller drives data for button B
18 ; 18us - Data clock dropped. Read data for button B
19 ; 24us - Data clock raised. Controller drives data for button Y
22 ; 186us - Data clock dropped. Read data for button 15
23 ; 192us - Data clock raised. Controller drives data for bit 16
24 ; 198us - Data clock remains high. Read high bit 16. (ignored)
26 ; Data is driven HIGH if button is pressed. This may be counterintuitive.
28 ; Drive times are read times - 6us
30 ; Bit Time Read Button Reported
31 ; ==== ============= ===============
39 ; 8 102 Right on joypad
45 ; 13 162 none (always high)
46 ; 14 174 none (always high)
47 ; 15 186 none (always high;)
48 ; 16 198 none (always high)
50 ; Mnemonics for some important registers and bits
64 ; Function call to burn 99 clock cycles, including call and ret
74 ; Macro to do the same thing (burns 3 * n + 4 clock cycles)
75 .macro BURN_100_CLOCKS
78 dec r22 ; [4,7,10,...]
79 brne -2 ; [5,6, 8,9,...]
84 ;extern unsigned pollSnes(void);
85 ; This function polls the SNES controller, as described above
88 ;/* Register assignments for pollSnes on gcc */
89 ;/* Calling conventions on gcc:
90 ; * First parameter passed in r24/r25, second in r22/23 and so on.
91 ; * Callee must preserve r1-r17, r28/r29
92 ; * Result is passed in r24/r25
105 sbi PINC, PIN1 ; [0] Raise data latch
107 call burn_clock ; 12us
111 andi temp2, PIN2; Mask out serial data pin
114 cbi PINC, PIN1 ; drop data latch
116 call burn_clock ; wait for controller to drive data
118 ; Current time: ~18us, 30us,...102us
119 in temp2, PINC ; Read PINC pin states
120 ror temp2 ; Rotate PINC0 into carry flag
121 ror temp2 ; Rotate PINC1 into carry flag
122 ror temp2 ; Rotate PINC2 into carry flag (Controller 1 data)
123 rol resH ; Save the current bit (in carry flag)
124 ; To add another controller, just add another ror and
125 ; rol into another register for return values
126 cbi PINC, PIN0 ; drop data clock (indicating we've read this bit)
129 ; Current time: ~24us, 36us,...108us
130 sbi PINC, PIN0 ; Raise data clock
135 call burn_clock ; Wait for controller to drive data
137 ; Current time: ~114us, 126us,...198us
138 in temp2, PINC ; Read PINC pin states
139 ror temp2 ; Rotate PINC0 into carry flag
140 ror temp2 ; Rotate PINC1 into carry flag
141 ror temp2 ; Rotate PINC2 into carry flag (Controller 1 data)
142 rol resL ; Save the current bit (in carry flag)
145 cbi PINC, PIN0 ; drop data clock after test to avoid dropping
146 ; data clock after reading 16th bit
150 sbi PINC, PIN0 ; raise data clock
151 jmp readbitsecond8 ; loop
154 ldi temp2, 0xff ; for xor
155 eor resL, temp2 ; Invert for negative logic - to the SNES controller,
156 eor resH, temp2 ; low indicates button pressed. To USB HID, the opposite.
157 ret ; return to caller
159 unconnected: ; Controller was disconnected
160 clr resL ; Indicate no buttons pressed
162 ret ; return to caller