mirror of https://github.com/a2stuff/vnIIc.git
Add client
This commit is contained in:
parent
44ffbdc794
commit
395231b916
|
@ -0,0 +1,23 @@
|
|||
|
||||
CC65 = ~/dev/cc65/bin
|
||||
CAFLAGS = --target apple2enh --list-bytes 0
|
||||
CCFLAGS = --config apple2-asm.cfg
|
||||
|
||||
TARGETS = \
|
||||
client.bin
|
||||
|
||||
.PHONY: clean all
|
||||
all: $(TARGETS)
|
||||
|
||||
HEADERS = $(wildcard *.inc)
|
||||
|
||||
clean:
|
||||
rm -f *.o
|
||||
rm -f *.list
|
||||
rm -f $(TARGETS)
|
||||
|
||||
%.o: %.s $(HEADERS)
|
||||
$(CC65)/ca65 $(CAFLAGS) $(DEFINES) --listing $(basename $@).list -o $@ $<
|
||||
|
||||
%.bin: %.o
|
||||
$(CC65)/ld65 $(CCFLAGS) -o $@ $<
|
Binary file not shown.
|
@ -0,0 +1,933 @@
|
|||
ca65 V2.16 - Git f5e9b401
|
||||
Main file : client.s
|
||||
Current file: client.s
|
||||
|
||||
000000r 1
|
||||
000000r 1 PADDLE_SUPPORT = 1
|
||||
000000r 1 ;MOUSE_SUPPORT = 1 ; NOTE: tests for ifdef
|
||||
000000r 1
|
||||
000000r 1 ;---------------------------------------------------------
|
||||
000000r 1 ; Super Serial constants/locations
|
||||
000000r 1 ;---------------------------------------------------------
|
||||
000000r 1
|
||||
000000r 1 ; These get incremented by the slot where they appear
|
||||
000000r 1 UACTRL = $C08B ; Control Register
|
||||
000000r 1 UACMND = $C08A ; Command Register
|
||||
000000r 1 UASTAT = $C089 ; Status Register
|
||||
000000r 1 UADATA = $C088 ; Data Register - incoming and outgoing data
|
||||
000000r 1
|
||||
000000r 1
|
||||
000000r 1 ;---------------------------------------------------------
|
||||
000000r 1 ; Hi-res graphics constants/locations
|
||||
000000r 1 ;---------------------------------------------------------
|
||||
000000r 1
|
||||
000000r 1 PLOTPAGE = $E6 ; Active hires plotting page (Applesoft)
|
||||
000000r 1 PLOTPAGE1 = $20
|
||||
000000r 1 PLOTPAGE2 = $40
|
||||
000000r 1 PAGESIZE = $20 ; Size of hi-res screen in pages
|
||||
000000r 1
|
||||
000000r 1
|
||||
000000r 1 CLRTEXT = $C050 ;display graphics
|
||||
000000r 1 SETTEXT = $C051 ;display text
|
||||
000000r 1 CLRMIXED = $C052 ;clear mixed mode- enable full graphics
|
||||
000000r 1 SETMIXED = $C053 ;enable graphics/text mixed mode
|
||||
000000r 1 PAGE1 = $C054 ;select text/graphics page1
|
||||
000000r 1 PAGE2 = $C055 ;select text/graphics page2
|
||||
000000r 1 CLRHIRES = $C056 ;select Lo-res
|
||||
000000r 1 SETHIRES = $C057 ;select Hi-res
|
||||
000000r 1
|
||||
000000r 1
|
||||
000000r 1 ;---------------------------------------------------------
|
||||
000000r 1 ; Keyboard input constants/locations
|
||||
000000r 1 ;---------------------------------------------------------
|
||||
000000r 1
|
||||
000000r 1 KEYBD = $C000 ; key down in bit 7; key code in lower bits
|
||||
000000r 1 STROBE = $C010 ; write to clear key down state
|
||||
000000r 1 OPNAPPLE = $C061 ; open apple (command) key data (read)
|
||||
000000r 1 CLSAPPLE = $C062 ; closed apple (option) key data (read)
|
||||
000000r 1 PB2 = $C063 ; Paddle button 2 (read)
|
||||
000000r 1 PB3 = $C060 ; Paddle button 3 (read)
|
||||
000000r 1
|
||||
000000r 1
|
||||
000000r 1 ;---------------------------------------------------------
|
||||
000000r 1 ; Paddle/Joystick constants/locations/routines
|
||||
000000r 1 ;---------------------------------------------------------
|
||||
000000r 1
|
||||
000000r 1 PADDLE0 = $C064 ; bit 7 = status of pdl-0 timer (read)
|
||||
000000r 1 PADDLE1 = $C065 ; bit 7 = status of pdl-1 timer (read)
|
||||
000000r 1 PADDLE2 = $C066 ; bit 7 = status of pdl-2 timer (read)
|
||||
000000r 1 PADDLE3 = $C067 ; bit 7 = status of pdl-3 timer (read)
|
||||
000000r 1 PDLTRIG = $C070 ; trigger paddles
|
||||
000000r 1
|
||||
000000r 1 PREAD = $FB1E ; Monitor paddle reading routine, call
|
||||
000000r 1 ; with paddle # in X, returns value in Y
|
||||
000000r 1
|
||||
000000r 1
|
||||
000000r 1 ;--------------------------------------------------
|
||||
000000r 1 ; Mouse locations and constants
|
||||
000000r 1 ;--------------------------------------------------
|
||||
000000r 1
|
||||
000000r 1 ; For READMOUSE and POSMOUSE
|
||||
000000r 1
|
||||
000000r 1 MOUSE_X_LSB = $0478 ; + slot Low byte of absolute X position
|
||||
000000r 1 MOUSE_X_MSB = $0578 ; + slot High byte of absolute X position
|
||||
000000r 1 MOUSE_Y_LSB = $04F8 ; + slot Low byte of absolute Y position
|
||||
000000r 1 MOUSE_Y_MSB = $05F8 ; + slot High byte of absolute Y position
|
||||
000000r 1 MOUSE_RSV1 = $0678 ; + slot Reserved and used by the firmware
|
||||
000000r 1 MOUSE_RSV2 = $06F8 ; + slot Reserved and used by the firmware
|
||||
000000r 1 MOUSE_BTN = $0778 ; + slot Button 0/1 interrupt status byte
|
||||
000000r 1 MOUSE_MODE = $07F8 ; + slot Mode byte
|
||||
000000r 1
|
||||
000000r 1 ; For CLAMPMOUSE:
|
||||
000000r 1
|
||||
000000r 1 MOUSE_CMIN_LSB = $0478 ; low byte of low clamp
|
||||
000000r 1 MOUSE_CMIN_MSB = $0578 ; high byte of low clamp
|
||||
000000r 1 MOUSE_CMAX_LSB = $04F8 ; low byte of high clamp
|
||||
000000r 1 MOUSE_CMAX_MSB = $05F8 ; high byte of high clamp
|
||||
000000r 1
|
||||
000000r 1 MOUSE_CLAMP_X = 0 ; Value for A when setting X clamp with CLAMPMOUSE
|
||||
000000r 1 MOUSE_CLAMP_Y = 1 ; Value for A when setting X clamp with CLAMPMOUSE
|
||||
000000r 1
|
||||
000000r 1
|
||||
000000r 1 ;---------------------------------------------------------
|
||||
000000r 1 ; Other
|
||||
000000r 1 ;---------------------------------------------------------
|
||||
000000r 1
|
||||
000000r 1 SLOT_CASE = $c000 ; Firmware for slots are at $cx00
|
||||
000000r 1 MAX_SLOT = 7 ; Maximum slot # on an Apple II
|
||||
000000r 1
|
||||
000000r 1 ZP = $FA ; Write cursor location on zero page
|
||||
000000r 1 ESCAPE = $80 ; Unused image data byte (all black2)
|
||||
000000r 1 ESCAPE2 = $FF ; Unused image data byte (all white2)
|
||||
000000r 1
|
||||
000000r 1
|
||||
000000r 1 ;---------------------------------------------------------
|
||||
000000r 1 ; Generic Macros
|
||||
000000r 1 ;---------------------------------------------------------
|
||||
000000r 1
|
||||
000000r 1 ;----------------------------------------
|
||||
000000r 1 .macro SaveRegisters
|
||||
000000r 1 ;----------------------------------------
|
||||
000000r 1 pha
|
||||
000000r 1 txa
|
||||
000000r 1 pha
|
||||
000000r 1 tya
|
||||
000000r 1 pha
|
||||
000000r 1 .endmacro
|
||||
000000r 1
|
||||
000000r 1 ;----------------------------------------
|
||||
000000r 1 .macro RestoreRegisters
|
||||
000000r 1 ;----------------------------------------
|
||||
000000r 1 pla
|
||||
000000r 1 tay
|
||||
000000r 1 pla
|
||||
000000r 1 tax
|
||||
000000r 1 pla
|
||||
000000r 1 .endmacro
|
||||
000000r 1
|
||||
000000r 1
|
||||
000000r 1 ;-------------------------------------------------------------------
|
||||
000000r 1 ;
|
||||
000000r 1 ; Application-level logic
|
||||
000000r 1 ;
|
||||
000000r 1 ;-------------------------------------------------------------------
|
||||
000000r 1
|
||||
000000r 1
|
||||
000000r 1 .ORG $6000
|
||||
006000 1
|
||||
006000 1 ;---------------------------------------------------------
|
||||
006000 1 .proc APP_ENTRY
|
||||
006000 1 ;---------------------------------------------------------
|
||||
006000 1 ; Initialize the application, and enter the main loop
|
||||
006000 1 ;---------------------------------------------------------
|
||||
006000 1 AD C7 61 lda PSLOT ; Use slot 2
|
||||
006003 1 20 71 61 jsr INITSSC ; Initialize Super Serial Card
|
||||
006006 1 20 2C 61 jsr INITHIRES ; Initialize Hi-Res graphics
|
||||
006009 1 20 40 60 jsr INITINPUT ; Initialize input devices
|
||||
00600C 1 20 19 60 jsr MAINLOOP
|
||||
00600F 1
|
||||
00600F 1 ; fall through
|
||||
00600F 1 .endproc
|
||||
00600F 1
|
||||
00600F 1 ;---------------------------------------------------------
|
||||
00600F 1 .proc APP_EXIT
|
||||
00600F 1 ;---------------------------------------------------------
|
||||
00600F 1 ; Clean up and exit app
|
||||
00600F 1 ;---------------------------------------------------------
|
||||
00600F 1 20 BE 61 jsr RESETSSC
|
||||
006012 1 8D 54 C0 sta PAGE1
|
||||
006015 1 8D 51 C0 sta SETTEXT
|
||||
006018 1 60 rts
|
||||
006019 1 .endproc
|
||||
006019 1
|
||||
006019 1
|
||||
006019 1 ;-------------------------------------------------------------------
|
||||
006019 1 ;
|
||||
006019 1 ; Main loop functionality
|
||||
006019 1 ;
|
||||
006019 1 ;-------------------------------------------------------------------
|
||||
006019 1
|
||||
006019 1
|
||||
006019 1 ;---------------------------------------------------------
|
||||
006019 1 .proc MAINLOOP
|
||||
006019 1 ;---------------------------------------------------------
|
||||
006019 1
|
||||
006019 1 ; TODO: Sort out the protocol - should be able to send
|
||||
006019 1 ; input state without receiving data
|
||||
006019 1 ; jsr SSCHASDATA ; Anything to read?
|
||||
006019 1 ; bne :+ ; Nope
|
||||
006019 1
|
||||
006019 1 20 23 60 : jsr RECEIVEPAGE
|
||||
00601C 1 20 43 61 jsr FLIPHIRES
|
||||
00601F 1 4C 19 60 jmp :- ; TODO: define an exit trigger
|
||||
006022 1 60 rts
|
||||
006023 1 .endproc
|
||||
006023 1
|
||||
006023 1
|
||||
006023 1 ;---------------------------------------------------------
|
||||
006023 1 .proc RECEIVEPAGE
|
||||
006023 1 ;---------------------------------------------------------
|
||||
006023 1 ; Pull a hi-res page down over serial
|
||||
006023 1 ;
|
||||
006023 1 ; Protocol is:
|
||||
006023 1 ; * Recieve 256 bytes (graphic data)
|
||||
006023 1 ; * Send 1 byte (input state)
|
||||
006023 1 ;---------------------------------------------------------
|
||||
006023 1
|
||||
006023 1 A9 00 lda #0 ; set up write pointer
|
||||
006025 1 85 FA sta ZP
|
||||
006027 1 A5 E6 lda PLOTPAGE
|
||||
006029 1 85 FB sta ZP+1
|
||||
00602B 1 A2 20 ldx #PAGESIZE ; plan to receive this many pages
|
||||
00602D 1 A0 00 ldy #0
|
||||
00602F 1
|
||||
00602F 1 20 A9 61 : jsr SSCGET ; TODO: look for escape codes in the sequence
|
||||
006032 1 91 FA sta (ZP),Y
|
||||
006034 1 C8 iny
|
||||
006035 1 D0 F8 bne :- ; Do a full page...
|
||||
006037 1
|
||||
006037 1 20 5E 60 jsr SENDINPUTSTATE ; brief moment to send data back upstream
|
||||
00603A 1
|
||||
00603A 1 E6 FB inc ZP+1
|
||||
00603C 1 CA dex
|
||||
00603D 1 D0 F0 bne :- ; ...as many pages as we need
|
||||
00603F 1 60 rts
|
||||
006040 1 .endproc
|
||||
006040 1
|
||||
006040 1
|
||||
006040 1 ;-------------------------------------------------------------------
|
||||
006040 1 ;
|
||||
006040 1 ; Input device routines
|
||||
006040 1 ;
|
||||
006040 1 ;-------------------------------------------------------------------
|
||||
006040 1 ; Protocol:
|
||||
006040 1 ; $7f - $ff - key down, ASCII code + $80
|
||||
006040 1 ; otherwise, a transition:
|
||||
006040 1 ;
|
||||
006040 1 SIS_KBUP = $00 ; Key up
|
||||
006040 1 SIS_OADOWN = $01 ; Open Apple transitioned to down
|
||||
006040 1 SIS_OAUP = $02 ; Open Apple transitioned to up
|
||||
006040 1 SIS_CADOWN = $03 ; Closed Apple transitioned to down
|
||||
006040 1 SIS_CAUP = $04 ; Closed Apple transitioned to up
|
||||
006040 1 ;
|
||||
006040 1 ; $05 - $0f : reserved
|
||||
006040 1 ;
|
||||
006040 1 SIS_MX = $10 ; Mouse X high nibble
|
||||
006040 1 SIS_MY = $20 ; Mouse Y high nibble
|
||||
006040 1 SIS_PDL0 = $30 ; Paddle 0 high nibble
|
||||
006040 1 SIS_PDL1 = $40 ; Paddle 1 high nibble
|
||||
006040 1 ;
|
||||
006040 1 ; $50 - $7e : reserved
|
||||
006040 1 ;
|
||||
006040 1 SIS_SYNC = $7f
|
||||
006040 1
|
||||
006040 1 ;---------------------------------------------------------
|
||||
006040 1 .proc INITINPUT
|
||||
006040 1 ;---------------------------------------------------------
|
||||
006040 1 ; Initialize input devices and storage for detecting
|
||||
006040 1 ; state transitions
|
||||
006040 1 ;---------------------------------------------------------
|
||||
006040 1
|
||||
006040 1 ; Init keyboard state
|
||||
006040 1 A9 00 lda #SIS_KBUP
|
||||
006042 1 8D C9 61 sta LASTKB
|
||||
006045 1
|
||||
006045 1 ; Init Open/Closed Apple states
|
||||
006045 1 A9 02 lda #SIS_OAUP ; NOTE: Don't store OA state as it fluctuates
|
||||
006047 1 8D CA 61 sta LASTOA
|
||||
00604A 1 A9 04 lda #SIS_CAUP ; NOTE: Don't store CA state as it fluctuates
|
||||
00604C 1 8D CB 61 sta LASTCA
|
||||
00604F 1
|
||||
00604F 1 .ifdef PADDLE_SUPPORT
|
||||
00604F 1 ; Init Paddle state
|
||||
00604F 1 A9 30 lda #SIS_PDL0
|
||||
006051 1 09 08 ora #8 ; Middle of range 0...15
|
||||
006053 1 8D CC 61 sta LASTP0
|
||||
006056 1 A9 40 lda #SIS_PDL1
|
||||
006058 1 09 08 ora #8 ; Middle of range 0...15
|
||||
00605A 1 8D CD 61 sta LASTP1
|
||||
00605D 1 .endif
|
||||
00605D 1
|
||||
00605D 1 .ifdef MOUSE_SUPPORT
|
||||
00605D 1 jsr FINDMOUSE
|
||||
00605D 1 .endif
|
||||
00605D 1
|
||||
00605D 1 60 rts
|
||||
00605E 1 .endproc
|
||||
00605E 1
|
||||
00605E 1
|
||||
00605E 1 ;---------------------------------------------------------
|
||||
00605E 1 .proc SENDINPUTSTATE
|
||||
00605E 1 ;---------------------------------------------------------
|
||||
00605E 1 ; Send keyboard joystick and/or mouse state over the
|
||||
00605E 1 ; serial port
|
||||
00605E 1 ;
|
||||
00605E 1 ; Algorithm:
|
||||
00605E 1 ; - Send key state (if it changed)
|
||||
00605E 1 ; - otherwise send open-apple state (if it changed)
|
||||
00605E 1 ; - otherwise send closed-apple state (if it changed)
|
||||
00605E 1 ; - otherwise send paddle 0 state (if it changed)
|
||||
00605E 1 ; - (TODO: Mouse state)
|
||||
00605E 1 ; - otherwise send sync byte
|
||||
00605E 1 ;---------------------------------------------------------
|
||||
00605E 1
|
||||
00605E 1 48 8A 48 98 SaveRegisters ; Store registers
|
||||
006062 1 48
|
||||
006063 1 18 clc
|
||||
006064 1
|
||||
006064 1 ;--------------------------------------
|
||||
006064 1 ; Send key state, if it changed
|
||||
006064 1
|
||||
006064 1 ; NOTE: Can't use STROBE to detect key up -> key down transition
|
||||
006064 1 ; since the msb can change before the key code. Instead, consider
|
||||
006064 1 ; these cases:
|
||||
006064 1 ;
|
||||
006064 1 ; OLD STATE KEYBD STROBE RESULT
|
||||
006064 1 ; Up Up - No-op
|
||||
006064 1 ; Up Down - Save and send key down
|
||||
006064 1 ; Down - Up Save and send key up
|
||||
006064 1 ; Down - Down Save and send key ONLY if different
|
||||
006064 1 ;
|
||||
006064 1
|
||||
006064 1 AD C9 61 lda LASTKB
|
||||
006067 1 D0 0E bne KEY_WAS_DOWN
|
||||
006069 1
|
||||
006069 1 KEY_WAS_UP:
|
||||
006069 1 AD 00 C0 lda KEYBD ; Read keyboard
|
||||
00606C 1 10 27 bpl END_KEY ; - still up
|
||||
00606E 1 8D C9 61 sta LASTKB ; Down, so save it
|
||||
006071 1 20 9A 61 jsr SSCPUT ; and send it
|
||||
006074 1 4C 26 61 jmp DONE
|
||||
006077 1
|
||||
006077 1 KEY_WAS_DOWN:
|
||||
006077 1 ; key was down - strobe should match
|
||||
006077 1 ; unless the key changed or was released
|
||||
006077 1 AD 10 C0 lda STROBE
|
||||
00607A 1 30 0B bmi STROBE_DOWN
|
||||
00607C 1 STROBE_UP:
|
||||
00607C 1 A9 00 lda #SIS_KBUP ; Key was released
|
||||
00607E 1 8D C9 61 sta LASTKB ; so save it
|
||||
006081 1 20 9A 61 jsr SSCPUT ; and send it
|
||||
006084 1 4C 26 61 jmp DONE
|
||||
006087 1 STROBE_DOWN:
|
||||
006087 1 CD C9 61 cmp LASTKB ; Same key as last time?
|
||||
00608A 1 F0 09 beq END_KEY ; - no change
|
||||
00608C 1 8D C9 61 sta LASTKB ; New key, so save it
|
||||
00608F 1 20 9A 61 jsr SSCPUT ; and send it
|
||||
006092 1 4C 26 61 jmp DONE
|
||||
006095 1
|
||||
006095 1 END_KEY:
|
||||
006095 1
|
||||
006095 1 ;--------------------------------------
|
||||
006095 1 ; Send Open Apple state, if it changed
|
||||
006095 1
|
||||
006095 1 ; TODO: Can simplify this code if we make the high bits the same
|
||||
006095 1 ; for both OA states and bit = 0 down: lda OPNAPPLE ; ROL ; LDA #0 ; ROL ; ORA #signature
|
||||
006095 1
|
||||
006095 1 TEST_OA:
|
||||
006095 1 AD 61 C0 lda OPNAPPLE ; Test Open Apple state
|
||||
006098 1 30 10 bmi OA_IS_DOWN
|
||||
00609A 1 OA_IS_UP:
|
||||
00609A 1 A9 02 lda #SIS_OAUP
|
||||
00609C 1 CD CA 61 cmp LASTOA ; Changed?
|
||||
00609F 1 F0 19 beq END_OA ; Nope
|
||||
0060A1 1 8D CA 61 sta LASTOA ; Yes, save it / send it!
|
||||
0060A4 1 20 9A 61 jsr SSCPUT
|
||||
0060A7 1 4C 26 61 jmp DONE
|
||||
0060AA 1 OA_IS_DOWN:
|
||||
0060AA 1 A9 01 lda #SIS_OADOWN
|
||||
0060AC 1 CD CA 61 cmp LASTOA ; Changed?
|
||||
0060AF 1 F0 09 beq END_OA ; Nope
|
||||
0060B1 1 8D CA 61 sta LASTOA ; Yes, save it / send it!
|
||||
0060B4 1 20 9A 61 jsr SSCPUT
|
||||
0060B7 1 4C 26 61 jmp DONE
|
||||
0060BA 1
|
||||
0060BA 1 END_OA:
|
||||
0060BA 1
|
||||
0060BA 1 ;--------------------------------------
|
||||
0060BA 1 ; Send Closed Apple state, if it changed
|
||||
0060BA 1
|
||||
0060BA 1 TEST_CA:
|
||||
0060BA 1 AD 62 C0 lda CLSAPPLE ; Has the Open Apple/Button 1 value changed?
|
||||
0060BD 1 30 10 bmi CA_IS_DOWN
|
||||
0060BF 1 CA_IS_UP:
|
||||
0060BF 1 A9 04 lda #SIS_CAUP
|
||||
0060C1 1 CD CB 61 cmp LASTCA ; Changed?
|
||||
0060C4 1 F0 19 beq END_CA ; Nope
|
||||
0060C6 1 8D CB 61 sta LASTCA ; Yes, save it
|
||||
0060C9 1 20 9A 61 jsr SSCPUT ; and send it
|
||||
0060CC 1 4C 26 61 jmp DONE
|
||||
0060CF 1 CA_IS_DOWN:
|
||||
0060CF 1 A9 03 lda #SIS_CADOWN
|
||||
0060D1 1 CD CB 61 cmp LASTCA ; Changed?
|
||||
0060D4 1 F0 09 beq END_CA ; Nope
|
||||
0060D6 1 8D CB 61 sta LASTCA ; Yes, save it
|
||||
0060D9 1 20 9A 61 jsr SSCPUT ; and send it
|
||||
0060DC 1 4C 26 61 jmp DONE
|
||||
0060DF 1
|
||||
0060DF 1 END_CA:
|
||||
0060DF 1
|
||||
0060DF 1 .ifdef PADDLE_SUPPORT
|
||||
0060DF 1
|
||||
0060DF 1 ;--------------------------------------
|
||||
0060DF 1 ; Send Paddle 0 state, if it changed
|
||||
0060DF 1 TEST_PDL0:
|
||||
0060DF 1 A2 00 ldx #0
|
||||
0060E1 1 20 1E FB jsr PREAD
|
||||
0060E4 1 98 tya
|
||||
0060E5 1 4A lsr ; Shift to low nibble
|
||||
0060E6 1 4A lsr
|
||||
0060E7 1 4A lsr
|
||||
0060E8 1 4A lsr
|
||||
0060E9 1 09 30 ora #SIS_PDL0 ; And mark it with the signature
|
||||
0060EB 1 CD CC 61 cmp LASTP0 ; Change?
|
||||
0060EE 1 F0 09 beq END_PDL0 ; Nope
|
||||
0060F0 1 8D CC 61 sta LASTP0 ; Yes, save it
|
||||
0060F3 1 20 9A 61 jsr SSCPUT ; and send it
|
||||
0060F6 1 4C 26 61 jmp DONE
|
||||
0060F9 1 END_PDL0:
|
||||
0060F9 1 ; Chew up time so next paddle read will be correct
|
||||
0060F9 1 ; TODO: Replace this with a "read both" strobes
|
||||
0060F9 1 ; routine
|
||||
0060F9 1 EA EA EA EA : .repeat 11 ; By experiment, need 11 NOPs.
|
||||
0060FD 1 EA EA EA EA
|
||||
006101 1 EA EA EA
|
||||
006104 1 nop
|
||||
006104 1 .endrep
|
||||
006104 1 C8 iny
|
||||
006105 1 D0 F2 bne :-
|
||||
006107 1
|
||||
006107 1 ;--------------------------------------
|
||||
006107 1 ; Send Paddle 1 state, if it changed
|
||||
006107 1 TEST_PDL1:
|
||||
006107 1 A2 01 ldx #1
|
||||
006109 1 20 1E FB jsr PREAD
|
||||
00610C 1 98 tya
|
||||
00610D 1 4A lsr ; Shift to low nibble
|
||||
00610E 1 4A lsr
|
||||
00610F 1 4A lsr
|
||||
006110 1 4A lsr
|
||||
006111 1 09 40 ora #SIS_PDL1 ; And mark it with the signature
|
||||
006113 1 CD CD 61 cmp LASTP1 ; Change?
|
||||
006116 1 F0 09 beq END_PDL1 ; Nope
|
||||
006118 1 8D CD 61 sta LASTP1 ; Yes, save it
|
||||
00611B 1 20 9A 61 jsr SSCPUT ; and send it
|
||||
00611E 1 4C 26 61 jmp DONE
|
||||
006121 1 END_PDL1:
|
||||
006121 1 ; NOTE: No need to chew time like PDL0
|
||||
006121 1 ; since data receive will make up for it; if we
|
||||
006121 1 ; loop in SENDINPUTSTATE need to add it here
|
||||
006121 1
|
||||
006121 1 .endif
|
||||
006121 1
|
||||
006121 1
|
||||
006121 1 ;--------------------------------------
|
||||
006121 1 .ifdef MOUSE_SUPPORT
|
||||
006121 1 .error "Mouse support not fully implemented"
|
||||
006121 1 .endif
|
||||
006121 1
|
||||
006121 1 ;--------------------------------------
|
||||
006121 1 ; No state changes so send sync byte
|
||||
006121 1
|
||||
006121 1 A9 7F lda #SIS_SYNC
|
||||
006123 1 20 9A 61 jsr SSCPUT
|
||||
006126 1
|
||||
006126 1 DONE:
|
||||
006126 1 68 A8 68 AA RestoreRegisters
|
||||
00612A 1 68
|
||||
00612B 1 60 rts
|
||||
00612C 1
|
||||
00612C 1 .endproc
|
||||
00612C 1
|
||||
00612C 1
|
||||
00612C 1 ;-------------------------------------------------------------------
|
||||
00612C 1 ;
|
||||
00612C 1 ; Hi-res graphics routines
|
||||
00612C 1 ;
|
||||
00612C 1 ;-------------------------------------------------------------------
|
||||
00612C 1
|
||||
00612C 1 ;---------------------------------------------------------
|
||||
00612C 1 .proc INITHIRES
|
||||
00612C 1 ;---------------------------------------------------------
|
||||
00612C 1 ; Set up the graphics display and pointers
|
||||
00612C 1 ;---------------------------------------------------------
|
||||
00612C 1 A9 20 lda #PLOTPAGE1 ; clear page 1
|
||||
00612E 1 85 E6 sta PLOTPAGE
|
||||
006130 1 20 59 61 jsr CLEARHIRES
|
||||
006133 1
|
||||
006133 1 20 43 61 jsr FLIPHIRES ; then show it and flip to 2
|
||||
006136 1 8D 57 C0 sta SETHIRES
|
||||
006139 1 8D 50 C0 sta CLRTEXT
|
||||
00613C 1 8D 52 C0 sta CLRMIXED
|
||||
00613F 1 8D 54 C0 sta PAGE1
|
||||
006142 1
|
||||
006142 1 60 rts
|
||||
006143 1 .endproc
|
||||
006143 1
|
||||
006143 1
|
||||
006143 1 ;---------------------------------------------------------
|
||||
006143 1 .proc FLIPHIRES
|
||||
006143 1 ;---------------------------------------------------------
|
||||
006143 1 ; Call when done with the current plotting page
|
||||
006143 1 ; (selected in PLOTPAGE) and it will be shown and the
|
||||
006143 1 ; other page will be shown.
|
||||
006143 1 ;---------------------------------------------------------
|
||||
006143 1 A5 E6 lda PLOTPAGE ; plotting on which page?
|
||||
006145 1 C9 20 cmp #PLOTPAGE1
|
||||
006147 1 F0 08 beq :+
|
||||
006149 1
|
||||
006149 1 8D 55 C0 sta PAGE2 ; page 2 - so show it
|
||||
00614C 1 A9 20 lda #PLOTPAGE1 ; and plot on page 1
|
||||
00614E 1 85 E6 sta PLOTPAGE
|
||||
006150 1 60 rts
|
||||
006151 1
|
||||
006151 1 8D 54 C0 : sta PAGE1 ; page 1 - so show it
|
||||
006154 1 A9 40 lda #PLOTPAGE2 ; and plot on page 2
|
||||
006156 1 85 E6 sta PLOTPAGE
|
||||
006158 1 60 rts
|
||||
006159 1 .endproc
|
||||
006159 1
|
||||
006159 1
|
||||
006159 1 ;---------------------------------------------------------
|
||||
006159 1 .proc CLEARHIRES
|
||||
006159 1 ;---------------------------------------------------------
|
||||
006159 1 ; Clear hires plotting page (selected in PLOTPAGE) to
|
||||
006159 1 ; black uses ZP; not terribly efficient
|
||||
006159 1 ;---------------------------------------------------------
|
||||
006159 1 A9 00 lda #0 ; Set up ZP as a pointer into the hires page
|
||||
00615B 1 85 FA sta ZP
|
||||
00615D 1 A5 E6 lda PLOTPAGE
|
||||
00615F 1 85 FB sta ZP+1
|
||||
006161 1 A2 20 ldx #PAGESIZE ; Clear this many pages
|
||||
006163 1 A9 00 lda #0 ; with black!
|
||||
006165 1 A8 tay
|
||||
006166 1 91 FA : sta (ZP),Y
|
||||
006168 1 C8 iny
|
||||
006169 1 D0 FB bne :-
|
||||
00616B 1 E6 FB inc ZP+1
|
||||
00616D 1 CA dex
|
||||
00616E 1 D0 F6 bne :-
|
||||
006170 1 60 rts
|
||||
006171 1 .endproc
|
||||
006171 1
|
||||
006171 1
|
||||
006171 1
|
||||
006171 1 ;-------------------------------------------------------------------
|
||||
006171 1 ;
|
||||
006171 1 ; Serial port routines
|
||||
006171 1 ;
|
||||
006171 1 ;-------------------------------------------------------------------
|
||||
006171 1
|
||||
006171 1
|
||||
006171 1 ;---------------------------------------------------------
|
||||
006171 1 .proc INITSSC
|
||||
006171 1 ;---------------------------------------------------------
|
||||
006171 1 ; Initialize the SSC; slot passed in A
|
||||
006171 1 ; [based on ADTPro]
|
||||
006171 1 ;---------------------------------------------------------
|
||||
006171 1 0A asl ; Slot passed in A
|
||||
006172 1 0A asl
|
||||
006173 1 0A asl
|
||||
006174 1 0A asl ; Now $S0
|
||||
006175 1 69 88 adc #$88 ; Low byte of UADATA
|
||||
006177 1 AA tax
|
||||
006178 1 A9 0B lda #CMND_NRDI ; Command register: no parity, RTS on, DTR on, no interrupts
|
||||
00617A 1 9D 02 C0 sta $C002,X
|
||||
00617D 1 AC C6 61 ldy PSPEED ; Control register: look up by baud rate (8 data bits, 1 stop bit)
|
||||
006180 1 B9 C2 61 lda BPSCTRL,Y
|
||||
006183 1 9D 03 C0 sta $C003,X
|
||||
006186 1 8E A6 61 stx MOD_UADATA_1+1 ; Modify references to
|
||||
006189 1 8E B3 61 stx MOD_UADATA_2+1 ; UADATA to point at
|
||||
00618C 1 8E BF 61 stx MOD_UADATA_3+1 ; correct slot (UADATA+S0)
|
||||
00618F 1 E8 inx
|
||||
006190 1 8E 9C 61 stx MOD_UASTAT_1+1 ; Modify reference to
|
||||
006193 1 8E AA 61 stx MOD_UASTAT_2+1 ; UASTAT to point at
|
||||
006196 1 8E B7 61 stx MOD_UASTAT_3+1 ; correct slot (UASTAT+S0)
|
||||
006199 1 60 rts
|
||||
00619A 1
|
||||
00619A 1 .endproc
|
||||
00619A 1
|
||||
00619A 1
|
||||
00619A 1 ;---------------------------------------------------------
|
||||
00619A 1 SSCPUT:
|
||||
00619A 1 ;---------------------------------------------------------
|
||||
00619A 1 ; Send accumulator out the serial port
|
||||
00619A 1 ; (this is a blocking call)
|
||||
00619A 1 ; [based on ADTPro]
|
||||
00619A 1 ;---------------------------------------------------------
|
||||
00619A 1 48 pha ; Push A onto the stack
|
||||
00619B 1 MOD_UASTAT_1:
|
||||
00619B 1 AD 89 C0 : lda UASTAT ; Check status bits
|
||||
00619E 1 29 70 and #$70
|
||||
0061A0 1 C9 10 cmp #$10
|
||||
0061A2 1 D0 F7 bne :- ; Output register is full, so loop
|
||||
0061A4 1 68 pla
|
||||
0061A5 1 MOD_UADATA_1:
|
||||
0061A5 1 8D 88 C0 sta UADATA ; Put character
|
||||
0061A8 1 60 rts
|
||||
0061A9 1
|
||||
0061A9 1
|
||||
0061A9 1 ;---------------------------------------------------------
|
||||
0061A9 1 SSCGET:
|
||||
0061A9 1 ;---------------------------------------------------------
|
||||
0061A9 1 ; Read a character from the serial port to the accumulator
|
||||
0061A9 1 ; (this is a blocking call)
|
||||
0061A9 1 ; [based on ADTPro]
|
||||
0061A9 1 ;---------------------------------------------------------
|
||||
0061A9 1 MOD_UASTAT_2:
|
||||
0061A9 1 AD 89 C0 lda UASTAT ; Check status bits
|
||||
0061AC 1 29 68 and #$68
|
||||
0061AE 1 C9 08 cmp #$8
|
||||
0061B0 1 D0 F7 bne SSCGET ; Input register empty, loop
|
||||
0061B2 1 MOD_UADATA_2:
|
||||
0061B2 1 AD 88 C0 lda UADATA ; Get character
|
||||
0061B5 1 60 rts
|
||||
0061B6 1
|
||||
0061B6 1
|
||||
0061B6 1 ;---------------------------------------------------------
|
||||
0061B6 1 SSCHASDATA:
|
||||
0061B6 1 ;---------------------------------------------------------
|
||||
0061B6 1 ; Read a character from the serial port to the accumulator
|
||||
0061B6 1 ; (this is a blocking call)
|
||||
0061B6 1 ; [based on ADTPro]
|
||||
0061B6 1 ;---------------------------------------------------------
|
||||
0061B6 1 MOD_UASTAT_3:
|
||||
0061B6 1 AD 89 C0 lda UASTAT ; Check status bits
|
||||
0061B9 1 29 68 and #$68
|
||||
0061BB 1 C9 08 cmp #$8
|
||||
0061BD 1 60 rts
|
||||
0061BE 1
|
||||
0061BE 1
|
||||
0061BE 1 ;---------------------------------------------------------
|
||||
0061BE 1 RESETSSC:
|
||||
0061BE 1 ;---------------------------------------------------------
|
||||
0061BE 1 ; Clean up serial port
|
||||
0061BE 1 ; [based on ADTPro]
|
||||
0061BE 1 ;---------------------------------------------------------
|
||||
0061BE 1 MOD_UADATA_3:
|
||||
0061BE 1 2C 88 C0 bit UADATA
|
||||
0061C1 1 60 rts
|
||||
0061C2 1
|
||||
0061C2 1
|
||||
0061C2 1
|
||||
0061C2 1 .ifdef MOUSE_SUPPORT
|
||||
0061C2 1 ;-------------------------------------------------------------------
|
||||
0061C2 1 ;
|
||||
0061C2 1 ; Mouse routines
|
||||
0061C2 1 ;
|
||||
0061C2 1 ;-------------------------------------------------------------------
|
||||
0061C2 1
|
||||
0061C2 1 MOUSEPTR = $EB ; Zero page location
|
||||
0061C2 1
|
||||
0061C2 1 MOUSE_MIN_X = $10
|
||||
0061C2 1 MOUSE_MAX_X = $1f
|
||||
0061C2 1 MOUSE_CENTER_X = $17
|
||||
0061C2 1 MOUSE_MIN_Y = $20
|
||||
0061C2 1 MOUSE_MAX_Y = $2f
|
||||
0061C2 1 MOUSE_CENTER_Y = $2f
|
||||
0061C2 1
|
||||
0061C2 1
|
||||
0061C2 1 ;--------------------------------------------------
|
||||
0061C2 1 ; Macros for common mouse operations
|
||||
0061C2 1 ;--------------------------------------------------
|
||||
0061C2 1
|
||||
0061C2 1 ;----------------------------------------
|
||||
0061C2 1 .macro ClampMouse axis, min, max
|
||||
0061C2 1 ;----------------------------------------
|
||||
0061C2 1 ; axis: MOUSE_CLAMP_X or MOUSE_CLAMP_Y
|
||||
0061C2 1 ; min: minimum value (2 byte)
|
||||
0061C2 1 ; max: maximum value (2 byte)
|
||||
0061C2 1 ;----------------------------------------
|
||||
0061C2 1 ; Clamp X to 0...255
|
||||
0061C2 1 lda #<min
|
||||
0061C2 1 sta MOUSE_CMIN_LSB
|
||||
0061C2 1 lda #>min
|
||||
0061C2 1 sta MOUSE_CMIN_MSB
|
||||
0061C2 1 lda #<max
|
||||
0061C2 1 sta MOUSE_CMAX_LSB
|
||||
0061C2 1 lda #>max
|
||||
0061C2 1 sta MOUSE_CMAX_MSB
|
||||
0061C2 1 lda #axis
|
||||
0061C2 1 jsr CLAMPMOUSE
|
||||
0061C2 1 .endmacro
|
||||
0061C2 1
|
||||
0061C2 1 ;----------------------------------------
|
||||
0061C2 1 .macro PosMouse px, py
|
||||
0061C2 1 ;----------------------------------------
|
||||
0061C2 1 ldx MOUSE_SLOT
|
||||
0061C2 1 lda #<px
|
||||
0061C2 1 sta MOUSE_X_LSB,X
|
||||
0061C2 1 lda #>px
|
||||
0061C2 1 sta MOUSE_X_MSB,X
|
||||
0061C2 1 lda #<py
|
||||
0061C2 1 sta MOUSE_Y_LSB,X
|
||||
0061C2 1 lda #>py
|
||||
0061C2 1 sta MOUSE_Y_MSB,X
|
||||
0061C2 1 jsr POSMOUSE
|
||||
0061C2 1 .endmacro
|
||||
0061C2 1
|
||||
0061C2 1
|
||||
0061C2 1 ;---------------------------------------------------------
|
||||
0061C2 1 .proc FINDMOUSE
|
||||
0061C2 1 ;---------------------------------------------------------
|
||||
0061C2 1 ; Find and initialize the mouse port
|
||||
0061C2 1 ;---------------------------------------------------------
|
||||
0061C2 1
|
||||
0061C2 1 ; Reference: http://home.swbell.net/rubywand/R034MOUSEPRG.TXT
|
||||
0061C2 1
|
||||
0061C2 1 sei ; No interrupts while we're getting set up
|
||||
0061C2 1 ;
|
||||
0061C2 1 ; Step 1: Find the mouse card by scanning slots for ID bytes
|
||||
0061C2 1 ;
|
||||
0061C2 1
|
||||
0061C2 1 ldy #MAX_SLOT ; Start search in slot 7
|
||||
0061C2 1
|
||||
0061C2 1 TESTSLOT:
|
||||
0061C2 1 sty MOUSE_SLOT ; Save for later
|
||||
0061C2 1 tya
|
||||
0061C2 1 clc
|
||||
0061C2 1 adc #>SLOT_BASE ; Firmware is $c0 + slot
|
||||
0061C2 1 sta MOD_MOUSE_ID + 2 ; Update msb of signature test
|
||||
0061C2 1 ldx #MOUSEID_MAX ; This many signature bytes
|
||||
0061C2 1
|
||||
0061C2 1 TESTID:
|
||||
0061C2 1 lda MOUSEID_ADDR,x
|
||||
0061C2 1 sta MOD_MOUSE_ID + 1 ; Update lsb of signature test
|
||||
0061C2 1 MOD_MOUSE_ID:
|
||||
0061C2 1 lda SLOT_BASE
|
||||
0061C2 1 cmp MOUSEID_VAL,x ; Does it match the signature?
|
||||
0061C2 1 bne NOMATCH ; Nope - try the next slot
|
||||
0061C2 1 dex ; Yes! Keep testing
|
||||
0061C2 1 bpl TESTID ; Fall through if all done
|
||||
0061C2 1 jmp FOUND_MOUSE
|
||||
0061C2 1
|
||||
0061C2 1 NOMATCH:
|
||||
0061C2 1 dey ; Didn't match
|
||||
0061C2 1 bne TESTSLOT ; Keep looking until slot 0
|
||||
0061C2 1 sty MOUSE_SLOT ; Oops, no mouse - make a note
|
||||
0061C2 1 rts ; and bail
|
||||
0061C2 1
|
||||
0061C2 1 ;
|
||||
0061C2 1 ; Step 2: Set up indirect calling routines
|
||||
0061C2 1 ;
|
||||
0061C2 1
|
||||
0061C2 1 FOUND_MOUSE:
|
||||
0061C2 1 ; Slot is in y
|
||||
0061C2 1
|
||||
0061C2 1 tya
|
||||
0061C2 1 ora #>SLOT_BASE ; Compute $Cn - needed for
|
||||
0061C2 1 sta MOUSEPTR+1 ; MSB of MOUSEPTR ($Cn00)
|
||||
0061C2 1 sta TOMOUSE_Cn ; X register before firmware calls
|
||||
0061C2 1 sta TOMOUSE_msb ; MSB of firmware calls
|
||||
0061C2 1
|
||||
0061C2 1 lda #0
|
||||
0061C2 1 sta MOUSEPTR ; LSB of MOUSEPTR ($Cn00)
|
||||
0061C2 1
|
||||
0061C2 1 tya
|
||||
0061C2 1 asl ; Compute $n0 - needed for
|
||||
0061C2 1 asl
|
||||
0061C2 1 asl
|
||||
0061C2 1 asl
|
||||
0061C2 1 sta TOMOUSE_n0 ; Y register before firmware calls
|
||||
0061C2 1
|
||||
0061C2 1 ;
|
||||
0061C2 1 ; Step 3: Configure the mouse card
|
||||
0061C2 1 ;
|
||||
0061C2 1
|
||||
0061C2 1 ; Initialize the mouse for use
|
||||
0061C2 1 jsr INITMOUSE ; reset, clamp to 0-1023 x/y
|
||||
0061C2 1 lda #1 ; mouse on, no interrupts
|
||||
0061C2 1 jsr SETMOUSE ; TODO: test carry bit result (set = error)
|
||||
0061C2 1 ;
|
||||
0061C2 1 ; Since we want deltas, clamp and center
|
||||
0061C2 1 ;
|
||||
0061C2 1 ClampMouse MOUSE_CLAMP_X, MOUSE_MIN_X, MOUSE_MAX_X
|
||||
0061C2 1 ClampMouse MOUSE_CLAMP_Y, MOUSE_MIN_Y, MOUSE_MAX_Y
|
||||
0061C2 1 PosMouse MOUSE_CENTER_X, MOUSE_CENTER_Y
|
||||
0061C2 1
|
||||
0061C2 1 cli ; Enable interrupts so mouse can function
|
||||
0061C2 1
|
||||
0061C2 1 rts
|
||||
0061C2 1
|
||||
0061C2 1 .endproc
|
||||
0061C2 1
|
||||
0061C2 1
|
||||
0061C2 1 ;--------------------------------------------------
|
||||
0061C2 1 ; Indirect jump table for mouse firmware routines
|
||||
0061C2 1 ;--------------------------------------------------
|
||||
0061C2 1
|
||||
0061C2 1 SETMOUSE: ldy #$12
|
||||
0061C2 1 jmp GOMOUSE
|
||||
0061C2 1 SERVEMOUSE: ldy #$13
|
||||
0061C2 1 jmp GOMOUSE
|
||||
0061C2 1 READMOUSE: ldy #$14
|
||||
0061C2 1 jmp GOMOUSE
|
||||
0061C2 1 CLEARMOUSE: ldy #$15
|
||||
0061C2 1 jmp GOMOUSE
|
||||
0061C2 1 POSMOUSE: ldy #$16
|
||||
0061C2 1 jmp GOMOUSE
|
||||
0061C2 1 CLAMPMOUSE: ldy #$17
|
||||
0061C2 1 jmp GOMOUSE
|
||||
0061C2 1 HOMEMOUSE: ldy #$18
|
||||
0061C2 1 jmp GOMOUSE
|
||||
0061C2 1 INITMOUSE: ldy #$19
|
||||
0061C2 1 jmp GOMOUSE
|
||||
0061C2 1
|
||||
0061C2 1 ;--------------------------------------------------
|
||||
0061C2 1 .proc GOMOUSE
|
||||
0061C2 1 ;--------------------------------------------------
|
||||
0061C2 1 tax ; Preserve the value in A
|
||||
0061C2 1 lda (MOUSEPTR),Y ; Get the routine entry point
|
||||
0061C2 1 sta TOMOUSE_lsb ; Patch the JMP instruction
|
||||
0061C2 1 txa ; Restore the value in A
|
||||
0061C2 1 .endproc
|
||||
0061C2 1 ; fall through
|
||||
0061C2 1
|
||||
0061C2 1 ; The following operand bytes must be patched by the
|
||||
0061C2 1 ; initialization code which detects the mouse.
|
||||
0061C2 1
|
||||
0061C2 1 BANK = $C054
|
||||
0061C2 1
|
||||
0061C2 1 TOMOUSE:
|
||||
0061C2 1 ldx #$C1 ; Set up slot in $Cn form in X
|
||||
0061C2 1 ldy #$10 ; Set up slot in $n0 form in Y
|
||||
0061C2 1 php ; Save interrupt state
|
||||
0061C2 1 sei ; No interrupts while calling
|
||||
0061C2 1 bit BANK
|
||||
0061C2 1 jsr SLOT_BASE ; Go to the mouse routine
|
||||
0061C2 1 plp ; Restore interrupt state
|
||||
0061C2 1 rts
|
||||
0061C2 1
|
||||
0061C2 1 TOMOUSE_Cn = TOMOUSE + 1
|
||||
0061C2 1 TOMOUSE_n0 = TOMOUSE + 3
|
||||
0061C2 1 TOMOUSE_lsb = TOMOUSE + 10
|
||||
0061C2 1 TOMOUSE_msb = TOMOUSE + 11
|
||||
0061C2 1
|
||||
0061C2 1
|
||||
0061C2 1 ; TODO: Turn this into a proper delta-sending routine
|
||||
0061C2 1
|
||||
0061C2 1 ;--------------------------------------------------
|
||||
0061C2 1 .proc FOOMOUSE
|
||||
0061C2 1 ;--------------------------------------------------
|
||||
0061C2 1 ;
|
||||
0061C2 1 ;--------------------------------------------------
|
||||
0061C2 1 txa ; save x
|
||||
0061C2 1 pha
|
||||
0061C2 1 tya ; save y
|
||||
0061C2 1 pha
|
||||
0061C2 1
|
||||
0061C2 1 jsr READMOUSE
|
||||
0061C2 1
|
||||
0061C2 1 jmp DONE
|
||||
0061C2 1
|
||||
0061C2 1 ldx MOUSE_SLOT
|
||||
0061C2 1
|
||||
0061C2 1 lda MOUSE_X_LSB,x
|
||||
0061C2 1 sta LAST_MX
|
||||
0061C2 1
|
||||
0061C2 1 lda MOUSE_Y_LSB,x
|
||||
0061C2 1 sta LAST_MY
|
||||
0061C2 1
|
||||
0061C2 1 lda LAST_MX
|
||||
0061C2 1 cmp #MOUSE_CENTER_X
|
||||
0061C2 1 bne SEND
|
||||
0061C2 1
|
||||
0061C2 1 lda LAST_MY
|
||||
0061C2 1 cmp #MOUSE_CENTER_Y
|
||||
0061C2 1 beq DONE
|
||||
0061C2 1
|
||||
0061C2 1 SEND:
|
||||
0061C2 1 lda LAST_MX
|
||||
0061C2 1 ora #SIS_MX
|
||||
0061C2 1 jsr SSCPUT
|
||||
0061C2 1 lda LAST_MY
|
||||
0061C2 1 ora #SIS_MY
|
||||
0061C2 1 jsr SSCPUT
|
||||
0061C2 1
|
||||
0061C2 1 PosMouse MOUSE_CENTER_X, MOUSE_CENTER_Y
|
||||
0061C2 1
|
||||
0061C2 1 DONE:
|
||||
0061C2 1 pla ; restore y
|
||||
0061C2 1 tay
|
||||
0061C2 1 pla ; restore x
|
||||
0061C2 1 tax
|
||||
0061C2 1 rts
|
||||
0061C2 1
|
||||
0061C2 1 .endproc
|
||||
0061C2 1
|
||||
0061C2 1 .endif ; MOUSE_SUPPORT
|
||||
0061C2 1
|
||||
0061C2 1
|
||||
0061C2 1 ;-------------------------------------------------------------------
|
||||
0061C2 1 ;
|
||||
0061C2 1 ; Lookup Tables and Variable Storage
|
||||
0061C2 1 ;
|
||||
0061C2 1 ;-------------------------------------------------------------------
|
||||
0061C2 1
|
||||
0061C2 1 ; Lookup table for UACTRL register, by baud rate
|
||||
0061C2 1
|
||||
0061C2 1 16 1E 1F 10 BPSCTRL: .byte $16,$1E,$1F,$10 ; 300, 9600, 19200, 115k (with 8 data bits, 1 stop bit, no echo)
|
||||
0061C6 1 .enum
|
||||
0061C6 1 BPS_300
|
||||
0061C6 1 BPS_9600
|
||||
0061C6 1 BPS_19200
|
||||
0061C6 1 BPS_115k
|
||||
0061C6 1 .endenum
|
||||
0061C6 1 CMND_NRDI = $0B ; Command: no parity, RTS on, DTR on, no interrupts
|
||||
0061C6 1
|
||||
0061C6 1
|
||||
0061C6 1 ; Application configuration
|
||||
0061C6 1 03 PSPEED: .byte BPS_115k ; Hardcoded for Apple IIc (TODO: Allow configuration)
|
||||
0061C7 1 02 PSLOT: .byte 2 ; Hardcoded for Apple IIc (TODO: Allow configuration)
|
||||
0061C8 1 00 PEXIT: .byte 0 ; Set when it's time to exit (Not Yet Implemented)
|
||||
0061C9 1
|
||||
0061C9 1
|
||||
0061C9 1 ; Keyboard state
|
||||
0061C9 1 00 LASTKB: .byte 0
|
||||
0061CA 1 00 LASTOA: .byte 0
|
||||
0061CB 1 00 LASTCA: .byte 0
|
||||
0061CC 1
|
||||
0061CC 1 .ifdef PADDLE_SUPPORT
|
||||
0061CC 1
|
||||
0061CC 1 ; Paddle state
|
||||
0061CC 1 00 LASTP0: .byte 0
|
||||
0061CD 1 00 LASTP1: .byte 0
|
||||
0061CE 1
|
||||
0061CE 1 .endif ; PADDLE_SUPPORT
|
||||
0061CE 1
|
||||
0061CE 1
|
||||
0061CE 1 .ifdef MOUSE_SUPPORT
|
||||
0061CE 1
|
||||
0061CE 1 ; Mouse
|
||||
0061CE 1 MOUSE_SLOT: .byte 0 ; mouse slot, or 0 if none
|
||||
0061CE 1 LAST_MX: .byte $7f
|
||||
0061CE 1 LAST_MY: .byte $7f
|
||||
0061CE 1
|
||||
0061CE 1 ; Mouse ID bytes
|
||||
0061CE 1 MOUSEID_MAX = 4
|
||||
0061CE 1 MOUSEID_ADDR: .byte $05, $07, $0b, $0c, $fb
|
||||
0061CE 1 MOUSEID_VAL: .byte $38, $18, $01, $20, $d6
|
||||
0061CE 1
|
||||
0061CE 1 .endif ; MOUSE_SUPPORT
|
||||
0061CE 1
|
||||
0061CE 1
|
|
@ -0,0 +1,924 @@
|
|||
|
||||
PADDLE_SUPPORT = 1
|
||||
;MOUSE_SUPPORT = 1 ; NOTE: tests for ifdef
|
||||
|
||||
;---------------------------------------------------------
|
||||
; Super Serial constants/locations
|
||||
;---------------------------------------------------------
|
||||
|
||||
; These get incremented by the slot where they appear
|
||||
UACTRL = $C08B ; Control Register
|
||||
UACMND = $C08A ; Command Register
|
||||
UASTAT = $C089 ; Status Register
|
||||
UADATA = $C088 ; Data Register - incoming and outgoing data
|
||||
|
||||
|
||||
;---------------------------------------------------------
|
||||
; Hi-res graphics constants/locations
|
||||
;---------------------------------------------------------
|
||||
|
||||
PLOTPAGE = $E6 ; Active hires plotting page (Applesoft)
|
||||
PLOTPAGE1 = $20
|
||||
PLOTPAGE2 = $40
|
||||
PAGESIZE = $20 ; Size of hi-res screen in pages
|
||||
|
||||
|
||||
CLRTEXT = $C050 ;display graphics
|
||||
SETTEXT = $C051 ;display text
|
||||
CLRMIXED = $C052 ;clear mixed mode- enable full graphics
|
||||
SETMIXED = $C053 ;enable graphics/text mixed mode
|
||||
PAGE1 = $C054 ;select text/graphics page1
|
||||
PAGE2 = $C055 ;select text/graphics page2
|
||||
CLRHIRES = $C056 ;select Lo-res
|
||||
SETHIRES = $C057 ;select Hi-res
|
||||
|
||||
|
||||
;---------------------------------------------------------
|
||||
; Keyboard input constants/locations
|
||||
;---------------------------------------------------------
|
||||
|
||||
KEYBD = $C000 ; key down in bit 7; key code in lower bits
|
||||
STROBE = $C010 ; write to clear key down state
|
||||
OPNAPPLE = $C061 ; open apple (command) key data (read)
|
||||
CLSAPPLE = $C062 ; closed apple (option) key data (read)
|
||||
PB2 = $C063 ; Paddle button 2 (read)
|
||||
PB3 = $C060 ; Paddle button 3 (read)
|
||||
|
||||
|
||||
;---------------------------------------------------------
|
||||
; Paddle/Joystick constants/locations/routines
|
||||
;---------------------------------------------------------
|
||||
|
||||
PADDLE0 = $C064 ; bit 7 = status of pdl-0 timer (read)
|
||||
PADDLE1 = $C065 ; bit 7 = status of pdl-1 timer (read)
|
||||
PADDLE2 = $C066 ; bit 7 = status of pdl-2 timer (read)
|
||||
PADDLE3 = $C067 ; bit 7 = status of pdl-3 timer (read)
|
||||
PDLTRIG = $C070 ; trigger paddles
|
||||
|
||||
PREAD = $FB1E ; Monitor paddle reading routine, call
|
||||
; with paddle # in X, returns value in Y
|
||||
|
||||
|
||||
;--------------------------------------------------
|
||||
; Mouse locations and constants
|
||||
;--------------------------------------------------
|
||||
|
||||
; For READMOUSE and POSMOUSE
|
||||
|
||||
MOUSE_X_LSB = $0478 ; + slot Low byte of absolute X position
|
||||
MOUSE_X_MSB = $0578 ; + slot High byte of absolute X position
|
||||
MOUSE_Y_LSB = $04F8 ; + slot Low byte of absolute Y position
|
||||
MOUSE_Y_MSB = $05F8 ; + slot High byte of absolute Y position
|
||||
MOUSE_RSV1 = $0678 ; + slot Reserved and used by the firmware
|
||||
MOUSE_RSV2 = $06F8 ; + slot Reserved and used by the firmware
|
||||
MOUSE_BTN = $0778 ; + slot Button 0/1 interrupt status byte
|
||||
MOUSE_MODE = $07F8 ; + slot Mode byte
|
||||
|
||||
; For CLAMPMOUSE:
|
||||
|
||||
MOUSE_CMIN_LSB = $0478 ; low byte of low clamp
|
||||
MOUSE_CMIN_MSB = $0578 ; high byte of low clamp
|
||||
MOUSE_CMAX_LSB = $04F8 ; low byte of high clamp
|
||||
MOUSE_CMAX_MSB = $05F8 ; high byte of high clamp
|
||||
|
||||
MOUSE_CLAMP_X = 0 ; Value for A when setting X clamp with CLAMPMOUSE
|
||||
MOUSE_CLAMP_Y = 1 ; Value for A when setting X clamp with CLAMPMOUSE
|
||||
|
||||
|
||||
;---------------------------------------------------------
|
||||
; Other
|
||||
;---------------------------------------------------------
|
||||
|
||||
SLOT_CASE = $c000 ; Firmware for slots are at $cx00
|
||||
MAX_SLOT = 7 ; Maximum slot # on an Apple II
|
||||
|
||||
ZP = $FA ; Write cursor location on zero page
|
||||
ESCAPE = $80 ; Unused image data byte (all black2)
|
||||
ESCAPE2 = $FF ; Unused image data byte (all white2)
|
||||
|
||||
|
||||
;---------------------------------------------------------
|
||||
; Generic Macros
|
||||
;---------------------------------------------------------
|
||||
|
||||
;----------------------------------------
|
||||
.macro SaveRegisters
|
||||
;----------------------------------------
|
||||
pha
|
||||
txa
|
||||
pha
|
||||
tya
|
||||
pha
|
||||
.endmacro
|
||||
|
||||
;----------------------------------------
|
||||
.macro RestoreRegisters
|
||||
;----------------------------------------
|
||||
pla
|
||||
tay
|
||||
pla
|
||||
tax
|
||||
pla
|
||||
.endmacro
|
||||
|
||||
|
||||
;-------------------------------------------------------------------
|
||||
;
|
||||
; Application-level logic
|
||||
;
|
||||
;-------------------------------------------------------------------
|
||||
|
||||
|
||||
.ORG $6000
|
||||
|
||||
;---------------------------------------------------------
|
||||
.proc APP_ENTRY
|
||||
;---------------------------------------------------------
|
||||
; Initialize the application, and enter the main loop
|
||||
;---------------------------------------------------------
|
||||
lda PSLOT ; Use slot 2
|
||||
jsr INITSSC ; Initialize Super Serial Card
|
||||
jsr INITHIRES ; Initialize Hi-Res graphics
|
||||
jsr INITINPUT ; Initialize input devices
|
||||
jsr MAINLOOP
|
||||
|
||||
; fall through
|
||||
.endproc
|
||||
|
||||
;---------------------------------------------------------
|
||||
.proc APP_EXIT
|
||||
;---------------------------------------------------------
|
||||
; Clean up and exit app
|
||||
;---------------------------------------------------------
|
||||
jsr RESETSSC
|
||||
sta PAGE1
|
||||
sta SETTEXT
|
||||
rts
|
||||
.endproc
|
||||
|
||||
|
||||
;-------------------------------------------------------------------
|
||||
;
|
||||
; Main loop functionality
|
||||
;
|
||||
;-------------------------------------------------------------------
|
||||
|
||||
|
||||
;---------------------------------------------------------
|
||||
.proc MAINLOOP
|
||||
;---------------------------------------------------------
|
||||
|
||||
; TODO: Sort out the protocol - should be able to send
|
||||
; input state without receiving data
|
||||
; jsr SSCHASDATA ; Anything to read?
|
||||
; bne :+ ; Nope
|
||||
|
||||
: jsr RECEIVEPAGE
|
||||
jsr FLIPHIRES
|
||||
jmp :- ; TODO: define an exit trigger
|
||||
rts
|
||||
.endproc
|
||||
|
||||
|
||||
;---------------------------------------------------------
|
||||
.proc RECEIVEPAGE
|
||||
;---------------------------------------------------------
|
||||
; Pull a hi-res page down over serial
|
||||
;
|
||||
; Protocol is:
|
||||
; * Recieve 256 bytes (graphic data)
|
||||
; * Send 1 byte (input state)
|
||||
;---------------------------------------------------------
|
||||
|
||||
lda #0 ; set up write pointer
|
||||
sta ZP
|
||||
lda PLOTPAGE
|
||||
sta ZP+1
|
||||
ldx #PAGESIZE ; plan to receive this many pages
|
||||
ldy #0
|
||||
|
||||
: jsr SSCGET ; TODO: look for escape codes in the sequence
|
||||
sta (ZP),Y
|
||||
iny
|
||||
bne :- ; Do a full page...
|
||||
|
||||
jsr SENDINPUTSTATE ; brief moment to send data back upstream
|
||||
|
||||
inc ZP+1
|
||||
dex
|
||||
bne :- ; ...as many pages as we need
|
||||
rts
|
||||
.endproc
|
||||
|
||||
|
||||
;-------------------------------------------------------------------
|
||||
;
|
||||
; Input device routines
|
||||
;
|
||||
;-------------------------------------------------------------------
|
||||
; Protocol:
|
||||
; $7f - $ff - key down, ASCII code + $80
|
||||
; otherwise, a transition:
|
||||
;
|
||||
SIS_KBUP = $00 ; Key up
|
||||
SIS_OADOWN = $01 ; Open Apple transitioned to down
|
||||
SIS_OAUP = $02 ; Open Apple transitioned to up
|
||||
SIS_CADOWN = $03 ; Closed Apple transitioned to down
|
||||
SIS_CAUP = $04 ; Closed Apple transitioned to up
|
||||
;
|
||||
; $05 - $0f : reserved
|
||||
;
|
||||
SIS_MX = $10 ; Mouse X high nibble
|
||||
SIS_MY = $20 ; Mouse Y high nibble
|
||||
SIS_PDL0 = $30 ; Paddle 0 high nibble
|
||||
SIS_PDL1 = $40 ; Paddle 1 high nibble
|
||||
;
|
||||
; $50 - $7e : reserved
|
||||
;
|
||||
SIS_SYNC = $7f
|
||||
|
||||
;---------------------------------------------------------
|
||||
.proc INITINPUT
|
||||
;---------------------------------------------------------
|
||||
; Initialize input devices and storage for detecting
|
||||
; state transitions
|
||||
;---------------------------------------------------------
|
||||
|
||||
; Init keyboard state
|
||||
lda #SIS_KBUP
|
||||
sta LASTKB
|
||||
|
||||
; Init Open/Closed Apple states
|
||||
lda #SIS_OAUP ; NOTE: Don't store OA state as it fluctuates
|
||||
sta LASTOA
|
||||
lda #SIS_CAUP ; NOTE: Don't store CA state as it fluctuates
|
||||
sta LASTCA
|
||||
|
||||
.ifdef PADDLE_SUPPORT
|
||||
; Init Paddle state
|
||||
lda #SIS_PDL0
|
||||
ora #8 ; Middle of range 0...15
|
||||
sta LASTP0
|
||||
lda #SIS_PDL1
|
||||
ora #8 ; Middle of range 0...15
|
||||
sta LASTP1
|
||||
.endif
|
||||
|
||||
.ifdef MOUSE_SUPPORT
|
||||
jsr FINDMOUSE
|
||||
.endif
|
||||
|
||||
rts
|
||||
.endproc
|
||||
|
||||
|
||||
;---------------------------------------------------------
|
||||
.proc SENDINPUTSTATE
|
||||
;---------------------------------------------------------
|
||||
; Send keyboard joystick and/or mouse state over the
|
||||
; serial port
|
||||
;
|
||||
; Algorithm:
|
||||
; - Send key state (if it changed)
|
||||
; - otherwise send open-apple state (if it changed)
|
||||
; - otherwise send closed-apple state (if it changed)
|
||||
; - otherwise send paddle 0 state (if it changed)
|
||||
; - (TODO: Mouse state)
|
||||
; - otherwise send sync byte
|
||||
;---------------------------------------------------------
|
||||
|
||||
SaveRegisters ; Store registers
|
||||
clc
|
||||
|
||||
;--------------------------------------
|
||||
; Send key state, if it changed
|
||||
|
||||
; NOTE: Can't use STROBE to detect key up -> key down transition
|
||||
; since the msb can change before the key code. Instead, consider
|
||||
; these cases:
|
||||
;
|
||||
; OLD STATE KEYBD STROBE 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
|
||||
;
|
||||
|
||||
lda LASTKB
|
||||
bne KEY_WAS_DOWN
|
||||
|
||||
KEY_WAS_UP:
|
||||
lda KEYBD ; Read keyboard
|
||||
bpl END_KEY ; - still up
|
||||
sta LASTKB ; Down, so save it
|
||||
jsr SSCPUT ; and send it
|
||||
jmp DONE
|
||||
|
||||
KEY_WAS_DOWN:
|
||||
; key was down - strobe should match
|
||||
; unless the key changed or was released
|
||||
lda STROBE
|
||||
bmi STROBE_DOWN
|
||||
STROBE_UP:
|
||||
lda #SIS_KBUP ; Key was released
|
||||
sta LASTKB ; so save it
|
||||
jsr SSCPUT ; and send it
|
||||
jmp DONE
|
||||
STROBE_DOWN:
|
||||
cmp LASTKB ; Same key as last time?
|
||||
beq END_KEY ; - no change
|
||||
sta LASTKB ; New key, so save it
|
||||
jsr SSCPUT ; and send it
|
||||
jmp DONE
|
||||
|
||||
END_KEY:
|
||||
|
||||
;--------------------------------------
|
||||
; Send Open Apple state, if it changed
|
||||
|
||||
; TODO: Can simplify this code if we make the high bits the same
|
||||
; for both OA states and bit = 0 down: lda OPNAPPLE ; ROL ; LDA #0 ; ROL ; ORA #signature
|
||||
|
||||
TEST_OA:
|
||||
lda OPNAPPLE ; Test Open Apple state
|
||||
bmi OA_IS_DOWN
|
||||
OA_IS_UP:
|
||||
lda #SIS_OAUP
|
||||
cmp LASTOA ; Changed?
|
||||
beq END_OA ; Nope
|
||||
sta LASTOA ; Yes, save it / send it!
|
||||
jsr SSCPUT
|
||||
jmp DONE
|
||||
OA_IS_DOWN:
|
||||
lda #SIS_OADOWN
|
||||
cmp LASTOA ; Changed?
|
||||
beq END_OA ; Nope
|
||||
sta LASTOA ; Yes, save it / send it!
|
||||
jsr SSCPUT
|
||||
jmp DONE
|
||||
|
||||
END_OA:
|
||||
|
||||
;--------------------------------------
|
||||
; Send Closed Apple state, if it changed
|
||||
|
||||
TEST_CA:
|
||||
lda CLSAPPLE ; Has the Open Apple/Button 1 value changed?
|
||||
bmi CA_IS_DOWN
|
||||
CA_IS_UP:
|
||||
lda #SIS_CAUP
|
||||
cmp LASTCA ; Changed?
|
||||
beq END_CA ; Nope
|
||||
sta LASTCA ; Yes, save it
|
||||
jsr SSCPUT ; and send it
|
||||
jmp DONE
|
||||
CA_IS_DOWN:
|
||||
lda #SIS_CADOWN
|
||||
cmp LASTCA ; Changed?
|
||||
beq END_CA ; Nope
|
||||
sta LASTCA ; Yes, save it
|
||||
jsr SSCPUT ; and send it
|
||||
jmp DONE
|
||||
|
||||
END_CA:
|
||||
|
||||
.ifdef PADDLE_SUPPORT
|
||||
|
||||
;--------------------------------------
|
||||
; Send Paddle 0 state, if it changed
|
||||
TEST_PDL0:
|
||||
ldx #0
|
||||
jsr PREAD
|
||||
tya
|
||||
lsr ; Shift to low nibble
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
ora #SIS_PDL0 ; And mark it with the signature
|
||||
cmp LASTP0 ; Change?
|
||||
beq END_PDL0 ; Nope
|
||||
sta LASTP0 ; Yes, save it
|
||||
jsr SSCPUT ; and send it
|
||||
jmp DONE
|
||||
END_PDL0:
|
||||
; Chew up time so next paddle read will be correct
|
||||
; TODO: Replace this with a "read both" strobes
|
||||
; routine
|
||||
: .repeat 11 ; By experiment, need 11 NOPs.
|
||||
nop
|
||||
.endrep
|
||||
iny
|
||||
bne :-
|
||||
|
||||
;--------------------------------------
|
||||
; Send Paddle 1 state, if it changed
|
||||
TEST_PDL1:
|
||||
ldx #1
|
||||
jsr PREAD
|
||||
tya
|
||||
lsr ; Shift to low nibble
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
ora #SIS_PDL1 ; And mark it with the signature
|
||||
cmp LASTP1 ; Change?
|
||||
beq END_PDL1 ; Nope
|
||||
sta LASTP1 ; Yes, save it
|
||||
jsr SSCPUT ; and send it
|
||||
jmp DONE
|
||||
END_PDL1:
|
||||
; NOTE: No need to chew time like PDL0
|
||||
; since data receive will make up for it; if we
|
||||
; loop in SENDINPUTSTATE need to add it here
|
||||
|
||||
.endif
|
||||
|
||||
|
||||
;--------------------------------------
|
||||
.ifdef MOUSE_SUPPORT
|
||||
.error "Mouse support not fully implemented"
|
||||
.endif
|
||||
|
||||
;--------------------------------------
|
||||
; No state changes so send sync byte
|
||||
|
||||
lda #SIS_SYNC
|
||||
jsr SSCPUT
|
||||
|
||||
DONE:
|
||||
RestoreRegisters
|
||||
rts
|
||||
|
||||
.endproc
|
||||
|
||||
|
||||
;-------------------------------------------------------------------
|
||||
;
|
||||
; Hi-res graphics routines
|
||||
;
|
||||
;-------------------------------------------------------------------
|
||||
|
||||
;---------------------------------------------------------
|
||||
.proc INITHIRES
|
||||
;---------------------------------------------------------
|
||||
; Set up the graphics display and pointers
|
||||
;---------------------------------------------------------
|
||||
lda #PLOTPAGE1 ; clear page 1
|
||||
sta PLOTPAGE
|
||||
jsr CLEARHIRES
|
||||
|
||||
jsr FLIPHIRES ; then show it and flip to 2
|
||||
sta SETHIRES
|
||||
sta CLRTEXT
|
||||
sta CLRMIXED
|
||||
sta PAGE1
|
||||
|
||||
rts
|
||||
.endproc
|
||||
|
||||
|
||||
;---------------------------------------------------------
|
||||
.proc FLIPHIRES
|
||||
;---------------------------------------------------------
|
||||
; Call when done with the current plotting page
|
||||
; (selected in PLOTPAGE) and it will be shown and the
|
||||
; other page will be shown.
|
||||
;---------------------------------------------------------
|
||||
lda PLOTPAGE ; plotting on which page?
|
||||
cmp #PLOTPAGE1
|
||||
beq :+
|
||||
|
||||
sta PAGE2 ; page 2 - so show it
|
||||
lda #PLOTPAGE1 ; and plot on page 1
|
||||
sta PLOTPAGE
|
||||
rts
|
||||
|
||||
: sta PAGE1 ; page 1 - so show it
|
||||
lda #PLOTPAGE2 ; and plot on page 2
|
||||
sta PLOTPAGE
|
||||
rts
|
||||
.endproc
|
||||
|
||||
|
||||
;---------------------------------------------------------
|
||||
.proc CLEARHIRES
|
||||
;---------------------------------------------------------
|
||||
; Clear hires plotting page (selected in PLOTPAGE) to
|
||||
; black uses ZP; not terribly efficient
|
||||
;---------------------------------------------------------
|
||||
lda #0 ; Set up ZP as a pointer into the hires page
|
||||
sta ZP
|
||||
lda PLOTPAGE
|
||||
sta ZP+1
|
||||
ldx #PAGESIZE ; Clear this many pages
|
||||
lda #0 ; with black!
|
||||
tay
|
||||
: sta (ZP),Y
|
||||
iny
|
||||
bne :-
|
||||
inc ZP+1
|
||||
dex
|
||||
bne :-
|
||||
rts
|
||||
.endproc
|
||||
|
||||
|
||||
|
||||
;-------------------------------------------------------------------
|
||||
;
|
||||
; Serial port routines
|
||||
;
|
||||
;-------------------------------------------------------------------
|
||||
|
||||
|
||||
;---------------------------------------------------------
|
||||
.proc INITSSC
|
||||
;---------------------------------------------------------
|
||||
; Initialize the SSC; slot passed in A
|
||||
; [based on ADTPro]
|
||||
;---------------------------------------------------------
|
||||
asl ; Slot passed in A
|
||||
asl
|
||||
asl
|
||||
asl ; Now $S0
|
||||
adc #$88 ; Low byte of UADATA
|
||||
tax
|
||||
lda #CMND_NRDI ; Command register: no parity, RTS on, DTR on, no interrupts
|
||||
sta $C002,X
|
||||
ldy PSPEED ; Control register: look up by baud rate (8 data bits, 1 stop bit)
|
||||
lda BPSCTRL,Y
|
||||
sta $C003,X
|
||||
stx MOD_UADATA_1+1 ; Modify references to
|
||||
stx MOD_UADATA_2+1 ; UADATA to point at
|
||||
stx MOD_UADATA_3+1 ; correct slot (UADATA+S0)
|
||||
inx
|
||||
stx MOD_UASTAT_1+1 ; Modify reference to
|
||||
stx MOD_UASTAT_2+1 ; UASTAT to point at
|
||||
stx MOD_UASTAT_3+1 ; correct slot (UASTAT+S0)
|
||||
rts
|
||||
|
||||
.endproc
|
||||
|
||||
|
||||
;---------------------------------------------------------
|
||||
SSCPUT:
|
||||
;---------------------------------------------------------
|
||||
; Send accumulator out the serial port
|
||||
; (this is a blocking call)
|
||||
; [based on ADTPro]
|
||||
;---------------------------------------------------------
|
||||
pha ; Push A onto the stack
|
||||
MOD_UASTAT_1:
|
||||
: lda UASTAT ; Check status bits
|
||||
and #$70
|
||||
cmp #$10
|
||||
bne :- ; Output register is full, so loop
|
||||
pla
|
||||
MOD_UADATA_1:
|
||||
sta UADATA ; Put character
|
||||
rts
|
||||
|
||||
|
||||
;---------------------------------------------------------
|
||||
SSCGET:
|
||||
;---------------------------------------------------------
|
||||
; Read a character from the serial port to the accumulator
|
||||
; (this is a blocking call)
|
||||
; [based on ADTPro]
|
||||
;---------------------------------------------------------
|
||||
MOD_UASTAT_2:
|
||||
lda UASTAT ; Check status bits
|
||||
and #$68
|
||||
cmp #$8
|
||||
bne SSCGET ; Input register empty, loop
|
||||
MOD_UADATA_2:
|
||||
lda UADATA ; Get character
|
||||
rts
|
||||
|
||||
|
||||
;---------------------------------------------------------
|
||||
SSCHASDATA:
|
||||
;---------------------------------------------------------
|
||||
; Read a character from the serial port to the accumulator
|
||||
; (this is a blocking call)
|
||||
; [based on ADTPro]
|
||||
;---------------------------------------------------------
|
||||
MOD_UASTAT_3:
|
||||
lda UASTAT ; Check status bits
|
||||
and #$68
|
||||
cmp #$8
|
||||
rts
|
||||
|
||||
|
||||
;---------------------------------------------------------
|
||||
RESETSSC:
|
||||
;---------------------------------------------------------
|
||||
; Clean up serial port
|
||||
; [based on ADTPro]
|
||||
;---------------------------------------------------------
|
||||
MOD_UADATA_3:
|
||||
bit UADATA
|
||||
rts
|
||||
|
||||
|
||||
|
||||
.ifdef MOUSE_SUPPORT
|
||||
;-------------------------------------------------------------------
|
||||
;
|
||||
; Mouse routines
|
||||
;
|
||||
;-------------------------------------------------------------------
|
||||
|
||||
MOUSEPTR = $EB ; Zero page location
|
||||
|
||||
MOUSE_MIN_X = $10
|
||||
MOUSE_MAX_X = $1f
|
||||
MOUSE_CENTER_X = $17
|
||||
MOUSE_MIN_Y = $20
|
||||
MOUSE_MAX_Y = $2f
|
||||
MOUSE_CENTER_Y = $2f
|
||||
|
||||
|
||||
;--------------------------------------------------
|
||||
; Macros for common mouse operations
|
||||
;--------------------------------------------------
|
||||
|
||||
;----------------------------------------
|
||||
.macro ClampMouse axis, min, max
|
||||
;----------------------------------------
|
||||
; axis: MOUSE_CLAMP_X or MOUSE_CLAMP_Y
|
||||
; min: minimum value (2 byte)
|
||||
; max: maximum value (2 byte)
|
||||
;----------------------------------------
|
||||
; Clamp X to 0...255
|
||||
lda #<min
|
||||
sta MOUSE_CMIN_LSB
|
||||
lda #>min
|
||||
sta MOUSE_CMIN_MSB
|
||||
lda #<max
|
||||
sta MOUSE_CMAX_LSB
|
||||
lda #>max
|
||||
sta MOUSE_CMAX_MSB
|
||||
lda #axis
|
||||
jsr CLAMPMOUSE
|
||||
.endmacro
|
||||
|
||||
;----------------------------------------
|
||||
.macro PosMouse px, py
|
||||
;----------------------------------------
|
||||
ldx MOUSE_SLOT
|
||||
lda #<px
|
||||
sta MOUSE_X_LSB,X
|
||||
lda #>px
|
||||
sta MOUSE_X_MSB,X
|
||||
lda #<py
|
||||
sta MOUSE_Y_LSB,X
|
||||
lda #>py
|
||||
sta MOUSE_Y_MSB,X
|
||||
jsr POSMOUSE
|
||||
.endmacro
|
||||
|
||||
|
||||
;---------------------------------------------------------
|
||||
.proc FINDMOUSE
|
||||
;---------------------------------------------------------
|
||||
; Find and initialize the mouse port
|
||||
;---------------------------------------------------------
|
||||
|
||||
; Reference: http://home.swbell.net/rubywand/R034MOUSEPRG.TXT
|
||||
|
||||
sei ; No interrupts while we're getting set up
|
||||
;
|
||||
; Step 1: Find the mouse card by scanning slots for ID bytes
|
||||
;
|
||||
|
||||
ldy #MAX_SLOT ; Start search in slot 7
|
||||
|
||||
TESTSLOT:
|
||||
sty MOUSE_SLOT ; Save for later
|
||||
tya
|
||||
clc
|
||||
adc #>SLOT_BASE ; Firmware is $c0 + slot
|
||||
sta MOD_MOUSE_ID + 2 ; Update msb of signature test
|
||||
ldx #MOUSEID_MAX ; This many signature bytes
|
||||
|
||||
TESTID:
|
||||
lda MOUSEID_ADDR,x
|
||||
sta MOD_MOUSE_ID + 1 ; Update lsb of signature test
|
||||
MOD_MOUSE_ID:
|
||||
lda SLOT_BASE
|
||||
cmp MOUSEID_VAL,x ; Does it match the signature?
|
||||
bne NOMATCH ; Nope - try the next slot
|
||||
dex ; Yes! Keep testing
|
||||
bpl TESTID ; Fall through if all done
|
||||
jmp FOUND_MOUSE
|
||||
|
||||
NOMATCH:
|
||||
dey ; Didn't match
|
||||
bne TESTSLOT ; Keep looking until slot 0
|
||||
sty MOUSE_SLOT ; Oops, no mouse - make a note
|
||||
rts ; and bail
|
||||
|
||||
;
|
||||
; Step 2: Set up indirect calling routines
|
||||
;
|
||||
|
||||
FOUND_MOUSE:
|
||||
; Slot is in y
|
||||
|
||||
tya
|
||||
ora #>SLOT_BASE ; Compute $Cn - needed for
|
||||
sta MOUSEPTR+1 ; MSB of MOUSEPTR ($Cn00)
|
||||
sta TOMOUSE_Cn ; X register before firmware calls
|
||||
sta TOMOUSE_msb ; MSB of firmware calls
|
||||
|
||||
lda #0
|
||||
sta MOUSEPTR ; LSB of MOUSEPTR ($Cn00)
|
||||
|
||||
tya
|
||||
asl ; Compute $n0 - needed for
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
sta TOMOUSE_n0 ; Y register before firmware calls
|
||||
|
||||
;
|
||||
; Step 3: Configure the mouse card
|
||||
;
|
||||
|
||||
; Initialize the mouse for use
|
||||
jsr INITMOUSE ; reset, clamp to 0-1023 x/y
|
||||
lda #1 ; mouse on, no interrupts
|
||||
jsr SETMOUSE ; TODO: test carry bit result (set = error)
|
||||
;
|
||||
; Since we want deltas, clamp and center
|
||||
;
|
||||
ClampMouse MOUSE_CLAMP_X, MOUSE_MIN_X, MOUSE_MAX_X
|
||||
ClampMouse MOUSE_CLAMP_Y, MOUSE_MIN_Y, MOUSE_MAX_Y
|
||||
PosMouse MOUSE_CENTER_X, MOUSE_CENTER_Y
|
||||
|
||||
cli ; Enable interrupts so mouse can function
|
||||
|
||||
rts
|
||||
|
||||
.endproc
|
||||
|
||||
|
||||
;--------------------------------------------------
|
||||
; Indirect jump table for mouse firmware routines
|
||||
;--------------------------------------------------
|
||||
|
||||
SETMOUSE: ldy #$12
|
||||
jmp GOMOUSE
|
||||
SERVEMOUSE: ldy #$13
|
||||
jmp GOMOUSE
|
||||
READMOUSE: ldy #$14
|
||||
jmp GOMOUSE
|
||||
CLEARMOUSE: ldy #$15
|
||||
jmp GOMOUSE
|
||||
POSMOUSE: ldy #$16
|
||||
jmp GOMOUSE
|
||||
CLAMPMOUSE: ldy #$17
|
||||
jmp GOMOUSE
|
||||
HOMEMOUSE: ldy #$18
|
||||
jmp GOMOUSE
|
||||
INITMOUSE: ldy #$19
|
||||
jmp GOMOUSE
|
||||
|
||||
;--------------------------------------------------
|
||||
.proc GOMOUSE
|
||||
;--------------------------------------------------
|
||||
tax ; Preserve the value in A
|
||||
lda (MOUSEPTR),Y ; Get the routine entry point
|
||||
sta TOMOUSE_lsb ; Patch the JMP instruction
|
||||
txa ; Restore the value in A
|
||||
.endproc
|
||||
; fall through
|
||||
|
||||
; The following operand bytes must be patched by the
|
||||
; initialization code which detects the mouse.
|
||||
|
||||
BANK = $C054
|
||||
|
||||
TOMOUSE:
|
||||
ldx #$C1 ; Set up slot in $Cn form in X
|
||||
ldy #$10 ; Set up slot in $n0 form in Y
|
||||
php ; Save interrupt state
|
||||
sei ; No interrupts while calling
|
||||
bit BANK
|
||||
jsr SLOT_BASE ; Go to the mouse routine
|
||||
plp ; Restore interrupt state
|
||||
rts
|
||||
|
||||
TOMOUSE_Cn = TOMOUSE + 1
|
||||
TOMOUSE_n0 = TOMOUSE + 3
|
||||
TOMOUSE_lsb = TOMOUSE + 10
|
||||
TOMOUSE_msb = TOMOUSE + 11
|
||||
|
||||
|
||||
; TODO: Turn this into a proper delta-sending routine
|
||||
|
||||
;--------------------------------------------------
|
||||
.proc FOOMOUSE
|
||||
;--------------------------------------------------
|
||||
;
|
||||
;--------------------------------------------------
|
||||
txa ; save x
|
||||
pha
|
||||
tya ; save y
|
||||
pha
|
||||
|
||||
jsr READMOUSE
|
||||
|
||||
jmp DONE
|
||||
|
||||
ldx MOUSE_SLOT
|
||||
|
||||
lda MOUSE_X_LSB,x
|
||||
sta LAST_MX
|
||||
|
||||
lda MOUSE_Y_LSB,x
|
||||
sta LAST_MY
|
||||
|
||||
lda LAST_MX
|
||||
cmp #MOUSE_CENTER_X
|
||||
bne SEND
|
||||
|
||||
lda LAST_MY
|
||||
cmp #MOUSE_CENTER_Y
|
||||
beq DONE
|
||||
|
||||
SEND:
|
||||
lda LAST_MX
|
||||
ora #SIS_MX
|
||||
jsr SSCPUT
|
||||
lda LAST_MY
|
||||
ora #SIS_MY
|
||||
jsr SSCPUT
|
||||
|
||||
PosMouse MOUSE_CENTER_X, MOUSE_CENTER_Y
|
||||
|
||||
DONE:
|
||||
pla ; restore y
|
||||
tay
|
||||
pla ; restore x
|
||||
tax
|
||||
rts
|
||||
|
||||
.endproc
|
||||
|
||||
.endif ; MOUSE_SUPPORT
|
||||
|
||||
|
||||
;-------------------------------------------------------------------
|
||||
;
|
||||
; Lookup Tables and Variable Storage
|
||||
;
|
||||
;-------------------------------------------------------------------
|
||||
|
||||
; Lookup table for UACTRL register, by baud rate
|
||||
|
||||
BPSCTRL: .byte $16,$1E,$1F,$10 ; 300, 9600, 19200, 115k (with 8 data bits, 1 stop bit, no echo)
|
||||
.enum
|
||||
BPS_300
|
||||
BPS_9600
|
||||
BPS_19200
|
||||
BPS_115k
|
||||
.endenum
|
||||
CMND_NRDI = $0B ; Command: no parity, RTS on, DTR on, no interrupts
|
||||
|
||||
|
||||
; Application configuration
|
||||
PSPEED: .byte 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)
|
||||
|
||||
|
||||
; Keyboard state
|
||||
LASTKB: .byte 0
|
||||
LASTOA: .byte 0
|
||||
LASTCA: .byte 0
|
||||
|
||||
.ifdef PADDLE_SUPPORT
|
||||
|
||||
; Paddle state
|
||||
LASTP0: .byte 0
|
||||
LASTP1: .byte 0
|
||||
|
||||
.endif ; PADDLE_SUPPORT
|
||||
|
||||
|
||||
.ifdef MOUSE_SUPPORT
|
||||
|
||||
; Mouse
|
||||
MOUSE_SLOT: .byte 0 ; mouse slot, or 0 if none
|
||||
LAST_MX: .byte $7f
|
||||
LAST_MY: .byte $7f
|
||||
|
||||
; Mouse ID bytes
|
||||
MOUSEID_MAX = 4
|
||||
MOUSEID_ADDR: .byte $05, $07, $0b, $0c, $fb
|
||||
MOUSEID_VAL: .byte $38, $18, $01, $20, $d6
|
||||
|
||||
.endif ; MOUSE_SUPPORT
|
||||
|
244
index.html
244
index.html
|
@ -8,246 +8,4 @@ video, canvas { border: 2px dotted black; }
|
|||
<br>
|
||||
<button id=save>Save</button>
|
||||
|
||||
<script>
|
||||
const palette = [
|
||||
/* Black1 */ [0x00, 0x00, 0x00],
|
||||
/* Green */ [0x2f, 0xbc, 0x1a],
|
||||
/* Violet */ [0xd0, 0x43, 0xe5],
|
||||
/* White1 */ [0xff, 0xff, 0xff],
|
||||
/* Black2 */ [0x00, 0x00, 0x00],
|
||||
/* Orange */ [0xd0, 0x6a, 0x1a],
|
||||
/* Blue */ [0x2f, 0x95, 0xe5],
|
||||
/* White2 */ [0xff, 0xff, 0xff]
|
||||
];
|
||||
|
||||
(async function() {
|
||||
const $ = document.querySelector.bind(document);
|
||||
|
||||
let hires_buffer = new Uint8Array(8192);
|
||||
|
||||
$('#save').addEventListener('click', e => {
|
||||
const blob = new Blob([hires_buffer], {type: 'application/octet-stream'});
|
||||
const anchor = document.createElement('a');
|
||||
anchor.download = 'image.bin';
|
||||
anchor.href = URL.createObjectURL(blob);
|
||||
document.body.appendChild(anchor);
|
||||
anchor.click();
|
||||
anchor.remove();
|
||||
URL.revokeObjectURL(anchor.href);
|
||||
});
|
||||
|
||||
|
||||
try {
|
||||
const mediaStream = await navigator.getDisplayMedia({video:true});
|
||||
const vid = document.createElement('video');
|
||||
vid.srcObject = mediaStream;
|
||||
vid.play();
|
||||
|
||||
const quant = $('#quant');
|
||||
const qctx = quant.getContext('2d');
|
||||
|
||||
const can = document.createElement('canvas');
|
||||
can.width = quant.width;
|
||||
can.height = quant.height;
|
||||
const ctx = can.getContext('2d');
|
||||
ctx.imageSmoothingQuality = 'high';
|
||||
|
||||
const indexes = new Array(can.width * can.height);
|
||||
|
||||
setInterval(() => {
|
||||
ctx.drawImage(vid, 0, 0, can.width, can.height);
|
||||
|
||||
const imagedata = ctx.getImageData(0, 0, can.width, can.height);
|
||||
|
||||
quantize(imagedata, indexes);
|
||||
hires(indexes, hires_buffer);
|
||||
|
||||
qctx.putImageData(imagedata, 0, 0);
|
||||
|
||||
}, 500);
|
||||
|
||||
} catch (e) {
|
||||
console.warn(`Error: ${e.name} - ${e.message}`);
|
||||
}
|
||||
})();
|
||||
|
||||
|
||||
// Distance in 3-space
|
||||
function distance(r1,g1,b1,r2,g2,b2) {
|
||||
const dr = r1 - r2;
|
||||
const dg = g1 - g2;
|
||||
const db = b1 - b2;
|
||||
return Math.sqrt(dr*dr + dg*dg + db*db);
|
||||
}
|
||||
|
||||
function quantize(imagedata, indexes) {
|
||||
const hash = {};
|
||||
for (let i = 0; i < palette.length; ++i) {
|
||||
const entry = palette[i];
|
||||
const rgb = (entry[0] << 16) | (entry[1] << 8) | entry[2];
|
||||
hash[rgb] = i;
|
||||
}
|
||||
|
||||
// Floyd-Steinberg
|
||||
function offset(x, y) {
|
||||
return 4 * (x + y * imagedata.width);
|
||||
}
|
||||
|
||||
function err(x, y, er, eg, eb) {
|
||||
if (x < 0 || x >= imagedata.width || y < 0 || y >= imagedata.height)
|
||||
return;
|
||||
const i = offset(x, y);
|
||||
const data = imagedata.data;
|
||||
data[i + 0] += er;
|
||||
data[i + 1] += eg;
|
||||
data[i + 2] += eb;
|
||||
}
|
||||
|
||||
const data = imagedata.data;
|
||||
for (let y = 0; y < imagedata.height; ++y) {
|
||||
for (let x = 0; x < imagedata.width; ++x) {
|
||||
const i = offset(x, y);
|
||||
|
||||
const r = data[i];
|
||||
const g = data[i+1];
|
||||
const b = data[i+2];
|
||||
|
||||
// Find closest in palette.
|
||||
const rgb = (r << 16) | (g << 8) | b;
|
||||
let index = hash[rgb];
|
||||
if (index === undefined) {
|
||||
let dist;
|
||||
for (let p = 0; p < palette.length; ++p) {
|
||||
const entry = palette[p];
|
||||
const d = distance(r,g,b, entry[0], entry[1], entry[2]);
|
||||
if (dist === undefined || d < dist) {
|
||||
dist = d;
|
||||
index = p;
|
||||
}
|
||||
}
|
||||
hash[rgb] = index;
|
||||
}
|
||||
const pi = palette[index];
|
||||
|
||||
// Calculate error
|
||||
const err_r = data[i] - pi[0];
|
||||
const err_g = data[i+1] - pi[1];
|
||||
const err_b = data[i+2] - pi[2];
|
||||
|
||||
// Update pixel
|
||||
data[i] = pi[0];
|
||||
data[i+1] = pi[1];
|
||||
data[i+2] = pi[2];
|
||||
|
||||
indexes[i / 4] = index;
|
||||
|
||||
// Distribute error
|
||||
err(x + 1, y, err_r * 7/16, err_g * 7/16, err_b * 7/16);
|
||||
err(x - 1, y + 1, err_r * 3/16, err_g * 3/16, err_b * 3/16);
|
||||
err(x, y + 1, err_r * 5/16, err_g * 5/16, err_b * 5/16);
|
||||
err(x + 1, y + 1, err_r * 1/16, err_g * 1/16, err_b * 1/16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function hires(indexes, buffer) {
|
||||
// Scan line mapping table for Apple II Hi-Res screen.
|
||||
// Index into the array is the y-coordinate. The value
|
||||
// in the array is the offset (in bytes) from the
|
||||
// start of the hi-res screen buffer to the start of the
|
||||
// scan line. The scan line itself is 40 bytes wide.
|
||||
const offsets = [
|
||||
0x0000,0x0400,0x0800,0x0c00,0x1000,0x1400,0x1800,0x1c00,
|
||||
0x0080,0x0480,0x0880,0x0c80,0x1080,0x1480,0x1880,0x1c80,
|
||||
0x0100,0x0500,0x0900,0x0d00,0x1100,0x1500,0x1900,0x1d00,
|
||||
0x0180,0x0580,0x0980,0x0d80,0x1180,0x1580,0x1980,0x1d80,
|
||||
0x0200,0x0600,0x0a00,0x0e00,0x1200,0x1600,0x1a00,0x1e00,
|
||||
0x0280,0x0680,0x0a80,0x0e80,0x1280,0x1680,0x1a80,0x1e80,
|
||||
0x0300,0x0700,0x0b00,0x0f00,0x1300,0x1700,0x1b00,0x1f00,
|
||||
0x0380,0x0780,0x0b80,0x0f80,0x1380,0x1780,0x1b80,0x1f80,
|
||||
0x0028,0x0428,0x0828,0x0c28,0x1028,0x1428,0x1828,0x1c28,
|
||||
0x00a8,0x04a8,0x08a8,0x0ca8,0x10a8,0x14a8,0x18a8,0x1ca8,
|
||||
0x0128,0x0528,0x0928,0x0d28,0x1128,0x1528,0x1928,0x1d28,
|
||||
0x01a8,0x05a8,0x09a8,0x0da8,0x11a8,0x15a8,0x19a8,0x1da8,
|
||||
0x0228,0x0628,0x0a28,0x0e28,0x1228,0x1628,0x1a28,0x1e28,
|
||||
0x02a8,0x06a8,0x0aa8,0x0ea8,0x12a8,0x16a8,0x1aa8,0x1ea8,
|
||||
0x0328,0x0728,0x0b28,0x0f28,0x1328,0x1728,0x1b28,0x1f28,
|
||||
0x03a8,0x07a8,0x0ba8,0x0fa8,0x13a8,0x17a8,0x1ba8,0x1fa8,
|
||||
0x0050,0x0450,0x0850,0x0c50,0x1050,0x1450,0x1850,0x1c50,
|
||||
0x00d0,0x04d0,0x08d0,0x0cd0,0x10d0,0x14d0,0x18d0,0x1cd0,
|
||||
0x0150,0x0550,0x0950,0x0d50,0x1150,0x1550,0x1950,0x1d50,
|
||||
0x01d0,0x05d0,0x09d0,0x0dd0,0x11d0,0x15d0,0x19d0,0x1dd0,
|
||||
0x0250,0x0650,0x0a50,0x0e50,0x1250,0x1650,0x1a50,0x1e50,
|
||||
0x02d0,0x06d0,0x0ad0,0x0ed0,0x12d0,0x16d0,0x1ad0,0x1ed0,
|
||||
0x0350,0x0750,0x0b50,0x0f50,0x1350,0x1750,0x1b50,0x1f50,
|
||||
0x03d0,0x07d0,0x0bd0,0x0fd0,0x13d0,0x17d0,0x1bd0,0x1fd0
|
||||
];
|
||||
|
||||
const SCREEN_WIDTH = 280;
|
||||
const SCREEN_WIDTH_COLOR = SCREEN_WIDTH/2;
|
||||
const SCREEN_HEIGHT = 192;
|
||||
const PIXEL_BITS_PER_BYTE = 7;
|
||||
|
||||
for (let y = 0; y < SCREEN_HEIGHT; ++y) {
|
||||
let hbas = offsets[y];
|
||||
let hidx = y * SCREEN_WIDTH_COLOR;
|
||||
|
||||
// Process two bytes at a time (20 per scan line) since pixel patterns
|
||||
// repeat every two bytes (7 color pixels).
|
||||
for (let pair = 0; pair < (SCREEN_WIDTH_COLOR / PIXEL_BITS_PER_BYTE); ++pair) {
|
||||
// Count the pixels in each "palette"; the most votes wins the byte
|
||||
let pal1 = 0; // count of "palette 1" (green/violet) pixels
|
||||
let pal2 = 0; // count of "palette 2" (orange/blue) pixels
|
||||
|
||||
// Accumulate the pixel bit-pairs into accum at offset
|
||||
let accum = 0;
|
||||
let offset = 0;
|
||||
|
||||
for (let pixel = 0; pixel < PIXEL_BITS_PER_BYTE; ++pixel) {
|
||||
const index = indexes[hidx++];
|
||||
let bits = 0;
|
||||
|
||||
// Note that pixels are in "reverse" order
|
||||
switch (index) {
|
||||
case 0: bits = 0; break;
|
||||
case 1: bits = 2; ++pal1; break;
|
||||
case 2: bits = 1; ++pal1; break;
|
||||
case 3: bits = 3; break;
|
||||
case 4: bits = 0; break;
|
||||
case 5: bits = 2; ++pal2; break;
|
||||
case 6: bits = 1; ++pal2; break;
|
||||
case 7: bits = 3; break;
|
||||
default:
|
||||
throw new Error(`Invalid palette index: ${index} ${y}`);
|
||||
}
|
||||
|
||||
accum |= ( bits << offset );
|
||||
offset += 2;
|
||||
|
||||
// bits: 01234560123456
|
||||
// pixels: 00112233445566
|
||||
|
||||
// NOTE: This is a poor approximation and doesn't account for white
|
||||
// emerging from any two adjacent lit bits and other NTSC fun.
|
||||
|
||||
if (pixel == 3 || pixel == 6) {
|
||||
// emit byte
|
||||
let b = accum & 0x7f;
|
||||
accum >>= 7;
|
||||
offset = 1;
|
||||
|
||||
if (pal2 > pal1)
|
||||
b |= 0x80;
|
||||
|
||||
buffer[hbas] = b;
|
||||
hbas++;
|
||||
|
||||
pal1 = 0;
|
||||
pal2 = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
<script src="vniic.js"></script>
|
||||
|
|
Loading…
Reference in New Issue