Skip to content

Commit

Permalink
Support 1 player 2 controllers control style
Browse files Browse the repository at this point in the history
GoldenEye and Perfect Dark got a control style using
two controllers as a way to get dual analog sticks.

Since the adaptor is now interrupt base it's quite easy now
to answer another poll on another pin.

This duplicate the mapping of the C buttons (as analog) and R buttons into
second set of buffers for the second controller.

The second controller interrupt is only enabled if the adaptor detect
at boot that the second port is connected.
  • Loading branch information
darthcloud committed Jun 6, 2018
1 parent ae2d243 commit fa380ab
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 67 deletions.
72 changes: 54 additions & 18 deletions firmware/cube64.asm
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@

#define N64_PIN PORTB, 4
#define N64_TRIS TRISB, 4
#define N64_PIN2 PORTB, 5
#define N64_TRIS2 TRISB, 5
#define GAMECUBE_PIN PORTA, 4
#define GAMECUBE_TRIS TRISA, 4
#define N64C_PIN PORTA, 2
Expand All @@ -51,13 +53,15 @@ io_init macro
clrf PORTB, a
clrf WPUA, a ; Disable pull-ups.
clrf WPUB, a
bsf IOCB, IOCB4, a ; Enable interrupt on N64_PIN.
setf TRISA, a
setf TRISB, a
clrf PORTC, a ; Debug port
clrf TRISC, a ; Debug port
clrf ANSEL, a ; Set IOs to digital.
clrf ANSELH, a
bsf IOCB, IOCB4, a ; Enable interrupt on N64_PIN.
btfsc N64_PIN2, a ; If 2nd port connected,
bsf IOCB, IOCB5, a ; enable interrupt on N64_PIN2.
endm

else
Expand All @@ -84,15 +88,17 @@ pll_startup_delay macro
org 0x00
goto startup
org 0x08
n64_rx_command_start
call n64_rx_command_end
clrf STKPTR, a
call n64_rx_command
call n64_detect_command
call n64_reinit
goto int_reentry

;; Variables accessed through Direct Addressing Mode. (Bank 0)
;; We keep a single copy of those variables.
;; Variables.
cblock 0x00
n64_status_buffer:0
n64_status_buffer0:4
n64_status_buffer1:4
flags
flags2
menu_flags
Expand Down Expand Up @@ -132,23 +138,14 @@ pll_startup_delay macro
gamecube_scale:8 ; bytes of gc_scale as it allows using the same macro for both buffers.
endc

;; Variables accessed through Indexed Literal Offset Mode. (Bank 1)
;; This allows toggling between 2 copies of those variables via FSR2.
cblock 0x00
n64_status_buffer:0
n64_status_buffer0:4
n64_status_buffer1:4
endc


;; *******************************************************************************
;; ****************************************************** Initialization *******
;; *******************************************************************************

startup
movlb 0x00 ; Set bank 0 active for non-mirrored data.
movlw 0x01
movwf FSR2H, a
clrf FSR2H, a
clrf FSR2L, a
bcf INTCON, GIE, a ; Init interrupts.
bsf INTCON, RABIE, a
Expand Down Expand Up @@ -202,6 +199,7 @@ int_reentry
nop
bcf INTCON, RABIF, a
bsf INTCON, GIEH, a
call gamecube_wait_for_idle
main_loop
clrwdt
call update_rumble_feedback ; Give feedback for remapping operations using the rumble motor.
Expand Down Expand Up @@ -332,6 +330,11 @@ map_button_to macro virtual, dest_byte, dest_bit
btfss STATUS, Z, a
goto next
bsf n64_status_buffer + dest_byte, dest_bit, a
if dest_byte == 1 && dest_bit == 4
incf FSR2H, f, a
bsf n64_status_buffer + N64_Z, a
clrf FSR2H, a
endif
return
next
endm
Expand Down Expand Up @@ -424,6 +427,7 @@ map_axis_to macro virtual, dest_byte
endif
negf temp2, b ; Two's complement buffer if sign mismatch.
assign_greater_abs_value temp2, n64_status_buffer + dest_byte
clrf FSR2H, a
return
next
endm
Expand Down Expand Up @@ -514,6 +518,12 @@ n64_translate_restart
clrf n64_status_buffer + 1, a
clrf n64_status_buffer + 2, a
clrf n64_status_buffer + 3, a
incf FSR2H, f, a
clrf n64_status_buffer + 0, a ; Start out with everything zeroed...
clrf n64_status_buffer + 1, a
clrf n64_status_buffer + 2, a
clrf n64_status_buffer + 3, a
clrf FSR2H, a
bsf FLAG_NO_VIRTUAL_BTNS

map_button_from GC_A, BTN_A
Expand Down Expand Up @@ -592,6 +602,13 @@ set_virtual_axis
map_axis_to BTN_LJ_RIGHT, N64_JOYSTICK_X
map_axis_to BTN_LJ_DOWN, N64_JOYSTICK_Y
map_axis_to BTN_LJ_UP, N64_JOYSTICK_Y

incf FSR2H, f, a
map_axis_to BTN_RJ_LEFT, N64_JOYSTICK_X
map_axis_to BTN_RJ_RIGHT, N64_JOYSTICK_X
map_axis_to BTN_RJ_DOWN, N64_JOYSTICK_Y
map_axis_to BTN_RJ_UP, N64_JOYSTICK_Y
clrf FSR2H, a
return

;; This is called by remap_virtual_button to convert a virtual button code,
Expand Down Expand Up @@ -1091,16 +1108,19 @@ update_slot_empty_timer

n64_reinit
clrf FSR1H, a
clrf FSR2H, a
btg FSR2L, 2, a
bsf N64C_TRIS, a

bcf FLAG_AXIS
bcf FLAG_LAYOUT_MODIFIER
call gamecube_wait_for_idle
bcf FLAG_CTRL2
return

;; Service commands coming in from the N64
n64_detect_command
btfsc FLAG_CTRL2
bra n64_detect_base_cmd

ifndef DBG_TRACE
btfsc FLAG_BYPASS_MODE
Expand Down Expand Up @@ -1136,6 +1156,7 @@ endif

bsf N64C_TRIS, a ; Reset bypass bus state.

n64_detect_base_cmd
movf n64_command, w, b ; Check for both identity cmd (0x00 & 0xFF) at the same time.
btfss STATUS, Z, a
comf n64_command, w, b
Expand Down Expand Up @@ -1337,6 +1358,8 @@ n64_send_id
movwf n64_id_buffer + 0, b
clrf n64_id_buffer + 1, b
movff n64_slot_status, n64_id_buffer + 2
btfsc FLAG_CTRL2
clrf n64_id_buffer + 2, b

movlw n64_id_buffer ; Transmit the ID buffer
movwf FSR1L, a
Expand All @@ -1359,19 +1382,32 @@ keep_waiting_for_idle
;; been left high by a read-modify-write operation elsewhere.
;; For controller response we allways need an 2us stop bit.
n64_tx
wait .55
wait .53
btfsc FLAG_CTRL2
bra n64_tx2
bsf N64_TRIS, a
bcf N64_PIN, a
n64gc_tx_buffer N64_TRIS, 1

n64_tx2
bsf N64_TRIS2, a
bcf N64_PIN2, a
n64gc_tx_buffer N64_TRIS2, 1

n64_rx_bus
n64gc_rx_buffer N64_PIN, bus_byte_count, 0

n64_rx_address
n64gc_rx_buffer N64_PIN, byte_count, 0

n64_rx_command_end
n64_rx_command
btfsc N64_PIN, a
bra n64_rx_command2
n64_rx_command_start 1
n64_bus_copy N64_PIN, N64C_TRIS, byte_count, 0, 0
n64_rx_command2
n64_rx_command_start 0
n64gc_rx_buffer N64_PIN2, byte_count, 0


;; *******************************************************************************
Expand Down
4 changes: 4 additions & 0 deletions firmware/cube64.inc
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@
#define BIT_LAYOUT_MODIFIER 0x02
#define FLAG_LAYOUT_MODIFIER flags2, 1, b

;; Flag for N64 CTRL2.
#define BIT_CTRL2 0x04
#define FLAG_CTRL2 flags2, 2, b

;; Set when we are waiting for item selection in the top config menu.
#define BIT_TOP_CONFIG_MENU 0x01
#define FLAG_TOP_CONFIG_MENU menu_flags, 0, b
Expand Down
49 changes: 31 additions & 18 deletions firmware/n64gc_comm.inc
Original file line number Diff line number Diff line change
Expand Up @@ -398,32 +398,49 @@ not_last_bit ; 1.6250us

;; We get late into the first bit around 0.4 us. Use the spare cycle to init
;; pretty much everything.
n64_rx_command_start macro
wait .11 ; 0.3750us We get into the interrupt at around 0.4 us.
n64_rx_command_start macro ctrl1
wait .5 ; 0.6875us We get into the interrupt at around 0.4 us.
clrf FSR2H, a ; 1.0000us Point to buffers on bank 0.
bsf GAMECUBE_TRIS ; 1.0625us
bcf N64C_PIN ; 1.1250us Finish secondary port setup.
bcf N64C_TRIS ; 1.1875us *0.0000us Copy's next bit falling edge.
wait .3 ; 1.2500us
clrf FSR1H, a ; 1.4375us
movlw n64_command ; 1.5000us
movwf FSR1L, a ; 1.5625us
btg FSR2L, 2, a ; 1.6250us Use last good regs copy.
clrf STKPTR, a ; 1.6875us
if ctrl1
bcf N64C_PIN ; 1.1250us Finish secondary port setup.
bcf N64C_TRIS ; 1.1875us *0.0000us Copy's next bit falling edge.
else
bsf FLAG_CTRL2 ; 1.1250us 2nd controller poll.
incf FSR2H, f, a ; 1.1875us Point to buffers on bank 1.
endif
wait .4 ; 1.2500us
clrf FSR1H, a ; 1.5000us
movlw n64_command ; 1.5625us
movwf FSR1L, a ; 1.6250us
btg FSR2L, 2, a ; 1.6875us Use last good regs copy.
movlw high crc_large_table ; 1.7500us Load CRC table high address byte
movwf TBLPTRH, a ; 1.8125us with spare time.
rlcf INDF1, f, a ; 1.8750us Make room for the new bit.
bcf INDF1, 0, a ; 1.9375us Assume it's 0 to begin with.
btfsc N64_PIN ; 2.0000us Sample the incoming bit.
if ctrl1
btfsc N64_PIN ; 2.0000us Sample the incoming bit.
else
btfsc N64_PIN2 ; 2.0000us Sample the incoming bit.
endif
bsf INDF1, 0, a ; 2.0625us
btfsc INDF1, 0, a ; 2.1250us
bsf N64C_TRIS ; 2.1875us *1.0000us Copy's 'one bit' rising edge.
if ctrl1
btfsc INDF1, 0, a ; 2.1250us
bsf N64C_TRIS ; 2.1875us *1.0000us Copy's 'one bit' rising edge.
else
wait .2 ; 2.1250us
endif
movlw 7 ; 2.2500us We just did first bit, 7 remaining.
movwf bit_count, b ; 2.3125us
movlw .1 ; 2.3750us
movwf byte_count, b ; 2.4375us
movf PORTA, w, a ; 2.5000us
movf PORTB, w, a ; 2.5625us
btfss N64_PIN ; 2.6250us Wait for the data line to go back high.
if ctrl1
btfss N64_PIN ; 2.6250us Wait for the data line to go back high.
else
btfss N64_PIN2
endif
bra $-2 ; 2.6875us
endm

Expand Down Expand Up @@ -473,10 +490,6 @@ bit_loop
ifdef DBG_TRACE
movff INDF1, PORTC
endif
;; Following controller stop bit, got back waiting for host command right away.
;; Some games may send us another read/write within les than 400 us. Polling
;; the GameCube controller and the adaptor mapping work can take up to 500 us.
;; We would then miss a command from the host and the transfer would fail.
endif

return ; 2.2500us
Expand Down
Binary file modified hardware/cube64.pdf
Binary file not shown.
Loading

0 comments on commit fa380ab

Please sign in to comment.