Für meine C64 portierung von 2048 (erster Versuch eines C64-Spiels) brauche ich Eingaben als einzelne "Impulse", also dachte ich mir ich baue die Joystick-Abfrage ähnlich wie einen Tastatur-Treiber, mit einer Queue, die nur befüllt wird, wenn sich etwas ändert. "Release" events werden nicht benötigt, allerdings filtere ich im Moment nur den Idle Zustand heraus -- das wäre eventuell noch verbesserungswürdig, ist hier aber erst mal egal. Die erste Version sah so aus:
Code
- .zeropage
- js_buf: .res $10 ; ring buffer
- js_latest: .res 1 ; last value read
- js_front: .res 1 ; front buffer index
- js_back: .res 1 ; back buffer index
- .code
- ; called once per frame from IRQ
- js_check:
- lda CIA1_PRA
- and #$1f ; filter joystick pins
- eor #$1f ; and invert
- beq jc_done ; no input -> only save to latest
- cmp js_latest ; same as last state
- beq jc_done ; -> do nothing
- ldx js_front ; find next index in ring buffer
- dex
- bpl jc_store
- ldx #$f
- jc_store: stx js_front ; store in ring buffer
- sta js_buf,x
- jc_done: sta js_latest
- rts
- ; called from application code, dequeue single element:
- js_get:
- ldx js_back
- cpx js_front
- beq jg_done
- dex
- bpl jg_dequeue
- ldx #$f
- jg_dequeue: stx js_back
- lda js_buf,x
- clc
- jg_done: rts
Das funktionierte schon einwandfrei im vice. Jetzt frage ich mich, ob für diesen Anwendungszweck prellende Taster im echten Joystick ein Problem sind -- testen kann ich das leider gerade nicht, Brotkasten ist außer Gefecht...
Ich hatte folgende Idee zum Entprellen:
Code
- .zeropage
- js_buf: .res $10 ; ring buffer
- js_latest: .res 1 ; last value read
- js_debounce: .res 1 ; last pins changed from 0 to 1
- js_next: .res 1 ; "candidate" value with pins changed to 0
- js_front: .res 1 ; front buffer index
- js_back: .res 1 ; back buffer index
- .code
- ; called once per frame from IRQ
- js_check:
- lda CIA1_PRA
- and #$1f ; filter joystick pins
- eor #$1f ; and invert
- tay ; save to Y
- and js_debounce ; filter pins last changed to 1
- eor js_debounce ; and invert these
- beq jc_nobounce ; if 0, no pins changed back to 0
- cpy js_next ; compare with last "change candidate"
- beq jc_nobounce ; same -> do the change
- sty js_next ; store "change candidate"
- rts ; and return
- jc_nobounce: tya ; input value back to accu
- sta js_debounce ; reference for pins set
- sta js_next ; and init "change candidate"
- beq jc_done ; no input -> only save to latest
- cmp js_latest ; same as last state
- beq jc_done ; -> do nothing
- ldx js_front ; find next index in ring buffer
- dex
- bpl jc_store
- ldx #$f
- jc_store: stx js_front ; store in ring buffer
- sta js_buf,x
- jc_done: sty js_latest
- rts
- ; called from application code, dequeue single element:
- js_get:
- ldx js_back
- cpx js_front
- beq jg_done
- dex
- bpl jg_dequeue
- ldx #$f
- jg_dequeue: stx js_back
- lda js_buf,x
- clc
- jg_done: rts
Die Fragen dazu:
- Ist das überhaupt nötig?
- Wenn ja, tut dieser einfache Code seinen Job?
- (Wie) kann ich das ohne reale Hardware testen? Gibt es einen Emu, der prellende Taster simuliert?