vnIIc/client/client.s

363 lines
9.0 KiB
ArmAsm

;;;-------------------------------------------------------------------
;;;
;;; vnIIc Client Application
;;;
;;;-------------------------------------------------------------------
PADDLE_SUPPORT = 1
;;; MOUSE_SUPPORT = 1
.include "apple2.inc"
.include "macros.inc"
;;;---------------------------------------------------------
;;; Hi-res graphics constants/locations
;;;---------------------------------------------------------
PAGE := $E6 ; Active hires plotting page (Applesoft)
PAGE1 := $20
PAGE2 := $40
PAGESIZE := $20 ; Size of hi-res screen in pages
;;;---------------------------------------------------------
;;; ROM routines
;;;---------------------------------------------------------
PREAD := $FB1E ; Monitor paddle reading routine, call
; with paddle # in X, returns value in Y
HCLR := $F3F2 ; Clear current hires screen to black
;;;---------------------------------------------------------
;;; Other
;;;---------------------------------------------------------
MAX_SLOT := 7 ; Maximum slot # on an Apple II
ZP_PTR := $FA ; Write cursor location on zero page
;;;-------------------------------------------------------------------
;;; Protocol:
;;;-------------------------------------------------------------------
.proc Protocol
Keyboard := $00
Button0 := $10
Button1 := $11
Paddle0 := $20
Paddle1 := $21
MouseX := $30
MouseY := $31
MouseBtn := $32
Screen := $80
.endproc
;;;-------------------------------------------------------------------
;;;
;;; Client Code
;;;
;;;-------------------------------------------------------------------
.org $6000
jmp AppEntry
.include "ssc.inc"
.ifdef MOUSE_SUPPORT
.include "mouse.inc"
.endif
;;;-------------------------------------------------------------------
;;; Variables
;;;-------------------------------------------------------------------
;;; Application configuration
PSPEED: .byte SSC::BPS_115k ; Hardcoded for Apple IIc (TODO: Allow configuration)
PSLOT: .byte 2 ; Hardcoded for Apple IIc (TODO: Allow configuration)
PEXIT: .byte 0 ; Set when it's time to exit (Not Yet Implemented)
;;;---------------------------------------------------------
;;; Initialize the application, and enter the main loop
.proc AppEntry
lda PSLOT ; Use slot 2
jsr SSC::Init ; Initialize Super Serial Card
jsr InitHires ; Initialize Hi-Res graphics
jsr InitInput ; Initialize input devices
jsr MainLoop
;; fall through
.endproc
;;;---------------------------------------------------------
;;; Clean up and exit app
.proc AppExit
jsr SSC::Reset
sta LOWSCR
sta TXTSET
rts
.endproc
;;;-------------------------------------------------------------------
;;;
;;; Main loop functionality
;;;
;;;-------------------------------------------------------------------
;;;---------------------------------------------------------
.proc MainLoop
;;; TODO: Sort out the protocol - should be able to send
;;; input state without receiving data
;;; jsr SSC::HasData ; Anything to read?
;;; bne :+ ; Nope
: jsr ReceivePage
;; Input is sent every 256 bytes (32 times per page)
jsr FlipHires
jmp :- ; TODO: define an exit trigger
rts
.endproc
;;;---------------------------------------------------------
;;; Pull a hi-res page down over serial
;;;
;;; Protocol is:
;;; * Recieve 256 bytes (graphic data)
;;; * Send 1 byte (input state)
.proc ReceivePage
lda #Protocol::Screen
jsr SSC::Put
lda #0 ; data size
jsr SSC::Put
lda #0 ; set up write pointer
sta ZP_PTR
lda PAGE
sta ZP_PTR+1
ldx #PAGESIZE ; plan to receive this many pages
ldy #0
: jsr SSC::Get
sta (ZP_PTR),Y
iny
bne :- ; Do a full page...
;; Interleave to maintain responsiveness
jsr SendInputState
inc ZP_PTR+1
dex
bne :- ; ...as many pages as we need
rts
.endproc
;;;-------------------------------------------------------------------
;;;
;;; Input device routines
;;;
;;;-------------------------------------------------------------------
;;;---------------------------------------------------------
;;; Initialize input devices and storage for detecting
;;; state transitions
.proc InitInput
.ifdef MOUSE_SUPPORT
jsr Mouse::FindMouse
.endif
rts
.endproc
;;;---------------------------------------------------------
;;; Send a full set of input state updates.
;;; Assumes time to transmit is roughly comparable to time
;;; to measure input state, therefore only sending changes is
;;; not worthwhile in most cases.
.proc SendInputState
jsr MaybeSendKeyboard
jsr SendButtons
.ifdef PADDLE_SUPPORT
jsr SendPaddles
.endif
.ifdef MOUSE_SUPPORT
jsr SendMouse
.endif
.endproc
;;;------------------------------------------------------------
;;; Keyboard
;;; NOTE: Can't use KBDSTRB to detect key up -> key down transition
;;; since the msb can change before the key code. Instead, consider
;;; these cases:
;;;
;;; OLD STATE KBD KBDSTRB RESULT
;;; Up Up - No-op
;;; Up Down - Save and send key down
;;; Down - Up Save and send key up
;;; Down - Down Save and send key ONLY if different
;;;
last_kb: .byte 0
.proc MaybeSendKeyboard
lda last_kb
bne key_was_down
key_was_up:
;; Key was up - send only if now down.
lda KBD ; Read keyboard
bpl done ; Do nothing if it is still up.
jmp send ; Otherwise send.
key_was_down:
;; Key was down - strobe should match
;; unless the key changed or was released.
lda KBDSTRB
bmi kbdstrb_down
kbdstrb_up:
lda #0 ; Now released
jmp send
kbdstrb_down:
cmp last_kb ; Same key as last time?
beq done ; - no change, don't send.
jmp send
send: sta last_kb
lda Protocol::Keyboard
jsr SSC::Put
lda #1 ; Data size
jsr SSC::Put
lda last_kb
jsr SSC::Put
done: rts
.endproc
;;;------------------------------------------------------------
;;; Buttons
.proc SendButtons
lda Protocol::Button0
jsr SSC::Put
lda #1 ; Data size
jsr SSC::Put
lda BUTN0
jsr SSC::Put
lda Protocol::Button1
jsr SSC::Put
lda #1 ; Data size
jsr SSC::Put
lda BUTN1
jsr SSC::Put
rts
.endproc
;;;------------------------------------------------------------
;;; Paddles
.ifdef PADDLE_SUPPORT
.proc SendPaddles
lda Protocol::Paddle0
jsr SSC::Put
lda #1 ; Data size
jsr SSC::Put
ldx #0
jsr PREAD
tya
jsr SSC::Put
;; Assumes at least 11 cycles to send, so
;; timer has a chance to reset.
lda Protocol::Paddle1
jsr SSC::Put
lda #1 ; Data size
jsr SSC::Put
ldx #1
jsr PREAD
tya
jsr SSC::Put
rts
.endproc
.endif
;;;-------------------------------------------------------------------
;;;
;;; Hi-res graphics routines
;;;
;;;-------------------------------------------------------------------
;;;---------------------------------------------------------
;;; Set up the graphics display and pointers
.proc InitHires
lda #PAGE1 ; clear page 1
sta PAGE
jsr HCLR
jsr FlipHires ; then show it and flip to 2
sta HIRES
sta TXTCLR
sta MIXCLR
sta LOWSCR
rts
.endproc
;;;---------------------------------------------------------
;;; Call when done with the current plotting page
;;; (selected in PAGE) and it will be shown and the
;;; other page will be shown.
.proc FlipHires
lda PAGE ; plotting on which page?
cmp #PAGE1
beq :+
sta HISCR ; page 2 - so show it
lda #PAGE1 ; and plot on page 1
sta PAGE
rts
: sta LOWSCR ; page 1 - so show it
lda #PAGE2 ; and plot on page 2
sta PAGE
rts
.endproc