pt3_lib: add directory with just the pt3 player

This will be less optimized than pt3_player but possibly
easier for other programs to use.
This commit is contained in:
Vince Weaver 2019-06-07 15:18:51 -04:00
parent e003095820
commit 73d9b710c7
11 changed files with 3269 additions and 0 deletions

29
pt3_lib/Makefile Normal file
View File

@ -0,0 +1,29 @@
include ../Makefile.inc
DOS33 = ../dos33fs-utils/dos33
PNG2GR = ../gr-utils/png2gr
all: pt3_lib.dsk
$(DOS33):
cd ../dos33fs-utils && make
pt3_lib.dsk: PT3_TEST HELLO
cp empty.dsk pt3_lib.dsk
$(DOS33) -y pt3_lib.dsk SAVE A HELLO
$(DOS33) -y pt3_lib.dsk BSAVE -a 0x1000 PT3_TEST
HELLO: hello.bas
../asoft_basic-utils/tokenize_asoft < hello.bas > HELLO
#
PT3_TEST: pt3_test.o
ld65 -o PT3_TEST pt3_test.o -C ../linker_scripts/apple2_1000.inc
pt3_test.o: pt3_test.s pt3_lib.s interrupt_handler.s zp.inc
ca65 -o pt3_test.o pt3_test.s -l pt3_test.lst
#
clean:
rm -f *~ *.o *.lst PT3_TEST HELLO

47
pt3_lib/OPTIMIZATION.txt Normal file
View File

@ -0,0 +1,47 @@
Code Optimization
~~~~~~~~~~~~~~~~~
The original working code is about 4k (not counting the pt3 file)
and has an overhead of roughly 20% when playing a song interrupt-driven
at 50Hz.
I'm keeping some stats here as I try to optimize the size and speed.
Song: "Summer of Rain" SR.PT3
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
lz4 compressed
pt3 size: raw size: ym5 size: pt3.lz4:
3871 137015 7637 1793
Size=pt3lib_end - note_a
Decoder Type size ZP use raw decode total CPU overhead
-------------------------------------------------------------
Original 3407 22B 1F.22 31s 171s 18%
VolTableGen 3302 22B 20.0E 32s 171s 19%
SizeOpts 3262 22B 20.0A 32s 171s 19%
MoreSizeOpt 3203 22B 1F.1D 31s 171s 18%
Qkumba#1 2937 ?? 1D.18 29s 171s 17%
Qkumba#2 2879 ?? 1C.18 28s 171s 16%
Qkumba#3+vmw 2816 ?? 1C.22 28s 171s 16%
Times: Validated
BH.PT3: 10.0B 16 1:33 93 17.2%
CH.PT3: 1D.12 29 2:49 169 17.2%
CR.PT3: 0F.25 15 1:30 90 16.7% Yes
DF.PT3: 19.1C 25 2:27 147 17.0%
EA.PT3: 1E.13 30 2:53 173 17.3% Yes
F4.PT3: 18.1D 24 2:16 136 17.6%
FC.PT3: 20.24 32 3:12 192 16.7%
FR.PT3: 0B.0A 11 1:01 61 18.0%
HI.PT3: 11.19 17 1:34 94 18.0%
I2.PT3: 1E.0C 30 2:59 179 16.8%
IT.PT3: 16.19 22 2:11 131 16.8% Yes
MB.PT3: 14.08 20 1:59 119 16.8%
ND.PT3: 14.1C 20 1:52 112 17.9%
OS.PT3: 13.24 19 1:48 108 17.6%
RI.PT3: 0F.03 15 1:26 86 17.4%
SD.PT3: 11.16 17 1:40 100 17.0%
SR.PT3: 1F.22 31 2:51 171 18.1%
VC.PT3: 1B.20 27 2:40 160 16.9%

17
pt3_lib/README.pt3_lib Normal file
View File

@ -0,0 +1,17 @@
The PT3_player Library
~~~~~~~~~~~~~~~~~~~~~~
by Vince "Deater" Weaver
7 June 2019
http://www.deater.net/weave/vmwprod/pt3_player/
Plays Vortex Tracker II .pt3 files on the Apple II
This code is meant as a relatively simple, reasonably optimized version
of the PT3 Vortex-Tracker player for use in other programs.
The orignal player code can be found in ../pt3_player/
That codebase is being *extremely* optimized to the point it's no longer
very straightforward to reuse the code.

BIN
pt3_lib/empty.dsk Normal file

Binary file not shown.

2
pt3_lib/hello.bas Normal file
View File

@ -0,0 +1,2 @@
10 PRINT "PT3 LIB TEST V0.1"
100 PRINT CHR$ (4)"BRUN PT3_TEST"

157
pt3_lib/interrupt_handler.s Normal file
View File

@ -0,0 +1,157 @@
;================================
;================================
; mockingboard interrupt handler
;================================
;================================
; On Apple II/6502 the interrupt handler jumps to address in 0xfffe
; This is in the ROM, which saves the registers
; on older IIe it saved A to $45 (which could mess with DISK II)
; newer IIe doesn't do that.
; It then calculates if it is a BRK or not (which trashes A)
; Then it sets up the stack like an interrupt and calls 0x3fe
TIME_OFFSET EQU 13
interrupt_handler:
; pha ; save A ; 3
; A is saved in $45 by firmware
txa
pha ; save X
tya
pha ; save Y
; inc $0404 ; debug (flashes char onscreen)
bit $C404 ; clear 6522 interrupt by reading T1C-L ; 4
lda DONE_PLAYING ; 3
beq pt3_play_music ; if song done, don't play music ; 3/2nt
jmp exit_interrupt ; 3
;============
; 13
pt3_play_music:
; decode a frame of music
jsr pt3_make_frame
; handle song over condition
lda DONE_SONG
beq mb_write_frame ; if not done, continue
lda LOOP ; see if looping
beq move_to_next
pt3_loop_smc:
lda #0 ; looping, move to loop location
sta current_pattern
lda #$0
sta current_line
sta current_subframe
sta DONE_SONG ; undo the next song
beq done_interrupt ; branch always
move_to_next:
; same as "press right"
ldx #$20
jmp quiet_exit
;======================================
; Write frames to Mockingboard
;======================================
; for speed could merge this into
; the decode code
mb_write_frame:
tax ; set up reg count ; 2
;============
; 2
;==================================
; loop through the 14 registers
; reading the value, then write out
;==================================
mb_write_loop:
lda AY_REGISTERS,X ; load register value ; 4
; special case R13. If it is 0xff, then don't update
; otherwise might spuriously reset the envelope settings
cpx #13 ; 2
bne mb_not_13 ; 3/2nt
cmp #$ff ; 2
beq mb_skip_13 ; 3/2nt
;============
; typ 5
mb_not_13:
; address
stx MOCK_6522_ORA1 ; put address on PA1 ; 4
stx MOCK_6522_ORA2 ; put address on PA2 ; 4
lda #MOCK_AY_LATCH_ADDR ; latch_address for PB1 ; 2
sta MOCK_6522_ORB1 ; latch_address on PB1 ; 4
sta MOCK_6522_ORB2 ; latch_address on PB2 ; 4
ldy #MOCK_AY_INACTIVE ; go inactive ; 2
sty MOCK_6522_ORB1 ; 4
sty MOCK_6522_ORB2 ; 4
; value
lda AY_REGISTERS,X ; load register value ; 4
sta MOCK_6522_ORA1 ; put value on PA1 ; 4
sta MOCK_6522_ORA2 ; put value on PA2 ; 4
lda #MOCK_AY_WRITE ; ; 2
sta MOCK_6522_ORB1 ; write on PB1 ; 4
sta MOCK_6522_ORB2 ; write on PB2 ; 4
sty MOCK_6522_ORB1 ; 4
sty MOCK_6522_ORB2 ; 4
;===========
; 60
mb_no_write:
inx ; point to next register ; 2
cpx #14 ; if 14 we're done ; 2
bmi mb_write_loop ; otherwise, loop ; 3/2nt
;============
; 7
mb_skip_13:
jmp exit_interrupt
;=================================
; Finally done with this interrupt
;=================================
done_interrupt:
quiet_exit:
stx DONE_PLAYING
jsr clear_ay_both
;ldx #$ff ; also mute the channel
stx AY_REGISTERS+7 ; just in case
done_key:
exit_interrupt:
pla
tay ; restore Y
pla
tax ; restore X
lda $45 ; restore A
; pla ; restore a ; 4
rti ; return from interrupt ; 6
;============
; typical
; ???? cycles

241
pt3_lib/mockingboard_a.s Normal file
View File

@ -0,0 +1,241 @@
; Mockingboad programming:
; + Has two 6522 I/O chips connected to two AY-3-8910 chips
; + Optionally has some speech chips controlled via the outport on the AY
; + Often in slot 4
; TODO: how to auto-detect?
; References used:
; http://macgui.com/usenet/?group=2&id=8366
; 6522 Data Sheet
; AY-3-8910 Data Sheet
;========================
; Mockingboard card
; Essentially two 6522s hooked to the Apple II bus
; Connected to AY-3-8910 chips
; PA0-PA7 on 6522 connected to DA0-DA7 on AY
; PB0 on 6522 connected to BC1
; PB1 on 6522 connected to BDIR
; PB2 on 6522 connected to RESET
; left speaker
MOCK_6522_ORB1 EQU $C400 ; 6522 #1 port b data
MOCK_6522_ORA1 EQU $C401 ; 6522 #1 port a data
MOCK_6522_DDRB1 EQU $C402 ; 6522 #1 data direction port B
MOCK_6522_DDRA1 EQU $C403 ; 6522 #1 data direction port A
; right speaker
MOCK_6522_ORB2 EQU $C480 ; 6522 #2 port b data
MOCK_6522_ORA2 EQU $C481 ; 6522 #2 port a data
MOCK_6522_DDRB2 EQU $C482 ; 6522 #2 data direction port B
MOCK_6522_DDRA2 EQU $C483 ; 6522 #2 data direction port A
; AY-3-8910 commands on port B
; RESET BDIR BC1
MOCK_AY_RESET EQU $0 ; 0 0 0
MOCK_AY_INACTIVE EQU $4 ; 1 0 0
MOCK_AY_READ EQU $5 ; 1 0 1
MOCK_AY_WRITE EQU $6 ; 1 1 0
MOCK_AY_LATCH_ADDR EQU $7 ; 1 1 1
;========================
; Mockingboard Init
;========================
; Initialize the 6522s
; set the data direction for all pins of PortA/PortB to be output
mockingboard_init:
lda #$ff ; all output (1)
sta MOCK_6522_DDRB1
sta MOCK_6522_DDRA1
sta MOCK_6522_DDRB2
sta MOCK_6522_DDRA2
rts
;======================
; Reset Left AY-3-8910
;======================
reset_ay_both:
lda #MOCK_AY_RESET
sta MOCK_6522_ORB1
lda #MOCK_AY_INACTIVE
sta MOCK_6522_ORB1
;======================
; Reset Right AY-3-8910
;======================
;reset_ay_right:
;could be merged with both
lda #MOCK_AY_RESET
sta MOCK_6522_ORB2
lda #MOCK_AY_INACTIVE
sta MOCK_6522_ORB2
rts
; Write sequence
; Inactive -> Latch Address -> Inactive -> Write Data -> Inactive
;=========================================
; Write Right/Left to save value AY-3-8910
;=========================================
; register in X
; value in MB_VALUE
write_ay_both:
; address
stx MOCK_6522_ORA1 ; put address on PA1 ; 3
stx MOCK_6522_ORA2 ; put address on PA2 ; 3
lda #MOCK_AY_LATCH_ADDR ; latch_address on PB1 ; 2
sta MOCK_6522_ORB1 ; latch_address on PB1 ; 3
sta MOCK_6522_ORB2 ; latch_address on PB2 ; 3
ldy #MOCK_AY_INACTIVE ; go inactive ; 2
sty MOCK_6522_ORB1 ; 3
sty MOCK_6522_ORB2 ; 3
; value
lda MB_VALUE ; 3
sta MOCK_6522_ORA1 ; put value on PA1 ; 3
sta MOCK_6522_ORA2 ; put value on PA2 ; 3
lda #MOCK_AY_WRITE ; ; 2
sta MOCK_6522_ORB1 ; write on PB1 ; 3
sta MOCK_6522_ORB2 ; write on PB2 ; 3
sty MOCK_6522_ORB1 ; 3
sty MOCK_6522_ORB2 ; 3
rts ; 6
;===========
; 51
;=======================================
; clear ay -- clear all 14 AY registers
; should silence the card
;=======================================
clear_ay_both:
ldx #14
lda #0
sta MB_VALUE
clear_ay_left_loop:
jsr write_ay_both
dex
bpl clear_ay_left_loop
rts
;=======================================
; Detect a Mockingboard card
;=======================================
; Based on code from the French Touch "Pure Noise" Demo
; Attempts to time an instruction sequence with a 6522
;
; If found, puts in bMB
; MB_ADDRL:MB_ADDRH has address of Mockingboard
; returns X=0 if not found, X=1 if found
mockingboard_detect:
lda #0
sta MB_ADDRL
mb_detect_loop: ; self-modifying
lda #$07 ; we start in slot 7 ($C7) and go down to 0 ($C0)
ora #$C0 ; make it start with C
sta MB_ADDRH
ldy #04 ; $CX04
ldx #02 ; 2 tries?
mb_check_cycle_loop:
lda (MB_ADDRL),Y ; timer 6522 (Low Order Counter)
; count down
sta TEMP ; 3 cycles
lda (MB_ADDRL),Y ; + 5 cycles = 8 cycles
; between the two accesses to the timer
sec
sbc TEMP ; subtract to see if we had 8 cycles
cmp #$f8 ; -8
bne mb_not_in_this_slot
dex ; decrement, try one more time
bne mb_check_cycle_loop ; loop detection
inx ; Mockingboard found (X=1)
done_mb_detect:
;stx bMB ; store result to bMB
rts ; return
mb_not_in_this_slot:
dec mb_detect_loop+1 ; decrement the "slot" (self_modify)
bne mb_detect_loop ; loop down to one
ldx #00
beq done_mb_detect
;alternative MB detection from Nox Archaist
; lda #$04
; sta MB_ADDRL
; ldx #$c7
;
;find_mb:
; stx MB_ADDRH
;
; ;detect sound I
;
; sec
; ldy #$00
; lda (MB_ADDRL), y
; sbc (MB_ADDRL), y
; cmp #$05
; beq found_mb
; dex
; cpx #$c0
; bne find_mb
; ldx #$00 ;no mockingboard found
; rts
;
;found_mb:
; ldx #$01 ;mockingboard found
; rts
;
; ;optionally detect sound II
;
; sec
; ldy #$80
; lda (MB_ADDRL), y
; sbc (MB_ADDRL), y
; cmp #$05
; beq found_mb
;=======================================
; Detect a Mockingboard card in Slot4
;=======================================
; Based on code from the French Touch "Pure Noise" Demo
; Attempts to time an instruction sequence with a 6522
;
; MB_ADDRL:MB_ADDRH has address of Mockingboard
; returns X=0 if not found, X=1 if found
mockingboard_detect_slot4:
lda #0
sta MB_ADDRL
mb4_detect_loop: ; self-modifying
lda #$04 ; we're only looking in Slot 4
ora #$C0 ; make it start with C
sta MB_ADDRH
ldy #04 ; $CX04
ldx #02 ; 2 tries?
mb4_check_cycle_loop:
lda (MB_ADDRL),Y ; timer 6522 (Low Order Counter)
; count down
sta TEMP ; 3 cycles
lda (MB_ADDRL),Y ; + 5 cycles = 8 cycles
; between the two accesses to the timer
sec
sbc TEMP ; subtract to see if we had 8 cycles
cmp #$f8 ; -8
bne mb4_not_in_this_slot
dex ; decrement, try one more time
bne mb4_check_cycle_loop ; loop detection
inx ; Mockingboard found (X=1)
done_mb4_detect:
rts ; return
mb4_not_in_this_slot:
ldx #00
beq done_mb4_detect

BIN
pt3_lib/pt3_lib.dsk Normal file

Binary file not shown.

2329
pt3_lib/pt3_lib.s Normal file

File diff suppressed because it is too large Load Diff

184
pt3_lib/pt3_test.s Normal file
View File

@ -0,0 +1,184 @@
;=================
; VMW PT3_LIB test
;=================
; template for using the pt3_lib
; zero page definitions
.include "zp.inc"
; Location the files load at.
; If you change this, you need to update the Makefile
PT3_LOC = song
;=============================
; Setup
;=============================
pt3_setup:
jsr HOME
jsr TEXT
;===========================
; Check for Apple II/II+/IIc
;===========================
; this is used to see if we have lowecase support
lda $FBB3 ; IIe and newer is $06
cmp #6
beq apple_iie
lda #1 ; set if older than a IIe
sta apple_ii
apple_iie:
;===============
; init variables
;===============
lda #0
sta DONE_PLAYING
sta LOOP
;=======================
; Detect mockingboard
;========================
; Note, we do this, but then ignore it, as sometimes
; the test fails and then you don't get music.
; In theory this could do bad things if you had something
; easily confused in slot4, but that's probably not an issue.
; print detection message
; lda #<mocking_message ; load loading message
; sta OUTL
; lda #>mocking_message
; sta OUTH
; jsr move_and_print ; print it
jsr mockingboard_detect_slot4 ; call detection routine
cpx #$1
beq mockingboard_found
; lda #<not_message ; if not found, print that
; sta OUTL
; lda #>not_message
; sta OUTH
; inc CV
; jsr move_and_print
; jmp forever_loop ; and wait forever
mockingboard_found:
; lda #<found_message ; print found message
; sta OUTL
; lda #>found_message
; sta OUTH
; inc CV
; jsr move_and_print
;============================
; Init the Mockingboard
;============================
jsr mockingboard_init
jsr reset_ay_both
jsr clear_ay_both
;=========================
; Setup Interrupt Handler
;=========================
; Vector address goes to 0x3fe/0x3ff
; FIXME: should chain any existing handler
lda #<interrupt_handler
sta $03fe
lda #>interrupt_handler
sta $03ff
;============================
; Enable 50Hz clock on 6522
;============================
sei ; disable interrupts just in case
lda #$40 ; Continuous interrupts, don't touch PB7
sta $C40B ; ACR register
lda #$7F ; clear all interrupt flags
sta $C40E ; IER register (interrupt enable)
lda #$C0
sta $C40D ; IFR: 1100, enable interrupt on timer one oflow
sta $C40E ; IER: 1100, enable timer one interrupt
lda #$E7
sta $C404 ; write into low-order latch
lda #$4f
sta $C405 ; write into high-order latch,
; load both values into counter
; clear interrupt and start counting
; 4fe7 / 1e6 = .020s, 50Hz
;==================
; init song
;==================
jsr pt3_init_song
;============================
; Enable 6502 interrupts
;============================
start_interrupts:
cli ; clear interrupt mask
;============================
; Loop forever
;============================
main_loop:
jmp main_loop
;==============================-=========
;========================================
; Helper routines below
;========================================
;========================================
;=========
; vars
;=========
time_frame: .byte $0
apple_ii: .byte $0
;=========
;routines
;=========
.include "mockingboard_a.s"
.include "interrupt_handler.s"
.include "pt3_lib.s"
;=========
; strings
;=========
;mocking_message: .asciiz "LOOKING FOR MOCKINGBOARD IN SLOT #4"
not_message: .byte "NOT "
found_message: .asciiz "FOUND"
;done_message: .asciiz "DONE PLAYING"
;=============
; include song
;=============
.align 256 ; must be on page boundary
; this can be fixed but some changes would have
; to be made throughout the player code
song:
.incbin "../pt3_player/music/EA.PT3"

263
pt3_lib/zp.inc Normal file
View File

@ -0,0 +1,263 @@
.define EQU =
LZ4_SRC EQU $00
LZ4_DST EQU $02
LZ4_END EQU $04
COUNT EQU $06
DELTA EQU $08
;; Zero page monitor routines addresses
WNDLFT EQU $20
WNDWDTH EQU $21
WNDTOP EQU $22
WNDBTM EQU $23
CH EQU $24
CV EQU $25
GBASL EQU $26
GBASH EQU $27
BASL EQU $28
BASH EQU $29
BAS2L EQU $2A
BAS2H EQU $2B
H2 EQU $2C
V2 EQU $2D
MASK EQU $2E
LASTIN EQU $3F
COLOR EQU $30
MODE EQU $31
INVFLG EQU $32
PROMPT EQU $33
YSAV EQU $34
YSAV1 EQU $35
CSWL EQU $36 ; address of COUT1 routine
CSWH EQU $37
KSWL EQU $38 ; key in routine
KSWH EQU $39
SEEDL EQU $4E
SEEDH EQU $4F
; dos33 zero page = 26-2f, 35-38, 3e 3f 40-4d
; overlap applesoft 67-6a,6f,70,af,b0,ca-cd,d8
; DOS33: Confirmed kills $68
RWTSL EQU $60
RWTSH EQU $61
DOSBUFL EQU $62
DOSBUFH EQU $63
FILEML EQU $64
FILEMH EQU $65
;TURNING EQU $60
;SCREEN_X EQU $61 ; not used?
;SCREEN_Y EQU $62
;ANGLE EQU $63
;HORIZ_SCALE_I EQU $64
;HORIZ_SCALE_F EQU $65
;FACTOR_I EQU $66
;FACTOR_F EQU $67
;DX_I EQU $68
;DX_F EQU $69
;SPACEX_I EQU $6A
;SPACEX_F EQU $6B
;CX_I EQU $6C
;CX_F EQU $6D
;DY_I EQU $6E
;DY_F EQU $6F
AY_REGISTERS EQU $70
A_FINE_TONE EQU $70
A_COARSE_TONE EQU $71
B_FINE_TONE EQU $72
B_COARSE_TONE EQU $73
C_FINE_TONE EQU $74
C_COARSE_TONE EQU $75
NOISE EQU $76
ENABLE EQU $77
A_VOLUME EQU $78
B_VOLUME EQU $79
C_VOLUME EQU $7A
ENVELOPE_FINE EQU $7B
ENVELOPE_COARSE EQU $7C
ENVELOPE_SHAPE EQU $7D
COPY_OFFSET EQU $7E
DECODER_STATE EQU $7F
PATTERN_L EQU $80
PATTERN_H EQU $81
ORNAMENT_L EQU $82
ORNAMENT_H EQU $83
SAMPLE_L EQU $84
SAMPLE_H EQU $85
DECODE_ERROR EQU $90
A_COLOR EQU $91
B_COLOR EQU $92
C_COLOR EQU $93
COPY_TIME EQU $94
DECOMPRESS_TIME EQU $95
TIME_TAKEN EQU $96
SCREEN_Y EQU $97
WHICH_FILE EQU $98
COLOR_MASK EQU $99
RASTERBARS_ON EQU $9A
RANDOM_POINTER EQU $9B
LOOP EQU $9C
MB_VALUE EQU $9D
;MB_CHUNK EQU $9E
MB_ADDRL EQU $9F
MB_ADDRH EQU $A0
DONE_PLAYING EQU $A1
MB_CHUNK_OFFSET EQU $A2
DONE_SONG EQU $A3
FIRE_FB_L EQU $A4
FIRE_FB_H EQU $A5
FIRE_FB2_L EQU $A6
FIRE_FB2_H EQU $A7
FIRE_FB_LINE EQU $A8
FIRE_Q EQU $A9
FIRE_Y EQU $AA
FIRE_X EQU $AB
; More zero-page addresses
; we try not to conflict with anything DOS, MONITOR or BASIC related
;COLOR1 EQU $E0
COLOR2 EQU $E1
;MATCH EQU $E2
XX EQU $E3
;YY EQU $E4
;SHIPY EQU $E4
;YADD EQU $E5
;LOOP EQU $E6
;MEMPTRL EQU $E7
;MEMPTRH EQU $E8
;NAMEL EQU $E9
;NAMEH EQU $EA
;NAMEX EQU $EB
;CHAR EQU $EC
DISP_PAGE EQU $ED
DRAW_PAGE EQU $EE
;FIRST EQU $F0
LASTKEY EQU $F1
;PADDLE_STATUS EQU $F2
XPOS EQU $F3
YPOS EQU $F4
namlo = $f6
namhi = $f7
step = $f8 ; state for stepper motor
tmptrk = $f9 ; temporary copy of current track
phase = $fa ; current phase for /seek
TEMP EQU $FA
;RUN EQU $FA
;TEMP2 EQU $FB
TEMPY EQU $FB
INL EQU $FC
INH EQU $FD
OUTL EQU $FE
OUTH EQU $FF
KEYPRESS EQU $C000
KEYRESET EQU $C010
;; SOFT SWITCHES
CLR80COL EQU $C000 ; PAGE0/PAGE1 normal
SET80COL EQU $C001 ; PAGE0/PAGE1 switches PAGE0 in Aux instead
EIGHTYCOL EQU $C00D
SPEAKER EQU $C030
SET_GR EQU $C050
SET_TEXT EQU $C051
FULLGR EQU $C052
TEXTGR EQU $C053
PAGE0 EQU $C054
PAGE1 EQU $C055
LORES EQU $C056 ; Enable LORES graphics
HIRES EQU $C057 ; Enable HIRES graphics
AN3 EQU $C05E ; Annunciator 3
PADDLE_BUTTON0 EQU $C061
PADDL0 EQU $C064
PTRIG EQU $C070
;; BASIC ROUTINES
NORMAL EQU $F273
;; MONITOR ROUTINES
HLINE EQU $F819 ;; HLINE Y,$2C at A
VLINE EQU $F828 ;; VLINE A,$2D at Y
CLRSCR EQU $F832 ;; Clear low-res screen
CLRTOP EQU $F836 ;; clear only top of low-res screen
SETCOL EQU $F864 ;; COLOR=A
TEXT EQU $FB36
TABV EQU $FB5B ;; VTAB to A
BASCALC EQU $FBC1 ;;
VTAB EQU $FC22 ;; VTAB to CV
HOME EQU $FC58 ;; Clear the text screen
WAIT EQU $FCA8 ;; delay 1/2(26+27A+5A^2) us
SETINV EQU $FE80 ;; INVERSE
SETNORM EQU $FE84 ;; NORMAL
COUT EQU $FDED ;; output A to screen
COUT1 EQU $FDF0 ;; output A to screen
CROUT EQU $FD8E ;; send a RETURN
CROUT1 EQU $FD8B ;; send a RETURN and clear end of line
PRBYTE EQU $FDDA
PRHEX EQU $FDE3
;; Applesoft routines
HCLR EQU $F3F2
;HGR_PAGE EQU $E6
COLOR_BLACK EQU 0
COLOR_RED EQU 1
COLOR_DARKBLUE EQU 2
COLOR_PURPLE EQU 3
COLOR_DARKGREEN EQU 4
COLOR_GREY EQU 5
COLOR_MEDIUMBLUE EQU 6
COLOR_LIGHTBLUE EQU 7
COLOR_BROWN EQU 8
COLOR_ORANGE EQU 9
COLOR_GREY2 EQU 10
COLOR_PINK EQU 11
COLOR_LIGHTGREEN EQU 12
COLOR_YELLOW EQU 13
COLOR_AQUA EQU 14
COLOR_WHITE EQU 15
COLOR_BOTH_BLACK EQU $00
COLOR_BOTH_RED EQU $11
COLOR_BOTH_DARKBLUE EQU $22
COLOR_BOTH_DARKGREEN EQU $44
COLOR_BOTH_GREY EQU $55
COLOR_BOTH_MEDIUMBLUE EQU $66
COLOR_BOTH_LIGHTBLUE EQU $77
COLOR_BOTH_BROWN EQU $88
COLOR_BOTH_ORANGE EQU $99
COLOR_BOTH_PINK EQU $BB
COLOR_BOTH_LIGHTGREEN EQU $CC
COLOR_BOTH_YELLOW EQU $DD
COLOR_BOTH_AQUA EQU $EE
COLOR_BOTH_WHITE EQU $FF
AUX_BOTH_MEDIUMBLUE EQU $33 ; 0011 0011
AUX_BOTH_GREY EQU $AA ; 1010 1010