ref: da406973c565c24c089d137d056e03be8451242e
parent: 9102b9a498c1f3073b89367945330b7de6baf016
author: yenatch <[email protected]>
date: Tue Feb 19 18:57:07 EST 2013
Split out joypad
--- a/constants.asm
+++ b/constants.asm
@@ -3417,15 +3417,20 @@
; joypad
-NO_INPUT EQU %00000000
-BUTTON_A EQU %00000001
-BUTTON_B EQU %00000010
-SELECT EQU %00000100
-START EQU %00001000
-D_RIGHT EQU %00010000
-D_LEFT EQU %00100000
-D_UP EQU %01000000
-D_DOWN EQU %10000000
+BUTTONS EQU %00010000
+D_PAD EQU %00100000
+
+AUTO_INPUT EQU $ff
+
+NO_INPUT EQU %00000000
+BUTTON_A EQU %00000001
+BUTTON_B EQU %00000010
+SELECT EQU %00000100
+START EQU %00001000
+D_RIGHT EQU %00010000
+D_LEFT EQU %00100000
+D_UP EQU %01000000
+D_DOWN EQU %10000000
; mbc
NUM_SRAM_BANKS EQU 4
--- /dev/null
+++ b/joypad.asm
@@ -1,0 +1,275 @@
+JoypadInt: ; 92e
+; Replaced by Joypad, called from VBlank instead of the useless
+; joypad interrupt.
+
+; This is a placeholder in case the interrupt is somehow enabled.
+ reti
+; 92f
+
+ClearJoypadPublic: ; 92f
+ xor a
+; Pressed this frame (delta)
+ ld [$ffa7], a
+; Currently pressed
+ ld [$ffa8], a
+ ret
+; 935
+
+Joypad: ; 935
+; Read the joypad register and translate it to something more
+; workable for use in-game. There are 8 buttons, so we can use
+; one byte to contain all player input.
+
+; Updates:
+
+; $ffa2: released this frame (delta)
+; $ffa3: pressed this frame (delta)
+; $ffa4: currently pressed
+; $ffa5: pressed so far
+
+; Any of these three bits can be used to disable input.
+ ld a, [$cfbe]
+ and %11010000
+ ret nz
+
+; If we're saving, input is disabled.
+ ld a, [$c2cd]
+ and a
+ ret nz
+
+; We can only get four inputs at a time.
+; We take d-pad first for no particular reason.
+ ld a, D_PAD
+ ld [$ff00], a
+; Read twice to give the request time to take.
+ ld a, [$ff00]
+ ld a, [$ff00]
+
+; The Joypad register output is in the lo nybble (inversed).
+; We make the hi nybble of our new container d-pad input.
+ cpl
+ and $f
+ swap a
+
+; We'll keep this in b for now.
+ ld b, a
+
+; Buttons make 8 total inputs (A, B, Select, Start).
+; We can fit this into one byte.
+ ld a, BUTTONS
+ ld [$ff00], a
+; Wait for input to stabilize.
+ ld a, [$ff00]
+ ld a, [$ff00]
+ ld a, [$ff00]
+ ld a, [$ff00]
+ ld a, [$ff00]
+ ld a, [$ff00]
+; Buttons take the lo nybble.
+ cpl
+ and $f
+ or b
+ ld b, a
+
+; Reset the joypad register since we're done with it.
+ ld a, $30
+ ld [$ff00], a
+
+; To get the delta we xor the last frame's input with the new one.
+ ld a, [$ffa4] ; last frame
+ ld e, a
+ xor b
+ ld d, a
+; Released this frame:
+ and e
+ ld [$ffa2], a
+; Pressed this frame:
+ ld a, d
+ and b
+ ld [$ffa3], a
+
+; Add any new presses to the list of collective presses:
+ ld c, a
+ ld a, [$ffa5]
+ or c
+ ld [$ffa5], a
+
+; Currently pressed:
+ ld a, b
+ ld [$ffa4], a
+
+; Now that we have the input, we can do stuff with it.
+
+; For example, soft reset:
+ and BUTTON_A | BUTTON_B | SELECT | START
+ cp BUTTON_A | BUTTON_B | SELECT | START
+ jp z, $0150 ; reset
+
+ ret
+; 984
+
+
+GetJoypadPublic: ; 984
+; Update mirror joypad input from $ffa4 (real input)
+
+; $ffa6: released this frame (delta)
+; $ffa7: pressed this frame (delta)
+; $ffa8: currently pressed
+
+; bit 0 A
+; 1 B
+; 2 SELECT
+; 3 START
+; 4 RIGHT
+; 5 LEFT
+; 6 UP
+; 7 DOWN
+
+ push af
+ push hl
+ push de
+ push bc
+
+; The player input can be automated using an input stream.
+; See more below.
+ ld a, [InputType]
+ cp a, AUTO_INPUT
+ jr z, .auto
+
+; To get deltas, take this and last frame's input.
+ ld a, [$ffa4] ; real input
+ ld b, a
+ ld a, [$ffa8] ; last frame mirror
+ ld e, a
+
+; Released this frame:
+ xor b
+ ld d, a
+ and e
+ ld [$ffa6], a
+
+; Pressed this frame:
+ ld a, d
+ and b
+ ld [$ffa7], a
+
+; It looks like the collective presses got commented out here.
+ ld c, a
+
+; Currently pressed:
+ ld a, b
+ ld [$ffa8], a ; frame input
+
+.quit
+ pop bc
+ pop de
+ pop hl
+ pop af
+ ret
+
+.auto
+; Use a predetermined input stream (used in the catching tutorial).
+
+; Stream format: [input][duration]
+; A value of $ff will immediately end the stream.
+
+; Read from the input stream.
+ ld a, [$ff9d]
+ push af
+ ld a, [AutoInputBank]
+ rst Bankswitch
+
+ ld hl, AutoInputAddress
+ ld a, [hli]
+ ld h, [hl]
+ ld l, a
+
+; We only update when the input duration has expired.
+ ld a, [AutoInputLength]
+ and a
+ jr z, .updateauto
+
+; Until then, don't change anything.
+ dec a
+ ld [AutoInputLength], a
+ pop af
+ rst Bankswitch
+ jr .quit
+
+
+.updateauto
+; An input of $ff will end the stream.
+ ld a, [hli]
+ cp a, $ff
+ jr z, .stopauto
+ ld b, a
+
+; A duration of $ff will end the stream indefinitely.
+ ld a, [hli]
+ ld [AutoInputLength], a
+ cp a, $ff
+ jr nz, .next
+
+; The current input is overwritten.
+ dec hl
+ dec hl
+ ld b, NO_INPUT
+ jr .finishauto
+
+.next
+; On to the next input...
+ ld a, l
+ ld [AutoInputAddress], a
+ ld a, h
+ ld [AutoInputAddress+1], a
+ jr .finishauto
+
+.stopauto
+ call StopAutoInput
+ ld b, NO_INPUT
+
+.finishauto
+ pop af
+ rst Bankswitch
+ ld a, b
+ ld [$ffa7], a ; pressed
+ ld [$ffa8], a ; input
+ jr .quit
+; 9ee
+
+
+StartAutoInput: ; 9ee
+; Start reading automated input stream at a:hl.
+
+ ld [AutoInputBank], a
+ ld a, l
+ ld [AutoInputAddress], a
+ ld a, h
+ ld [AutoInputAddress+1], a
+; Start reading the stream immediately.
+ xor a
+ ld [AutoInputLength], a
+; Reset input mirrors.
+ xor a
+ ld [$ffa7], a ; pressed this frame
+ ld [$ffa6], a ; released this frame
+ ld [$ffa8], a ; currently pressed
+
+ ld a, AUTO_INPUT
+ ld [InputType], a
+ ret
+; a0a
+
+
+StopAutoInput: ; a0a
+; Clear variables related to automated input.
+ xor a
+ ld [AutoInputBank], a
+ ld [AutoInputAddress], a
+ ld [AutoInputAddress+1], a
+ ld [AutoInputLength], a
+; Back to normal input.
+ ld [InputType], a
+ ret
+; a1b
+
--- a/main.asm
+++ b/main.asm
@@ -47,7 +47,7 @@
jp $06ef
SECTION "joypad",HOME[$60] ; joypad interrupt
- jp $092e
+ jp JoypadInt
SECTION "romheader",HOME[$100]
Start:
@@ -425,252 +425,11 @@
ret
; 6c4
-INCBIN "baserom.gbc",$6c4,$935 - $6c4
+INCBIN "baserom.gbc",$6c4,$92e - $6c4
-Joypad: ; 935
-; update joypad state
-; $ffa2: released
-; $ffa3: pressed
-; $ffa4: input
-; $ffa5: total pressed
-;
- ld a, [$cfbe]
- and $d0
- ret nz
-
-; pause game update?
- ld a, [$c2cd]
- and a
- ret nz
-
-; d-pad
- ld a, $20
- ld [$ff00], a
- ld a, [$ff00]
- ld a, [$ff00]
-; hi nybble
- cpl
- and $f
- swap a
- ld b, a
-
-; buttons
- ld a, $10
- ld [$ff00], a
-; wait to stabilize
- ld a, [$ff00]
- ld a, [$ff00]
- ld a, [$ff00]
- ld a, [$ff00]
- ld a, [$ff00]
- ld a, [$ff00]
-; lo nybble
- cpl
- and $f
- or b
- ld b, a
-
-; reset joypad
- ld a, $30
- ld [$ff00], a
-
-; get change in input
- ld a, [$ffa4] ; last frame's input
- ld e, a
- xor b ; current frame input
- ld d, a
-; released
- and e
- ld [$ffa2], a
-; pressed
- ld a, d
- and b
- ld [$ffa3], a
-
-; total pressed
- ld c, a
- ld a, [$ffa5]
- or c
- ld [$ffa5], a
-
-; original input
- ld a, b
- ld [$ffa4], a
-
-; A+B+SELECT+START
- and $f
- cp $f
- jp z, $0150 ; reset
-
- ret
-; 984
+INCLUDE "joypad.asm"
-
-GetJoypadPublic: ; 984
-; update mirror joypad input from $ffa4 (real input)
-
-; $ffa6: released
-; $ffa7: pressed
-; $ffa8: input
-
-; bit 0 A
-; 1 B
-; 2 SELECT
-; 3 START
-; 4 RIGHT
-; 5 LEFT
-; 6 UP
-; 7 DOWN
-
- push af
- push hl
- push de
- push bc
-
-; automated input?
- ld a, [InputType]
- cp a, $ff ; INPUT_AUTO
- jr z, .auto
-
-; get input
- ld a, [$ffa4] ; real input
- ld b, a
- ld a, [$ffa8] ; last frame mirror
- ld e, a
-
-; released
- xor b
- ld d, a
- and e
- ld [$ffa6], a
-
-; pressed
- ld a, d
- and b
- ld [$ffa7], a
-
-; leftover from pasted code
- ld c, a
-
-;
- ld a, b
- ld [$ffa8], a ; frame input
-.quit
- pop bc
- pop de
- pop hl
- pop af
- ret
-
-.auto
-; use predetermined input feed (used in catch tutorial)
-; struct: [input][duration]
-
-; save bank
- ld a, [$ff9d]
- push af
-;
- ld a, [AutoInputBank]
- rst Bankswitch
-;
- ld hl, AutoInputAddress ; AutoInputAddress-9
- ld a, [hli]
- ld h, [hl]
- ld l, a
-
-; update when frame count hits 0
- ld a, [AutoInputLength]
- and a
- jr z, .updateauto
-
-; until then, do nothing
- dec a
- ld [AutoInputLength], a
-; restore bank
- pop af
- rst Bankswitch
-; we're done
- jr .quit
-
-.updateauto
-; get input
- ld a, [hli]
-; stop?
- cp a, $ff
- jr z, .stopinput
- ld b, a
-
-; duration
- ld a, [hli]
- ld [AutoInputLength], a
-; duration $ff = end at input
- cp a, $ff
- jr nz, .next
-
-; no input
- dec hl
- dec hl
- ld b, $00 ; no input
- jr .finishauto
-
-.next
-; output recorded
- ld a, l
- ld [AutoInputAddress], a
- ld a, h
- ld [AutoInputAddress+1], a
- jr .finishauto
-
-.stopinput
- call StopAutoInput
- ld b, $00 ; no input
-
-.finishauto
-; restore bank
- pop af
- rst Bankswitch
-; update mirrors
- ld a, b
- ld [$ffa7], a ; pressed
- ld [$ffa8], a ; input
- jr .quit
-; 9ee
-
-StartAutoInput: ; 9ee
-; start auto input stream at a:hl
-; bank
- ld [AutoInputBank], a
-; address
- ld a, l
- ld [AutoInputAddress], a
- ld a, h
- ld [AutoInputAddress+1], a
-; don't wait to update
- xor a
- ld [AutoInputLength], a
-; clear input mirrors
- xor a
- ld [$ffa7], a ; pressed
- ld [$ffa6], a ; released
- ld [$ffa8], a ; input
-; start reading input stream instead of player input
- ld a, $ff ; INPUT_AUTO
- ld [InputType], a
- ret
-; a0a
-
-StopAutoInput: ; a0a
-; clear autoinput ram
- xor a
- ld [AutoInputBank], a
- ld [AutoInputAddress], a
- ld [AutoInputAddress+1], a
- ld [AutoInputLength], a
-; normal input
- ld [InputType], a
- ret
-; a1b
INCBIN "baserom.gbc",$a1b,$b40 - $a1b