view secb.s @ 1:704b2c9dc19e default tip

Remove extraneous unused and incorrect definition
author William Astle <lost@l-w.ca>
date Wed, 02 Jan 2019 10:11:19 -0700
parents 605ff82c4618
children
line wrap: on
line source

                *pragma nolist
                include defs.s
DC0DC           equ 0xC0DC                      ; needed for Disk Basic path jump backs
                *pragma list
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; EXTENDED COLOR BASIC ROM area
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                org EXBAS
                fcc 'EX'                        ; magic number that Color Basic uses to identify the presence of Extended Basic
L8002           ldx #L80DE                      ; point to command interpretation table information
                ldu #COMVEC+10                  ; point to command interpretation table location
                ldb #10                         ; 10 bytes to move
                jsr LA59A                       ; copy command interpretation table
                ldx #LB277                      ; initialize Disk Basic's entries to error
                stx 3,u
                stx 8,u
                ldx #XIRQSV                     ; set up IRQ service routine
                stx IRQVEC+1
                ldx ZERO                        ; reset the TIMER value
                stx TIMVAL
                jsr XVEC18                      ; do a bunch of initialization
                ldd #0x2c05                     ; initialize DLOAD baud rate constant and timeout
                std DLBAUD
                ldx #USR0                       ; set up pointer to USR routine addresses
                stx USRADR
                ldu #LB44A                      ; set up USR routine addresses to "FC error"
                ldb #10                         ; there are 10 routines
L8031           stu ,x++                        ; set a routine to FC error
                decb                            ; done all?
                bne L8031                       ; brif not
                lda #0x7e                       ; op code of JMP extended (for RAM hook intialization)
                sta RVEC20                      ; command interpretation loop
                ldx #XVEC20
                stx RVEC20+1
                sta RVEC15                      ; expression evaluation
                ldx #XVEC15
                stx RVEC15+1
                sta RVEC19                      ; number parsing
                ldx #XVEC19
                stx RVEC19+1
                sta RVEC9                       ; PRINT
                ldx #XVEC9
                stx RVEC9+1
                sta RVEC17                      ; error handler
                ldx #XVEC17
                stx RVEC17+1
                sta RVEC4                       ; generic input
                ldx #XVEC4
                stx RVEC4+1
                sta RVEC3                       ; generic output
                ldx #XVEC3
                stx RVEC3+1
                sta RVEC8                       ; close file
                ldx #XVEC8
                stx RVEC8+1
                sta RVEC23                      ; tokenize line
                ldx #XVEC23
                stx RVEC23+1
                sta RVEC18                      ; RUN
                ldx #XVEC18
                stx RVEC18+1
                sta EXPJMP                      ; exponentiation
                ldx #L8489
                stx EXPJMP+1
                jsr L96E6                       ; initialize graphics stuff
                lda PIA0+3                      ; enable 60Hz interrupt
                ora #1
                sta PIA0+3
                ldx #'D*256+'K                  ; magic number for a Disk Basic ROM
                cmpx DOSBAS                     ; do we have a Disk Basic ROM?
                lbeq DOSBAS+2                   ; brif so - launch it
                andcc #0xaf                     ; enable interrupts
L80B2           ldx #L80E8-1                    ; show sign on message
                jsr STRINOUT
L80B8           ldx #XBWMST                     ; install warm start handler
                stx RSTVEC
                jmp LA0E2                       ; set up warm start flag and launch immediate mode
; Extended Basic warm start code
XBWMST          fcb 0xff                        ; mark routine as invalid so that ROMs are always copied to RAM on RESET
                clr PLYTMR                      ; cancel any PLAY command in progress
                clr PLYTMR+1
                lda PIA0+3                      ; enable 60Hz interrupt
                ora #1
                sta PIA0+3
                jmp BAWMST                      ; let Color Basic's warm start process run
; This code is to fix the famous PCLEAR bug. It replaces dead code in the 1.0 ROM. This patch corrects
; the input pointer so that it points to the correct place after the program has been relocated by
; PCLEAR instead of continuing with something that, in the best case, is a syntax error.
L80D0           lda CURLIN                      ; immediate mode?
                inca
                beq L80DD                       ; brif so
                tfr y,d                         ; save offset to D
                subd TXTTAB                     ; see how far into the program we are
                addd CHARAD                     ; now adjust the input pointer based on that
                std CHARAD                      ; save corrected input pointer
L80DD           rts
L80DE           fcb 25                          ; 25 Extended Basic commands
                fdb L8183                       ; reserved word table (commands)
                fdb L813C                       ; interpretation handler (commands)
                fcb 14                          ; 14 Extended Basic functions
                fdb L821E                       ; reserved word table (functions)
                fdb L8168                       ; function handler
L80E8           fcc 'EXTENDED COLOR BASIC 2.0'
                fcb 0x0d
                fcc 'COPR. 1982, 1986 BY TANDY  '
                fcb 0x0d
                fcc 'UNDER LICENSE FROM MICROSOFT'
                fcb 0x0d,0x0d,0x00
; Extended Basic command interpretation loop
L813C           cmpa #0xcb                      ; is it an Extended Basic command?
                bhi L8148                       ; brif not
                ldx #L81F0                      ; point to dispatch table
                suba #0xb5                      ; normalize the token number so 0 is the first entry
                jmp LADD4                       ; go transfer control to the command
L8148           cmpa #0xff                      ; is it a function token?
                beq L8154                       ; brif so - for MID$()=, TIMER=
                cmpa #0xcd                      ; is it a token for a keyword that isn't a command?
                bls L8165                       ; brif so - error for USING and FN
L8150           jmp [COMVEC+23]                 ; transfer control to Disk Basic if it is present
L8154           jsr GETNCH                      ; get token after the function flag
                cmpa #0x90                      ; MID$?
                lbeq L86D6                      ; brif so (substring replacement)
                cmpa #0x9f                      ; TIMER?
                lbeq L8960                      ; brif so - TIMER setting
                jsr RVEC22                      ; do a RAM hook in case something wants to extend this
L8165           jmp LB277                       ; we have nothing valid here
; Function handler
L8168           cmpb #2*33                      ; is it a valid Extended Basic function?
                bls L8170                       ; brif so
L816C           jmp [COMVEC+28]                 ; transfer control to Disk Basic if it is present
L8170           subb #2*20                      ; normalize Extended Basic functions to 0
                cmpb #2*8                       ; Above HEX$?
                bhi L817D                       ; brif so - we don't pre-evaluate an argument
                pshs b                          ; save token value
                jsr LB262                       ; evaluate the function parameter
                puls b                          ; get back token value
L817D           ldx #L8257                      ; point to dispatch table
                jmp LB2CE                       ; go transfer control to the function
; Reserved words (commands)
L8183           fcs 'DEL'                       ; 0xb5
                fcs 'EDIT'                      ; 0xb6
                fcs 'TRON'                      ; 0xb7
                fcs 'TROFF'                     ; 0xb8
                fcs 'DEF'                       ; 0xb9
                fcs 'LET'                       ; 0xba
                fcs 'LINE'                      ; 0xbb
                fcs 'PCLS'                      ; 0xbc
                fcs 'PSET'                      ; 0xbd
                fcs 'PRESET'                    ; 0xbe
                fcs 'SCREEN'                    ; 0xbf
                fcs 'PCLEAR'                    ; 0xc0
                fcs 'COLOR'                     ; 0xc1
                fcs 'CIRCLE'                    ; 0xc2
                fcs 'PAINT'                     ; 0xc3
                fcs 'GET'                       ; 0xc4
                fcs 'PUT'                       ; 0xc5
                fcs 'DRAW'                      ; 0xc6
                fcs 'PCOPY'                     ; 0xc7
                fcs 'PMODE'                     ; 0xc8
                fcs 'PLAY'                      ; 0xc9
                fcs 'DLOAD'                     ; 0xca
                fcs 'RENUM'                     ; 0xcb
                fcs 'FN'                        ; 0xcc
                fcs 'USING'                     ; 0xcd
; Dispatch table (commands)
L81F0           fdb DEL                         ; 0xb5 DEL
                fdb EDIT                        ; 0xb6 EDIT
                fdb TRON                        ; 0xb7 TRON
                fdb TROFF                       ; 0xb8 TROFF
                fdb DEF                         ; 0xb9 DEF
                fdb LET                         ; 0xba LET (note: implemented by Color Basic!)
                fdb LINE                        ; 0xbb LINE
                fdb PCLS                        ; 0xbc PCLS
                fdb PSET                        ; 0xbd PSET
                fdb PRESET                      ; 0xbe PRESET
                fdb SCREEN                      ; 0xbf SCREEN
                fdb PCLEAR                      ; 0xc0 PCLEAR
                fdb COLOR                       ; 0xc1 COLOR
                fdb CIRCLE                      ; 0xc2 CIRCLE
                fdb PAINT                       ; 0xc3 PAINT
                fdb GET                         ; 0xc4 GET
                fdb PUT                         ; 0xc5 PUT
                fdb DRAW                        ; 0xc6 DRAW
                fdb PCOPY                       ; 0xc7 PCOPY
                fdb PMODETOK                    ; 0xc8 PMODE
                fdb PLAY                        ; 0xc9 PLAY
                fdb DLOAD                       ; 0xca DLOAD
                fdb RENUM                       ; 0xcb RENUM
; Reserved words (functions)
L821E           fcs 'ATN'                       ; 0x94
                fcs 'COS'                       ; 0x95
                fcs 'TAN'                       ; 0x96
                fcs 'EXP'                       ; 0x97
                fcs 'FIX'                       ; 0x98
                fcs 'LOG'                       ; 0x99
                fcs 'POS'                       ; 0x9a
                fcs 'SQR'                       ; 0x9b
                fcs 'HEX$'                      ; 0x9c
                fcs 'VARPTR'                    ; 0x9d
                fcs 'INSTR'                     ; 0x9e
                fcs 'TIMER'                     ; 0x9f
                fcs 'PPOINT'                    ; 0xa0
                fcs 'STRING$'                   ; 0xa1
; Dispatch table (functions)
L8257           fdb ATN                         ; 0x94 ATN
                fdb COS                         ; 0x95 COS
                fdb TAN                         ; 0x96 TAN
                fdb EXP                         ; 0x97 EXP
                fdb FIX                         ; 0x98 FIX
                fdb LOG                         ; 0x99 LOG
                fdb POS                         ; 0x9a POS
                fdb SQR                         ; 0x9b SQR
                fdb HEXDOL                      ; 0x9c HEX$
                fdb VARPTRTOK                   ; 0x9d VARPTR
                fdb INSTR                       ; 0x9e INSTR
                fdb TIMER                       ; 0x9f TIMER
                fdb PPOINT                      ; 0xa0 PPOINT
                fdb STRING                      ; 0xa1 STRING$
; Generic output handler
XVEC3           tst DEVNUM                      ; screen?
                lbeq L95AC                      ; brif so - force text screen active
                pshs b                          ; save register
                ldb DEVNUM                      ; get output device
                cmpb #-3                        ; check for DLOAD
                puls b                          ; restore register
                bne L8285                       ; brif not DLOAD
                leas 2,s                        ; bail out of output handler if DLOAD
L8285           rts
; Close file handler. This corrects a bug in Color Basic 1.0 which didn't handle writing the
; end of file block correctly. That bug is fixed in Color Basic 1.1 so this isn't required
; if a recent enough version of Color Basic is installed.
XVEC8           lda DEVNUM                      ; get device number
                inca                            ; is it tape?
                bne L8285                       ; brif not - we aren't going to mess with it
                lda FILSTA                      ; get tape file status
                cmpa #2                         ; output file?
                bne L8285                       ; brif not
                lda CINCTR                      ; is there anything waiting to be written out?
                bne L8285                       ; brif so - mainline code will handle it properly
                clr DEVNUM                      ; reset output to screen
                leas 2,s                        ; don't return to mainline code
                jmp LA444                       ; write EOF block
; RUN handler - sets up some Extended Basic stuff to defaults at program start
XVEC18          ldd #0xba42                     ; initialize PLAY volume
                std VOLHI
                lda #2                          ; set PLAY tempo to 2, PLAY octave to 3
                sta TEMPO
                sta OCTAVE
                asla                            ; set default note length to 5
                sta NOTELN
                clr DOTVAL                      ; don't do any note length extension
                ldd ZERO                        ; initialize DRAW angle and scale to default 1
                std ANGLE
                ldb #128                        ; initialize horizontal and vertical default coordinates to the middle of the screen
                std HORDEF
                ldb #96
                std VERDEF
                rts
; Command interpretation loop handler; we need to intercept this to implement TRON/TROFF
XVEC20          leas 2,s                        ; don't return to the mainline code
L82BB           andcc #0xaf                     ; make sure interrupts are running
                jsr LADEB                       ; do a BREAK/pause check
                ldx CHARAD                      ; save input pointer
                stx TINPTR
                lda ,x+                         ; get current input character
                beq L82CF                       ; brif end of line
                cmpa #':                        ; statement separator?
                beq L82F1                       ; brif so
                jmp LB277                       ; raise error we got here with extra junk
L82CF           lda ,x++                        ; get first byte of next line address
                sta ENDFLG                      ; use it to set "END" flag to "END"
                bne L82D8                       ; brif not end of program
                jmp LAE15                       ; go do the "END"
L82D8           ldd ,x+                         ; get line number of next line (and leave pointer one before line text)
                std CURLIN                      ; set current line number
                stx CHARAD                      ; save input pointer
                lda TRCFLG                      ; are we tracing?
                beq L82F1                       ; brif not
                lda #'[                         ; show opening marker for TRON line number
                jsr PUTCHR
                lda CURLIN                      ; restore MSB of line number
                jsr LBDCC                       ; show line number
                lda #']                         ; show closing marker for TRON line number
                jsr PUTCHR
L82F1           jsr GETNCH                      ; get the start of the statement
                tfr cc,b                        ; save status flags
                cmpa #0x98                      ; is it CSAVE?
                beq L8316                       ; brif so - go to Extended Basic patch (adds CSAVEM)
                cmpa #0x97                      ; is it CLOAD?
                beq L8311                       ; brif so - go to Extended Basic patch (adds multi-origin binaries)
                tfr b,cc                        ; restore character status
                jsr LADC6                       ; go process command
                bra L82BB                       ; restart interpretation loop
; Tokenizaton handler. This is actually a hack to intercept CLOAD and CSAVE during immediate mode by causing the
; tokenization routine to return to the interpretation loop above instead of the mainline interpretation loop. This
; is necessary because the first command encountered on a line in immediate mode is executed BEFORE the interpretation
; loop RAM hook is called. This patch doesn't actually affect tokenization itself at all.
XVEC23          ldx 2,s                         ; get return address of caller to the tokenizer
                cmpx #LAC9D                     ; is it coming from immediate mode prior to executing the line?
                bne L8310                       ; brif not
                ldx #L82F1                      ; force return to Extended Basic's main loop patch above
                stx 2,s
L8310           rts
; These two patches are set up this way so that control can be transferred back to the original Color Basic
; implementations if the Extended Basic addons are not triggered.
L8311           jsr L8C62                       ; transfer control to Extended Basic's CLOAD handler
                bra L82BB                       ; go do another command
L8316           bsr L831A                       ; go do Extended Basic's CSAVE handler
                bra L82BB                       ; go do another command
; Extended Basic's CSAVE handler which implements CSAVEM (which Color Basic does not have)
L831A           jsr GETNCH                      ; get character after CSAVE
                cmpa #'M                        ; is it CSAVEM?
                lbne CSAVE                      ; brif not - Color Basic can handle this
                jsr GETNCH                      ; eat the "M"
                jsr LA578                       ; parse file name
                bsr L836C                       ; get start address
                stx CASBUF+13                   ; save it in file header
                bsr L836C                       ; get end address
                cmpx 2,s                        ; compare to start address
                lblo LB44A                      ; brif end address is before the start address
                bsr L836C                       ; get execution address
                stx CASBUF+11                   ; put in file header
                jsr GETCCH                      ; are we at the end of the commmand?
                bne L8310                       ; brif not
                lda #2                          ; file type to machine language
                ldx ZERO                        ; set to binary and single block
                jsr LA65F                       ; write header
                clr FILSTA                      ; mark any open tape file closed
                inc BLKTYP                      ; set block type to data
                jsr WRLDR                       ; write a data leader
                ldx 4,s                         ; get starting address
L834D           stx CBUFAD                      ; set start of data address
                lda #255                        ; try a full length block by default
                sta BLKLEN
                ldd 2,s                         ; get ending address
                subd CBUFAD                     ; see how much is left
                bhs L835E                       ; brif we have more to write
                leas 6,s                        ; clean up stack
                jmp LA491                       ; write EOF block
L835E           cmpd #255                       ; do we have a full block left?
                bhs L8367                       ; brif so
                incb                            ; set block size to remainder
                stb BLKLEN
L8367           jsr SNDBLK                      ; write a data block
                bra L834D                       ; go see if we have more to write
L836C           jsr SYNCOMMA                    ; make sure we have a comma
                jsr LB73D                       ; evaluate unsigned expression to X
                ldu ,s                          ; get return address
                stx ,s                          ; save result on stack
                tfr u,pc                        ; return to caller
; COS function
COS             ldx #L83AB                      ; point to PI/2 constant
                jsr LB9C2                       ; add to argument ( cos(x) = sin((pi/2)+x) )
L837E           jmp SIN                         ; now calculate sin((pi/2)+x)
; TAN function. This is determined by the identity TAN(X) = SIN(X)/COS(X)
TAN             jsr LBC2F                       ; save FPA0 in FPA3
                clr RELFLG                      ; reset quadrant flag
                bsr L837E                       ; calculate SIN(x)
                ldx #V4A                        ; save result in FPA5
                jsr LBC35
                ldx #V40                        ; get back original argument
                jsr LBC14
                clr FP0SGN                      ; force result positive
                lda RELFLG                      ; get quadrant flag
                bsr L83A6                       ; calculate COS(x)
                tst FP0EXP                      ; did we get 0 for COS(x)
                lbeq LBA92                      ; brif so - overflow
                ldx #V4A                        ; point to sin(x)
L83A3           jmp LBB8F                       ; divide the sin(x) value by the cos(x) value
L83A6           pshs a                          ; save sign flag
                jmp LBFA6                       ; expand polynomial
L83AB           fcb 0x81,0x49,0x0f,0xda,0xa2    ; pi/2 constant
; ATN function (inverse tangent). There are two calculation streams used to improve precision.
; One if the parameter is >= 1.0 and the other if it is < 1.0
ATN             lda FP0SGN                      ; get sign of argument
                pshs a                          ; save it
                bpl L83B8                       ; brif positive
                bsr L83DC                       ; flip sign of argument
L83B8           lda FP0EXP                      ; get exponent
                pshs a                          ; save it
                cmpa #0x81                      ; exponent for 1.0
                blo L83C5                       ; brif less - value is less than 1.0
                ldx #LBAC5                      ; point to FP constant 1.0
                bsr L83A3                       ; calculate reciprocal
L83C5           ldx #L83E0                      ; point to polynomical coefficients
                jsr LBEF0                       ; expand polynomial
                puls a                          ; get exponent of argument
                cmpa #0x81                      ; did we do a reciprocal calculation?
                blo L83D7                       ; brif not
                ldx #L83AB                      ; subtract result from pi/2 if we did
                jsr LB9B9
L83D7           puls a                          ; get sign of original
                tsta                            ; was it positive?
                bpl L83DF                       ; brif so
L83DC           jmp LBEE9                       ; flip sign of result
L83DF           rts
; Chebyshev modified taylor series coefficients for inverse tangent. Note that these diverge quite significantly
; from the standard taylor series after 1/9. The standard coefficients are 1/1,-1/3, 1/5, -1/7, 1/9, -1/11, and
; so on. These modified coefficients yield reasonable accuracy for the precision available, presumably with
; fewer coefficients.
L83E0           fcb 11                          ; 12 coefficients
                fcb 0x76,0xb3,0x83,0xbd,0xd3    ; -0.000684793912
                fcb 0x79,0x1e,0xf4,0xa6,0xf5    ; 0.00485094216
                fcb 0x7b,0x83,0xfc,0xb0,0x10    ; -0.0161117018
                fcb 0x7c,0x0c,0x1f,0x67,0xca    ; 0.0342096381
                fcb 0x7c,0xde,0x53,0xcb,0xc1    ; -0.0542791328
                fcb 0x7d,0x14,0x64,0x70,0x4c    ; 0.0724571965 
                fcb 0x7d,0xb7,0xea,0x51,0x7a    ; -0.0898023954
                fcb 0x7d,0x63,0x30,0x88,0x7e    ; 0.110932413
                fcb 0x7e,0x92,0x44,0x99,0x3a    ; -0.142839808
                fcb 0x7e,0x4c,0xcc,0x91,0xc7    ; 0.199999121
                fcb 0x7f,0xaa,0xaa,0xaa,0x13    ; -0.333333316
                fcb 0x81,0x00,0x00,0x00,0x00    ; 1.0
; Chebyshev modified taylor series coefficients for the ln(x)/ln(2) (base 2 log of x)
L841D           fcb 3                           ; four coefficients
                fcb 0x7f,0x5e,0x56,0xcb,0x79    ; 0.434255942 from (2/7)/ln(2)
                fcb 0x80,0x13,0x9b,0x0b,0x64    ; 0.576584541 from (2/5)/ln(2)
                fcb 0x80,0x76,0x38,0x93,0x16    ; 0.961800759 from (2/3)/ln(2) 
                fcb 0x82,0x38,0xaa,0x3b,0x20    ; 2.88539007 from 2/ln(2)
L8432           fcb 0x80,0x35,0x04,0xf3,0x34    ; 1/sqrt(2)
L8437           fcb 0x81,0x35,0x04,0xf3,0x34    ; sqrt(2)
L843C           fcb 0x80,0x80,0x00,0x00,0x00    ; -0.5
L8441           fcb 0x80,0x31,0x72,0x17,0xf8    ; ln(2)
; LOG function (natural log, ln)
; FP representation is of the form A*2^B. Thus, the log routine determines the value of
; ln(A*2^B).
;
; ln(A*2^B) = ln(A) + ln(2^B) = ln(A) + B*ln(2) = (ln(A)/ln(2) + B)*ln(2), OR:
; (log2(A) + B)*ln(2)
; Now if we write A as A*(sqrt(2)/sqrt(2)), we haven't changed anything so:
; (log2(A*sqrt(2)/sqrt(2)) + B)*ln(2) = (log2(A*sqrt(2)) - log2(sqrt(2)) + B) * ln(2)
; which gives: (-1/2 + log2(A*sqrt(2)) + B) * ln(2)
;
; Everything except log2(A*sqrt(2)) is either constant or trivial.
;
; What the actual code below feeds into the modified taylor series is actually:
; 1 - (sqrt(2)/(A + sqrt(2)) which algebra reveals to be (A*sqrt(2)-1)/(A*sqrt(2)+1)
;
; Thus, the code is using (A*sqrt(2)-1)/(A*sqrt(2)+1) instead of A*sqrt(2) as one would
; expect from the identities. However, the modified coefficients in the series above
; could be correcting for that or the introduced error was deemed acceptable.
; NOTE: this routine does NOT return 0 for LOG(1)
LOG             jsr LBC6D                       ; get status of FPA0
                lble LB44A                      ; brif <= 0 - logarithms don't exist in that case
                ldx #L8432                      ; point to 1/sqrt(2)
                lda FP0EXP                      ; get exponent of argument
                suba #0x80                      ; remove bias
                pshs a                          ; save it for later
                lda #0x80                       ; force exponent to 0 (this turns FPA0 into A in the above description)
                sta FP0EXP
                jsr LB9C2                       ; add 1/sqrt(2) to A
                ldx #L8437                      ; point to sqrt(2)
                jsr LBB8F                       ; divide that by FPA0
                ldx #LBAC5                      ; point to 1.0
                jsr LB9B9                       ; subtract result from 1.0: Now FPA0 is 1-(sqrt(2)/(A+1/sqrt(2)))
                ldx #L841D                      ; point to coefficients
                jsr LBEF0                       ; expand polynomial (calculate base 2 log of modified argument)
                ldx #L843C                      ; point to -0.5
                jsr LB9C2                       ; add result
                puls b                          ; get original exponent back
                jsr LBD99                       ; add B to FPA0
                ldx #L8441                      ; point to ln(2)
                jmp LBACA                       ; multiply by ln(2) which gives us the result in base e
; SQR function (square root) - returns the principle root (positive)
SQR             jsr LBC5F                       ; move argument to FPA1 (first argument for exponentiation)
                ldx #LBEC0                      ; point to 0.5 (exponent for square root)
                jsr LBC14                       ; set up second argument to exponentiation (the exponent)
; Exponentiation operator
; This is calculated as A^x = e^(x*ln(A)) where A is in FPA1 and x is in FPA0
L8489           beq EXP                         ; do "EXP" if exponent is 0 (this will catch 0^0)
                tsta                            ; check that the base is not 0
                bne L8491                       ; brif base is not 0
                jmp LBA3A                       ; 0^(nonzero) is 0
L8491           ldx #V4A                        ; save exponent (to FPA5)
                jsr LBC35
                clrb                            ; result sign will default to positive
                lda FP1SGN                      ; check if base is positive
                bpl L84AC                       ; brif so
                jsr INT                         ; convert exponent to integer
                ldx #V4A                        ; point to original expoent
                lda FP1SGN                      ; get sign of FPA1
                jsr LBCA0                       ; compare original exponent with truncated one
                bne L84AC                       ; brif not equal
                coma                            ; flip sign
                ldb CHARAC                      ; get LS byte of integer exponent (result sign flag)
L84AC           jsr LBC4C                       ; copy FPA1 (base) to FPA0 (A = sign)
                pshs b                          ; save result sign
                jsr LOG                         ; get natural log of the base
                ldx #V4A                        ; multiply the log by the exponent
                jsr LBACA
                bsr EXP                         ; now raise e to the resulting power
                puls a                          ; get result sign
                rora                            ; brif it was negative
                lbcs LBEE9                      ; brif negative - flip sign
                rts
L84C4           fcb 0x81,0x38,0xaa,0x3b,0x29    ; 1.44269504 (correction factor for exponential function)
; Chebyshev modified taylor series coefficients for e^x
L84C9           fcb 7                           ; eight coefficients
                fcb 0x71,0x34,0x58,0x3e,0x56    ; 1/(7!*(CF^7))
                fcb 0x74,0x16,0x7e,0xb3,0x1b    ; 1/(6!*(CF^6))
                fcb 0x77,0x2f,0xee,0xe3,0x85    ; 1/(5!*(CF^5))
                fcb 0x7a,0x1d,0x84,0x1c,0x2a    ; 1/(4!*(CF^4))
                fcb 0x7c,0x63,0x59,0x58,0x0a    ; 1/(3!*(CF^3))
                fcb 0x7e,0x75,0xfd,0xe7,0xc6    ; 1/(2!*(CF^2))
                fcb 0x80,0x31,0x72,0x18,0x10    ; 1/(1!*(CF^1))
                fcb 0x81,0x00,0x00,0x00,0x00    ; 1
; EXP function (e^x)
EXP             ldx #L84C4                      ; point to correction factor
                jsr LBACA                       ; multiply it
                jsr LBC2F                       ; save corrected argument to FPA3
                lda FP0EXP                      ; get exponent of FPA0
                cmpa #0x88                      ; is it too big?
                blo L8504                       ; brif not
L8501           jmp LBB5C                       ; to 0 (underflow) or overflow error
L8504           jsr INT                         ; convert argument to an integer
                lda CHARAC                      ; get ls byte of integer
                adda #0x81                      ; was argument 127? if so, the OV error; adds bias
                beq L8501
                deca                            ; adjust for the extra +1 above
                pshs a                          ; save integer exponent
                ldx #V40                        ; get fractional part of argument
                jsr LB9B9
                ldx #L84C9                      ; point to coefficients
                jsr LBEFF                       ; evaluate polynomial on the fractional part
                clr RESSGN                      ; force result to be positive
                puls a                          ; get back original exponent
                jsr LBB48                       ; add original exponent to the fractional result
                rts
; FIX function (truncate/round toward 0) (NOTE: INT() always rounds down so INT(-0.5) gives -1 but FIX(-0.5) gives 0)
FIX             jsr LBC6D                       ; get status of argument
                bmi L852C                       ; brif negative
L8529           jmp INT                         ; do regular "int" if positive
L852C           com FP0SGN                      ; flip the sign
                bsr L8529                       ; do "INT" on this
                jmp LBEE9                       ; flip the sign back
; EDIT command
EDIT            jsr L89AE                       ; get line number
                leas 2,s                        ; we're not going to return to the main loop
L8538           lda #1                          ; "LIST" flag
                sta VD8                         ; set to list the line
                jsr LAD01                       ; find line number
                lbcs LAED2                      ; brif line wasn't found
                jsr LB7C2                       ; go unpack the line into the buffer
                tfr y,d                         ; calculate the actual length of the line
                subd #LINBUF+2
                stb VD7                         ; save line length (it will only be 8 bits)
L854D           ldd BINVAL                      ; get the line number
                jsr LBDCC                       ; display it
                jsr LB9AC                       ; put a space after it
                ldx #LINBUF+1                   ; point to iput uffer
                ldb VD8                         ; are we listing?
                bne L8581                       ; brif so
L855C           clrb                            ; reset digit accumulator
L855D           jsr L8687                       ; get a keypress
                jsr L90AA                       ; set carry if not numeric
                bcs L8570                       ; brif not a number
                suba #'0                        ; remove ASCII bias
                pshs a                          ; save digit value
                lda #10                         ; multiply accumulator by 10
                mul
                addb ,s+                        ; add in new digit
                bra L855D                       ; go check for another digit
L8570           subb #1                         ; this converts 0 to 1, but *only* 0 to 1
                adcb #1
                cmpa #'A                        ; abort?
                bne L857D                       ; brif not
                jsr LB958                       ; to a CR
                bra L8538                       ; restart EDIT process
L857D           cmpa #'L                        ; list?
                bne L858C                       ; brif not
L8581           bsr L85B4                       ; list the line
                clr VD8                         ; reset to "not listing"
                jsr LB958                       ; do a CR
                bra L854D                       ; start editing
L858A           leas 2,s                        ; lose return address
L858C           cmpa #0x0d                      ; ENTER?
                bne L859D                       ; brif not
                bsr L85B4                       ; echo out the line
L8592           jsr LB958                       ; do a CR
                ldx #LINBUF+1                   ; reset input pointer to start of buffer
                stx CHARAD
                jmp LACA8                       ; join immediate mode to replace the line in the program
L859D           cmpa #'E                        ; exit?
                beq L8592                       ; brif so - end edit with no echo
                cmpa #'Q                        ; quit?
                bne L85AB                       ; brif not
                jsr LB958                       ; do a CR
                jmp LAC73                       ; go to immediate mode with no fanfare - no changes saved
L85AB           bsr L85AF                       ; go do commands
                bra L855C                       ; go handle another command
L85AF           cmpa #0x20                      ; space?
                bne L85C3                       ; brif not
                skip2
L85B4           ldb #LBUFMX-1                   ; display up to a whole line
L85B6           lda ,x                          ; get buffer chracter
                beq L85C2                       ; brif end of line
                jsr PUTCHR                      ; output character
                leax 1,x                        ; move to next character
                decb                            ; done?
                bne L85B6                       ; brif not
L85C2           rts
L85C3           cmpa #'D                        ; delete?
                bne L860F                       ; brif not
L85C7           tst ,x                          ; end of line?
                beq L85C2                       ; brif so - can't delete
                bsr L85D1                       ; remove a character
                decb                            ; done all requested?
                bne L85C7                       ; brif not
                rts
L85D1           dec VD7                         ; account for character being removed
                leay -1,x                       ; set pointer and compensate for increment below
L85D5           leay 1,y                        ; move to next character
                lda 1,y                         ; get next character
                sta ,y                          ; move it forward
                bne L85D5                       ; brif we didn't hit the end of the buffer
                rts
L85DE           cmpa #'I                        ; insert?
                beq L85F5                       ; brif so
                cmpa #'X                        ; extend?
                beq L85F3                       ; brif so
                cmpa #'H                        ; "hack"?
                bne L8646                       ; brif not
                clr ,x                          ; mark current location as end of line
                tfr x,d                         ; calculate new line length
                subd #LINBUF+2
                stb VD7                         ; save new length
L85F3           bsr L85B4                       ; display the line
L85F5           jsr L8687                       ; read a character
                cmpa #0x0d                      ; ENTER?
                beq L858A                       ; brif so - terminate entry
                cmpa #0x1b                      ; ESC?
                beq L8625                       ; brif so - back to command mode
                cmpa #0x08                      ; backspace?
                bne L8626                       ; brif no
                cmpx #LINBUF+1                  ; are we at the start of the buffer?
                beq L85F5                       ; brif so - it's a no-op
                bsr L8650                       ; move pointer back one, do a BS
                bsr L85D1                       ; remove character from the buffer
                bra L85F5                       ; go handle more input
L860F           cmpa #'C                        ; change?
                bne L85DE                       ; brif not
L8613           tst ,x                          ; is there something to change?
                beq L8625                       ; brif not
                jsr L8687                       ; get a key stroke
                bcs L861E                       ; brif valid key
                bra L8613                       ; try again if invalid key
L861E           sta ,x+                         ; put new character in the buffer
                bsr L8659                       ; echo it
                decb                            ; changed number requested?
                bne L8613                       ; brif not
L8625           rts
L8626           ldb VD7                         ; get length of line
                cmpb #LBUFMX-1                  ; at maximum line length?
                bne L862E                       ; brif not
                bra L85F5                       ; process another input character
L862E           pshs x                          ; save input pointer
L8630           tst ,x+                         ; are we at the end of the line?
                bne L8630                       ; brif not
L8634           ldb ,-x                         ; get character before current pointer, move back
                stb 1,x                         ; move it forward
                cmpx ,s                         ; at the original buffer pointer?
                bne L8634                       ; brif not
                leas 2,s                        ; remove saved buffer pointer
                sta ,x+                         ; save input character in newly made hole
                bsr L8659                       ; echo it
                inc VD7                         ; bump line length counter
                bra L85F5                       ; go handle more stuff
L8646           cmpa #0x08                      ; backspace?
                bne L865C                       ; brif not
L864A           bsr L8650                       ; move pointer back, echo BS
                decb                            ; done enough of them?
                bne L864A                       ; brif not
                rts
L8650           cmpx #LINBUF+1                  ; at start of buffer?
                beq L8625                       ; brif so
                leax -1,x                       ; move pointer back
                lda #0x08                       ; character to echo - BS
L8659           jmp PUTCHR                      ; echo character to screen
L865C           cmpa #'K                        ; "kill"?
                beq L8665                       ; brif so
                suba #'S                        ; search?
                beq L8665                       ; brif so
                rts
L8665           pshs a                          ; save kill/search flag
                bsr L8687                       ; read target
                pshs a                          ; save search character
L866B           lda ,x                          ; get current character in buffer
                beq L8685                       ; brif end of line - nothing more to search
                tst 1,s                         ; is it KILL?
                bne L8679                       ; brif so
                bsr L8659                       ; echo the character
                leax 1,x                        ; move ahead
                bra L867C                       ; check next character
L8679           jsr L85D1                       ; remove character from buffer
L867C           lda ,x                          ; get character in buffer
                cmpa ,s                         ; are we at the target?
                bne L866B                       ; brif not
                decb                            ; have we found enough of them?
                bne L866B                       ; brif not
L8685           puls y,pc                       ; clean up stack and return to main EDIT routine
L8687           jsr LA171                       ; get input from the generic input handler (will show the cursor)
                cmpa #0x7f                      ; graphics (or DEL)?
                bhs L8687                       ; brif so - ignore it
                cmpa #0x5f                      ; SHIFT-UP?
                bne L8694                       ; brif not
                lda #0x1b                       ; replace with ESC
L8694           cmpa #0x0d                      ; carriage return?
                beq L86A6                       ; brif so (C=0)
                cmpa #0x1b                      ; ESC
                beq L86A6                       ; brif so (C=0)
                cmpa #0x08                      ; backspace?
                beq L86A6                       ; brif so (C=0)
                cmpa #32                        ; control code?
                blo L8687                       ; brif control code - try again
                orcc #1                         ; set C for "valid" (printable) character
L86A6           rts
; TRON and TROFF commands
TRON            skip1lda                        ; load flag with nonzero for trace enabled (and skip next)
TROFF           clra                            ; clear flag for trace disabled
                sta TRCFLG                      ; save trace status
                rts
; POS function
POS             lda DEVNUM                      ; get original device number
                pshs a                          ; save it for later
                jsr LA5AE                       ; fetch device number
                jsr LA406                       ; check for open file
                jsr LA35F                       ; set up print parameters
                ldb DEVPOS                      ; get current line position for the device
                jmp LA5E4                       ; return position in B as unsigned
; VARPTR function
VARPTRTOK       jsr LB26A                       ; make sure we have (
                ldd ARYEND                      ; get address of end of arrays
                pshs d                          ; save it
                jsr LB357                       ; parse variable descriptor
                jsr LB267                       ; make sure there is a )
                puls d                          ; get original end of arrays
                exg x,d                         ; swap original end of arrays and the discovered variable pointer
                cmpx ARYEND                     ; did array end move (variable created?)
                bne L8724                       ; brif so (FC error)
                jmp GIVABF                      ; return the pointer (NOTE: as signed)
; MID$() assignment; note that this cannot make the string longer or shorter and if the replacement is shorter
; than the specified size, only the number of characters actually in the replacement will be used.
L86D6           jsr GETNCH                      ; eat the MID$ token
                jsr LB26A                       ; force (
                jsr LB357                       ; evaluate the variable
                pshs x                          ; save variable descriptor
                ldd 2,x                         ; point to start of original string
                cmpd FRETOP                     ; is it in string space?
                bls L86EB                       ; brif not
                subd MEMSIZ                     ; is it still in string space (top end)?
                bls L86FD                       ; brif so
L86EB           ldb ,x                          ; get length of original string
                jsr LB56D                       ; allocate space in string space
                pshs x                          ; save pointer to string space
                ldx 2,s                         ; get to original string descriptor
                jsr LB643                       ; move the string into string space
                puls x,u                        ; get new string address and string descriptor
                stx 2,u                         ; save new data address for the string
                pshs u                          ; save descriptor address again
L86FD           jsr LB738                       ; evaluate ",start"
                pshs b                          ; save start offset
                tstb                            ; is start 0?
                beq L8724                       ; brif so - strings offsets are 1-based
                ldb #255                        ; default use the entire string
                cmpa #')                        ; end of parameters?
                beq L870E                       ; brif so
                jsr LB738                       ; evaluate ",length"
L870E           pshs b                          ; save length
                jsr LB267                       ; make sure we have a )
                ldb #0xb3                       ; make sure we have =
                jsr LB26F
                bsr L8748                       ; evaluate replacement string
                tfr x,u                         ; save replacement string address
                ldx 2,s                         ; get original string descriptor
                lda ,x                          ; get length of original string
                suba 1,s                        ; subtract start position
                bhs L8727                       ; brif within the string - insert replacement
L8724           jmp LB44A                       ; raise illegal function call
L8727           inca                            ; A is now number of characters to the right of the position parameter
                cmpa ,s                         ; compare to length desired
                bhs L872E                       ; brif new length fits
                sta ,s                          ; only use as much of the length as will fit
L872E           lda 1,s                         ; get position offset
                exg a,b                         ; swap replacement length and position
                ldx 2,x                         ; point to original string address
                decb                            ; we work with 0-based offsets
                abx                             ; now X points to start of replacement
                tsta                            ; replacing 0?
                beq L8746                       ; brif so - done
                cmpa ,s                         ; is replacement shorter than the hole?
                bls L873F                       ; brif so
                lda ,s                          ; use copy the maximum number specified
L873F           tfr a,b                         ; save number to move in B
                exg u,x                         ; swap pointers so they are right for the routine
                jsr LA59A                       ; copy string data
L8746           puls a,b,x,pc                   ; clean up stack and return
L8748           jsr LB156                       ; evaluate expression
                jmp LB654                       ; make sure it's a string and return string details
; STRING$ function
STRING          jsr LB26A                       ; make sure we have (
                jsr EVALEXPB                    ; evaluate repeat count (error if > 255)
                pshs b                          ; save repeat count
                jsr SYNCOMMA                    ; make sure there's a comma
                jsr LB156                       ; evaluate the thing to repeat
                jsr LB267                       ; make sure we have a )
                lda VALTYP                      ; is it string?
                bne L8768                       ; brif so
                jsr LB70E                       ; get 8 bit character code
                bra L876B                       ; use that
L8768           jsr LB6A4                       ; get first character of string
L876B           pshs b                          ; save repeat character
                ldb 1,s                         ; get repeat count
                jsr LB50F                       ; reserve space for the string
                puls a,b                        ; get character and repeat count
                beq L877B                       ; brif NULL string
L8776           sta ,x+                         ; put character into string
                decb                            ; put enough?
                bne L8776                       ; brif not
L877B           jmp LB69B                       ; return the newly created string
; INSTR function
INSTR           jsr LB26A                       ; evaluate (
                jsr LB156                       ; evaluate first argument
                ldb #1                          ; default start position is 1 (start of string)
                pshs b                          ; save start position
                lda VALTYP                      ; get type of first argument
                bne L879C                       ; brif string - use default starting position
                jsr LB70E                       ; convert first argument into string offset
                stb ,s                          ; save offset
                beq L8724                       ; brif starting at 0 - not allowed
                jsr SYNCOMMA                    ; make sure there's a comma
                jsr LB156                       ; evaluate the search string
                jsr LB146                       ; make sure it *is* a string
L879C           ldx FPA0+2                      ; get search string descriptor
                pshs x                          ; save it
                jsr SYNCOMMA                    ; make sure we have a comma
                jsr L8748                       ; evalute the target string
                pshs x,b                        ; save address and length of target string
                jsr LB267                       ; make sure we have a )
                ldx 3,s                         ; get search string address
                jsr LB659                       ; get string details
                pshs b                          ; save search string length
                cmpb 6,s                        ; compare length of search string to the start
                blo L87D9                       ; brif start position is beyond the search string - return 0
                lda 1,s                         ; get length of target string
                beq L87D6                       ; brif targetstring is NULL - match will be immediate
                ldb 6,s                         ; get start position
                decb                            ; zero-base it
                abx                             ; now X points to the start position for the search
L87BE           leay ,x                         ; point to start of search
                ldu 2,s                         ; get target string pointer
                ldb 1,s                         ; get targetlength
                lda ,s                          ; get length of serach
                suba 6,s                        ; see how much is left in searh
                inca                            ; add one for "inclusivity"
                cmpa 1,s                        ; do we have less than the target string?
                blo L87D9                       ; brif so - we obviously won't match
L87CD           lda ,x+                         ; compare a byte
                cmpa ,u+
                bne L87DF                       ; brif no match
                decb                            ; compared all of target?
                bne L87CD                       ; brif not
L87D6           ldb 6,s                         ; get position where we matched
                skip1
L87D9           clrb                            ; flag no match
                leas 7,s                        ; clean up stack
                jmp LB4F3                       ; return unsigned B
L87DF           inc 6,s                         ; bump start position
                leax 1,y                        ; move starting pointer
                bra L87BE                       ; see if we match now
; Number parsing handler
XVEC19          cmpa #'&                        ; do we have & (hex or octal)?
L87E7           bne L8845                       ; brif not
                leas 2,s                        ; we won't return to the original invoker
L87EB           clr FPA0+2                      ; clear bottom of FPA0 for 16 bit value
                clr FPA0+3
                ldx #FPA0+2                     ; point to accumulator
                jsr GETNCH                      ; eat the &
                cmpa #'O                        ; octal?
                beq L880A                       ; brif so
                cmpa #'H                        ; hex?
                beq L881F                       ; brif so
                jsr GETCCH                      ; reset flags on input
                bra L880C                       ; go process octal (default)
L8800           cmpa #'8                        ; is it a valid octal character?
                lbhi LB277                      ; brif not (BUG: should be LBHS or above be #'7)
                ldb #3                          ; base 8 multiplier
                bsr L8834                       ; add digit to accumulator
L880A           jsr GETNCH                      ; get input character
L880C           bcs L8800                       ; brif numeric
L880E           clr FPA0                        ; clear upper bytes of FPA0
                clr FPA0+1
                clr VALTYP                      ; result is numeric
                clr FPSBYT                      ; clear out any extra precision
                clr FP0SGN                      ; make it positive
                ldb #0xa0                       ; exponent for integer aligned to right of FPA0
                stb FP0EXP
                jmp LBA1C                       ; go normalize the result and return
L881F           jsr GETNCH                      ; get input character
                bcs L882E                       ; brif digit
                jsr LB3A2                       ; set carry if not alpha
L8826           bcs L880E                       ; brif not alpha
                cmpa #'G                        ; is it valid HEX digit?
                bhs L880E                       ; brif not
                suba #7                         ; normalize A-F to be just above 0-9
L882E           ldb #4                          ; four bits per digit
                bsr L8834                       ; add digit to accumlator
                bra L881F                       ; process another digit
L8834           asl 1,x                         ; shift accumulator one bit left
                rol ,x
                lbcs LBA92                      ; brif too big - overflow
                decb                            ; done enough bit shifts?
                bne L8834                       ; brif not
L883F           suba #'0                        ; remove ASCII bias
                adda 1,x                        ; merge digit into accumlator (this cannot cause carry)
                sta 1,x
L8845           rts
; Expression evaluation handler
XVEC15          puls u                          ; get back return address
                clr VALTYP                      ; set result to numeric
                ldx CHARAD                      ; save input pointer
                jsr GETNCH                      ; get the input character
                cmpa #'&                        ; HEX or OCTAL?
                beq L87EB                       ; brif so
                cmpa #0xcc                      ; FN?
                beq L88B4                       ; brif so - do "FNx()"
                cmpa #0xff                      ; function token?
                bne L8862                       ; brif not
                jsr GETNCH                      ; get function token value
                cmpa #0x83                      ; USR?
                lbeq L892C                      ; brif so - short circuit Color Basic's USR handler
L8862           stx CHARAD                      ; restore input pointer
                jmp ,u                          ; return to mainline code
L8866           ldx CURLIN                      ; are we in immediate mode?
                leax 1,x
L886A           bne L8845                       ; brif not - we're good
                ldb #2*11                       ; code for illegal direct statement
L886E           jmp LAC46                       ; raise error
; DEF command (DEF FN, DEF USR)
DEF             ldx [CHARAD]                    ; get two input characters
                cmpx #0xff83                    ; USR?
                lbeq L890F                      ; brif so - do DEF USR
                bsr L88A1                       ; get descriptor address for FN variable
                bsr L8866                       ; disallow DEF FN in immediate mode
                jsr LB26A                       ; make sure we have (
                ldb #0x80                       ; disallow arrays as arguments
                stb ARYDIS
                jsr LB357                       ; evaluate variable
                bsr L88B1                       ; make sure it's numeric
                jsr LB267                       ; make sure we have )
                ldb #0xb3                       ; make sure we have =
                jsr LB26F
                ldx V4B                         ; get variable descriptor address
                ldd CHARAD                      ; get input pointer
                std ,x                          ; save address of the actual function code in variable descriptor
                ldd VARPTR                      ; get descriptor address of argument
                std 2,x                         ; save argument descriptor address
                jmp DATA                        ; move to the end of this statement
L88A1           ldb #0xcc                       ; make sure we have FN
                jsr LB26F
                ldb #0x80                       ; disable array lookup
                stb ARYDIS
                ora #0x80                       ; set bit 7 of first character (to indicate FN variable)
                jsr LB35C                       ; find the variable
                stx V4B                         ; save descriptor pointer
L88B1           jmp LB143                       ; make sure we have a numeric variable
; Evaluate an FN call
L88B4           bsr L88A1                       ; parse the FNx bit and get the descriptor
                pshs x                          ; save descriptor
                jsr LB262                       ; evaluate parameter
                bsr L88B1                       ; make sure it's a number
                puls u                          ; get FN descriptor
                ldb #2*25                       ; code for undefined function
                ldx 2,u                         ; point to argument variable descriptor
                beq L886E                       ; brif nothing doing there (if it was just created, this will be NULL)
                ldy CHARAD                      ; save current input pointer
                ldu ,u                          ; point to start of FN definition
                stu CHARAD                      ; put input pointer there
                lda 4,x                         ; save original value of argument and save it with current input, and variable pointers
                pshs a
                ldd ,x
                ldu 2,x
                pshs u,y,x,d
                jsr LBC35                       ; set argument variable to the argument
L88D9           jsr LB141                       ; go evaluate the FN expression
                puls d,x,y,u                    ; get back variable pointers, input pointer, and original variable value
                std ,x
                stu 2,x
                puls a
                sta 4,x
                jsr GETCCH                      ; test end of FN formula
                lbne LB277                      ; brif not end of statement - problem with the function
                sty CHARAD                      ; restore input pointer
L88EF           rts
; Error handler
XVEC17          cmpb #2*25                      ; is it a valid Extended Basic error code?
                blo L88EF                       ; brif not - return to mainline
                jsr LA7E9                       ; turn off tape
                jsr LA974                       ; turn off sound
                jsr LAD33                       ; clean up stack and other bits
                clr DEVNUM                      ; reset output to screen
                jsr LB95C                       ; do a newline if needed
                jsr LB9AF                       ; do a ?
                ldx #L890B-25*2                 ; point to error message table
                jmp LAC60                       ; go display error message
; Extended Basic error codes. Yes, NE is defined here even though it is only actually documented in the
; Disk Basic documentation. It is here for the use of DLOAD.
L890B           fcc 'UF'                        ; 25 undefined function call
                fcc 'NE'                        ; 26 File not found
; DEF USR
L890F           jsr GETNCH                      ; eat the USR token
                bsr L891C                       ; get pointer to USR call
                pshs x                          ; save FN exec address location
                bsr L8944                       ; calculate execution address
                puls u                          ; get FN address pointer
                stx ,u                          ; save new address
                rts
L891C           clrb                            ; default routine number is 0
                jsr GETNCH                      ; fetch the call number
                bcc L8927                       ; brif not a number
                suba #'0                        ; remove ASCII bias
                tfr a,b                         ; save it in the right place
                jsr GETNCH                      ; eat the call number
L8927           ldx USRADR                      ; get start address of USR jump table
                aslb                            ; two bytes per address
                abx                             ; now X points to the right entry
                rts
; Evaluate a USR call
L892C           bsr L891C                       ; find the correct routine address location
                ldx ,x                          ; get routine address
                pshs x                          ; save it
                jsr LB262                       ; evaluate argument
                ldx #FP0EXP                     ; point to FPA0 (argument value)
                lda VALTYP                      ; is it string?
                beq L8943                       ; brif not
                jsr LB657                       ; fetch string details (removes it from the string stack)
                ldx FPA0+2                      ; get string descriptor pointer
                lda VALTYP                      ; set flags for the value type
L8943           rts                             ; call the routine and return to mainline code
L8944           ldb #0xb3                       ; check for "="
                jsr LB26F
                jmp LB73D                       ; evaluate integer expression to X and return
; Extended Basic IRQ handler
XIRQSV          lda PIA0+3                      ; is it VSYNC interrupt?
                bmi L8952                       ; brif so
                rti                             ; really should clear the HSYNC interrupt here
L8952           lda PIA0+2                      ; clear VSYNC interrupt
                ldx TIMVAL                      ; increment the TIMER value
                leax 1,x
                stx TIMVAL
                jmp L9C3E                       ; check for other stuff
; TIMER=
L8960           jsr GETNCH                      ; eat the TIMER token
                bsr L8944                       ; evaluate =nnnn to X
                stx TIMVAL                      ; set the timer
                rts
; TIMER function
TIMER           ldx TIMVAL                      ; get timer value
                stx FPA0+2                      ; set it in FPA0
                jmp L880E                       ; return as positive 16 bit value
; DEL command
DEL             lbeq LB44A                      ; raise error if no argument (probably to avoid accidentally deleting line 0)
                jsr LAF67                       ; parse line number
                jsr LAD01                       ; find line
                stx VD3                         ; save address of line
                jsr GETCCH                      ; is there something more?
                beq L8990                       ; brif not
                cmpa #0xac                      ; dash?
                bne L89BF                       ; brif not - error out
                jsr GETNCH                      ; each the -
                beq L898C                       ; brif no ending line - use default line number
                bsr L89AE                       ; parse second line number and save in BINVAL
                bra L8990                       ; do the deletion
L898C           lda #0xff                       ; set to maximum line number
                sta BINVAL
L8990           ldu VD3                         ; point end to start
                skip2
L8993           ldu ,u                          ; point to start of next line
                ldd ,u                          ; check for end of program
                beq L899F                       ; brif end of program
                ldd 2,u                         ; get line number
                subd BINVAL                     ; is it in range?
                bls L8993                       ; brif so
L899F           ldx VD3                         ; get starting line address
                bsr L89B8                       ; close up gap
                jsr LAD21                       ; reset input pointer and erase variables
                ldx VD3                         ; get start of program after the deletion
                jsr LACF1                       ; recompute netl ine pointers
                jmp LAC73                       ; return to immediate mode
L89AE           jsr LAF67                       ; parse a line number
                jmp LA5C7                       ; make sure there's nothing more
L89B4           lda ,u+                         ; copy a byte
                sta ,x+
L89B8           cmpu VARTAB                     ; end of program?
                bne L89B4                       ; brif not
                stx VARTAB                      ; save new start of variables/end of program
L89BF           rts
; LINE INPUT
L89C0           jsr L8866                       ; raise error if in immediate mode
                jsr GETNCH                      ; eat the "INPUT" token
                cmpa #'#                        ; device number?
                bne L89D2                       ; brif not
                jsr LA5A5                       ; parse device number
                jsr LA3ED                       ; make sure it's valid for input
                jsr SYNCOMMA                    ; make sure there's a comma after the device number
L89D2           cmpa #'"                        ; is there a prompt?
                bne L89E1                       ; brif not
                jsr LB244                       ; parse the string
                ldb #';                         ; make sure there's a semicolon after the prompt
                jsr LB26F
                jsr LB99F                       ; go actually display the prompt
L89E1           leas -2,s                       ; make a hole on the stack (so number of return adddresses is right)
                jsr LB035                       ; read an input line from current device
                leas 2,s                        ; clean up stack
                clr DEVNUM                      ; reset to screen/keyboard
                jsr LB357                       ; parse a variable
                stx VARDES                      ; save pointer to it
                jsr LB146                       ; make sure it's a string
                ldx #LINBUF                     ; point to input buffer
                clra                            ; make sure we terminate on NUL only
                jsr LB51A                       ; parse string and store it in string space
                jmp LAFA4                       ; go assign the string to its final resting place
; RENUM command
L89FC           jsr LAF67                       ; read a line number
                ldx BINVAL                      ; get value
                rts
L8A02           ldx VD1                         ; get current old number being renumbered
L8A04           stx BINVAL                      ; save number being searched for
                jmp LAD01                       ; go find line number
RENUM           jsr LAD26                       ; erase variables
                ldd #10                         ; default line number interval and start
                std VD5                         ; set starting line number
                std VCF                         ; set number interval
                clrb                            ; now D is 0
                std VD1                         ; save default start for renumbering
                jsr GETCCH                      ; are there any arguments
                bcc L8A20                       ; brif not numeric
                bsr L89FC                       ; fetch line number
                stx VD5                         ; save line beginning number
                jsr GETCCH                      ; get input character
L8A20           beq L8A3D                       ; brif end of line
                jsr SYNCOMMA                    ; make sure we have a comma
                bcc L8A2D                       ; brif next isn't numeric
                bsr L89FC                       ; fetch starting line number
                stx VD1                         ; save the number where we start working
                jsr GETCCH                      ; fetch input character
L8A2D           beq L8A3D                       ; brif end of line
                jsr SYNCOMMA                    ; make sure we have a comma
                bcc L8A3A                       ; brif we don't have a number
                bsr L89FC                       ; parse the number
                stx VCF                         ; save interval
                beq L8A83                       ; brif we ave a zero interval
L8A3A           jsr LA5C7                       ; raise error if more stuff
L8A3D           bsr L8A02                       ; get address of old number to process
                stx VD3                         ; save address
                ldx VD5                         ; get the next renumbered line to use
                bsr L8A04                       ; find that line
                cmpx VD3                        ; is it before the previous one?
                blo L8A83                       ; brif so - raise error
                bsr L8A67                       ; make sure renumbered line numbers will be in range
                jsr L8ADD                       ; convert line numbers to "expanded" binary
                jsr LACEF                       ; recalculate next line pointers
                bsr L8A02                       ; get address of first line to renumber
                stx VD3                         ; save it
                bsr L8A91                       ; make sure line numbers exist
                bsr L8A68                       ; renumber the actual lines
                bsr L8A91                       ; update line numbers in program text
                jsr L8B7B                       ; convert packed binary line numbers to text
                jsr LAD26                       ; erase variables, reset stack, etc.
                jsr LACEF                       ; recalculate next line pointers
                jmp LAC73                       ; bounce back to immediate mode
L8A67           skip1lda                        ; set line number flag to nonzero (skip next instruction)
L8A68           clra                            ; set line number flag to zero (insert new numbers)
                sta VD8                         ; save line number flag
                ldx VD3                         ; get address of line being renumbered
                ldd VD5                         ; get the current renumbering number
                bsr L8A86                       ; return if end of program
L8A71           tst VD8                         ; test line number flag
                bne L8A77                       ; brif not adding new numbers
                std 2,x                         ; set new number
L8A77           ldx ,x                          ; point to next line
                bsr L8A86                       ; return if end of program
                addd VCF                        ; add interval to current number
                bcs L8A83                       ; brif we overflowed - bad line number
                cmpa #MAXLIN                    ; maximum legal number?
                blo L8A71                       ; brif so - do another
L8A83           jmp LB44A                       ; raise FC error
L8A86           pshs d                          ; save D (we're going to clobber it)
                ldd ,x                          ; get next line pointer
                puls d                          ; unclobber D
                bne L8A90                       ; brif not end of program
                leas 2,s                        ; return to caller's caller
L8A90           rts
L8A91           ldx TXTTAB                      ; get start of program
                leax -1,x                       ; move pointer back one (compensate for leax 1,x below)
L8A95           leax 1,x                        ; move to next line
                bsr L8A86                       ; return if end of program
L8A99           leax 3,x                        ; move past next line address and line number, go one before line
L8A9B           leax 1,x                        ; move to next character
                lda ,x                          ; check input character
                beq L8A95                       ; brif end of line
                stx TEMPTR                      ; save current pointer
                deca                            ; is it start of packed numeric line number?
                beq L8AB2                       ; brif so
                deca                            ; does line exist?
                beq L8AD3                       ; brif line number exists
                deca                            ; not part of something to process?
                bne L8A9B                       ; brif so
L8AAC           lda #3                          ; set 1st byte to 3 to indicate line number not existing
                sta ,x+
                bra L8A99                       ; go process another
L8AB2           ldd 1,x                         ; get MSB of line number
                dec 2,x                         ; is MS byte zero?
                beq L8AB9                       ; brif not
                clra                            ; set MS byte to 0
L8AB9           ldb 3,x                         ; get LSB of line number
                dec 4,x                         ; is it zero?
                beq L8AC0                       ; brif not
                clrb                            ; clear byte
L8AC0           std 1,x                         ; save binary number
                std BINVAL                      ; save trial number
                jsr LAD01                       ; find the line number
L8AC7           ldx TEMPTR                      ; get start of packed line
                bcs L8AAC                       ; brif line number not found
                ldd V47                         ; get address of line number
                inc ,x+                         ; bump first byte to 2 (exists if checking) or 1 if inserting
                std ,x                          ; save address of correct number
                bra L8A99                       ; go process more
L8AD3           clr ,x                          ; clear carry and first byte
                ldx 1,x                         ; point to address of correct line
                ldx 2,x                         ; get correct line number
                stx V47                         ; save it
                bra L8AC7                       ; insert into line
L8ADD           ldx TXTTAB                      ; get beginning of program
                bra L8AE5
L8AE1           ldx CHARAD                      ; get input pointer
                leax 1,x                        ; move it forward
L8AE5           bsr L8A86                       ; return if end of program
                leax 2,x                        ; move past line address
L8AE9           leax 1,x                        ; move forward
L8AEB           stx CHARAD                      ; save input pointer
L8AED           jsr GETNCH                      ; get an input character
L8AEF           tsta                            ; is it actual 0?
                beq L8AE1                       ; brif end of line
                bpl L8AED                       ; brif not a token
                ldx CHARAD                      ; get input pointer
                cmpa #0xff                      ; function?
                beq L8AE9                       ; brif so - ignore it (and following byte)
                jsr RVEC22                      ; do the RAM hook thing
                cmpa #0xa7                      ; THEN?
                beq L8B13                       ; brif so
                cmpa #0x84                      ; ELSE?
                beq L8B13                       ; brif so
                cmpa #0x81                      ; GO(TO|SUB)?
                bne L8AED                       ; brif not - we don't have a line number
                jsr GETNCH                      ; get TO/SUB
                cmpa #0xa5                      ; GOTO?
                beq L8B13                       ; brif so
                cmpa #0xa6                      ; GOSUB?
                bne L8AEB                       ; brif not
L8B13           jsr GETNCH                      ; fetch character after token
                bcs L8B1B                       ; brif numeric (line number)
L8B17           jsr GETCCH                      ; set flags on input character
                bra L8AEF                       ; keep checking for line numbers
L8B1B           ldx CHARAD                      ; get input pointer
                pshs x                          ; save it
                jsr LAF67                       ; parse line number
                ldx CHARAD                      ; get input pointer after line
L8B24           lda ,-x                         ; get character before pointer
                jsr L90AA                       ; set C if numeric
                bcs L8B24                       ; brif not numeric
                leax 1,x                        ; move pointer up
                tfr x,d                         ; calculate size of line number
                subb 1,s
                subb #5                         ; make sure at least 5 bytes
                beq L8B55                       ; brif exactly 5 bytes - no change
                blo L8B41                       ; brif less than 5 bytes
                leau ,x                         ; move remainder of program backward
                negb                            ; negate extra number of bytes (to subtract from X)
                leax b,x                        ; now X is the correct position to move program to
                jsr L89B8                       ; shift program backward
                bra L8B55
L8B41           stx V47                         ; save end of line number space (end of copy)
                ldx VARTAB                      ; get end of program
                stx V43                         ; set source pointer
                negb                            ; get positive difference
                leax b,x                        ; now X is the top of the destination block
                stx V41                         ; set copy destination
                stx VARTAB                      ; save new end of program
                jsr LAC1E                       ; make sure enough room and make a hole in the program
                ldx V45                         ; get end address of destination block
                stx CHARAD                      ; set input there
L8B55           puls x                          ; get starting address of the line number
                lda #1                          ; set "new number" flag
                sta ,x
                sta 2,x
                sta 4,x
                ldb BINVAL                      ; get MS byte of line number
                bne L8B67                       ; brif it is not zero
                ldb #1                          ; set to 1 if MSB is 0
                inc 2,x                         ; flag MSB as 0
L8B67           stb 1,x                         ; set MSB of line number
                ldb BINVAL+1                    ; get LSB of number
                bne L8B71                       ; brif nonzero
                ldb #1                          ; set to 1 if LSB is 0
                inc 4,x                         ; flag LSB as 0
L8B71           stb 3,x                         ; save LSB of line number
                jsr GETCCH                      ; get input character
                cmpa #',                        ; multiple line numbers? (ON GOTO, ON GOSUB)
                beq L8B13                       ; brif so - process another
                bra L8B17                       ; go look for more line numbers
L8B7B           ldx TXTTAB                      ; point to start of program
                leax -1,x                       ; move back (compensate for inc below)
L8B7F           leax 1,x                        ; move forward
                ldd 2,x                         ; get this line number
                std CURLIN                      ; save it (for error message)
                jsr L8A86                       ; return if end of program
                leax 3,x                        ; skip address and line number, stay one before line text
L8B8A           leax 1,x                        ; move to next character
L8B8C           lda ,x                          ; get input character
                beq L8B7F                       ; brif end of line
                deca                            ; valid line new line number?
                beq L8BAE                       ; brif so
                suba #2                         ; undefined line?
                bne L8B8A                       ; brif not
                pshs x                          ; save line number pointer
                ldx #L8BD9-1                    ; show UL message
                jsr STRINOUT
                ldx ,s                          ; get input pointer
                ldd 1,x                         ; get undefined line number
                jsr LBDCC                       ; display line number
                jsr LBDC5                       ; print out "IN XXXX"
                jsr LB958                       ; do a newline
                puls x                          ; get input pointer back
L8BAE           pshs x                          ; save input pointer
                ldd 1,x                         ; get binary value of line number
                std FPA0+2                      ; save it in FPA0
                jsr L880E                       ; adjust FPA0 as integer
                jsr LBDD9                       ; convert to text string
                puls u                          ; get previous input pointer address
                ldb #5                          ; each expanded line uses 5 bytes
L8BBE           leax 1,x                        ; move pointer forward (in string number) past sign
                lda ,x                          ; do we have a digit?
                beq L8BC9                       ; brif not - end of number
                decb                            ; mark a byte consumed
                sta ,u+                         ; put digit in program
                bra L8BBE                       ; copy another digit
L8BC9           leax ,u                         ; point to address at end of text number
                tstb                            ; did number fill whole space?
                beq L8B8C                       ; brif so - move on
                leay ,u                         ; save end of number pointer
                leau b,u                        ; point to the end of the original expanded number
                jsr L89B8                       ; close up gap in program
                leax ,y                         ; get end of line number pointer back
                bra L8B8C                       ; go process more
L8BD9           fcn 'UL '
; HEX$ function
HEXDOL          jsr LB740                       ; convert argument to positive integer
                ldx #STRBUF+2                   ; point to string buffer
                ldb #4                          ; convert 4 nibbles
L8BE5           pshs b                          ; save nibble counter
                clrb                            ; clear digit accumulator
                lda #4                          ; do 4 shifts
L8BEA           asl FPA0+3                      ; shift a bit off the left of the value into low bits of B
                rol FPA0+2
                rolb
                deca                            ; done all shifts?
                bne L8BEA                       ; brif not
                tstb                            ; do we have a nonzero digit?
                bne L8BFF                       ; brif so
                lda ,s                          ; is it last digit?
                deca
                beq L8BFF                       ; brif so - keep the 0
                cmpx #STRBUF+2                  ; is it a middle zero?
                beq L8C0B                       ; brif not
L8BFF           addb #'0                        ; add ASCII bias
                cmpb #'9                        ; above 9?
                bls L8C07                       ; brif not
                addb #7                         ; adjust into alpha range
L8C07           stb ,x+                         ; save digit in output
                clr ,x                          ; make sure we have a NUL term
L8C0B           puls b                          ; get back nibble counter
                decb                            ; done all?
                bne L8BE5                       ; brif not
                leas 2,s                        ; don't return mainline (we're returning a string)
                ldx #STRBUF+1                   ; point to start of converted number
                jmp LB518                       ; save string in string space, etc., and return it
; DLOAD command; this is eliminated on the Coco3. It was basically useless anyway so it was
; a good candidate to overwrite for some extra code space in the lower 16K of the internal
; ROM. Now, DLOAD functions as another entry into the RESET sequence.
DLOAD           jsr LA429                       ; close tape file
L8C1B           orcc #0x50                      ; make sure interrupts are disabled
                lda #MC3+MC1                    ; disable MMU, 32K internal ROM, not "coco" compatible
                sta INIT0
                clr TYCLR                       ; go to ROM mapping mode
                jmp SC000                       ; transfer control to the "hidden" init code
L8C28           clr INT.FLAG                    ; set the interrupt flag to not valid
                clr PIA1+3                      ; disable cartridge interrupt
L8C2E           lda #COCO+MMUEN+MC3+MC2         ; enable SCS, 16K split, MMU, COCO mode
                sta INIT0
                clr TYCLR                       ; go to ROM mode
L8C36           rts
L8C37           pshs a,b,x                      ; save registers
                ldx CURPOS                      ; get cursor position
                ldb HRWIDTH                     ; hi-res mode?
                lbne ALINK22                    ; brif so
                ldb 1,s                         ; restore B
                jmp LA30E                       ; go back to mainline code
L8C46           pshs cc                         ; save Z
                tst HRWIDTH                     ; hi-res?
                beq L8C4F                       ; brif not
                jmp ALINK23                     ; go to hi-res handler
L8C4F           puls cc                         ; get back Z
                jmp LA913                       ; go back to mainline code
                nop
                fcb 0xc7                        ; junk byte (too few NOPs above)
; This returns to the remainder of the original ECB 1.1 DLOAD code
                tstb                            ; ASCII?
                beq L8C5F                       ; brif not - do error
                jsr LAD19                       ; clear out program
                jmp LAC7C                       ; go read program
L8C5F           jmp LA616                       ; raise bad file mode
; CLOADM patch for Extended Basic
L8C62           jsr GETNCH                      ; get character after CLOAD
                cmpa #'M                        ; CLOADM?
                lbne CLOAD                      ; brif not - Color Basic's CLOAD can handle it
                clr FILSTA                      ; close tape file
                jsr GETNCH                      ; eat the "M"
                jsr LA578                       ; parse file name
                jsr LA648                       ; find the file
                tst CASBUF+10                   ; is it a chunked file?
                lbeq LA505                      ; brif not - Color Basic's CLOADM can handle it
                ldu CASBUF+8                    ; get file type and ASCII flag
                dec DEVNUM                      ; set source device to tape
                jsr LA635                       ; go read the first block
                tfr u,d                         ; put type and ASCII flag somewhere more useful
; NOTE: DLOADM comes here to do the final processing
L8C85           subd #0x200                     ; is it binary and "machine language"?
                bne L8C5F                       ; brif not - raise an error
                ldx ZERO                        ; default load offset
                jsr GETCCH                      ; is there any offset?
                beq L8C96                       ; brif not
                jsr SYNCOMMA                    ; make sure there's a comma
                jsr LB73D                       ; evaluate offset in X
L8C96           stx VD3                         ; save offset
                jsr LA5C7                       ; raise error if more stuff follows
L8C9B           bsr L8CC6                       ; get type of "amble"
                pshs a                          ; save it
                bsr L8CBF                       ; read in block length
                tfr d,y                         ; save it
                bsr L8CBF                       ; read in load address
                addd VD3                        ; add in offset
                std EXECJP                      ; save it as the execution address
                tfr d,x                         ; put load address in a pointer
                lda ,s+                         ; get "amble" type
                lbne LA42D                      ; brif postamble - close file
L8CB1           bsr L8CC6                       ; read a data byte
                sta ,x                          ; save in memory
                cmpa ,x+                        ; did it actually save?
                bne L8CCD                       ; brif not RAM - raise error
                leay -1,y                       ; done yet?
                bne L8CB1                       ; brif not
                bra L8C9B                       ; look for another "amble"
L8CBF           bsr L8CC1                       ; read a character to B
L8CC1           bsr L8CC6                       ; read character to A
                exg a,b                         ; swap character with previously read one
L8CC5           rts
L8CC6           jsr LA176                       ; read a character from input
                tst CINBFL                      ; EOF?
                beq L8CC5                       ; brif not
L8CCD           jmp LA619                       ; raise I/O error if EOF
L8CD0           bsr L8D14                       ; transmit file name
                pshs b,a                        ; save file status
                inca                            ; was file found?
                beq L8CDD                       ; brif not
                ldu ZERO                        ; zero U - first block
                bsr L8CE4                       ; read block
                puls a,b,pc                     ; restore status and return
L8CDD           ldb #2*26                       ; code for NE error
                jmp LAC46                       ; raise error
L8CE2           ldu CBUFAD                      ; get block number
L8CE4           leax 1,u                        ; bump block number
                stx CBUFAD                      ; save new block number
                ldx #CASBUF                     ; use cassette buffer
                jsr L8D7C                       ; read a block
                jmp LA644                       ; reset input buffer pointers
; Generic input handler for Extended Basic
XVEC4           lda DEVNUM                      ; get device number
                cmpa #-3                        ; DLOAD?
                bne L8D01                       ; brif not
                leas 2,s                        ; don't return to mainline code
                clr CINBFL                      ; reset EOF flag to not EOF
                tst CINCTR                      ; anything available?
                bne L8D02                       ; brif so - fetch one
                com CINBFL                      ; flag EOF
L8D01           rts
L8D02           pshs u,y,x,b                    ; save registers
                ldx CINPTR                      ; get buffer pointer
                lda ,x+                         ; get character from buffer
                pshs a                          ; save it for return
                stx CINPTR                      ; save new input pointer
                dec CINCTR                      ; account for byte removed from buffer
                bne L8D12                       ; brif buffer not empty
                bsr L8CE2                       ; go read a block
L8D12           puls a,b,x,y,u,pc               ; restore registers, return value, and return
L8D14           clra                            ; clear attempt counter
                pshs x,b,a                      ; make a hole for variables
                leay ,s                         ; set up frame pointer
                bra L8D1D                       ; go read block
L8D1B           bsr L8D48                       ; bump attempt counter
L8D1D           lda #0x8a                       ; send file request control code
                bsr L8D58
                bne L8D1B                       ; brif no echo or error
                ldx #CFNBUF+1                   ; point to file name
L8D26           lda ,x+                         ; get file name characater
                jsr L8E04                       ; send it
                cmpx #CFNBUF+9                  ; end of file name?
                bne L8D26                       ; brif not
                bsr L8D62                       ; output check byte and look for response
                bne L8D1B                       ; transmit name again if not ack
                bsr L8D72                       ; get file type (0xff is not found)
                bne L8D1B                       ; brif error
                sta 2,y                         ; save file type
                bsr L8D72                       ; read ASCII flag
                bne L8D1B                       ; brif error
                sta 3,y                         ; save ASCII flag
                bsr L8D6B                       ; read check byte
                bne L8D1B                       ; brif error
                leas 2,s                        ; lose attempt counter and check byte
                puls a,b,pc                     ; return file type and ascii flag
L8D48           inc ,y                          ; bump attempt counter
                lda ,y                          ; get new count
                cmpa #5                         ; done 5 times?
                blo L8D6A                       ; brif not
                lda #0xbc                       ; send abort code
                jsr L8E0C
                jmp LA619                       ; raise an I/O error
L8D58           pshs a                          ; save compare character
                bsr L8DB8                       ; send character
                bne L8D60                       ; brif read error
                cmpa ,s                         ; does it match? (set Z if good)
L8D60           puls a,pc                       ; restore character and return
L8D62           lda 1,y                         ; get XOR check byte
                bsr L8DB8                       ; send it and read
                bne L8D6A                       ; brif read error
                cmpa #0xc8                      ; is it ack? (set Z if so)
L8D6A           rts
L8D6B           bsr L8D72                       ; read character from rs232
                bne L8D6A                       ; brif error
                lda 1,y                         ; get check byte
                rts
L8D72           bsr L8DBC                       ; read a character from rs232
                pshs a,cc                       ; save result (and flags)
                eora 1,y                        ; accumulate xor checksum
                sta 1,y
                puls cc,a,pc                    ; restore byte, flags, and return
L8D7C           clra                            ; reset attempt counter
                pshs u,y,x,b,a                  ; make a stack frame
                asl 7,s                         ; split block number into two 7 bit chuncks
                rol 6,s
                lsr 7,s
                leay ,s                         ; set up frame pointer
                bra L8D8B
L8D89           bsr L8D48                       ; bump attempt counter
L8D8B           lda #0x97                       ; send block request code
                bsr L8D58
                bne L8D89                       ; brif error
                lda 6,y                         ; send out block number (high bits first)
                bsr L8E04
                lda 7,y
                bsr L8E04
                bsr L8D62                       ; send check byte and get ack
                bne L8D89                       ; brif error
                bsr L8D72                       ; read block size
                bne L8D89                       ; brif read error
                sta 4,y                         ; save character count
                ldx 2,y                         ; get buffer pointer
                ldb #128                        ; length of data block
L8DA7           bsr L8D72                       ; read a data byte
                bne L8D89                       ; brif error
                sta ,x+                         ; save byte in buffer
                decb                            ; done a whole block?
                bne L8DA7                       ; brif not
                bsr L8D6B                       ; read check byte
                bne L8D89                       ; brif error
                leas 4,s                        ; lose attempt counter, check byte, and buffer pointer
                puls a,b,x,pc                   ; return with character count in A, clean rest of stack
L8DB8           clr 1,y                         ; clear check byte
                bsr L8E0C                       ; output character
L8DBC           clra                            ; clear attempt counter
                pshs x,b,cc                     ; save registers and interrupt status
                orcc #0x50                      ; disable interrupts
                lda TIMOUT                      ; get timout delay (variable)
                ldx ZERO                        ; get constant timeout value
L8DC5           bsr L8DE6                       ; get RS232 status
                bcc L8DC5                       ; brif "space" - waiting for "mark"
L8DC9           bsr L8DE6                       ; get RS232 status
                bcs L8DC9                       ; brif "mark" - waiting for "space" (start bit)
                bsr L8DF9                       ; delay for half of bit time
                ldb #1                          ; set bit probe
                pshs b                          ; save it
                clra                            ; reset data byte
L8DD4           bsr L8DF7                       ; wait one bit time
                ldb PIA1+2                      ; get input bit to carry
                rorb
                bcc L8DDE                       ; brif "space" (0)
                ora ,s                          ; merge bit probe in
L8DDE           asl ,s                          ; shift bit probe over
                bcc L8DD4                       ; brif we haven't done 8 bits
                leas 1,s                        ; remove bit probe
                puls cc,b,x,pc                  ; restore interrupts, registers, and return
L8DE6           ldb PIA1+2                      ; get RS232 value
                rorb                            ; put in C
                leax 1,x                        ; bump timeout 
                bne L8DF6                       ; brif nonzero
                deca                            ; did the number of waits expire?
                bne L8DF6                       ; brif not
                leas 2,s                        ; don't return - we timed out
                puls cc,b,x                     ; restore interrupts and registers
                inca                            ; clear Z (A was zero above)
L8DF6           rts
L8DF7           bsr L8DF9                       ; do first half of bit delay then fall through for second
L8DF9           pshs a                          ; save register
                lda DLBAUD                      ; get baud rate constant
L8DFD           brn L8DFD                       ; do nothing - delay
                deca                            ; time expired?
                bne L8DFD                       ; brif not
                puls a,pc                       ; restore register and return
L8E04           pshs a                          ; save character to send
                eora 1,y                        ; accumulate chechsum
                sta 1,y
                puls a                          ; get character back
L8E0C           pshs b,a,cc                     ; save registers and interrupt status
                orcc #0x50                      ; disable interrupts
                bsr L8DF7                       ; do a bit delay
                bsr L8DF7                       ; do another bit delay
                clr PIA1                        ; set output to space (start bit)
                bsr L8DF7                       ; do a bit delay
                ldb #1                          ; bit probe start at LSB
                pshs b                          ; save bitprobe
L8E1D           lda 2,s                         ; get output byte
                anda ,s                         ; see what our current bit is
                beq L8E25                       ; brif output is 0
                lda #2                          ; set output to "marking"
L8E25           sta PIA1                        ; send bit
                bsr L8DF7                       ; do a bit delay
                asl ,s                          ; shift bit probe
                bcc L8E1D                       ; brif not last bit
                lda #2                          ; set output to marking ("stop" bit)
                sta PIA1
                leas 1,s                        ; lose bit probe
                puls cc,a,b,pc                  ; restore registers, interrupts, and return
; PRINT USING
; This is a massive block of code for something that has limited utility. It is *almost* flexible enough to
; be truly useful outside of a narrow range of use cases. Indeed, this comes in at about 1/8 of the total
; Extended Color Basic ROM.
;
; This uses several variables:
; VD5: pointer to format string descriptor
; VD7: next print item flag
; VD8: right digit counter
; VD9: left digit counter (or length of string argument)
; VDA: status byte (bits as follows):
;     6: force comma
;     5: force leading *
;     4: floating $
;     3: pre-sign
;     2: post-sign
;     0: scientific notation
L8E37           lda #1                          ; set length to use to 1
                sta VD9
L8E3B           decb                            ; consume character from format string
                jsr L8FD8                       ; show error flag if flags set
                jsr GETCCH                      ; get input character
                lbeq L8ED8                      ; brif end of line - bail
                stb VD3                         ; save remaining string length
                jsr LB156                       ; evaluate the argument
                jsr LB146                       ; error if numeric
                ldx FPA0+2                      ; get descriptor for argument
                stx V4D                         ; save it for later
                ldb VD9                         ; get length counter to use
                jsr LB6AD                       ; get B bytes of string space (do a LEFT$)
                jsr LB99F                       ; print the formatted string
                ldx FPA0+2                      ; get formatted string descriptor
                ldb VD9                         ; get requested length
                subb ,x                         ; see if we have any left over
L8E5F           decb                            ; have we got the right width?
                lbmi L8FB3                      ; brif so - go process more
                jsr LB9AC                       ; output a space
                bra L8E5F                       ; go see if we're done yet
L8E69           stb VD3                         ; save current format string counter and pointer
                stx TEMPTR
                lda #2                          ; initial spaces count = 2 (for the two %s)
                sta VD9                         ; save length counter
L8E71           lda ,x                          ; get character in string
                cmpa #'%                        ; is it the end of the sequence?
                beq L8E3B                       ; brif so - display requested part of the strign
                cmpa #0x20                      ; space?
                bne L8E82                       ; brif not
                inc VD9                         ; bump spaces count
                leax 1,x                        ; move format pointer forward
                decb                            ; consume character
                bne L8E71                       ; brif not end of format string
L8E82           ldx TEMPTR                      ; restore format string pointer
                ldb VD3                         ; get back format string length
                lda #'%                         ; show % as debugging aid
L8E88           jsr L8FD8                       ; send error indicator if flags set
                jsr PUTCHR                      ; output character
                bra L8EB9                       ; go process more format string
; PRINT extension for USING
XVEC9           cmpa #0xcd                      ; USING?
                beq L8E95                       ; brif so
                rts                             ; return to mainline code
; This is the main entry point for PRINT USING
L8E95           leas 2,s                        ; don't return to the mainline code
                jsr LB158                       ; evaluate the format string
                jsr LB146                       ; error if numeric
                ldb #';                         ; make sure there's a ; after the string
                jsr LB26F
                ldx FPA0+2                      ; get format string descriptor
                stx VD5                         ; save it for later
                bra L8EAE                       ; process format string
L8EA8           lda VD7                         ; is there a print item?
                beq L8EB4                       ; brif not
                ldx VD5                         ; get back format string descriptor
L8EAE           clr VD7                         ; reset next print item flag
                ldb ,x                          ; get length of format string
                bne L8EB7                       ; brif string is non-null
L8EB4           jmp LB44A                       ; raise FC error
L8EB7           ldx 2,x                         ; point to start of string
L8EB9           clr VDA                         ; clear status (new item)
L8EBB           clr VD9                         ; clear left digit counter
                lda ,x+                         ; get character from format string
                cmpa #'!                        ; ! (use first character of string)?
                lbeq L8E37                      ; brif so
                cmpa #'#                        ; digit?
                beq L8F24                       ; brif so - handle numeric
                decb                            ; consume format character
                bne L8EE2                       ; brif not done
                jsr L8FD8                       ; show a "+" if any flags set - indicates error at end of string
                jsr PUTCHR                      ; output format string character
L8ED2           jsr GETCCH                      ; get current input character
                bne L8EA8                       ; brif not end of statement
                lda VD7                         ; get next item flag
L8ED8           bne L8EDD                       ; brif more print items
                jsr LB958                       ; do newline
L8EDD           ldx VD5                         ; point to format string descriptor
                jmp LB659                       ; remove from string stack, etc., if appropriate (and return)
L8EE2           cmpa #'+                        ; is it + (pre-sign)?
                bne L8EEF                       ; brif not
                jsr L8FD8                       ; send a "+" if flags set
                lda #8                          ; flag for pre-sign
                sta VDA                         ; set flags
                bra L8EBB                       ; go interpret some more stuff
L8EEF           cmpa #'.                        ; decimal?
                beq L8F41                       ; brif so - numeric
                cmpa #'%                        ; % (show string)?
                lbeq L8E69                      ; brif so
                cmpa ,x                         ; do we have two identical characters?
L8EFB           bne L8E88                       ; brif not - invalid format character
                cmpa #'$                        ; double $?
                beq L8F1A                       ; brif so - floating $
                cmpa #'*                        ; double *?
                bne L8EFB                       ; brif not
                lda VDA                         ; get status byte
                ora #0x20                       ; enable * padding
                sta VDA
                cmpb #2                         ; is $$ the last two?
                blo L8F20                       ; brif so
                lda 1,x                         ; is it $ after?
                cmpa #'$
                bne L8F20                       ; brif not
                decb                            ; consume the "$"
                leax 1,x
                inc VD9                         ; add to digit counter * pad + $ counter
L8F1A           lda VDA                         ; indicate floating $
                ora #0x10
                sta VDA
L8F20           leax 1,x                        ; consume the second format character
                inc VD9                         ; add one more left place
L8F24           clr VD8                         ; clear right digit counter
L8F26           inc VD9                         ; bump left digit counter
                decb                            ; consume character
                beq L8F74                       ; brif end of string
                lda ,x+                         ; get next format character
                cmpa #'.                        ; decimal?
                beq L8F4F                       ; brif so
                cmpa #'#                        ; digit?
                beq L8F26                       ; brif so
                cmpa #',                        ; comma flag?
                bne L8F5A                       ; brif not
                lda VDA                         ; set commas flag
                ora #0x40
                sta VDA
                bra L8F26                       ; handle more characters to left of decimal
L8F41           lda ,x                          ; get character after .
                cmpa #'#                        ; digit?
                lbne L8E88                      ; brif not - invalid
                lda #1                          ; set right digit counter to 1 (for the .)
                sta VD8
                leax 1,x                        ; consume the .
L8F4F           inc VD8                         ; add one to right digit counter
                decb                            ; consume character
                beq L8F74                       ; brif end of format string
                lda ,x+                         ; get another format character
                cmpa #'#                        ; digit?
                beq L8F4F                       ; brif so
L8F5A           cmpa #0x5e                      ; up arrow?
                bne L8F74                       ; brif not
                cmpa ,x                         ; two of them?
                bne L8F74                       ; brif not
                cmpa 1,x                        ; three of them?
                bne L8F74                       ; brif not
                cmpa 2,x                        ; four of them?
                bne L8F74                       ; brif not
                cmpb #4                         ; string actually has the characters?
                blo L8F74                       ; brif not
                subb #4                         ; consome them
                leax 4,x
                inc VDA                         ; set scientific notation bit
L8F74           leax -1,x                       ; back up input pointer
                inc VD9                         ; add one digit for pre-sign force
                lda VDA                         ; is it pre-sign?
                bita #8
                bne L8F96                       ; brif so
                dec VD9                         ; undo pre-sign adjustment
                tstb                            ; end of string?
                beq L8F96                       ; brif so
                lda ,x                          ; get next character
                suba #'-                        ; post sign force?
                beq L8F8F                       ; brif so
                cmpa #'+-'-                     ; plus?
                bne L8F96                       ; brif not
                lda #8                          ; trailing + is a pre-sign force
L8F8F           ora #4                          ; add in post sign flag
                ora VDA                         ; merge with flags
                sta VDA
                decb                            ; consume character
L8F96           jsr GETCCH                      ; do we have an argument
                lbeq L8ED8                      ; brif not
                stb VD3                         ; save format string length
                jsr LB141                       ; evluate numeric expression
                lda VD9                         ; get left digit counter
                adda VD8                        ; add in right digit counter
                cmpa #17                        ; is it more than 16 digits + decimal?
                lbhi LB44A                      ; brif so - this is a problem
                jsr L8FE5                       ; format value according to settings
                leax -1,x                       ; move buffer pointer back
                jsr STRINOUT                    ; display formatted number string
L8FB3           clr VD7                         ; reset next print item flag
                jsr GETCCH                      ; get current input character
                beq L8FC6                       ; brif end of statement
                sta VD7                         ; set next print flag to nonzero
                cmpa #';                        ; list separator ;?
                beq L8FC4                       ; brif so
                jsr SYNCOMMA                    ; require a comma between if not ;
                bra L8FC6                       ; process next item
L8FC4           jsr GETNCH                      ; munch the semicolon
L8FC6           ldx VD5                         ; get format string descriptor
                ldb ,x                          ; get length of string
                subb VD3                        ; subtract amount left after last item
                ldx 2,x                         ; point to string address
                abx                             ; move pointer to correct spot
                ldb VD3                         ; get remaining string length
                lbne L8EB9                      ; if we have more, interpret from there
                jmp L8ED2                       ; re-interpret from start if we hit the end
L8FD8           pshs a                          ; save character
                lda #'+                         ; "error" flag character
                tst VDA                         ; did we have some flags set?
                beq L8FE3                       ; brif not
                jsr PUTCHR                      ; output error flag
L8FE3           puls a,pc                       ; restore character and return
L8FE5           ldu #STRBUF+4                   ; point to string buffer
                ldb #0x20                       ; blank space
                lda VDA                         ; get flags
                bita #8                         ; pre-sign?
                beq L8FF2                       ; brif not
                ldb #'+                         ; plus sign
L8FF2           tst FP0SGN                      ; get sign of value
                bpl L8FFA                       ; brif positive
                clr FP0SGN                      ; make number positive (for later)
                ldb #'-                         ; negative sign
L8FFA           stb ,u+                         ; put sign in buffer
                ldb #'0                         ; put a zero there
                stb ,u+
                anda #1                         ; check scientific notation force
                lbne L910D                      ; brif so
                ldx #LBDC0                      ; point to FP 1E+9
                jsr LBCA0                       ; is it less?
                bmi L9023                       ; brif so
                jsr LBDD9                       ; convert FP number to string (we're doing scientific notation)
L9011           lda ,x+                         ; advance pointer to end of string
                bne L9011
L9015           lda ,-x                         ; make a hole at the start
                sta 1,x
                cmpx #STRBUF+3                  ; done yet?
                bne L9015                       ; brif not
                lda #'%                         ; put "overflow" flag at start
                sta ,x
                rts
L9023           lda FP0EXP                      ; get exponent of value
                sta V47                         ; save it
                beq L902C                       ; brif value is 0
                jsr L91CD                       ; convert to number with 9 significant figures to left of decimal
L902C           lda V47                         ; get base 10 exponent offset
                lbmi L90B3                      ; brif < 100,000,000
                nega                            ; get negative difference
                adda VD9                        ; add to number of left digits
                suba #9                         ; account for the 9 we actually have
                jsr L90EA                       ; put leading zeroes in buffer
                jsr L9263                       ; initialize the decimal point and comma counters
                jsr L9202                       ; convert FPA0 to decimal ASCII in buffer
                lda V47                         ; get base 10 exponent
                jsr L9281                       ; put that many zeroes in buffer, stop at decimal point
                lda V47                         ; get base 10 exponent
                jsr L9249                       ; check for decimal
                lda VD8                         ; get right digit counter
                bne L9050                       ; brif we want stuff after decimal
                leau -1,u                       ; delete decimal if not needed
L9050           deca                            ; subtract one place (for decimal)
                jsr L90EA                       ; put zeroes in buffer (trailing)
L9054           jsr L9185                       ; insert * padding, floating $, and post-sign
                tsta                            ; was there a post sign?
                beq L9060                       ; brif not
                cmpb #'*                        ; was first character a *?
                beq L9060                       ; brif so
                stb ,u+                         ; store the post sign
L9060           clr ,u                          ; make srue it's NUL terminated
                ldx #STRBUF+3                   ; point to start of buffer
L9065           leax 1,x                        ; move to next character
                stx TEMPTR                      ; save it for later
                lda VARPTR+1                    ; get address of decimal point
                suba TEMPTR+1                   ; subtract out actual digits left of decimal
                suba VD9                        ; subtract out required left digits
                beq L90A9                       ; brif no padding needed
                lda ,x                          ; get current character
                cmpa #0x20                      ; space?
                beq L9065                       ; brif so - advance pointer
                cmpa #'*                        ; *?
                beq L9065                       ; brif so - advance pointer
                clra                            ; zero on stack is end of data ponter
L907C           pshs a                          ; save character on stack
                lda ,x+                         ; get next character
                cmpa #'-                        ; minus?
                beq L907C                       ; brif so
                cmpa #'+                        ; plus?
                beq L907C                       ; brif so
                cmpa #'$                        ; $?
                beq L907C                       ; brif so
                cmpa #'0                        ; zero?
                bne L909E                       ; brif not
                lda 1,x                         ; get character after 0
                bsr L90AA                       ; clear carry if number
                bcs L909E                       ; brif not number
L9096           puls a                          ; get character off stack
                sta ,-x                         ; put it back in string buffer
                bne L9096                       ; brif not - restore another
                bra L9065                       ; keep cleaning up buffer
L909E           puls a                          ; get the character on the stack
                tsta                            ; is it NUL?
                bne L909E                       ; brif not
                ldx TEMPTR                      ; get string buffer start pointer
                lda #'%                         ; put error flag in front
                sta ,-x
L90A9           rts
L90AA           cmpa #'0                        ; zero?
                blo L90B2                       ; brif not
                suba #'9+1                      ; set C if > "9"
                suba #-('9+1)
L90B2           rts
L90B3           lda VD8                         ; get right digit counter
                beq L90B8                       ; brif not right digits
                deca                            ; account for decimal point
L90B8           adda V47                        ; add base 10 exponent offset
                bmi L90BD                       ; if >= 0, no shifts are required
                clra                            ; force shift counter to 0
L90BD           pshs a                          ; save shift counter
L90BF           bpl L90CB                       ; brif positive count
                pshs a                          ; save shift counter
                jsr LBB82                       ; divide FPA0 by 10 (shift 1 digit to the right)
                puls a                          ; get shift counter back
                inca                            ; account for the shift
                bra L90BF                       ; see if we're done yet
L90CB           lda V47                         ; get base 10 exponent offset
                suba ,s+                        ; account for adjustment
                sta V47                         ; save new exponent offset
                adda #9                         ; account for significant places
                bmi L90EE                       ; brif we don't need zeroes to left
                lda VD9                         ; get left decimal counter
                suba #9                         ; account for significant figures
                suba V47                        ; subtract exponent offset
                bsr L90EA                       ; output leading zeroes
                jsr L9263                       ; initialize decimal and comma counters
                bra L90FF                       ; process remainder of digits
L90E2           pshs a                          ; save zero counter
                lda #'0                         ; insert a 0
                sta ,u+
                puls a                          ; get back counter
L90EA           deca                            ; do we need more zeroes?
                bpl L90E2                       ; brif so
                rts
L90EE           lda VD9                         ; get left digit counter
                bsr L90EA                       ; put that many zeroes in
                jsr L924D                       ; put decimal in buffer
                lda #-9                         ; figure out filler zeroes
                suba V47
                bsr L90EA                       ; output required leader zeroes
                clr V45                         ; clear decimal pointer counter
                clr VD7                         ; clear comma counter
L90FF           jsr L9202                       ; decode FPA0 to decimal string
                lda VD8                         ; get right digit counter
                bne L9108                       ; brif there are right digits
                ldu VARPTR                      ; point to decimal location of decimal
L9108           adda V47                        ; add base 10 exponent
                lbra L9050                      ; add in leading astrisks, etc.
L910D           lda FP0EXP                      ; get exponent of FPA0
                pshs a                          ; save it
                beq L9116                       ; brif 0
                jsr L91CD                       ; convert to number with 9 figures
L9116           lda VD8                         ; get right digit counter
                beq L911B                       ; brif no right digits
                deca                            ; account for decimal point
L911B           adda VD9                        ; get left digit counter
                clr STRBUF+3                    ; use buffer byte as temporary storage
                ldb VDA                         ; get status flags
                andb #4                         ; post-sign?
                bne L9129                       ; brif so
                com STRBUF+3                    ; flip byte if no post sign
L9129           adda STRBUF+3                   ; subtract 1 if no post sign
                suba #9                         ; account for significant figures
                pshs a                          ; save shift counter
L9130           bpl L913C                       ; brif no more shifts needed
                pshs a                          ; save counter
                jsr LBB82                       ; divide by 10 (shift right one)
                puls a                          ; get back counter
                inca                            ; account for the shift
                bra L9130                       ; see if we need more
L913C           lda ,s                          ; get original shift count
                bmi L9141                       ; brif shifting happened
                clra                            ; flag for no shifting
L9141           nega                            ; calculate position of decimal (negate shift count, add left digit and post sign if needed)
                adda VD9                        ; add left digit counter
                inca                            ; and post sign
                adda STRBUF+3
                sta V45                         ; save decimal counter
                clr VD7                         ; clear comma counter
                jsr L9202                       ; convert to decimal string
                puls a                          ; get shift counter
                jsr L9281                       ; put the needed zeroes in
                lda VD8                         ; get right digit counter
                bne L915A                       ; brif we want some
                leau -1,u                       ; remove te decimal point
L915A           ldb ,s+                         ; get original exponent
                beq L9167                       ; brif it was 0
                ldb V47                         ; get base 10 exponent
                addb #9                         ; account for significant figures
                subb VD9                        ; remove left digit count
                subb STRBUF+3                   ; add one if post sign
L9167           lda #'+                         ; positive sign
                tstb                            ; is base 10 exponent positive?
                bpl L916F                       ; brif so
                lda #'-                         ; negative sign
                negb                            ; flip exponent
L916F           sta 1,u                         ; put exponent sign
                lda #'E                         ; put "E" and advance output pointer
                sta ,u++
                lda #'0-1                       ; initialize digit accumulator
L9177           inca                            ; bump digit
                subb #10                        ; are we at the right digit?
                bcc L9177                       ; brif not
                addb #'0+10                     ; add ASCII bias and undo extra subtraction
                std ,u++                        ; save exponent in buffer
                clr ,u                          ; clear final byte in buffer
                jmp L9054                       ; insert *, $, etc.
L9185           ldx #STRBUF+4                   ; point to start of result
                ldb ,x                          ; get sign
                pshs b                          ; save it
                lda #0x20                       ; default pad with spaces
                ldb VDA                         ; get flags
                bitb #0x20                      ; padding with *?
                puls b
                beq L919E                       ; brif no padding
                lda #'*                         ; pad with *
                cmpb #0x20                      ; do we have a blank? (positive)
                bne L919E                       ; brif not
                tfr a,b                         ; use pad character
L919E           pshs b                          ; save first character
L91A0           sta ,x+                         ; store padding
                ldb ,x                          ; get next character
                beq L91B6                       ; brif end of string
                cmpb #'E                        ; exponent?
                beq L91B6                       ; brif so - treat as 0
                cmpb #'0                        ; zero?
                beq L91A0                       ; brif so - pad it
                cmpb #',                        ; leading comma?
                beq L91A0                       ; brif so - pad it
                cmpb #'.                        ; decimal?
                bne L91BA                       ; brif so - don't put a 0 before it
L91B6           lda #'0                         ; put a zero before
                sta ,-x
L91BA           lda VDA                         ; get status byte
                bita #0x10                      ; floating $?
                beq L91C4                       ; brif not
                ldb #'$                         ; stuff a $ in
                stb ,-x
L91C4           anda #4                         ; pre-sgn?
                puls b                          ; get back first character
                bne L91CC                       ; brif not
                stb ,-x                         ; save leading character (sign)
L91CC           rts
L91CD           pshs u                          ; save buffer pointer
                clra                            ; initial exponent offset is 0
L91D0           sta V47                         ; save exponent offset
                ldb FP0EXP                      ; get actual exponent
                cmpb #0x80                      ; is value >= 1.0?
                bhi L91E9                       ; brif so
                ldx #LBDC0                      ; point to FP number 1E9
                jsr LBACA                       ; multiply by 1000000000
                lda V47                         ; account for 9 shifts
                suba #9
                bra L91D0                       ; brif not there yet
L91E4           jsr LBB82                       ; divide by 10
                inc V47                         ; account for shift
L91E9           ldx #LBDBB                      ; point to 999999999
                jsr LBCA0                       ; compare it
                bgt L91E4                       ; brif not in range yet
L91F1           ldx #LBDB6                      ; point to 99999999.9
                jsr LBCA0                       ; compare
                bgt L9200                       ; brif in range
                jsr LBB6A                       ; multiply by 10
                dec V47                         ; account for shift
                bra L91F1                       ; see if we're in range yet
L9200           puls u,pc                       ; restore buffer pointer and return
L9202           pshs u                          ; save buffer pointer           
                jsr LB9B4                       ; add .5 (round off)
                jsr LBCC8                       ; convert to integer format
                puls u                          ; restore buffer pointer
                ldx #LBEC5                      ; point to 32 bit powers of 10 (alternating signs)
                ldb #0x80                       ; intitial digit counter is 0 with 0x80 bias
L9211           bsr L9249                       ; check for comma
L9213           lda FPA0+3                      ; add a power of 10
                adda 3,x
                sta FPA0+3
                lda FPA0+2
                adca 2,x
                sta FPA0+2
                lda FPA0+1
                adca 1,x
                sta FPA0+1
                lda FPA0
                adca ,x
                sta FPA0
                incb                            ; add one to digit counter
                rorb                            ; set V if carry and sign differ
                rolb
                bvc L9213                       ; brif we haven't "wrapped"
                bcc L9235                       ; brif subtracting
                subb #10+1                      ; take 9's complement if adding
                negb
L9235           addb #'0-1                      ; add in ASCII bias
                leax 4,x                        ; move to next power
                tfr b,a                         ; save digit
                anda #0x7f                      ; mask off subtract flag
                sta ,u+                         ; save digit
                comb                            ; toggle add/subtract
                andb #0x80
                cmpx #LBEE9                     ; done all places?
                bne L9211                       ; brif not
                clr ,u                          ; but NUL at end
L9249           dec V45                         ; at decimal?
                bne L9256                       ; brif not
L924D           stu VARPTR                      ; save decimal point pointer
                lda #'.                         ; insert decimal
                sta ,u+
                clr VD7                         ; clear comma counter
                rts
L9256           dec VD7                         ; do we need a comma?
                bne L9262                       ; brif not
                lda #3                          ; reset comma counter
                sta VD7
                lda #',                         ; insert comma
                sta ,u+
L9262           rts
L9263           lda V47                         ; get base 10 exponent offset
                adda #10                        ; account for significant figures
                sta V45                         ; save decimal counter
                inca                            ; add one for decimal point
L926A           suba #3                         ; divide by 3, leave remainder in A
                bcc L926A
                adda #5                         ; renormalize to range 1-3
                sta VD7                         ; save comma counter
                lda VDA                         ; get status
                anda #0x40                      ; commas wanted?
                bne L927A                       ; brif not
                sta VD7                         ; clear comma counter
L927A           rts
L927B           pshs a                          ; save zeroes counter
                bsr L9249                       ; check for decimal
                puls a                          ; get back counter
L9281           deca                            ; need a zero?
                bmi L928E                       ; brif not
                pshs a                          ; save counter
                lda #'0                         ; put a zero
                sta ,u+
                lda ,s+                         ; get back counter and set flags
                bne L927B                       ; brif not done enough
L928E           rts
; From here to the end of the Extended Basic ROM is the PMODE graphics system and related
; infrastructure with the exception of the PLAY command which shares some of its machinery
; with the DRAW command.
;
; Fetch screen address calculation routine address for the selected graphics mode
L928F           ldu #L929C                      ; point to normalization routine jump table
                lda PMODE                       ; get graphics mode
                asla                            ; two bytes per address
                ldu a,u                         ; get routine address
                rts
; Normalize VERBEG/HORBEG coordinates and return screen address in X and pixel mask in A.
L9298           bsr L928F                       ; fetch normalization routine pointer
                jmp ,u                          ; transfer control to it
L929C           fdb L92A6                       ; PMODE 0
                fdb L92C2                       ; PMODE 1
                fdb L92A6                       ; PMODE 2
                fdb L92C2                       ; PMODE 3
                fdb L92A6                       ; PMODE 4
; Two colour mode address calculatoin
L92A6           pshs u,b                        ; savce registers
                ldb HORBYT                      ; get number of bytes in each graphics row
                lda VERBEG+1                    ; get vertical coordinate
                mul
                addd BEGGRP                     ; now D is the absolute address of the start of the row
                tfr d,x                         ; get address to the return location
                ldb HORBEG+1                    ; get horizontal coordinate
                lsrb                            ; divide by 8 (8 pixels per byte in 2 colour mode)
                lsrb
                lsrb
                abx                             ; now X is the address of the actual pixel byte
                lda HORBEG+1                    ; get horizontal coordinate
                anda #7                         ; keep only the low 3 bits which contain the pixel number
                ldu #L92DD                      ; point to pixel mask lookup
                lda a,u                         ; get pixel mask
                puls b,u,pc                     ; restore registers and return result
; four colour address calculation
L92C2           pshs u,b                        ; save registers
                ldb HORBYT                      ; get bytes per graphics row
                lda VERBEG+1                    ; get vertical coordinate
                mul
                addd BEGGRP                     ; now D is the address of the start of the row
                tfr d,x                         ; put it in returnlocatin
                ldb HORBEG+1                    ; get horizontal coordinate
                lsrb                            ; divide by 4 (four colour modes have four pixels per byte)
                lsrb
                abx                             ; now X points to the screen byte
                lda HORBEG+1                    ; get horizontal coordinate
                anda #3                         ; keep low two bits for pixel number
                ldu #L92E5                      ; point to four colour pixel masks
                lda a,u                         ; get pixel mask
                puls b,u,pc                     ; restore registers and return result
L92DD           fcb 0x80,0x40,0x20,0x10         ; two colour pixel masks
                fcb 0x08,0x04,0x02,0x01
L92E5           fcb 0xc0,0x30,0x0c,0x03         ; four colour pixel masks
;  Move X down one graphics row
L92E9           ldb HORBYT                      ; get bytes per row
                abx                             ; add to screen address
                rts
; Move one pixel right in 2 colour mode
L92ED           lsra                            ; move pixel mask right
                bcc L92F3                       ; brif same byte
                rora                            ; move pixel mask to left of byte
                leax 1,x                        ; move to next byte
L92F3           rts
; Move one pixel right in 4 colour mode
L92F4           lsra                            ; shift mask half a pixel right
                bcc L92ED                       ; brif not past end of byte - shift one more
                lda #0xc0                       ; set mask on left of byte
                leax 1,x                        ; move to next byte
                rts
; Evaluate two expressions (coordinates). Put first in HORBEG and second in VERBEG.
L92FC           jsr LB734                       ; evaluate two expressions - first in BINVAL, second in B
                ldy #HORBEG                     ; point to storage location
L9303           cmpb #192                       ; is vertical outside range?
                blo L9309                       ; brif not
                ldb #191                        ; max it at bottom of screen
L9309           clra                            ; zero extend vertical coordinate
                std 2,y                         ; save vertical coordinate
                ldd BINVAL                      ; get horizontal coordinate
                cmpd #256                       ; in range?
                blo L9317                       ; brif so
                ldd #255                        ; max it out to right side of screen
L9317           std ,y                          ; save horizontal coordinate
                rts
; Normalize coordinates for proper PMODE
L931A           jsr L92FC                       ; parse coordinates
L931D           ldu #HORBEG                     ; point to start coordinates
L9320           lda PMODE                       ; get graphics mode
                cmpa #2                         ; is it pmode 0 or 1?
                bhs L932C                       ; brif not
                ldd 2,u                         ; get vertical coordinate
                lsra                            ; divide it by two
                rorb
                std 2,u                         ; save it back
L932C           lda PMODE                       ; get graphics mode
                cmpa #4                         ; pmode 4?
                bhs L9338                       ; brif so
                ldd ,u                          ; cut horizontal coordinate in half
                lsra
                rorb
                std ,u                          ; save new coordinate
L9338           rts
; PPOINT function
PPOINT          jsr L93B2                       ; evaluate two expressions (coordinates)
                jsr L931D                       ; normalize coordinates
                jsr L9298                       ; get screen address
                anda ,x                         ; get colour value of desired screen coordinate
                ldb PMODE                       ; get graphics mode
                rorb                            ; is it a two colour m ode?
                bcc L935B                       ; brif so
L9349           cmpa #4                         ; is it on rightmost bits?
                blo L9351                       ; brif not
                rora                            ; shift right
                rora
                bra L9349                       ; see if we're there yet
L9351           inca                            ; colour numbers start at 1
                asla                            ; add in colour set (0 or 8)
                adda CSSVAL
                lsra                            ; get colour in range of 0 to 8
L9356           tfr a,b                         ; put result to B
                jmp LB4F3                       ; return B as FP number
L935B           tsta                            ; is pixel on?
                beq L9356                       ; brif not, return 0 (off)
                clra                            ; set colour number to "1"
                bra L9351                       ; make it 1 or 5 and return
; PSET command
PSET            lda #1                          ; PSET flag
                bra L9366                       ; go turn on the pixel
; PRESET command
PRESET          clra                            ; PRESET flag
L9366           sta SETFLG                      ; store whether we're setting or resetting
                jsr LB26A                       ; enforce (
                jsr L931A                       ; evaluate coordinates
                jsr L9581                       ; evaluate colour
                jsr LB267                       ; enforce )
                jsr L9298                       ; get address of pixel
L9377           ldb ,x                          ; get screen data
                pshs b                          ; save it
                tfr a,b                         ; duplicate pixel mask
                coma                            ; invert mask
                anda ,x                         ; turn off screen pixel
                andb ALLCOL                     ; adjust pixel mask to be the current colour
                pshs b                          ; merge pixel data into the screen data
                ora ,s+
                sta ,x                          ; put it on screen
                suba ,s+                        ; nonzero if screen data changed
                ora CHGFLG                      ; propagate change flag
                sta CHGFLG
                rts
; Evaluate two sets of coordinates separated by a minus sign. First at HORBEG,VERBEG and
; second at HOREND,VEREND. If no first set, use HORDEF,VERDEF.
L938F           ldx HORDEF                      ; set default start coords
                stx HORBEG
                ldx VERDEF
                stx VERBEG
                cmpa #0xac                      ; do we start with a -?
                beq L939E                       ; brif no starting coordinates
                jsr L93B2                       ; parse coordinates
L939E           ldb #0xac                       ; make sure we have a -
                jsr LB26F
                jsr LB26A                       ; require a (
                jsr LB734                       ; evaluate two expressions
                ldy #HOREND                     ; point to storage location
                jsr L9303                       ; process coordinates
                bra L93B8                       ; finish up with a )
L93B2           jsr LB26A                       ; make sure there's a (
                jsr L92FC                       ; evaluate coordinates
L93B8           jmp LB267                       ; force a )
; LINE command
LINE            cmpa #0x89                      ; is it LINE INPUT?
                lbeq L89C0                      ; brif so - go handle it
                cmpa #'(                        ; starting coord?
                beq L93CE                       ; brif so
                cmpa #0xac                      ; leading -?
                beq L93CE                       ; brif so
                ldb #'@                         ; if it isn't the above, make sure it's @
                jsr LB26F
L93CE           jsr L938F                       ; parse coordinates
                ldx HOREND                      ; set ending coordinates as the defaults
                stx HORDEF
                ldx VEREND
                stx VERDEF
                jsr SYNCOMMA                    ; make sure we have a comma
                cmpa #0xbe                      ; PRESET?
                beq L93E9                       ; brif so
                cmpa #0xbd                      ; PSET?
                lbne LB277                      ; brif not
                ldb #01                         ; PSET flag
                skip1lda                        ; skip byte and set A nonzero
L93E9           clrb                            ; PRESET flag
                pshs b                          ; save PSET/PRESET flag
                jsr GETNCH                      ; eat the PSET/PRESET
                jsr L9420                       ; normalize coordinates
                puls b                          ; get back PSET/PRESET flag
                stb SETFLG                      ; flag which we're doing
                jsr L959A                       ; set colour byte
                jsr GETCCH                      ; get next bit
                lbeq L94A1                      ; brif no box option
                jsr SYNCOMMA                    ; make sure it's comma
                ldb #'B                         ; make sure "B" for "box"
                jsr LB26F
                bne L9429                       ; brif something follows the B
                bsr L9444                       ; draw horizontal line
                bsr L946E                       ; draw vertical line
                ldx HORBEG                      ; save horizontal coordinate
                pshs x                          ; save it
                ldx HOREND                      ; switch in horizontal end
                stx HORBEG
                bsr L946E                       ; draw vertical line
                puls x                          ; get back original start
                stx HORBEG                      ; put it back
                ldx VEREND                      ; do the same dance with the vertical end
                stx VERBEG
                bra L9444                       ; draw horizontal line
L9420           jsr L931D                       ; normalize the start coordinates
                ldu #HOREND                     ; point to end coords
                jmp L9320                       ; normalize those coordinates
L9429           ldb #'F                         ; make sure we have "BF" for "filled box"
                jsr LB26F
                bra L9434                       ; fill the box
L9430           leax -1,x                       ; move vertical coordinate up one
L9432           stx VERBEG                      ; save new vertical coordinate
L9434           jsr L9444                       ; draw a horizontal line
                ldx VERBEG                      ; are we at the end of the box?
                cmpx VEREND
                beq L9443                       ; brif so
                bcc L9430                       ; brif we're moving up the screen
                leax 1,x                        ; move down the screen
                bra L9432                       ; go draw another line
L9443           rts
; Draw a horizontal line from HORBEG to HOREND at VERBEG using color mask in ALLCOL
L9444           ldx HORBEG                      ; get starting horizontal coordinate
                pshs x                          ; save it
                jsr L971D                       ; get absolute value of HOREND-HORBEG
                bcc L9451                       ; brif end is > start
                ldx HOREND                      ; copy end coordinate to start it is smaller
                stx HORBEG
L9451           tfr d,y                         ; save difference - it's a pixel count
                leay 1,y                        ; coordinates are inclusive
                jsr L9298                       ; get screen position of start coord
                puls u                          ; restore original start coordinate
                stu HORBEG
                bsr L9494                       ; point to routine to move pizel pointers to right
L945E           sta VD7                         ; save pixel mask
                jsr L9377                       ; turn on pixel
                lda VD7                         ; get pixel mask back
                jsr ,u                          ; move one pixel right
                leay -1,y                       ; turned on enough pixels yet?
                bne L945E                       ; brif not
L946B           rts
L946C           puls b,a                        ; clean up stack
L946E           ldd VERBEG                      ; save original vertical start coordinate
                pshs b,a
                jsr L9710                       ; get vertical difference
                bcc L947B                       ; brif end coordinate > start
                ldx VEREND                      ; swap in end coordinate if not
                stx VERBEG
L947B           tfr d,y                         ; save number of pixels to set
                leay 1,y                        ; the coordinates are inclusive
                jsr L9298                       ; get screen pointer
                puls u                          ; restore start coordinate
                stu VERBEG
                bsr L949D                       ; point to routine to move down one row
                bra L945E                       ; draw vertical line
; Point to routine which will move one pixel right
L948A           fdb L92ED                       ; PMODE 0
                fdb L92F4                       ; PMODE 1
                fdb L92ED                       ; PMODE 2
                fdb L92F4                       ; PMODE 3
                fdb L92ED                       ; PMODE 4
L9494           ldu #L948A                      ; point to jump table
                ldb PMODE                       ; get graphics mode
                aslb                            ; two bytes per address
                ldu b,u                         ; get jump address
                rts
; Point to routine to move down one row
L949D           ldu #L92E9                      ; point to "move down one row" routien
                rts
; Draw a line from HORBEG,VERBEG to HOREND,VEREND
L94A1           ldy #L950D                      ; point to increase vertical coord
                jsr L9710                       ; calculate difference
                lbeq L9444                      ; brif none - draw a horizontal line
                bcc L94B2                       ; brif vertical end is > vertical start
                ldy #L951B                      ; point to decrease vertical coord
L94B2           pshs d                          ; save vertical difference
                ldu #L9506                      ; point to increase horizontal coord
                jsr L971D                       ; get difference
                beq L946C                       ; brif none - draw a vertical line
                bcc L94C1                       ; brif horizontal end > horizontal start
                ldu #L9514                      ; point to decrease hoizontal coord
L94C1           cmpd ,s                         ; compare vert and horiz differences
                puls x                          ; get X difference
                bcc L94CC                       ; brif horiz diff > vert diff
                exg u,y                         ; swap change routine pointers
                exg d,x                         ; swap differences
L94CC           pshs u,d                        ; save larger difference and routine
                pshs d                          ; save larger difference
                lsra                            ; divide by two
                rorb
                bcs L94DD                       ; brif odd number
                cmpu #L950D+1                   ; increase or decrease?
                blo L94DD                       ; brif increase
                subd #1                         ; back up one
L94DD           pshs x,b,a                      ; save smallest difference and initial middle offset
                jsr L928F                       ; point to proper coordinate to screen conversion routine
L94E2           jsr ,u                          ; convert coordinates to screen address
                jsr L9377                       ; turn on a pixel
                ldx 6,s                         ; get distnace counter
                beq L9502                       ; brif line is completely drawn
                leax -1,x                       ; account for one pixel drawn
                stx 6,s                         ; save new counter
                jsr [8,s]                       ; increment/decrement larger delta
                ldd ,s                          ; get the minor coordinate increment counter
                addd 2,s                        ; add the smallest difference
                std ,s                          ; save new minor coordinate incrementcounter
                subd 4,s                        ; subtractout the largest difference
                bcs L94E2                       ; brif not greater - draw another pixel
                std ,s                          ; save new minor coordinate increment
                jsr ,y                          ; adjust minor coordinate
                bra L94E2                       ; go draw another pixel
L9502           puls x                          ; clean up stack and return
                puls a,b,x,y,u,pc
L9506           ldx HORBEG                      ; bump horizontal coordinate
                leax 1,x
                stx HORBEG
                rts
L950D           ldx VERBEG                      ; bump vertical coordinate
                leax 1,x
                stx VERBEG
                rts
L9514           ldx HORBEG                      ; decrement horizontal coordinate
                leax -1,x
                stx HORBEG
                rts
L951B           ldx VERBEG                      ; decrement vertical coordinate
                leax -1,x
                stx VERBEG
                rts
; Get normalized maximum coordinate values in VD3 and VD5
L9522           ldu #VD3                        ; point to temp storage
                ldx #255                        ; set maximum horizontal
                stx ,u
                ldx #191                        ; set maximum vertical
                stx 2,u
                jmp L9320                       ; normalize them
; PCLS command
PCLS            beq L9542                       ; clear to background colour if no argument
                bsr L955A                       ; evaluate colour
L9536           lda #0x55                       ; consider each byte as 4 groups of 2 bit sub-nibbles
                mul                             ; now colour is in all four sub-pixels
                ldx BEGGRP                      ; get start of graphics screen
L953B           stb ,x+                         ; set byte to proper colour
                cmpx ENDGRP                     ; at end of graphics page?
                bne L953B                       ; brif not
                rts
L9542           ldb BAKCOL                      ; get background colour
                bra L9536                       ; do the clearing dance
; COLOR command
COLOR           cmpa #',                        ; check for comma
                beq L9552                       ; brif no foreground colour
                bsr L955A                       ; evaluate first colour
                stb FORCOL                      ; set foreground colour
                jsr GETCCH                      ; is there a background colour?
                beq L9559                       ; brif not
L9552           jsr SYNCOMMA                    ; make sure we have a comma
                bsr L955A                       ; evaluate background colour argument
                stb BAKCOL                      ; set background colour
L9559           rts
; Evaluate a colour agument and convert to proper code based on graphics mode
L955A           jsr EVALEXPB                    ; evaluate colour code
L955D           cmpb #9                         ; is it in range of 0-8?
                lbhs LB44A                      ; brif not - raise error
                clra                            ; CSS value for first colour set
                cmpb #5                         ; is it first or second colour set?
                blo L956C                       ; brif first colour set
                lda #8                          ; flag second colour set
                subb #4                         ; adjust into basic range
L956C           pshs a                          ; save CSS value
                lda PMODE                       ; get graphics mode
                rora                            ; 4 colour or 2?
                bcc L957B                       ; brif 2 colour
                tstb                            ; was it 0?
                bne L9578                       ; brif not
L9576           ldb #4                          ; if so, make it 4
L9578           decb                            ; convert to zero based
L9579           puls a,pc                       ; get back CSS value and return
L957B           rorb                            ; is colour number odd?
                bcs L9576                       ; brif so - force all bits set colour
                clrb                            ; force colour 0 if not
                bra L9579
; Set all pixel byte and active colour
L9581           jsr L959A                       ; set colour byte
                jsr GETCCH                      ; is there something to evaluate?
                beq L9598                       ; brif not
                cmpa #')                        ; )?
                beq L9598                       ; brif so
                jsr SYNCOMMA                    ; force comma
                cmpa #',                        ; another comma?
                beq L9598                       ; brif so
                jsr L955A                       ; evaluate expression and return colour
                bsr L95A2                       ; save colour and pixel byte
L9598           jmp GETCCH                      ; re-fetch input character and return
L959A           ldb FORCOL                      ; use foreground colour by default
                tst SETFLG                      ; doing PRESET?
                bne L95A2                       ; brif not
                ldb BAKCOL                      ; default to background colour
L95A2           stb WCOLOR                      ; save working colour
                lda #0x55                       ; consider a byte as 4 pixels
                mul                             ; now all pixels are set to the same bit pattern
                stb ALLCOL                      ; set all pixels byte
                rts
L95AA           bne L95CF                       ; brif graphics mode
L95AC           pshs x,b,a                      ; save registers
                ldx #SAMREG+8                   ; point to middle of control register
                sta 10,x                        ; reset display page to 0x400
                sta 8,x
                sta 6,x
                sta 4,x
                sta 2,x
                sta 1,x
                sta -2,x
                sta -4,x                        ; reset to alpha mode
                sta -6,x
                sta -8,x
                lda PIA1+2                      ; set VDG to alpha mode, colour set 0
                anda #7
                sta PIA1+2
                puls a,b,x,pc                   ;restore registers and return
L95CF           pshs x,b,a                      ; save registers
                lda PMODE                       ; get graphics mode
                adda #3                         ; offset to 3-7 (we don't use the bottom 3 modes)
                ldb #0x10                       ; shift to high 4 bits
                mul
                orb #0x80                       ; set to graphics mode
                orb CSSVAL                      ; set the desired colour set
                lda PIA1+2                      ; get get original PIA values
                anda #7                         ; mask off VDG control
                pshs a                          ; merge with new VDG control
                orb ,s+
                stb PIA1+2                      ; set new VDG mode
                lda BEGGRP                      ; get start of graphics page
                lsra                            ; divide by two - pages are on 512 byte boundaries
                jsr L960F                       ; set SAM control register
                lda PMODE                       ; get graphics mode
                adda #3                         ; shift to VDG values
                cmpa #7                         ; PMODE 4?
                bne L95F7                       ; brif not
                deca                            ; treat PMODE 4 the same as PMODE 3
L95F7           bsr L95FB                       ; program SAM's VDG bits
                puls a,b,x,pc                   ; restore registers and return
L95FB           ldb #3                          ; set 3 bits in register
                ldx #SAMREG                     ; point to VDG control bits
L9600           rora                            ; get bit to set
                bcc L9607                       ; brif we need to clear the bit
                sta 1,x                         ; set the bit
                bra L9609
L9607           sta ,x                          ; clear the bit
L9609           leax 2,x                        ; move to next bit
                decb                            ; done all bits?
                bne L9600                       ; brif not
                rts
L960F           ldb #7                          ; 7 screen address bits
                ldx #SAMREG+6                   ; point to screen address bits in SAM
                bra L9600                       ; go program SAM bits
L9616           lda PIA1+2                      ; get VDG bits
                anda #0xf7                      ; keep everything but CSS bit
                ora CSSVAL                      ; set correct CSS bit
                sta PIA1+2                      ; set desired CSS
                rts
; PMODE command
PMODETOK        cmpa #',                        ; is first argument missing?
                beq L9650                       ; brif so
                jsr EVALEXPB                    ; evaluate PMODE number
                cmpb #5                         ; valid (0-4)?
                bhs L966D                       ; brif not
                lda GRPRAM                      ; get start of graphics memory
L962E           sta BEGGRP                      ; set start of graphics page
                aslb                            ; multiply mode by two (table has two bytes per entry)
                ldu #L9706+1                    ; point to lookup table
                adda b,u                        ; add in number of 256 byte pages used for graphics screen
                cmpa TXTTAB                     ; does it fit?
                bhi L966D                       ; brif not
                sta ENDGRP                      ; save end of graphics
                leau -1,u                       ; point to bytes per horizontal row
                lda b,u                         ; get bytes per row
                sta HORBYT                      ; set it
                lsrb                            ; restore PMODE value
                stb PMODE                       ; set graphics mode
                clra                            ; set background colour to 0
                sta BAKCOL
                lda #3                          ; set foreground colour to maximum (3)
                sta FORCOL
                jsr GETCCH                      ; is there a starting page number?
                beq L966C                       ; brif not
L9650           jsr LB738                       ; evaluate an expression following a comma
                tstb                            ; page 0?
                beq L966D                       ; brif so - not valid
                decb                            ; zero-base it
                lda #6                          ; each graphics page is 6*256
                mul
                addb GRPRAM                     ; add to start of graphics memory
                pshs b                          ; save start of screen memory
                addb ENDGRP                     ; add current and address
                subb BEGGRP                     ; subtract current start (adds size of screen)
                cmpb TXTTAB                     ; does it fit?
                bhi L966D                       ; brif not
                stb ENDGRP                      ; save new end of graphics
                puls b                          ; get back start of graphics
                stb BEGGRP                      ; set start of graphics
L966C           rts
L966D           jmp LB44A                       ; raise FC error
; SCREEN command
SCREEN          cmpa #',                        ; is there a mode?
                beq L967F                       ; brif no mode
                jsr EVALEXPB                    ; get mode argument
                tstb                            ; set Z if alpha
                jsr L95AA                       ; set SAM/VDG for graphics mode
                jsr GETCCH                      ; is there a second argument?
                beq L966C                       ; brif not
L967F           jsr LB738                       ; evaluate ,<expr>
                tstb                            ; colour set 0?
                beq L9687                       ; brif so
                ldb #8                          ; flag for colour set 1
L9687           stb CSSVAL                      ; set colour set
                bra L9616                       ; set up VDG
; PCLEAR command
PCLEAR          jsr EVALEXPB                    ; evaulate number of pages requested
                tstb                            ; 0?
                beq L966D                       ; brif zero - not allowed
                cmpb #9                         ; more than 8?
                bhs L966D                       ; brif so - not allowed
                lda #6                          ; there are 6 "pages" per graphics page
                mul                             ; now B is the number of pages to reserve
                addb GRPRAM                     ; add to start of graphics memory
                tfr b,a                         ; now A is the MSB of the start of free memory
                ldb #1                          ; program memory always starts one above
                tfr d,y                         ; save pointer to program memory
                cmpd ENDGRP                     ; are we trying to deallocate the current graphics page?
                blo L966D                       ; brif so (note that this prevents PCLEAR 0 anyway)
                subd TXTTAB                     ; subtract out current start of basic program
                addd VARTAB                     ; add in end of program - now D is new top of program
                tfr d,x                         ; save new end of program
                inca                            ; make some extra space (for stack)
                subd FRETOP                     ; see if new top of program fits
                bhs L966D                       ; brif there isn't enough space
                jsr L80D0                       ; adjust input pointer
                nop                             ; space filler for 1.1 patch (the JSR above)
                ldu VARTAB                      ; get end of program
                stx VARTAB                      ; save new end of program
                cmpu VARTAB                     ; is old end higher?
                bhs L96D4                       ; brif so
L96BD           lda ,-u                         ; copy a byte upward
                sta ,-x
                cmpu TXTTAB                     ; at beginning?
                bne L96BD                       ; brif not
                sty TXTTAB                      ; save new start of program
                clr -1,y                        ; there must always be a NUL before the program
L96CB           jsr LACEF                       ; re-assign basic program addresses
                jsr LAD26                       ; reset variables and stack
                jmp LAD9E                       ; return to interpretation loop
L96D4           ldu TXTTAB                      ; get start of program
                sty TXTTAB                      ; save new start of program
                clr -1,y                        ; there must be a NUL at the start of the program
L96DB           lda ,u+                         ; move a byte downward
                sta ,y+
                cmpy VARTAB                     ; at the top of the program?
                bne L96DB                       ; brif not
                bra L96CB                       ; finish up
; Graphics initialization routine - this really should be up at the start of the ROM with the
; rest of the initialization code.
L96E6           ldb #0x1e                       ; set start of program to 0x1e00 ("PCLEAR 4")
                stb TXTTAB
                lda #6                          ; graphics memory starts immediately after the screen
L96EC           sta GRPRAM                      ; set graphics memory start
                sta BEGGRP                      ; set start of current graphics page
                clra                            ; set PMODE to 0
                sta PMODE
                lda #16                         ; 16 bytes per graphics row
                sta HORBYT
                lda #3                          ; set foreground colour to 3
                sta FORCOL
                lda #0x0c                       ; set ending graphics page (for PMODE 0)
                sta ENDGRP
                ldx TXTTAB                      ; get start of program
                clr -1,x                        ; make sure there's a NUL before it
L9703           jmp LAD19                       ; do a "NEW"
; PMODE data table (bytes per row and number of 256 byte pages required for a screen)
L9706           fcb 16,6                        ; PMODE 0
                fcb 32,12                       ; PMODE 1
                fcb 16,12                       ; PMODE 2
                fcb 32,24                       ; PMODE 3
                fcb 32,24                       ; PMODE 4
; Calculate absolute value of vertical coordinate difference
L9710           ldd VEREND                      ; get ending address
                subd VERBEG                     ; get difference
L9714           bcc L9751                       ; brif we didn't carry
                pshs cc                         ; save status (C set if start > end)
                jsr L9DC3                       ; negate the difference to be positive
                puls cc,pc                      ; restore C and return
; Calculate absolute value of horizontal coordinate difference
L971D           ldd HOREND                      ; get end coordinate
                subd HORBEG                     ; calculate difference
                bra L9714                       ; turn into absolute value
; PCOPY command
PCOPY           bsr L973F                       ; fetch address of the source page
                pshs d                          ; save address
                ldb #0xa5                       ; make sure we have TO
                jsr LB26F
                bsr L973F                       ; fetch address of the second page
                puls x                          ; get back source
                tfr d,u                         ; put destination into a pointer
                ldy #0x300                      ; 0x300 words to copy
L9736           ldd ,x++                        ; copy a word
                std ,u++
                leay -1,y                       ; done?
                bne L9736                       ; brif not
                rts
L973F           jsr EVALEXPB                    ; evaluate page number
                tstb                            ; zero?
                beq L9752                       ; brif invalid page number
; BUG: this should be deferred until after the address is calculated at which point it should
; be bhs instead of bhi. There should also be a check to make sure the page number is less than
; or equal to 8 above so we don't have to test for overflows below.
                cmpb TXTTAB                     ; is page number higher than start of program (BUG!)
                bhi L9752                       ; brif so - error
                decb                            ; zero-base the page number
                lda #6                          ; 6 "pages" per graphics page
                mul                             ; now we have proper number of "pages" for the offset
                addb GRPRAM                     ; add start of graphics memory
                exg a,b                         ; put MSB into A, 0 into B.
L9751           rts
L9752           jmp LB44A                       ; raise illegal function call
; GET command
GET             clrb                            ; GET flag
                bra L975A                       ; go on to the main body
PUT             ldb #1                          ; PUT flag
L975A           stb VD8                         ; save GET/PUT flag
                jsr RVEC22                      ; do the RAM hook dance (so Disk Basic can do its thing)
L975F           cmpa #'@                        ; @ before coordinates?
                bne L9765                       ; brif not
                jsr GETNCH                      ; eat the @
L9765           jsr L938F                       ; evaluate start/end coordinates
                jsr SYNCOMMA                    ; make sure we have a comma
                jsr L98CC                       ; get pointer to array
                tfr X,D                         ; save descriptor pointer
                ldu ,x                          ; get offset to next descriptor
                leau -2,u                       ; move back to array name
                leau d,u                        ; point to end of array
                stu VD1                         ; save end of data
                leax 2,x                        ; point to number of dimensions
                ldb ,x                          ; get dimension count
                aslb                            ; two bytes per dimension size
                abx                             ; now X points to start of data
                stx VCF                         ; save start of array data
                lda VALTYP                      ; is it numeric
                bne L9752                       ; brif not
                clr VD4                         ; set default graphic action to PSET
                jsr GETCCH                      ; get input character
                beq L97B7                       ; brif no action flag
                com VD4                         ; flag action enabled
                jsr SYNCOMMA                    ; make sure there's a comma
                tst VD8                         ; PUT?
                bne L979A                       ; brif so
                ldb #'G                         ; check for full graphics option
                jsr LB26F
                bra L97CA                       ; handle the rest of the process
L979A           ldb #5                          ; 5 legal actions for PUT
                ldx #L9839                      ; point to action table
L979F           ldu ,x++                        ; get "clear bit" action routine
                ldy ,x++                        ; get "set bit" action routine
                cmpa ,x+                        ; does token match?
                beq L97AE                       ; brif so
                decb                            ; checked all?
                bne L979F                       ; brif not
                jmp LB277                       ; raise error
L97AE           sty VD5                         ; save set bit action address
                stu VD9                         ; save clear bit action address
                jsr GETNCH                      ; munch the acton token
                bra L97CA                       ; handle rest of process
L97B7           ldb #0xf8                       ; mask for bottom three bits
                lda PMODE                       ; get graphics mode
                rora                            ; odd number mode?
                bcc L97C0                       ; brif even
                ldb #0xfc                       ; bottom 2 bits mask
L97C0           tfr b,a                         ; save mask
                andb HORBEG+1                   ; round down the start address
                stb HORBEG+1
                anda HOREND+1                   ; round down end address
                sta HOREND+1
L97CA           jsr L971D                       ; get horizontal size
                bcc L97D3                       ; brif end > start
                ldx HOREND                      ; switch end in for start
                stx HORBEG
L97D3           std HOREND                      ; save size
                jsr L9710                       ; calculate vertical size
                bcc L97DE                       ; brif end > start
                ldx VEREND                      ; swap in vertical end for the start
                stx VERBEG
L97DE           std VEREND                      ; save vertical size
                lda PMODE                       ; get graphics mode
                rora                            ; even?
                ldd HOREND                      ; get difference
                bcc L97EB                       ; brif even (2 colour)
                addd HOREND                     ; add in size (double it)
                std HOREND                      ; save adjusted end size
L97EB           jsr L9420                       ; normalize differences
                ldd HOREND                      ; get end coord
                ldx VEREND                      ; get end size
                leax 1,x                        ; make vertical size inclusive
                stx VEREND                      ; save it back
                tst VD4                         ; got "G" or GET action
                bne L9852                       ; brif given
                lsra                            ; we're going for whole bytes here
                rorb
                lsra
                rorb
                lsra
                rorb
                addd #1                         ; make it inclusive
                std HOREND                      ; save new coordinate
                jsr L9298                       ; convert to screen address
L9808           ldb HOREND+1                    ; get horizontal size
                pshs x                          ; save screen position
L980C           tst VD8                         ; get/put flag
                beq L9831                       ; brif get
                bsr L9823                       ; bump array data pointer
                lda ,u                          ; copy data from array to screen
                sta ,x+
L9816           decb                            ; are we done the row?
                bne L980C                       ; brif not
                puls x                          ; get screen address
                jsr L92E9                       ; move to next row
                dec VEREND+1                    ; done?
                bne L9808                       ; brif not
L9822           rts
L9823           ldu VCF                         ; get array data location
                leau 1,u                        ; bump it
                stu VCF                         ; save new array data location
                cmpu VD1                        ; did we hit the end of the array?
                bne L9822                       ; brif not
L982E           jmp LB44A                       ; raise function call error
L9831           lda ,x+                         ; get data from screen
                bsr L9823                       ; bump array data pointer
                sta ,u                          ; put data in array
                bra L9816                       ; do the loopy thing
; PUT actions
L9839           fdb L9894,L989B                 ; PSET
                fcb 0xbd
                fdb L989B,L9894                 ; PRESET
                fcb 0xbe
                fdb L98B1,L989B                 ; OR
                fcb 0xb1
                fdb L9894,L98B1                 ; AND
                fcb 0xb0
                fdb L98A1,L98A1                 ; NOT
                fcb 0xa8
L9852           addd #1                         ; add to horiz difference
                std HOREND                      ; save it
                lda VD8                         ; PUT?
                bne L9864                       ; brif so
                ldu VD1                         ; get end of array
L985D           sta ,-u                         ; zero out a byte
                cmpu VCF                        ; done?
                bhi L985D                       ; brif not
L9864           jsr L9298                       ; get screen address
                ldb PMODE                       ; get graphics mode
                rorb                            ; even?
                bcc L986E                       ; brif so
                anda #0xaa                      ; use as pixel mask for 4 colour mode
L986E           ldb #1                          ; set bit probe
                ldy VCF                         ; point to start of array data
L9873           pshs x,a                        ; save screen address
                ldu HOREND                      ; get horizontal size
L9877           pshs u,a                        ; save horizontal size and pixel mask
                lsrb                            ; move bit probe right
                bcc L9884                       ; brif we didn't fall off a byte
                rorb                            ; shift carry back in on the left
                leay 1,y                        ; move ahead a byte in the array
                cmpy VD1                        ; end of array data?
                beq L982E                       ; raise error if so
L9884           tst VD8                         ; PUT?
                beq L98A7                       ; brif not
                bitb ,y                         ; test bit in array
                beq L9890                       ; brif not set
                jmp [VD5]                       ; do action routine for bit set
L9890           jmp [VD9]                       ; do action routine for bit clear
L9894           coma                            ; invert mask
                anda ,x                         ; read screen data and reset the desired bit
                sta ,x                          ; save on screen
                bra L98B1
L989B           ora ,x                          ; merge pixel mask with screen data (turn on bit)
                sta ,x                          ; save on screen
                bra L98B1
L98A1           eora ,x                         ; invert the pixel in the screen data
                sta ,x                          ; save on screen
                bra L98B1
L98A7           bita ,x                         ; is the bit set?
                beq L98B1                       ; brif not - do nothing
                tfr b,a                         ; get bit probe
                ora ,y                          ; turn on proper bit in data
                sta ,y
L98B1           puls a,u                        ; get back array address
                jsr L92ED                       ; move screen address to the right
                leau -1,u                       ; account for consumed pixel
                cmpu ZERO                       ; done yet?
                bne L9877                       ; brif not
                ldx 1,s                         ; get start of row back
                lda HORBYT                      ; get number of bytes per row
                leax a,x                        ; move ahead one line
                puls a                          ; get back screen pixel mask
                leas 2,s                        ; lose the screen pointer
                dec VEREND+1                    ; done all rows?
                bne L9873                       ; brif not
                rts
L98CC           jsr LB357                       ; evaluate a variable
                ldb ,-x                         ; get variable name
                lda ,-x
                tfr d,u                         ; save it
                ldx ARYTAB                      ; get start of arrays
L98D7           cmpx ARYEND                     ; end of arrays?
                lbeq LB44A                      ; brif not found
                cmpu ,x                         ; correct variable?
                beq L98E8                       ; brif so
                ldd 2,x                         ; get array size
                leax d,x                        ; move to next array
                bra L98D7                       ; check this array
L98E8           leax 2,x                        ; move pointer to the array header
                rts                             ; obviously this rts is not needed
L98EB           rts
; PAINT command
PAINT           cmpa #'@                        ; do we have @ before coords?
                bne L98F2                       ; brif not
                jsr GETNCH                      ; eat the @
L98F2           jsr L93B2                       ; evaluate coordinates
                jsr L931D                       ; normalize coordinates
                lda #1                          ; PSET flag (use working colour)
                sta SETFLG
                jsr L9581                       ; parse colour and set working colour, etc.
                ldd WCOLOR                      ; get working colour and all pixels byte
                pshs d                          ; save them
                jsr GETCCH                      ; is there anything else?
                beq L990A                       ; brif not
                jsr L9581                       ; evaluate border colour
L990A           lda ALLCOL                      ; get border colour all pixel byte
                sta VD8                         ; save border colour pixel byte
                puls d                          ; get back working colour details
                std WCOLOR
                clra                            ; store a "stop" frame on the stack so PAINT knows when it's finished unwinding
                pshs u,x,b,a
                jsr L9522                       ; set up starting coordinates
                jsr L928F                       ; point to pixel mask routine
                stu VD9                         ; save pixel mask routine
                jsr L99DF                       ; paint from current horizontal coordinate to zero (left)
                beq L9931                       ; brif hit border immediately
                jsr L99CB                       ; paint from current horizontal coordinate upward (right)
                lda #1                          ; set direction to "down"
                sta VD7
                jsr L99BA                       ; save "down" frame
                neg VD7                         ; set direction to "up"
                jsr L99BA                       ; save "up" frame
L9931           sts TMPSTK                      ; save stack pointer
L9934           tst CHGFLG                      ; did the paint change anything?
                bne L993B                       ; brif so
                lds TMPSTK                      ; get back stack pointer
L993B           puls a,b,x,u                    ; get frame from stack
                clr CHGFLG                      ; mark nothing changed
                sts TMPSTK                      ; save stack pointer
                leax 1,x                        ; move start coordinate right
                stx HORBEG                      ; save new coordinate
                stu VD1                         ; save length of line
                sta VD7                         ; save up/down flag
                beq L98EB                       ; did we hit the "stop" frame?
                bmi L9954                       ; brif negative going (up)?
                incb                            ; bump vertical coordinate
                cmpb VD6                        ; at end?
                bls L9958                       ; brif not
                clrb                            ; set vertical to 0 (wrap around)
L9954           tstb                            ; did we wrap?
                beq L9934                       ; do another block if so
                decb                            ; move up a row
L9958           stb VERBEG+1                    ; save vertical coordinate
                jsr L99DF                       ; paint from horizontal to 0
                beq L996E                       ; brif we hit the border immediately
                cmpd #3                         ; less than 3 pixels?
                blo L9969                       ; brif so
                leax -2,x                       ; move two pixels left
                bsr L99A1                       ; save paint block on the stack
L9969           jsr L99CB                       ; continue painting to the right
L996C           bsr L99BA                       ; save paint data frame
L996E           coma                            ; complement length of line just painted and add to length of line
                comb
L9970           addd VD1                        ; save difference between this line and parent line
                std VD1
                ble L998C                       ; brif parent line is shorter
                jsr L9506                       ; bump horizontal coordinate
                jsr L9A12                       ; see if we bounced into the border
                bne L9983                       ; brif not border
                ldd #-1                         ; move left
                bra L9970                       ; keep looking
L9983           jsr L9514                       ; move horizontally left
                bsr L99C6                       ; save horizontal coordinate
                bsr L99E8                       ; paint right
                bra L996C                       ; save paint block and do more
L998C           jsr L9506                       ; bump horizontal coordinate
                leax d,x                        ; point to right end of parent line
                stx HORBEG                      ; set as curent coordinate
                coma                            ; get amount we extend past parent line
                comb
                subd #1
                ble L999E                       ; brif doesn't extend
                tfr d,x                         ; save length of line
                bsr L99A1                       ; save paint frame
L999E           jmp L9934
L99A1           std VCB                         ; save number of pixels painted
                puls y                          ; get return address
                ldd HORBEG                      ; get horizontal coordinate
                pshs x,b,a                      ; save horizontal coordinate and pointer
                lda VD7                         ; get up/down flag
                nega                            ; reverse it
L99AC           ldb VERBEG+1                    ; get vertical coordainte
                pshs b,a                        ; save vertical coord and up/down flag
                pshs y                          ; put return address back
                ldb #2                          ; make sure we haven't overflowed memory
                jsr LAC33
                ldd VCB                         ; get line length back
                rts
L99BA           std VCB                         ; save length of painted line
                puls y                          ; get return address
                ldd HOREND                      ; get start coord
                pshs x,b,a                      ; save horizontal start and length
                lda VD7                         ; get up/down flag
                bra L99AC                       ; finish up with the stack
L99C6           ldx HORBEG                      ; save current horizontal coord and save it
                stx HOREND
                rts
L99CB           std VCD                         ; save number of pixels painted
                ldy HOREND                      ; get last horizontal start
                bsr L99C6                       ; save current coordinate
                sty HORBEG                      ; save coordinate
                bsr L99E8                       ; paint a line
                ldx VCD                         ; get number painted
                leax d,x                        ; add to the number painted going the other way
                addd #1                         ; now D is length of line
                rts
L99DF           jsr L99C6                       ; put starting coordinate in end
                ldy #L9514                      ; decrement horizontal coordinate address
                bra L99EE                       ; go paint line
L99E8           ldy #L9506                      ; increment horizontal coordinate address
                jsr ,y                          ; bump coordinate
L99EE           ldu ZERO                        ; initialize pixel count
                ldx HORBEG                      ; get starting coordinate
L99F2           bmi L9A0B                       ; brif out of range for hoizontal coordinate
                cmpx VD3                        ; at end?
                bhi L9A0B                       ; brif right of max
                pshs u,y                        ; save counter and inc/dec routine pointer
                bsr L9A12                       ; at border?
                beq L9A09                       ; brif so
                jsr L9377                       ; set pixel to paint colour
                puls y,u                        ; restore counter and inc/dec/pointer
                leau 1,u                        ; bump number of painted pixels
                jsr ,y                          ; inc/dec screen address
                bra L99F2                       ; go do another pixel
L9A09           puls y,u                        ; get back counter and inc/dec routine
L9A0B           tfr u,d                         ; save count in D
                tfr d,x                         ; and in X
                subd ZERO                       ; set flags on D (smaller/faster than cmpd ZERO)
                rts
L9A12           jsr [VD9]                       ; get the screen address
                tfr a,b                         ; save pixel mask
                andb VD8                        ; set pixel to border colour
                pshs b,a                        ; save mask and border
                anda ,x                         ; mask current pixel into A
                cmpa 1,s                        ; does it match border? Z=1 if so
                puls a,b,pc                     ; restore mask, border pixel, and return
; PLAY command
; This is here mixed in with the graphics package because it shares some machinery with DRAW.
PLAY            ldx ZERO                        ; default values for note length, etc.
                ldb #1
                pshs x,b                        ; save default values
                jsr LB156                       ; evaluate argument
                clrb                            ; enable DA and sound output
                jsr LA9A2
                jsr LA976
L9A32           jsr LB654                       ; fetch PLAY string details
                bra L9A39                       ; go evaluate the string
L9A37           puls b,x                        ; get back play string details
L9A39           stb VD8                         ; save length of string
                beq L9A37                       ; brif end of string
                stx VD9                         ; save start of string
                lbeq LA974                      ; brif NULL string - disable sound and return
L9A43           tst VD8                         ; have anything left?
                beq L9A37                       ; brif not
                jsr L9B98                       ; get command character
                cmpa #';                        ; command separator?
                beq L9A43                       ; brif so - ignore it
                cmpa #''                        ; '?
                beq L9A43                       ; brif so - ignore it
                cmpa #'X                        ; execuate sub string?
                lbeq L9C0A                      ; brif so - handle it
                bsr L9A5C                       ; handle other commands
                bra L9A43                       ; look for more stuff
L9A5C           cmpa #'O                        ; octave?
                bne L9A6D                       ; brif not
                ldb OCTAVE                      ; get current octave
                incb                            ; 1-base it
                bsr L9AC0                       ; get value if present
                decb                            ; zero-base it
                cmpb #4                         ; valid octave?
                bhi L9ACD                       ; raise error if not
                stb OCTAVE                      ; save new octave
                rts
L9A6D           cmpa #'V                        ; volume?
                bne L9A8B                       ; brif not
                ldb VOLHI                       ; get current high volume limit
                lsrb                            ; shift 2 bits right (DA is 6 bits in high bits)
                lsrb
                subb #31                        ; subtract out mid value offset
                bsr L9AC0                       ; read argument
                cmpb #31                        ; maximum range is 31
                bhi L9ACD                       ; brif out of range
                aslb                            ; adjust back in range
                aslb
                pshs b                          ; save new volume
                ldd #0x7e7e                     ; midrange value for both high and low
                adda ,s                         ; add new volume to high limit
                subb ,s+                        ; subtract volume from low limit
                std VOLHI                       ; save new volume limits (sets high and low amplitudes)
                rts
L9A8B           cmpa #'L                        ; note length?
                bne L9AB2                       ; brif not
                ldb NOTELN                      ; get current length
                bsr L9AC0                       ; read parameter
                tstb                            ; resulting length 0?
                beq L9ACD                       ; brif so - problem
                stb NOTELN                      ; save new length
                clr DOTVAL                      ; reset note timer scale factor
L9A9A           bsr L9A9F                       ; check for dot
                bcc L9A9A                       ; brif there was one
                rts
L9A9F           tst VD8                         ; check length
                beq L9AAD                       ; brif zero
                jsr L9B98                       ; get command character
                cmpa #'.                        ; dot?
                beq L9AAF                       ; brif so
                jsr L9BE2                       ; move input back and bump length
L9AAD           coma                            ; set C to indicate nothing found
                rts
L9AAF           inc DOTVAL                      ; bump number of dots
                rts
L9AB2           cmpa #'T                        ; tempo?
                bne L9AC3                       ; brif not
                ldb TEMPO                       ; get current tempo
                bsr L9AC0                       ; parse tempo argument
                tstb                            ; 0?
                beq L9ACD                       ; brif so - invalid
                stb TEMPO                       ; save new tempo
                rts
L9AC0           jmp L9BAC                       ; evaluate various operators
L9AC3           cmpa #'P                        ; pause?
                bne L9AEB                       ; brif not
                jsr L9CCB                       ; evaluate parameter
                tstb                            ; is the pause number 0?
                bne L9AD0                       ; brif not
L9ACD           jmp LB44A                       ; raise FC error
L9AD0           lda DOTVAL                      ; save current volume and note scale
                ldx VOLHI
                pshs x,a
                lda #0x7e                       ; drop DA to mid range
                sta VOLHI
                sta VOLLOW
                clr DOTVAL
                bsr L9AE7                       ; go play a "silence"
                puls a,x                        ; restore volume and note scale
                sta DOTVAL
                stx VOLHI
                rts
L9AE7           clr ,-s                         ; set not number 0
                bra L9B2B                       ; go play it
L9AEB           cmpa #'N                        ; N for "note"?
                bne L9AF2                       ; brif not - it's optional
                jsr L9B98                       ; skip the "N"
L9AF2           cmpa #'A                        ; is it a valid note?
                blo L9AFA                       ; brif not
                cmpa #'G                        ; is it above the note range?
                bls L9AFF                       ; brif not - valid note
L9AFA           jsr L9BBE                       ; evaluate a number
                bra L9B22                       ; process note value
L9AFF           suba #'A                        ; normalize note number to 0
                ldx #L9C5B                      ; point to note number lookup table
                ldb a,x                         ; get not number
                tst VD8                         ; any command characters left?
                beq L9B22                       ; brif not
                jsr L9B98                       ; get character
                cmpa #'#                        ; sharp?
                beq L9B15                       ; brif so
                cmpa #'+                        ; also sharp?
                bne L9B18                       ; brif not
L9B15           incb                            ; add one half tone
                bra L9B22
L9B18           cmpa #'-                        ; flat?
                bne L9B1F                       ; brif not
                decb                            ; subtract one half tone
                bra L9B22
L9B1F           jsr L9BE2                       ; back up command pointer
L9B22           decb                            ; adjust note number (zero base it)
                cmpb #11                        ; is it valid?
                bhi L9ACD                       ; raise error if not
                pshs b                          ; save note value
                ldb NOTELN                      ; get note length
L9B2B           lda TEMPO                       ; get tempo value
                mul                             ; calculate note duration
                std VD5                         ; save duration
                leau 1,s                        ; point to where the stack goes after we're done
                lda OCTAVE                      ; get current octave
                cmpa #1                         ; 0 or 1?
                bhi L9B64                       ; brif not
                ldx #L9C62                      ; point to delay table
                ldb #2*12                       ; 24 bytes per octave
                mul                             ; now we have the base address
                abx                             ; now X points to the octave base
                puls b                          ; get back note value
                aslb                            ; two bytes per delay
                abx                             ; now we're pointing to the delay
                leay ,x                         ; save pointer to note value
                bsr L9B8C                       ; calculate note timer value
                std PLYTMR                      ; set timer for note playing (IRQ will count this down)
L9B49           bsr L9B57                       ; set to mid range and delay
                lda VOLHI                       ; get high value
                bsr L9B5A                       ; set to high value and delay
                bsr L9B57                       ; set to mid range and delay
                lda VOLLOW                      ; get low value
                bsr L9B5A                       ; set to low value and delay
                bra L9B49                       ; do it again (IRQ will break the loop)
L9B57           lda #0x7e                       ; mid value for DA with RS232 marking
                nop                             ; a delay to fine tune frequencies
L9B5A           sta PIA1                        ; set DA
                ldx ,y                          ; get delay value
L9B5F           leax -1,x                       ; count down
                bne L9B5F                       ; brif not done yet
                rts
L9B64           ldx #L9C92-2*12                 ; point to delay table for octaves 2+
                ldb #12                         ; 12 bytes per octave
                mul                             ; now we have the offset to the desired octave
                abx                             ; now we point to the start of the octave
                puls b                          ; get back note value
                abx                             ; now we point to the delay value
                bsr L9B8C                       ; calculate timer value
                std PLYTMR                      ; set play timer (IRQ counts this down)
L9B72           bsr L9B80                       ; send mid value and delay
                lda VOLHI                       ; get high value
                bsr L9B83                       ; send high value and delay
                bsr L9B80                       ; send low value and delay
                lda VOLLOW                      ; get low value
                bsr L9B83                       ; send low value and delay
                bra L9B72                       ; do it again (IRQ will break the loop)
L9B80           lda #0x7e                       ; mid range value with RS232 marking
                nop                             ; fine tuning delay
L9B83           sta PIA1                        ; set DA
                lda ,x                          ; get delay value
L9B88           deca                            ; count down
                bne L9B88                       ; brif not done
                rts
L9B8C           ldb #0xff                       ; base timer value
                lda DOTVAL                      ; get number of dots
                beq L9B97                       ; use default value if 0
                adda #2                         ; add in constant timer factor
                mul                             ; multiply scale by base
                lsra                            ; divide by two - each increment will increase note timer by 128
                rorb
L9B97           rts
L9B98           pshs x                          ; save register
L9B9A           tst VD8                         ; do we have anything left?
                beq L9BEB                       ; brif not - raise error
                ldx VD9                         ; get parsing address
                lda ,x+                         ; get character
                stx VD9                         ; save pointer
                dec VD8                         ; account for character consumed
                cmpa #0x20                      ; space?
                beq L9B9A                       ; brif so - skip it
                puls x,pc                       ; restore register and return
L9BAC           bsr L9B98                       ; get character
                cmpa #'+                        ; add one?
                beq L9BEE                       ; brif so
                cmpa #'-                        ; subtract one?
                beq L9BF2                       ; brif so
                cmpa #'>                        ; double?
                beq L9BFC                       ; brif so
                cmpa #'<                        ; halve?
                beq L9BF7                       ; brif so
L9BBE           cmpa #'=                        ; variable equate?
                beq L9C01                       ; brif so
                jsr L90AA                       ; clear carry if numeric
                bcs L9BEB                       ; brif not numeric
                clrb                            ; initialize value to 0
L9BC8           suba #'0                        ; remove ASCII bias
                sta VD7                         ; save digit
                lda #10                         ; make room for digit
                mul
                tsta                            ; did we overflow 8 bits?
                bne L9BEB                       ; brif so
                addb VD7                        ; add in digit
                bcs L9BEB                       ; brif that overflowed
                tst VD8                         ; more digits?
                beq L9BF1                       ; brif not
                jsr L9B98                       ; get character
                jsr L90AA                       ; clear carry if numeric
                bcc L9BC8                       ; brif another digit
L9BE2           inc VD8                         ; unaccount for character just read
                ldx VD9                         ; move pointer back
                leax -1,x
                stx VD9
                rts
L9BEB           jmp LB44A                       ; raise FC error
L9BEE           incb                            ; bump param
                beq L9BEB                       ; brif overflow
L9BF1           rts
L9BF2           tstb                            ; already zero?
                beq L9BEB                       ; brif so - underflow
                decb                            ; decrease parameter
                rts
L9BF7           tstb                            ; already at 0?
                beq L9BEB                       ; brif so - raise error
                lsrb                            ; halve it
                rts
L9BFC           tstb                            ; will it overflow?
                bmi L9BEB                       ; brif so
                aslb                            ; double it
                rts
L9C01           pshs u,y                        ; save registers
                bsr L9C1B                       ; interpret command string as a variable
                jsr LB70E                       ; convert it to an 8 bit number
                puls y,u,pc                     ; restore registers and return
L9C0A           jsr L9C1B                       ; evaluate expression in command string
                ldb #2                          ; room for 4 bytes?
                jsr LAC33
                ldb VD8                         ; get the command length and pointer
                ldx VD9
                pshs x,b                        ; save them
                jmp L9A32                       ; go process the sub string
L9C1B           ldx VD9                         ; get command pointer
                pshs x                          ; save it
                jsr L9B98                       ; get input character
                jsr LB3A2                       ; set carry if not alpha
                bcs L9BEB                       ; brif not a variable reference
L9C27           jsr L9B98                       ; get command character
                cmpa #';                        ; semicolon?
                bne L9C27                       ; keep scanning if not
                puls x                          ; get back start of variable string
                ldu CHARAD                      ; get current interpreter input pointer
                pshs u                          ; save it
                stx CHARAD                      ; point interpreter at command string
                jsr LB284                       ; evaluate expression as string
                puls x                          ; restore interpeter input pointer
                stx CHARAD
                rts
; The bit of Extended Basic's IRQ routine that handles PLAY. Note that everything after
; clr PLYTMR+1 could be replaced with a simple lds 8,s followed by rts.
L9C3E           clra                            ; make sure DP is set to 0
                tfr a,dp
                ldd PLYTMR                      ; is PLAY running?
                lbeq LA9BB                      ; brif not - transfer control on the Color Basic's routine
                subd VD5                        ; subtract out the interval
                std PLYTMR                      ; save new timer value
                bhi L9C5A                       ; brif it isn't <= 0
                clr PLYTMR                      ; disable the timer
                clr PLYTMR+1
                puls a                          ; get saved CC
                lds 7,s                         ; set stack to saved U value
                anda #0x7f                      ; clear E flag (to return minimal state)
                pshs a                          ; set fake "FIRQ" stack frame
L9C5A           rti
L9C5B           fcb 10,12,1,3,5,6,8             ; table of half tone numbers for notes A-G
L9C62           fdb 0x01a8,0x0190,0x017a,0x0164 ; delays for octave 1
                fdb 0x0150,0x013d,0x012b,0x011a
                fdb 0x010a,0x00fb,0x00ed,0x00df
                fdb 0x00d3,0x00c7,0x00bb,0x00b1 ; delays for octave 2
                fdb 0x00a6,0x009d,0x0094,0x008b
                fdb 0x0083,0x007c,0x0075,0x006e
L9C92           fcb 0xa6,0x9c,0x93,0x8b         ; delays for octave 3
                fcb 0x83,0x7b,0x74,0x6d
                fcb 0x67,0x61,0x5b,0x56
                fcb 0x51,0x4c,0x47,0x43         ; delays for octave 4
                fcb 0x3f,0x3b,0x37,0x34
                fcb 0x31,0x2e,0x2b,0x28
                fcb 0x26,0x23,0x21,0x1f         ; delays for octave 5
                fcb 0x1d,0x1b,0x19,0x18
                fcb 0x16,0x14,0x13,0x12
; DRAW command
DRAW            ldx ZERO                        ; create an empty "DRAW" frame
                ldb #1
                pshs x,b
                stb SETFLG                      ; set to "PSET" mode
                stx VD5                         ; clear update and draw flag
                jsr L959A                       ; set active colour byte
                jsr LB156                       ; evaluate command string
L9CC6           jsr LB654                       ; fetch command string details
                bra L9CD3                       ; interpret the command string
L9CCB           jsr L9B98                       ; fetch command character
                jmp L9BBE                       ; evaluate a number
L9CD1           puls b,x                        ; get previously saved command string
L9CD3           stb VD8                         ; save length counter
                beq L9CD1                       ; brif end of string
                stx VD9                         ; save pointer
                lbeq L9DC7                      ; brif overall end of command
L9CDD           tst VD8                         ; are we at the end of the string?
                beq L9CD1                       ; brif so - return to previous string
                jsr L9B98                       ; get command character
                cmpa #';                        ; semicolon?
                beq L9CDD                       ; brif so - ignore it
                cmpa #''                        ; '?
                beq L9CDD                       ; brif so - ignore that too
                cmpa #'N                        ; update position toggle?
                bne L9CF4                       ; brif not
                com VD5                         ; toggle update position flag
                bra L9CDD                       ; get on for another command
L9CF4           cmpa #'B                        ; blank flag?
                bne L9CFC                       ; brif not
                com VD6                         ; toggle blank flag
                bra L9CDD                       ; get on for another command
L9CFC           cmpa #'X                        ; substring?
                lbeq L9D98                      ; brif so - execute command
                cmpa #'M                        ; move draw position?
                lbeq L9E32                      ; brif so
                pshs a                          ; save command character
                ldb #1                          ; default value if no number follows
                tst VD8                         ; is there something there?
                beq L9D21                       ; brif not
                jsr L9B98                       ; get character
                jsr LB3A2                       ; set C if not alpha
                pshs cc                         ; save alpha state
                jsr L9BE2                       ; move back pointer
                puls cc                         ; get back alpha flag
                bcc L9D21                       ; brif it's alpha
                bsr L9CCB                       ; evaluate a number
L9D21           puls a                          ; get command back
                cmpa #'C                        ; color change?
                beq L9D4F                       ; brif so
                cmpa #'A                        ; angle?
                beq L9D59                       ; brif so
                cmpa #'S                        ; scale?
                beq L9D61                       ; brif so
                cmpa #'U                        ; up?
                beq L9D8F                       ; brif so
                cmpa #'D                        ; down?
                beq L9D8C                       ; brif so
                cmpa #'L                        ; left?
                beq L9D87                       ; brif so
                cmpa #'R                        ; right?
                beq L9D82                       ; brif so
                suba #'E                        ; normalize the half cardinals to 0
                beq L9D72                       ; brif E (45°)
                deca                            ; F (135°?)
                beq L9D6D                       ; brif so
                deca                            ; G (225°?)
                beq L9D7B                       ; brif so
                deca                            ; H (315°?)
                beq L9D69                       ; brif so
L9D4C           jmp LB44A                       ; raise FC error
L9D4F           jsr L955D                       ; adjust colour for PMODE
                stb FORCOL                      ; save new foreground colour
                jsr L959A                       ; set up working colour and all pixels byte
L9D57           bra L9CDD                       ; go process another command
L9D59           cmpb #4                         ; only 3 angles are valid
                bhs L9D4C                       ; brif not valid
                stb ANGLE                       ; save new angle
                bra L9D57                       ; go process another command
L9D61           cmpb #63                        ; only 64 scale values are possible
                bhs L9D4C                       ; brif out of range
                stb SCALE                       ; save new scale factor
                bra L9D57                       ; go process another command
L9D69           clra                            ; make horizontal negative
                bsr L9DC4
                skip1
L9D6D           clra                            ; keep horizontal distance positive
                tfr d,x                         ; make horizontal distance and vertical distance the same
                bra L9DCB                       ; go do the draw thing
L9D72           clra                            ; zero extend horizontal distance
                tfr d,x                         ; set it as vertical
                bsr L9DC4                       ; negate horizontal distance
                exg d,x                         ; swap directions (vertical is now negative)
                bra L9DCB                       ; go do the draw thing
L9D7B           clra                            ; zero extend horizontal distance
                tfr d,x                         ; copy horizontal to vertical
                bsr L9DC4                       ; negate horizontal
                bra L9DCB                       ; go do the drawing thing
L9D82           clra                            ; zero extend horizontal distance
L9DB3           ldx ZERO                        ; no vertical distance
                bra L9DCB                       ; go do the drawing things
L9D87           clra                            ; zero extend horizontal
                bsr L9DC4                       ; negate horizontal
                bra L9DB3                       ; zero out vertical and do the drawing thing
L9D8C           clra                            ; zero extend distance
                bra L9D92                       ; make the distance vertical and zero out horizontal
L9D8F           clra                            ; zero extend distance
                bsr L9DC4                       ; negate distance
L9D92           ldx ZERO                        ; zero out vertical distance
                exg x,d                         ; swap vertical and horizontal
                bra L9DCB                       ; go do the drawing thing
L9D98           jsr L9C1B                       ; evaluate substring expression
                ldb #2                          ; is there enough room for the state?
                jsr LAC33
                ldb VD8                         ; save current command string state
                ldx VD9
                pshs x,b
                jmp L9CC6                       ; go evaluate the sub string
L9DA9           ldb SCALE                       ; get scale factor
                beq L9DC8                       ; brif zero - default to full size
                clra                            ; zero extend
                exg d,x                         ; put distance somewhere useful
                sta ,-s                         ; save MS of distance
                bpl L9DB6                       ; brif positive distance
                bsr L9DC3                       ; negate the distance
L9DB6           jsr L9FB5                       ; multiply D and X
                tfr u,d                         ; save ms bytes in D
                lsra                            ; divide by 2
                rorb
L9DBD           lsra                            ; ...divide by 4
                rorb
                tst ,s+                         ; negative distance?
                bpl L9DC7                       ; brif it was positive
L9DC3           nega                            ; negate D
L9DC4           negb
                sbca #0
L9DC7           rts
L9DC8           tfr x,d                         ; copy unchanged sitance to D
                rts
L9DCB           pshs b,a                        ; save horizontal distance
                bsr L9DA9                       ; apply scale factor to vertical
                puls x                          ; get horizontal distance
                pshs b,a                        ; save scaled vertical
                bsr L9DA9                       ; apply scale to horizontal
                puls x                          ; get back vertical distance
                ldy ANGLE                       ; get draw angle and scale
                pshs y                          ; save them
L9DDC           tst ,s                          ; is there an angle?
                beq L9DE8                       ; brif no angle
                exg x,d                         ; swap distances
                bsr L9DC3                       ; negate D
                dec ,s                          ; account for one tick around the rotation
                bra L9DDC                       ; see if we're there yet
L9DE8           puls y                          ; get angle and scale back
                ldu ZERO                        ; default end position (horizontal) is 0
                addd HORDEF                     ; add default horizontal to horizontal distance
                bmi L9DF2                       ; brif we went negative
                tfr d,u                         ; save calculated end coordindate
L9DF2           tfr x,d                         ; get vertical distance somewhere useful
                ldx ZERO                        ; default vertical end is 0
                addd VERDEF                     ; add distance to default vertical start
                bmi L9DFC                       ; brif negative - use 0
                tfr d,x                         ; save calculated end coordinate
L9DFC           cmpu #256                       ; is horizontal in range?
                blo L9E05                       ; brif su
                ldu #255                        ; maximize it
L9E05           cmpx #192                       ; is vertical in range?
                blo L9E0D                       ; brif so
                ldx #191                        ; maximize it
L9E0D           ldd HORDEF                      ; set starting coordinates for the line
                std HORBEG
                ldd VERDEF
                std VERBEG
                stx VEREND                      ; set end coordinates
                stu HOREND
                tst VD5                         ; are we updating position?
                bne L9E21                       ; brif not
                stx VERDEF                      ; update default coordinates
                stu HORDEF
L9E21           jsr L9420                       ; normalize coordindates
                tst VD6                         ; are we drawing something?
                bne L9E2B                       ; brif not
                jsr L94A1                       ; draw the line
L9E2B           clr VD5                         ; reset draw and update flags
                clr VD6
                jmp L9CDD                       ; do another command
L9E32           jsr L9B98                       ; get a command character
                pshs a                          ; save it
                jsr L9E5E                       ; evaluate horizontal distance
                pshs b,a                        ; save it
                jsr L9B98                       ; get character
                cmpa #',                        ; comma between coordinates?
                lbne L9D4C                      ; brif not - raise error
                jsr L9E5B                       ; evaluate vertical distance
                tfr d,x                         ; save vertical distance
                puls u                          ; get horizontal distance
                puls a                          ; get back first command character
                cmpa #'+                        ; was it + at start?
                beq L9E56                       ; brif +; treat values as positive
                cmpa #'-                        ; was it -?
                bne L9DFC                       ; brif not - treat it as absolute
L9E56           tfr u,d                         ; put horizontal distance somewhere useful
                jmp L9DCB                       ; move draw position (relative)
L9E5B           jsr L9B98                       ; get input character
L9E5E           cmpa #'+                        ; leading +?
                beq L9E69                       ; brif so
                cmpa #'-                        ; leading -?
                beq L9E6A                       ; brif so - negative
                jsr L9BE2                       ; move pointer back one
L9E69           clra                            ; 0  for +, nonzero for -
L9E6A           pshs a                          ; save sign flag
                jsr L9CCB                       ; evaluate number
                puls a                          ; get sign flag
                tsta                            ; negative?
                beq L9E78                       ; brif not
                clra                            ; zero extend and negate
                negb
                sbca #0
L9E78           rts
; Table of sines and cosines for CIRCLE
L9E79           fdb 0x0000,0x0001               ; subarc 0
                fdb 0xfec5,0x1919               ; subarc 1
                fdb 0xfb16,0x31f2               ; subarc 2
                fdb 0xf4fb,0x4a51               ; subarc 3
                fdb 0xec84,0x61f9               ; subarc 4
                fdb 0xe1c7,0x78ae               ; subarc 5
                fdb 0xd4dc,0x8e3b               ; subarc 6
                fdb 0xc5e5,0xa269               ; subarc 7
                fdb 0xb506,0xb506               ; subarc 8
; CIRCLE command
; The circle is drawn as a 64 sided polygon (64 LINE commands essentially)
CIRCLE          cmpa #'@                        ; is there an @ before coordinates?
                bne L9EA3                       ; brif not
                jsr GETNCH                      ; eat the @
L9EA3           jsr L9522                       ; get max coordinates for screen
                jsr L93B2                       ; parse coordinates for circle centre
                jsr L931D                       ; normalize the start coordinates
                ldx ,u                          ; get horizontal coordinate
                stx VCB                         ; save it
                ldx 2,u                         ; get vertical coordinate
                stx VCD                         ; saveit
                jsr SYNCOMMA                    ; make sure we have a comma
                jsr LB73D                       ; evaluate radius expression
                ldu #VCF                        ; point to temp storage
                stx ,u                          ; save radius
                jsr L9320                       ; normalize radius
                lda #1                          ; default to PSET
                sta SETFLG
                jsr L9581                       ; evaluate the colour expression
                ldx #0x100                      ; height/width default value
                jsr GETCCH                      ; is there a ratio?
                beq L9EDF                       ; brif not
                jsr SYNCOMMA                    ; make sure we have a comma
                jsr LB141                       ; evaluate the ratio
                lda FP0EXP                      ; multiply ratio by 256
                adda #8
                sta FP0EXP
                jsr LB740                       ; evaluate ratio to X (fraction part in LSB)
L9EDF           lda PMODE                       ; get graphics mode
                bita #2                         ; is it even?
                beq L9EE9                       ; brif so
                tfr x,d                         ; double the ratio
                leax d,x
L9EE9           stx VD1                         ; save height/width ratio
                ldb #1                          ; set the SET flag to PSET
                stb SETFLG
                stb VD8                         ; set first time flag (set to 0 after arc drawn)
                jsr L9FE2                       ; evaluate circle starting point (octant, subarc)
                pshs b,a                        ; save startpoint
                jsr L9FE2                       ; evaluate circle end point (octant, subarc)
                std VD9                         ; save endp oint
                puls a,b
L9EFD           pshs b,a                        ; save current circle position
                ldx HOREND                      ; move end coordinates to start coordinates
                stx HORBEG
                ldx VEREND
                stx VERBEG
                ldu #L9E79+2                    ; point to sine/cosine table
                anda #1                         ; even octant?
                beq L9F11                       ; brif so
                negb                            ; convert 0-7 to 8-1 for odd octants
                addb #8
L9F11           aslb                            ; four bytes per table entry
                aslb
                leau b,u                        ; point to correct table entry
                pshs u                          ; save sine/cosine table entry pointer
                jsr L9FA7                       ; calculate horizontal offset
                puls u                          ; get back table entry pointer
                leau -2,u                       ; move to cosine entry
                pshs x                          ; save horizontal offset
                jsr L9FA7                       ; calculate vertical offset
                puls y                          ; put horizontal in Y
                lda ,s                          ; get octant number
                anda #3                         ; is it 0 or 4?
                beq L9F31                       ; brif so
                cmpa #3                         ; is it 3 or 7?
                beq L9F31                       ; brif so
                exg x,y                         ; swap horizontal and vertical
L9F31           stx HOREND                      ; save horizontal offset
                tfr y,x                         ; put vertical offset in X
                ldd VD1                         ; get height/width ratio
                jsr L9FB5                       ; multiply vertical by h/w ratio
                tfr y,d                         ; save the product to D
                tsta                            ; did it overflow?
                lbne LB44A                      ; brif so
                stb VEREND                      ; save vertical coordinate MSB
                tfr u,d                         ; get LSW of product
                sta VEREND+1                    ; save LSB of integer part (we have 8 bits of fraction in the ratio)
                lda ,s                          ; get octant
                cmpa #2                         ; is it 0 or 1?
                blo L9F5B                       ; brif so
                cmpa #6                         ; is it 6 or 7?
                bhs L9F5B                       ; brif so
                ldd VCB                         ; get horizontal centre
                subd HOREND                     ; subtract horizontal displacement
                bcc L9F68                       ; brif we didn't overflow the screen
                clra                            ; zero out coordinate if we overflowed the screen
                clrb
                bra L9F68
L9F5B           ldd VCB                         ; get horizontal coordinate of the centre
                addd HOREND                     ; add displacement
                bcs L9F66                       ; brif overlod
                cmpd VD3                        ; larger than max horizontal coord?
                blo L9F68                       ; brif not
L9F66           ldd VD3                         ; maximize the coordinate
L9F68           std HOREND                      ; save horizontal ending coordainte
                lda ,s                          ; get octant
                cmpa #4                         ; is it 0-3?
                blo L9F7A                       ; brif so
                ldd VCD                         ; get vertical coordinate of centre
                subd VEREND                     ; subtract displacement
                bcc L9F87                       ; brif we didn't overflow the screen
                clra                            ; minimize to top of screen
                clrb
                bra L9F87
L9F7A           ldd VCD                         ; get vertical centre coordinate
                addd VEREND                     ; add displacement
                bcs L9F85                       ; brif we overflowed the screen
                cmpd VD5                        ; did we go past max coordinate?
                blo L9F87                       ; brif not
L9F85           ldd VD5                         ; maximize the coordinate
L9F87           std VEREND                      ; save end coordinate
                tst VD8                         ; check first time flag
                bne L9F8F                       ; do not draw if first time through (it was setting start coord)
                bsr L9FDF                       ; draw the line
L9F8F           puls a,b                        ; get arc number and sub arc
                lsr VD8                         ; get first time flag value (and clear it!)
                bcs L9F9A                       ; do not check for end point after drawing for first coordinate
                cmpd VD9                        ; at end point?
                beq L9FA6                       ; brif drawing finished
L9F9A           incb                            ; bump arc counter
                cmpb #8                         ; done 8 arcs?
                bne L9FA3                       ; brif not
                inca                            ; bump octant
                clrb                            ; reset subarc number
                anda #7                         ; make sure octant number stays in 0-7 range
L9FA3           jmp L9EFD                       ; go do another arc
L9FA6           rts
L9FA7           ldx VCF                         ; get radius
                ldd ,u                          ; get sine/cosine table entry
                beq L9FB4                       ; brif 0 - offset = radius
                subd #1                         ; adjust values to correct range
                bsr L9FB5                       ; multiply radius by sine/cosine
                tfr y,x                         ; resturn result in X
L9FB4           rts
L9FB5           pshs u,y,x,b,a                  ; save registers and reserve temp space
                clr 4,s                         ; reset overflow byte (YH)
                lda 3,s                         ; calcuate B*XL
                mul
                std 6,s                         ; put in "U"
                ldd 1,s                         ; calculate B*XH
                mul
                addb 6,s                        ; accumluate with previous product
                adca #0
                std 5,s                         ; save in YL,UH
                ldb ,s                          ; calculate A*XL
                lda 3,s
                mul
                addd 5,s                        ; accumulate with previous partical product
                std 5,s                         ; save in YL,UH
                bcc L9FD4                       ; brif no carry
                inc 4,s                         ; bump YH for carry
L9FD4           lda ,s                          ; calculate A*XH
                ldb 2,s
                mul
                addd 4,s                        ; accumulate with previous partial product
                std 4,s                         ; save in Y (we can't have a carry here)
                puls a,b,x,y,u,pc               ; restore multiplicands and return results
L9FDF           jmp L94A1                       ; go draw a line
L9FE2           clrb                            ; default arc number (0)
                jsr GETCCH                      ; is there something there for a value?
                beq L9FF8                       ; brif not
                jsr SYNCOMMA                    ; evaluate , + expression
                jsr LB141
                lda FP0EXP                      ; multiply by 64
                adda #6
                sta FP0EXP
                jsr LB70E                       ; get integer value of circle fraction
                andb #0x3f                      ; max value of 63
L9FF8           tfr b,a                         ; save arc value in A to calculate octant
                andb #7                         ; calculate subarc
                lsra                            ; calculate octant
                lsra
                lsra
                rts
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; COLOR BASIC ROM area
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; This is the official set of ROM entry points. It is unfortunate that the generic input ("console in") routine is not exposed
; here. It is also unfortunate that no open and close file routines are exposed. This and other oversignts led to a lot of
; software either having to re-invent the wheel or calling directly into the ROM instead of via these official entry points.
POLCAT          fdb KEYIN                       ; indirect jump, get a keystroke
CHROUT          fdb PUTCHR                      ; indirect jump, output character
CSRDON          fdb CASON                       ; indirect jump, turn cassette on and start reading
BLKIN           fdb GETBLK                      ; indirect jump, read a block from tape
BLKOUT          fdb SNDBLK                      ; indirect jump, write a block to tape
JOYIN           fdb GETJOY                      ; indirect jump, read joystick axes
WRTLDR          fdb WRLDR                       ; indirect jump, turn cassette on and write a leader
; Initialization code.
LA00E           lds #LINBUF+LBUFMX+1            ; put the stack in the line input buffer which is a safe place for now
                lda #0x37                       ; enable the cartidge interrupt (to detect autostarting cartridges)
                sta PIA1+3
                lda RSTFLG                      ; get warm start flag
                cmpa #0x55                      ; is it valid?
                bne BACDST                      ; brif not - cold start
                ldx RSTVEC                      ; get warm start routine pointer
                lda ,x                          ; get first byte of the routine
                cmpa #0x12                      ; is it NOP?
                bne BACDST                      ; brif not - the routine is invalid so do a cold start
                jmp ,x                          ; transfer control to the warm start routine
; RESET/power on comes here
RESVEC          leay LA00E,pcr                  ; point to warm start check code
LA02A           lda #0x3a                       ; restore MMU block in 0x4000-0x5fff block
                sta MMUREG+2
                ldx #PIA1                       ; point to PIA1
                ldd #0xff34                     ; set up for initializing PIAs
                clr 1,x                         ; set PIA1 DA to direction mode
                clr 3,x                         ; set PIA1 DB to direction mode
                deca
                sta ,x                          ; set PIA1 DA bits 7-1 as output, 0 as input
                lda #0xf8                       ; set PIA1 DB bits 7-3 as output, 2-0 as input
                sta 2,x
                stb 1,x                         ; set PIA1 DA to data mode
                stb 3,x                         ; set PIA1 DB to data mode
                clr 2,x                         ; set VDG to alpha-numeric
                lda #2                          ; set RS232 to marking
                sta ,x
                lda #0xff
                ldx #PIA0                       ; point to PIA0
                clr 1,x                         ; set PIA0 DA to direction mode
                clr 3,x                         ; set PIA0 DB to direction mode
                clr ,x                          ; set PIA0 DA to input
                sta 2,x                         ; set PIA0 DB to output
                stb 1,x                         ; set PIA0 DA to direction mode
                stb 3,x                         ; set PIA0 DB to direction mode
                jmp LA072                       ; continue initializing
LA05E           jsr L8C2E                       ; map ROM pack
                jmp 0xc000                      ; transfer control to ROM pack
; Left over initialization code from Color Basic 1.2 follows
	bitb 2,x                        ; check RAMSZ input
	beq LA072                       ; brif set for 4K RAMs
	clr -2,x                        ; set strobe low
	bitb 2,x                        ; check input
	beq LA070                       ; brif set for 64K rams
	leau -2,u                       ; adjust pointer to set SAM for 16K RAMs
LA070           sta -3,u                        ; program SAM for either 16K or 64K RAMs
LA072           jmp ,y                          ; transfer control to startup routine
; Cold start jumps here
BACDST          ldx #VIDRAM+1                   ; point past the top of the first 1K of memory (for double predec below)
LA077           clr ,--x                        ; clear a byte (last will actually try clearing LSB of RESET vector in ROM)
                leax 1,x                        ; move forward one byte (will set Z if we're done)
                bne LA077                       ; brif not donw yet
                jsr LA928                       ; clear the screen
                clr ,x+                         ; put the constant zero that lives before the program
                stx TXTTAB                      ; set beginning of program storage
LA084           ldx #0x7fff                     ; set to of available RAM to just below the "ROM" area
                bra LA093
                nop
                nop
                nop
                nop
                nop
                nop
                nop
                nop
                nop
                nop
LA093           stx TOPRAM                      ; save top of memory (one below actual top because we need a byte for VAL() to work)
                stx MEMSIZ                      ; save top of string space
                stx STRTAB                      ; set bottom of allocated string space
                leax -200,x                     ; allocate 200 bytes of string space
                stx FRETOP                      ; set top of actually free memory
                tfr x,s                         ; put the stack there
                ldx #LA10D                      ; point to variable initializer
                ldu #CMPMID                     ; point to variables to initialize (first batch)
                ldb #28                         ; 28 bytes in first batch
                jsr LA59A                       ; copy bytes to variables
                ldu #IRQVEC                     ; point to variables to initialize (second batch)
                ldb #30                         ; 30 bytes this time
                jsr LA59A                       ; copy bytes to variables
                ldx -12,x                       ; get SN error address
                stx 3,u                         ; set ECB's command handlers to error
                stx 8,u
                ldx #RVEC0                      ; point to RAM vectors
                ldd #0x394b                     ; write 75 RTS opcodes (25 RAM vectors)
LA0C0           sta ,x+                         ; put an RTS
                decb                            ; done?
                bne LA0C0                       ; brif not
                sta LINHDR-1                    ; make temporary line header data for line encoding have a nonzero next line pointer
                jsr LAD19                       ; do a "NEW"
                jmp L8002                       ; transfer control to ECB's initialization routine
LA0CE           pshs b,x                        ; save registers
                tst HRWIDTH                     ; is it VDG mode?
                lbne ALINK24                    ; brif not
LA0D6           jsr LA199                       ; do a "cursor"
                jsr KEYIN                       ; read a key
                beq LA0D6                       ; brif no key
LA0DE           jmp LA1B9                       ; return to mainline
                fcb 0x72                        ; left-over from code replacement above
LA0E2           lda #0x55                       ; warm start valid flag
                sta RSTFLG                      ; mark warm start valid
                bra LA0F3                       ; go to direct mode
; Warm start entry point
BAWMST          nop                             ; valid routine marker
                clr DEVNUM                      ; reset output/input to screen
                jsr LAD33                       ; do a partial NEW
                andcc #0xaf                     ; start interrupts
                jsr CLS                         ; clear the screen
LA0F3           jmp LAC73                       ; go to direct mode
; FIRQ service routine - this handles starting autostart cartridges
BFRQSV          tst PIA1+3                      ; is it the cartridge interrupt?
                bmi LA0FC                       ; brif so
                rti
LA0FC           jsr L8C28                       ; map cartridge
                jsr LA7D1                       ; delay for another while
                leay <LA108,pcr                 ; point to cartridge starter
                jmp LA02A                       ; go initialize everything clean for the cartridge
LA108           clr RSTFLG                      ; force a cold start a cartridge reset
                jmp ROMPAK                      ; transfer control to the cartridge
; Variable initializers (first batch)
LA10D           fcb 18                          ; mid band partition of the 1200/2400 Hz period
                fcb 24                          ; upper limit of 1200 Hz period
                fcb 10                          ; upper limit of 2400 Hz period
                fdb 128                         ; number of 0x55s for cassette leader
                fcb 11                          ; cursor blink delay
                fdb 88                          ; 600 baud delay constant
                fdb 1                           ; printer carriage return delay constant
                fcb 16                          ; printer tab field width
                fcb 112                         ; last printer tab zone
                fcb 132                         ; printer carriage width
                fcb 0                           ; printer carriage position
                fdb LB44A                       ; default execution address for EXEC
                inc CHARAD+1                    ;* character fetching routines (DP portion) - we first do a two
                bne LA123                       ;* two stage increment of CHARAD then load the value into A
                inc CHARAD                      ;* before transferring control to the bottom half routine in ROM
LA123           lda >0                          ; NOTE: the 0 is a placeholder, extended addressing is required
                jmp BROMHK
; Variable initializers (second batch)
                jmp BIRQSV                      ; IRQ handler
                jmp BFRQSV                      ; FIRQ handler
                jmp LB44A                       ; default USR() address
                fcb 0x80,0x4f,0xc7,0x52,0x59    ; random seed
                fcb 0xff                        ; capslock flag - default to upper case
                fdb DEBDEL                      ; keyboard debounce delay (why is it a variable?)
                jmp LB277                       ; exponentiation handler vector
                fcb 53                          ; (command interpretation table) 53 commands
                fdb LAA66                       ; (command interpretation table) reserved words list (commands)
                fdb LAB67                       ; (command interpretation table) jump table (commands)
                fcb 20                          ; (command interpretation table) 20 functions
                fdb LAB1A                       ; (command interpretation table) reserved words list (functions)
                fdb LAA29                       ; (command interpretation table) jump table (functions)
; This is the signon message.
LA147           fcc 'COLOR BASIC 1.2'
                fcb 0x0d
                fcc '(C) 1982 TANDY'
                fcb 0
; This is the "invalid colour" CLS easter egg text. Basically 11 wasted bytes
LA166           fcc 'MICROSOFT'
                fcb 0x0d,0
; Read a character from current device and mask off bit 7 (keep it as 7 bit ASCII)
LA171           bsr LA176                       ; get character
                anda #0x7f                      ; mask off high bit
                rts
; Generic read routine. Reads a character from the device specified by DEVNUM. If no input was available,
; CINBFL will bet nonzero (on EOF). If input was available, CINBFL will be zero. Note that this routine
; has undefined results when called on an output only device. All registers except CC and A are preserved.
LA176           jsr RVEC4                       ; do RAM hook
                clr CINBFL                      ; flag data available
                tst DEVNUM                      ; is it keyboard?
                beq LA1B1                       ; brif so - blink cursor and wait for key press
                tst CINCTR                      ; is there anything in cassette input buffer?
                bne LA186                       ; brif so
                com CINBFL                      ; flag EOF
                rts
; Read character from cassette file
LA186           pshs u,y,x,b                    ; preserve registers
                ldx CINPTR                      ; get input buffer pointer
                lda ,x+                         ; get character from buffer
                pshs a                          ; save it for return
                stx CINPTR                      ; save new input buffer pointer
                dec CINCTR                      ; count character just consumed
                bne LA197                       ; brif buffer is not empty yet
                jsr LA635                       ; go read another block, if any, to refill the buffer
LA197           puls a,b,x,y,u,pc               ; restore registers and return the character
; Blink the cursor. This might be better timed via an interrupt or something.
LA199           dec BLKCNT                      ; is it time to blink the cursor?
                bne LA1AB                       ; brif not
                ldb #11                         ; reset blink timer
                stb BLKCNT
                ldx CURPOS                      ; get cursor position
                lda ,x                          ; get character at the cursor
                adda #0x10                      ; move to next color
                ora #0x8f                       ; make sure it's a grahpics block with all elements lit
                sta ,x                          ; put new cursor block on screen
LA1AB           ldx #DEBDEL                     ; we'll use the debounce delay for the cursor blink timer (10ms)
LA1AE           jmp LA7D3                       ; go count X down
; Blink cursor while waiting for a key press
LA1B1           pshs x,b                        ; save registers
LA1B3           bsr LA199                       ; go do a cursor iteration
                bsr KEYIN                       ; go read a key
                beq LA1B3                       ; brif no key pressed
LA1B9           ldb #0x60                       ; VDG screen space character
                stb [CURPOS]                    ; blank cursor out
                puls b,x,pc                     ; restore registers and return
; This is the actual keyboard polling routine. Returns 0 if no new key is down. Compared to the 1.0 and 1.1
; ROMs, this routine is quite a lot more compact and robust.
LA1C1           jmp KEYIN                       ; transfer control to actual keyboard scan
                rts                             ;* this actually removes a check to see if any keys are actually down
                rts                             ;* which is unfortunate because it makes programs run slower.
                rts
                rts
                rts
                rts
                rts
KEYIN           pshs u,x,b                      ; save registers
                ldu #PIA0                       ; point to keyboard PIA
                ldx #KEYBUF                     ; point to state table
                clra                            ; clear carry, set column to 0xff (no strobe)
                deca                            ; (note: deca does not affect C)
                pshs x,a                        ; save column counter and make a couple of holes for temporaries
                sta 2,u                         ; set strobe to no columns
LA1D9           rol 2,u                         ; move to next column (C is 0 initially, 1 after)
                bcc LA220                       ; brif we shifted out a 0 - we've done 8 columns
                inc 0,s                         ; bump column counter (first bump goes to 0)
                bsr LA23A                       ; read row data
                sta 1,s                         ; save key data (for debounce check and later saving)
                eora ,x                         ; now bits set if key state changed
                anda ,x                         ; now bits are only set if a key has been pressed
                ldb 1,s                         ; get new key data
                stb ,x+                         ; save in state table
                tsta                            ; was a key down?
                beq LA1D9                       ; brif not - do another (nothing above cleared C)
                ldb 2,u                         ; get strobe data
                stb 2,s                         ; save it for debounce check
                ldb #0xf8                       ; set up so B is 0 after first add
LA1F4           addb #8                         ; add 8 for each row
                lsra                            ; did we hit the right row?
                bcc LA1F4                       ; brif not
                addb 0,s                        ; add in column number
                beq LA245                       ; brif @
                cmpb #26                        ; letter?
                bhi LA247                       ; brif not
                orb #0x40                       ; bias into letter range
                bsr LA22E                       ; check for SHIFT
                ora CASFLG                      ; merge in capslock state
                bne LA20C                       ; brif either capslock or SHIFT - keep upper case
                orb #0x20                       ; move to lower case
LA20C           stb 0,s                         ; save ASCII value
                ldx DEBVAL                      ; get debounce delay
                bsr LA1AE                       ; do the 10ms debounce delay
                ldb #0xff                       ; set strobe to none - only joystick buttons register now
                bsr LA238                       ; read keyboard
                inca                            ; A now 0 if no buttons down
                bne LA220                       ; brif button down - return nothing since we have interference
LA21A           ldb 2,s                         ; get column strobe data
                bsr LA238                       ; read row data
                cmpa 1,s                        ; does it match original read?
LA220           puls a,x                        ; clean up stack and get return value
                bne LA22B                       ; brif failed debounce or a joystick button down
                cmpa #0x12                      ; is it SHIFT-0?
                bne LA22C                       ; brif not
                com CASFLG                      ; swap capslock state
LA22B           clra                            ; set no key down
LA22C           puls b,x,u,pc                   ; restore registers and return
LA22E           lda #0x7f                       ; column strobe for SHIFT
                sta 2,u                         ; set column
                lda ,u                          ; get row data
                coma                            ; set if key down
                anda #0x40                      ; only keep SHIFT state
                rts
LA238           stb 2,u                         ; save strobe data
LA23A           lda ,u                          ; get row data
                ora #0x80                       ; mask off comparator so it doesn't interfere
                tst 2,u                         ; are we on column 7?
                bmi LA244                       ; brif not
                ora #0xc0                       ; also mask off SHIFT
LA244           rts
LA245           ldb #51                         ; scan code for @
LA247           ldx #CONTAB-0x36                ; point to code table
                cmpb #33                        ; arrows, space, zero?
                blo LA264                       ; brif so
                ldx #CONTAB-0x54                ; adjust to other half of table
                cmpb #48                        ; ENTER, CLEAR, BREAK, @?
                bhs LA264                       ; brif so
                bsr LA22E                       ; read shift state
                cmpb #43                        ; is it a number, colon, semicolon?
                bls LA25D                       ; brif so
                eora #0x40                      ; invert shift state for others
LA25D           tsta                            ; shift down?
                bne LA20C                       ; brif not - return result
                addb #0x10                      ; add in offset to shifted character
                bra LA20C                       ; go return result
LA264           lslb                            ; two entries per key
                bsr LA22E                       ; check SHIFT state
                beq LA26A                       ; brif not shift
                incb                            ; point to shifted entry
LA26A           ldb b,x                         ; get actual key code
                bra LA20C                       ; go return result
CONTAB          fcb 0x5e,0x5f                   ; <UP> (^, _)
                fcb 0x0a,0x5b                   ; <DOWN> (LF, [)
                fcb 0x08,0x15                   ; <LEFT> (BS, ^U)
                fcb 0x09,0x5d                   ; <RIGHT> (TAB, ])
                fcb 0x20,0x20                   ; <SPACE>
                fcb 0x30,0x12                   ; <0> (0, ^R)
                fcb 0x0d,0x0d                   ; <ENTER> (CR, CR)
                fcb 0x0c,0x5c                   ; <CLEAR> (FF, \)
                fcb 0x03,0x03                   ; <BREAK> (^C, ^C)
                fcb 0x40,0x13                   ; <@> (@, ^S)
; Generic output routine.
; Output character in A to the device specified by DEVNUM. All registers are preserved except CC.
; Sending output to a device that does not support output is undefined.
PUTCHR          jsr RVEC3                       ; call RAM hook
                pshs b                          ; save B
                ldb DEVNUM                      ; get desired device number
                incb                            ; set flags (Z for -1, etc.)
                puls b                          ; restore B
                bmi LA2BF                       ; brif < -1 (line printer)
                bne LA30A                       ; brif > -1 (screen)
; Write character to tape file
                pshs x,b,a                      ; save registers
                ldb FILSTA                      ; get file status
                decb                            ; input file?
                beq LA2A6                       ; brif so
                ldb CINCTR                      ; get character count
                incb                            ; account for this character
                bne LA29E                       ; brif buffer not full
                bsr LA2A8                       ; write previously full block to tape
LA29E           ldx CINPTR                      ; get output buffer pointer
                sta ,x+                         ; put character in output
                stx CINPTR                      ; save new buffer pointer
                inc CINCTR                      ; account for this character
LA2A6           puls a,b,x,pc                   ; restore registers and return
; Write a block of data to tape.
LA2A8           ldb #1                          ; data block type
LA2AA           stb BLKTYP                      ; set block type
                ldx #CASBUF                     ; point to output buffer
                stx CBUFAD                      ; set buffer pointer
                ldb CINCTR                      ; get number of bytes in the block
                stb BLKLEN                      ; set length to write
                pshs u,y,a                      ; save registers
                jsr LA7E5                       ; write a block to tape
                puls a,y,u                      ; restore registers
                jmp LA650                       ; reset buffer pointers
; Send byte to line printer
LA2BF           pshs x,b,a,cc                   ; save registers and interrupt status
                orcc #0x50                      ; disable interrupts
LA2C3           ldb PIA1+2                      ; get RS232 status
                lsrb                            ; get status to C
                bcs LA2C3                       ; brif busy - loop until not busy
                bsr LA2FB                       ; set output to marking
                clrb                            ; transmit one start bit
                bsr LA2FD
                ldb #8                          ; counter for 8 bits
LA2D0           pshs b                          ; save bit count
                clrb                            ; zero output bits
                lsra                            ; bet output bit to C
                rolb                            ; get output bit to correct bit for output byte
                lslb
                bsr LA2FD                       ; transmit bit
                puls b                          ; get back bit counter
                decb                            ; are we done yet?
                bne LA2D0                       ; brif not
                bsr LA2FB                       ; send stop bit (marking)
                puls cc,a                       ; restore interrupt status and output character
                cmpa #0x0d                      ; carriage return?
                beq LA2ED                       ; brif so
                inc LPTPOS                      ; bump output position
                ldb LPTPOS                      ; get new position
                cmpb LPTWID                     ; end of line?
                blo LA2F3                       ; brif not
LA2ED           clr LPTPOS                      ; reset position to start of line
                bsr LA305                       ; do carriage return delay
                bsr LA305
LA2F3           ldb PIA1+2                      ; get RS232 status
                lsrb                            ; get status to C
                bcs LA2F3                       ; brif still busy, keep waiting
                puls b,x,pc                     ; restore registers and return
LA2FB           ldb #2                          ; set output to high (marking)
LA2FD           stb PIA1                        ; set RS232 output
                bsr LA302                       ; do baud delay (first iteration) then fall through for second
LA302           ldx LPTBTD                      ; get buard rate delay constant
                skip2
LA305           ldx LPTLND                      ; get carriage return delay constant
                jmp LA7D3                       ; count X down
; Output character to screen
LA30A           pshs x,b,a                      ; save registers
                ldx CURPOS                      ; get cursor pointer
LA30E           cmpa #0x08                      ; backspace?
                bne LA31D                       ; brif not
                cmpx #VIDRAM                    ; at top of screen?
                beq LA35D                       ; brif so - it's a no-op
                lda #0x60                       ; VDG space character
                sta ,-x                         ; put a space at previous location and move pointer back
                bra LA344                       ; save new cursor position and return
LA31D           cmpa #0x0d                      ; carriage return?
                bne LA32F                       ; brif not
                ldx CURPOS                      ; get cursor pointer (why? we already have it)
LA323           lda #0x60                       ; VDG space character
                sta ,x+                         ; put output space
                tfr x,d                         ; see if we at a multiple of 32 now
                bitb #0x1f
                bne LA323                       ; brif not
                bra LA344                       ; go check for scrolling
LA32F           cmpa #0x20                      ; control character?
                blo LA35D                       ; brif so
                tsta                            ; is it graphics block?
                bmi LA342                       ; brif so
                cmpa #0x40                      ; number or special?
                blo LA340                       ; brif so (flip "case" bit)
                cmpa #0x60                      ; upper case alpha?
                blo LA342                       ; brif so - keep it unmodified
                anda #0xdf                      ; clear bit 5 (inverse video)
LA340           eora #0x40                      ; flip inverse video bit
LA342           sta ,x+                         ; output character
LA344           stx CURPOS                      ; save new cursor position
                cmpx #VIDRAM+511                ; end of screen?
                bls LA35D                       ; brif not
                ldx #VIDRAM                     ; point to start of screen
LA34E           ldd 32,x                        ; get two characters from next row
                std ,x++                        ; put them on this row
                cmpx #VIDRAM+0x1e0              ; at start of last row on screen?
                blo LA34E                       ; brif not
                ldb #0x60                       ; VDG space
                jsr LA92D                       ; blank out last line (borrow CLS's loop)
LA35D           puls a,b,x,pc                   ; restore registers and return
; Set up device parameters for output
LA35F           jsr RVEC2                       ; do the RAM hook dance
                pshs x,b,a                      ; save registers
                clr PRTDEV                      ; flag device as a screen
                lda DEVNUM                      ; get devicenumber
                beq LA373                       ; brif screen
                inca                            ; is it tape?
                beq LA384                       ; brif so
                ldx LPTCFW                      ; get tab width and last tab stop for printer
                ldd LPTWID                      ; get line width and current position for printer
                bra LA37C                       ; set parameters
LA373           ldb CURPOS+1                    ; get LSB of cursor position
                andb #0x1f                      ; now we have the offset into the line
                ldx #0x1010                     ; 16 character tab, position 16 is last tab stop
                lda #32                         ; screen is 32 characters wide
LA37C           stx DEVCFW                      ; save tab width and last tab stop for active device
                stb DEVPOS                      ; save line position for current device
                sta DEVWID                      ; save line width for current device
                puls a,b,x,pc                   ; restore registers and return
LA384           com PRTDEV                      ; flag device as non-display
                ldx #0x0100                     ; tab width is 1, last tab field is 0
                clra                            ; line width is 0
                clrb                            ; character position on line is 0
                bra LA37C                       ; go set parameters
; This is the line input routine used for reading lines for Basic, both in immediate mode and for
; INPUT and LINE INPUT. Exit with C set if terminated by BREAK and C clear if terminated by ENTER.
; The actualy entry point is LA390. Note that this routine echoes to *all* devices.
LA38D           jsr LA928                       ; clear screen (CLEAR key handling)
LA390           jsr RVEC12                      ; do the RAM hook dance
                clr IKEYIM                      ; reset cached input character from BREAK check
                ldx #LINBUF+1                   ; point to line input buffer (input pointer)
                ldb #1                          ; Number of characters in line (we start at 1 so BS handling is easier)
LA39A           jsr LA171                       ; get an input character, only keep low 7 bits
                tst CINBFL                      ; is it EOF?
                bne LA3CC                       ; brif EOF
                tst DEVNUM                      ; is it keyboard input?
                bne LA3C8                       ; brif not - don't do line editing
                cmpa #0x0c                      ; form feed (CLEAR)?
                beq LA38D                       ; brif so - clear screen and reset
                cmpa #0x08                      ; backspace?
                bne LA3B4                       ; brif not
                decb                            ; move back one character
                beq LA390                       ; brif we were at the start of the line - reset and start again
                leax -1,x                       ; move input pointer back
                bra LA3E8                       ; echo the backspace and continue
LA3B4           cmpa #0x15                      ; SHIFT-LEFT (kill line)?
                bne LA3C2                       ; brif not
LA3B8           decb                            ; at start of line?
                beq LA390                       ; brif so - reset and restart
                lda #0x08                       ; echo a backspace
                jsr PUTCHR
                bra LA3B8                       ; see if we've erased everything yet
LA3C2           cmpa #0x03                      ; BREAK?
                orcc #1                         ; set C if it is (only need Z for the next test
LA3C6           beq LA3CD                       ; brif BREAK - exit
LA3C8           cmpa #0x0d                      ; ENTER (CR)
                bne LA3D9                       ; brif not
LA3CC           clra                            ; clear carry (it might not be clear on EOF)
LA3CD           pshs cc                         ; save ENTER/BREAK flag
                jsr LB958                       ; echo a carriage return
                clr ,x                          ; make sure we have a NUL at the end of the buffer
                ldx #LINBUF                     ; point to input buffer
                puls cc,pc                      ; restore ENTER/BREAK flag and return
LA3D9           cmpa #0x20                      ; control character?
                blo LA39A                       ; brif so - skip it
                cmpa #'z+1                      ; above z?
                bhs LA39A                       ; brif so - ignore it
                cmpb #LBUFMX                    ; is the buffer full?
                bhs LA39A                       ; brif so - ignore extra characters
                sta ,x+                         ; put character in the buffer
                incb                            ; bump character count
LA3E8           jsr PUTCHR                      ; echo character
                bra LA39A                       ; go handle next input character
; Check if DEVNUM Is valid for reading. Raise FM error if open but not for reading. NO error if not open.
LA3ED           jsr RVEC5                       ; do the RAM hook dance
                lda DEVNUM                      ; get device number
                beq LA415                       ; brif keyboard - always valid
                inca                            ; is it tape?
                bne LA403                       ; brif not
                lda FILSTA                      ; get tape file status
                bne LA400                       ; brif file is open
LA3FB           ldb #22*2                       ; raise NO error
                jmp LAC46
LA400           deca                            ; is it in input mode?
                beq LA415                       ; brif so
LA403           jmp LA616                       ; raise FM error
; Check if DEVNUM is valid for writing. Raise FM error if open but not for writing. NO error if not open.
LA406           jsr RVEC6                       ; do the RAM hook dance
                lda DEVNUM                      ; get device number
                inca                            ; is it tape?
                bne LA415                       ; brif not
                lda FILSTA                      ; get file status
                beq LA3FB                       ; brif not open
                deca                            ; is it open for reading?
                beq LA403                       ; brif so - bad mode
LA415           rts
; CLOSE command
CLOSE           beq LA426                       ; brif no file specified - close all files
                jsr LA5A5                       ; parse device number
LA41B           bsr LA42D                       ; close specified file
                jsr GETCCH                      ; is there more?
                beq LA44B                       ; brif not
                jsr LA5A2                       ; check for comma and parse another device number
                bra LA41B                       ; go close this one
; Close all files handler.
LA426           jsr RVEC7                       ; Yup. The RAM hook dance.
LA429           lda #-1                         ; start with tape file
                sta DEVNUM
; Close file specified in DEVNUM. Note that this never fails.
LA42D           jsr RVEC8                       ; You know it. RAM hook.
                lda DEVNUM                      ; get device we're closing
                clr DEVNUM                      ; reset to screen/keyboard
                inca                            ; is it tape?
                bne LA44B                       ; brif not
                lda FILSTA                      ; get file status
                cmpa #2                         ; is it output?
                bne LA449                       ; brif not
                lda CINCTR                      ; is there anything waiting to be written?
                beq LA444                       ; brif not
                jsr LA2A8                       ; write final block of data
LA444           ldb #0xff                       ; write EOF block
                jsr LA2AA
LA449           clr FILSTA                      ; mark tape file closed
LA44B           rts
; CSAVE command
CSAVE           jsr LA578                       ; parse filename
                jsr GETCCH                      ; see what we have after the file name
                beq LA469                       ; brif none
                jsr SYNCOMMA                    ; make sure there's a comma
                ldb #'A                         ; make sure there's an A after
                jsr LB26F
                bne LA44B                       ; brif not end of line
                clra                            ; file type 0 (basic program)
                jsr LA65C                       ; write out header block
                lda #-1                         ; set output to tape
                sta DEVNUM
                clra                            ; set Z so we list the whole program
                jmp LIST                        ; go list the program to tape
LA469           clra                            ; file type 0 (basic program)
                ldx ZERO                        ; set to binary file mode
                jsr LA65F                       ; write header block
                clr FILSTA                      ; close files
                inc BLKTYP                      ; set block type to data
                jsr WRLDR                       ; write out a leader
                ldx TXTTAB                      ; point to start of program
LA478           stx CBUFAD                      ; set buffer location
                lda #255                        ; block size to 255 bytes (max size)
                sta BLKLEN
                ldd VARTAB                      ; get end of program
                subd CBUFAD                     ; how much is left?
                beq LA491                       ; brif we have nothing left
                cmpd #255                       ; do we have a full block worth?
                bhs LA48C                       ; brif so
                stb BLKLEN                      ; save actual remainder as block length
LA48C           jsr SNDBLK                      ; write a block out
                bra LA478                       ; go do another block
LA491           neg BLKTYP                      ; set block type to 0xff (EOF)
                clr BLKLEN                      ; no data in EOF block
                jmp LA7E7                       ; write EOF, stop tape, and return
; CLOAD and CLOADM commands
CLOAD           clr FILSTA                      ; close tape file
                cmpa #'M                        ; is it ClOADM?
                beq LA4FE                       ; brif so
                leas 2,s                        ; clean up stack
                jsr LA5C5                       ; parse file name
                jsr LA648                       ; go find the file
                tst CASBUF+10                   ; is it binary?
                beq LA4C8                       ; brif so
                lda CASBUF+9                    ; is it ASCII?
                beq LA4CD                       ; brif not
                jsr LAD19                       ; clear out existing program
                lda #-1                         ; set up for reading from tape
                sta DEVNUM
                inc FILSTA                      ; set tape file to input
                jsr LA635                       ; go read first block
                jmp LAC7C                       ; go to immediate mode to read in the program
; This is the EOF handler for immediate mode. It's rather assinine for this to be located here. It is
; probably an artifact of a substantially different code layout prior to compacting the ROM to fit in
; 8K.
LA4BF           jsr RVEC13                      ; do the RAM hook dance
                jsr LA42D                       ; close file
                jmp LAC73                       ; go back to immediate mode
LA4C8           lda CASBUF+8                    ; get file type
                beq LA4D0                       ; brif basic program
LA4CD           jmp LA616                       ; raise FM error
LA4D0           jsr LAD19                       ; erase existing program
                jsr CASON                       ; start reading tape
                ldx TXTTAB                      ; get start of program storage
LA4D8           stx CBUFAD                      ; set load address for block
                ldd CBUFAD                      ; get start of block
                inca                            ; bump by 256
                jsr LAC37                       ; check if there's room for a maximum sized block of 255
                jsr GETBLK                      ; go read a block
                bne LA4F8                       ; brif there was an error during reading
                lda BLKTYP                      ; get type of block read
                beq LA4F8                       ; brif header block - IO error
                bpl LA4D8                       ; brif data block - read another
                stx VARTAB                      ; save new end of program
                bsr LA53B                       ; stop tape
                ldx #LABED-1                    ; point to "OK" prompt
                jsr STRINOUT                    ; show prompt
                jmp LACE9                       ; reset various things and return
LA4F8           jsr LAD19                       ; clear out partial program load
LA4FB           jmp LA619                       ; raise IO error
; This is the CLOADM command
LA4FE           jsr GETNCH                      ; eat the "M"
                bsr LA578                       ; parse file name
                jsr LA648                       ; go find the file
LA505           ldx ZERO                        ; default offset is 0
                jsr GETCCH                      ; see if there's something after the file name
                beq LA511                       ; brif no offset
                jsr SYNCOMMA                    ; make sure there's a comma
                jsr LB73D                       ; evaluate offset to X
LA511           lda CASBUF+8                    ; get file mode
                cmpa #2                         ; M/L program?
                bne LA4CD                       ; brif not - FM error
                ldd CASBUF+11                   ; get load address
                leau D,x                        ; add in offset
                stu EXECJP                      ; set EXEC default address
                tst CASBUF+10                   ; is it binary?
                bne LA4CD                       ; brif not
                ldd CASBUF+13                   ; get load address
                leax d,x                        ; add in offset
                stx CBUFAD                      ; set buffer address for loading
                jsr CASON                       ; start up tape
LA52E           jsr GETBLK                      ; read a block
                bne LA4FB                       ; brif error reading
                stx CBUFAD                      ; save new load address
                tst BLKTYP                      ; set flags on block type
                beq LA4FB                       ; brif another header - IO error
                bpl LA52E                       ; brif it was data - read more
LA53B           jmp LA7E9                       ; turn off tape and return
; The EXEC command
EXEC            beq LA545                       ; brif no argument - use default address
                jsr LB73D                       ; evaluate EXEC address to X
                stx EXECJP                      ; set new default EXEC address
LA545           jmp [EXECJP]                    ; transfer control to execution address
; Break check for LIST so it doesn't interrupt ASCII saves. Why is this here instead of with the rest of the break
; check logic or packaged up with LIST?
LA549           jsr RVEC11                      ; do the RAM hook dance
                lda DEVNUM                      ; get device number
                inca                            ; is it tape?
                beq LA5A1                       ; brif so - don't do break check
                jmp LADEB                       ; do the actual break check
; Evaluate an expression and make sure it is within the limits of the screen and sets the cursor position.
; This really should be located with the PRINT command.
LA554           jsr LB3E4                       ; evaluate a positive expression to D
                subd #511                       ; is it within bounds?
                lbhi LB44A                      ; brif not - error out
                addd #VIDRAM+511                ; adjust to be within the screen (and undo the SUBD above)
                std CURPOS                      ; set cursor position
                rts
; INKEY$ function
INKEY           lda IKEYIM                      ; was a key down during break check?
                bne LA56B                       ; brif so
                jsr KEYIN                       ; poll the keyboard
LA56B           clr IKEYIM                      ; reset the break check cache
                sta FPA0+3                      ; store result for later return
                lbne LB68F                      ; brif a key was down - return it as a string
                sta STRDES                      ; set string length to 0 (no key down)
                jmp LB69B                       ; return the NULL string
; Parse a filename
LA578           ldx #CFNBUF                     ; point to file name buffer
                clr ,x+                         ; zero out file name length
                lda #0x20                       ; space character to initialize file name
LA57F           sta ,x+                         ; put a space in the buffer
                cmpx #CASBUF                    ; at end of file name?
                bne LA57F                       ; brif not
                jsr GETCCH                      ; get input character
                beq LA5A1                       ; brif no name present
                jsr LB156                       ; evaluate the file name expression
                jsr LB654                       ; point to start of the file name
                ldu #CFNBUF                     ; point to file name buffer
                stb ,u+                         ; save string length
                beq LA5A1                       ; brif empty - we're done
                skip2
LA598           ldb #8                          ; copy 8 bytes
; Move B bytes from (X) to (U)
LA59A           lda ,x+                         ; copy a byte
                sta ,u+
                decb                            ; done yet?
                bne LA59A                       ; brif not
LA5A1           rts
; Parse a device number and check validity
LA5A2           jsr SYNCOMMA                    ; check for comma and SN error if not
LA5A5           cmpa #'#                        ; do we have a #?
                bne LA5AB                       ; brif not (it's optional)
                jsr GETNCH                      ; munch the #
LA5AB           jsr LB141                       ; evaluate the expression
LA5AE           jsr INTCNV                      ; convert it to an integer in D
                rolb                            ; move sign of B into C
                adca #0                         ; add sign of B to A
                bne LA61F                       ; brif A doesn't match the sign of B
                rorb                            ; restore B (ADCA will have set C if B was negative)
                stb DEVNUM                      ; set device number
                jsr RVEC1                       ; do the RAM hook dance
                beq LA5C4                       ; brif device number set to screen/keyboard (valid)
                bpl LA61F                       ; brif not negative (not valid)
                cmpb #-2                        ; is it printer or tape?
                blt LA61F                       ; brif not (not valid)
LA5C4           rts
; Read file name from the line and do an error if anything follows it
LA5C5           bsr LA578                       ; parse file name
LA5C7           jsr GETCCH                      ; set flags on current character
LA5C9           beq LA5C4                       ; brif nothing there - it's good
                jmp LB277                       ; raise SN error
; EOF function
EOF             jsr RVEC14                      ; do the RAM hook dance
                lda DEVNUM                      ; get device number
                pshs a                          ; save it (so we can restore it later)
                bsr LA5AE                       ; check the device number (which is in FPA0)
                jsr LA3ED                       ; check validity for reading
LA5DA           clrb                            ; not EOF = 0 (FALSE)
                lda DEVNUM                      ; get device number
                beq LA5E4                       ; brif keyboard - never EOF
                tst CINCTR                      ; is there anything in the input buffer?
                bne LA5E4                       ; brif so - not EOF
                comb                            ; set EOF flag to -1 (true)
LA5E4           puls a                          ; get back original device
                sta DEVNUM                      ; restore it
LA5E8           sex                             ; sign extend result to 16 bits
                jmp GIVABF                      ; go return the result
; SKIPF command
SKIPF           bsr LA5C5                       ; parse file name
                bsr LA648                       ; look for the file
                jsr LA6D1                       ; read the file
                bne LA619                       ; brif error reading file
                rts
; OPEN command
OPEN            jsr RVEC0                       ; do the RAM hook dance
                jsr LB156                       ; get file status (input/output)
                jsr LB6A4                       ; get first character of status string
                pshs b                          ; save status
                bsr LA5A2                       ; parse a comma then the device number
                jsr SYNCOMMA                    ; make sure there's a comma
                bsr LA5C5                       ; parse the file name
                lda DEVNUM                      ; get device number of the file
                clr DEVNUM                      ; reset actual device to the screen
                puls b                          ; get back status
                cmpb #'I                        ; INPUT?
                beq LA624                       ; brif so - open a file for INPUT
                cmpb #'O                        ; OUTPUT?
                beq LA658                       ; brif so - open a file for OUTPUT
LA616           ldb #21*2                       ; raise FM error
                skip2
LA619           ldb #20*2                       ; raise I/O error
                skip2
LA61C           ldb #18*2                       ; raise AO error
                skip2
LA61F           ldb #19*2                       ; raise DN error
                jmp LAC46
LA624           inca                            ; are we opening the tape?
                bmi LA616                       ; brif printer - FM error; printer can't be opened for READ
                bne LA657                       ; brif screen - screen is always open
                bsr LA648                       ; read header block
                lda CASBUF+9                    ; clear A if binary or machine language file
                anda CASBUF+10
                beq LA616                       ; bad file mode if not data file
                inc FILSTA                      ; open file for input
LA635           jsr LA701                       ; start tape, read block           
                bne LA619                       ; brif error during read
                tst BLKTYP                      ; check block type
                beq LA619                       ; brif header block - something's wrong
                bmi LA657                       ; brif EOF
                lda BLKLEN                      ; get length of block
                beq LA635                       ; brif empty block - read another
LA644           sta CINCTR                      ; set buffer count
                bra LA652                       ; reset buffer pointer
LA648           tst FILSTA                      ; is the file open?
                bne LA61C                       ; brif so - AO error
                bsr LA681                       ; search for file
                bne LA619                       ; brif error on read
LA650           clr CINCTR                      ; mark buffer empty
LA652           ldx #CASBUF                     ; set buffer pointer to start of buffer
                stx CINPTR
LA657           rts
LA658           inca                            ; check for tape device
                bne LA657                       ; brif not tape (nothing doing - it's always open)
                inca                            ; make file type 1
LA65C           ldx #0xffff                     ; ASCII and data mode
LA65F           tst FILSTA                      ; is file open?
                bne LA61C                       ; brif so - raise error
                ldu #CASBUF                     ; point to tape buffer
                stu CBUFAD                      ; set address of block to write
                sta 8,u                         ; set file type
                stx 9,u                         ; set ASCII flag and mode
                ldx #CFNBUF+1                   ; point to file name
                jsr LA598                       ; move file name to the tape buffer
                clr BLKTYP                      ; set for header block
                lda #15                         ; 15 bytes in a header block
                sta BLKLEN                      ; set block length
                jsr LA7E5                       ; write the block
                lda #2                          ; set file type to output
                sta FILSTA
                bra LA650                       ; reset file pointers
; Search for correct cassette file name
LA681           ldx #CASBUF                     ; point to cassette buffer
                stx CBUFAD                      ; set location to read blocks to
LA686           lda CURLIN                      ; are we in immediate mode?
                inca
                bne LA696                       ; brif not
                jsr LA928                       ; clear screen
                ldx CURPOS                      ; get start of screen (set after clear)
                ldb #'S                         ; for "searching"
                stb ,x++                        ; put it on the screen
                stx CURPOS                      ; save cursor position to be one past the search indicator
LA696           bsr LA701                       ; read a block
                orb BLKTYP                      ; merge error flag with block type
                bne LA6D0                       ; brif error or not header
                ldx #CASBUF                     ; point to block just read
                ldu #CFNBUF+1                   ; point to the desired name
                ldb #8                          ; compare 8 characters
                clr ,-s                         ; set flag to "match"
LA6A6           lda ,x+                         ; get character from just read block
                ldy CURLIN                      ; immediate mode?
                leay 1,y
                bne LA6B4                       ; brif not
                clr DEVNUM                      ; set output to screen
                jsr PUTCHR                      ; display character
LA6B4           suba ,u+                        ; subtract from desired file name (nonzero if no match)
                ora ,s                          ; merge with match flag
                sta ,s                          ; save new match flag (will be nonzero if any character differs)
                decb                            ; done all characters?
                bne LA6A6                       ; brif not - do another
                lda ,s+                         ; get match flag (and set flags)
                beq LA6CB                       ; brif we have a match
                tst -9,u                        ; did we actually have a file name or will any file do?
                beq LA6CB                       ; brif any file will do
                bsr LA6D1                       ; go read past the file
                bne LA6D0                       ; return on error
                bra LA686                       ; keep looking
LA6CB           lda #'F                         ; for "found"
                bsr LA6F8                       ; put "F" on screen
                clra                            ; set Z to indicat eno errors
LA6D0           rts
LA6D1           tst CASBUF+10                   ; check type of file
                bne LA6DF                       ; brif "blocked" file
                jsr CASON                       ; turn on tape
LA6D9           bsr GETBLK                      ; read a block
                bsr LA6E5                       ; error or EOF?
                bra LA6D9                       ; read another block
LA6DF           bsr LA701                       ; read a single block
                bsr LA6E5                       ; error or EOF?
                bra LA6DF                       ; read another block
LA6E5           bne LA6ED                       ; got error reading block
                lda BLKTYP                      ; check block type
                nega                            ; A is 0 now if EOF
                bmi LA700                       ; brif not end of file
                deca                            ; clear error indicator
LA6ED           sta CSRERR                      ; set error flag
                leas 2,s                        ; don't return to original caller
                bra LA705                       ; turn off motor and return
LA6F3           lda VIDRAM                      ; get first char on screen
                eora #0x40                      ; flip case
LA6F8           ldb CURLIN                      ; immediate mode?
                incb
                bne LA700                       ; brif not
                sta VIDRAM                      ; save flipped case character
LA700           rts
; Read a single block from tape (for a "blocked" file)
LA701           bsr CASON                       ; start tape going
                bsr GETBLK                      ; read block
LA705           jsr LA7E9                       ; stop tape
                ldb CSRERR                      ; get error status
                rts
; Read a block from tape - this does the heavy lifting
GETBLK          orcc #0x50                      ; disable interrupts (timing is important)
                bsr LA6F3                       ; reverse video of upper left character in direct mode
                ldx CBUFAD                      ; point to destination buffer
                clra                            ; reset read byte
LA712           bsr LA755                       ; read a bit
                rora                            ; move bit into accumulator
                cmpa #0x3c                      ; have we synched on the start of the block data yet?
                bne LA712                       ; brif not
                bsr LA749                       ; read block type
                sta BLKTYP
                bsr LA749                       ; get block size
                sta BLKLEN
                adda BLKTYP                     ; accumulate checksum
                sta CCKSUM                      ; save current checksum
                lda BLKLEN                      ; get back count
                sta CSRERR                      ; initialize counter; we use this since it will be ovewritten later anyway
                beq LA73B                       ; brif empty block
LA72B           bsr LA749                       ; read a byte
                sta ,x                          ; save in buffer
                cmpa ,x+                        ; make sure it wrote
                bne LA744                       ; brif error if it didn't match
                adda CCKSUM                     ; accumulate checksum
                sta CCKSUM
                dec CSRERR                      ; read all bytes?
                bne LA72B                       ; brif not
LA73B           bsr LA749                       ; read checksum from tape
                suba CCKSUM                     ; does it match?
                beq LA746                       ; brif so
                lda #1                          ; checksum error flag
                skip2
LA744           lda #2                          ; non-RAM error flag
LA746           sta CSRERR                      ; save error status
                rts
LA749           lda #8                          ; read 8 bits
                sta CPULWD                      ; initialize counter
LA74D           bsr LA755                       ; read a bit
                rora                            ; put it into accumulator
                dec CPULWD                      ; got all 8 bits?
                bne LA74D                       ; brif not
                rts
LA755           bsr LA75D                       ; get time between transitions
                ldb CPERTM                      ; get timer
                decb
                cmpb CMPMID                     ; set C if timer is below the transition point - high or 1; clear otherwise
                rts
LA75D           clr CPERTM                      ; reset timer
                tst CBTPHA                      ; check which phase we synched on
                bne LA773                       ; brif HI-LO synch
LA763           bsr LA76C                       ; read input
                bcs LA763                       ; brif still high
LA767           bsr LA76C                       ; read input
                bcc LA767                       ; brif still low
                rts
LA76C           inc CPERTM                      ; bump timer
                ldb PIA1                        ; get input bit to C
                rorb
                rts
LA773           bsr LA76C                       ; read input
                bcc LA773                       ; brif still low
LA777           bsr LA76C                       ; read output
                bcs LA777                       ; brif still high
                rts
; Start tape and look for sync bytes
CASON           orcc #0x50                      ; disable interrupts
                bsr LA7CA                       ; turn on tape
                clr CPULWD                      ; reset timer
LA782           bsr LA763                       ; wait for low-high transition
LA784           bsr LA7AD                       ; wait for it to go low again
                bhi LA797                       ; brif in range for 1200 Hz
LA788           bsr LA7A7                       ; wait for it to go high again
                blo LA79B                       ; brif in range for 2400 Hz
                dec CPULWD                      ; decrement counter (synched on low-high)
                lda CPULWD                      ; get counter
                cmpa #-96                       ; have we seen 96 1-0-1-0 patterns (48 0x55s)?
LA792           bne LA782                       ; brif not - wait some more
                sta CBTPHA                      ; save phase we synched on
                rts
LA797           bsr LA7A7                       ; wait for it to go high again
                bhi LA784                       ; brif another 1200 Hz, 2 in a row, try again
LA79B           bsr LA7AD                       ; wait for it to go low again
                blo LA788                       ; brif another 2400 Hz; go try again for high
                inc CPULWD                      ; bump counter
                lda CPULWD                      ; get counter
                suba #96                        ; set 0 if we've seen enought 0-1-0-1 patterns (0xaa)
                bra LA792                       ; set phase and return or keep waiting
LA7A7           clr CPERTM                      ; reset period timer
                bsr LA767                       ; wait for high
                bra LA7B1                       ; set flags on result
LA7AD           clr CPERTM                      ; reset period timer
                bsr LA777                       ; wait for low
LA7B1           ldb CPERTM                      ; get period count
                cmpb CMP0                       ; is it too long for 1200Hz?
                bhi LA7BA                       ; brif so - reset counts
                cmpb CMP1                       ; set C if 2400Hz, clear C if 1200 Hz
                rts
LA7BA           clr CPULWD                      ; reset sync counter (too slow or drop out)
                rts
; MOTOR command
MOTOR           tfr a,b                         ; save ON/OFF
                jsr GETNCH                      ; eat the ON/OFF token
                cmpb #0xaa                      ; OFF?
                beq LA7E9                       ; brif so - turn off tape
                cmpb #0x88                      ; ON?
                jsr LA5C9                       ; SN error if no match
; Turn on tape
LA7CA           lda PIA1+1                      ; get motor control value
                ora #8                          ; turn on bit 3 (starts motor)
                bsr LA7F0                       ; put it back (dumb but it saves a byte)
LA7D1           ldx ZERO                        ; maximum delay timer
LA7D3           leax -1,x                       ; count down
                bne LA7D3                       ; brif not at 0 yet
                rts
; Write a synch leader to tape
WRLDR           orcc #0x50                      ; disable interrupts
                bsr LA7CA                       ; turn on tape
                ldx SYNCLN                      ; get count of 0x55s to write
LA7DE           bsr LA828                       ; write a 0x55
                leax -1,x                       ; done?
                bne LA7DE                       ; brif not
                rts
; Write sync bytes and a block, then stop tape
LA7E5           bsr WRLDR                       ; write sync
LA7E7           bsr SNDBLK                      ; write block
; Turn off tape
LA7E9           andcc #0xaf                     ; enable interrupts
                lda PIA1+1                      ; get control register
                anda #0xf7                      ; disable motor bit
LA7F0           sta PIA1+1                      ; set motor enable bit
                rts
; Write a block to tape.
SNDBLK          orcc #0x50                      ; disable interrupts
                ldb BLKLEN                      ; get block size
                stb CSRERR                      ; initialize character counter
                lda BLKLEN                      ; initialize checksum
                beq LA805                       ; brif empty block
                ldx CBUFAD                      ; point to tape buffer
LA800           adda ,x+                        ; accumulate checksum
                decb                            ; end of block data?
                bne LA800                       ; brif not
LA805           adda BLKTYP                     ; accumulate block type into checksum
                sta CCKSUM                      ; save calculated checksum
                ldx CBUFAD                      ; point to buffer
                bsr LA828                       ; send a 0x55
                lda #0x3c                       ; and then a 0x3c
                bsr LA82A
                lda BLKTYP                      ; send block type
                bsr LA82A
                lda BLKLEN                      ; send block size
                bsr LA82A
                tsta                            ; empty block?
                beq LA824                       ; brif so
LA81C           lda ,x+                         ; send character from block data
                bsr LA82A
                dec CSRERR                      ; are we done yet?
                bne LA81C                       ; brif not
LA824           lda CCKSUM                      ; send checksum
                bsr LA82A
LA828           lda #0x55                       ; send a 0x55
LA82A           pshs a                          ; save output byte
                ldb #1                          ; initialize bit probe
LA82E           lda CLSTSN                      ; get ending value of last cycle
                sta PIA1                        ; set DA
                ldy #LA85C                      ; point to sine wave table
                bitb ,s                         ; is bit set?
                bne LA848                       ; brif so - do high frequency
LA83B           lda ,y+                         ; get next sample (use all for low frequency)
                cmpy #LA85C+36                  ; end of table?
                beq LA855                       ; brif so
                sta PIA1                        ; set output sample
                bra LA83B                       ; do another sample
LA848           lda ,y++                        ; get next sample (use every other for high frequency)
                cmpy #LA85C+36                  ; end of table?
                beq LA855                       ; brif so
                sta PIA1                        ; send output sample
                bra LA848                       ; do another sample
LA855           sta CLSTSN                      ; save last sample that *would* have been sent
                lslb                            ; shift mask to next bit
                bcc LA82E                       ; brif not done all 8 bits
                puls a,pc                       ; get back original character and return
; This is the sample table for the tape sine wave
LA85C           fcb 0x82,0x92,0xaa,0xba,0xca,0xda
                fcb 0xea,0xf2,0xfa,0xfa,0xfa,0xf2
                fcb 0xea,0xda,0xca,0xba,0xaa,0x92
                fcb 0x7a,0x6a,0x52,0x42,0x32,0x22
                fcb 0x12,0x0a,0x02,0x02,0x02,0x0a
                fcb 0x12,0x22,0x32,0x42,0x52,0x6a
; SET command
SET             bsr LA8C1                       ; get absolute screen position of graphics block
                pshs x                          ; save character location
                jsr LB738                       ; evaluate comma then expression in B
                puls x                          ; get back character pointer
                cmpb #8                         ; valid colour?
                bhi LA8D5                       ; brif not
                decb                            ; normalize colours
                bmi LA895                       ; brif colour 0 (use current colour)
                lda #0x10                       ; 16 patterns per colour
                mul
                bra LA89D                       ; go save the colour
LA895           ldb ,x                          ; get current value
                bpl LA89C                       ; brif not grahpic
                andb #0x70                      ; keep only the colour
                skip1
LA89C           clrb                            ; reset block to all black
LA89D           pshs b                          ; save colour
                bsr LA90D                       ; force a )
                lda ,x                          ; get current screen value
                bmi LA8A6                       ; brif graphic block already
                clra                            ; force all pixels off
LA8A6           anda #0x0f                      ; keep only pixel data
                ora GRBLOK                      ; set the desired pixel
                ora ,s+                         ; merge with desired colour
LA8AC           ora #0x80                       ; force it to be a graphic block
                sta ,x                          ; put new block on screen
                rts
; RESET command
RESET           bsr LA8C1                       ; get address of desired block
                bsr LA90D                       ; force a )
                clra                            ; zero block (no pixels)
                ldb ,x                          ; is it graphics?
                bpl LA8AC                       ; brif not - just blank the block
                com GRBLOK                      ; invert pixel data
                andb GRBLOK                     ; turn off the desired pixel
                stb ,x                          ; put new pixel data on screen
                rts
; Parse SET/RESET/POINT coordinates except for closing )
LA8C1           jsr LB26A                       ; make sure it starts with (
LA8C4           jsr RVEC21                      ; do the RAM hook dance
                jsr EVALEXPB                    ; get first coordinate
                cmpb #63                        ; valid horizontal coordinate
                bhi LA8D5                       ; brif out of range
                pshs b                          ; save horizontal coordinate
                jsr LB738                       ; look for , followed by vertical coordinate
                cmpb #31                        ; in range for vertical?
LA8D5           bhi LA948                       ; brif not
                pshs b                          ; save vertical coordinate
                lsrb                            ; divide by two (two blocks per row)
                lda #32                         ; 32 bytes per row
                mul                             ; now we have the offset into video RAM
                ldx #VIDRAM                     ; point to start of screen
                leax d,x                        ; now X points to the correct character row
                ldb 1,s                         ; get horizontal coordinate
                lsrb                            ; divide by two (two per character cell)
                abx                             ; now we're pointing to the correct character cell
                puls a,b                        ; get back coordinates (vertical in A)
                anda #1                         ; keep only row offset of vertical
                rorb                            ; get column offset of horizontal to C
                rola                            ; now we have "row * 2 + col" in A
                ldb #0x10                       ; make a bit mask (one bit left of first pixel)
LA8EE           lsrb                            ; move mask right
                deca                            ; at the right pixel?
                bpl LA8EE                       ; brif not
                stb GRBLOK                      ; save graphics block mask
                rts
; POINT function
POINT           bsr LA8C4                       ; evaluate coordinates
                ldb #0xff                       ; default colour value is -1 (not graphics)
                lda ,x                          ; get character
                bpl LA90A                       ; brif not graphics
                anda GRBLOK                     ; is desired pixel set?
                beq LA909                       ; brif not - return 0 for "black"
                ldb ,x                          ; get graphics data
                lsrb                            ; shift right 4 to get colour in low bits
                lsrb
                lsrb
                lsrb
                andb #7                         ; lose the graphics block bias
LA909           incb                            ; shift colours into 1 to 8 range
LA90A           jsr LA5E8                       ; convert B to floating point
LA90D           jmp LB267                       ; make sure we have a ) and return
; CLS command
CLS             jsr RVEC22                      ; do the RAM hook dance
LA913           beq LA928                       ; brif no colour - just do a basic screen clear
                jsr EVALEXPB                    ; evaluate colour number
                cmpb #8                         ; valid colour?
                bhi LA937                       ; brif not - do the easter egg
                tstb                            ; color 0?
                beq LA925                       ; brif so
                decb                            ; normalize to 0 based colour numbers
                lda #0x10                       ; 16 blocks per colour
                mul                             ; now we have the base code for that colour
                orb #0x0f                       ; set all pixels
LA925           orb #0x80                       ; make it a graphics block
                skip2
LA928           ldb #0x60                       ; VDG screen space character
                ldx #VIDRAM                     ; point to start of screen
LA92D           stx CURPOS                      ; set cursor position
LA92F           stb ,x+                         ; blank a character
                cmpx #VIDRAM+511                ; end of screen?
                bls LA92F                       ; brif not
                rts
LA937           bsr LA928                       ; clear te screen
                ldx #LA166-1                    ; point to the easter egg
                jmp STRINOUT                    ; go display it
; Evaluate an expression to B, prefixed by a comma, and do FC error if 0
LA93F           jsr SYNCOMMA                    ; force a comma
LA942           jsr EVALEXPB                    ; evaluate expression to B
                tstb                            ; is it 0?
                bne LA984                       ; brif not - return
LA948           jmp LB44A                       ; raise FC error
; SOUND command
SOUND           bsr LA942                       ; evaluate frequency
                stb SNDTON                      ; save it
                bsr LA93F                       ; evaluate duration (after a comma)
LA951           lda #4                          ; constant factor for duration (each increment is 1/15 of a second)
                mul
                std SNDDUR                      ; save length of sound (IRQ will count it down)
                lda PIA0+3                      ; enable 60 Hz interrupt
                ora #1
                sta PIA0+3
                clr ARYDIS                      ; clear array disable flag for some reason
                bsr LA9A2                       ; connect DAC to MUX output
                bsr LA976                       ; turn on sound
LA964           bsr LA985                       ; store mid range output value and delay
                lda #0xfe                       ; store high value and delay
                bsr LA987
                bsr LA985                       ; store mid range value and delay
                lda #2                          ; store low value and delay
                bsr LA987
                ldx SNDDUR                      ; has timer expired?
                bne LA964                       ; brif not, do another wave
; Disable sound output
LA974           clra                            ; bit 3 to 0 will disable output
                skip2
; Enable sound output
LA976           lda #8                          ; bit 3 set to enable output
                sta ,-s                         ; save desired value
                lda PIA1+3                      ; get control register value
                anda #0xf7                      ; reset value
                ora ,s+                         ; set to desired value
                sta PIA1+3                      ; set new sound output status
LA984           rts
LA985           lda #0x7e                       ; mid range value for DAC
LA987           sta PIA1                        ; set DAC output value
                lda SNDTON                      ; get frequency
LA98C           inca                            ; increment it (gives shorter count with higher values, so higher frequencies work)
                bne LA98C                       ; brif not done yet
                rts
; AUDIO command
AUDIO           tfr a,b                         ; save ON/OFF token
                jsr GETNCH                      ; munch the ON/OFF token
                cmpb #0xaa                      ; OFF?
                beq LA974                       ; brif so
                subb #0x88                      ; ON?
                jsr LA5C9                       ; do SN error if not
                incb                            ; now B is 1 - cassette sound source
                bsr LA9A2                       ; set MUX input to tape
                bra LA976                       ; enable sound
; Set MUX source to value in B
LA9A2           ldu #PIA0+1                     ; point to PIA0 control register A
                bsr LA9A7                       ; program bit 0 then fall through for bit 1
LA9A7           lda ,u                          ; get control register value
                anda #0xf7                      ; reset mux control bit
                asrb                            ; shift desired value to C
                bcc LA9B0                       ; brif this bit is clear
                ora #8                          ; set the bit
LA9B0           sta ,u++                        ; set register value and move to next register
                rts
; IRQ service routine
BIRQSV          lda PIA0+3                      ; check for VSYNC interrupt
                bpl LA9C5                       ; brif not - return. BUG: should clear HSYNC interrupt status first
                lda PIA0+2                      ; clear VSYNC interrupt status
LA9BB           ldx >SNDDUR                     ; are we counting down for SOUND? (force extended in case DP is modified)
                beq LA9C5                       ; brif not
                leax -1,x                       ; count down one tick
                stx >SNDDUR                     ; save new count (forced extended in case DP is modified)
LA9C5           rti
; JOYSTK function
JOYSTK          jsr LB70E                       ; evaluate which joystick axis is desired
                cmpb #3                         ; valid axis?
                lbhi LB44A                      ; brif not
                tstb                            ; want axis 0?
                bne LA9D4                       ; brif not
                bsr GETJOY                      ; read axis data if axis 0
LA9D4           ldx #POTVAL                     ; point to axis values
                ldb FPA0+3                      ; get desired axis
                ldb b,x                         ; get axis value
                jmp LB4F3                       ; return value
; Read all four joystick axes. Note that this routine will try 10 times to get a value that matches
; the value obtained during the *previous call to this routine*. Thus, if the axis value has changed,
; this routine will do the read *ten times* before just returning the last value. This is assininely
; slow and probably a bug since it seems more logical to look for two matching reads in a row. Note
; also that this routine should be using PSHS and PULS but it doesn't.
GETJOY          bsr LA974                       ; turn off sound
                ldx #POTVAL+4                   ; point to the end of the axis data (we'll work backwards)
                ldb #3                          ; start with axis 3
LA9E5           lda #10                         ; 10 tries to see if we match *the last call* to this routine
                std ,--s                        ; save retry counter and axis number
                bsr LA9A2                       ; set MUX for the correct axis
LA9EB           ldd #0x4080                     ; set initial trial value to mid range and the next difference to add/subtract to half
LA9EE           sta ,-s                         ; store the add/subtract value
                orb #2                          ; keep rs232 output marking
                stb PIA1                        ; set DAC output to the trial value
                eorb #2                         ; remove RS232 output value
                lda PIA0                        ; read the comparator
                bmi LA9FF                       ; brif comparator output is high (DAC is lower than the axis value)
                subb ,s                         ; subtract next bit value (split the difference toward 0)
                skip2
LA9FF           addb ,s                         ; add next bit value (split the different toward infinity)
                lda ,s+                         ; get bit value back
                lsra                            ; cut in half
                cmpa #1                         ; have we done that last value for the DAC?
                bne LA9EE                       ; brif not
                lsrb                            ; normalize the axis value
                lsrb
                cmpb -1,x                       ; does it match the read from the last call to this routine?
                beq LAA12                       ; brif so
                dec ,s                          ; are we out of retries?
                bne LA9EB                       ; brif not - try again
LAA12           stb ,-x                         ; save new value and move pointer back
                ldd ,s++                        ; get axis counter and clean up retry counter
                decb                            ; move to next axis
                bpl LA9E5                       ; brif still more axes to do
                rts
; This is the "bottom half" of the character fetching routines.
BROMHK          cmpa #'9+1                      ; is it >= colon?
                bhs LAA28                       ; brif so Z set if colon, C clear.
                cmpa #0x20                      ; space?
                bne LAA24                       ; brif not
                jmp GETNCH                      ; move on to another character if space
LAA24           suba #'0                        ; normalize ascii digit to 0-9; we already handled above digit 9
                suba #-'0                       ; this will cause a carry for any value that was already positive
LAA28           rts
; Jump table for functions
LAA29           fdb SGN                         ; SGN 0x80
                fdb INT                         ; INT 0x81
                fdb ABS                         ; ABS 0x82
                fdb USRJMP                      ; USR 0x83
                fdb RND                         ; RND 0x84
                fdb SIN                         ; SIN 0x85
                fdb PEEK                        ; PEEK 0x86
                fdb LEN                         ; LEN 0x87
                fdb STR                         ; STR$ 0x88
                fdb VAL                         ; VAL 0x89
                fdb ASC                         ; ASC 0x8a
                fdb CHR                         ; CHR$ 0x8b
                fdb EOF                         ; EOF 0x8c
                fdb JOYSTK                      ; JOYSTK 0x8d
                fdb LEFT                        ; LEFT$ 0x8e
                fdb RIGHT                       ; RIGHT$ 0x8f
                fdb MID                         ; MID$ 0x90
                fdb POINT                       ; POINT 0x91
                fdb INKEY                       ; INKEY$ 0x92
                fdb MEM                         ; MEM 0x93
; Operator precedence and jump table (binary ops except relational)
LAA51           fcb 0x79                        ; +
                fdb LB9C5
                fcb 0x79                        ; -
                fdb LB9BC
                fcb 0x7b                        ; *
                fdb LBACC
                fcb 0x7b                        ; /
                fdb LBB91
                fcb 0x7f                        ; ^ (exponentiation)
                fdb EXPJMP
                fcb 0x50                        ; AND
                fdb LB2D5
                fcb 0x46                        ; OR
                fdb LB2D4
; Reserved words table for commands
LAA66           fcs 'FOR'                       ; 0x80
                fcs 'GO'                        ; 0x81
                fcs 'REM'                       ; 0x82
                fcs "'"                         ; 0x83
                fcs 'ELSE'                      ; 0x84
                fcs 'IF'                        ; 0x85
                fcs 'DATA'                      ; 0x86
                fcs 'PRINT'                     ; 0x87
                fcs 'ON'                        ; 0x88
                fcs 'INPUT'                     ; 0x89
                fcs 'END'                       ; 0x8a
                fcs 'NEXT'                      ; 0x8b
                fcs 'DIM'                       ; 0x8c
                fcs 'READ'                      ; 0x8d
                fcs 'RUN'                       ; 0x8e
                fcs 'RESTORE'                   ; 0x8f
                fcs 'RETURN'                    ; 0x90
                fcs 'STOP'                      ; 0x91
                fcs 'POKE'                      ; 0x92
                fcs 'CONT'                      ; 0x93
                fcs 'LIST'                      ; 0x94
                fcs 'CLEAR'                     ; 0x95
                fcs 'NEW'                       ; 0x96
                fcs 'CLOAD'                     ; 0x97
                fcs 'CSAVE'                     ; 0x98
                fcs 'OPEN'                      ; 0x99
                fcs 'CLOSE'                     ; 0x9a
                fcs 'LLIST'                     ; 0x9b
                fcs 'SET'                       ; 0x9c
                fcs 'RESET'                     ; 0x9d
                fcs 'CLS'                       ; 0x9e
                fcs 'MOTOR'                     ; 0x9f
                fcs 'SOUND'                     ; 0xa0
                fcs 'AUDIO'                     ; 0xa1
                fcs 'EXEC'                      ; 0xa2
                fcs 'SKIPF'                     ; 0xa3
                fcs 'TAB('                      ; 0xa4
                fcs 'TO'                        ; 0xa5
                fcs 'SUB'                       ; 0xa6
                fcs 'THEN'                      ; 0xa7
                fcs 'NOT'                       ; 0xa8
                fcs 'STEP'                      ; 0xa9
                fcs 'OFF'                       ; 0xaa
                fcs '+'                         ; 0xab
                fcs '-'                         ; 0xac
                fcs '*'                         ; 0xad
                fcs '/'                         ; 0xae
                fcs '^'                         ; 0xaf
                fcs 'AND'                       ; 0xb0
                fcs 'OR'                        ; 0xb1
                fcs '>'                         ; 0xb2
                fcs '='                         ; 0xb3
                fcs '<'                         ; 0xb4
; Reserved word list for functions
LAB1A           fcs 'SGN'                       ; 0x80
                fcs 'INT'                       ; 0x81
                fcs 'ABS'                       ; 0x82
                fcs 'USR'                       ; 0x83
                fcs 'RND'                       ; 0x84
                fcs 'SIN'                       ; 0x85
                fcs 'PEEK'                      ; 0x86
                fcs 'LEN'                       ; 0x87
                fcs 'STR$'                      ; 0x88
                fcs 'VAL'                       ; 0x89
                fcs 'ASC'                       ; 0x8a
                fcs 'CHR$'                      ; 0x8b
                fcs 'EOF'                       ; 0x8c
                fcs 'JOYSTK'                    ; 0x8d
                fcs 'LEFT$'                     ; 0x8e
                fcs 'RIGHT$'                    ; 0x8f
                fcs 'MID$'                      ; 0x90
                fcs 'POINT'                     ; 0x91
                fcs 'INKEY$'                    ; 0x92
                fcs 'MEM'                       ; 0x93
; Jump table for commands
LAB67           fdb FOR                         ; 0x80 FOR
                fdb GO                          ; 0x81 GO
                fdb REM                         ; 0x82 REM
                fdb REM                         ; 0x83 '
                fdb REM                         ; 0x84 ELSE
                fdb IFTOK                       ; 0x85 IF
                fdb DATA                        ; 0x86 DATA
                fdb PRINT                       ; 0x87 PRINT
                fdb ON                          ; 0x88 ON
                fdb INPUT                       ; 0x89 INPUT
                fdb ENDTOK                      ; 0x8a END
                fdb NEXT                        ; 0x8b NEXT
                fdb DIM                         ; 0x8c DIM
                fdb READ                        ; 0x8d READ
                fdb RUN                         ; 0x8e RUN
                fdb RESTOR                      ; 0x8f RESTORE
                fdb RETURN                      ; 0x90 RETURN
                fdb STOP                        ; 0x91 STOP
                fdb POKE                        ; 0x92 POKE
                fdb CONT                        ; 0x93 CONT
                fdb LIST                        ; 0x94 LIST
                fdb CLEAR                       ; 0x95 CLEAR
                fdb NEW                         ; 0x96 NEW
                fdb CLOAD                       ; 0x97 CLOAD
                fdb CSAVE                       ; 0x98 CSAVE
                fdb OPEN                        ; 0x99 OPEN
                fdb CLOSE                       ; 0x9a CLOSE
                fdb LLIST                       ; 0x9b LLIST
                fdb SET                         ; 0x9c SET
                fdb RESET                       ; 0x9d RESET
                fdb CLS                         ; 0x9e CLS
                fdb MOTOR                       ; 0x9f MOTOR
                fdb SOUND                       ; 0xa0 SOUND
                fdb AUDIO                       ; 0xa1 AUDIO
                fdb EXEC                        ; 0xa2 EXEC
                fdb SKIPF                       ; 0xa3 SKIPF
; Error message table
LABAF           fcc 'NF'                        ; 0 NEXT without FOR
                fcc 'SN'                        ; 1 Syntax error
                fcc 'RG'                        ; 2 RETURN without GOSUB
                fcc 'OD'                        ; 3 Out of data
                fcc 'FC'                        ; 4 Illegal function call
                fcc 'OV'                        ; 5 Overflow
                fcc 'OM'                        ; 6 Out of memory
                fcc 'UL'                        ; 7 Undefined line number
                fcc 'BS'                        ; 8 Bad subscript
                fcc 'DD'                        ; 9 Redimensioned array
                fcc '/0'                        ; 10 Division by 0
                fcc 'ID'                        ; 11 Illegal direct statement
                fcc 'TM'                        ; 12 Type mismatch
                fcc 'OS'                        ; 13 Out of string space
                fcc 'LS'                        ; 14 String too long
                fcc 'ST'                        ; 15 String formula too complex
                fcc 'CN'                        ; 16 Can't continue
                fcc 'FD'                        ; 17 Bad file data
                fcc 'AO'                        ; 18 File already open
                fcc 'DN'                        ; 19 Device number error
                fcc 'IO'                        ; 20 Input/output error
                fcc 'FM'                        ; 21 Bad file mode
                fcc 'NO'                        ; 22 File not open
                fcc 'IE'                        ; 23 Input past end of file
                fcc 'DS'                        ; 24 Direct statement in file
LABE1           fcn ' ERROR'
LABE8           fcn ' IN '
LABED           fcb 0x0d
LABEE           fcc 'OK'
                fcb 0x0d,0x00
LABF2           fcb 0x0d
                fcn 'BREAK'
; Search stack for a FOR/NEXT stack frame. Stop search when something that isn't a FOR/NEXT
; stack frame is found. Enter with the index variable descriptor pointer in VARDES, or NULL
; for the first match.
;
; NOTE: this routine can be reworked to avoid needed two temporaries by taking advantage of the
; 6809's registers. This requires some minor tweaks where the routine is called. Further, the
; use of B is completely pointless and, even if B is going to be used, why is it reloaded on
; every loop?
LABF9           leax 4,s                        ; skip past our caller and the main command loop return address
LABFB           ldb #18                         ; each FOR/NEXT frame is 18 bytes
                stx TEMPTR                      ; save current search pointer
                lda ,x                          ; get first byte of this frame
                suba #0x80                      ; set to 0 if FOR/NEXT
                bne LAC1A                       ; brif not FOR/NEXT (we hit the end of the stack for a GOSUB frame)
                ldx 1,x                         ; get index variable descriptor
                stx TMPTR1                      ; save it
                ldx VARDES                      ; get desired index descriptor
                beq LAC16                       ; brif NULL - we found something
                cmpx TMPTR1                     ; does this one match?
                beq LAC1A                       ; brif so
                ldx TEMPTR                      ; get back frame pointer
                abx                             ; move to next entry
                bra LABFB                       ; check next block of data
LAC16           ldx TMPTR1                      ; get index variable of this frame
                stx VARDES                      ; set it as the one found
LAC1A           ldx TEMPTR                      ; get matching frame pointer
                tsta                            ; set Z if FOR/NEXT
                rts
; This is a block copy routine which copies from top to bottom. It's not clear that the use of
; this routine actually saves any ROM space compared to just implementing the copies directly
; once all the marshalling to set up the parameter variables is taken into account.
LAC1E           bsr LAC37                       ; check to see if stack collides with D
LAC20           ldu V41                         ; point to destination
                leau 1,u                        ; offset for pre-dec
                ldx V43                         ; point to source
                leax 1,x                        ; offset for pre-dec
LAC28           lda ,-x                         ; get source byte
                pshu a                          ; store at destination (sta ,-u would be less weird)
                cmpx V47                        ; at the bottom of the copy?
                bne LAC28                       ; brif not
                stu V45                         ; save final destination address
LAC32           rts
; Check for 2*B (0 <= B <= 127) bytes for free memory
LAC33           clra                            ; zero extend
                aslb                            ; times 2 (loses bit 7 of B)
                addd ARYEND                     ; add to top of used memory
LAC37           addd #STKBUF                    ; add a fudge factor for interpreter operation
                bcs LAC44                       ; brif >65535!
                sts BOTSTK                      ; get current stack pointer
                cmpd BOTSTK                     ; is our new address above that?
                blo LAC32                       ; brif not - no error
LAC44           ldb #6*2                        ; raise OM error
; The error servicing routine
LAC46           jsr RVEC16                      ; do the RAM hook dance (ON ERROR reserved hook)
LAC49           jsr RVEC17                      ; do the RAM hook dance again
                jsr LA7E9                       ; turn off tape
                jsr LA974                       ; disable sound
                jsr LAD33                       ; reset stack, etc.
                clr DEVNUM                      ; reset output to screen
                jsr LB95C                       ; do a newline
                jsr LB9AF                       ; send a ?
                ldx #LABAF                      ; point to error table
LAC60           abx                             ; offset to correct message
                bsr LACA0                       ; send a char from X
                bsr LACA0                       ; send another char from X
LAC65           ldx #LABE1-1                    ; point to "ERROR" message
LAC68           jsr STRINOUT                    ; print ERROR message (or BREAK)
                lda CURLIN                      ; are we in immediate mode?
                inca
                beq LAC73                       ; brif not - go to immediate mode
                jsr LBDC5                       ; print "IN ****"
; This is the immediate mode loop
LAC73           jsr LB95C                       ; do a newline if needed
LAC76           ldx #LABEE-1                    ; point to prompt (without leading CR)
                jsr STRINOUT                    ; show prompt
LAC7C           jsr LA390                       ; read an input line
                ldu #0xffff                     ; flag immediate mode
                stu CURLIN
                bcs LAC7C                       ; brif we ended on BREAK - just go for another line
                tst CINBFL                      ; EOF?
                lbne LA4BF                      ; brif so
                stx CHARAD                      ; save start of input line as input pointer
                jsr GETNCH                      ; get character from input line
                beq LAC7C                       ; brif no input
                bcs LACA5                       ; brif numeric - adding or removing a line number
                ldb #2*24                       ; code for "direct statement in file"
                tst DEVNUM                      ; keyboard input?
                bne LAC46                       ; brif not - complain about direct statement
                jsr LB821                       ; go tokenize the input line
LAC9D           jmp LADC0                       ; go execute the newly tokenized line
LACA0           lda ,x+                         ; get character and advance pointer
                jmp LB9B1                       ; output it
LACA5           jsr LAF67                       ; convert line number to binary
LACA8           ldx BINVAL                      ; get converted number
                stx LINHDR                      ; put it before the line we just read
                jsr LB821                       ; tokenize the input line
                stb TMPLOC                      ; save line length
                bsr LAD01                       ; find where the line should be in the program
                bcs LACC8                       ; brif the line number isn't already present
                ldd V47                         ; get address where the line is in the program
                subd ,x                         ; get the difference between here and the end of the line (negative)
                addd VARTAB                     ; subtract line length from the end of the program
                std VARTAB                      ; save new end of program address
                ldu ,x                          ; get start of next line
LACC0           pulu a                          ; get source byte (lda ,u+ would be less weird)
                sta ,x+                         ; move it down
                cmpx VARTAB                     ; have we moved everything yet?
                bne LACC0                       ; brif not
LACC8           lda LINBUF                      ; see if there is actually a line to input
                beq LACE9                       ; brif not - we just needed to remove the line
                ldd VARTAB                      ; get current end of program
                std V43                         ; set as source pointer
                addb TMPLOC                     ; add in the length of the new line
                adca #0
                std V41                         ; save destination pointer
                jsr LAC1E                       ; make sure there's enough room and then make a hole for the new line
                ldu #LINHDR-2                   ; point to the line (well, 4 bytes before it, incl line number and fake next line pointer)
LACDD           pulu a                          ; get byte from new line (lda ,u+ would be less weird)
                sta ,x+                         ; stow it
                cmpx V45                        ; at the end of the hole we just made?
                bne LACDD                       ; brif not
                ldx V41                         ; get save new top of program address
                stx VARTAB
LACE9           bsr LAD21                       ; reset variables, etc.
                bsr LACEF                       ; adjust next line pointers
                bra LAC7C                       ; go read another input line
; Recompute next line pointers
LACEF           ldx  TXTTAB                     ; point to start of program
LACF1           ldd ,x                          ; get address of next line
                beq LAD16                       ; brif end of program
                leau 4,x                        ; move past pointer and line number
LACF7           lda ,u+                         ; are we at the end of the line?
                bne LACF7                       ; brif not
                stu ,x                          ; save new next line pointer
                ldx ,x                          ; point to next line
                bra LACF1                       ; process the next line
; Find a line in the program
LAD01           ldd BINVAL                      ; get desired line number
                ldx TXTTAB                      ; point to start of program
LAD05           ldu ,x                          ; get address of next line
                beq LAD12                       ; brif end of program
                cmpd 2,x                        ; do we have a match?
                bls LAD14                       ; brif our search number is <= the number here
                ldx ,x                          ; move to next line
                bra LAD05                       ; check another line
LAD12           orcc #1                         ; set C for not found
LAD14           stx V47                         ; save address of matching line *or* line just after where it would have been
LAD16           rts
; NEW command
; This routine has multiple entry points used for various "levels" of NEW
NEW             bne LAD14                       ; brif there was input given; should be LAD16!
LAD19           ldx TXTTAB                      ; point to start of program
                clr ,x+                         ; blank out program (with NULL next line pointer)
                clr ,x+
                stx VARTAB                      ; save end of program
LAD21           ldx TXTTAB                      ; get start of program
                jsr LAEBB                       ; put input pointer there
LAD26           ldx MEMSIZ                      ; reset string space
                stx STRTAB
                jsr RESTOR                      ; reset DATA pointer
                ldx VARTAB                      ; clear out scalars and arrays
                stx ARYTAB
                stx ARYEND
LAD33           ldx #STRSTK                     ; reset the string stack
                stx TEMPPT
                ldx ,s                          ; get return address (we're going to reset the stack)
                lds FRETOP                      ; reset the stack to top of memory
                clr ,-s                         ; put stopper so FOR/NEXT search will actually stop here
LAD3F           clr OLDPTR                      ; reset "CONT" state
                clr OLDPTR+1
LAD43           clr ARYDIS                      ; un-disable arrays
                jmp ,x                          ; return to original caller
; FOR command
FOR             lda #0x80                       ; disable array parsing
                sta ARYDIS
                jsr LET                         ; assign start value to index
                jsr LABF9                       ; search stack for matching FOR/NEXT frame
                leas 2,s                        ; lose return address
                bne LAD59                       ; brif variable not already being used
                ldx TEMPTR                      ; get address of matched data
                leas b,x                        ; move stack pointer to the end of it (B is set to 18 in the stack search)
LAD59           ldb #9                          ; is there room for 18 bytes in memory?
                jsr LAC33
                jsr LAEE8                       ; get address of the end of this statement in X
                ldd CURLIN                      ; get line number
                pshs x,b,a                      ; save next line address and current line number
                ldb #0xa5                       ; make sure we have TO
                jsr LB26F
                jsr LB143                       ; make sure we have a numeric index
                jsr LB141                       ; evaluate terminal condition value
                ldb FP0SGN                      ; pack FPA0 in place
                orb #0x7f
                andb FPA0
                stb FPA0
                ldy #LAD7F                      ; where to come back to
                jmp LB1EA                       ; stash terminal condition on the stack
LAD7F           ldx #LBAC5                      ; point to FP 1.0 (default step)
                jsr LBC14                       ; unpack it to FPA0
                jsr GETCCH                      ; get character after the terminal
                cmpa #0xa9                      ; is it STEP?
                bne LAD90                       ; brif not
                jsr GETNCH                      ; eat STEP
                jsr LB141                       ; evaluate step condition
LAD90           jsr LBC6D                       ; get "status" of FPA0
                jsr LB1E6                       ; stash FPA0 on the stack (for step value)
                ldd VARDES                      ; get variable descriptor pointer
                pshs d                          ; put that on the stack too
                lda #0x80                       ; flag the frame as a FOR/NEXT frame
                pshs a
; Main command interpretation loop
LAD9E           jsr RVEC20                      ; do the RAM hook dance
                andcc #0xaf                     ; make sure interrupts are running
                bsr LADEB                       ; check for BREAK/pause
                ldx CHARAD                      ; get input pointer
                stx TINPTR                      ; save input pointer for start of line
                lda ,x+                         ; get current input character
                beq LADB4                       ; brif end of line - move to another line
                cmpa #':                        ; end of statement?
                beq LADC0                       ; brif so - keep processing
LADB1           jmp LB277                       ; raise a syntax error
LADB4           lda ,x++                        ; get MSB of next line pointer and skip past pointer
                sta ENDFLG
                beq LAE15                       ; brif MSB of next line address is 0 (do END)
                ldd ,x+                         ; get line number but only advance one
                std CURLIN                      ; set current line number
                stx CHARAD                      ; set input pointer to one before line text
LADC0           jsr GETNCH                      ; move past statement separator or to first character in line
                bsr LADC6                       ; process a command
LADC4           bra LAD9E                       ; handle next statement or line
LADC6           beq LAE40                       ; return if end of statement
                tsta                            ; is it a token?
                lbpl LET                        ; brif not - do a LET
                cmpa #0xa3                      ; above SKIPF?
                bhi LADDC                       ; brif so
                ldx COMVEC+3                    ; point to jump table
LADD4           lsla                            ; two bytes per entry (loses the token bias)
                tfr a,b                         ; put it in B for unsigned ABX
                abx
                jsr GETNCH                      ; move past token
                jmp [,x]                        ; transfer control to the handler (which will return to the main loop)
LADDC           cmpa #0xb4                      ; is it a non-executable token?
                bls LADB1                       ; brif so
                jmp [COMVEC+13]                 ; transfer control to ECB command handler
; RESTORE command
RESTOR          ldx TXTTAB                      ; point to beginning of the program
                leax -1,x                       ; move back one (to compensate for "GETNCH")
LADE8           stx DATPTR                      ; save as new data pointer
                rts
; BREAK check
LADEB           jsr LA1C1                       ; read keyboard
                beq LADFA                       ; brif no key down
LADF0           cmpa #3                         ; BREAK?
                beq STOP                        ; brif so - do a STOP
LADF4           cmpa #0x13                      ; pause (SHIFT-@)?
                beq LADFB                       ; brif so
                sta IKEYIM                      ; cache key for later INKEY$ so break check doesn't break INKEY$
LADFA           rts
LADFB           jsr KEYIN                       ; read keyboard
                beq LADFB                       ; brif no key down
                bra LADF0                       ; process pressed key in case BREAK or SHIFT-@ again
; END command
ENDTOK          jsr LA426                       ; close files
                jsr GETCCH                      ; re-get input character
                bra LAE0B
; STOP command
STOP            orcc #1                         ; flag "STOP"
LAE0B           bne LAE40                       ; brif not end of statement
                ldx CHARAD                      ; save current input pointer
                stx TINPTR
LAE11           ror ENDFLG                      ; save END/STOP flag (C)
                leas 2,s                        ; lose return address
LAE15           ldx CURLIN                      ; get current input line (end of program comes here)
                cmpx #0xffff                    ; immediate mode?
                beq LAE22                       ; brif so
                stx OLDTXT                      ; save line where we stopped executing
                ldx TINPTR                      ; get input pointer
                stx OLDPTR                      ; save location where we stopped executing
LAE22           clr DEVNUM                      ; reset to screen/keyboard
                ldx #LABF2-1                    ; point to BREAK message
                tst ENDFLG                      ; are we doing "BREAK"?
                lbpl LAC73                      ; brif not
                jmp LAC68                       ; go do the BREAK message and return to main loop
; CONT command
CONT            bne LAE40                       ; brif not end of statement
                ldb #2*16                       ; code for can't continue
                ldx OLDPTR                      ; get saved execution pointer
                lbeq LAC46                      ; brif no saved pointer - raise CN error
                stx CHARAD                      ; reset input pointer
                ldx OLDTXT                      ; reset current line number
                stx CURLIN
LAE40           rts
; CLEAR command
CLEAR           beq LAE6F                       ; brif no argument
                jsr LB3E6                       ; evaluate string space size
                pshs d                          ; save it
                ldx MEMSIZ                      ; get memory size (top of memory)
                jsr GETCCH                      ; is there anything after the string space size?
                beq LAE5A                       ; brif not
                jsr SYNCOMMA                    ; force a comma
                jsr LB73D                       ; get top of memory value in X
                leax -1,x                       ; move back one (top of cleared space)
                cmpx TOPRAM                     ; is it within the memory available?
                bhi LAE72                       ; brif higher than top of memory - OM error
LAE5A           tfr x,d                         ; so we can do math for checking memory usage
                subd ,s++                       ; subtract out string space value
                bcs LAE72                       ; brif less than 0
                tfr d,u                         ; U is bottom of cleared space
                subd #STKBUF                    ; also account for slop space
                bcs LAE72                       ; brif less than 0
                subd VARTAB                     ; is there still room for the program?
                blo LAE72                       ; brif not
                stu FRETOP                      ; set top of free memory
                stx MEMSIZ                      ; set size of usable memory
LAE6F           jmp LAD26                       ; erase variables, etc.
LAE72           jmp LAC44                       ; raise OM error
; RUN command
RUN             jsr RVEC18                      ; do the RAM hook dance
                jsr LA426                       ; close any open files
                jsr GETCCH                      ; is there a line number
                lbeq LAD21                      ; brif no line number - start from beginning
                jsr LAD26                       ; clear variables, etc.
                bra LAE9F                       ; "GOTO" the line number
; GO command (GOTO and GOSUB)
GO              tfr a,b                         ; save TO/SUB
LAE88           jsr GETNCH                      ; eat the TO/SUB token
                cmpb #0xa5                      ; TO?
                beq LAEA4                       ; brif GOTO
                cmpb #0xa6                      ; SUB?
                bne LAED7                       ; brif not
                ldb #3                          ; room for 6 bytes?
                jsr LAC33
                ldu CHARAD                      ; get input pointer
                ldx CURLIN                      ; get line number
                lda #0xa6                       ; flag for GOSUB frame
                pshs u,x,a                      ; set stack frame
LAE9F           bsr LAEA4                       ; do "GOTO"
                jmp LAD9E                       ; go back to main loop
; Actual GOTO is here
LAEA4           jsr GETCCH                      ; get current input
                jsr LAF67                       ; convert number to binary
                bsr LAEEB                       ; move input pointer to end of statement
                leax 1,x                        ; point to start of next line
                ldd BINVAL                      ; get desired line number
                cmpd CURLIN                     ; is it beyond here?
                bhi LAEB6                       ; brif so
                ldx TXTTAB                      ; start search at beginning of program
LAEB6           jsr LAD05                       ; find line number
                bcs LAED2                       ; brif not found
LAEBB           leax -1,x                       ; move to just before start of line
                stx CHARAD                      ; reset input pointer
LAEBF           rts
; RETURN command
RETURN          bne LAEBF                       ; exit if argument given
                lda #0xff                       ; set VARDES to an illegal value so we ignore FOR frames
                sta VARDES
                jsr LABF9                       ; look for a GOSUB frame
                tfr x,s                         ; reset stack
                cmpa #0xa6-0x80                 ; is it a GOSUB frame?
                beq LAEDA                       ; brif so
                ldb #2*2                        ; code for RETURN without GOSUB
                skip2
LAED2           ldb #7*2                        ; code for undefined line number
                jmp LAC46                       ; raise error
LAED7           jmp LB277                       ; raise syntax error
LAEDA           puls a,x,u                      ; get back saved line number and input pointer
                stx CURLIN                      ; reset line number
                stu CHARAD                      ; reset input pointer
; DATA command
DATA            bsr LAEE8                       ; move input pointer to end of statement
                skip2
; REM command (also ELSE)
REM             bsr LAEEB                       ; move input pointer to end of line
                stx CHARAD                      ; save new input pointer
LAEE7           rts
; Return end of statement (LAEE8) or line (AEEB) in X
LAEE8           ldb #':                         ; colon is statement terminator
                skip1lda
LAEEB           clrb                            ; make main terminator NUL
                stb CHARAC                      ; save terminator
                clrb                            ; end of line - always terminates
                ldx CHARAD                      ; get input pointer
LAEF1           tfr b,a                         ; save secondary terminator
                ldb CHARAC                      ; get main terminator
                sta CHARAC                      ; save secondary
LAEF7           lda ,x                          ; get input character
                beq LAEE7                       ; brif end of line
                pshs b                          ; save terminator
                cmpa ,s+                        ; does it match?
                beq LAEE7                       ; brif so - bail
                leax 1,x                        ; move pointer ahead
                cmpa #'"                        ; start of string?
                beq LAEF1                       ; brif so
                inca                            ; functon token?
                bne LAF0C                       ; brif not
                leax 1,x                        ; skip second part of function token
LAF0C           cmpa #0x85+1                    ; IF?
                bne LAEF7                       ; brif not
                inc IFCTR                       ; bump "IF" count
                bra LAEF7                       ; get check another input character
; IF command
IFTOK           jsr LB141                       ; evaluate condition
                jsr GETCCH                      ; find out what's after the conditin
                cmpa #0x81                      ; GO?
                beq LAF22                       ; treat same as THEN
                ldb #0xa7                       ; make sure we have a THEN
                jsr LB26F
LAF22           lda FP0EXP                      ; get true/false (false is 0)
                bne LAF39                       ; brif condition true
                clr IFCTR                       ; reset IF counter
LAF28           bsr DATA                        ; skip over statement
                tsta                            ; end of line?
                beq LAEE7                       ; brif so
                jsr GETNCH                      ; get start of this statement
                cmpa #0x84                      ; ELSE?
                bne LAF28                       ; brif not
                dec IFCTR                       ; is it a matching ELSE?
                bpl LAF28                       ; brif not - keep looking
                jsr GETNCH                      ; eat the ELSE
LAF39           jsr GETCCH                      ; get current input
                lbcs LAEA4                      ; brif numeric - to a GOTO
                jmp LADC6                       ; let main loop interpret the next command
; ON command
ON              jsr EVALEXPB                    ; evaluate index expression
LAF45           ldb #0x81                       ; make sure we have "GO"
                jsr LB26F
                pshs a                          ; save TO/SUB
                cmpa #0xa6                      ; SUB?
                beq LAF54                       ; brif so
                cmpa #0xa5                      ; TO?
LAF52           bne LAED7                       ; brif not
LAF54           dec FPA0+3                      ; are we at the right index?
                bne LAF5D                       ; brif not
                puls b                          ; get TO/SUB token
                jmp LAE88                       ; go do GOTO or GOSUB
LAF5D           jsr GETNCH                      ; munch a character
                bsr LAF67                       ; parse line number
                cmpa #',                        ; is there another line following?
                beq LAF54                       ; brif so - see if we're there yet
                puls b,pc                       ; clean up TO/SUB token and return - we fell through
; Parse a line number
LAF67           ldx ZERO                        ; initialize line number accumulator to 0
                stx BINVAL
LAF6B           bcc LAFCE                       ; brif not numeric
                suba #'0                        ; adjust to actual value of digit
                sta CHARAC                      ; save digit
                ldd BINVAL                      ; get accumulated number
                cmpa #24                        ; will this overflow?
                bhi LAF52                       ; brif so - raise syntax error
                aslb                            ; times 2
                rola
                aslb                            ; times 4
                rola
                addd BINVAL                     ; times 5
                aslb                            ; times 10
                rola
                addb CHARAC                     ; add in digit
                adca #0
                std BINVAL                      ; save new accumulated number
                jsr GETNCH                      ; fetch next character
                bra LAF6B                       ; process next digit
; LET command (the LET keyword requires Extended Basic)
LET             jsr LB357                       ; evaluate destination variable
                stx VARDES                      ; save descriptor pointer
                ldb #0xb3                       ; make sure we have =
                jsr LB26F
                lda VALTYP                      ; get destination variable type
                pshs a                          ; save it for later
                jsr LB156                       ; evaluate the expression to assign
                puls a                          ; get back original variable type
                rora                            ; put type in C
                jsr LB148                       ; make sure the current result matches the type
                lbeq LBC33                      ; bri fnumeric - copy FPA0 to variable
LAFA4           ldx FPA0+2                      ; point to descriptor of replacement string
                ldd FRETOP                      ; get bottom of string space
                cmpd 2,x                        ; is the string already in string space?
                bhs LAFBE                       ; brif so
                cmpx VARTAB                     ; is the descriptor in variable space?
                blo LAFBE                       ; brif not
LAFB1           ldb ,x                          ; get length of string
                jsr LB50D                       ; allocate space for this string
                ldx V4D                         ; get descriptor pointer back
                jsr LB643                       ; copy string into string space
                ldx #STRDES                     ; point to temporary string descriptor
LAFBE           stx V4D                         ; save descriptor pointer
                jsr LB675                       ; remove string from string stack if appropriate
                ldu V4D                         ; get back replacement descriptor
                ldx VARDES                      ; get target descriptor
                pulu a,b,y                      ; get string length (A) and data pointer (Y)
                sta ,x                          ; save new length
                sty 2,x                         ; save new pointer
LAFCE           rts
; READ and INPUT commands.
LAFCF           fcc '?REDO'                     ; The ?REDO message
                fcb 0x0d,0x00
LAFD6           ldb #2*17                       ; bad file data code
                tst DEVNUM                      ; are we reading from the keyboard?
                beq LAFDF                       ; brif so
LAFDC           jmp LAC46                       ; raise the error
LAFDF           lda INPFLG                      ; are we doing INPUT?
                beq LAFEA                       ; brif so
                ldx DATTXT                      ; get line number where the DATA statement happened
                stx CURLIN                      ; set current line number to that so can report the correct location
                jmp LB277                       ; raise a syntax error on bad data
LAFEA           ldx #LAFCF-1                    ; show the ?REDO if we're doing INPUT
                jsr STRINOUT
                ldx TINPTR                      ;* reset input pointer to start of statement (this will cause the
                stx CHARAD                      ;* INPUT statement to be re-executed
                rts
INPUT           ldb #11*2                       ; code for illegal direct statement
                ldx CURLIN                      ; are we in immediate mode?
                leax 1,x
                beq LAFDC                       ; brif so - raise ID error
                bsr LB002                       ; go do the INPUT thing
                clr DEVNUM                      ; reset device to screen/keyboard
                rts
LB002           cmpa #'#                        ; is there a device number?
                bne LB00F                       ; brif not
                jsr LA5A5                       ; parse device number
                jsr LA3ED                       ; make sure it's valid for input
                jsr SYNCOMMA                    ; make sure we have a comma after the device number
LB00F           cmpa #'"                        ; is there a prompt string?
                bne LB01E                       ; brif not
                jsr LB244                       ; parse the prompt string
                ldb #';                         ; make sure we have a semicolon after the prompt
                jsr LB26F
                jsr LB99F                       ; print the prompt
LB01E           ldx #LINBUF                     ; point to line input buffer
                clr ,x                          ; NUL first byte to indicate no data
                tst DEVNUM                      ; is it keyboard input?
                bne LB049                       ; brif not
                bsr LB02F                       ; read a line from the keyboard
                ldb #',                         ; put a comma at the start of the buffer
                stb ,x
                bra LB049                       ; go process some input
LB02F           jsr LB9AF                       ; send a ?
                jsr LB9AC                       ; send a space
LB035           jsr LA390                       ; read input from the keyboard
                bcc LB03F                       ; brif not BREAK
                leas 4,s                        ; clean up stack
LB03C           jmp LAE11                       ; go process BREAK
LB03F           ldb #2*23                       ; input past end of file error code
                tst CINBFL                      ; was it EOF?
                bne LAFDC                       ; brif so - raise the error
                rts
READ            ldx DATPTR                      ; fetch current DATA pointer
                skip1lda                        ; set A to nonzero (for READ)
LB049           clra                            ; set A to zero (for INPUT)
                sta INPFLG                      ; record whether we're doing READ or INPUT
                stx DATTMP                      ; save current input location
LB04E           jsr LB357                       ; evaluate a variable (destination of data)
                stx VARDES                      ; save descriptor
                ldx CHARAD                      ; save interpreter input pointer
                stx BINVAL
                ldx DATTMP                      ; get data pointer
                lda ,x                          ; is there anything to read?
                bne LB069                       ; brif so
                lda INPFLG                      ; is it INPUT?
                bne LB0B9                       ; brif not
                jsr RVEC10                      ; do the RAM hook dance
                jsr LB9AF                       ; send a ? (so subsequent lines get ??)
                bsr LB02F                       ; go read an input line
LB069           stx CHARAD                      ; save data pointer
                jsr GETNCH                      ; fetch next data character
                ldb VALTYP                      ; do we want a number?
                beq LB098                       ; brif so
                ldx CHARAD                      ; get input pointer
                sta CHARAC                      ; save initial character as the delimiter
                cmpa #'"                        ; do we have a string delimiter?
                beq LB08B                       ; brif so - use " as both delimiters
                leax -1,x                       ; back up input if we don't have a delimiter
                clra                            ; set delimiter to NUL (end of line)
                sta CHARAC
                jsr LA35F                       ; set up print parameters
                tst PRTDEV                      ; is it a file type device?
                bne LB08B                       ; brif so - use two NULs
                lda #':                         ; use colon as one delimiter
                sta CHARAC
                lda #',                         ; and use comma as the other
LB08B           sta ENDCHR                      ; save second terminator
                jsr LB51E                       ; parse out the string
                jsr LB249                       ; move input pointer past the string
                jsr LAFA4                       ; assign the string to the variable
                bra LB09E                       ; go see if there's more to read
LB098           jsr LBD12                       ; parse a numeric string
                jsr LBC33                       ; assign the numbe to the variable
LB09E           jsr GETCCH                      ; get current input character
                beq LB0A8                       ; brif end of line
                cmpa #',                        ; check for comma
                lbne LAFD6                      ; brif not - we have bad data
LB0A8           ldx CHARAD                      ; get current data pointer
                stx DATTMP                      ; save the data pointer
                ldx BINVAL                      ; restore the interpreter input pointer
                stx CHARAD
                jsr GETCCH                      ; get current input from program
                beq LB0D5                       ; brif end of statement
                jsr SYNCOMMA                    ; make sure there's a comma between variables
                bra LB04E                       ; go read another item
LB0B9           stx CHARAD                      ; reset input pointer
                jsr LAEE8                       ; search for end of statement
                leax 1,x                        ; move past end of statement
                tsta                            ; was it end of line?
                bne LB0CD                       ; brif not
                ldb #2*3                        ; code for out of data
                ldu ,x++                        ; get pointer to next line
                beq LB10A                       ; brif end of program - raise OD error
                ldd ,x++                        ; get line number
                std DATTXT                      ; record it for raising errors in DATA statements
LB0CD           lda ,x                          ; do we have a DATA statement?
                cmpa #0x86
                bne LB0B9                       ; brif not - keep scanning
                bra LB069                       ; go process the input
LB0D5           ldx DATTMP                      ; get data pointer
                ldb INPFLG                      ; were we doing READ?
                lbne LADE8                      ; brif so - save DATA pointer
                lda ,x                          ; is there something after the input in the input buffer?
                beq LB0E7                       ; brif not - we consumed everything
                ldx #LB0E8-1                    ; print the ?EXTRA IGNORED message
                jmp STRINOUT
LB0E7           rts
LB0E8           fcc '?EXTRA IGNORED'
                fcb 0x0d,0x00
; NEXT command
NEXT            bne LB0FE                       ; brif argument given
                ldx ZERO                        ; set to NULL descriptor pointer
                bra LB101                       ; go process "any index will do"
LB0FE           jsr LB357                       ; evaluate the variable
LB101           stx VARDES                      ; save the index we're looking for
                jsr LABF9                       ; search the stack for the matching frame
                beq LB10C                       ; brif we found a matching frame
                ldb #0                          ; code for NEXT without FOR
LB10A           bra LB153                       ; raise the error
LB10C           tfr x,s                         ; reset the stack to the start of the stack frame
                leax 3,x                        ; point to the STEP value
                jsr LBC14                       ; copy the value to FPA0
                lda 8,s                         ; get step direction
                sta FP0SGN                      ; save as sign of FPA0
                ldx VARDES                      ; point to index variable
                jsr LB9C2                       ; add (X) to FPA0 (steps the index)
                jsr LBC33                       ; save new value to the index
                leax 9,s                        ; point to terminal condition
                jsr LBC96                       ; compare the new index value with the terminal
                subb 8,s                        ; set B=0 if we hit the terminal (or passed it with nonzero step)
                beq LB134                       ; brif loop complete
                ldx 14,s                        ; restore line number and input pointer to start of loop
                stx CURLIN
                ldx 16,s
                stx CHARAD
LB131           jmp LAD9E                       ; return to interpretation loop
LB134           leas 18,s                       ; remove the frame from the stack
                jsr GETCCH                      ; get character after the index
                cmpa #',                        ; do we have more indexes?
                bne LB131                       ; brif not
                jsr GETNCH                      ; munch the comma
                bsr LB0FE                       ; go process another value
; NOTE: despite the BSR on the preceding line, execution of the NEXT command will not fall
; through this point, nor will the stack grow without bound. The BSR is required to make sure
; the stack is aligned properly for the stack search for the subsequent index variable.
;
; The following is the expression evaluation system. It has various entry points including for type
; checking. This really consists of two co-routines, one for evaluating operators and one for individual
; terms. However, it does some rather confusing stack operations so it's a bit difficult to follow
; just how some of this works.
;
; Evaluate numeric expression
LB141           bsr LB156                       ; evaluate an expression
; TM error if string
LB143           andcc #0xfe                     ; clear C to indicate we want a number
                skip2keepc
; TM error if numeric
LB146           orcc #1                         ; set C to indicate we want a string
; TM error if: C = 1 and number, OR C = 0 and string
LB148           tst VALTYP                      ; set flags on the current value to (doesn't change C)
                bcs LB14F                       ; brif we want a string
                bpl LB0E7                       ; brif we have a number (we want a number)
                skip2
LB14F           bmi LB0E7                       ; brif we have a string (we want a string)
LB151           ldb #12*2                       ; code for TM error
LB153           jmp LAC46                       ; raise the error
; The general expression evaluation entry point
LB156           bsr LB1C6                       ; back up input pointer to compensate for GETNCH below
LB158           clra                            ; set operator precedence to 0 (no previous operator)
                skip2
LB15A           pshs b                          ; save relational operator flags
                pshs a                          ; save previous operator precedence
                ldb #1                          ; make sure we aren't overflowing the stack
                jsr LAC33
                jsr LB223                       ; go evaluate the first term
LB166           clr TRELFL                      ; flag no relational operators seen
LB168           jsr GETCCH                      ; get input character
LB16A           suba #0xb2                      ; token for > (lowest relational operator)
                blo LB181                       ; brif below relational operators
                cmpa #3                         ; there are three relational operators, is it one?
                bhs LB181                       ; brif not
                cmpa #1                         ; set C if >
                rola                            ; shift C into bit 0 (4: <, 2: =, 1: >)
                eora TRELFL                     ; flip the bit for this operator
                cmpa TRELFL                     ; did the result get lower?
                blo LB1DF                       ; brif so - we have a duplicate so raise an error
                sta TRELFL                      ; save new operator flags
                jsr GETNCH                      ; munch the operator
                bra LB16A                       ; go see if we have another one
LB181           ldb TRELFL                      ; do we have a relational comparison?
                bne LB1B8                       ; brif so
                lbcc LB1F4                      ; brif the token is above the relational operators
                adda #7                         ; put operators starting at 0
                bhs LB1F4                       ; brif we're above 0 - it's an operator, Jim
                adca VALTYP                     ; add carry, numeric flag, and modified token number
                lbeq LB60F                      ; brif we have string and A is + - do concatenation
                adca #-1                        ; restore operator number
                pshs a                          ; save operator number
                asla                            ; times 2
                adda ,s+                        ; and times 3 (3 bytes per entry)
                ldx #LAA51                      ; point to operator pecedence and jump table
                leax a,x                        ; point to correct entry
LB19F           puls a                          ; get precedence of previous operation
                cmpa ,x                         ; is hit higher (or same) than the current one?
                bhs LB1FA                       ; brif so - we need to process that operator
                bsr LB143                       ; TM error if we have a string
LB1A7           pshs a                          ; save previous operation precedence
                bsr LB1D4                       ; push operator handler address and FPA0 onto the stack
                ldx RELPTR                      ; get pointer to arithmetic/logical table entry for last operation
                puls a                          ; get back precedence
                bne LB1CE                       ; brif we had a relational operation
                tsta                            ; check precedence of previous operation
                lbeq LB220                      ; brif end of expression
                bra LB203                       ; go handle operation
LB1B8           asl VALTYP                      ; get type of value to C
                rolb                            ; mix it in to bit 0 of relational flags
                bsr LB1C6                       ; back up input pointer
                ldx #LB1CB                      ; point to relational operator precedence and handler
                stb TRELFL                      ; save relational comparison flags
                clr VALTYP                      ; result will be numeric
                bra LB19F                       ; to process the operation
LB1C6           ldx CHARAD                      ; get input pointer
                jmp LAEBB                       ; back it up one and put it back
LB1CB           fcb 0x64                        ; precedence of relational comparison
                fdb LB2F4                       ; handler address for relational comparison
LB1CE           cmpa ,x                         ; is last done operation higher (or same) precedence?
                bhs LB203                       ; brif so - go process it
                bra LB1A7                       ; go push things on the stack and process this operation otherwise
LB1D4           ldd 1,x                         ; get address of operatorroutine
                pshs d                          ; save it
                bsr LB1E2                       ; push FPA0 onto the stack
                ldb TRELFL                      ; get back relational operator flags
                lbra LB15A                      ; go evaluate another operation
LB1DF           jmp LB277                       ; raise a syntax error
LB1E2           ldb FP0SGN                      ; get sign of FPA0
                lda ,x                          ; get precedence of this operation
LB1E6           puls y                          ; get back original caller
                pshs b                          ; save sign
LB1EA           ldb FP0EXP                      ; get exponent
                ldx FPA0                        ; get mantissa
                ldu FPA0+2
                pshs u,x,b                      ; stow FPA0 sign and mantissa
                jmp ,y                          ; return to caller
LB1F4           ldx ZERO                        ; point to dummy value
                lda ,s+                         ; get precedence of previous operation (and set flags)
                beq LB220                       ; brif end of expression
LB1FA           cmpa #0x64                      ; relational operation?
                beq LB201                       ; brif so
                jsr LB143                       ; type mismatch if string
LB201           stx RELPTR                      ; save pointer to operator routine
LB203           puls b                          ; get relational flags
                cmpa #0x5a                      ; NOT operation?
                beq LB222                       ; brif so (it was unary)
                cmpa #0x7d                      ; unary negation?
                beq LB222                       ; brif so
                lsrb                            ; shift value type flag out of relational flags
                stb RELFLG                      ; save relational operator flag
                puls a,x,u                      ; get FP value back
                sta FP1EXP                      ; set exponent and mantissa in FPA1
                stx FPA1
                stu FPA1+2
                puls b                          ; and the sign
                stb FP1SGN
                eorb FP0SGN                     ; set RESSGN if the two operand signs differ
                stb RESSGN
LB220           ldb FP0EXP                      ; get exponent of FPA0
LB222           rts                             ; return or transfer control to operator handler routine
LB223           jsr RVEC15                      ; do the RAM hook dance
                clr VALTYP                      ; set type to numeric
                jsr GETNCH                      ; get first character in the term
                bcc LB22F                       ; brif not numeric
LB22C           jmp LBD12                       ; parse a number (and return)
LB22F           jsr LB3A2                       ; set carry if not alpha
                bcc LB284                       ; brif alpha character (variable)
                cmpa #'.                        ; decimal point?
                beq LB22C                       ; brif so - evaluate number
                cmpa #0xac                      ; minus?
                beq LB27C                       ; brif so - process unary negation
                cmpa #0xab                      ; plus?
                beq LB223                       ; brif so - ignore unary "posation"
                cmpa #'"                        ; string delimiter?
                bne LB24E                       ; brif not
LB244           ldx CHARAD                      ; get input pointer
                jsr LB518                       ; go parse the string
LB249           ldx COEFPT                      ; get address of end of string
                stx CHARAD                      ; move input pointer past string
                rts
LB24E           cmpa #0xa8                      ; NOT?
                bne LB25F                       ; brif not
                lda #0x5a                       ; precedence of unary NOT
                jsr LB15A                       ; process the operand of NOT
                jsr INTCNV                      ; convert to integer in D
                coma                            ; do a bitwise complement
                comb
                jmp GIVABF                      ; resturn the result
LB25F           inca                            ; is it a function token?
                beq LB290                       ; brif so
LB262           bsr LB26A                       ; only other legal thing must be a (expr)
                jsr LB156                       ; evaluate parentheticized expression
LB267           ldb #')                         ; force a )
                skip2
LB26A           ldb #'(                         ; force a (
                skip2
SYNCOMMA        ldb #',                         ; force a ,
LB26F           cmpb [CHARAD]                   ; does character match?
                bne LB277                       ; brif not
                jmp GETNCH                      ; each the character and return the next
LB277           ldb #2*1                        ; raise syntax error
                jmp LAC46
LB27C           lda #0x7d                       ; unary negation precedence
                jsr LB15A                       ; evaluate argument
                jmp LBEE9                       ; flip sign of FPA0 and return
LB284           jsr LB357                       ; evaluate variable
LB287           stx FPA0+2                      ; save descriptor address in FPA0
                lda VALTYP                      ; test variable type
                bne LB222                       ; brif string - we're done
                jmp LBC14                       ; copy FP number from (X) into FPA0
LB290           jsr GETNCH                      ; get the actual token number
                tfr a,b                         ; save it (for offsetting X)
                lslb                            ; two bytes per jump table entry (and lose high bit)
                jsr GETNCH                      ; eat the token byte
                cmpb #2*19                      ; is it a valid token for Color Basic?
                bls LB29F                       ; brif so
                jmp [COMVEC+18]                 ; transfer control to Extended Basic if not
LB29F           pshs b                          ; save jump table offset
                cmpb #2*14                      ; does it expect a numeric argument?
                blo LB2C7                       ; brif so
                cmpb #2*18                      ; does it need no arguments?
                bhs LB2C9                       ; brif so
                bsr LB26A                       ; force a (
                lda ,s                          ; get token value
                cmpa #2*17                      ; is it POINT?
                bhs LB2C9                       ; brif so
                jsr LB156                       ; evaluate first argument string
                bsr SYNCOMMA                    ; force a comma
                jsr LB146                       ; TM error if string
                puls a                          ; get token value
                ldu FPA0+2                      ; get string descriptor
                pshs u,a                        ; now we save the first string argument and the token value
                jsr EVALEXPB                    ; evaluate first numeric argument
                puls a                          ; get back token value
                pshs b,a                        ; save second argument and token value
                fcb 0x8e                        ; opcode of LDX immediate (skips two bytes)
LB2C7           bsr LB262                       ; force a (
LB2C9           puls b                          ; get offset
                ldx COMVEC+8                    ; get jump table pointer
LB2CE           abx                             ; add offset into table
                jsr [,x]                        ; go process function
                jmp LB143                       ; make sure result is numeric
; operator OR
LB2D4           skip1lda                        ; set flag to nonzero to signal OR
; operator AND
LB2D5           clra                            ; set flag to zero to signal AND
                sta TMPLOC                      ; save AND/OR flag
                jsr INTCNV                      ; convert second argument to intenger
                std CHARAC                      ; save it
                jsr LBC4A                       ; move first argument to FPA0
                jsr INTCNV                      ; convert first argument to integer
                tst TMPLOC                      ; is it AND or OR?
                bne LB2ED                       ; brif OR
                anda CHARAC                     ; do the bitwise AND
                andb ENDCHR
                bra LB2F1                       ; finish up
LB2ED           ora CHARAC                      ; do the bitwise OR
                orb ENDCHR
LB2F1           jmp GIVABF                      ; return integer result
; relational comparision operators
LB2F4           jsr LB148                       ; TM error if type mismatch
                BNE LB309                       ; brif we have a string comparison
                lda FP1SGN                      ; pack FPA1
                ora #0x7f
                anda FPA1
                sta FPA1
                ldx #FP1EXP                     ; point to packed FPA1
                jsr LBC96                       ; compare FPA0 to FPA1
                bra LB33F                       ; handle truth comparison
LB309           clr VALTYP                      ; the result of a comparison is always a number
                dec TRELFL                      ; remove the string flag from the comparison data
                jsr LB657                       ; get string details for second argument
                stb STRDES                      ; save them in the temporary string descriptor
                stx STRDES+2
                ldx FPA1+2                      ; get pointer to first argument descriptor
                jsr LB659                       ; get string details for second argument
                lda STRDES                      ; get length of second argument
                pshs b                          ; save length of first argument
                suba ,s+                        ; now A is the difference in string lengths
                beq LB328                       ; brif string lengths are equal
                lda #1                          ; flag for second argument is longer than first
                bcc LB328                       ; brif second string is longer than first
                ldb STRDES                      ; get length of second string (shorter)
                nega                            ; invert default comparison result
LB328           sta FP0SGN                      ; save default truth flag
                ldu STRDES+2                    ; get pointer to start of second string
                incb                            ; compensate for DECB
LB32D           decb                            ; have we compared everything?
                bne LB334                       ; brif not
                ldb FP0SGN                      ; get default truth value
                bra LB33F                       ; decide comparison truth
LB334           lda ,x+                         ; get byte from first argument
                cmpa ,u+                        ; compare with second argument
                beq LB32D                       ; brif equal - keep comparing
                ldb #0xff                       ; negative if first string is > second
                bcc LB33F                       ; brif string A > string B
                negb                            ; invert result
LB33F           addb #1                         ; convert to 0,1,2
                rolb                            ; shift left - now it's 4,2,1 for <, =, >
                andb RELFLG                     ; keep only the truth we care about
                beq LB348                       ; brif no matching bits - it's false
                ldb #0xff                       ; set true
LB348           jmp LBC7C                       ; convert result to FP and return it
; DIM command
LB34B           jsr SYNCOMMA                    ; make sure there's a comma between variables
DIM             ldb #1                          ; flag that we're dimensioning
                bsr LB35A                       ; go allocate the variable
                jsr GETCCH                      ; are we done?
                bne LB34B                       ; brif not
                rts
; This routine parses a variable. For scalars, it will return a NULL string or 0 value number
; if it is called from "evaluate term". Otherwise, it allocates the variable. For arrays, it will
; allocate a default sized array if dimensioning is not underway and then attempt to look up
; the requested coordinates in that array. Otherwise, it will allocate an array based on the
; specified dimension values.
LB357           clrb                            ; flag that we're not setting up an array
                jsr GETCCH
LB35A           stb DIMFLG                      ; save dimensioning flag
LB35C           sta VARNAM                      ; save first character of variable name
                jsr GETCCH                      ; get input character (why? we already have it)
                bsr LB3A2                       ; set carry if not alpha
                lbcs LB277                      ; brif our variable doesn't start with a letter
                clrb                            ; default second variable character to NUL
                stb VALTYP                      ; set value type to numeric
                jsr GETNCH                      ; get second character
                bcs LB371                       ; brif numeric - numbers are allowed
                bsr LB3A2                       ; set carry if not alpha
                bcs LB37B                       ; brif not alpha
LB371           tfr a,b                         ; save set second character of variable name
LB373           jsr GETNCH                      ; get an input character
                bcs LB373                       ; brif numeric - still in variable name
                bsr LB3A2                       ; set carry if not alpha
                bcc LB373                       ; brif alpha - still in variable name
LB37B           cmpa #'$                        ; do we have the string sigil?
                bne LB385                       ; brif not
                com VALTYP                      ; set value type to string
                addb #0x80                      ; set bit 7 of second variable character to indicate string
                jsr GETNCH                      ; eat the sigil
LB385           stb VARNAM+1                    ; save second variable name character
                ora ARYDIS                      ; merge array disable flag (will set bit 7 of input character if no arrays)
                suba #'(                        ; do we have a subscript?
                lbeq LB404                      ; brif so
                clr ARYDIS                      ; disable the array disable flag - it's single use
                ldx VARTAB                      ; point to the start of the variable table
                ldd VARNAM                      ; get variable name
LB395           cmpx ARYTAB                     ; are we at the top of the variable table?
                beq LB3AB                       ; brif so
                cmpd ,x++                       ; does the variable name match (and move pointer to variable data)
                beq LB3DC                       ; brif so
                leax 5,x                        ; move to next table entry
                bra LB395                       ; see if we have a match
; Set carry if not upper case alpha
LB3A2           cmpa #'A                        ; set C if less than A
                bcs LB3AA                       ; brif less than A
                suba #'Z+1                      ; set C if greater than Z
                suba #-('Z+1)
LB3AA           rts
LB3AB           ldx #ZERO                       ; point to empty location (NULL/0 value)
                ldu ,s                          ; get caller address
                cmpu #LB287                     ; coming from "evaluate term"?
                beq LB3DE                       ; brif so - don't allocate
                ldd ARYEND                      ; get end of arrays
                std V43                         ; save as top of source block
                addd #7                         ; 7 bytes per scalar entry
                std V41                         ; save as top of destination block
                ldx ARYTAB                      ; get bottom of arrays
                stx V47                         ; save as bottom of source block
                jsr LAC1E                       ; move the arrays up to make a hole
                ldx V41                         ; get new top of arrays
                stx ARYEND                      ; set new end of arrays
                ldx V45                         ; get bottom of destination block
                stx ARYTAB                      ; set as new start of arrays
                ldx V47                         ; get old end of variables
                ldd VARNAM                      ; get name of variable
                std ,x++                        ; set variable name and advance X to the value
                clra                            ; zero out the variable value
                clrb
                std ,x
                std 2,x
                sta 4,x
LB3DC           stx VARPTR                      ; save descriptor address of return value
LB3DE           rts
; Various integer conversion routines
LB3DF           fcb 0x90,0x80,0x00,0x00,0x00    ; FP constant -32768
LB3E4           jsr GETNCH                      ; fetch input character
LB3E6           jsr LB141                       ; evaluate numeric expression
LB3E9           lda FP0SGN                      ; get sign of value
                bmi LB44A                       ; brif negative (raise FC error)
INTCNV          jsr LB143                       ; TM error if string
                lda FP0EXP                      ; get exponent
                cmpa #0x90                      ; is it within the range for a 16 bit integer?
                blo LB3FE                       ; brif smaller than 32768
                ldx #LB3DF                      ; point to -32678 constant
                jsr LBC96                       ; is FPA0 equal to -32768?
                bne LB44A                       ; brif not - magnitude is too far negative
LB3FE           jsr LBCC8                       ; move binary point to the right of FPA0 and correct sign
                ldd FPA0+2                      ; get the resulting integer
                rts
LB404           ldd DIMFLG                      ; get dimensioning flag and variable type
                pshs b,a                        ; save them (to avoid issues while evaluating dimension values)
                nop                             ; dead space caused by 1.2 revision
                clrb                            ; reset dimension counter
LB40A           ldx VARNAM                      ; get variable name
                pshs x,b                        ; save dimension counter and variable name
                bsr LB3E4                       ; evaluate a dimension value (and skip either ( or ,)
                puls b,x,y                      ; get variable name, dimension counter, and dimensioning/type flag
                stx VARNAM                      ; restore variable name
                ldu FPA0+2                      ; get dimension size/index
                pshs u,y                        ; save dimension size and dimensioning/type flag
                incb                            ; bump dimension counter
                jsr GETCCH                      ; get what's after the dimension count
                cmpa #',                        ; do we have another dimension?
                beq LB40A                       ; brif so - parse it
                stb TMPLOC                      ; save dimension counter
                jsr LB267                       ; make sure we have a )
                puls a,b                        ; get back variable type and dimensioning flag
                std DIMFLG                      ; restore variable type and dimensioning flag
                ldx ARYTAB                      ; get start of arrays
LB42A           cmpx ARYEND                     ; are we at the end of the array table
                beq LB44F                       ; brif so
                ldd VARNAM                      ; get variable name
                cmpd ,x                         ; does it match?
                beq LB43B                       ; brif so
                ldd 2,x                         ; get length of this array
                leax d,x                        ; move to next array
                bra LB42A                       ; go check another entry
LB43B           ldb #2*9                        ; code for redimensioned array error
                lda DIMFLG                      ; are we dimensioning?
                bne LB44C                       ; brif so - raise error
                ldb TMPLOC                      ; get number of dimensions given
                cmpb 4,x                        ; does it match?
                beq LB4A0                       ; brif so
LB447           ldb #8*2                        ; raise "bad subscript"
                skip2
LB44A           ldb #4*2                        ; raise "illegal function call"
LB44C           jmp LAC46                       ; raise error
LB44F           ldd #5                          ; 5 bytes per array entry
                std COEFPT                      ; initialize array size to entry size
                ldd VARNAM                      ; get variable name
                std ,x                          ; set array name
                ldb TMPLOC                      ; get dimension count
                stb 4,x                         ; set dimension count
                jsr LAC33                       ; make sure we haven't overflowed memory
                stx V41                         ; save array descriptor address
LB461           ldb #11                         ; default dimension value (zero-based, gives max index of 10)
                clra                            ; zero extend (??? why not LDD above?)
                tst DIMFLG                      ; are we dimensioning?
                beq LB46D                       ; brif not
                puls a,b                        ; get dimension size
                addd #1                         ; account for zero based indexing
LB46D           std 5,x                         ; save dimension size
                bsr LB4CE                       ; multiply by accumulated array size
                std COEFPT                      ; save new array size
                leax 2,x                        ; move to next dimension
                dec TMPLOC                      ; have we done all dimensions?
                bne LB461                       ; brif not
                stx TEMPTR                      ; save end of array descriptor (minus 5)
                addd TEMPTR                     ; add total size of array to address of descriptor
                lbcs LAC44                      ; brif it overflows memory
                tfr d,x                         ; save end of array for later
                jsr LAC37                       ; does array fit in memory?
                subd #STKBUF-5                  ; subtract out the "stack fudge factor" but add 5 to the result
                std ARYEND                      ; save new end of arrays
                clra                            ; set up for clearing
LB48C           leax -1,x                       ; move back one
                sta 5,x                         ; blank out a byte in the array data
                cmpx TEMPTR                     ; have we reached the array header?
                bne LB48C                       ; brif not
                ldx V41                         ; get address of start of descriptor
                lda ARYEND                      ; get MSB of end of array back (B still has LSB)
                subd V41                        ; subtract start of descriptor
                std 2,x                         ; save length of array in array header
                lda DIMFLG                      ; are we dimensioning?
                bne LB4CD                       ; brif so - we're done
LB4A0           ldb 4,x                         ; get number of dimensions
                stb TMPLOC                      ; initialize counter
                clra                            ; initialize accumulated offset
                clrb
LB4A6           std COEFPT                      ; save accumulated offset
                puls a,b                        ; get desired index
                std FPA0+2                      ; save it
                cmpd 5,x                        ; is it in range for this dimension?
                bhs LB4EB                       ; brif not
                ldu COEFPT                      ; get accumulated offset
                beq LB4B9                       ; brif first dimension
                bsr LB4CE                       ; multiply accumulated offset by dimension length
                addd FPA0+2                     ; add in offset into this dimension
LB4B9           leax 2,x                        ; move to next dimension in header
                dec TMPLOC                      ; done all dimensions?
                bne LB4A6                       ; brif not
                std ,--s                        ; save D for multiply by 5 (should be pshs d)
                aslb                            ; times 2
                rola
                aslb                            ; times 4
                rola
                addd ,s++                       ; times 5
                leax d,x                        ; add in offset from start of array data
                leax 5,x                        ; offset to end of header
                stx VARPTR                      ; save pointer to element data
LB4CD           rts
; multiply 16 bit number at 5,x by the 16 bit number in COEFPT; return result in D; BS error if carry
LB4CE           lda #16                         ; 16 shifts to do a multiply
                sta V45                         ; save shift counter
                ldd 5,x                         ; get multiplier
                std BOTSTK                      ; save it
                clra                            ; zero out product
                clrb
LB4D8           aslb                            ; shift product left
                rola
                bcs LB4EB                       ; brif we have a carry
                asl COEFPT+1                    ; shift other factor left
                rol COEFPT
                bcc LB4E6                       ; brif no carry - this bit position is 0
                addd BOTSTK                     ; add in multiplier at this bit position
                bcs LB4EB                       ; brif carry - do an error
LB4E6           dec V45                         ; have we done all 16 bits?
                bne LB4D8                       ; brif not
                rts
LB4EB           jmp LB447                       ; raise a BS error
; MEM function
; BUG: this doesn't account for the STKBUF fudge factor used for memory availability checks
MEM             tfr s,d                         ; get stack pointer where we can do math
                subd ARYEND                     ; calculate number of bytes between the stack and the top of arrays
                skip1                           ; return result
; Convert unsigned value in B to FP
LB4F3           clra                            ; zero extend
; Convert signed value in D to FP
GIVABF          clr VALTYP                      ; set value type to numeric
                std FPA0                        ; save value in FPA0
                ldb #0x90                       ; exponent for top two bytes to be an integer
                jmp LBC82                       ; finish conversion to integer
; STR$ function
STR             jsr LB143                       ; make sure we have a number
                ldu #STRBUF+2                   ; convert FP number to string in temporary string buffer
                jsr LBDDC
                leas 2,s                        ; don't return to the function evaluator (which will do a numeric type check)
                ldx #STRBUF+1                   ; point to number string
                bra LB518                       ; to stash the string in string space and return to the "evaluate term" caller
; Reserve B bytes of string space. Return start in X and FRESPC
LB50D           stx V4D                         ; save X somewhere in case the caller needs it
LB50F           bsr LB56D                       ; allocate string space
LB511           stx STRDES+2                    ; save pointer to allocated space in the temporary descriptor
                stb STRDES                      ; save length in the temporary descriptor
                rts
LB516           leax -1,x                       ; move pointer back one (to compensate for the increment below)
; Scan from X until either NUL or one of the string terminators is found
LB518           lda #'"                         ; set terminator to be string delimiter
LB51A           sta CHARAC                      ; set both delimiters
                sta ENDCHR
LB51E           leax 1,x                        ; move to next character        
                stx RESSGN                      ; save start of string
                stx STRDES+2                    ; save start of string in the temporary string descriptor
                ldb #-1                         ; initialize length counter to -1 (compensate for initial INCB)
LB526           incb                            ; bump string length
                lda ,x+                         ; get character from string
                beq LB537                       ; brif end of line
                cmpa CHARAC                     ; is it delimiter #1?
                beq LB533                       ; brif so
                cmpa ENDCHR                     ; is it delimiter #2?
                bne LB526                       ; brif not - keep scanning
LB533           cmpa #'"                        ; string delimiter?
                beq LB539                       ; brif so - don't move pointer back
LB537           leax -1,x                       ; move pointer back (so we don't consume the delimiter)
LB539           stx COEFPT                      ; save end of string address
                stb STRDES                      ; save string length
                ldu RESSGN                      ; get start of string
                cmpu #STRBUF+2                  ; is it at the start of the string buffer?
                bhi LB54C                       ; brif so - don't copy it to string space
                bsr LB50D                       ; allocate string space
                ldx RESSGN                      ; point to beginning of the string
                jsr LB645                       ; copy string data (B bytes) from (X) to (FRESPC)
; Put temporary string descriptor on the string stack
LB54C           ldx TEMPPT                      ; get top of string stack
                cmpx #CFNBUF                    ; is the string stack full?
                bne LB558                       ; brif not
                ldb #15*2                       ; code for "string formula too complex"
LB555           jmp LAC46                       ; raise error
LB558           lda STRDES                      ; get string length
                sta 0,x                         ; save it in the string stack descriptor
                ldd STRDES+2                    ; get string data pointer
                std 2,x                         ; save in string stack descriptor
                lda #0xff                       ; set value type to string
                sta VALTYP
                stx LASTPT                      ; set pointer to last used entry on the string stack
                stx FPA0+2                      ; set pointer to descriptor in the current evaluation value
                leax 5,x                        ; advance string stack pointer
                stx TEMPPT
                rts
; Reserve B bytes in string space. If there isn't enough space, try compacting string space and
; then try the allocation again. If it still fails, raise OS error.
LB56D           clr GARBFL                      ; flag that compaction not yet done
LB56F           clra                            ; zero extend the length
                pshs d                          ; save requested string length
                ldd STRTAB                      ; get current bottom of strings
                subd ,s+                        ; calculate new bottom of strings and remove zero extension
                cmpd FRETOP                     ; does the string fit?
                blo LB585                       ; brif not - try compaction
                std STRTAB                      ; save new bottom of strings
                ldx STRTAB                      ; get bottom of strings
                leax 1,x                        ; now X points to the real start of the allocated space
                stx FRESPC                      ; save the string pointer
                puls b,pc                       ; restore length and return
LB585           ldb #2*13                       ; code for out of string space
                com GARBFL                      ; have we compacted string space yet?
                beq LB555                       ; brif so - raise error
                bsr LB591                       ; compact string space
                puls b                          ; get back string length
                bra LB56F                       ; go try allocation again
; Compact string space
; This is an O(n^2) algorithm. It first searches all extant strings for the highest address data pointer
; that hasn't already been moved into the freshly compacted string space. If then moves that string data
; up to the highest address it can go to. It repeats this process over and over until it finds no string
; that isn't already in the compacted space. While doing this, it has to search all strings on the string
; stack (this is why the string stack is needed - so we can track anonymous strings), all scalar string
; variables, and *every* entry in every string array.
LB591           ldx MEMSIZ                      ; get to of string space
LB593           stx STRTAB                      ; save top of uncompacted stringspace
                clra                            ; zero out D and reset pointer to discovered variable to NULL
                clrb
                std V4B
                ldx FRETOP                      ; point to bottom of string space
                stx V47                         ; save as lowest match address (match will be higher)
                ldx #STRSTK                     ; point to start of string stack
LB5A0           cmpx TEMPPT                     ; are we at the top of the string stack?
                beq LB5A8                       ; brif so - done with the string stack
                bsr LB5D8                       ; check for string in uncompacted space (and advance pointer)
                bra LB5A0                       ; check another on the string stack
LB5A8           ldx VARTAB                      ; point to start of scalar variables
LB5AA           cmpx ARYTAB                     ; end of scalars?
                beq LB5B2                       ; brif so
                bsr LB5D2                       ; check for string in uncompacted space and advance pointer
                bra LB5AA                       ; check another variable
LB5B2           stx V41                         ; save address of end of variables (address of first array)
LB5B4           ldx V41                         ; get start of the next array
LB5B6           cmpx ARYEND                     ; end of arrays?
                beq LB5EF                       ; brif so
                ldd 2,x                         ; get length of array
                addd V41                        ; add to start of array
                std V41                         ; save address of next array
                lda 1,x                         ; get second character of variable name
                bpl LB5B4                       ; brif numeric
                ldb 4,x                         ; get number of dimensions
                aslb                            ; two bytes per dimension size
                addb #5                         ; add in fixed overhead for array descriptor
                abx                             ; now X points to first array element
LB5CA           cmpx V41                        ; at the start of the next array?
                beq LB5B6                       ; brif so - go handle another array
                bsr LB5D8                       ; check for string in uncompacted space (and advance pointer)
                bra LB5CA                       ; process next array element
LB5D2           lda 1,x                         ; get second character of variable name
                leax 2,x                        ; move to variable data
                bpl LB5EC                       ; brif numeric
LB5D8           ldb ,x                          ; get length of string
                beq LB5EC                       ; brif NULL - don't need to check data pointer
                ldd 2,x                         ; get data pointer
                cmpd STRTAB                     ; is it in compacted string space?
                bhi LB5EC                       ; brif so
                cmpd V47                        ; is it better match than previous best?
                bls LB5EC                       ; brif not
                stx V4B                         ; save descriptor address of best match
                std V47                         ; save new best data pointer match
LB5EC           leax 5,x                        ; move to next descriptor
LB5EE           rts
LB5EF           ldx V4B                         ; get descriptor address of the matched string
                beq LB5EE                       ; brif we didn't find one - we're done
                clra                            ; zero extend length
                ldb ,x                          ; get string length
                decb                            ; subtract one (we won't have a NULL string here)
                addd V47                        ; now D points to the address of the end of the string data
                std V43                         ; save as top address of move
                ldx STRTAB                      ; set top of uncompacted space as destination
                stx V41
                jsr LAC20                       ; move string to top of uncompactedspace
                ldx V4B                         ; point to string descriptor
                ldd V45                         ; get new data pointer address
                std 2,x                         ; update descriptor
                ldx V45                         ; get bottom of copy destination
                leax -1,x                       ; move back below it
                jmp LB593                       ; go search for another string to move (and set new bottom of string space)
; Concatenate two strings. We come here directly from the operator handler rather than via a JSR.
LB60F           ldd FPA0+2                      ; get string descriptor for the first string
                pshs d                          ; save it
                jsr LB223                       ; evaluate a second string (concatenation is left associative)
                jsr LB146                       ; make sure we have a string
                puls x                          ; get back first string descriptor
                stx RESSGN                      ; save it
                ldb ,x                          ; get length of first string
                ldx FPA0+2                      ; get pointer to second string
                addb ,x                         ; add length of second string
                bcc LB62A                       ; brif combined length is OK
                ldb #2*14                       ; raise string too long error
                jmp LAC46
LB62A           jsr LB50D                       ; reserve room for new string
                ldx RESSGN                      ; get descriptor address of the first string
                ldb ,x                          ; get length of first string
                bsr LB643                       ; copy it to string space
                ldx V4D                         ; get descriptor address of second string
                bsr LB659                       ; get string details for second string
                bsr LB645                       ; copy second string into new string space
                ldx RESSGN                      ; get pointer to first string
                bsr LB659                       ; remove it from the string stack if possible
                jsr LB54C                       ; put new string on the string stack
                jmp LB168                       ; return to expression evaluator
; Copy B bytes to space pointed to by FRESPC
LB643           ldx 2,x                         ; get source address from string descriptor
LB645           ldu FRESPC                      ; get destination address
                incb                            ; compensate for decb
                bra LB64E                       ; do the copy
LB64A           lda ,x+                         ; copy a byte
                sta ,u+
LB64E           decb                            ; done yet?
                bne LB64A                       ; brif not
                stu FRESPC                      ; save destination pointer
                rts
; Fetch details of string in FPA0+2 and remove from the string stack if possible
LB654           jsr LB146                       ; make sure we have a string
LB657           ldx FPA0+2                      ; get descriptor pointer
LB659           ldb ,x                          ; get length of string
                bsr LB675                       ; see if it's at the top of the string stack and remove it if so
                bne LB672                       ; brif not removed
                ldx 5+2,x                       ; get start address of string just removed
                leax -1,x                       ; move pointer down 1
                cmpx STRTAB                     ; is it at the bottom of string space?
                bne LB66F                       ; brif not
                pshs b                          ; save length
                addd STRTAB                     ; add length to start of strings (A was cleared previously)
                std STRTAB                      ; save new string space start (deallocated space for this string)
                puls b                          ; get back string length
LB66F           leax 1,x                        ; restore pointer to pointing at the actual string data
                rts
LB672           ldx 2,x                         ; get data pointer for the string
                rts
; Remove string pointed to by X from the string stack if it is at the top of the stack; return with
; A clear and Z set if string removed
LB675           cmpx LASTPT                     ; is it at the top of the string stack?
                bne LB680                       ; brif not - do nothing
                stx TEMPPT                      ; save new top of stack
                leax -5,x                       ; move the "last" pointer back as well
                stx LASTPT
                clra                            ; flag string removed
LB680           rts
; LEN function
LEN             bsr LB686                       ; get string details
LB683           jmp LB4F3                       ; return unsigned length in B
LB686           bsr LB654                       ; get string details and remove from string stack
                clr VALTYP                      ; set value type to numeric
                tstb                            ; set flags according to length
                rts
; CHR$ function
CHR             jsr LB70E                       ; get 8 bit unsigned integer to B
LB68F           ldb #1                          ; allocate a one byte string
                jsr LB56D
                lda FPA0+3                      ; get character code
                jsr LB511                       ; save reserved string details in temp descriptor
                sta ,x                          ; put character in string
LB69B           leas 2,s                        ; don't go back to function handler - avoid numeric type check
LB69D           jmp LB54C                       ; return temporary string on string stack
; ASC function
ASC             bsr LB6A4                       ; get first character of argument
                bra LB683                       ; return unsigned code in B
LB6A4           bsr LB686                       ; fetch string details
                beq LB706                       ; brif NULL string
                ldb ,x                          ; get character at start of string
                rts
; LEFT$ function
LEFT            bsr LB6F5                       ; get arguments from the stack
LB6AD           clra                            ; clear pointer offset (set to start of string)
LB6AE           cmpb ,x                         ; are we asking for more characters than there are in the string?
                bls LB6B5                       ; brif not
                ldb ,x                          ; only return the number that are in the string
                clra                            ; force starting offset to be the start of the string
LB6B5           pshs b,a                        ; save offset and length
                jsr LB50F                       ; reserve space in string space
                ldx V4D                         ; point to original string descriptor
                bsr LB659                       ; get string details
                puls b                          ; get string offset
                abx                             ; now X points to the start of the data to copy
                puls b                          ; get length of copy
                jsr LB645                       ; copy the data to the allocated space
                bra LB69D                       ; return temp string on string stack
; RIGHT$ function
RIGHT           bsr LB6F5                       ; get arguments from stack
                suba ,x                         ; subtract length of original string from desired length
                nega                            ; now A is offset into old string where we start copying
                bra LB6AE                       ; go handle everything else
; MID$ function
MID             ldb #255                        ; default length is the whole string
                stb FPA0+3                      ; save it
                jsr GETCCH                      ; see what we have after offset
                cmpa #')                        ; end of function?
                beq LB6DE                       ; brif so - no length
                jsr SYNCOMMA                    ; force a comma
                bsr EVALEXPB                    ; get length parameter
LB6DE           bsr LB6F5                       ; get string and offset parameters from the stack
                beq LB706                       ; brif we have a 0 offset requested (string offsets are 1-based)
                clrb                            ; clear length counter
                deca                            ; subtract one from position parameter (we work on 0-based, param is 1-based)
                cmpa ,x                         ; is start greater than length of string?
                bhs LB6B5                       ; brif so - return NULL string
                tfr a,b                         ; save absolute position parameter
                subb ,x                         ; now B is postition less length
                negb                            ; now B is amount of string to copy
                cmpb FPA0+3                     ; is it less than the length requested?
                bls LB6B5                       ; brif so
                ldb FPA0+3                      ; set length to the requested length
                bra LB6B5                       ; go finish up copying the substring
; Common routine for LEFT$, RIGHT$, MID$ - check for ) and fetch string data and first parameter
; from the stack. These were evaluated in the function evaluation handler. (It's not clear that doing
; it that way is actually beneficial. However, this is what the ROM designers did, so here we are.)
LB6F5           jsr LB267                       ; make sure we have )
                ldu ,s                          ; get return address - we're going to mess with the stack
                ldx 5,s                         ; get address of string descriptor
                stx V4D                         ; save descriptor adddress
                lda 4,s                         ; get first numeric parameter in both A and B
                ldb 4,s
                leas 7,s                        ; clean up stack
                tfr u,pc                        ; return to original caller
LB706           jmp LB44A                       ; raise FC error
; Evaluate an unsigned 8 bit expression to B
LB709           jsr GETNCH                      ; move to next character
EVALEXPB        jsr LB141                       ; evaluate a numeric expression
LB70E           jsr LB3E9                       ; convert to integer in D
                tsta                            ; are we negative or > 255?
                bne LB706                       ; brif so - FC error
                jmp GETCCH                      ; fetch current input character and return
; VAL function
VAL             jsr LB686                       ; get string details
                lbeq LBA39                      ; brif NULL string - return 0
                ldu CHARAD                      ; get input pointer so we can replace it later
                stx CHARAD                      ; point interpreter at string data
                abx                             ; calculate end address of the string
                lda ,x                          ; get byte after the end of the string
                pshs u,x,a                      ; save end of string address, input pointer, and character after end of string
                clr ,x                          ; put a NUL after the string (stops the number interpreter)
                jsr GETCCH                      ; get input character at start of string
                jsr LBD12                       ; evaluate numeric expression in string
                puls a,x,u                      ; get back saved character and pointers
                sta ,x                          ; restore byte after string
                stu CHARAD                      ; restore interpeter's input pointer
                rts
; Evaluate unsigned expression to BINVAL, then evaluate an unsigned expression to B
LB734           bsr LB73D                       ; evaluate expression
                stx BINVAL                      ; save result
LB738           jsr SYNCOMMA                    ; make sure there's a comma
                bra EVALEXPB                    ; evaluate unsigned expression to B
; Evaluate unsigned expression in X
LB73D           jsr LB141                       ; evaluate numeric expression
LB740           lda FP0SGN                      ; is it negative?
                bmi LB706                       ; brif so
                lda FP0EXP                      ; get exponent
                cmpa #0x90                      ; largest possible exponent for 16 bits
                bhi LB706                       ; brif too large
                jsr LBCC8                       ; move binary point to right of FPA0
                ldx FPA0+2                      ; get resulting unsigned value
                rts
; PEEK function
PEEK            bsr LB740                       ; get address to X
                ldb ,x                          ; get the value at that address
                jmp LB4F3                       ; return B as unsigned value
; POKE function
POKE            bsr LB734                       ; evaluate address and byte value
                ldx BINVAL                      ; get address
                stb ,x                          ; put value there
                rts
; LLIST command
LLIST           ldb #-2                         ; set output device to printer
                stb DEVNUM
                jsr GETCCH                      ; reset flags for input character and fall through to LIST
; LIST command
LIST            pshs cc                         ; save zero flag (end of statement)
                jsr LAF67                       ; parse line number
                jsr LAD01                       ; find address of that line
                stx LSTTXT                      ; save that address as the start of the list
                puls cc                         ; get back ent of statement flag
                beq LB784                       ; brif end of line - list whole program
                jsr GETCCH                      ; are we at the end of the line (one number)?
                beq LB789                       ; brif end of line
                cmpa #0xac                      ; is it "-"?
                bne LB783                       ; brif not
                jsr GETNCH                      ; eat the "-"
                beq LB784                       ; brif no second number - list to end of program
                jsr LAF67                       ; evaluate the second number
                beq LB789                       ; brif illegal number
LB783           rts
LB784           ldu #0xffff                     ; this will cause listing to do the entire program
                stu BINVAL
LB789           leas 2,s                        ; don't return to the caller - we'll jump back to the main loop
                ldx LSTTXT                      ; get address of line to list
LB78D           jsr LB95C                       ; do a newline if needed
                jsr LA549                       ; do a break check
                ldd ,x                          ; get address of next line
                bne LB79F                       ; brif not end of program
LB797           jsr LA42D                       ; close output file
                clr DEVNUM                      ; reset device to screen
                jmp LAC73                       ; go back to immediate mode
LB79F           stx LSTTXT                      ; save new line address
                ldd 2,x                         ; get line number of this line
                cmpd BINVAL                     ; is it above the end line?
                bhi LB797                       ; brif so - return
                jsr LBDCC                       ; display line number
                jsr LB9AC                       ; put a space after it
                ldx LSTTXT                      ; get line address
                bsr LB7C2                       ; detokenize the line
                ldx [LSTTXT]                    ; get pointer to next line
                ldu #LINBUF+1                   ; point to start of detokenized line
LB7B9           lda ,u+                         ; get byte from detokenized line
                beq LB78D                       ; brif end of line
                jsr LB9B1                       ; output character
                bra LB7B9                       ; handle next character
; Detokenize a line from (X) to the line input buffer
LB7C2           jsr RVEC24                      ; do the RAM hook dance
                leax 4,x                        ; move past next line pointer and line number
                ldy #LINBUF+1                   ; point to line input buffer (destination)
LB7CB           lda ,x+                         ; get character from tokenized line
                beq LB820                       ; brif end of input
                bmi LB7E6                       ; brif it's a token
                cmpa #':                        ; colon?
                bne LB7E2                       ; brif not
                ldb ,x                          ; get what's after the colon
                cmpb #0x84                      ; ELSE?
                beq LB7CB                       ; brif so - suppress the colon
                cmpb #0x83                      ; '?
                beq LB7CB                       ; brif so - suppress the colon
                skip2
LB7E0           lda #'!                         ; placeholder for unknown token
LB7E2           bsr LB814                       ; stow output character
                bra LB7CB                       ; go process another input character
LB7E6           ldu #COMVEC-10                  ; point to command interptation table
                cmpa #0xff                      ; is it a function?
                bne LB7F1                       ; brif not
                lda ,x+                         ; get function token
                leau 5,u                        ; shift to the function half of the interpretation tables
LB7F1           anda #0x7f                      ; remove token bias
LB7F3           leau 10,u                       ; move to next command/function table
                tst ,u                          ; is this table active?
                beq LB7E0                       ; brif not - use place holder
LB7F9           suba ,u                         ; subtract number of tokens handled by this table entry
                bpl LB7F3                       ; brif this token isn't handled here
                adda ,u                         ; undo extra subtraction
                ldu 1,u                         ; get reserved word list for this table
LB801           deca                            ; are we at the right entry?
                bmi LB80A                       ; brif so
LB804           tst ,u+                         ; end of entry?
                bpl LB804                       ; brif not
                bra LB801                       ; see if we're there yet
LB80A           lda ,u                          ; get character from wordlist
                bsr LB814                       ; put character in the buffer
                tst ,u+                         ; end of word?
                bpl LB80A                       ; brif not
                bra LB7CB                       ; go handle another input character
LB814           cmpy #LINBUF+LBUFMX             ; is there room?
                bhs LB820                       ; brif not
                anda #0x7f                      ; lose bit 7
                sta ,y+                         ; save character in output
                clr ,y                          ; make sure there's always a NUL terminator
LB820           rts
; Tokenize the line that the input pointer is pointing to; put result in the line input buffer; return
; length in D
LB821           jsr RVEC23                      ; do the RAM hook dance
                ldx CHARAD                      ; get input pointer
                ldu #LINBUF                     ; set destination pointer
LB829           clr V43                         ; clear alpha string flag
                clr V44                         ; clear DATA flag
LB82D           lda ,x+                         ; get input character
                beq LB852                       ; brif end of input
                tst V43                         ; are we handling an alphanumeric string?
                beq LB844                       ; brif not
                jsr LB3A2                       ; set carry if not alpha
                bcc LB852                       ; brif alpha
                cmpa #'0                        ; is it below the digits?
                blo LB842                       ; brif so
                cmpa #'9                        ; is it within the digits?
                bls LB852                       ; brif so
LB842           clr V43                         ; flag that we're past the alphanumeric string
LB844           cmpa #0x20                      ; space?
                beq LB852                       ; brif so - keep it
                sta V42                         ; save scan delimiter
                cmpa #'"                        ; string delimiter?
                beq LB886                       ; brif so - copy until another "
                tst V44                         ; doing "DATA"?
                beq LB86B                       ; brif not
LB852           sta ,u+                         ; put character in output
                beq LB85C                       ; brif end of input
                cmpa #':                        ; colon?
                beq LB829                       ; brif so - reset DATA and alpha string flags
LB85A           bra LB82D                       ; go process another input character
LB85C           clr ,u+                         ; put a double NUL at the end
                clr ,u+
                tfr u,d                         ; calculate length of result (includes double NUL and an extra two bytes)
                subd #LINHDR
                ldx #LINBUF-1                   ; point to one before the output
                stx CHARAD                      ; set input pointer there
                rts
LB86B           cmpa #'?                        ; print abbreviation?
                bne LB873                       ; brif not
                lda #0x87                       ; token for PRINT
                bra LB852                       ; go stash it
LB873           cmpa #''                        ; REM abbreviation?
                bne LB88A                       ; brif not
                ldd #0x3a83                     ; colon plus ' token
                std ,u++                        ; put it in the output
LB87C           clr V42                         ; set delimiter to NUL
LB87E           lda ,x+                         ; get input
                beq LB852                       ; brif end of line
                cmpa V42                        ; at the delimiter?
                beq LB852                       ; brif so
LB886           sta ,u+                         ; save in output
                bra LB87E                       ; keep scanning for delimiter
LB88A           cmpa #'0                        ; is it below digits?
                blo LB892                       ; brif so
                cmpa #';+1                      ; is it digit, colon, or semicolon?
                blo LB852                       ; brif so
LB892           leax -1,x                       ; move input pointer back one (to point at this input character)
                pshs u,x                        ; save input and output pointers
                clr V41                         ; set token type to 0 (command)
                ldu #COMVEC-10                  ; point to command interpretation table
LB89B           clr V42                         ; set token counter to 0 (0x80)
LB89D           leau 10,u                       ; 
                lda ,u                          ; get number of reserved words
                beq LB8D4                       ; brif this table isn't active
                ldy 1,u                         ; point to reserved words list
LB8A6           ldx ,s                          ; get input pointer
LB8A8           ldb ,y+                         ; get character from reserved word table
                subb ,x+                        ; compare with input character
                beq LB8A8                       ; brif exact match
                cmpb #0x80                      ; brif it was the last character in word and exact match
                bne LB8EA                       ; brif not
                leas 2,s                        ; remove original input pointer from stack
                puls u                          ; get back output pointer
                orb V42                         ; create token value (B has 0x80 from above)
                lda V41                         ; get token type
                bne LB8C2                       ; brif function
                cmpb #0x84                      ; is it ELSE?
                bne LB8C6                       ; brif not
                lda #':                         ; silently add a colon before ELSE
LB8C2           std ,u++                        ; put two byte token into output
                bra LB85A                       ; go handle more input
LB8C6           stb ,u+                         ; save single byte token
                cmpb #0x86                      ; DATA?
                bne LB8CE                       ; brif not
                inc V44                         ; set DATA flag
LB8CE           cmpb #0x82                      ; REM?
                beq LB87C                       ; brif so - skip over rest of line
LB8D2           bra LB85A                       ; go handle more input
LB8D4           ldu #COMVEC-5                   ; point to interpretation table, function style
LB8D7           com V41                         ; invert token flag
                bne LB89B                       ; brif we haven't already done functions
                puls x,u                        ; restore input and output pointers
                lda ,x+                         ; copy first character
                sta ,u+
                jsr LB3A2                       ; set C if not alpha
                bcs LB8D2                       ; brif not alpha - it isn't a variable
                com V43                         ; set alphanumeric string flag
                bra LB8D2                       ; process more input
LB8EA           inc V42                         ; bump token number
                deca                            ; checked all in this table?
                beq LB89D                       ; brif so
                leay -1,y                       ; unconsume last compared character
LB8F1           ldb ,y+                         ; end of entry?
                bpl LB8F1                       ; brif not
                bra LB8A6                       ; check next reserved word
; PRINT command
PRINT           beq LB958                       ; brif no argument - do a newline
                bsr LB8FE                       ; process print options
                clr DEVNUM                      ; reset output to screen
                rts
LB8FE           cmpa #'@                        ; is it PRINT @?
                bne LB907                       ; brif not
LB902           jsr LA554                       ; move cursor to correct location
LB905           bra LB911                       ; handle some more
LB907           cmpa #'#                        ; device number specified?
                bne LB918                       ; brif not
                jsr LA5A5                       ; parse device number
                jsr LA406                       ; check for valid output file
LB911           jsr GETCCH                      ; get input character
                beq LB958                       ; brif nothing - do newline
                jsr SYNCOMMA                    ; need comma after @ or #
LB918           jsr RVEC9                       ; do the RAM hook boogaloo
LB91B           beq LB965                       ; brif end of input
LB91D           cmpa #0xa4                      ; TAB(?
                beq LB97E                       ; brif so
                cmpa #',                        ; comma (next tab field)?
                beq LB966                       ; brif so
                cmpa #';                        ; semicolon (do not advance print position)
                beq LB997                       ; brif so
                jsr LB156                       ; evaluate expression
                lda VALTYP                      ; get type of value
                pshs a                          ; save it
                bne LB938                       ; brif string
                jsr LBDD9                       ; convert FP number to string
                jsr LB516                       ; parse a string and put on string stack
LB938           bsr LB99F                       ; print string
                puls b                          ; get back variable type
                jsr LA35F                       ; set up print parameters
                tst PRTDEV                      ; is it a display device?
                beq LB949                       ; brif so
                bsr LB958                       ; do a newline
                jsr GETCCH                      ; get input
                bra LB91B                       ; process more print stuff
LB949           tstb                            ; set flags on print position
                bne LB954                       ; brif not at start of line
                jsr GETCCH                      ; get current input
                cmpa #',                        ; comma?
                beq LB966                       ; skip to next tab field if so
                bsr LB9AC                       ; send a space
LB954           jsr GETCCH                      ; get input character
                bne LB91D                       ; brif not end of statement
LB958           lda #0x0d                       ; carriage return
                bra LB9B1                       ; send it to output
LB95C           jsr LA35F                       ; set up print parameters
LB95F           beq LB958                       ; brif width is 0
                lda DEVPOS                      ; get line position
                bne LB958                       ; brif not at start of line
LB965           rts
LB966           jsr LA35F                       ; set up print parameters
                beq LB975                       ; brif line width is 0
                ldb DEVPOS                      ; get line position
                cmpb DEVLCF                     ; at or past last comma field?
                blo LB977                       ; brif so
                bsr LB958                       ; move to next line
                bra LB997                       ; handle more stuff
LB975           ldb DEVPOS                      ; get line position
LB977           subb DEVCFW                     ; subtract a comma field width
                bhs LB977                       ; brif we don't have a remainder yet
                negb                            ; now B is number of of spaces needed
                bra LB98E                       ; go advance
LB97E           jsr LB709                       ; evaluate TAB distance
                cmpa #')                        ; closing )?
                lbne LB277                      ; brif not
                jsr LA35F                       ; set up print parameters
                subb DEVPOS                     ; subtract print position from desired position
                bls LB997                       ; brif we're already past it
LB98E           tst PRTDEV                      ; is it a display device?
                bne LB997                       ; brif not
LB992           bsr LB9AC                       ; output a space
                decb                            ; done enough?
                bne LB992                       ; brif not
LB997           jsr GETNCH                      ; get input character
                jmp LB91B                       ; process more items
; cpoy string from (X-1) to output
STRINOUT        jsr LB518                       ; parse the string
LB99F           jsr LB657                       ; get string details
LB9A2           incb                            ; compensate for decb
LB9A3           decb                            ; done all of the string?
                beq LB965                       ; brif so
                lda ,x+                         ; get character from string
                bsr LB9B1                       ; send to output
                bra LB9A3                       ; go do another character
LB9AC           lda #0x20                       ; space character
                skip2
LB9AF           lda #'?                         ; question mark character
LB9B1           jmp PUTCHR                      ; output character
; The floating point math package and related functions and operations follow from here
; to the end of the Color Basic ROM area
LB9B4           ldx #LBEC0                      ; point to FP constant 0.5
                bra LB9C2                       ; add 0.5 to FPA0
LB9B9           jsr LBB2F                       ; unpack FP data from (X) to FPA1
; subtraction operator
LB9BC           com FP0SGN                      ; invert sign of FPA0 (subtracting is adding the negative)
                com RESSGN                      ; that also inverts the sign differential
                bra LB9C5                       ; go add the negative of FPA0 to FPA1
LB9C2           jsr LBB2F                       ; unpack FP data from (X) to FPA1
; addition operator
LB9C5           tstb                            ; check exponent of FPA0
                lbeq LBC4A                      ; copy FPA1 to FPA0 if FPA0 is 0
                ldx #FP1EXP                     ; point X to FPA1 (first operand) as the operand to denormalize
LB9CD           tfr a,b                         ; put exponent of FPA1 into B
                tstb                            ; is FPA1 0?
                beq LBA3E                       ; brif exponent is 0 - no-op; adding 0 to FPA0
                subb FP0EXP                     ; get difference in exponents - number of bits to shift the smaller mantissa
                beq LBA3F                       ; brif exponents are equal - no need to denormalize
                blo LB9E2                       ; brif FPA0 > FPA1
                sta FP0EXP                      ; replace result exponent with FPA1's (FPA1 is bigger)
                lda FP1SGN                      ; also copy sign over
                sta FP0SGN
                ldx #FP0EXP                     ; point to FPA0 (we need to denormalize the smaller number)
                negb                            ; invert the difference - this is the number of bits to shift the mantissa
LB9E2           cmpb #-8                        ; do we have to shift by a whole byte?
                ble LBA3F                       ; brif so start by shifting whole bytes to the right
                clra                            ; clear overflow byte
                lsr 1,x                         ; shift high bit of mantissa right (LSR will force a zero into the high bit)
                jsr LBABA                       ; shift remainder of mantissa right -B times
LB9EC           ldb RESSGN                      ; get the sign flag
                bpl LB9FB                       ; brif signs are the same (we add the mantissas then)
                com 1,x                         ; complement the mantissa and extra precision bytes
                com 2,x
                com 3,x
                com 4,x
                coma
                adca #0                         ; add one to A (COM sets C); this may cause a carry to enter the ADD below
LB9FB           sta FPSBYT                      ; save extra precision byte
                lda FPA0+3                      ; add the main mantissa bytes (and propage carry from above)
                adca FPA1+3
                sta FPA0+3
                lda FPA0+2
                adca FPA1+2
                sta FPA0+2
                lda FPA0+1
                adca FPA1+1
                sta FPA0+1
                lda FPA0
                adca FPA1
                sta FPA0
                tstb                            ; were signs the same?
                bpl LBA5C                       ; brif so - number may have gotten bigger so normalize if needed
LBA18           bcs LBA1C                       ; brif we had a carry - result is positive?)
                bsr LBA79                       ; do a proper negation of FPA0 mantissa
LBA1C           clrb                            ; clear temporary exponent accumulator
LBA1D           lda FPA0                        ; test high byte of mantissa
                bne LBA4F                       ; brif not 0 - we need to do bit shifting
                lda FPA0+1                      ; shift left 8 bits
                sta FPA0
                lda FPA0+2
                sta FPA0+1
                lda FPA0+3
                sta FPA0+2
                lda FPSBYT
                sta FPA0+3
                clr FPSBYT
                addb #8                         ; account for 8 bits shifted
                cmpb #5*8                       ; shifted 5 bytes worth?
                blt LBA1D                       ; brif not
LBA39           clra                            ; zero out exponent and sign - result is 0
LBA3A           sta FP0EXP                      ; set exponent and sign
                sta FP0SGN
LBA3E           rts
LBA3F           bsr LBAAE                       ; shift FPA0 mantissa to the right
                clrb                            ; clear carry
                bra LB9EC                       ; get on with adding
LBA44           incb                            ; account for one bit shift
                asl FPSBYT                      ; shift mantissa and extra precision left
                rol FPA0+3
                rol FPA0+2
                rol FPA0+1
                rol FPA0
LBA4F           bpl LBA44                       ; brif we haven't got a 1 in bit 7
                lda FP0EXP                      ; get exponent of result
                pshs b                          ; subtract shift count from exponent
                suba ,s+
                sta FP0EXP                      ; save adjusted exponent
                bls LBA39                       ; brif we underflowed - set result to 0
	skip2
LBA5C           bcs LBA66                       ; brif mantissa overflowed
                asl FPSBYT                      ; get bit 7 of expra precision to C (used for round off)
                lda #0                          ; set to 0 without affecting C
                sta FPSBYT                      ; clear out extra precision bits
                bra LBA72                       ; go round off result
LBA66           inc FP0EXP                      ; bump exponent (for a right shift to bring carry in)
                beq LBA92                       ; brif we overflowed
                ror FPA0                        ; shift carry into mantissa, shift right
                ror FPA0+1
                ror FPA0+2
                ror FPA0+3
LBA72           bcc LBA78                       ; brif no round-off needed
                bsr LBA83                       ; add one to mantissa
                beq LBA66                       ; brif carry - need to shift right again
LBA78           rts
LBA79           com FP0SGN                      ; invert sign of value
LBA7B           com FPA0                        ; first do a one's copmlement
                com FPA0+1
                com FPA0+2
                com FPA0+3
LBA83           ldx FPA0+2                      ; add one to mantissa (after one's complement gives two's complement)
                leax 1,x                        ; bump low word
                stx FPA0+2
                bne LBA91                       ; brif no carry from low word
                ldx FPA0                        ; bump high word
                leax 1,x
                stx FPA0
LBA91           rts
LBA92           ldb #2*5                        ; code for overflow
                jmp LAC46                       ; raise error
LBA97           ldx #FPA2-1                     ; point to FPA2
LBA9A           lda 4,x                         ; shift mantissa right by 8 bits
                sta FPSBYT
                lda 3,x
                sta 4,x
                lda 2,x
                sta 3,x
                lda 1,x
                sta 2,x
                lda FPCARY                      ; and handle extra precision on the left
                sta 1,x
LBAAE           addb #8                         ; account for 8 bits shifted
                ble LBA9A                       ; brif more shifts needed
                lda FPSBYT                      ; get sub byte (extra precision)
                subb #8                         ; undo the 8 added above
                beq LBAC4                       ; brif difference is 0
LBAB8           asr 1,x                         ; shift mantissa and sub byte one bit (keep mantissa high bit set)
LBABA           ror 2,x
                ror 3,x
                ror 4,x
                rora
                incb                            ; account for one shift
                bne LBAB8                       ; brif not enought shifts yet
LBAC4           rts
LBAC5           fcb 0x81,0x00,0x00,0x00,0x00    ; packed FP 1.0
LBACA           bsr LBB2F                       ; unpack FP value from (X) to FPA1
; multiplication operator
LBACC           beq LBB2E                       ; brif exponent of FPA0 is 0 (result is 0)
                bsr LBB48                       ; calculate exponent of product
LBAD0           lda #0                          ; zero out mantissa of FPA2
                sta FPA2
                sta FPA2+1
                sta FPA2+2
                sta FPA2+3
                ldb FPA0+3                      ; multiply FPA1 by LSB of FPA0
                bsr LBB00
                ldb FPSBYT                      ; save extra precision byte
                stb VAE
                ldb FPA0+2
                bsr LBB00                       ; again for next byte of FPA0
                ldb FPSBYT
                stb VAD
                ldb FPA0+1                      ; again for next byte of FPA0
                bsr LBB00
                ldb FPSBYT
                stb VAC
                ldb FPA0                        ; and finally for the high byte
                bsr LBB02
                ldb FPSBYT
                stb VAB
                jsr LBC0B                       ; copy mantissa from FPA2 to FPA0 (result)
                jmp LBA1C                       ; normalize
LBB00           beq LBA97                       ; brif multiplier is 0 - just shift, don't multiply
LBB02           coma                            ; set carry
LBB03           lda FPA2                        ; get FPA2 MS byte
                rorb                            ; data bit to carry; will be 0 when all shifts done
                beq LBB2E                       ; brif 8 shifts done
                bcc LBB20                       ; brif data bit is 0 - no addition
                lda FPA2+3                      ; add mantissa of FPA1 and FPA2
                adda FPA1+3
                sta FPA2+3
                lda FPA2+2
                adca FPA1+2
                sta FPA2+2
                lda FPA2+1
                adca FPA1+1
                sta FPA2+1
                lda FPA2
                adca FPA1
LBB20           rora                            ; shift carry into FPA2
                sta FPA2
                ror FPA2+1
                ror FPA2+2
                ror FPA2+3
                ror FPSBYT
                clra                            ; clear carry
                bra LBB03
LBB2E           rts
; Unpack FP value from (X) to FPA1
LBB2F           ldd 1,x                         ; copy mantissa (and sign)
                sta FP1SGN                      ; save sign bit
                ora #0x80                       ; make sure mantissa has bit 7 set
                std FPA1
                ldb FP1SGN                      ; get sign
                eorb FP0SGN                     ; set if FPA0 sign differs
                stb RESSGN
                ldd 3,x                         ; copy remainder of mantissa
                std FPA1+2
                lda ,x                          ; and exponent
                sta FP1EXP
                ldb FP0EXP                      ; fetch FPA0 exponent and set flags
                rts
; Calculate eponent for product of FPA0 and FPA1
LBB48           tsta                            ; is FPA1 zero?
                beq LBB61                       ; brif so
                adda FP0EXP                     ; add to exponent of FPA0 (this is how scientific notation works)
                rora                            ; set V if we *don't* have an overflow
                rola
                bvc LBB61                       ; brif exponent too larger or small
                adda #0x80                      ; restore the bias
                sta FP0EXP                      ; set result exponent
                beq LBB63                       ; brif 0 - clear FPA0
                lda RESSGN                      ; the result sign (negative if signs differ) is the result sign
                sta FP0SGN                      ; so set it as such
                rts
LBB5C           lda FP0SGN                      ; get sign of FPA0
                coma                            ; invert sign
                bra LBB63                       ; zero sign and exponent
LBB61           leas 2,s                        ; don't go back to caller (mul/div) - return to previous caller
LBB63           lbpl LBA39                      ; brif we underflowed - go zero things out
LBB67           jmp LBA92                       ; raise overflow error
; fast multiply by 10 - leave result in FPA0
LBB6A           jsr LBC5F                       ; copy FPA0 to FPA1 (for addition later)
                beq LBB7C                       ; brif exponent is 0 - it's a no-op then
                adda #2                         ; this gives "times 4"
                bcs LBB67                       ; raise overflow if required
                clr RESSGN                      ; set result sign to "signs the same"
                jsr LB9CD                       ; add FPA1 to FPA0 "times 5"
                inc FP0EXP                      ; times 10
                beq LBB67                       ; brif overflow
LBB7C           rts
LBB7D           fcb 0x84,0x20,0x00,0x00,0x00    ; packed FP constant 10.0
; Divide by 10
LBB82           jsr LBC5F                       ; move FPA0 to FPA1
                ldx #LBB7D                      ; point to constant 10
                clrb                            ; zero sign
LBB89           stb RESSGN                      ; result will be positive or zero
                jsr LBC14                       ; unpack constant 10 to FPA0
                skip2                           ; fall through to division (divide FPA1 by 10)
LBB8F           bsr LBB2F                       ; unpack FP number from (X) to FPA1
; division operator
LBB91           beq LBC06                       ; brif FPA0 is 0 - division by zero
                neg FP0EXP                      ; get exponent of reciprocal of the divisor
                bsr LBB48                       ; calculate exponent of quotient
                inc FP0EXP                      ; bump exponent (due to division algorithm below)
                beq LBB67                       ; brif overflow
                ldx #FPA2                       ; point to temporary storage location
                ldb #4                          ; do 5 bytes
                stb TMPLOC                      ; save counter
                ldb #1                          ; shift counter and quotient byte
LBBA4           lda FPA0                        ; compare mantissa of FPA0 to FPA1, set C if FPA1 less
                cmpa FPA1
                bne LBBBD
                lda FPA0+1
                cmpa FPA1+1
                bne LBBBD
                lda FPA0+2
                cmpa FPA1+2
                bne LBBBD
                lda FPA0+3
                cmpa FPA1+3
                bne LBBBD
                coma                            ; set C if FPA0 = FPA1 (it "goes")
LBBBD           tfr cc,a                        ; save "it goes" status
                rolb                            ; rotate carry into quotient
                bcc LBBCC                       ; brif carry clear - haven't done 8 shifts yet
                stb ,x+                         ; save quotient byte
                dec TMPLOC                      ; done enough bytes?
                bmi LBBFC                       ; brif done all 5
                beq LBBF8                       ; brif last byte
                ldb #1                          ; reset shift counter and quotient byte
LBBCC           tfr a,cc                        ; get back carry status
                bcs LBBDE                       ; brif it "went"
LBBD0           asl FPA1+3                      ; shift mantissa (dividend) left
                rol FPA1+2
                rol FPA1+1
                rol FPA1
                bcs LBBBD                       ; brif carry - it "goes" so we have to bump quotient
                bmi LBBA4                       ; brif high order bit is set - compare mantissas
                bra LBBBD                       ; otherwise, count a 0 bit and try next bit
LBBDE           lda FPA1+3                      ; subtract mantissa of FPA0 from mantissa of FPA1
                suba FPA0+3
                sta FPA1+3
                lda FPA1+2
                sbca FPA0+2
                sta FPA1+2
                lda FPA1+1
                sbca FPA0+1
                sta FPA1+1
                lda FPA1
                sbca FPA0
                sta FPA1
                bra LBBD0                       ; go check for another go
LBBF8           ldb #0x40                       ; only two bits in last byte (for rounding)
                bra LBBCC                       ; go do the last byte
LBBFC           rorb                            ; get low bits to bits 7,6 and C to bit 5
                rorb
                rorb
                stb FPSBYT                      ; save result extra precision
                bsr LBC0B                       ; move FPA2 mantissa to FPA0 (result)
                jmp LBA1C                       ; go normalize the result
LBC06           ldb #2*10                       ; division by zero
                jmp LAC46                       ; raise error
; Copy mantissa of FPA2 to FPA0
LBC0B           ldx FPA2                        ; copy high word
                stx FPA0
                ldx FPA2+2                      ; copy low word
                stx FPA0+2
                rts
; unpack FP number at (X) to FPA0
LBC14           pshs a                          ; save register
                ldd 1,x                         ; get mantissa high word and sign
                sta FP0SGN                      ; set sign
                ora #0x80                       ; make sure mantissa always has bit 7 set
                std FPA0
                clr FPSBYT                      ; clear extra precision
                ldb ,x                          ; get exponent
                ldx 3,x                         ; copy mantissa low word
                stx FPA0+2
                stb FP0EXP                      ; save exponent (and set flags)
                puls a,pc                       ; restore register and return
LBC2A           ldx #V45                        ; point to FPA4
                bra LBC35                       ; pack FPA0 there
LBC2F           ldx #V40                        ; point to FPA3
                skip2                           ; fall through to pack FPA0 there
LBC33           ldx VARDES                      ; get variable descriptor pointer
; Pack FPA0 to (X)
LBC35           lda FP0EXP                      ; get exponent
                sta ,x                          ; save it
                lda FP0SGN                      ; get sign
                ora #0x7f                       ; force set low bits - only keep sign in high bit
                anda FPA0                       ; merge in bits 6-0 of high byte of mantissa
                sta 1,x                         ; save it
                lda FPA0+1                      ; copy next highest byte
                sta 2,x
                ldu FPA0+2                      ; and the low word of the mantissa
                stu 3,x
                rts
; Copy FPA1 to FPA0; return with sign in A
LBC4A           lda FP1SGN                      ; copy sign
LBC4C           sta FP0SGN
                ldx FP1EXP                      ; copy exponent, mantissa high byte
                stx FP0EXP
                clr FPSBYT                      ; clear extra precision
                lda FPA1+1                      ; copy mantissa second highest byte
                sta FPA0+1
                lda FP0SGN                      ; set sign for return
                ldx FPA1+2                      ; copy low word of mantissa
                stx FPA0+2
                rts
; Copy FPA0 to FPA1
LBC5F           ldd FP0EXP                      ; copy exponent and high byte of mantissa
                std FP1EXP
                ldx FPA0+1                      ; copy middle bytes of mantissa
                stx FPA1+1
                ldx FPA0+3                      ; copy low byte of mantissa and sign
                stx FPA1+3
                tsta                            ; set flags on exponent
                rts
; check FPA0: return B = 0, if FPA0 is 0, 0xff if negative, and 0x01 if positive
LBC6D           ldb FP0EXP                      ; get exponent
                beq LBC79                       ; brif 0
LBC71           ldb FP0SGN                      ; get sign
LBC73           rolb                            ; get sign to C
                ldb #0xff                       ; set for negative result
                bcs LBC79                       ; brif negative
                negb                            ; set to 1 for positive
LBC79           rts
; SGN function
SGN             bsr LBC6D                       ; get sign of FPA0
LBC7C           stb FPA0                        ; save result
                clr FPA0+1                      ; clear next lower 8 bits
                ldb #0x88                       ; exponent if mantissa is 8 bit integer
LBC82           lda FPA0                        ; get high bits of mantissa
                suba #0x80                      ; set C if mantissa was positive (will cause a negation if it was negative)
LBC86           stb FP0EXP                      ; set exponent
                ldd ZERO                        ; clear out low word
                std FPA0+2
                sta FPSBYT                      ; clear extra precision
                sta FP0SGN                      ; set sign to positive
                jmp LBA18                       ; normalize the result
; ABS function
ABS             clr FP0SGN                      ; force FPA0 to be positive (yes, it's that simple)
                rts
; Compare packed FP number at (X) to FPA0
; Return with B = -1, 0, 1 for FPA0 <, =, > (X) and flags set based on that
LBC96           ldb ,x                          ; get exponent of (X)
                beq LBC6D                       ; brif (X) is 0
                ldb 1,x                         ; get MS byte of mantissa of (X)
                eorb FP0SGN                     ; set bit 7 if signs of (X) and FPA0 differ
                bmi LBC71                       ; brif signs differ - no need to compare the magnitude
LBCA0           ldb FP0EXP                      ; compare exponents and brif different
                cmpb ,x
                bne LBCC3
                ldb 1,x                         ; compare mantissa (but we have to pack the FPA0 bits first
                orb #0x7f                       ; keep only sign bit (note: signs are the same)
                andb FPA0                       ; merge in the mantissa bits from FPA0
                cmpb 1,x                        ; do the packed versions match?
                bne LBCC3                       ; brif not
                ldb FPA0+1                      ; compare second byte of mantissas
                cmpb 2,x
                bne LBCC3
                ldb FPA0+2                      ; compare third byte of mantissas
                cmpb 3,x
                bne LBCC3
                ldb FPA0+3                      ; compare low byte of mantissas, but use subtraction so B = 0 on match
                subb 4,x
                bne LBCC3
                rts                             ; return B = 0 if (X) = FPA0
LBCC3           rorb                            ; shift carry to bit 7 (C set if FPA0 < (X))
                eorb FP0SGN                     ; invert the comparision sense if the signs are negative
                bra LBC73                       ; interpret comparison result
; Shift mantissa of FPA0 until the binary point is immediately to the right of the mantissa and set up the
; result as a two's complement value.
LBCC8           ldb FP0EXP                      ; get exponent of FPA0
                beq LBD09                       ; brif FPA0 is zero - we don't have to do anything, just blank it
                subb #0xa0                      ; calculate number of shifts to get to the correct exponent (binary point to the right)
                lda FP0SGN                      ; do we have a positive number?
                bpl LBCD7                       ; brif so
                com FPCARY                      ; negate the mantissa and set extra inbound precision to the correct sign
                jsr LBA7B
LBCD7           ldx #FP0EXP                     ; point to FPA0
                cmpb #-8                        ; moving by whole bytes?
                bgt LBCE4                       ; brif not
                jsr LBAAE                       ; do bit shifting
                clr FPCARY                      ; clear carry in byte
                rts
LBCE4           clr FPCARY                      ; clear the extra carry in precision
                lda FP0SGN                      ; get sign of value
                rola                            ; get sign to carry (so rotate repeats the sign)
                ror FPA0                        ; shift the first bit
                jmp LBABA                       ; do the shifting dance
; INT function
INT             ldb FP0EXP                      ; get exponent
                cmpb #0xa0                      ; is the number big enough that there can be no fractional part?
                bhs LBD11                       ; brif so - we don't have to do anything
                bsr LBCC8                       ; go shift binary point to the right of the mantissa
                stb FPSBYT                      ; save extra precision bits
                lda FP0SGN                      ; get original sign
                stb FP0SGN                      ; force result to be positive
                suba #0x80                      ; set C if we had a positive result
                lda #0xa0                       ; set exponent to match denormalized result
                sta FP0EXP
                lda FPA0+3                      ; save low byte
                sta CHARAC
                jmp LBA18                       ; go normalize (this will correct for the two's complement representation of negatives)
LBD09           stb FPA0                        ; replace mantissa of FPA0 with contents of B
                stb FPA0+1
                stb FPA0+2
                stb FPA0+3
LBD11           rts
; Convert ASCII string to FP
; BUG: no overflow is checked on the decimal exponent in exponential notation.
LBD12           ldx ZERO                        ; zero out FPA0 and temporaries
                stx FP0SGN
                stx FP0EXP
                stx FPA0+1
                stx FPA0+2
                stx V47
                stx V45
                bcs LBD86                       ; brif input character is numeric
                jsr RVEC19                      ; do the RAM hook dance
                cmpa #'-                        ; regular negative sign
                bne LBD2D                       ; brif not
                com COEFCT                      ; invert sign
                bra LBD31                       ; process stuff after the sign
LBD2D           cmpa #'+                        ; regular plus?
                bne LBD35                       ; brif not
LBD31           jsr GETNCH                      ; get character after sign
                bcs LBD86                       ; brif numeric
LBD35           cmpa #'.                        ; decimal point?
                beq LBD61                       ; brif so
                cmpa #'E                        ; scientific notation
                bne LBD65                       ; brif not
                jsr GETNCH                      ; eat the "E"
                bcs LBDA5                       ; brif numeric
                cmpa #0xac                      ; negative sign (token)?
                beq LBD53                       ; brif so
                cmpa #'-                        ; regular negative?
                beq LBD53                       ; brif so
                cmpa #0xab                      ; plus sign (token)?
                beq LBD55                       ; brif so
                cmpa #'+                        ; regular plus?
                beq LBD55
                bra LBD59                       ; brif no sign found
LBD53           com V48                         ; set exponent sign to negative
LBD55           jsr GETNCH                      ; eat the sign
                bcs LBDA5                       ; brif numeric
LBD59           tst V48                         ; is the exponent sign negatvie?
                beq LBD65                       ; brif not
                neg V47                         ; negate base 10 exponent
                bra LBD65
LBD61           com V46                         ; toggle decimal point flag
                bne LBD31                       ; brif we haven't seen two decimal points
LBD65           lda V47                         ; get base 10 exponent
                suba V45                        ; subtract number of places to the right
                sta V47                         ; we now have a complete decimal exponent
                beq LBD7F                       ; brif we have no base 10 shifting required
                bpl LBD78                       ; brif positive exponent
LBD6F           jsr LBB82                       ; divide FPA0 by 10 (shift decimal point left)
                inc V47                         ; bump exponent
                bne LBD6F                       ; brif we haven't reached 0 yet
                bra LBD7F                       ; return result
LBD78           jsr LBB6A                       ; multiply by 10
                dec V47                         ; downshift the exponent
                bne LBD78                       ; brif not at 0 yet
LBD7F           lda COEFCT                      ; get desired sign
                bpl LBD11                       ; brif it will be positive - no need to do anything
                jmp LBEE9                       ; flip the sign of FPA0
LBD86           ldb V45                         ; get the decimal count
                subb V46                        ; (if decimal seen, will add one; otherwise it does nothing)
                stb V45
                pshs a                          ; save new digit
                jsr LBB6A                       ; multiply partial result by 10
                puls b                          ; get back digit
                subb #'0                        ; remove ASCII bias
                bsr LBD99                       ; add B to FPA0
                bra LBD31                       ; go process another digit
LBD99           jsr LBC2F                       ; save FPA0 to FPA3
                jsr LBC7C                       ; convert B to FP number
                ldx #V40                        ; point to FPA3
                jmp LB9C2                       ; add FPA3 and FPA0
LBDA5           ldb V47                         ; get exponent value
                aslb                            ; times 2
                aslb                            ; times 4
                addb V47                        ; times 5
                aslb                            ; times 10
                suba #'0                        ; remove ASCII bias
                pshs b                          ; save acculated result
                adda ,s+                        ; add new digit to accumulated result
                sta V47                         ; save new accumulated decimal exponent
                bra LBD55                       ; interpret another exponent character
LBDB6           fcb 0x9b,0x3e,0xbc,0x1f,0xfd    ; packed FP: 99999999.9
LBDBB           fcb 0x9e,0x6e,0x6b,0x27,0xfd    ; packed FP: 999999999
LBDC0           fcb 0x9e,0x6e,0x6b,0x28,0x00    ; pakced FP: 1E9
LBDC5           ldx #LABE8-1                    ; point to "IN" message
                bsr LBDD6                       ; output the string
                ldd CURLIN                      ; get basic line number
LBDCC           std FPA0                        ; save 16 bit unsigned integer
                ldb #0x90                       ; exponent for upper 16 bits of FPA0 to be an integer
                coma                            ; set C (force normalization to treat as positive)
                jsr LBC86                       ; zero bottom half, save exponent, and normalize
                bsr LBDD9                       ; convert FP number to ASCII string
LBDD6           jmp STRINOUT                    ; output string
; Convert FP number to ASCII string
LBDD9           ldu #STRBUF+3                   ; point to buffer address that will not cause string to go to string space
LBDDC           lda #0x20                       ; default sign is a space character
                ldb FP0SGN                      ; get sign of value
                bpl LBDE4                       ; brif positive
                lda #'-                         ; use negative sign
LBDE4           sta ,u+                         ; save sign
                stu COEFPT                      ; save output buffer pointer
                sta FP0SGN                      ; save sign character
                lda #'0                         ; result is 0 if exponent is 0
                ldb FP0EXP                      ; get exponent
                lbeq LBEB8                      ; brif FPA0 is 0
                clra                            ; base 10 exponent is 0 for > 1
                cmpb #0x80                      ; is number > 1?
                bhi LBDFF                       ; brif so
                ldx #LBDC0                      ; point to 1E+09
                jsr LBACA                       ; shift decimal to the right by 9 spaces
                lda #-9                         ; account for shift
LBDFF           sta V45                         ; save base 10 exponent
LBE01           ldx #LBDBB                      ; point to 999999999
                jsr LBCA0                       ; are we above that?
                bgt LBE18                       ; brif so
LBE09           ldx #LBDB6                      ; point to 99999999.9
                jsr LBCA0                       ; are we above that?
                bgt LBE1F                       ; brif in range
                jsr LBB6A                       ; multiply by 10 (we were small)
                dec V45                         ; account for shift
                bra LBE09                       ; see if we've come into range
LBE18           jsr LBB82                       ; divide by 10
                inc V45                         ; account for shift
                bra LBE01                       ; see if we've come into range
LBE1F           jsr LB9B4                       ; add 0.5 to FPA0 (rounding)
                jsr LBCC8                       ; do the integer dance
                ldb #1                          ; default decimal flag (force immediate decimal)
                lda V45                         ; get base 10 exponent
                adda #10                        ; account for "unormalized" number
                bmi LBE36                       ; brif number < 1.0
                cmpa #11                        ; do we have more than 9 places?
                bhs LBE36                       ; brif so - do scientific notation
                deca
                tfr a,b
                lda #2                          ; force no scientific notation
LBE36           deca                            ; subtract wo without affecting carry
                deca
                sta V47                         ; save exponent - 0 is do not display in scientific notation
                stb V45                         ; save number of places to left of decimal
                bgt LBE4B                       ; brif >= 1
                ldu COEFPT                      ; point to string buffer
                lda #'.                         ; put decimal
                sta ,u+
                tstb                            ; is there anything to left of decimal?
                beq LBE4B                       ; brif not
                lda #'0                         ; store a zero
                sta ,u+
LBE4B           ldx #LBEC5                      ; point to powers of 10
                ldb #0x80                       ; set digit counter to 0x80
LBE50           lda FPA0+3                      ; add mantissa to power of 10
                adda 3,x
                sta FPA0+3
                lda FPA0+2
                adca 2,x
                sta FPA0+2
                lda FPA0+1
                adca 1,x
                sta FPA0+1
                lda FPA0
                adca ,x
                sta FPA0
                incb                            ; add one to digit counter
                rorb                            ; put carry into bit 7
                rolb                            ; set V if carry and sign differ
                bvc LBE50                       ; brif positive mantissa or carry is 0 and negative mantissa
                bcc LBE72                       ; brif negative mantissa
                subb #10+1                      ; take 9's complement if adding mantissa
                negb
LBE72           addb #'0-1                      ; add ASCII bias
                leax 4,x                        ; move to next power of 10
                tfr b,a                         ; save digit
                anda #0x7f                      ; remove add/subtract flag
                sta ,u+                         ; put in output
                dec V45                         ; do we need a decimal yet?
                bne LBE84                       ; brif not
                lda #'.                         ; put decimal
                sta ,u+
LBE84           comb                            ; toggle bit 7 (add/sub flag)
                andb #0x80                      ; only keep bit 7
                cmpx #LBEC5+9*4                 ; done all places?
                bne LBE50                       ; brif not
LBE8C           lda ,-u                         ; get last character
                cmpa #'0                        ; was it 0?
                beq LBE8C                       ; brif so
                cmpa #'.                        ; decimal?
                bne LBE98                       ; brif not
                leau -1,u                       ; move past decimal if it isn't needed
LBE98           lda #'+                         ; plus sign
                ldb V47                         ; get scientific notation exponent
                beq LBEBA                       ; brif not scientific notation
                bpl LBEA3                       ; brif positive exponent
                lda #'-                         ; negative sign for base 10 exponent
                negb                            ; switch to positive exponent
LBEA3           sta 2,u                         ; put sign
                lda #'E                         ; put "E"
                sta 1,u
                lda #'0-1                       ; init to ASCII 0 (compensate for INC)
LBEAB           inca                            ; bump digit
                subb #10                        ; have we hit the correct one yet?
                bcc LBEAB                       ; brif not
                addb #'9+1                      ; convert units digit to ASCII
                std 3,u                         ; put exponent in output
                clr 5,u                         ; put trailing NUL
                bra LBEBC                       ; go reset pointer
LBEB8           sta ,u                          ; store last character
LBEBA           clr 1,u                         ; put NUL at the end
LBEBC           ldx #STRBUF+3                   ; point to start of string
                rts
LBEC0           fcb 0x80,0x00,0x00,0x00,0x00    ; packed FP 0.5
LBEC5           fqb -100000000
                fqb 10000000
                fqb -1000000
                fqb 100000
                fqb -10000
                fqb 1000
                fqb -100
                fqb 10
                fqb -1
LBEE9           lda FP0EXP                      ; get exponent of FPA0
                beq LBEEF                       ; brif 0 - don't flip sign
                com FP0SGN                      ; flip sign
LBEEF           rts
; Expand a polynomial of the form
; AQ+BQ^3+CQ^5+DQ^7..... where Q is FPA0 and X points to a table
LBEF0           stx COEFPT                      ; save coefficient table pointer
                jsr LBC2F                       ; copy FPA0 to FPA3
                bsr LBEFC                       ; multiply FPA3 by FPA0
                bsr LBF01                       ; expand polynomial
                ldx #V40                        ; point to FPA3
LBEFC           jmp LBACA                       ; multiply FPA0 by FPA3
LBEFF           stx COEFPT                      ; save coefficient table counter
LBF01           jsr LBC2A                       ; move FPA0 to FPA4
                ldx COEFPT                      ; get the current coefficient
                ldb ,x+                         ; get the number of entries
                stb COEFCT                      ; save as counter
                stx COEFPT                      ; save new pointer
LBF0C           bsr LBEFC                       ; multiply (X) and FPA0
                ldx COEFPT                      ; get this coefficient
                leax 5,x                        ; move to next one
                stx COEFPT                      ; save new pointer
                jsr LB9C2                       ; add (X) to FPA0
                ldx #V45                        ; point X to FPA4
                dec COEFCT                      ; done all coefficients?
                bne LBF0C                       ; brif more left
                rts
; RND function
RND             jsr LBC6D                       ; set flags on FPA0
                bmi LBF45                       ; brif negative - set seed
                beq LBF3B                       ; brif 0 - do random between 0 and 1
                bsr LBF38                       ; convert to integer
                jsr LBC2F                       ; save range value
                bsr LBF3B                       ; get random number
                ldx #V40                        ; point to FPA3
                bsr LBEFC                       ; multply (X) by FPA0
                ldx #LBAC5                      ; point to FP 1.0
                jsr LB9C2                       ; add 1 to FPA0
LBF38           jmp INT                         ; return integer value
LBF3B           ldx RVSEED+1                    ; move variable random number seed to FPA0
                stx FPA0
                ldx RVSEED+3
                stx FPA0+2
LBF45           ldx RSEED                       ; move fixed seed to FPA1
                stx FPA1
                ldx RSEED+2
                stx FPA1+2
                jsr LBAD0                       ; multiply them
                ldd VAD                         ; get lowest order  product bytes
                addd #0x658b                    ; add a constant
                std RVSEED+3                    ; save it as new seed
                std FPA0+2                      ; save in result
                ldd VAB                         ; get high order extra product bytes
                adcb #0xb0                      ; add upper bytes of constant
                adca #5
                std RVSEED+1                    ; save as new seed
                std FPA0                        ; save as result
                clr FP0SGN                      ; set result to positive
                lda #0x80                       ; set exponent to 0 < FPA0 < 1
                sta FP0EXP
                lda FPA2+2                      ; get a byte from FPA2
                sta FPSBYT                      ; save as extra precision
                jmp LBA1C                       ; go normalize FPA0
RSEED           fqb 0x40e64dab                  ; constant random number generator seed
; SIN function
SIN             jsr LBC5F                       ; copy FPA0 to FPA1
                ldx #LBFBD                      ; point to 2*pi
                ldb FP1SGN                      ; get sign of FPA1
                jsr LBB89                       ; divide FPA0 by 2*pi
                jsr LBC5F                       ; copy FPA0 to FPA1
                bsr LBF38                       ; convert FPA0 to an integer
                clr RESSGN                      ; set result to positive
                lda FP1EXP                      ; get exponent of FPA1
                ldb FP0EXP                      ; get exponent of FPA0
                jsr LB9BC                       ; subtract FPA0 from FPA1
                ldx #LBFC2                      ; point to FP 0.25
                jsr LB9B9                       ; subtract FPA0 from 0.25 (pi/2)
                lda FP0SGN                      ; get result sign
                pshs a                          ; save it
                bpl LBFA6                       ; brif positive
                jsr LB9B4                       ; add 0.5 (pi) to FPA0
                lda FP0SGN                      ; get sign of result
                bmi LBFA9                       ; brif negative
                com RELFLG                      ; if 3pi/2 >= arg >= pi/2
LBFA6           jsr LBEE9                       ; flip sign of FPA0
LBFA9           ldx #LBFC2                      ; point to 0.25
                jsr LB9C2                       ; add 0.25 (pi/2) to FPA0
                puls a                          ; get original sign
                tsta                            ; was it positive
                bpl LBFB7                       ; brif so
                jsr LBEE9                       ; flip result sign
LBFB7           ldx #LBFC7                      ; point to series coefficients
                jmp LBEF0                       ; go calculate value
LBFBD           fcb 0x83,0x49,0x0f,0xda,0xa2    ; 2*pi
LBFC2           fcb 0x7f,0x00,0x00,0x00,0x00    ; 0.25
; modified taylor series SIN coefficients
LBFC7           fcb 6-1                         ; six coefficients
                fcb 0x84,0xe6,0x1a,0x2d,0x1b    ; -((2pi)^11)/11!
                fcb 0x86,0x28,0x07,0xfb,0xf8    ; ((2pi)^9)/9!
                fcb 0x87,0x99,0x68,0x89,0x01    ; -((2pi)^7)/7!
                fcb 0x87,0x23,0x35,0xdf,0xe1    ; ((2pi)^5)/5!
                fcb 0x86,0xa5,0x5d,0xe7,0x28    ; -(2pi)^3)/3!
                fcb 0x83,0x49,0x0f,0xda,0xa2    ; 2*pi
; these 12 bytes are unused
                fcb 0xa1,0x54,0x46,0x8f,0x13,0x8f,0x52,0x43
                fcb 0x89,0xcd,0xa6,0x81
; these are a copy of the interrupt vectors that live at the top of the ROM. It's not clear
; why these vectors have been modified since they are not actually used.
                fdb INT.SWI3                    ; SWI3
                fdb INT.SWI2                    ; SWI2
                fdb INT.FIRQ                    ; FIRQ
                fdb INT.IRQ                     ; IRQ
                fdb INT.SWI                     ; SWI
                fdb INT.NMI                     ; NMI
                fdb L8C1B                       ; RESET
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Coco3 internal ROM, upper 32K
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; This is the initialization code specific to the Coco3. This handles copying the ROMs to RAM and adding various patches in.
; This sequence of code demonstrates clearly that the creators of the Coco3 additions were rushed and didn't have a clear
; understanding of the Coco3 hardware or how Color Basic works. There is evidence of last minute adjustments along with code
; that serves no purpose but which is still present.
;
; There is also a major bug. The F1 for burst phase invert enable is clearly supposed to be enabled for the HSCREEN graphics
; modes. However, the code that enables it actually patches the wrong byte in the graphics mode initializers. Instead of enabling
; the burst phase invert bit in FF98, it actually enables the FIRQ enable bit in FF90.
SC000           orcc #0x50                      ; make sure interrupts are disabled
                lds #0x5eff                     ; put the stack somewhere
                lda #0x12                       ; nuclear green colour
                ldb #16                         ; 16 palette registers
                ldx #PALETREG                   ; point to palette registers
SC00D           sta ,x+                         ; set a palette register to green
                decb                            ; done?
                bne SC00D                       ; brif not
                ldx #MMUREG                     ; point to MMU registers
                leay MMUIMAGE,pcr               ; point to MMU initializer
                ldb #16                         ; there are 16 MMU registers
SC01B           lda ,y+                         ; copy an MMU initializer
                sta ,x+
                decb                            ; done all?
                bne SC01B                       ; brif not
                lda #COCO+MMUEN+MC3+MC2+MC1     ; enable coco compatible, mmu, SCS, FExx, and 32K internal
                sta INIT0
                leax BEGMOVE,pcr                ; point to start of relocated initialization code
                ldy #0x4000                     ; point to RAM address where it goes
SC02F           ldd ,x++                        ; copy four bytes
                ldu ,x++
                std ,y++
                stu ,y++
                cmpx #ENDMOVE                   ; copied everything?
                blo SC02F                       ; brif not
                jmp 0x4000                      ; transfer control to code in RAM
; The rest runs from RAM. This allows it to mess with the ROM mapping (for the ROM/RAM copy). Unfortunately,
; this clobbers an 8K memory block *before* it determines that it isn't going to copy ROM to RAM which is
; somewhat problematic for things that intercept a warm start.
BEGMOVE         leas -1,s                       ; make a hole on the stack
                nop                             ; space fillers; probably something removed at the eleventh hour
                nop
                nop
                nop
                nop
                lda #0xff                       ; set GIME timer to maximum value and start it counting
                sta V.TIMER
                sta V.TIMER+1
                leax VIDIMAGE,pcr               ; point to video mode initializer
                ldy #VIDEOMOD                   ; point to video mode registers
SC056           lda ,x+                         ; copy a byte
                sta ,y+
                cmpy #MMUREG                    ; done?
                bne SC056                       ; brif not
                ldx #PIA1                       ; point to PIA1
                ldd #0xff34                     ; set up for initializing PIAs
                clr 1,x                         ; set PIA1 DA to direction mode
                clr 3,x                         ; set PIA1 DB to direction mode
                deca
                sta ,x                          ; set PIA1 DA bits 7-1 as output, 0 as input
                lda #0xf8                       ; set PIA1 DB bits 7-3 as output, 2-0 as input
                sta 2,x
                stb 1,x                         ; set PIA1 DA to data mode
                stb 3,x                         ; set PIA1 DB to data mode
                clr 2,x                         ; set VDG to alpha-numeric
                lda #2                          ; set RS232 to marking
                sta ,x
                lda #0xff
                ldx #PIA0                       ; point to PIA0
                clr 1,x                         ; set PIA0 DA to direction mode
                clr 3,x                         ; set PIA0 DB to direction mode
                clr ,x                          ; set PIA0 DA to input
                sta 2,x                         ; set PIA0 DB to output
                stb 1,x                         ; set PIA0 DA to direction mode
                stb 3,x                         ; set PIA0 DB to direction mode
                ldb #12                         ; there are 12 SAM bits to reset
                ldu #SAMREG                     ; point to SAM register
SC091           sta ,u++                        ; clear a bit
                decb                            ; done all?
                bne SC091                       ; brif not
                sta SAMREG+9                    ; put VDG display at 0x400
                tfr b,dp                        ; set direct page to 0
                clr 2,x                         ; strobe all keyboard columns (pointless)
                sta -3,u                        ; select RAM page 1 (also pointless)
                ldx #PIA0                       ; point to PIA0 (unneeded - already points there)
                ldb #0xdf                       ; column strobe for F1
                stb 2,x                         ; strobe for F1
                lda ,x                          ; get row data
                coma                            ; set nonzero if F1 down
                anda #0x40
                sta ,s                          ; save F1 state for later
                ldy #2                          ; check for two keys
SC0B1           asrb                            ; shift strobe (why not just shift directly in the PIA?)
                stb 2,x                         ; strobe new column
                lda ,x                          ; get row data
                coma                            ; set nonzero if CTRL or ALT is down
                anda #0x40
                beq SC0C2                       ; brif not - we don't have C-A-RESET
                leay -1,y                       ; done both?
                bne SC0B1                       ; brif not
                lbra SC1F0                      ; go do easter egg picture if C-A-RESET
SC0C2           lda #COCO+MMUEN+MC3+MC1         ; turn off standard SCS (why?)
                sta INIT0
; This checks if we have a valid warm start routine. If there is one, we don't do a ROM/RAM copy. This and
; everything above could just as easily have been done from ROM.
                lda INT.FLAG                    ; are the bounce vectors valid?
                cmpa #0x55
                bne SC0F6                       ; brif not - copy ROM to RAM
                lda RSTFLG                      ; is the DP reset vector marked valid?
                cmpa #0x55
                bne NOWARM                      ; brif not
                ldx RSTVEC                      ; does the vector point to NOP?
                lda ,x
                cmpa #0x12
                lbeq SC18C                      ; brif so - don't do ROM/RAM copy
NOWARM          clr MMUREG                      ; put bottom memory block in logical block 0 (replaces DP)
                lda RSTFLG                      ; does this give us a valid reset vector?
                cmpa #0x55
                bne SC0F1                       ; brif not
                ldx RSTVEC                      ; does this routine point to a NOP?
                lda ,x
                cmpa #0x12
                lbeq SC18C                      ; brif so - don't do ROM/RAM copy and keep modified memory map
SC0F1           lda #BLOCK7.0                   ; restore memory map
                sta MMUREG
SC0F6           ldx #DOSBAS                     ; point to the end of Color Basic
                ldy #EXBAS                      ; point to start of Extended Basic
                lbsr SC1AA                      ; copy them to RAM
                leay PATCHTAB,pcr               ; point to patch table
                lda ,y+                         ; get number of patches to be made
SC106           pshs a                          ; save patch counter
                ldx ,y++                        ; get address to patch
                ldb ,y+                         ; get number of bytes in the patch
SC10C           lda ,y+                         ; copy a byte
                sta ,x+
                decb                            ; done all in this patch?
                bne SC10C
                puls a                          ; get back patch counter
                deca                            ; done all patches?
                bne SC106                       ; brif not
                clr TYCLR                       ; got back to ROM mode
                lda #COCO+MMUEN+MC3             ; set up for 16K split mode
                sta INIT0
                ldd DOSBAS                      ; is there a Disk Basic ROM signature?
                cmpa #'D                        ; (note that this should just be CMPD)
                bne SC137
                cmpb #'K
                bne SC137
                ldx #SUPERVAR                   ; point to end of Disk Basic ROM
                ldy #DOSBAS                     ; point to start of Disk Basic ROM
                bsr SC1AA                       ; copy it to RAM
                lbsr SC322                      ; add patches to Disk Basic
SC137           clr TYCLR                       ; go back to ROM mode
                lda #COCO+MMUEN+MC3+MC1         ; set 32K internal mocde
                sta INIT0
                ldx #H.CRSLOC                   ; point to end of the Coco3 additions
                ldy #SUPERVAR                   ; point to start of the Coco3 additions
                bsr SC1AA                       ; copy it to RAM
                lbsr SC1DE                      ; set up an easter egg
                leay INTIMAGE,pcr               ; point to bounce vector initializer
                ldx #INT.FLAG                   ; point to bounce vectors
                ldb #19                         ; 19 bytes in bounce vectors
                lbsr MOVE.XY                    ; initialize the bounce vectors
                clr TYSET                       ; enable RAM mode (the ROM/RAM copy already did this)
                tst ,s                          ; was F1 pressed?
                beq SC180                       ; brif not
                ldx #IM.TEXT                    ; point to text mode initializers
                ldb #3                          ; there are three sets of them
                leax 1,x                        ; move past the FF90 initializer
SC165           lda ,x                          ; get video mode initializer
                ora #0x20                       ; enable burst phase invert
                sta ,x                          ; update initializer
                leax 9,x                        ; move to next mode
                decb                            ; done all of them?
                bne SC165                       ; brif not
                ldb #2                          ; two graphics mode initalizers
                ldx #IM.GRAPH                   ; point to graphics mode initializers (should be +1; we're actually enabling GIME FIRQ)
SC175           lda ,x                          ; get initializer
                ora #0x20                       ; enable burst phase invert (or it would if X pointed to the right place)
                sta ,x                          ; save modified initializer
                leax 9,x                        ; move to next set
                decb                            ; done all of them?
                bne SC175                       ; brif not
SC180           ldx #VIDRAM                     ; point to start of VDG text screen
                lda #0x60                       ; VDG space character
SC185           sta ,x+                         ; blank a character
                cmpx #VIDRAM+512                ; end of screen?
                blo SC185                       ; brif not
SC18C           lda #COCO+MMUEN+MC3+MC2+MC1     ; turn the SCS back on
                sta INIT0
                tst ,s                          ; F1?
                beq SC19A                       ; brif not
                lda #0x20                       ; enable burst phase invert
                sta VIDEOMOD
SC19A           ldx #PALETREG                   ; point to palette registers
                leay PALIMAGE,PCR               ; point to palette initializer
                ldb #16                         ; do 16 palette registers
                bsr MOVE.XY                     ; initialize palette
                leas 1,s                        ; clean up stack (not much point since it will be reset anyway)
                jmp RESVEC                      ; transfer control to the original Color Basic initialization routine
SC1AA           stx 0x5f02                      ; save end copy address
                sts 0x5f00                      ; save stack
SC1B1           clr TYCLR                       ; go to ROM mode
                ldd ,y                          ; grab 8 bytes
                ldx 2,y
                ldu 4,y
                lds 6,y
                clr TYSET                       ; go to RAM mode
                std ,y                          ; save the 8 bytes
                stx 2,y
                stu 4,y
                sts 6,y
                leay 8,y                        ; move pointer forward
                cmpy 0x5f02                     ; done yet?
                blo SC1B1                       ; brif not
                lds 0x5f00                      ; restore stack pointer
                rts
MOVE.XY         lda ,y+                         ; copy a byte
                sta ,x+
                decb                            ; done all?
                bne MOVE.XY                     ; brif not
                rts
SC1DE           ldx #AUTHORMS                   ; point to author name easter egg
                leay SC30D,pcr                  ; point to encoded names
                ldb #21                         ; 21 bytes in names
SC1E7           lda ,y+                         ; get encoded byte
                coma                            ; decode (wow. one's complement encoding.)
                sta ,x+                         ; put in copied ROM
                decb                            ; done all?
                bne SC1E7                       ; brif not
                rts
SC1F0           clra                            ; set up to mark things as invalid
                sta INT.FLAG                    ; mark bounce vectors invalid
                sta RSTFLG                      ; mark reset vector invalid
                sta TYCLR                       ; go to ROM mode
                ldb #9                          ; foreground colour for image
                stb PALETREG+10
                ldb #63                         ; white background
                stb PALETREG+11
                ldx #AUTHPIC                    ; point to author picture data
                ldy #0xe00                      ; put picture at 0xe00 in memory
SC20A           ldd ,x++                        ; copy four bytes
                ldu ,x++
                std ,y++
                stu ,y++
                cmpx #AUTHPICe                  ; at end of picture data?
                blo SC20A                       ; brif not
                lda #0xf9                       ; 256x192, CSS0 VDG mode
                sta PIA1+2
                clra                            ; this instruction is useless
                ldx #SAMREG                     ; point to SAM register
                sta ,x                          ; set SAM address to 0xe00 and video mode to 256x192
                sta 3,x
                sta 5,x
                sta 7,x
                sta 9,x
                sta 11,x
WAITLOOP        bra WAITLOOP                    ; freeze the system
VIDIMAGE        fcb 0x00,0x00,0x00,0x00,0x0f,0xe0,0x00,0x00
PALIMAGE        fcb 18,36,11,7,63,31,9,38,0,18,0,63,0,18,0,38
MMUIMAGE        fcb BLOCK7.0,BLOCK7.1,BLOCK6.4,BLOCK7.3
                fcb BLOCK7.4,BLOCK7.5,BLOCK7.6,BLOCK7.7
                fcb BLOCK7.0,BLOCK6.0,BLOCK6.1,BLOCK6.2
                fcb BLOCK6.3,BLOCK7.5,BLOCK6.5,BLOCK7.7
PATCHTAB        fcb 27                          ; 27 patches to install
; Patch #1: enable warm start routine after ROM/RAM copy
patch1          fdb XBWMST
                fcb patch2-*-1
                nop
; Patch #2: intercept tokenization routine
patch2          fdb LB8D4
                fcb patch3-*-1
                jmp ALINK2
; Patch #3: intercept detokenization routine
patch3          fdb LB7F3
                fcb patch4-*-1
                jmp ALINK3
; Patch #4: intercept Extended Basic's command interpretation handler
patch4          fdb L8150
                fcb patch5-*-1
                jmp ALINK4
                nop
; Patch #5: intercept Extended Basic's function handler
patch5          fdb L816C
                fcb patch6-*-1
                jmp ALINK5
                nop
; Patch #6 through patch #10 - extend &H and &O to allow 24 bit values
patch6          fdb L8834
                fcb patch7-*-1
                jmp ALINK6A
                clr FPA0+1
                clr FPA0+2
                clr FPA0+3
                bra *-78
                clr FPA0
                bra *-47
                jmp ALINK6B
patch7          fdb L87EB
                fcb patch8-*-1
                bra *+76
                nop
                rts
                ldx #FPA0+1
patch8          fdb L880C
                fcb patch9-*-1
                bra *+55
patch9          fdb L8826
                fcb patch10-*-1
                bcs *+25
patch10         fdb L87E7
                fcb patch11-*-1
                bne *+7
; Patch #11 is needed because the above removed an RTS used by this routine
patch11         fdb L886A
                fcb patch12-*-1
                bne *-124
; Patch #12 - intercept signon message display
patch12         fdb L80B2
                fcb patch13-*-1
                jmp ALINK12
; Patch #13 - remove one carriage return from signon message
patch13         fdb L80E8+82
                fcb patch14-*-1
                fcb 0
; Patch #14 - extend Extended Basic's graphics initialization routine
patch14         fdb L9703
                fcb patch15-*-1
                jmp ALINK14
; Patch #15 - intercept break check
patch15         fdb LADF0
                fcb patch16-*-1
                jmp ALINK15
                nop
; Patch #16 - intercept break check when handling "line input"
patch16         fdb LA3C2
                fcb patch17-*-1
                jmp ALINK16
                nop
; Patch #17 - cause INPUT to respond to ON BRK
patch17         fdb LB03C+1
                fcb patch18-*-1
                fdb ALINK17
; Patch #18 - intercept ON command
patch18         fdb ON
                fcb patch19-*-1
                jmp ALINK18
; Patch #19 - add on extra stuff to end of NEW
patch19         fdb LAD3F
                fcb patch20-*-1
                jmp ALINK19
                nop
; Patch #20 - intercept error handler
patch20         fdb LAC46
                fcb patch21-*-1
                jmp ALINK20
; Patch #21 - intercept immediate mode loop
patch21         fdb LAC73
                fcb patch22-*-1
                jmp ALINK21
; Patch #22 - intercept character to screen routine
patch22         fdb LA30A
                fcb patch23-*-1
                jmp L8C37
; Patch #23 - intercept CLS
patch23         fdb CLS
                fcb patch24-*-1
                jmp L8C46
; Patch #24 - intercept waiting for keypress with cursor routine
patch24         fdb LA1B1
                fcb patch25-*-1
                jmp LA0CE
                nop
                nop
                nop
                nop
                nop
; Patch #25 - intercept PRINT @
patch25         fdb LB902
                fcb patch26-*-1
                jmp ALINK25
; Patch #26 - intercept conditional newline routine
patch26         fdb LB95C
                fcb patch27-*-1
                jmp ALINK26
; Patch #27 - intercept CLEAR handling in line input routine
patch27         fdb LA38D
                fcb patch27e-*-1
                jmp ALINK27
patch27e        equ *
; Names of the authors in one's complemented ASCII
SC30D           fcb 0xab,0xd1,0xb7,0x9e,0x8d,0x8d,0x96,0x8c
                fcb 0xdf,0xd9,0xdf,0xab,0xd1,0xba,0x9e,0x8d
                fcb 0x93,0x9a,0x8c,0xf2,0xff
SC322           lda DOSBAS+4                    ; get MSB of DSKCON vector
                cmpa #0xd6                      ; is it 0xd6?
                bne SC334                       ; brif not - we have Disk Basic 1.1
                ldx #0xc0c6                     ; point to patch address in Disk Basic 1.0
                leay SC355,pcr                  ; point to patch for Disk Basic 1.0
                ldb ,y+                         ; get number of bytes to patch
                bra SC349                       ; go patch it
SC334           ldx #0xC8B4                     ; point to Disk Basic 1.1 keyboard check (in the interpretation loop handler)
                lda #0x12                       ; NOP opcode
                ldb #11                         ; clobber 11 bytes (which check for a key down before calling the break check)
SC33B           sta ,x+                         ; put a NOP
                decb                            ; done?
                bne SC33B                       ; brif not
                ldx #0xc0d9                     ; point to the Disk Basic 1.1 patch address
                leay SC351,pcr                  ; point to patch for Disk Basic 1.1
                ldb ,y+                         ; get number of bytes in patch
SC349           lda ,y+                         ; put a byte from the patch
                sta ,x+
                decb                            ; done yet?
                bne SC349                       ; brif not
                rts
; Copyright message patch for Disk Basic 1.1
SC351           fcb SC355-*-1
                jmp ALINK29
; Copyright message patch for Disk Basic 1.0
SC355           fcb SC355e-*-1
                jmp ALINK28
SC355e          equ *
; This is the initializer for the bounce vector table. It sets up to transfer control to Color Basic's
; interrupt vectors at 0x100. These really should be JMP instead of LBRA, if only because JMP is faster.
INTIMAGE        fcb 0x55                        ; valid vector table flag
                lbra (INTIMAGE+1)-(INT.JUMP)+SW3VEC             ; SWI3
                lbra (INTIMAGE+1)-(INT.JUMP)+SW2VEC             ; SWI2
                lbra (INTIMAGE+1)-(INT.JUMP)+FRQVEC             ; FIRQ
                lbra (INTIMAGE+1)-(INT.JUMP)+IRQVEC             ; IRQ
                lbra (INTIMAGE+1)-(INT.JUMP)+SWIVEC             ; SWI
                lbra (INTIMAGE+1)-(INT.JUMP)+NMIVEC             ; NMI
ENDMOVE         equ *
; Unused bytes
                fcb 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0x00,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0x00,0x18,0x00,0x0E,0x00
; This is the "pmode 4" author picture easter egg
AUTHPIC         fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF7,0xFF,0xFB,0xEE,0xEF,0xFB,0xFF,0xBB,0xFF,0xFF,0xFF,0xFB,0xFF,0xFF,0xBB
                fcb 0xBB,0xBB,0xBF,0xBB,0xBB,0xFF,0xBF,0xFF,0xFE,0xEF,0xFF,0xFF,0xFF,0xEF,0x7F,0xFF
                fcb 0xFF,0xF7,0xBB,0xFF,0xBB,0xBB,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xBB,0xBF,0xBB,0xFF,0xBB,0x7F,0xFF
                fcb 0xFF,0xF6,0xEE,0xEE,0xEE,0xEE,0xEE,0xEF,0xFF,0xFE,0xFF,0xFE,0xEE,0xEE,0xFE,0xEE
                fcb 0xEE,0xEE,0xEF,0xEE,0xEE,0xEE,0xEE,0xEE,0xFE,0xEE,0xEE,0xEE,0xEE,0xEE,0x7F,0xFF
                fcb 0xFF,0xF3,0xBB,0xFF,0xBB,0xBB,0xBB,0xBB,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFB,0xBB,0xBB,0xBB,0xBB,0xBB,0x7F,0xFF
                fcb 0xFF,0xF6,0xAA,0xAE,0xAA,0xAE,0xAA,0xEA,0xBB,0xBB,0xFB,0xFF,0xBB,0xFF,0xBF,0xBF
                fcb 0xFF,0xFB,0xBF,0xBB,0xBB,0xBB,0xBB,0xBB,0xBA,0xEA,0xAA,0xEE,0xAE,0xEE,0x7F,0xFF
                fcb 0xFF,0xF3,0xBB,0xBF,0xBB,0xBB,0xBB,0xBB,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFB,0xBB,0xBB,0xBB,0xBB,0xBB,0x7F,0xFF
                fcb 0xFF,0xF6,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEF,0xFE,0xEF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFE,0xEF,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEF,0x7F,0xFF
                fcb 0xFF,0xF7,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xBB,0xBB,0xBB,0xBB,0xBB,0x7F,0xFF
                fcb 0xFF,0xF6,0xAA,0xEE,0xAA,0xAA,0xAA,0xEA,0xAB,0xBB,0xBB,0xFF,0xBB,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFB,0xBF,0xFF,0xFF,0xBB,0xBB,0xEA,0xAE,0xAA,0xAA,0xAF,0x7F,0xFF
                fcb 0xFF,0xF7,0xBB,0xBB,0xBF,0xFF,0xFB,0xBB,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFB,0xBB,0xBB,0xBB,0xBB,0x7F,0xFF
                fcb 0xFF,0xF6,0xEE,0xEE,0xEE,0xEF,0xEF,0xEE,0xEE,0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEE,0xEE,0xFF,0xEF,0xEE,0xEE,0xEF,0x7F,0xFF
                fcb 0xFF,0xF7,0xBB,0xBB,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xBB,0xBB,0xBB,0x7F,0xFF
                fcb 0xFF,0xF7,0xEA,0xAA,0xBB,0xBB,0xBB,0xBB,0xBB,0xFB,0xBB,0xBF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFB,0xFF,0xFB,0xFB,0xBB,0xBB,0xBA,0xAA,0xAA,0xEF,0x7F,0xFF
                fcb 0xFF,0xF7,0xBB,0xBB,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFB,0xBB,0xBB,0xBB,0x7F,0xFF
                fcb 0xFF,0xF6,0xEE,0xEE,0xEE,0xFE,0xEE,0xEE,0xEE,0xEE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xEE,0xEF,0xFE,0xEE,0xEE,0xEE,0xEF,0x7F,0xFF
                fcb 0xFF,0xF7,0xBB,0xBB,0xFB,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFB,0xBB,0xBB,0xBB,0x7F,0xFF
                fcb 0xFF,0xF6,0xEA,0xAB,0xAA,0xAB,0xBB,0xBB,0xBF,0xBF,0xFF,0xFF,0xFF,0x80,0x00,0x7F
                fcb 0xFF,0xFF,0xC0,0x00,0x3F,0xFF,0xFF,0xBB,0xBB,0xBF,0xAA,0xAA,0xAA,0xEF,0x7F,0xFF
                fcb 0xFF,0xF3,0xBB,0xBB,0xBB,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xBB,0xBB,0xBB,0xBF,0x7F,0xFF
                fcb 0xFF,0xF6,0xEE,0xEE,0xEE,0xEF,0xEE,0xFF,0xFF,0xFF,0xEE,0xFF,0xFF,0x80,0x00,0x3F
                fcb 0xFF,0xFF,0x80,0x00,0x3F,0xFF,0xFF,0xEE,0xFE,0xEE,0xEE,0xEE,0xEE,0xEF,0x7F,0xFF
                fcb 0xFF,0xF3,0xBB,0xBB,0xBB,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0x00,0x07,0xFF,0xFF,0xFF,0xFF,0xFF,0xBB,0xBB,0xBB,0xBF,0x7F,0xFF
                fcb 0xFF,0xF6,0xEE,0xAB,0xAE,0xEB,0xBB,0xBF,0xFB,0xFF,0xFF,0xFF,0xFF,0x80,0x00,0x1F
                fcb 0xFF,0xFF,0x00,0x00,0x3F,0xFF,0xFF,0xFF,0xBB,0xBB,0xAA,0xAA,0xBE,0xAB,0x7F,0xFF
                fcb 0xFF,0xF3,0xBB,0xBF,0xBB,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFB,0xFB,0xBB,0xBB,0xBF,0x7F,0xFF
                fcb 0xFF,0xF6,0xEE,0xEE,0xEE,0xEE,0xEE,0xEF,0xFE,0xEF,0xFF,0xFF,0xFF,0x80,0x00,0x0F
                fcb 0xFF,0xFE,0x00,0x00,0x3F,0xFF,0xFF,0xEF,0xEF,0xEE,0xEE,0xEE,0xEE,0xEF,0x7F,0xFF
                fcb 0xFF,0xF3,0xBB,0xBF,0xFB,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0x00,0x03,0xFF,0xFF,0xFF,0xFF,0xFB,0xBF,0xFF,0xBB,0xBF,0x7F,0xFF
                fcb 0xFF,0xF6,0xEA,0xAB,0xBA,0xAB,0xBB,0xFB,0xFF,0xBF,0xFF,0xFF,0xFF,0x80,0x00,0x07
                fcb 0xFF,0xFC,0x00,0x00,0x3F,0xFF,0xFF,0xFF,0xFB,0xAA,0xFF,0xFE,0xEA,0xAB,0x7F,0xFF
                fcb 0xFF,0xF3,0xBB,0xBF,0xFB,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xBB,0xBF,0xFF,0xBB,0xBF,0x7F,0xFF
                fcb 0xFF,0xF6,0xEE,0xEE,0xFF,0xFE,0xEE,0xEE,0xFF,0xFF,0xFF,0xFF,0xFF,0x80,0x00,0x03
                fcb 0xFF,0xF8,0x00,0x00,0x3F,0xFF,0xFF,0xFE,0xEE,0xEE,0xFF,0xFE,0xEE,0xEF,0x7F,0xFF
                fcb 0xFF,0xF7,0xBB,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0x00,0x03,0xFF,0xFF,0xFF,0xFF,0xBB,0xBF,0xFF,0xBB,0xFF,0x7F,0xFF
                fcb 0xFF,0xF7,0xAA,0xFB,0xBB,0xBB,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x80,0x00,0x01
                fcb 0xFF,0xF0,0x00,0x00,0x3F,0xFF,0xFF,0xBB,0xBB,0xAE,0xBB,0xBE,0xAF,0xBB,0x7F,0xFF
                fcb 0xFF,0xF7,0xBB,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xBB,0xFF,0xFF,0xBB,0xFF,0x7F,0xFF
                fcb 0xFF,0xF6,0xEE,0xEE,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0x80,0x08,0x00
                fcb 0xFF,0xE0,0x02,0x00,0x3F,0xFF,0xFF,0xFE,0xEF,0xEE,0xFF,0xEE,0xEF,0xEF,0x7F,0xFF
                fcb 0xFF,0xF7,0xBB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0x00,0x03,0xFF,0xFF,0xFF,0xFF,0xFB,0xFF,0xFF,0xBB,0xFF,0x7F,0xFF
                fcb 0xFF,0xF7,0xAA,0xBB,0xBB,0xFB,0xBB,0xFF,0xBF,0xFF,0xFF,0xFF,0xFF,0x80,0x0C,0x00
                fcb 0x7F,0xC0,0x06,0x00,0x3F,0xFF,0xFF,0xFF,0xBB,0xFF,0xFF,0xBF,0xEB,0xBB,0x7F,0xFF
                fcb 0xFF,0xF7,0xBB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0xFF
                fcb 0xFF,0xF6,0xEE,0xEF,0xFF,0xEF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x80,0x0E,0x00
                fcb 0x3F,0x80,0x0E,0x00,0x3F,0xFF,0xFF,0xFE,0xFF,0xFF,0xFE,0xEE,0xEE,0xFF,0x7F,0xFF
                fcb 0xFF,0xF7,0xBB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0x00,0x03,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0xFF
                fcb 0xFF,0xF3,0xEA,0xBB,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x80,0x0F,0x00
                fcb 0x1F,0x00,0x1E,0x00,0x3F,0xFF,0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,0xFF,0xBF,0x7F,0xFF
                fcb 0xFF,0xF7,0xBB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0xFF
                fcb 0xFF,0xF7,0xEE,0xEE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x80,0x0F,0x80
                fcb 0x0E,0x00,0x3E,0x00,0x3F,0xFF,0xFF,0xEE,0xFF,0xFF,0xFF,0xFE,0xEF,0xEF,0x7F,0xFF
                fcb 0xFF,0xF7,0xBB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0x00,0x03,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xBF,0x7F,0xFF
                fcb 0xFF,0xF6,0xEA,0xBB,0xBB,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x80,0x0F,0xC0
                fcb 0x00,0x00,0x7E,0x00,0x3F,0xFF,0xFF,0xBF,0xFF,0xFF,0xFF,0xFF,0xBA,0xEF,0x7F,0xFF
                fcb 0xFF,0xF7,0xBB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0x00,0x1F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xBB,0x7F,0xFF
                fcb 0xFF,0xF6,0xEE,0xEE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x80,0x0F,0xE0
                fcb 0x00,0x00,0xFE,0x00,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xFE,0xEF,0x7F,0xFF
                fcb 0xFF,0xF7,0xBB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0x00,0x03,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xBB,0x7F,0xFF
                fcb 0xFF,0xF6,0xEB,0xBF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x80,0x0F,0xC0
                fcb 0x00,0x00,0x3E,0x00,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xEB,0x7F,0xFF
                fcb 0xFF,0xF7,0xBB,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00
                fcb 0x00,0x00,0x1F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xBA,0x7F,0xFF
                fcb 0xFF,0xF6,0xEE,0xEF,0xFF,0xFF,0xFF,0xC0,0x1F,0xFF,0xFF,0xFF,0xFF,0x80,0x0C,0x00
                fcb 0x00,0x00,0x1E,0x00,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEE,0xEB,0x7F,0xFF
                fcb 0xFF,0xF7,0xBB,0xFF,0xFF,0xFF,0xFC,0x00,0x0F,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0x00,0x03,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xAA,0x7F,0xFF
                fcb 0xFF,0xF6,0xAB,0xBB,0xFF,0xFF,0x00,0x00,0x03,0xFF,0xFF,0xFF,0xFF,0x80,0x0C,0x00
                fcb 0x00,0x00,0x06,0x00,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0x79,0x9F,0xFB,0xAB,0x7F,0xFF
                fcb 0xFF,0xF7,0xBB,0xFF,0xFF,0xF8,0x00,0x00,0x01,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00
                fcb 0x00,0x38,0x03,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x03,0xFE,0xEE,0x7F,0xFF
                fcb 0xFF,0xF6,0xEF,0xFF,0xFF,0xE0,0x00,0x00,0x00,0x4F,0xFF,0xFF,0xFF,0x80,0x00,0x00
                fcb 0x01,0x7C,0x00,0x00,0x3F,0xFF,0xFF,0xFF,0xFF,0x80,0x00,0x00,0xFA,0xBB,0x7F,0xFF
                fcb 0xFF,0xF7,0xFF,0xFF,0xFF,0xC0,0x00,0x00,0x00,0x01,0xFF,0xFF,0xF0,0x00,0x00,0x00
                fcb 0x03,0xFE,0x00,0x00,0x03,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x7E,0xEE,0x7F,0xFF
                fcb 0xFF,0xF3,0xBB,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x80,0x00,0x00
                fcb 0x0F,0xFF,0x00,0x00,0x3F,0xFF,0xFF,0xFF,0xFC,0x00,0x00,0x00,0x3B,0xBB,0x7F,0xFF
                fcb 0xFF,0xF7,0xFF,0xFF,0xFE,0x00,0x00,0x00,0x00,0x00,0x7F,0xFF,0xFF,0xFF,0x00,0x00
                fcb 0x2F,0xFF,0x00,0x7F,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x0E,0xEE,0x7F,0xFF
                fcb 0xFF,0xF6,0xFF,0xFF,0xFC,0x00,0x00,0x00,0x00,0x00,0x3F,0xFF,0xFF,0x80,0x00,0x01
                fcb 0xFF,0xFF,0x80,0x00,0x3F,0xFF,0xFF,0xFF,0xE0,0x00,0x00,0x00,0x07,0xBB,0x7F,0xFF
                fcb 0xFF,0xF7,0xFF,0xFF,0xF8,0x00,0x00,0x00,0x00,0x00,0x3F,0xFF,0xF0,0x00,0x00,0x03
                fcb 0xFF,0xFF,0x40,0x00,0x03,0xFF,0xFF,0xFF,0xC0,0x00,0x00,0x00,0x03,0xEE,0x7F,0xFF
                fcb 0xFF,0xF3,0xBB,0xFF,0xF0,0x00,0x00,0x00,0x01,0x00,0x1F,0xFF,0xFF,0x80,0x01,0x07
                fcb 0xFF,0xFF,0xA0,0x00,0x3F,0xFF,0xFF,0xFF,0x80,0x00,0x00,0x00,0x01,0xBB,0x7F,0xFF
                fcb 0xFF,0xF7,0xFF,0xFF,0xE0,0x00,0x00,0x00,0x01,0x80,0x1F,0xFF,0xFF,0xFE,0x0E,0x2F
                fcb 0xFF,0xFF,0xC0,0x1F,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0xEE,0x7F,0xFF
                fcb 0xFF,0xF6,0xFF,0xFF,0xE0,0x00,0x00,0x00,0x65,0xE0,0x0F,0xFF,0xFF,0x80,0x0C,0x1F
                fcb 0xFF,0xFF,0xE0,0x00,0x3F,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x3B,0x7F,0xFF
                fcb 0xFF,0xF7,0xFF,0xFF,0xC0,0x00,0x00,0x0B,0xFF,0xF0,0x0F,0xFF,0xFC,0x00,0x18,0x0F
                fcb 0xF8,0x00,0x60,0x00,0x07,0xFF,0xFF,0xFE,0x00,0x00,0x00,0x00,0x00,0x0E,0x7F,0xFF
                fcb 0xFF,0xF3,0xBB,0xFF,0xC0,0x00,0x01,0xFF,0xFF,0xF8,0x0F,0xFF,0xFF,0x80,0x00,0x01
                fcb 0xF8,0x00,0x20,0x00,0x3F,0xFF,0xFF,0xFE,0x00,0x00,0x00,0x00,0x00,0x1B,0x7F,0xFF
                fcb 0xFF,0xF7,0xFF,0xFF,0x80,0x00,0x03,0xFF,0xFF,0xFC,0x0F,0xFF,0xFF,0xFC,0x03,0x03
                fcb 0xFF,0x7F,0xF0,0x03,0xFF,0xFF,0xFF,0xFC,0x00,0x00,0x00,0x00,0x00,0x0E,0x7F,0xFF
                fcb 0xFF,0xF7,0xFE,0xFF,0x80,0x01,0x5D,0xFF,0xFF,0xFC,0x0F,0xFF,0xFF,0xC0,0x07,0xF1
                fcb 0xFC,0x07,0xFC,0x00,0x3F,0xFF,0xFF,0xFC,0x00,0x00,0x00,0x00,0x00,0x03,0x7F,0xFF
                fcb 0xFF,0xF7,0xBF,0xFF,0x00,0x02,0xEF,0xFF,0xFF,0xFC,0x0F,0xFF,0xFF,0x00,0x0E,0x00
                fcb 0x7C,0x00,0xF4,0x00,0x0C,0x7F,0xFF,0xF8,0x00,0x00,0x00,0x00,0x00,0x0E,0x7F,0xFF
                fcb 0xFF,0xF2,0xAB,0xFF,0x00,0x05,0xFF,0xFF,0xFF,0xFE,0x0F,0xFF,0xFF,0xF8,0x1C,0x00
                fcb 0xFC,0x01,0xF8,0x01,0xFB,0xBF,0xFF,0xF8,0x00,0x00,0x0F,0xE1,0x80,0x0B,0x7F,0xFF
                fcb 0xFF,0xF7,0xBF,0xFF,0x00,0x03,0xFF,0xFF,0xFF,0xFE,0x0F,0xFF,0xFF,0xF8,0x1F,0xC0
                fcb 0xFE,0x3F,0xFC,0x01,0xF6,0xDF,0xFF,0xF8,0x00,0x3F,0xFF,0xFF,0x80,0x0E,0x7F,0xFF
                fcb 0xFF,0xF6,0xEE,0xEE,0x00,0x07,0xFF,0xFF,0xFF,0xFE,0x0F,0xFE,0xFF,0xFC,0x1F,0xF1
                fcb 0xFF,0x9F,0xF8,0x37,0xF5,0xDF,0xFF,0xF8,0x00,0xFF,0xFF,0xFF,0x80,0x0B,0x7F,0xFF
                fcb 0xFF,0xF7,0xBF,0xFF,0x00,0x07,0xFF,0xFF,0xFF,0xFF,0x07,0xFF,0xFF,0xF8,0x0F,0xEF
                fcb 0x7F,0xFF,0xFC,0x03,0xF6,0xDF,0xFF,0xF8,0x7F,0xFF,0xFF,0xFF,0x80,0x06,0x7F,0xFF
                fcb 0xFF,0xF6,0xFF,0xBF,0x00,0x03,0xFF,0xFF,0xFF,0xFF,0x07,0xFB,0xBB,0xFD,0xDF,0xFF
                fcb 0xEF,0xFF,0xF9,0x7F,0xFB,0xBF,0xFF,0xFC,0x7F,0xFF,0xFF,0xFF,0xC0,0x0B,0x7F,0xFF
                fcb 0xFF,0xF7,0xBF,0xFE,0x00,0x03,0xFF,0xFF,0xFF,0xF8,0x07,0xFF,0xFF,0xFF,0x9F,0xFF
                fcb 0xFF,0xFF,0xFF,0xBF,0xFC,0x7F,0xFF,0xFC,0x75,0x0F,0xFF,0xCF,0xC0,0x0E,0x7F,0xFF
                fcb 0xFF,0xF6,0xFF,0xFE,0x00,0x07,0xF5,0x47,0xFF,0xE0,0x07,0xFF,0xEF,0xFF,0xCF,0xFD
                fcb 0xFF,0xFF,0xFF,0x3F,0xFF,0xFF,0xFF,0xFC,0x00,0x00,0xE0,0x07,0xC0,0x0F,0x7F,0xFF
                fcb 0xFF,0xF7,0xBF,0xFF,0x00,0x0F,0xF8,0x07,0xFF,0xDC,0x07,0xFF,0xFF,0xFF,0xCF,0xFB
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFC,0x00,0x00,0x00,0x03,0xE0,0x0D,0x7F,0xFF
                fcb 0xFF,0xF6,0xFF,0xFE,0x00,0x1F,0xD1,0x1F,0xFF,0xEF,0x07,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xF1,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x00,0x00,0x00,0x7B,0xF0,0x0B,0x7F,0xFF
                fcb 0xFF,0xF3,0xBF,0xFE,0x00,0x1F,0xFF,0xEF,0xFE,0x81,0x07,0xFF,0xFF,0xFF,0x7F,0xF8
                fcb 0x40,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x60,0x01,0xFC,0x1D,0xF0,0x0D,0x7F,0xFF
                fcb 0xFF,0xF6,0xEE,0xFF,0x00,0x1F,0xFF,0x01,0xFE,0x01,0x87,0xFE,0xEE,0xFF,0xFF,0xF0
                fcb 0x00,0x1F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0xE0,0x03,0xF0,0x67,0xF0,0x17,0x7F,0xFF
                fcb 0xFF,0xF3,0xBF,0xFE,0x00,0x1F,0xF8,0x01,0xFC,0x03,0x87,0xFF,0xFF,0xFF,0xFF,0xC0
                fcb 0x00,0x0F,0xFC,0x3F,0xFF,0xFF,0xFF,0xFF,0xC0,0x03,0xF0,0x33,0xF0,0x5F,0x7F,0xFF
                fcb 0xFF,0xF6,0xAF,0xFE,0x00,0x1F,0xFF,0xF0,0xFE,0x0F,0x87,0xFF,0xBF,0xFF,0xFF,0x80
                fcb 0xFF,0x07,0xF8,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0x03,0xFA,0xFF,0xF1,0xBB,0x7F,0xFF
                fcb 0xFF,0xF3,0xBF,0xBF,0x00,0x1F,0xFF,0xFE,0xFE,0x9B,0x87,0xFF,0xFF,0xFF,0xFF,0xBD
                fcb 0x80,0xF3,0xF8,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0x17,0xFF,0xFF,0xF4,0xEE,0x7F,0xFF
                fcb 0xFF,0xF6,0xEE,0xFF,0x00,0x1F,0xFF,0xFF,0xFF,0x03,0x87,0xEF,0xEE,0xEF,0xFF,0x00
                fcb 0x00,0x07,0xF8,0x3F,0xFF,0xFF,0xFF,0xFF,0xFF,0x77,0xFF,0xFF,0xFE,0xBB,0x7F,0xFF
                fcb 0xFF,0xF3,0xBF,0xBF,0x00,0x0F,0xFF,0xEF,0xF8,0x83,0x87,0xFF,0xFF,0xFF,0xFF,0xBE
                fcb 0xBF,0xFF,0xF8,0x7F,0xFF,0xFF,0xFF,0xFF,0xFD,0xB3,0xFF,0xFF,0xFD,0xEE,0x7F,0xFF
                fcb 0xFF,0xF6,0xEE,0xEF,0x00,0x0F,0xFF,0xF8,0x7F,0xF7,0x8F,0xFF,0xFB,0xBF,0xFF,0xFF
                fcb 0xFF,0xF7,0xFC,0xFF,0xBF,0xFF,0xFF,0xFF,0xFF,0x07,0xFF,0xFF,0xFF,0xBB,0x7F,0xFF
                fcb 0xFF,0xF3,0xBB,0xBB,0x00,0x0F,0xFF,0xF3,0x7F,0x0F,0x8F,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xBF,0xE3,0xFC,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x07,0xFF,0xFF,0xFF,0xEE,0x7F,0xFF
                fcb 0xFF,0xF6,0xEE,0xEF,0x00,0x0F,0xFE,0xF7,0xFF,0xCF,0x8E,0xFF,0xFF,0xEF,0xFF,0xFF
                fcb 0x17,0xF7,0xFD,0xEF,0xEF,0xFE,0xFF,0xFF,0xFF,0x9F,0xFF,0xFF,0xFF,0xBB,0x7F,0xFF
                fcb 0xFF,0xF3,0xBB,0xBB,0x00,0x07,0xFF,0xFE,0xFF,0xC1,0x9F,0xFF,0xFF,0xFF,0xFF,0xFE
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x07,0xF7,0xFF,0xFE,0xEE,0x7F,0xFF
                fcb 0xFF,0xF6,0xEE,0xEE,0x00,0x03,0xFF,0xC4,0x1C,0x03,0x9B,0xFB,0xAF,0xBF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFE,0xFB,0xFB,0xBB,0xFF,0xBF,0xFE,0x02,0xAB,0xFF,0xF8,0xFB,0x7F,0xFF
                fcb 0xFF,0xF3,0xBF,0xBA,0x04,0x03,0xFA,0x00,0x00,0x01,0x9F,0xFF,0xBB,0xFF,0xFB,0xFF
                fcb 0xFF,0xFF,0xFB,0xBF,0xFF,0xFB,0xFE,0xEF,0xFC,0x00,0x05,0xFF,0xF9,0xEE,0x7F,0xFF
                fcb 0xFF,0xF6,0xEE,0xEC,0x06,0x01,0xFC,0xA2,0x00,0x03,0x9F,0xEE,0xEE,0xEF,0xFE,0xFF
                fcb 0xFF,0xFF,0xFE,0xFF,0xFE,0xEE,0xEF,0xBF,0xFE,0x00,0x00,0x3F,0xFB,0xBB,0x7F,0xFF
                fcb 0xFF,0xF3,0xBB,0xB0,0x00,0x01,0xFA,0x10,0x00,0x03,0x9F,0xFB,0xBB,0xFF,0xFB,0xFF
                fcb 0xFF,0xFF,0xFB,0xBF,0xFF,0xFB,0xBE,0xEF,0xFC,0x0F,0x80,0x1F,0xF6,0xEE,0x7F,0xFF
                fcb 0xFF,0xF6,0xEE,0xEE,0x00,0x00,0x68,0x5F,0xFE,0x03,0x1B,0xAE,0xAE,0xFB,0xEE,0xFD
                fcb 0xFF,0xFF,0xFE,0xAB,0xBB,0xEA,0xFF,0xBF,0xF8,0x0B,0xFC,0x1F,0xFF,0xBB,0x7F,0xFF
                fcb 0xFF,0xF3,0xBB,0xBA,0x00,0x00,0x7B,0x0F,0xFE,0x00,0x1F,0xBB,0xBB,0xFF,0xFB,0xFF
                fcb 0xFF,0xFF,0xFB,0xBB,0xFF,0xBB,0xBE,0xEF,0xFC,0x07,0xFC,0x5F,0xF6,0xEE,0x7F,0xFF
                fcb 0xFF,0xF6,0xEE,0xEE,0x00,0x00,0x14,0x40,0x3C,0x00,0x0E,0xEE,0xEE,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFE,0xEE,0xEE,0xEE,0xEF,0xBF,0xFE,0x00,0x61,0xFF,0xFF,0xBB,0x7F,0xFF
                fcb 0xFF,0xF3,0xBB,0x80,0x00,0x00,0x00,0x7E,0x00,0x00,0x3F,0xBB,0xFF,0xFF,0xBF,0xFF
                fcb 0xFF,0xFF,0xFF,0xBB,0xFF,0xBB,0xBE,0xEF,0xFF,0xE0,0x07,0xFF,0xFF,0xEE,0x7F,0xFF
                fcb 0xFF,0xF6,0xEE,0x00,0x00,0x00,0x00,0x3F,0xEE,0x80,0x2E,0xAB,0xBF,0xBE,0xFC,0xFF
                fcb 0xFF,0xFF,0xFE,0xEB,0xBB,0xAA,0xBB,0xBF,0xEF,0xFA,0xFF,0xFF,0xF8,0x0B,0x7F,0xFF
                fcb 0xFF,0xF3,0xBA,0x00,0x00,0xC0,0x00,0x0F,0xFE,0x00,0x3B,0xBF,0xFF,0xFB,0xB1,0xFF
                fcb 0xFF,0xFF,0xF3,0xBB,0xFF,0xBB,0xAE,0xEF,0xBF,0xD9,0x7F,0xFF,0xF8,0x02,0x7F,0xFF
                fcb 0xFF,0xF6,0xEC,0x00,0x00,0xE0,0x00,0x00,0x00,0x00,0xEE,0xEE,0xEF,0xEE,0xE1,0xFF
                fcb 0xFF,0xFF,0xF0,0xEE,0xEE,0xEE,0xEB,0xBF,0xEF,0x8E,0x3F,0xFF,0xF8,0x00,0x7F,0xFF
                fcb 0xFF,0xF3,0xBA,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0xBB,0xBB,0xBF,0xBB,0xB1,0xFF
                fcb 0xFF,0xFF,0xE0,0x3B,0xFF,0xBB,0xEE,0xFF,0xBB,0x00,0x5F,0xFF,0xF8,0x00,0x7F,0xFF
                fcb 0xFF,0xF6,0xE0,0x04,0x00,0x78,0x00,0x00,0x00,0x01,0xEE,0xAA,0xAE,0xEA,0xC0,0x7F
                fcb 0xFF,0xFF,0x80,0x0B,0xFF,0xEF,0xAB,0xFF,0xEF,0xC2,0x3F,0xFF,0xFF,0xE0,0x7F,0xFF
                fcb 0xFF,0xF3,0x80,0x00,0x00,0x7C,0x00,0x00,0x00,0x00,0x3B,0xBB,0xBB,0xBB,0x00,0x3F
                fcb 0xFF,0xFF,0x00,0x03,0xFF,0xFE,0xEE,0xEF,0xBB,0xC0,0x7F,0xFF,0xFE,0xF8,0x7F,0xFF
                fcb 0xFF,0xF6,0x60,0xC0,0x00,0x7F,0x00,0x00,0x00,0x00,0x2E,0xEE,0xEE,0xEC,0x00,0x01
                fcb 0x3F,0xFC,0x00,0x00,0x6E,0xEF,0xFF,0xFB,0xEE,0xE2,0x3F,0xFF,0xFE,0x78,0x7F,0xFF
                fcb 0xFF,0xF0,0x98,0x60,0x00,0x3F,0x80,0x00,0x00,0x00,0x03,0xBB,0xBB,0xB8,0x00,0x00
                fcb 0x00,0x00,0x00,0x00,0x01,0xBB,0xBB,0xBA,0xBB,0x5F,0x9F,0xFF,0xFC,0xF8,0x7F,0xFF
                fcb 0xFF,0xF6,0x00,0x30,0x00,0x0F,0xC0,0x00,0x00,0x00,0x00,0x6A,0xEE,0xA0,0x00,0x00
                fcb 0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFA,0xEE,0x83,0xFF,0xFF,0xFC,0xF8,0x7F,0xFF
                fcb 0xFF,0xF4,0x00,0x00,0x00,0x07,0xE0,0x00,0x00,0x00,0x05,0x13,0xBB,0x80,0x00,0x00
                fcb 0x00,0x00,0x00,0x00,0x00,0x2E,0xEE,0xEA,0x9B,0xA3,0xFF,0xFF,0xFD,0xF0,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x01,0xF0,0x00,0x00,0x00,0x00,0x0E,0xEE,0x80,0x00,0x00
                fcb 0x00,0x00,0x00,0x00,0x00,0x2F,0xFE,0xAA,0x0E,0xED,0xFF,0xFF,0xF9,0xF0,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0x00,0x03,0xBB,0x80,0x00,0x00
                fcb 0x00,0x00,0x00,0x00,0x00,0x0A,0xBA,0xA8,0x0B,0xFB,0x7F,0xFF,0xF3,0xF0,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x3C,0x00,0x00,0x00,0x00,0x02,0x8A,0x80,0x00,0x00
                fcb 0x00,0x00,0x00,0x00,0x00,0x02,0xFE,0xA0,0x06,0xFE,0xFF,0xFF,0x07,0xF0,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x1E,0x00,0x00,0x00,0x00,0x07,0x03,0x80,0x00,0x00
                fcb 0x00,0x00,0x00,0x00,0x00,0x02,0xAA,0x80,0x07,0xF9,0xFF,0xFC,0x07,0xF4,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x0F,0x14,0x0E,0x00,0x00,0x02,0x80,0x80,0x00,0x00
                fcb 0x00,0x00,0x00,0x00,0x00,0x00,0xAA,0x80,0xBF,0xFF,0xBF,0xF0,0x0F,0xF6,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x03,0xFF,0xFC,0x00,0x00,0x03,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0x00,0x00,0x00,0xEA,0x0F,0xFE,0x7C,0x77,0x80,0x1F,0xF6,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x01,0xFF,0xF8,0x00,0x00,0x03,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x7F,0xFC,0xFE,0x80,0x00,0x1F,0xF7,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0x00,0x00,0x03,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x37,0x3C,0xFE,0xC0,0x00,0xBF,0xF7,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x07,0x7F,0xE0,0x00,0x00,0xF3,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x3E,0xFF,0x80,0x01,0xFF,0xF7,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0xA3,0xFF,0xC0,0x00,0x00,0x63,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0xFD,0xEE,0x80,0x07,0xFF,0xF7,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x63,0xFF,0xC0,0x00,0x00,0x73,0x00,0x00,0x00,0x00
                fcb 0xFF,0x00,0x00,0x00,0x00,0x00,0x08,0x1F,0x78,0xF7,0xE8,0x9F,0xFF,0xFC,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x77,0xBF,0x80,0x00,0x00,0x33,0x00,0x00,0x00,0x3F
                fcb 0xBB,0xE0,0x00,0x00,0x00,0x00,0x00,0x1F,0xF8,0x3B,0x55,0x7F,0x80,0x70,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x01,0xFF,0x00,0x00,0x00,0x3B,0x00,0x00,0x00,0xFF
                fcb 0x3B,0xFC,0x00,0x00,0x00,0x00,0x00,0x1F,0xFF,0x1D,0x8E,0xE7,0x82,0xF8,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x30,0x00,0x00,0x01,0xFE
                fcb 0xF9,0x9F,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xC1,0x17,0xFF,0xFF,0xC0,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0xF8
                fcb 0xFF,0x3F,0xE0,0x00,0x04,0x00,0x00,0x0F,0xBF,0xC2,0xEF,0xFF,0xFF,0x80,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x1C,0x00,0x00,0x08,0xFB
                fcb 0xFF,0x37,0xE0,0x00,0x00,0x00,0x00,0x0F,0xBF,0xC1,0x1F,0xFF,0xFF,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x00,0x1D,0x07
                fcb 0xFF,0xE3,0x68,0x00,0x00,0x00,0x00,0x07,0x7F,0xC7,0x3F,0xFF,0xFE,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F
                fcb 0xFF,0xFB,0xF6,0x00,0x00,0x00,0x00,0x07,0x7F,0xE1,0x7F,0xFF,0xFC,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x00,0x00,0x00,0x00,0x01,0xC6,0x7F
                fcb 0xFF,0xFF,0xE8,0x00,0x00,0x00,0x00,0x07,0x0F,0xF3,0x8F,0x97,0xFC,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xB1,0xEF
                fcb 0xFF,0xEF,0xB7,0x00,0x00,0x00,0x00,0x07,0x83,0xE1,0xC6,0x00,0x78,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x21,0xDF
                fcb 0xFF,0xD1,0xA2,0x00,0x00,0x40,0x00,0x03,0x00,0xF1,0xFF,0x14,0x20,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0xFF
                fcb 0xFF,0xFF,0xDF,0x00,0x00,0x00,0x00,0x03,0x06,0x70,0x7C,0x00,0xC0,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF
                fcb 0xFF,0xFF,0xE7,0xE0,0x00,0x00,0x00,0x03,0x87,0xF1,0xF8,0x03,0x80,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0xAF
                fcb 0xFF,0xFF,0xF7,0x00,0x00,0x00,0x00,0x03,0x8F,0xFB,0xF8,0x20,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0xBF
                fcb 0xFF,0xFF,0xBF,0xE0,0x00,0x00,0x00,0xF3,0x8D,0xFF,0xF8,0x5F,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1E,0xFF
                fcb 0xFF,0xFF,0x4F,0xF0,0x00,0x00,0x01,0xE3,0x87,0xFF,0xFC,0x6E,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0D,0xF7
                fcb 0xBF,0xFF,0xEF,0xE8,0x00,0x00,0x00,0x01,0x1F,0xFF,0xFF,0xFE,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0xFF
                fcb 0x9F,0xFF,0xFD,0xF8,0x00,0x00,0x00,0x01,0xBF,0xFF,0xFF,0xFF,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xFF
                fcb 0xFF,0xFF,0x8F,0xE8,0x00,0x00,0x00,0x01,0xBF,0xFF,0xFF,0xFC,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xFF
                fcb 0xFF,0xFF,0xFF,0xF8,0x00,0x00,0x00,0x01,0xBF,0xFF,0xFF,0xF8,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xFF
                fcb 0xFF,0x9F,0xFF,0xF8,0x00,0x00,0x00,0x01,0x3F,0xFF,0xFF,0xF0,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0x07,0xFF
                fcb 0x1F,0xFF,0xF5,0xFC,0x00,0x00,0x00,0x01,0x3F,0xFF,0xFF,0xE0,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xFC
                fcb 0x3F,0xFF,0xBF,0xF8,0x00,0x00,0x00,0x01,0x3F,0x85,0xFF,0xC0,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xFF
                fcb 0xF7,0xFF,0xDF,0xF8,0x00,0x00,0x00,0x00,0x1D,0x2A,0x07,0x80,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xFF
                fcb 0xFF,0xFF,0xFF,0xF8,0x00,0x00,0x00,0x01,0x06,0xFF,0x00,0x00,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x1F,0xFF
                fcb 0xFF,0xFF,0xDF,0xF8,0x00,0x00,0x00,0x01,0x17,0x3D,0x95,0x00,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xFF,0x80,0x00,0x07,0xFF
                fcb 0xFF,0xFF,0xEF,0xF8,0x00,0x00,0x00,0x00,0x0E,0xEF,0xDA,0x00,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xFF
                fcb 0xFF,0xFF,0xF7,0xF0,0x00,0x00,0x00,0x00,0x15,0xF7,0x80,0x00,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xFF
                fcb 0xFF,0xFF,0xED,0xE0,0x00,0x00,0x00,0x00,0x0F,0xBF,0xEC,0x00,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xFF
                fcb 0xFF,0xFF,0xDC,0xE0,0x00,0x00,0x00,0x00,0x17,0x7F,0xD8,0x00,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xFF
                fcb 0xFF,0xFF,0xBC,0xC0,0x00,0x00,0x00,0x00,0x3F,0xFF,0xF8,0x00,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xFF
                fcb 0xFF,0xFF,0xDE,0x00,0x00,0x00,0x00,0x00,0x7F,0xFF,0xF8,0x00,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xFF
                fcb 0xFF,0xFF,0xFF,0x80,0x00,0x00,0x00,0x00,0x7F,0xFF,0xF8,0x00,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF
                fcb 0xFF,0xFB,0xFF,0x80,0x00,0x00,0x00,0x00,0x7F,0xFF,0xF0,0x00,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xDF
                fcb 0xFE,0xC1,0xF2,0x00,0x00,0x00,0x00,0x18,0x7F,0xFF,0xF0,0x00,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x83
                fcb 0x00,0x1F,0xCC,0x00,0x00,0x00,0x00,0x00,0x7F,0xFF,0xF0,0x00,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00
                fcb 0x80,0x3F,0x98,0x00,0x00,0x00,0x00,0x00,0x7F,0xFF,0xF0,0x00,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE2
                fcb 0x46,0x3E,0x60,0x00,0x00,0x00,0x00,0x00,0x7F,0xFF,0xE0,0x00,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80
                fcb 0x33,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x60,0x00,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xA0
                fcb 0x73,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x15,0x3A,0x80,0x00,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0
                fcb 0x08,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0xF6,0x00,0x00,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0
                fcb 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x17,0xB6,0x00,0x00,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0xED,0x80,0x00,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x2C,0x00,0x00,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0xB0,0x80,0x00,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0xFF,0x00,0x00,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x7F,0xFF,0x80,0x00,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x7F,0xFF,0xC0,0x00,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0xFF,0x80,0x00,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0xFF,0x80,0x00,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0xFF,0x80,0x00,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xF7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0xFF
                fcb 0xFF,0xF7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0xFF
                fcb 0xFF,0xF7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0xFF
                fcb 0xFF,0xF7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0xFF
                fcb 0xFF,0xF7,0xFF,0xFF,0x3C,0xFF,0xF3,0x3F,0xFF,0xCF,0x9F,0xFF,0xFF,0xFF,0x03,0xFF
                fcb 0xCC,0xFF,0xFF,0xF3,0xFF,0xFF,0xF8,0x1F,0xFE,0x0F,0xFF,0x8F,0xFF,0xFF,0x7F,0xFF
                fcb 0xFF,0xF7,0xFF,0xFF,0x18,0xFF,0xF3,0x3F,0xFF,0xCF,0xFF,0xFF,0xFF,0xFF,0xCF,0xFF
                fcb 0xCC,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x7F,0xFE,0x7F,0xFF,0xCF,0xFF,0xFF,0x7F,0xFF
                fcb 0xFF,0xF7,0xFF,0xFF,0x00,0xFF,0xF3,0x31,0x9E,0x49,0x10,0xE1,0xFF,0xFF,0xCF,0xFF
                fcb 0xCC,0xC6,0x08,0x23,0x0F,0xFF,0xFE,0x7F,0xFE,0x7C,0x60,0xCC,0x70,0xFF,0x7F,0xFF
                fcb 0xFF,0xF7,0xFF,0xFF,0x24,0xFF,0xF0,0x3C,0xC0,0xC3,0x92,0x4F,0xFF,0xFF,0xCF,0xFF
                fcb 0xC0,0xF2,0x38,0xF2,0x7F,0xFF,0xFE,0x7F,0xFE,0x1F,0x23,0xC9,0x27,0xFF,0x7F,0xFF
                fcb 0xFF,0xF7,0xFF,0xFF,0x3C,0xFF,0xF3,0x30,0xC0,0xC7,0x92,0x63,0xFF,0xFF,0xCF,0xFF
                fcb 0xCC,0xC2,0x79,0xF3,0x1F,0xFF,0xFE,0x7F,0xFE,0x7C,0x27,0xC8,0x31,0xFF,0x7F,0xFF
                fcb 0xFF,0xF7,0xFF,0xFF,0x3C,0xFF,0xF3,0x24,0xE1,0xC3,0x92,0x79,0xFF,0xFF,0xCF,0xFF
                fcb 0xCC,0x92,0x79,0xF3,0xCF,0xFF,0xFE,0x7F,0xFE,0x79,0x27,0xC9,0xFC,0xFF,0x7F,0xFF
                fcb 0xFF,0xF7,0xFF,0xFF,0x3C,0x9F,0xF3,0x30,0xE1,0xC9,0x92,0x43,0xFF,0xFF,0xCE,0x7F
                fcb 0xCC,0xC2,0x79,0xF2,0x1F,0xFF,0xFE,0x73,0xFE,0x0C,0x27,0xCC,0x61,0xFF,0x7F,0xFF
                fcb 0xFF,0xF7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0xFF
                fcb 0xFF,0xF7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0xFF
                fcb 0xFF,0xF7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0xFF
                fcb 0xFF,0xF7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0xFF
                fcb 0xFF,0xF7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x7F,0xFF
                fcb 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
AUTHPICe        equ *
; Unused
                fcb 0xFF,0x00,0x00,0xA0,0x27,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xEF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF
                fcb 0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x40,0x00
                fcb 0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; The actual Super Extended Basic (SECB) extensions start here.
;
; Note that many routines in this area feature a "lbrn 0" instruction. This appears to be intended as a placeholder to allow
; patching into the routines similar to the RAM hooks in Color Basic except using direct overwiting of the instruction. It's
; completely pointless and probably illustrates that the writers of this code didn't really think through what they were doing.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SUPERVAR        fdb HRMODE                      ; address of direct page variables unique to SECB
PRGTEXT         fdb SETTEXT                     ; set video registers for text mode (indirect)
PRGGRAPH        fdb SETGRAPH                    ; set video registers for graphics mode (indirect)
PRGMMU          fdb SETMMU                      ; set MMU registers to their "default" (indirect)
GETTEXT         fdb SELTEXT                     ; put hi-res text screen in logical block 1 (indirect)
GETBLOK0        fdb SELBLOK0                    ; put block in B in logical block 0 (indirect)
GETTASK0        fdb SELTASK0                    ; re-select MMU task 0 (indirect)
GETTAKS1        fdb SELTASK1                    ; select MMU task 1(indirect)
                jmp LA05E                       ; execute non-self starting ROM
SPARE0          fdb 0                           ; undefined
SPARE1          fdb 0                           ; undefined
SPARE2          fdb 0                           ; undefined
; Set up video registers for the selected text screen. Given that the sets of video mode initializers are contiguous in
; memory, this would probably be better done with a simple sequence of MUL and ABX.
SETTEXT         pshs y,x,a                      ; save registers
                lbrn 0
                ldx #IM.TEXT                    ; point to 32 column video mode registers
                lda HRWIDTH                     ; get text mode
                beq SETVIDEO                    ; brif 32 column
                ldx #SE03B                      ; point to 40 column mode data
                cmpa #1                         ; is it 40 column?
                beq SETVIDEO                    ; brif so
                ldx #SE044                      ; assume 80 column
                bra SETVIDEO                    ; program video registers
; 32 column (VDG) initializer
IM.TEXT         fcb COCO+MMUEN+MC3+MC2          ; INIT0 (COCO bit enables VDG modes)
                fcb 0x00                        ; VIDEOMOD (unused for VDG modes)
                fcb 0x00                        ; VIDEORES (unused for VDG modes)
                fcb 0x00                        ; V.BORDER (black)
                fcb 0x00                        ; filler for reserved
                fcb 0x0f                        ; V.SCROLL - this value is needed to show a proper 12 lines per text row
                fdb 0xe000                      ; V.OFFSET - SAM offsets operate in 0x7xxx
                fcb 0x00                        ; H.OFFSET - no horizontal offset
; 40 column screen
SE03B           fcb MMUEN+MC3+MC2               ; INIT0 (disable VDG modes)
                fcb 0x03                        ; VIDEOMOD - 8 lines per row
                fcb 0x05                        ; VIDEORES - 40 columns, attributes enabled, 192 lines per field
                fcb 0x12                        ; V.BORDER - nuclear green
                fcb 0x00                        ; filler for reserved
                fcb 0x00                        ; V.SCROLL - no offset
                fdb 0xd800                      ; V.OFFSET - screen at 0x6c000
                fcb 0x00                        ; H.OFFSET - no offset
; 80 column screen
SE044           fcb MMUEN+MC3+MC2               ; INIT0 (disable VDG modes)
                fcb 0x03                        ; VIDEOMOD - 8 lines per row
                fcb 0x15                        ; VIDEORES - 80 columns, attributes enabled, 192 lines per field
                fcb 0x12                        ; V.BORDER - nuclear green
                fcb 0x00                        ; filler for reserved
                fcb 0x00                        ; V.SCROLL - no offset
                fdb 0xd800                      ; V.OFFSET - screen at 0x6c000
                fcb 0x00                        ; H.OFFSET - no offset
; Set up video registers for the selected "HSCREEN" mode. Note that the two code paths for the resolution widths
; are unneeded.
SETGRAPH        pshs y,x,a                      ; save registers
                lbrn 0
                ldx #IM.GRAPH                   ; point to graphics initlializer
                ldy #RESTABLE                   ; point to resolution bytes table
                lda HRMODE                      ; get graphics mode
                cmpa #2                         ; is it a 640 pixel mode?
                bls SE063                       ; brif not
                ldx #SE079                      ; point to 640 pixel registers
SE063           suba #1                         ; normalize mode numbers to start at 0
                lda a,y                         ; get resolution setting for this mode
                sta 2,x                         ; put it in the graphics mode initializer
                jmp SETVIDEO                    ; go set up video registers
RESTABLE        fcb 0x15                        ; 320x192, 4 colours
                fcb 0x1e                        ; 320x192, 16 colours
                fcb 0x14                        ; 640x192, 2 colours
                fcb 0x1d                        ; 640x192, 4 colours
; 320x192 graphics modes
IM.GRAPH        fcb MMUEN+MC3+MC2               ; INIT0 (disable VDG modes)
                fcb 0x80                        ; VIDEOMOD - enable bit plane, one line per row
                fcb 0x00                        ; VIDEORES - placeholder
                fcb 0x00                        ; V.BORDER - black
                fcb 0x00                        ; filler for reserved
                fcb 0x00                        ; V.SCROLL - no offset
                fdb 0xc000                      ; V.OFFSET - screen at 0x60000
                fcb 0x00                        ; H.SCROLL - no offset
; 640x192 graphics modes (observe that these are identical to the 320x192 ones above)
SE079           fcb MMUEN+MC3+MC2               ; INITo (disable VDG modes)
                fcb 0x80                        ; VIDEOMOD - enable bit plane, one line per row
                fcb 0x00                        ; VIDEORES - placeholder
                fcb 0x00                        ; V.BORDER - black
                fcb 0x00                        ; filler for reserved
                fcb 0x00                        ; V.SCROLL - no offset
                fdb 0xc000                      ; V.OFFSET - screen at 0x60000
                fcb 0x00                        ; H.SCROLL - no offset
; Program video registers and INIT0 from (X); enter with A,X,Y pre-saved
SETVIDEO        lda ,x+                         ; set INIT0
                sta INIT0
                ldy #VIDEOMOD                   ; point to start of video mode registers
SE08B           lda ,x+                         ; set a register
                sta ,y+
                cmpy #MMUREG                    ; done all of them?
                blo SE08B                       ; brif not
                puls a,x,y,pc                   ; restore registers and return
; Set MMU registers to their default values. All 16 of them.
SETMMU          pshs y,x,b,a                    ; save registers
                leax IM.MMU,pcr                 ; point to MMU initializer
                bsr SE0F1                       ; program MMU registers
                puls a,b,x,y,pc                 ; restore registers and return
; Set logical block 0 to the physical block in B. This is embarassingly inefficient since it sets
; *all 16* MMU registers to change one of them. All the faffing about with pointers and the call
; to set the MMU registers is pointless. It could be done with a single STB.
SELBLOK0        pshs y,x,b,a                    ; save registers
                leax IM.MMU,pcr                 ; point to MMU initializer
                pshs x                          ; save it for later
                stb ,x                          ; set desired block in initializer
                bsr SE0F1                       ; program *all 16* MMU registers (stupid)
                ldb #BLOCK7.0                   ; get correct block number for logical block 0
                puls x                          ; get back pointer to the initializer
                stb ,x                          ; restore initializer value
                puls a,b,x,y,pc                 ; restore registers and return
; Put hi-res text screen in logical address space block 1. This is embarassingly ineffecient since
; it sets *all 16* MMU registers to change only one. All the faffing about with pointers and the
; call to set the MMU registers is pointless. It could be done with a singel LD/ST sequence.
SELTEXT         pshs y,x,b,a                    ; save registers
                leax IM.MMU,pcr                 ; point to MMU initializer
                pshs x                          ; save pointer for later
                ldb #BLOCK6.6                   ; get block number for text screen
                stb 1,x                         ; put in logical block 1 of initializer
                bsr SE0F1                       ; program *all 16* MMU registers (stupid)
                puls x                          ; get back pointer
                ldb #BLOCK7.1                   ; get proper block for logical block 1
                stb 1,x                         ; put it back in the initializer
                puls a,b,x,y,pc                 ; restore registers and return
; Get block 6.4 (HBUFF buffers) to logical block 6 of task 1. This is embarassingly inefficient
; since it sets *all 16* MMU registers to change only one. All the faffing about with pointers and
; the call to set the MMU registers ispointless. It could be done with a single LD/ST sequence.
SE0CB           pshs y,x,b,a                    ; save registers
                leax IM.MMU,pcr                 ; point to MMU initializer
                pshs x                          ; save pointer for later
                ldb #BLOCK6.4                   ; get block for the HBUFF buffers
                stb 14,x                        ; put in logical block 6, task 1
                bsr SE0F1                       ; program *all 16* MMU registers (stupid)
                puls x                          ; get back pointer
                ldb #BLOCK6.5                   ; get default block for logical block 6 of task 1
                stb 14,x                        ; put it back in the initializer
                puls a,b,x,y,pc                 ; restore registers and return
; MMU initializer
IM.MMU          fcb BLOCK7.0,BLOCK7.1,BLOCK7.2,BLOCK7.3         ; task 0: map 0x70000-0x7ffff
                fcb BLOCK7.4,BLOCK7.5,BLOCK7.6,BLOCK7.7
                fcb BLOCK7.0,BLOCK6.0,BLOCK6.1,BLOCK6.2         ; task 1: put hires gfx at 0x2000 and a stack block at 0xc000
                fcb BLOCK6.3,BLOCK7.5,BLOCK6.5,BLOCK7.7
; Set all 16 MMU registers from the initializer pointed to by X.
SE0F1           ldy #MMUREG                     ; point to MMU registers
                ldb #16                         ; there are 16 to set
SE0F7           lda ,x+                         ; set a register
                sta ,y+
                decb                            ; done all?
                bne SE0F7                       ; brif not
                rts
; Select task register 0 as the active MMU set. Enter with stack in a temporary location which
; holds the original stack pointer. Note that the return could be done simply as jmp [V42] instead
; of pushing the return address onto the stack. Interrupts will be enabled on the way out.
SELTASK0        std V40                         ; temp save D
                ldd ,s                          ; get return address
                std V42                         ; save it
                ldd 2,s                         ; get original stack pointer
                std V44                         ; save it
                clrb                            ; reset INIT1 to task 0 (and slow timer), could just be CLR INIT1
                stb INIT1
                lds V44                         ; restore original stack pointer
                ldd V42                         ; get back return address
                pshs d                          ; set return address on stack
                ldd V40                         ; get back original D
                andcc #0xaf                     ; re-enable interrupts
                rts
; Select task register 1 as the active MMU set. Exit with interrupts disabled and the original
; stack pointer saved at the top of the temporary stack. Note that jmp [V42] could be used to
; return instead of pushing the return address back on the stack.
SELTASK1        orcc #0x50                      ; disable interrupts
                std V40                         ; temp save D
                puls d                          ; get return address
                std V42                         ; save it
                sts V44                         ; save stack pointer
                ldb #1                          ; set to enable task 1, slow timer input
                stb INIT1
                lds #TMPSTACK                   ; point to temporary stack location (top of the C000-Dfff range)
                ldd V44                         ; get old stack pointer
                pshs d                          ; stash it
                ldd V42                         ; put original return address back
                pshs d
                ldd V40                         ; restore original D
                rts
; Tokenziation patch
ALINK2          tst V41                         ; is it a function token?
                bne SE152                       ; brif so
                lda V42                         ; get token value
                cmpa #0x62                      ; have we reached the first SECB token?
                bls SE148                       ; brif not
                ldu #COMVEC-5                   ; point to function table and go again
                jmp LB8D7                       ; re-enter mainline code
SE148           lda #0x62                       ; force tokens to start at the correct number (above Disk Basic)
                ldu #EBCOMTAB-10                ; point to SECB command table
SE14D           sta V42                         ; set token counter to SECB values
                jmp LB89D                       ; re-enter mainstream still in command mode
SE152           lda V42                         ; get token number
                cmpa #0x29                      ; have we run through SECB functions yet?
                bls SE15B                       ; brif not
                jmp LB8D7                       ; re-enter mainline code (end of processing)
SE15B           lda #0x29                       ; force token into SECB range (this leaves one unused)
                ldu #EBCOMTAB-5                 ; point to SECB function table
                bra SE14D                       ; go transfer control back to mainline with new settings
EBCOMTAB        fcb 23                          ; number of keywords (commands)
                fdb COMDIC20                    ; keyword table (commands)
                fdb ALINK4                      ; interpretation handler (commands)
                fcb 5                           ; number of keywords (functions)
                fdb FUNDIC20                    ; keyword table (functions)
                fdb ALINK5                      ; interpretation handler (functions)
                fcb 0x00,0x00,0x00,0x00,0x00,0x00 ; marker for no further tables
; Detokenization patch. This routine has a bug. It freezes if an unknown token is encountered instead
; of using the placeholder.
ALINK3          leau 10,u                       ; move to next table
                tst ,u                          ; valid table?
                lbne LB7F9                      ; brif so - re-enter mainline code
                leax -1,x                       ; get token number
                lda ,x+
                anda #0x7f                      ; remove token bias
                cmpa #0x62                      ; SECB command?
                blo SE18B                       ; brif not
                suba #0x62                      ; zero-base SECB token number
                ldu #EBCOMTAB-10                ; point to command table
                bra ALINK3                      ; go try again
SE18B           suba #0x29                      ; zero-base function token
                ldu #EBCOMTAB-5                 ; point to SECB function table
                bra ALINK3                      ; go try again
; Command interpretation patch
ALINK4          cmpa #0xe2                      ; is it within the SECB range?
                blo SE19A                       ; brif not (below)
                cmpa #0xf8                      ; is it above range?
                bls SE19E                       ; brif not - we have a SECB command
SE19A           jmp [COMVEC+23]                 ; transfer control onward to Disk Basic
SE19E           suba #0xe2                      ; normalize SECB commands to 0
                ldx #COMDIS20                   ; point to jump table for SECB commands
                jmp LADD4                       ; go dispatch command
; Function processing patch
ALINK5          cmpb #0x29*2                    ; is it an SECB function?
                blo SE1AE                       ; brif not (below)
                cmpb #0x2d*2                    ; is it still an SECB function?
                bls SE1B2                       ; brif so
SE1AE           jmp [COMVEC+28]                 ; transfer control to Disk Basic
SE1B2           subb #0x29*2                    ; normalize SECB functions to 0
                cmpb #2*2                       ; do we need to parse a parameter?
                bhs SE1BF                       ; brif not
                pshs b                          ; save token offset
                jsr LB262                       ; parse parenthetical expression
                puls b                          ; get back token offset
SE1BF           ldx #FUNDIS20                   ; point to jump table for SECB functions
                jmp LB2CE                       ; go dispatch function call
; Keyword table (commands) for SECB
COMDIC20        fcs 'WIDTH'                     ; 0xe2
                fcs 'PALETTE'                   ; 0xe3
                fcs 'HSCREEN'                   ; 0xe4
                fcs 'LPOKE'                     ; 0xe5
                fcs 'HCLS'                      ; 0xe6
                fcs 'HCOLOR'                    ; 0xe7
                fcs 'HPAINT'                    ; 0xe8
                fcs 'HCIRCLE'                   ; 0xe9
                fcs 'HLINE'                     ; 0xea
                fcs 'HGET'                      ; 0xeb
                fcs 'HPUT'                      ; 0xec
                fcs 'HBUFF'                     ; 0xed
                fcs 'HPRINT'                    ; 0xee
                fcs 'ERR'                       ; 0xef
                fcs 'BRK'                       ; 0xf0
                fcs 'LOCATE'                    ; 0xf1
                fcs 'HSTAT'                     ; 0xf2
                fcs 'HSET'                      ; 0xf3
                fcs 'HRESET'                    ; 0xf4
                fcs 'HDRAW'                     ; 0xf5
                fcs 'CMP'                       ; 0xf6
                fcs 'RGB'                       ; 0xf7
                fcs 'ATTR'                      ; 0xf8
; Jump table for SECB commands
COMDIS20        fdb WIDTH                       ; 0xe2 WIDTH
                fdb PALETTE                     ; 0xe3 PALETTE
                fdb HSCREEN                     ; 0xe4 HSCREEN
                fdb LPOKE                       ; 0xe5 LPOKE
                fdb HCLS                        ; 0xe6 HCLS
                fdb HCOLOR                      ; 0xe7 HCOLOR
                fdb HPAINT                      ; 0xe8 HPAINT
                fdb HCIRCLE                     ; 0xe9 HCIRCLE
                fdb HLINE                       ; 0xea HLINE
                fdb HGET                        ; 0xeb HGET
                fdb HPUT                        ; 0xec HPUT
                fdb HBUFF                       ; 0xed HBUFF
                fdb HPRINT                      ; 0xee HPRINT
                fdb ERR                         ; 0xef ERR (should be LB277)
                fdb BRK                         ; 0xf0 BRK (should be LB277)
                fdb LOCATE                      ; 0xf1 LOCATE
                fdb HSTAT                       ; 0xf2 HSTAT
                fdb HSET                        ; 0xf3 HSET
                fdb HRESET                      ; 0xf4 HRESET
                fdb HDRAW                       ; 0xf5 HDRAW
                fdb CMP                         ; 0xf6 CMP
                fdb RGB                         ; 0xf7 RGB
                fdb ATTR                        ; 0xf8 ATTR
; Keyword table for SECB functions
FUNDIC20        fcs 'LPEEK'                     ; 0xa9
                fcs 'BUTTON'                    ; 0xaa
                fcs 'HPOINT'                    ; 0xab
                fcs 'ERNO'                      ; 0xac
                fcs 'ERLIN'                     ; 0xad
; Jump table for SECB functions
FUNDIS20        fdb LPEEK                       ; 0xa9 LPEEK
                fdb BUTTON                      ; 0xaa BUTTON
                fdb HPOINT                      ; 0xab HPOINT
                fdb ERNO                        ; 0xac ERNO
                fdb ERLIN                       ; 0xad ERLIN
; Signon message patch
ALINK12         ldx #L80E8-1                    ; point to ECB's message
                jsr STRINOUT                    ; display it
                ldx #MWAREMS-1                  ; point to Microware string
                jsr STRINOUT                    ; display it
                jmp L80B8                       ; return to mainline code
; Signon message patch for Disk Basic 1.0
ALINK28         ldx #DISK20MS-1                 ; point to modified message
                jmp DC0DC-19                    ; return to mainline code
; Signon message patch for Disk Basic 1.1
ALINK29         ldx #DISK21MS-1                 ; point to modified message
                jmp DC0DC                       ; return to mainline code
DISK20MS        fcc 'DISK EXTENDED COLOR BASIC 2.0'
                fcb 0x0d
                fcc 'COPR. 1981, 1986 BY TANDY'
                fcb 0x0d
                fcc 'UNDER LICENSE FROM MICROSOFT'
                fcb 0x0d
MWAREMS         fcc 'AND MICROWARE SYSTEMS CORP.'
                fcb 0x0d,0x0d,0x00
DISK21MS        fcc 'DISK EXTENDED COLOR BASIC 2.1'
                fcb 0x0d
                fcc 'COPR. 1982, 1986 BY TANDY'
                fcb 0x0d
                fcc 'UNDER LICENSE FROM MICROSOFT'
                fcb 0x0d
                fcc 'AND MICROWARE SYSTEMS CORP.'
                fcb 0x0d,0x0d,0x00
; Extended Basic extra initialization patch
ALINK14         clra                            ; set up to clear things
                clrb
                lbrn 0
                stb H.CRSATT                    ; reset cursor attributes
                std HRMODE                      ; reset to VDG screen and no HSCREEN graphics
                std H.ONBRK                     ; reset ON BRK destination
                std H.ONERR                     ; reset ON ERR destinatin
                sta H.BCOLOR                    ; default HSCREEN background to 0
                lda #1                          ; default HSCREEN foreground to 1
                sta H.FCOLOR
                lda #BLOCK6.4                   ; map the HGET/HPUT buffers
                sta MMUREG
                ldd #0xffff                     ; mark as empty
                std 0
                lda #BLOCK7.0                   ; restore memory map
                sta MMUREG
                jmp LAD19                       ; go finish initializing (NEW)
; ON command patch
ALINK18         cmpa #0xef                      ; ERR?
                beq ERR                         ; brif so
                cmpa #0xf0                      ; BRK?
                beq BRK                         ; brif so
                jsr EVALEXPB                    ; evaluate the ON index argument
                jmp LAF45                       ; return to mainline code
SE3C2           jsr GETNCH                      ; eat the ERR/BRK token
                cmpa #0x81                      ; GO?
                bne SE3CF                       ; brif not
                jsr GETNCH                      ; eat the GO
                cmpa #0xa5                      ; TO?
                bne SE3CF                       ; brif not
                rts
SE3CF           leas 2,s                        ; clean up stack (not needed)
                jmp LB277                       ; raise syntax error
; ERR jumps here if used as a command
; NOTE: you can do ERR <char> GOTO (where <char> is a single character that doesn't prevent GOTO from being tokenized
ERR             bsr SE3C2                       ; check for GOTO
                jsr GETNCH                      ; eat the "TO"
                jsr LAF67                       ; evaluate destination line number
                ldd BINVAL                      ; get line number
                std H.ONERR                     ; set error destination
                ldd CURLIN                      ; get current line number
                std H.ONERRS                    ; save line number where ON ERR was executed
                rts
; BRK jump shere if used as a command.
; Same note as for ERR applies.
BRK             bsr SE3C2                       ; check for GOTO
                jsr GETNCH                      ; eat the "TO"
                jsr LAF67                       ; evaluate destination line number
                ldd BINVAL                      ; get line number
                std H.ONBRK                     ; set break destination
                ldd CURLIN                      ; get current line number
                std H.ONBRKS                    ; save line number where ON BRK was executed
                rts
; Patches for &H parsing
ALINK6A         lsl 2,x                         ; multiply accumulator by 2
                rol 1,x
                rol ,x
                lbcs LBA92                      ; brif we overflowed
                decb                            ; done enough shifts?
                bne ALINK6A                     ; brif not
                suba #'0                        ; remove ASCII bias
                adda 2,x                        ; add digit to accumulator (this cannot cause carry)
                sta 2,x
                rts
ALINK6B         lbcs L8800                      ; brif numeric
                jmp L883F                       ; return to mainline
; Line input patch
ALINK16         cmpa #3                         ; is it BREAK?
                orcc #1                         ; set C for BREAK
                bne SE426                       ; brif not BREAK
                pshs a,cc                       ; save character and break status
                lda HRMODE                      ; is it graphics mode?
                beq SE424                       ; brif not
                clr HRMODE                      ; disable graphics mode
                jsr SETTEXT
SE424           puls cc,a                       ; get back BREAK status and character
SE426           jmp LA3C6                       ; return to mainline
; Break check patch
ALINK15         cmpa #3                         ; BREAK?
                beq SE430                       ; brif so
                jmp LADF4                       ; re-enter mainline
SE430           lda #1                          ; BREAK flag
                sta H.ERRBRK
                lda CURLIN                      ; immediate mode?
                inca
                beq SE43F                       ; brif so
                ldd H.ONBRK                     ; is ON BRK active?
                bne SE449                       ; brif so
SE43F           lda HRMODE                      ; graphics m ode?
                beq SE446                       ; brif not
                jsr SETTEXT                     ; set text mode
SE446           jmp STOP                        ; go handle BREAK
SE449           std BINVAL                      ; set destination line number
                tst H.ERRBRK                    ; error or break?
                bne SE458                       ; brif break
                lds FRETOP                      ; reset stack pointer
                ldd #LADC4                      ; return to main loop
                pshs d
SE458           jsr LAEEB                       ; move to end of line
                leax 1,x                        ; move past line terminator
                ldd BINVAL                      ; get desired line number
                cmpd CURLIN                     ; is it here or later?
                bhi SE466                       ; brif so
                ldx TXTTAB                      ; start search at beginning
SE466           jsr LAD05                       ; find program line
                lbcs SE51E                      ; brif not found
                jmp LAEBB                       ; reset input pointer and return to main loop
; Error handling patch
ALINK20         clr H.ERRBRK                    ; flag error handling
                lda CURLIN                      ; immediate mode?
                inca
                beq SE47D                       ; brif so
                ldx H.ONERR                     ; is ON ERR in effect
                bne SE4B3                       ; brif so
SE47D           pshs a                          ; save register
                lda HRMODE                      ; set flags on graphics mode
                puls a                          ; get back A
                beq SE488                       ; brif not graphics mode
                jsr SETTEXT                     ; force text mode
SE488           cmpb #38*2                      ; HG error?
                bne SE49F                       ; brif not
                jsr LB95C                       ; do newline
                jsr LB9AF                       ; do ?
                leax BAS20ERR,pcr               ; point to error string
SE496           jsr LACA0                       ; display two character error message
                jsr LACA0
                jmp LAC65                       ; return to mainline code
SE49F           cmpb #39*2                      ; HP error?
                bne SE4B0                       ; brif not
                jsr LB95C                       ; do newline
                jsr LB9AF                       ; do ?
                leax BAS20ERR+2,pcr             ; point to error string
                jmp SE496                       ; go finish up
SE4B0           jmp LAC49                       ; return to mainline error handler
SE4B3           stb H.ERROR                     ; save error number
                pshs b                          ; save error number
                ldd CURLIN                      ; get current line number
                std H.ERLINE                    ; save line number where error occurred
                puls b                          ; get back error number
                cmpb #3*2                       ; OD error?
                bne SE4C7                       ; brif not
                ldd BINVAL                      ; restore input pointer
                std CHARAD
SE4C7           tfr x,d                         ; save error destination line
                lbra SE449                      ; go transfer control to error handler
BAS20ERR        fcc 'HR'                        ; 38 Hi resolution graphics error
                fcc 'HP'                        ; 39 Hi resolutuion print error
; NEW handling patch
ALINK19         pshs d                          ; save D
                clra                            ; set up to clear things
                clrb
                std OLDPTR                      ; reset CONT address
                std H.ONBRK                     ; reset ON BRK line
                std H.ONERR                     ; reset ON ERR line
                std H.ERLINE                    ; reset error source line
                lda #0xff                       ; set error number to -1
                sta H.ERROR
                puls d                          ; restore d
                jmp LAD43                       ; return to mainline
; ERNO function
ERNO            clra                            ; zero extend error number
                ldb H.ERROR                     ; get error number
                cmpb #0xff                      ; real?
                bne SE4F4                       ; brif so
                sex                             ; return "-1"
                bra SE4FA
SE4F4           cmpb #0xf1                      ; error number 0xf1?
                bne SE4F9                       ; brif not
                comb                            ; turn it back into UL error
SE4F9           asrb                            ; error numbers are pre-multiplied by 2 - undo that
SE4FA           jmp GIVABF                      ; return error number
; ERLIN function
ERLIN           ldd H.ERLINE                    ; get the line number where the error occurred
                bra SE4FA                       ; return it - BUG: will treat lines above 32767 as negative
; Immediate mode patch
ALINK21         jsr SETTEXT                     ; force text mode
                jsr LB95C                       ; do line feed if needed
                orcc #0x50                      ; disable interrupts
                lda #BLOCK6.4                   ; map HGET/HPUT buffers
                sta MMUREG
                ldd #0xffff                     ; mark buffers empty
                std 0
                lda #BLOCK7.0                   ; restore memory map
                sta MMUREG
                andcc #0xaf                     ; re-enable interrupts
                jmp LAC76                       ; return to mainline
; Handle undefined line in ON ERR or ON BRK
SE51E           tst H.ERRBRK                    ; break?
                beq SE528                       ; brif not
                ldd H.ONBRKS                    ; get line number where ON BRK is
                bra SE52B
SE528           ldd H.ONERRS                    ; get line number where ON ERR is
SE52B           std CURLIN                      ; reset the current line number there
                ldb #7*2                        ; undefined line number
                jmp LAC49                       ; raise error (bypass ON ERR check)
; INPUT patch
ALINK17         ldd H.ONBRK                     ; is ON BRK operating?
                lbeq LAE11                      ; brif not
                pshs d                          ; save destination line
                lda #1                          ; set BREAK flag
                sta H.ERRBRK
                puls d                          ; get destination line
                lbra SE449                      ; go handle ON BRK in INPUT
; LPOKE command
LPOKE           jsr LB141                       ; evaluate numeric expression (address)
                lbrn 0
                bsr SE58E                       ; convert to extended address
                cmpb #BLOCK7.7                  ; valid block number?
                lbhi LB44A                      ; brif not
                pshs x,b                        ; save block and offset
                jsr SYNCOMMA                    ; require a comma
                jsr EVALEXPB                    ; evaluate value to put in memory
                tfr b,a                         ; save value in A
                puls b,x                        ; get back block and offset
                cmpb #BLOCK7.7                  ; valid block (we already tested this!!)
                lbhi LB44A                      ; brif not
                orcc #0x50                      ; clobber interrupts
                lbsr SELBLOK0                   ; map the block (by writing *all 16* MMU registers)
                sta ,x                          ; save byte in memory
                lbsr SETMMU                     ; unmap block (by writing *all 16* MMU registers)
                andcc #0xaf                     ; re-enable interrupts
                rts
; LPEEK function
LPEEK           bsr SE58E                       ; convert to block and offset
                lbrn 0
                cmpb #BLOCK7.7                  ; valid block?
                lbhi LB44A                      ; brif not
                orcc #0x50                      ; clobber interrupts
                lbsr SELBLOK0                   ; map the block (by writing *all 16* MMU registers)
                ldb ,x                          ; get memory contents
                lbsr SETMMU                     ; restore map (by writing *all 16* MMU registers)
                andcc #0xaf                     ; re-enable interrupts
                jmp LB4F3                       ; return B as unsigned
SE58E           pshs a                          ; save register
                lda FP0EXP                      ; is it in range for 0x80000?
                cmpa #0x93
                bls SE59A                       ; brif so
                ldb #BLOCK7.7+1                 ; return illegal block number
                bra SE5AF
SE59A           jsr LBCC8                       ; shift binary point to right of mantissa
                ldd FPA0+2                      ; get low bits
                anda #0x1f                      ; mask off block number bits
                tfr d,x                         ; now X has the block offset
                ldd FPA0+1                      ; get high bits
                asra                            ;* shift block number to the right of B; note that
                rorb                            ;* asr *should* be lsr but it works here because of
                asra                            ;* the maximum range of the value
                rorb
                asra
                rorb
                asra
                rorb
                asra
                rorb
SE5AF           puls a,pc                       ; restore registers and return
; BUTTON command
BUTTON          jsr INTCNV                      ; get button number
                lbrn 0
                cmpb #3                         ; button number in range?
                lbhi LB44A                      ; raise error if not
                tfr b,a                         ; save button number
                clrb                            ; set B to 0xff (strobe no keyboard columns)
                comb
                ldx #PIA0                       ; point to PIA0
                stb 2,x                         ; strobe nothing
                ldb ,x                          ; get button data
                cmpb #0x0f                      ; buttons are on bottom four rows
                beq SE5EA                       ; brif no buttons down
                leax SE5D5,pcr                  ; point to button mask routines
                asla                            ; four bytes per button routine
                asla
                jmp a,x                         ; jump to appropriate routine
SE5D5           andb #1                         ; keep button 1, right joystick
                bra SE5E3
                andb #4                         ; keep button #1, left joystick
                bra SE5E3
                andb #2                         ; keep button #2, right joystick
                bra SE5E3
                andb #8                         ; keep button #2, left joystick
SE5E3           bne SE5EA                       ; brif button was not down
                ldd #1                          ; return nonzero if button down
                bra SE5EC                       ; return result
SE5EA           clra                            ; return zero if not down
                clrb
SE5EC           jsr GIVABF                      ; return result
                rts
; PALETTE command
PALETTE         cmpa #0xf7                      ; RGB?
                lbrn 0
                bne SE600                       ; brif not
                jsr GETNCH                      ; munch the RGB
SE5FA           leax IM.RGB,pcr                 ; point to RGB palette initializer
                bra SE634                       ; go set palette registers
SE600           cmpa #0xf6                      ; CMP?
                bne SE60C                       ; brif not
                jsr GETNCH                      ; eat the CMP
SE606           leax IM.CMP,pcr                 ; point to CMP palette initializer
                bra SE634                       ; go set palette registers
SE60C           jsr SE7B2                       ; evaluate two expressions
                ldx #PALETREG                   ; point to palette registers
                ldy #IM.PALET                   ; point to palette register images
                lda BINVAL+1                    ; get palette number
                cmpa #16                        ; valid entry?
                lbhs LB44A                      ; brif not 0-15
                leax a,x                        ; offset the pointers to the right entries
                leay a,y
                ldb VERBEG+1                    ; get colour number
                cmpb #63                        ; valid?
                bls SE62A                       ; brif so
                ldb #63                         ; maximize to 63 (white)
SE62A           orcc #0x50                      ; disable interrupts
                sync                            ; synchronize to VSYNC
                stb ,x                          ; set palette register
                stb ,y                          ; record it in image
                andcc #0xaf                     ; restore interrupts
                rts
SE634           pshs x                          ; save source pointer
                ldy #IM.PALET                   ; point to palette register live image
                bsr SE648                       ; copy source to the live image
                puls x                          ; get source back
                ldy #PALETREG                   ; point to palette registers
                orcc #0x50                      ; disable interrupts
                sync                            ; synchronize to VSYNC
                bsr SE648                       ; copy the colour values into the palette registers
                rts
SE648           ldb #16-1                       ; BUG: should be 16 - this doesn't set register #15
SE64A           lda ,x+                         ; set a register
                sta ,y+
                decb                            ; done all?
                bne SE64A                       ; brif not
                andcc #0xaf                     ; re-enable interrupts
                rts
IM.CMP          fcb 18,36,11,7,63,31,9,38       ; palette values for CMP
                fcb 0,18,0,63,0,18,0,38
IM.RGB          fcb 18,54,9,36,63,27,45,38      ; palette values for RGB
                fcb 0,18,0,63,0,18,0,38
; CMP and RGB commands just jump to the relevant implementations above
RGB             bra SE5FA
CMP             bra SE606
IM.PALET        fcb 18,36,11,7,63,31,9,38       ; live palette images
                fcb 0,18,0,63,0,18,0,38
; HSCREEN command
HSCREEN         cmpa #0                         ; end of line? BUG: won't work if colon terminates the command
                lbrn 0
                bne SE693                       ; brif not end of line
                clrb                            ; default to HSCREEN 0 - turn off graphics
                bra SE69C
SE693           jsr EVALEXPB                    ; evaluate HSCREEN argument
                cmpb #4                         ; only 4 HSCREEN modes
                lbhi LB44A                      ; brif out of range
SE69C           stb HRMODE                      ; set graphics mode
                cmpb #0                         ; HSCREEN 0?
                bne SE6A5                       ; brif not
                jmp SETTEXT                     ; set text mode (disable graphics)
SE6A5           stb HRMODE                      ; set graphics mode (we already did!)
                ldx #SE6CB                      ; point to bytes/row table
                subb #1                         ; normalize mode to 0
                lda b,x                         ; get bytes per row value
                sta HORBYT                      ; set it
                cmpb #1                         ; is it 1 or 2?
                bgt SE6B9                       ; brif not
                ldd #160                        ; default coordinate for middle of 320 screen
                bra SE6BC
SE6B9           ldd #320                        ; default coordainte for middle of 640 screen
SE6BC           std HORDEF                      ; set default horizontal coordinate
                ldd #96                         ; set default vertical coordinate to middle
                std VERDEF
                ldb H.BCOLOR                    ; get background colour
                bsr CLRHIRES                    ; clear hi-res graphics screen
                jmp SETGRAPH                    ; set up to display the screen
SE6CB           fcb 80,160,80,160               ; bytes per row values for HSCREEN 1 through 4
; HCLS command
HCLS            bne SE6D6                       ; brif not end of statement
                ldb H.BCOLOR                    ; get background colour as default
                bra CLRHIRES                    ; go clear screen
SE6D6           bsr SE70E                       ; evaluate colour number
CLRHIRES        tst HRMODE                      ; graphics mode?
                beq SE6EF                       ; brif not
                bsr PIXELFIL                    ; get all pixels set byte
                jsr SELTASK1                    ; swap screen in
                ldx #HRESSCRN                   ; point to start of screen
SE6E4           stb ,x+                         ; set a byte worth of pixels
                cmpx #HRESSCRN+0x8000           ; end of graphics memory?
                bne SE6E4                       ; brif not
                jsr SELTASK0                    ; restore memory map
                rts
SE6EF           ldb #38*2                       ; code for HR error
                jmp LAC46                       ; raise error
; HCOLOR command
HCOLOR          cmpa #',                        ; was a foreground colour given?
                lbrn 0
                beq SE705                       ; brif not
                bsr SE70E                       ; evaluate colour number
                stb H.FCOLOR                    ; save foreground colour
                jsr GETCCH                      ; is there something after the foreground?
                beq SE70D                       ; brif not
SE705           jsr SYNCOMMA                    ; insist on a comma
                bsr SE70E                       ; evaluate colour number
                stb H.BCOLOR                    ; set background colour
SE70D           rts
; Evaluate a colour number and make sure it's between 0 and 15 inclusive
SE70E           jsr EVALEXPB                    ; evaluate colour
SE711           cmpb #16                        ; is it in range?
                lbhs LB44A                      ; brif not
                rts
SE718           jsr SE731                       ; set working colour and pixel bytes to default
                jsr GETCCH                      ; is there a colour number?
                beq SE72F                       ; brif not
                cmpa #')                        ; )?
                beq SE72F                       ; brif so - no colour
                jsr SYNCOMMA                    ; insist on a comma
                cmpa #',                        ; another comma?
                beq SE72F                       ; brif so - colour not specified
                jsr SE70E                       ; evaluate colour
                bsr SE73B                       ; set working colour and pixel bytes
SE72F           jmp GETCCH                      ; get current character and return
SE731           ldb H.FCOLOR                    ; get foreground colour
                tst SETFLG                      ; doing set?
                bne SE73B                       ; brif so
                ldb H.BCOLOR                    ; use background colour if doing reset
SE73B           stb WCOLOR                      ; save working colour
                bsr PIXELFIL                    ; get all pixel byte
                stb ALLCOL                      ; save all pixel byte
                rts
; Return B with all pixels set to colour number in B
PIXELFIL        pshs x                          ; save registers
                lda HRMODE                      ; get graphics mode
                suba #1                         ; normalize mode numbers to start at 0
                ldx #SE759                      ; point to colour masks
                andb a,x                        ; now B has only the relevant low bits of colour number
                lda HRMODE                      ; get graphics mode
                suba #1                         ; normalize mode numbers to start at 0
                ldx #SE75D                      ; point to multiplier table
                lda a,x                         ; get multplier
                mul                             ; now B has all pixels set
                puls x,pc                       ; restore registers and return
SE759           fcb 0x03,0x0f,0x01,0x03         ; colour masks to keep only necessary low bits
SE75D           fcb 0x55,0x11,0xff,0x55         ; multipliers to duplicate colour value across all pixels
; HSET command
HSET            lda #1                          ; HSET flag
                bra SE76A
; HRESET command
HRESET          clra                            ; HRESET flag
                lbrn 0
SE76A           tst HRMODE                      ; are we in a graphics mode?
                beq SE6EF                       ; brif not - raise error
                sta SETFLG                      ; save our set/reset state
                jsr LB26A                       ; insist on (
                jsr SE7AA                       ; evaluate coordindates
                tst SETFLG                      ; resetting?
                bne SE77F                       ; brif so
                jsr SE731                       ; set working colour and pixel byte
                bra SE782
SE77F           jsr SE718                       ; evaluate colour number if present
SE782           jsr LB267                       ; insist on a )
                jsr HCALPOS                     ; fetch screen pointer address and pixel mask
SE788           jsr SELTASK1                    ; map the screen
                jsr SE792                       ; set or reset the pixel
                jsr SELTASK0                    ; unmap the screen
                rts
SE792           ldb ,x                          ; get byte on screen
                pshs b                          ; save it
                tfr a,b                         ; duplicate mask
                coma                            ; invert the mask for clearing the screen data
                anda ,x                         ; reset the pixel
                andb ALLCOL                     ; set pixel mask to correct colour
                pshs b                          ; merge pixel colour into screen data
                ora ,s+
                sta ,x                          ; put modified data on screen
                suba ,s+                        ; nonzero if the screen changed
                ora CHGFLG                      ; merge with existing change flag
                sta CHGFLG
                rts
SE7AA           jsr SE7B2                       ; evaluate coordinates
SE7AD           ldu #HORBEG                     ; point to horizontal coordinates
SE7B0           rts                             ; dummy "normalization" routine
                rts                             ; pointles RTS
; Evaluate two expressions (usually coordinates)
SE7B2           jsr LB734                       ; evaluate two expressions, first in BINVAL, second in B
                ldy #HORBEG                     ; point to horizontal coordinates
SE7B9           cmpb #192                       ; in range vertically?
                blo SE7BF                       ; brif so
                ldb #191                        ; set to maximum coordinate
SE7BF           clra                            ; zero extend vertical
                std 2,y                         ; set vertical coordinate
                lda HRMODE                      ; get graphics mode
                cmpa #2                         ; is it 1 or 2?
                bgt SE7CD                       ; brif not
                ldd #319                        ; maximum coordinate for modes 1 and 2
                bra SE7D0
SE7CD           ldd #639                        ; maximum coordindate for modes 3 and 4
SE7D0           cmpd BINVAL                     ; is our max less than the specified one?
                blo SE7D7                       ; brif so - keep max
                ldd BINVAL                      ; use specified coordinate
SE7D7           std ,y                          ; save horizontal coordinate
                rts
; Calculate pixel mask and memory address for pixel
HCALPOS         bsr SE7E6                       ; point to correct routine for current mode
                jmp ,u                          ; execute it
CALTABLE        fdb G2BITPIX                    ; HSCREEN 1
                fdb G4BITPIX                    ; HSCREEN 2
                fdb G1BITPIX                    ; HSCREEN 3
                fdb G2BITPIX                    ; HSCREEN 4
SE7E6           ldu #CALTABLE                   ; point to routine table
                lda HRMODE                      ; get graphicsmode
                suba #1                         ; zero-base it
                asla                            ; two bytes per address
                ldu a,u                         ; get routine address
                rts
PIX1MASK        fcb 0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01 ; pixel masks for 1 bpp
PIX2MASK        fcb 0xc0,0x30,0x0c,0x03         ; pxiel masks for 2 bpp
PIX4MASK        fcb 0xf0,0x0f                   ; pixel masks for 4 bpp
G1BITPIX        pshs u,b                        ; save registers
                ldb HORBYT                      ; get bytes per row
                lda VERBEG+1                    ; get vergical coord
                mul                             ; now D is the offset to the start of the row
                addd #HRESSCRN                  ; add in start of screen in memory
                tfr d,x                         ; put it in a pointer
                ldd HORBEG                      ; get horiztonal coordindate
                lsra                            ; 8 pixels per byte do divide by 8
                rorb
                lsra
                rorb
                lsra
                rorb
                leax d,x                        ; offset to correct byte row
                lda HORBEG+1                    ; get pixel number
                anda #7                         ; keep only byte offset
                ldu #PIX1MASK                   ; point to 1 bpp masks
                lda a,u                         ; get pixel mask
                puls b,u,pc                     ; restore registers and return
G2BITPIX        pshs u,b                        ; save registers
                ldb HORBYT                      ; get number of bytes per row
                lda VERBEG+1                    ; get horizontal coordinate
                mul                             ; now D is the offset to the start of the row
                addd #HRESSCRN                  ; add in memory offset to the screen
                tfr d,x                         ; put that in a pointer
                ldd HORBEG                      ; get horizontal coordinate
                lsra                            ; 4 pixels per byte so divide by 4
                rorb
                lsra
                rorb
                leax d,x                        ; now X points to the correct memory byte
                lda HORBEG+1                    ; get horizontal coordinate
                anda #3                         ; keep only the pixel number in the byte
                ldu #PIX2MASK                   ; point to 2 bpp pixel masks
                lda a,u                         ; get mask for this pixel
                puls b,u,pc                     ; restore registers and return
G4BITPIX        pshs u,b                        ; save registers
                ldb HORBYT                      ; get bytes per row
                lda VERBEG+1                    ; get vertical coordinate
                mul                             ; now D is the offset to the start of the row
                addd #HRESSCRN                  ; add in memory address of start of screen
                tfr d,x                         ; put it in a pointer
                ldd HORBEG                      ; get horizontal coordinate
                lsra                            ; divide by 2 - only 2 pixels per byte
                rorb
                leax d,x                        ; now X points to the memory address of the pixel
                lda HORBEG+1                    ; get horiztonal coordinate
                anda #1                         ; keep offset into byte
                ldu #PIX4MASK                   ; point to 4 bpp pixel masks
                lda a,u                         ; get pixel mask
                puls b,u,pc                     ; restore registers and return
; HPOINT function
HPOINT          tst HRMODE                      ; is there a graphics mode?
                lbeq SE6EF                      ; brif not - raise error
                jsr LB26A                       ; insist on (
                jsr SE7AA                       ; evaluate coordinates
                jsr LB267                       ; insist on )
                jsr SELTASK1                    ; map the screen
                jsr HCALPOS                     ; get screen pointer
                tfr a,b                         ; save mask
                andb ,x                         ; get pixel data
SE875           lsra                            ; is the pixel aligned right?
                bcs SE87B                       ; brif so
                lsrb                            ; shift right
                bra SE875                       ; see if it's aligned yet
SE87B           jsr LB4F3                       ; return colour number
                jsr SELTASK0                    ; restore memory map
                rts
; HLINE command
HLINE           tst HRMODE                      ; is there a graphics mode active?
                lbeq SE6EF                      ; brif not - raise error
                lbrn 0
                cmpa #'(                        ; is there (?
                beq SE899                       ; brif so - we have start coords
                cmpa #0xac                      ; -?
                beq SE899                       ; brif no start given
                ldb #'@                         ; make sure it's @ if not
                jsr LB26F
SE899           jsr SE9E1                       ; get start/end coords
                ldx HOREND                      ; put end in the defaults
                stx HORDEF
                ldx VEREND
                stx VERDEF
                jsr SYNCOMMA                    ; make sure comma
                cmpa #0xbe                      ; PRESET?
                beq SE8B4                       ; brif so
                cmpa #0xbd                      ; PSET?
                lbne LB277                      ; brif not
                ldb #1                          ; set flag
                skip1lda
SE8B4           clrb                            ; reset flag
                pshs b                          ; save set/reset flag
                jsr GETNCH                      ; eat the PSET/PRESET token
                jsr SEA0D                       ; normalize start/end
                puls b                          ; get back set/reset flag
                stb SETFLG                      ; save set/reset flag
                jsr SE731                       ; set active colour byte
                jsr GETCCH                      ; is there more?
                lbeq SE94E                      ; brif not - no box
                jsr SYNCOMMA                    ; insist on a comma
                ldb #'B                         ; insist on a B
                jsr LB26F
                bne SE8EB                       ; brif something after B
                bsr SE906                       ; draw horizontal line (top)
                bsr SE931                       ; draw vertical line (left)
                ldx HORBEG                      ; save horizontal start
                pshs x
                ldx HOREND                      ; set up to draw vertical line (right)
                stx HORBEG
                bsr SE931                       ; draw vertical line (right)
                puls x                          ; restore start coord
                stx HORBEG
                ldx VEREND                      ; set up to draw horizontal line (bottom)
                stx VERBEG
                bra SE906                       ; draw horizontal line (bottom) and return
SE8EB           ldb #'F                         ; insist on F
                jsr LB26F
                bra SE8F6                       ; draw a filled box
SE8F2           leax -1,x                       ; move vertical coordinate up one
SE8F4           stx VERBEG                      ; save new vertical coordinate
SE8F6           jsr SE906                       ; draw horizontal line
                ldx VERBEG                      ; get current coordinate
                cmpx VEREND                     ; above or below end?
                beq SE905                       ; brif done
                bhs SE8F2                       ; brif below - move up
                leax 1,x                        ; move down (we're above)
                bra SE8F4                       ; draw another line
SE905           rts
SE906           ldx HORBEG                      ; get starting coordinate
                pshs x                          ; save it
                jsr SE9DB                       ; get absolute horizontal difference
                bcc SE913                       ; brif end > start
                ldx HOREND                      ; get ending coordinate
                stx HORBEG                      ; save as starting position
SE913           tfr d,y                         ; save difference (pixel count)
                leay 1,y                        ; bump it (coords are inclusive)
                jsr HCALPOS                     ; calculate pixel address
                puls u                          ; get start coordinate
                stu HORBEG                      ; restore it
                lbsr SEA16                      ; point to routine to move pixel pointer right
SE921           sta VD7                         ; save pixel mask
                jsr SE788                       ; turn on pixel
                lda VD7                         ; get back pixel mask
                jsr ,u                          ; move one pixel right
                leay -1,y                       ; done all pixels?
                bne SE921                       ; brif not
                rts
SE92F           puls d                          ; clean up stack
SE931           ldd VERBEG                      ; get vertical start
                pshs d                          ; save it
                jsr SE9CD                       ; calculate absolute vertical difference
                bcc SE93E                       ; brif end > start
                ldx VEREND                      ; swap coordinate
                stx VERBEG
SE93E           tfr d,y                         ; save difference (pixel count)
                leay 1,y                        ; coordinates are inclusive
                jsr HCALPOS                     ; get screen pointer
                puls u                          ; get original start coord
                stu VERBEG                      ; restore it
                lbsr SEA21                      ; get routine to move down one row
                bra SE921                       ; draw vertical line
SE94E           ldy #SE9B8                      ; point to vertical increment routine
                jsr SE9CD                       ; calculate absolute vertical difference
                beq SE906                       ; draw horizontal if difference is 0
                bcc SE95D                       ; brif vertical end > vertical start
                ldy #SE9C6                      ; point to decrement vertical routine
SE95D           pshs b,a                        ; save vertical difference
                ldu #SE9B1                      ; point to horitzontal increment routine
                jsr SE9DB                       ; calculate absolute horizontal difference
                beq SE92F                       ; draw vertical line if difference is 0
                bcc SE96C                       ; brif horizontal end > horizontal start
                ldu #SE9BF                      ; point to decrement horizontal routine
SE96C           cmpd ,s                         ; compare horiztonal difference with vertical difference
                puls x                          ; get vertical difference back
                bhs SE977                       ; brif horizontal difference is greater
                exg u,y                         ; swap major/minor directions
                exg d,x
SE977           pshs u,d                        ; save larger difference and incr/decr routine
                pshs d                          ; save larger difference
                lsra                            ; divide larger difference by 2
                rorb
                bcs SE988                       ; brif odd
                cmpu #SE9B8+1                   ; inc or dec?
                blo SE988                       ; brif inc
                subd #1                         ; move back of dec (round down)
SE988           pshs x,d                        ; save smaller difference and inc/dec
                jsr SE7E6                       ; point to screen address routine
SE98D           jsr ,u                          ; convert coordinates to screen address
                jsr SE788                       ; turn on pxiel
                ldx 6,s                         ; done all?
                beq SE9AD                       ; brif so
                leax -1,x                       ; account for pixel just drawn
                stx 6,s
                jsr [8,s]                       ; bump coordinate
                ldd ,s                          ; get minor coordinate increment counter
                addd 2,s                        ; add to minor coordinate
                std ,s                          ; save new minor increment
                subd 4,s                        ; subtract largest difference
                bcs SE98D                       ; brif result not bigger than largest difference
                std ,s                          ; save new minor increment
                jsr ,y                          ; inc/dec minor
                bra SE98D                       ; draw another pixel
SE9AD           puls x                          ; clean up stack
                puls d,x,y,u,pc                 ; clean up stack and return
SE9B1           ldx HORBEG                      ; bump horizontal coord
                leax 1,x
                stx HORBEG
                rts
SE9B8           ldx VERBEG                      ; bump vertical coord
                leax 1,x
                stx VERBEG
                rts
SE9BF           ldx HORBEG                      ; reduce horizontal coord
                leax -1,x
                stx HORBEG
                rts
SE9C6           ldx VERBEG                      ; reduce vertical coord
                leax -1,x
                stx VERBEG
SE9CC           rts
SE9CD           ldd VEREND                      ; get vertical end
                subd VERBEG                     ; get subtract start
SE9D1           bcc SE9CC                       ; brif end > start
                pshs cc                         ; save flag for which is >
                nega                            ; negate difference
                negb
                sbca #0
                puls cc,pc                      ; restore status andreturn
SE9DB           ldd HOREND                      ; get horizontal end coord
                subd HORBEG                     ; subtract start coord
                bra SE9D1                       ; handle going negative
; Evaluate two sets of coordinates
SE9E1           ldx HORDEF                      ; set start to default
                stx HORBEG
                ldx VERDEF
                stx VERBEG
                cmpa #0xac                      ; -?
                beq SE9F0                       ; brif so - use default start
                jsr SEA04                       ; evaluate coordinate pair
SE9F0           ldb #0xac                       ; insist on -
                jsr LB26F
                jsr LB26A                       ; insist on (
                jsr LB734                       ; evaluate two expressions (X, B)
                ldy #HOREND                     ; point to end coords
                jsr SE7B9                       ; validate end coords
                bra SEA0A                       ; handle rest of evaluation
SEA04           jsr LB26A                       ; insist on (
                jsr SE7B2                       ; evaluate coordinates with range check
SEA0A           jmp LB267                       ; insist on )
SEA0D           jsr SE7AD                       ; "normalize" start
                ldu #HOREND                     ; point to end coords
                jmp SE7B0                       ; "normalize" end
; Point U to routine to move pixel to right
SEA16           ldu #SEA25                      ; point to jump table
                ldb HRMODE                      ; get graphics mode
                subb #1                         ; zero-base it
                aslb                            ; two bytes per entry
                ldu b,u                         ; get routine address
                rts
SEA21           ldu #SEA45                      ; point to routine to move down one row
                rts
SEA25           fdb SEA34                       ; HSCREEN 1 right
                fdb SEA3D                       ; HSCREEN 2 right
                fdb SEA2D                       ; HSCREEN 3 right
                fdb SEA34                       ; HSCREEN 4 right
SEA2D           lsra                            ; move pixel mask right
                bcc SEA33                       ; brif not changing bytes
                rora                            ; shift mask back around to left
                leax 1,x                        ; move byte forward
SEA33           rts
SEA34           lsra                            ; move one pixel right
                lsra
                bcc SEA33                       ; brif same byte
                lda #0xc0                       ; reset pixel mask
                leax 1,x                        ; move to next byte
                rts
SEA3D           coma                            ; flip pixels
                cmpa #0xf0                      ; did we move to a new byte?
                bne SEA44                       ; brif not
                leax 1,x                        ; move to next byte
SEA44           rts
SEA45           ldb HORBYT                      ; get number of bytes per row
                abx                             ; move ahead that many
                rts
; HCIRCLE command
HCIRCLE         tst HRMODE                      ; graphics mode?
                lbeq SE6EF                      ; brif not - raise error
                lbrn 0
                cmpa #'@                        ; is there @ before coords?
                bne SEA59                       ; brif not
                jsr GETNCH                      ; eat the @
SEA59           jsr SEB60                       ; get max coords for video mode
                jsr SEA04                       ; parse centre coords
                jsr SE7AD                       ; normalize coordinates (ha ha)
                ldx ,u                          ; get horizontal coordinate
                stx VCB                         ; save it
                ldx 2,u                         ; get vertical coordinate
                stx VCD                         ; save it
                jsr SYNCOMMA                    ; insist on a comma
                jsr LB73D                       ; evaluate expression into X (radius)
                ldu #VCF                        ; point to temp storage area
                stx ,u                          ; save radius
                jsr SE7B0                       ; normalize - pointless
                lda #1                          ; put into "set" mode
                sta SETFLG
                jsr SE718                       ; evaluate colour
                ldx #0x100                      ; default H/W ratio (1:1)
                jsr GETCCH                      ; is the an HW ratio?
                beq SEA95                       ; brif not
                jsr SYNCOMMA                    ; insist on comma
                jsr LB141                       ; evaluate HW ratio
                lda FP0EXP                      ; multiply by 256
                adda #8
                sta FP0EXP
                jsr LB740                       ; fetch HW ratio to X (with a fixed 8 bit fraction part)
SEA95           lda HRMODE                      ; get graphics mode
                cmpa #2                         ; is it a 320 mode?
                bhi SEA9F                       ; brif not
                tfr x,d                         ; double HW ratio for 320 modes
                leax d,x
SEA9F           stx VD1                         ; save H/W ratio
                ldb #1                          ; go into SET mode
                stb SETFLG
                stb VD8                         ; flag for "first arc"
                jsr SEB7B                       ; evaluate start point (octant, subarc)
                pshs d                          ; save start point
                jsr SEB7B                       ; evaluate end point
                std VD9                         ; save end point
                puls d                          ; get back start point
SEAB3           pshs d                          ; save current circle position
                ldx HOREND                      ; switch previous end coords in as the start
                stx HORBEG
                ldx VEREND
                stx VERBEG
                ldu #CIRCDATA+2                 ; point to sines/cosines table
                anda #1                         ; is it an even octant?
                beq SEAC7                       ; brif so
                negb                            ; swap arc order for odd octants
                addb #8
SEAC7           aslb                            ; four bytes per table entry
                aslb
                leau b,u                        ; now U points to the correct entry
                pshs u                          ; save table entry
                jsr SEBBD                       ; calculate horizontal offset
                puls u                          ; get back table pointer
                leau -2,u                       ; move to other entry
                pshs x                          ; save horizontal offset
                jsr SEBBD                       ; calculaute vertical offset
                puls y                          ; get back horizontal offset
                lda ,s                          ; get octant number
                anda #3                         ; is it 0 or 4?
                beq SEAE7                       ; brif so
                cmpa #3                         ; is it 3 or 7?
                beq SEAE7                       ; brif so
                exg x,y                         ; swap horizontal and vertical otherwise
SEAE7           stx HOREND                      ; save horizontal offset
                tfr y,d                         ; divide offset by 2
                lsra
                rorb
                ldx VD1                         ; get H/W ratio
                jsr SEBCB                       ; multiply offset by ratio
                tfr y,d                         ; did MSB (bits 23-16) end up nonzero?
                tsta                            ; brif so - outside 16 bit range
                lbne LB44A                      ; brif so - raise error
                stb VEREND                      ; save vertical offset MSB
                tfr u,d                         ; get low bytes of result
                sta VEREND+1                    ; save LSB (lose fractional part)
                lda ,s                          ; get octant number
                cmpa #2                         ; 0 or 1?
                blo SEB13                       ; brif so
                cmpa #6                         ; 6 or h?
                bhs SEB13                       ; brif so
                ldd VCB                         ; get horizontal center
                subd HOREND                     ; subtract offset (going left)
                bcc SEB20                       ; brif we didn't go negative
                clra                            ; minimize to 0
                clrb
                bra SEB20
SEB13           ldd VCB                         ; get horizontal centre
                addd HOREND                     ; add offset
                bcs SEB1E                       ; brif we overflowed
                cmpd VD3                        ; did we overflow screen size?
                blo SEB20                       ; brif not
SEB1E           ldd VD3                         ; maximize horizontal coordinate
SEB20           std HOREND                      ; save new horizontal coordinate
                lda ,s                          ; get octantnumber
                cmpa #4                         ; is it 0-3 (bottom half)?
                blo SEB32                       ; brif so
                ldd VCD                         ; get vertical centre
                subd VEREND                     ; subtract offset
                bcc SEB3F                       ; brif we didn't run past 0
                clra                            ; minimize to 0
                clrb
                bra SEB3F
SEB32           ldd VCD                         ; get vertical centre
                addd VEREND                     ; add offset
                bcs SEB3D                       ; brif we overflowed
                cmpd VD5                        ; did we go past end of screen?
                blo SEB3F                       ; brif not
SEB3D           ldd VD5                         ; maximize to screen size
SEB3F           std VEREND                      ; save new vertical coord
                tst VD8                         ; was this the first coordinate?
                bne SEB48                       ; brif so - don't draw a line
                lbsr SE94E                      ; draw the subarc line
SEB48           puls d                          ; get octant and arc
                lsr VD8                         ; test if first point, and clear flag
                bcs SEB53                       ; brif first coord
                cmpd VD9                        ; at end of circle?
                beq SEB5F                       ; brif so
SEB53           incb                            ; bump arc counter
                cmpb #8                         ; done 8 subarcs?
                bne SEB5C                       ; brif not
                inca                            ; bump octant
                clrb                            ; reset arc counter
                anda #7                         ; wrap octant number if needed
SEB5C           jmp SEAB3                       ; move on with the next arc
SEB5F           rts
SEB60           ldu #VD3                        ; point to storage area
                ldx #639                        ; set max horizontal coord for 640 mode
                stx ,u
                lda HRMODE                      ; get graphics mode
                cmpa #2                         ; is it a 640 mode?
                bgt SEB73                       ; brif so
                ldx #319                        ; set max horzontalcoord for 320 mode
                stx ,u
SEB73           ldx #191                        ; all modes have a 191 vertical max
                stx 2,u
                jmp SE7B0                       ; "normalize" coords
SEB7B           clrb                            ; default circle start/end to 0
                jsr GETCCH                      ; is there a fraction?
                beq SEB91                       ; brif not
                jsr SYNCOMMA                    ; insist on a comma
                jsr LB141                       ; evaluate circle fraction
                lda FP0EXP                      ; multiply by 64 (calculate # of 64ths)
                adda #6
                sta FP0EXP
                jsr LB70E                       ; fetch result as 8 bits unsigned
                andb #0x3f                      ; keep only the fraction part
SEB91           tfr b,a                         ; copy fraction to A (for octant)
                andb #7                         ; keep only arc number in B
                lsra                            ; shift octant number to right of A
                lsra
                lsra
                rts
CIRCDATA        fdb 0x0000,0x0001               ; subarc 0
                fdb 0xfec5,0x1919               ; subarc 1
                fdb 0xfb16,0x31f2               ; subarc 2
                fdb 0xf4fb,0x4a51               ; subarc 3
                fdb 0xec84,0x61f9               ; subarc 4
                fdb 0xe1c7,0x78ae               ; subarc 5
                fdb 0xd4dc,0x8e3b               ; subarc 6
                fdb 0xc5e5,0xa269               ; subarc 7
                fdb 0xb506,0xb506               ; subarc 8
SEBBD           ldx VCF                         ; get radius
                ldd ,u                          ; get sin/cos value
                beq SEBCA                       ; brif 0 - just use radius
                subd #1                         ; subtract 1
                bsr SEBCB                       ; do the multiplication dance
                tfr y,x                         ; save result to X
SEBCA           rts
SEBCB           pshs u,y,x,b,a                  ; save registers and reserve storage
                clr 4,s                         ; clear high bits
                lda 3,s                         ; B*XL
                mul
                std 6,s                         ; save in partical result
                ldd 1,s                         ; A*XH
                mul
                addb 6,s                        ; add to partial product
                adca #0
                std 5,s
                ldb ,s                          ; A*XL
                lda 3,s
                mul
                addd 5,s                        ; add to partial product
                std 5,s
                bcc SEBEA
                inc 4,s
SEBEA           lda ,s                          ; A*XH
                ldb 2,s
                mul
                addd 4,s                        ; add to partial product
                std 4,s                         ; save final product bits
                puls a,b,x,y,u,pc               ; save factors, retrieve result, and return
; HPAINT command
HPAINT          tst HRMODE                      ; do we have a grahpics mode?
                lbeq SE6EF                      ; brif not - raise error
                lbrn 0
                cmpa #'@                        ; is there @ before the coords?
                bne SEC05                       ; brif not
                jsr GETNCH                      ; eat the @
SEC05           jsr SEA04                       ; insist on (
                jsr SE7AD                       ; evaluate the coordinates
                lda #1                          ; set up for "setting"
                sta SETFLG
                jsr SE718                       ; evaluate colour code
                ldd WCOLOR                      ; get working colour and all pixels byte
                pshs d                          ; save them for later
                jsr GETCCH                      ; do we have a border colour?
                beq SEC1D                       ; brif not - use default
                jsr SE718                       ; evaluate border colour
SEC1D           lda ALLCOL                      ; get border colour pixel byte
                sta VD8                         ; save it
                puls d                          ; get paint colour details
                std WCOLOR                      ; restore them
                jsr SELTASK1                    ; map the graphics screen
                clra                            ;* add a terminator block to the top of the stack
                pshs u,x,b,a                    ;* which is how HPAINT knows it's done 
                jsr SEB60                       ; get maximum coordinate values
                jsr SE7E6                       ; point U to routine that selects a pixel
                stu VD9                         ; save pixel selection routine address
                jsr SECBE                       ; paint from current coord to the left
                beq SEC47                       ; brif no painting done - we started on the border
                jsr SED01                       ; paint to the right
                lda #1                          ; set up a record to paint down the screen
                sta VD7
                jsr SED2E
                neg VD7                         ; set up a record to paint up the screen
                jsr SED2E
SEC47           sts TMPSTK                      ; save stack pointer
SEC4A           tst CHGFLG                      ; see if a pixel changed
                bne SEC51                       ; brif so
                lds TMPSTK                      ; get stack pointer back
SEC51           puls a,b,x,u                    ; get data for the next line to handle
                clr CHGFLG                      ; flag nothing changed yet
                sts TMPSTK                      ; save new stack address
                leax 1,x                        ; add one to the start position
                STX HORBEG                      ; set it as the starting position
                stu VD1                         ; save length of parent line
                sta VD7                         ; save up/down flag
                beq SECBA                       ; brif up/down is 0 - end marker
                bmi SEC6A                       ; brif we're going up the screen
                incb                            ; bump vertical coord
                cmpb VD6                        ; at end of screen?
                bls SEC6E                       ; brif not
                clrb                            ; wrap around - this will cause us to bail below
SEC6A           tstb                            ; is coord 0?
                beq SEC4A                       ; brif so - don't go upward
                decb                            ; move upward on the screen
SEC6E           stb VERBEG+1                    ; save new vertical coordinate
                jsr SECBE                       ; paint to the left
                beq SEC86                       ; brif no pixels changed
                cmpd #3                         ; less than 3 painted?
                blo SEC80                       ; brif so - no need to check for paintable data
                leax -2,x                       ; move coord left two
                jsr SED15                       ; save block of paint data in the other direction (vertically)
SEC80           jsr SED01                       ; paint to the right
SEC83           jsr SED2E                       ; save a block of paint data in the same direction
SEC86           coma                            ; invert number of pixels painted (but "less 1")
                comb
SEC88           addd VD1                        ; add to length of parent line
                std VD1                         ; now we have the new parent line length
                ble SECA5                       ; brif parent line was shorter
                jsr SE9B1                       ; bump horizontal
                jsr SECF1                       ; check for border
                bne SEC9B                       ; brif not
                ldd #-1                         ; count down
                bra SEC88                       ; keep looking
SEC9B           jsr SE9BF                       ; move left
                jsr SED3A                       ; save horizontal coord
                bsr SECC7                       ; paint to the right
                bra SEC83                       ; save paint block and keep going
SECA5           jsr SE9B1                       ; bump horizontal coord
                leax d,x                        ; point to right of end of parent line
                stx HORBEG                      ; set as start coord
                coma                            ; negate pixel count (and subtract 2?)
                comb
                subd #1
                ble SECB7                       ; brif line doesn't extend past right of parent
                tfr d,x                         ; save portion of line to the right as length
                bsr SED15                       ; save block of paint data
SECB7           jmp SEC4A                       ; go process more paint blocks
SECBA           jsr SELTASK0                    ; unmap screen
                rts
SECBE           jsr SED3A                       ; point starting coord in end
                ldy #SE9BF                      ; point to dec horizontal
                bra SECCD                       ; paint line
SECC7           ldy #SE9B1                      ; point to incr horizontal coord
                jsr ,y                          ; skip first - already done
SECCD           ldu ZERO                        ; initial pixel counter to 0
                ldx HORBEG                      ; get starting coord
SECD1           bmi SECEA                       ; brif off the left side
                cmpx VD3                        ; at max value?
                bhi SECEA                       ; brif off right side
                pshs u,y                        ; save counter and inc/dec p ointer
                bsr SECF1                       ; check for border
                beq SECE8                       ; brif so - we're done
                jsr SE792                       ; set pixel
                puls y,u                        ; restore count and inc/dec routine
                leau 1,u                        ; bump count
                jsr ,y                          ; adjust coord
                bra SECD1                       ; go do another pixel
SECE8           puls y,u                        ; get back counter and inc/dec pointer
SECEA           tfr u,d                         ; save paint counter in D and X
                tfr d,x
                subd ZERO                       ; set flags on counter
                rts
SECF1           jsr [VD9]                       ; get address of pixel
                tfr a,b                         ; duplicate mask
                andb VD8                        ; get pixel colour mask for the pixel
                pshs b,a                        ; save masks
                anda ,x                         ; merge in with pixel data on screen
                cmpa 1,s                        ; does it match? (Z set if so)
                puls a,b,pc                     ; restore masks and return
SED01           std VCD                         ; save pixel count
                ldy HOREND                      ; get last horizontal coord
                bsr SED3A                       ; save current coord
                sty HORBEG                      ; start painting to right from the previous end
                bsr SECC7                       ; go paint rightward
                ldx VCD                         ; get previous pixel count
                leax d,x                        ; now we have a total count for this line
                addd #1                         ; bump it by one?
                rts
SED15           std VCB                         ; save painted pixel count
                puls y                          ; get return address
                ldd HORBEG                      ; get start coord
                pshs x,d                        ; save start coord and line length
                lda VD7                         ; get direction
                nega                            ; invert it
SED20           ldb VERBEG+1                    ; get vertical coordinate
                pshs b,a                        ; save direction and vertical coord
                pshs y                          ; put return address back
                ldb #6                          ; make sure we didn't overflow the stack
                jsr SED3F
                ldd VCB                         ; get line length back
                rts
SED2E           std VCB                         ; save line length
                puls y                          ; get return address
                ldd HOREND                      ; get horizontal start
                pshs x,d                        ; save line length and horizontal coord
                lda VD7                         ; get direction flag
                bra SED20                       ; finish saving frame
SED3A           ldx HORBEG                      ; get start coord
                stx HOREND                      ; save it as end coord
                rts
SED3F           negb                            ; subtract B bytes from S
                leas b,s
                cmps #TMPSTACK-(0x2000+14)      ; does it overflow? (14 extra is from the unused vectors at the top of the CB ROM area)
                lblo SED4E                      ; raise OM error if we did
                negb                            ; restore stack pointer
                leas b,s
                rts
SED4E           lds #TMPSTACK-2                 ; reset stack (since we overflowed it)
                jsr SELTASK0                    ; restore default memory map
                jmp LAC44                       ; raise OM error
; HBUFF command
HBUFF           jsr LB73D                       ; evaluate buffer number to X
                lbrn 0
                cmpx #255                       ; valid?
                lbhi LB44A                      ; brif not
                stx VD1                         ; save buffer number
                beq SED72                       ; don't get size if buffer 0 select
                jsr SYNCOMMA                    ; insist on a comma
                jsr LB73D                       ; evaluate size to X
                stx VD3                         ; save buffer size
SED72           jsr SE0CB                       ; map the buffers
                jsr SELTASK1
                ldd VD1                         ; get buffer number
                tstb                            ; is it zero (not needed!)
                bne SED85                       ; brif not
                ldd #0xffff                     ; clear all buffers
                std HRESBUFF
                bra SEDBD                       ; reset memory map and return
SED85           ldy #HRESBUFF                   ; point to buffers
                ldd ,y                          ; get address of next block
                cmpd #0xffff                    ; empty buffer space?
                bne SED95                       ; brif not
                bsr SEDC4                       ; check for room in buffer space
                bra SEDB0                       ; set up buffer
SED95           ldb VD1+1                       ; get buffer number
SED97           cmpb 2,y                        ; is this buffer the same number?
                beq SEDD2                       ; brif so - throw error
                ldu ,y                          ; get address of next buffer
                beq SEDA3                       ; brif last buffer
                tfr u,y                         ; move on to next buffer
                bra SED97                       ; see if we have a matching number here
SEDA3           tfr y,u                         ; save start address to U
                ldd 3,y                         ; get size of last buffer
                leay 5,y                        ; move past header
                leay d,y                        ; move past buffer data
                bsr SEDC4                       ; check for enough room
                sty ,u                          ; save pointer to the new buffer in previous header
SEDB0           ldd #0                          ; mark this as the last buffer
                std ,y
                ldb VD1+1                       ; set buffer number
                stb 2,y
                ldd VD3                         ; set buffer size
                std 3,y
SEDBD           jsr SELTASK0                    ; restore memory map
                jsr SETMMU
                rts
SEDC4           tfr y,x                         ; point X to the start of the buffer data
                leax 5,x
                ldd VD3                         ; get length requested
                leax d,x                        ; point to end of new buffer
                cmpx #HRESBUFF+0x1f00           ; does it fit?
                bhi SEDD6                       ; brif not
                rts
SEDD2           ldb #9*2                        ; code for redim array
                bra SEDD8
SEDD6           ldb #6*2                        ; code for out of memory
SEDD8           lds #TMPSTACK-2                 ; reset stack
                jsr SELTASK0                    ; restore memory map
                jsr SETMMU
                jmp LAC46                       ; raise error
; HGET command
HGET            ldx #SEEC0                      ; point to HGET movement routine
                stx VD5                         ; save it
                clrb                            ; flag for "GET"
                bra SEDF4                       ; get on with things
; HPUT command
HPUT            ldx #SEEEF                      ; point to HPUT movement routine
                stx VD5                         ; save it
                ldb #1                          ; flag for "PUT"
SEDF4           tst HRMODE                      ; check for graphics
                lbeq SE6EF                      ; brif not - raise error
                lbrn 0
                stb VD8                         ; save GET/PUT flag
                cmpa #'@                        ; is there @ before coords?
                bne SEE06                       ; brif not
                jsr GETNCH                      ; eat the @
SEE06           jsr SE9E1                       ; evaluate box bounds
                jsr SYNCOMMA                    ; insist on a comma
                jsr EVALEXPB                    ; evaluate buffer number
                stb VD3                         ; save buffer number
                clr VD4                         ; default action to none
                jsr GETCCH                      ; is there an action flag?
                beq SEE38                       ; brif not
                com VD4                         ; flag for action flag specified
                jsr SYNCOMMA                    ; insist on a comma
                tst VD8                         ; is it GET?
                bne SEE23                       ; brif not
                lbra LB277                      ; raise error
SEE23           ldb #5                          ; 5 possible actions
                ldx #SEEE0                      ; point to action routine table address
SEE28           ldu ,x++                        ; get routine address
                cmpa ,x+                        ; does the action match?
                beq SEE34                       ; brif so
                decb                            ; checked all of them?
                bne SEE28                       ; brif not
                jmp LB277                       ; raise error
SEE34           stu VD5                         ; save action address
                jsr GETNCH                      ; eat the action token
SEE38           jsr SE0CB                       ; map the buffers and screen
                jsr SELTASK1
                ldb VD3                         ; get buffer number
                jsr SEF18                       ; find the correct buffer's data
                ldd HORBEG                      ; get horizontal start
                cmpd HOREND                     ; is it less than end?
                ble SEE50                       ; brif so
                ldx HOREND                      ; swap start/end horizontal coords
                stx HORBEG
                std HOREND
SEE50           ldd VERBEG                      ; get vertical start
                cmpd VEREND                     ; less that end?
                ble SEE5D                       ; brif so
                ldx VEREND                      ; swap vertical coords
                stx VERBEG
                std VEREND
SEE5D           lda HRMODE                      ; get graphics mode
                ldb #0xf8                       ; round off mask for mode 3 (1 bpp)
                cmpa #3                         ; is it mode 3 (1 bpp)
                beq SEE6D                       ; brif so
                ldb #0xfc                       ; mask for mode 1 or 4 (2 bpp)
                cmpa #2                         ; is it mode 2?
                bne SEE6D                       ; brif not - it's mode 1 or 4
                ldb #0xfe                       ; round off mask for mode 2 (4 bpp)
SEE6D           tfr b,a                         ; save round off in A and B - we need it twice
                anda HORBEG+1                   ; round off horizontal start
                sta HORBEG+1
                andb HOREND+1                   ; round of horizontal end coord
                stb HOREND+1
                jsr SE9DB                       ; calculate horizontal difference
                std HOREND                      ; save it
                jsr SE9CD                       ; calculate vertial difference
                addd #1                         ; make it inclusive
                std VEREND                      ; save it
                lda HRMODE                      ; get graphics mode
                cmpa #2                         ; HSCREEN 2?
                beq SEE96                       ; divide pixel count by 2 for byte count
                cmpa #3                         ; HSCREEN 3?
                bne SEE92                       ; brif not - divide by 4 (HSCREEN 1, 4)
                lsr HOREND                      ; divide by 8 (falls through to by 4)
                ror HOREND+1
SEE92           lsr HOREND                      ; divide by 4 (falls through to divide by 2)
                ror HOREND+1
SEE96           lsr HOREND                      ; divide by 2
                ror HOREND+1
                ldd HOREND                      ; get byte count
                addd #1                         ; make it inclusive of the end
                std HOREND
                jsr HCALPOS                     ; get pointer to screen location
                ldy VD5                         ; point to action routine address
SEEA7           ldb HOREND+1                    ; get LS byte of byte count
                pshs x                          ; save line start pointer
SEEAB           jsr ,y                          ; perform movement action
                decb                            ; done all bytes?
                bne SEEAB                       ; brif not
                puls x                          ; get back line start
                jsr SEA45                       ; move down one line
                dec VEREND+1                    ; done all rows?
                bne SEEA7                       ; brif not
                jsr SELTASK0                    ; restore memory map
                jsr SETMMU
                rts
SEEC0           lda ,x+                         ; get a byte from screen
                bsr SEEC7                       ; point to proper buffer location
                sta ,u                          ; save it
                rts
SEEC7           ldu VCF                         ; get buffer pointer
                leau 1,u                        ; move to next byte
                stu VCF                         ; save new pointer
                cmpu VD1                        ; did we run past the end of the buffer?
                bhi SEED3                       ; brif so - raise error
                rts
SEED3           lds #TMPSTACK-2                 ; reset stack
                jsr SELTASK0                    ; restore memory map
                jsr SETMMU
                jmp LB44A                       ; raise FC error
SEEE0           fdb SEEEF                       ; PSET action routine
                fcb 0xbd                        ; PSET token
                fdb SEEF6                       ; PRESET action routine
                fcb 0xbe                        ; PRESET token
                fdb SEF07                       ; OR action routine
                fcb 0xb1                        ; OR token
                fdb SEEFE                       ; AND action routine
                fcb 0xb0                        ; AND token
                fdb SEF10                       ; NOT action routine
                fcb 0xa8                        ; NOT token
SEEEF           bsr SEEC7                       ; point to buffer location
                lda ,u                          ; get byte from buffer
                sta ,x+                         ; put it on screen
                rts
SEEF6           bsr SEEC7                       ; point to buffer location
                lda ,u                          ; get byte
                coma                            ; invert it
                sta ,x+                         ; put it on screen
                rts
SEEFE           bsr SEEC7                       ; point to buffer location
                lda ,u                          ; get byte from buffer
                anda ,x                         ; "AND" with screen data
                sta ,x+                         ; put it on screen
                rts
SEF07           bsr SEEC7                       ; point to buffer location
                lda ,u                          ; get byte from buffer
                ora ,x                          ; "OR" with screen data
                sta ,x+                         ; put on screen
                rts
SEF10           bsr SEEC7                       ; point to buffer address
                lda ,x                          ; get byte from screen (BUG: should be ,u to get from buffer)
                coma                            ; invert data
                sta ,x+                         ; save on screen
                rts
SEF18           ldy #HRESBUFF                   ; point to start of buffers
                lda ,y                          ; are there any buffers?
                cmpa #0xff
                bne SEF2C                       ; brif so
                jmp SEED3                       ; raise error if no buffers
SEF25           ldy ,y                          ; point to next buffer
                lbeq SEED3                      ; brif end of buffers - raise error
SEF2C           cmpb 2,y                        ; is this the desired buffer?
                bne SEF25                       ; brif not
                ldd 3,y                         ; get size of buffer
                leay 4,y                        ; point to start of data (less one for "pre-inc" on use
                sty VCF                         ; save buffer pointer
                leay 1,y                        ; point to actual data start
                leay d,y                        ; calculate address of end of buffer
                sty VD1                         ; save end address
                rts
; HPRINT command
HPRINT          tst HRMODE                      ; graphics mode?
                lbeq SE6EF                      ; brif not - raise error
                lbrn 0
                jsr LB26A                       ; insist on (
                jsr SE7B2                       ; evaluate coordinates
                jsr LB267                       ; insist on )
                jsr SYNCOMMA                    ; insist on comma
                jsr LB156                       ; evaluate print string
                tst VALTYP                      ; is it string?
                bne SEF62                       ; brif not numeric (should be BMI)
                jsr LBDD9                       ; convert number to string
                jsr LB516                       ; save string in string space and all that jazz
SEF62           jsr LB657                       ; fetch string details
                stb H.PCOUNT                    ; save length in print count
                ldy #H.PBUF                     ; point to temporary string buffer
SEF6C           decb                            ; have we processed the whole string?
                bmi SEF75                       ; brif so (or if the string length was > 128)
                lda ,x+                         ; copy a character from the string into the buffer
                sta ,y+
                bra SEF6C                       ; see if we're done yet
SEF75           lda HRMODE                      ; get graphics mode
                ldb #40                         ; 40 characters on a 320 line
                cmpa #3                         ; is it mode 1 or 2?
                blo SEF7F                       ; brif so
                ldb #80                         ; 80 characters on a 640 line
SEF7F           clra                            ; zero extend line size
                subd HORBEG                     ; subtract first position from line length
                bmi SF001                       ; brif we're printing off the side of the screen
                cmpb H.PCOUNT                   ; is the print count larger than characters left?
                bhi SEF8E                       ; brif not
                stb H.PCOUNT                    ; save remaining screen positions as print count
                beq SF001                       ; brif nothing to print
SEF8E           lda #ROWMAX-1                   ; get highest row number
                cmpa VERBEG+1                   ; are we in range?
                bge SEF96                       ; brif so
                sta VERBEG+1                    ; force bottom row if not in range
SEF96           jsr SF08C                       ; calculate actual pixel coordinates
                jsr HCALPOS                     ; get screen pointer
                ldy #H.PBUF                     ; point to string data
                ldb H.PCOUNT                    ; get number of characters to print
SEFA3           lda ,y                          ; get character to print
                anda #0x7f                      ; lose bit 7 (character set repeats)
                suba #0x20                      ; lose the "control" characters - no glyphs for those codes
                bpl SEFAD                       ; brif it was not a control character
                lda #0                          ; use a space if it was
SEFAD           sta ,y+                         ; put glyph number into the buffer
                decb                            ; processed all of them?
                bgt SEFA3                       ; brif not
                lda HRMODE                      ; get graphics mode
                deca                            ; zero-base it
                asla                            ; two bytes per display routine
                ldy #SF002                      ; point to display routine table
                ldy a,y                         ; point to display routine
                sty VD1                         ; save it
                lda #8                          ; 8 rows per character
                sta VD3                         ; temp save row counter
                ldy #H.PBUF                     ; point to print buffer
                ldu #SF09D                      ; point to FONT data
                ldb H.FCOLOR                    ; get foreground colour
                jsr PIXELFIL                    ; get an all pixel byte
                stb ALLCOL                      ; save it
                jsr SELTASK1                    ; map the screen
                lda H.PCOUNT                    ; get character count to display
SEFD9           pshs y,x,a                      ; save buffer pointer, character count, and screen address
SEFDB           ldb ,y+                         ; get character from buffer
                clra                            ; zero extend it
                aslb                            ;* 8 bytes per character entry (don't need rola after first
                aslb                            ;* because characters are only 7 bits
                rola
                aslb
                rola
                lda d,u                         ; get font data for this row
                jsr [VD1]                       ; display it
                dec H.PCOUNT                    ; done all characters on this row?
                bgt SEFDB                       ; brif not
                puls a,x,y                      ; get back character count, buffer pointer, and screen address
                dec VD3                         ; have we done all the rows?
                beq SEFFE                       ; brif so
                sta H.PCOUNT                    ; restore print count
                leau 1,u                        ; move one row down the font data
                jsr SEA45                       ; move one row down the screen
                bra SEFD9                       ; go do another row of pixels
SEFFE           jsr SELTASK0                    ; restore memory map
SF001           rts
SF002           fdb SF01A                       ; HSCREEN 1 (2 bpp)
                fdb SF045                       ; HSCREEN 2 (4 bpp)
                fdb SF00A                       ; HSCREEN 3 (1 bpp)
                fdb SF01A                       ; HSCREEN 4 (2 bpp)
SF00A           pshs a                          ; save font data
                coma                            ; invert it
                anda ,x                         ; merge with screen - turns off pixels in the character
                sta ,x                          ; save it back on the screen
                puls a                          ; get back font data
                anda ALLCOL                     ; merge with colour data
                ora ,x                          ; merge with screen to fill hole created above
                sta ,x+                         ; save it on screen
                rts
SF01A           pshs y                          ; save buffer pointer
                ldy #SF035                      ; point to 2 bpp pixel masks
                tfr a,b                         ; copy character data (need two bytes per character)
                lsra                            ; use the upper 4 bits in first byte
                lsra
                lsra
                lsra
                lda a,y                         ; get pixel mask for all 16 possibilities for upper 4 bits
                jsr SF00A                       ; shove it on screen
                andb #0x0f                      ; lose upper bits for low half
                lda b,y                         ; get pixel mask for this pixel combination
                jsr SF00A                       ; shove that on screen too
                puls y                          ; restore buffer pointer
                rts
SF035           fcb 0x00,0x03,0x0c,0x0f         ; combined pixel masks for 16 possibilities for a 2 bpp byte
                fcb 0x30,0x33,0x3c,0x3f
                fcb 0xc0,0xc3,0xcc,0xcf
                fcb 0xf0,0xf3,0xfc,0xff
SF045           pshs y,a                        ; save buffer pointer and font data
                ldy #SF06C                      ; point to 16 colour masks
                lsra                            ; fetch high 4 bits
                lsra
                lsra
                lsra
                asla                            ; two bytes per mask (this is NOT redundant - this and above clears bit 0)
                ldd a,y                         ; get two byte mask for these four bits
                jsr SF00A                       ; show upper 2 pixels
                tfr b,a                         ; show lower 2 pixels
                jsr SF00A
                puls a                          ; get back font data
                anda #0x0f                      ; lost upper bits
                asla                            ; two bytes per mask
                ldd a,y                         ; get mask data
                jsr SF00A                       ; show upper 2 pixels
                tfr b,a                         ; show lower 2 pixels
                jsr SF00A
                puls y                          ; restore buffer pointer
                rts
SF06C           fdb 0x0000,0x000f,0x00f0,0x00ff ; combined pixel masks for 16 possibilities for a 4 bpp double byte
                fdb 0x0f00,0x0f0f,0x0ff0,0x0fff
                fdb 0xf000,0xf00f,0xf0f0,0xf0ff
                fdb 0xff00,0xff0f,0xfff0,0xffff
SF08C           ldd HORBEG                      ; get horizontal character cell coordinate
                aslb                            ; times 8 - 8x8 font data; note first shift can't cause carry with max 79 for column number
                aslb
                rola
                aslb
                rola
                std HORBEG                      ; save actual horizontal pixel position of print position
                lda VERBEG+1                    ; get vertical character cell coordinate
                asla                            ; times 8 - 8x8 font data
                asla
                asla
                sta VERBEG+1                    ; save actual vertical pixel position of print position
                rts
; This is the HPRINT font, which is basically equivalent to the hardware font in the GIME for character codes
; 0x20 through 0x7f. It does not include the extra characters in the 0x00-0x1f range of the hardware character
; set. However, glyphs for those are actually included in the ROM above the end of the actual code.
SF09D           fcb 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00     ; SPACE
                fcb 0x10,0x10,0x10,0x10,0x10,0x00,0x10,0x00     ; !
                fcb 0x28,0x28,0x28,0x00,0x00,0x00,0x00,0x00     ; "
                fcb 0x28,0x28,0x7C,0x28,0x7C,0x28,0x28,0x00     ; #
                fcb 0x10,0x3C,0x50,0x38,0x14,0x78,0x10,0x00     ; $
                fcb 0x60,0x64,0x08,0x10,0x20,0x4C,0x0C,0x00     ; %
                fcb 0x20,0x50,0x50,0x20,0x54,0x48,0x34,0x00     ; &
                fcb 0x10,0x10,0x20,0x00,0x00,0x00,0x00,0x00     ; '
                fcb 0x08,0x10,0x20,0x20,0x20,0x10,0x08,0x00     ; (
                fcb 0x20,0x10,0x08,0x08,0x08,0x10,0x20,0x00     ; )
                fcb 0x00,0x10,0x54,0x38,0x38,0x54,0x10,0x00     ; *
                fcb 0x00,0x10,0x10,0x7C,0x10,0x10,0x00,0x00     ; +
                fcb 0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x20     ; ,
                fcb 0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x00     ; -
                fcb 0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00     ; .
                fcb 0x00,0x04,0x08,0x10,0x20,0x40,0x00,0x00     ; /
                fcb 0x38,0x44,0x4C,0x54,0x64,0x44,0x38,0x00     ; 0
                fcb 0x10,0x30,0x10,0x10,0x10,0x10,0x38,0x00     ; 1
                fcb 0x38,0x44,0x04,0x38,0x40,0x40,0x7C,0x00     ; 2
                fcb 0x38,0x44,0x04,0x08,0x04,0x44,0x38,0x00     ; 3
                fcb 0x08,0x18,0x28,0x48,0x7C,0x08,0x08,0x00     ; 4
                fcb 0x7C,0x40,0x78,0x04,0x04,0x44,0x38,0x00     ; 5
                fcb 0x38,0x40,0x40,0x78,0x44,0x44,0x38,0x00     ; 6
                fcb 0x7C,0x04,0x08,0x10,0x20,0x40,0x40,0x00     ; 7
                fcb 0x38,0x44,0x44,0x38,0x44,0x44,0x38,0x00     ; 8
                fcb 0x38,0x44,0x44,0x38,0x04,0x04,0x38,0x00     ; 9
                fcb 0x00,0x00,0x10,0x00,0x00,0x10,0x00,0x00     ; :
                fcb 0x00,0x00,0x10,0x00,0x00,0x10,0x10,0x20     ; ;
                fcb 0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x00     ; <
                fcb 0x00,0x00,0x7C,0x00,0x7C,0x00,0x00,0x00     ; =
                fcb 0x20,0x10,0x08,0x04,0x08,0x10,0x20,0x00     ; >
                fcb 0x38,0x44,0x04,0x08,0x10,0x00,0x10,0x00     ; ?
                fcb 0x38,0x44,0x04,0x34,0x4C,0x4C,0x38,0x00     ; @
                fcb 0x10,0x28,0x44,0x44,0x7C,0x44,0x44,0x00     ; A
                fcb 0x78,0x24,0x24,0x38,0x24,0x24,0x78,0x00     ; B
                fcb 0x38,0x44,0x40,0x40,0x40,0x44,0x38,0x00     ; C
                fcb 0x78,0x24,0x24,0x24,0x24,0x24,0x78,0x00     ; D
                fcb 0x7C,0x40,0x40,0x70,0x40,0x40,0x7C,0x00     ; E
                fcb 0x7C,0x40,0x40,0x70,0x40,0x40,0x40,0x00     ; F
                fcb 0x38,0x44,0x40,0x40,0x4C,0x44,0x38,0x00     ; G
                fcb 0x44,0x44,0x44,0x7C,0x44,0x44,0x44,0x00     ; H
                fcb 0x38,0x10,0x10,0x10,0x10,0x10,0x38,0x00     ; I
                fcb 0x04,0x04,0x04,0x04,0x04,0x44,0x38,0x00     ; J
                fcb 0x44,0x48,0x50,0x60,0x50,0x48,0x44,0x00     ; K
                fcb 0x40,0x40,0x40,0x40,0x40,0x40,0x7C,0x00     ; L
                fcb 0x44,0x6C,0x54,0x54,0x44,0x44,0x44,0x00     ; M
                fcb 0x44,0x44,0x64,0x54,0x4C,0x44,0x44,0x00     ; N
                fcb 0x38,0x44,0x44,0x44,0x44,0x44,0x38,0x00     ; O
                fcb 0x78,0x44,0x44,0x78,0x40,0x40,0x40,0x00     ; P
                fcb 0x38,0x44,0x44,0x44,0x54,0x48,0x34,0x00     ; Q
                fcb 0x78,0x44,0x44,0x78,0x50,0x48,0x44,0x00     ; R
                fcb 0x38,0x44,0x40,0x38,0x04,0x44,0x38,0x00     ; S
                fcb 0x7C,0x10,0x10,0x10,0x10,0x10,0x10,0x00     ; T
                fcb 0x44,0x44,0x44,0x44,0x44,0x44,0x38,0x00     ; U
                fcb 0x44,0x44,0x44,0x28,0x28,0x10,0x10,0x00     ; V
                fcb 0x44,0x44,0x44,0x44,0x54,0x6C,0x44,0x00     ; W
                fcb 0x44,0x44,0x28,0x10,0x28,0x44,0x44,0x00     ; X
                fcb 0x44,0x44,0x28,0x10,0x10,0x10,0x10,0x00     ; Y
                fcb 0x7C,0x04,0x08,0x10,0x20,0x40,0x7C,0x00     ; Z
                fcb 0x38,0x20,0x20,0x20,0x20,0x20,0x38,0x00     ; ]
                fcb 0x00,0x40,0x20,0x10,0x08,0x04,0x00,0x00     ; \
                fcb 0x38,0x08,0x08,0x08,0x08,0x08,0x38,0x00     ; [
                fcb 0x10,0x38,0x54,0x10,0x10,0x10,0x10,0x00     ; UP ARROW
                fcb 0x00,0x10,0x20,0x7C,0x20,0x10,0x00,0x00     ; LEFT ARROW
                fcb 0x10,0x28,0x44,0x00,0x00,0x00,0x00,0x00     ; ^
                fcb 0x00,0x00,0x38,0x04,0x3C,0x44,0x3C,0x00     ; a
                fcb 0x40,0x40,0x58,0x64,0x44,0x64,0x58,0x00     ; b
                fcb 0x00,0x00,0x38,0x44,0x40,0x44,0x38,0x00     ; c
                fcb 0x04,0x04,0x34,0x4C,0x44,0x4C,0x34,0x00     ; d
                fcb 0x00,0x00,0x38,0x44,0x7C,0x40,0x38,0x00     ; e
                fcb 0x08,0x14,0x10,0x38,0x10,0x10,0x10,0x00     ; f
                fcb 0x00,0x00,0x34,0x4C,0x4C,0x34,0x04,0x38     ; g
                fcb 0x40,0x40,0x58,0x64,0x44,0x44,0x44,0x00     ; h
                fcb 0x00,0x10,0x00,0x30,0x10,0x10,0x38,0x00     ; i
                fcb 0x00,0x04,0x00,0x04,0x04,0x04,0x44,0x38     ; j
                fcb 0x40,0x40,0x48,0x50,0x60,0x50,0x48,0x00     ; k
                fcb 0x30,0x10,0x10,0x10,0x10,0x10,0x38,0x00     ; l
                fcb 0x00,0x00,0x68,0x54,0x54,0x54,0x54,0x00     ; m
                fcb 0x00,0x00,0x58,0x64,0x44,0x44,0x44,0x00     ; n
                fcb 0x00,0x00,0x38,0x44,0x44,0x44,0x38,0x00     ; o
                fcb 0x00,0x00,0x78,0x44,0x44,0x78,0x40,0x40     ; p
                fcb 0x00,0x00,0x3C,0x44,0x44,0x3C,0x04,0x04     ; q
                fcb 0x00,0x00,0x58,0x64,0x40,0x40,0x40,0x00     ; r
                fcb 0x00,0x00,0x3C,0x40,0x38,0x04,0x78,0x00     ; s
                fcb 0x20,0x20,0x70,0x20,0x20,0x24,0x18,0x00     ; t
                fcb 0x00,0x00,0x44,0x44,0x44,0x4C,0x34,0x00     ; u
                fcb 0x00,0x00,0x44,0x44,0x44,0x28,0x10,0x00     ; v
                fcb 0x00,0x00,0x44,0x54,0x54,0x28,0x28,0x00     ; w
                fcb 0x00,0x00,0x44,0x28,0x10,0x28,0x44,0x00     ; x
                fcb 0x00,0x00,0x44,0x44,0x44,0x3C,0x04,0x38     ; y
                fcb 0x00,0x00,0x7C,0x08,0x10,0x20,0x7C,0x00     ; z
                fcb 0x08,0x10,0x10,0x20,0x10,0x10,0x08,0x00     ; {
                fcb 0x10,0x10,0x10,0x00,0x10,0x10,0x10,0x00     ; |
                fcb 0x20,0x10,0x10,0x08,0x10,0x10,0x20,0x00     ; }
                fcb 0x20,0x54,0x08,0x00,0x00,0x00,0x00,0x00     ; ~
                fcb 0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00     ; _
; HDRAW command
HDRAW           tst HRMODE                      ; grahics mode?
                lbeq SE6EF                      ; brif not
                lbrn 0
                ldx #0                          ; set empty string for "end of DRAW"
                ldb #1
                pshs x,b
                stb SETFLG                      ; set up for "set" mode
                stx VD5                         ; clear update and draw flags
                jsr SE731                       ; set up color byte
                jsr LB156                       ; evaluate command string
SF3B8           jsr LB654                       ; fetch command string details
                bra SF3C5                       ; interpret command string
SF3BD           jsr SF591                       ; fetch command character
                jmp SF5A7                       ; evaluate number
SF3C3           puls b,x                        ; get "caller" command string details
SF3C5           stb VD8                         ; save string pointer
                beq SF3C3                       ; brif end of string - try another
                stx VD9                         ; set string data pointer
                lbeq SF4D0                      ; brif we hit the top of the stack
SF3CF           tst VD8                         ; is there anything left?
                beq SF3C3                       ; brif not
                jsr SF591                       ; get command character
                cmpa #';                        ; separator?
                beq SF3CF                       ; brif so - ignore it
                cmpa #''                        ; '?
                beq SF3CF                       ; brif so - ignore that too
                cmpa #'N                        ; update toggle?
                bne SF3E6                       ; brif not
                com VD5                         ; toggle the "update" flag (if set, return to original position after)
                bra SF3CF                       ; process more
SF3E6           cmpa #'B                        ; blank modifier?
                bne SF3EE                       ; brif not
                com VD6                         ; toggle "draw" flag - 0 = draw, nonzero = don't draw
                bra SF3CF                       ; process more
SF3EE           cmpa #'X                        ; substring call?
                lbeq SF4A1                      ; brif so - process it
                cmpa #'M                        ; M (move)?
                lbeq SF54C                      ; brif so - process "move"
                pshs a                          ; save command character
                ldb #1                          ; default count if no number follows
                clr VD3                         ; clear MS byte of count
                stb VD4                         ; save LS byte of count
                tst VD8                         ; is there anything left?
                beq SF417                       ; brif not
                jsr SF591                       ; get command character
                jsr LB3A2                       ; set C if not alpha
                pshs cc                         ; save alpha flag
                jsr SF5F2                       ; back up command pointer
                puls cc                         ; get back alpha flag
                bcc SF417                       ; brif command is alpha
                bsr SF3BD                       ; evaluate decimal string
SF417           puls a                          ; get command back
                cmpa #'C                        ; C (colour)?
                beq SF445                       ; brif so
                cmpa #'A                        ; A (angle)?
                beq SF451                       ; brif so
                cmpa #'S                        ; S (scale)?
                beq SF45C                       ; brif so
                cmpa #'U                        ; U (up)?
                beq SF496                       ; brif so
                cmpa #'D                        ; D (down)?
                beq SF492                       ; brif so
                cmpa #'L                        ; L (left)?
                beq SF48C                       ; brif so
                cmpa #'R                        ; R (right)?
                beq SF485                       ; brif so
                suba #'E                        ; shift E,F,G,H to be 0-3
                beq SF473                       ; brif E (UR)
                deca                            ; F (DR)
                beq SF46D                       ; brif so
                deca                            ; G (DL)
                beq SF47D                       ; brif so
                deca                            ; H (UL)
                beq SF467                       ; brif so
                jmp LB44A                       ; raise error if unrecognized command
SF445           jsr SE711                       ; adjust colour code for graphics mode
                stb H.FCOLOR                    ; set new foreground
                jsr SE731                       ; set up colour byte
                lbra SF3CF                      ; handle another command
SF451           cmpb #4                         ; only 4 angles valid
                lbhs LB44A                      ; brif invalid angle
                stb ANGLE                       ; save draw angle
                lbra SF3CF                      ; go handle another command
SF45C           cmpb #63                        ; only 0-62 are valid scale factors
                lbhs LB44A                      ; brif invalid scale
                stb SCALE                       ; set scale factor
                lbra SF3CF                      ; process another command
SF467           lda VD3                         ; get count MSB
                bsr NEGACCD                     ; negate horizontal difference (go left)
                bra SF46F                       ; go the same distance up
SF46D           lda VD3                         ; get count MSB
SF46F           tfr d,x                         ; go same distance right as down
                bra SF4D4                       ; go handle movement/drawing
SF473           lda VD3                         ; get MSB of count
                tfr d,x                         ; going same distance on both axes
                bsr NEGACCD                     ; negate the vertical distance
                exg d,x                         ; put vertical in X, horizontal in D
                bra SF4D4                       ; go handle drawing and moving
SF47D           lda VD3                         ; get MSB of count
                tfr d,x                         ; go same distance on both axes
                bsr NEGACCD                     ; go left horizontally (and down vertically)
                bra SF4D4                       ; go handle drawing and moving
SF485           lda VD3                         ; get MSB of difference (going right)
SF487           ldx #0                          ; no vertical movement
                bra SF4D4                       ; handle drawing/moving
SF48C           lda VD3                         ; get MSB of count
                bsr NEGACCD                     ; negate because going left
                bra SF487                       ; set no vertical difference, handle drawing/moving
SF492           lda VD3                         ; get MSB of count
                bra SF49A                       ; go make horizontal difference 0, use positive distance for down
SF496           lda VD3                         ; get MSB of count
                bsr NEGACCD                     ; use negative distance for up
SF49A           ldx #0                          ; use 0 horizontal distance
                exg x,d                         ; put horizontal and vertical in the right places
                bra SF4D4                       ; go move/draw
SF4A1           jsr SF611                       ; interpret command as a variable
                ldb #2                          ; see if we're about to run out of memory
                jsr LAC33
                ldb VD8                         ; get remaining characters in current command string
                ldx VD9                         ; get current command string pointer
                pshs x,b                        ; save the stack frame
                jmp SF3B8                       ; go evaluate the string
SF4B2           ldb SCALE                       ; get scaling factor
                beq SF4D1                       ; brif none - use full scale
                clra                            ; zero extend scale
                exg d,x                         ; put distance in D, save scale factor
                sta ,-s                         ; save MSB of distance and set flags on sign
                bpl SF4BF                       ; brif positive distance
                bsr NEGACCD                     ; make it positive if negative
SF4BF           jsr SEBCB                       ; multiply D and X
                tfr U,D                         ; save LSW in D
                lsra                            ; divide by 4
                rorb
                lsra
                rorb
                tst ,s+                         ; was original positive?
                bpl SF4D0                       ; brif so
NEGACCD         nega                            ; negate D
                negb
                sbca #0
SF4D0           rts
SF4D1           tfr x,d                         ; keep unmodified distance
                rts
SF4D4           pshs d                          ; save horizontal distance
                bsr SF4B2                       ; apply scale factor to vertical distance
                puls x                          ; get back horizontal distance
                pshs d                          ; save scaled vertical distance
                bsr SF4B2                       ; apply scale to horizontal distance
                puls x                          ; get back the vertical distance
                ldy ANGLE                       ; get draw angle (using Y to avoid clobbering D)
                pshs y                          ; save it
SF4E5           tst ,s                          ; check angle
                beq SF4F1                       ; brif no angle
                exg x,d                         ;* swap horizontal and vertical distances then negate new horizontal
                bsr NEGACCD                     ;* distance, which rotates 90° counterclockwise
                dec ,s                          ; count down the angle
                bra SF4E5                       ; see if we have rotated enough times
SF4F1           puls y                          ; clean up stack
                ldu #0                          ; default end position to 0
                addd HORDEF                     ; add distance to current draw position
                bmi SF4FC                       ; brif we went negative - use minimal 0
                tfr d,u                         ; use calculated draw coordinate
SF4FC           tfr x,d                         ; fetch vertical distance for calculation
                ldx #0                          ; default end position to 0
                addd VERDEF                     ; add distance to draw position
                bmi SF507                       ; brif we went negative - use minimal 0
                tfr d,x                         ; use calculated coordinate
SF507           cmpu #640                       ; is it out of range completely?
                blo SF510                       ; brif not
                ldu #639                        ; maximize to right edge of screen
SF510           lda HRMODE                      ; get graphics mode
                cmpa #2                         ; is it a 320 mode?
                bgt SF51F                       ; brif not
                cmpu #320                       ; out of range for 320 mode?
                blo SF51F                       ; brif not
                ldu #319                        ; maximize to right edge of screen
SF51F           cmpx #192                       ; out of range vertically?
                blo SF527                       ; brif not
                ldx #191                        ; maximize to bottom of screen
SF527           ldd HORDEF                      ; set start position to current draw position
                std HORBEG
                ldd VERDEF
                std VERBEG
                stx VEREND                      ; set calculated position as end position
                stu HOREND
                tst VD5                         ; are we going to update draw position?
                bne SF53B                       ; brif not
                stx VERDEF                      ; set new draw position
                stu HORDEF
SF53B           jsr SEA0D                       ; "normalize" coordinates
                tst VD6                         ; are we doing to draw a line?
                bne SF545                       ; brif not
                jsr SE94E                       ; draw a line
SF545           clr VD5                         ; reset the "update" flag
                clr VD6                         ; reset the "draw" flag
                jmp SF3CF                       ; go handle another command
SF54C           jsr SF591                       ; get input character
                pshs a                          ; save it
                jsr SF578                       ; evaluate horizontal distance
                pshs d                          ; save it
                jsr SF591                       ; get a character
                cmpa #',                        ; is it a comma separator?
                lbne LB44A                      ; brif not - raise error
                jsr SF575                       ; evaluate the vertical distance
                tfr d,x                         ; save vertical distance
                puls u                          ; get horizontal distance
                puls a                          ; get first command character
                cmpa #'+                        ; +?
                beq SF570                       ; treat coordinates as relative displacements
                cmpa #'-                        ; -?
                bne SF507                       ; brif neither + or -; treat as absolute coordinates
SF570           tfr u,d                         ; put horizontal distance in D
                jmp SF4D4                       ; treat distances as offsets
SF575           jsr SF591                       ; get character
SF578           cmpa #'+                        ; +?
                beq SF583                       ; brif so - do positive
                cmpa #'-                        ; -?
                beq SF584                       ; brif so - do negative
                jsr SF5F2                       ; back up input pointer
SF583           clra                            ; flag positive
SF584           pshs a                          ; save sign flag
                jsr SF3BD                       ; evaluate decimal number
                tst ,s+                         ; is it positive?
                beq SF590                       ; brif so
                negb                            ; negate the value - BUG: should be JSR NEGACCD; this code sequence doesn't work
                sbca #0
SF590           rts
SF591           pshs x                          ; save register
SF593           tst VD8                         ; is there anything to fetch?
                lbeq LB44A                      ; brif not - raise error
                ldx VD9                         ; get command pointer
                lda ,x+                         ; get command character
                stx VD9                         ; save updated pointer
                dec VD8                         ; account for character consumed
                cmpa #0x20                      ; space?
                beq SF593                       ; brif so - skip it
                puls x,pc                       ; restore register and return
SF5A7           cmpa #'=                        ; is it variable equate?
                bne SF5B6                       ; brif not
                pshs u,y                        ; save registers
                bsr SF611                       ; interpret variable in command string
                jsr LB3E9                       ; convert to integer in D
                std VD3                         ; save as count
                puls y,u,pc                     ; restore registers and return
SF5B6           jsr SF608                       ; clear carry if numeric
                lbcs LB44A                      ; bail if not numeric
                clr VD3                         ; initialize count to 0
                clr VD4
SF5C1           suba #'0                        ; remove ASCII bias
                sta VD7                         ; save digit value
                ldd VD3                         ; get accumulated value
                bsr SF5FD                       ; multiply by 10
                addb VD7                        ; add digit value
                adca #0                         ; propagate carry
                std VD3                         ; save accumulated count value
                lda HRMODE                      ; get graphics mode
                cmpa #2                         ; is it a 640 mode?
                bgt SF5DA                       ; brif so
                ldd #319                        ; get max for 320 mode
                bra SF5DD
SF5DA           ldd #639                        ; get max for 640 mode
SF5DD           cmpd VD3                        ; is the value in range for a horizontal coordinate?
                lblt LB44A                      ; brif not
                ldd VD3                         ; get accumulated value
                tst VD8                         ; is there anything more to parse?
                beq SF5FA                       ; brif not
                jsr SF591                       ; get a character
                jsr SF608                       ; set C if not digit
                bcc SF5C1                       ; brif digit - add to accumulated value
SF5F2           inc VD8                         ; account for character being unfetched
                ldx VD9                         ; move command pointer back
                leax -1,x
                stx VD9
SF5FA           ldd VD3                         ; get accumulated value
                rts
SF5FD           aslb                            ; times 2
                rola
                pshs d                          ; save 2D
                aslb                            ; times 4
                rola
                aslb                            ; times 8
                rola
                addd ,s++                       ; 8D+2D=10D
                rts
SF608           cmpa #'0                        ; is it less than ASCII 0?
                blo SF610                       ; brif so - sets C
                suba #'9+1                      ; set C if > ASCII 9
                suba #-('9+1)
SF610           rts
SF611           ldx VD9                         ; get command pointer
                pshs x                          ; save it
                jsr SF591                       ; get command character
                jsr LB3A2                       ; set C if not alpha
                lbcs LB44A                      ; brif not variable name
SF61F           jsr SF591                       ; get command character
                cmpa #';                        ; is it end of variable string?
                bne SF61F                       ; brif not
                puls x                          ; get back start of variable
                ldu CHARAD                      ; save interpreter input pointer
                pshs u
                stx CHARAD                      ; save command string pointer as interpeter input
                jsr LB284                       ; evaluate variable
                puls x                          ; restore interpreter input pointer
                stx CHARAD
                rts
; WIDTH command
WIDTH           clr HRMODE                      ; turn off graphics
                lbrn 0
                cmpa #0                         ; end of line? (BUG: should do a BEQ before the CLR above)
                beq SF64F                       ; brif so - raise error if no argument (won't trigger on :)
                jsr EVALEXPB                    ; evaluate width argument
                cmpb #32                        ; 32 columns?
                beq COL32                       ; brif so
                cmpb #40                        ; 40 columns?
                beq COL40                       ; brif so
                cmpb #80                        ; 80 columns?
                beq COL80                       ; brif so
SF64F           jmp LB44A                       ; raise FC error
COL32           clra                            ; set text mode to 32 columns
                sta HRWIDTH
                jsr LA928                       ; clear screen
                lbsr SETTEXT                    ; set up display for 32 column screen
                rts
COL40           lda #1                          ; mode number for 40 columns
                sta HRWIDTH                     ; set text screen mode
                lbsr SF772                      ; map text screen
                lda #40                         ; set up scren size in character cells
                ldb #ROWMAX
                std H.COLUMN
                ldd #HRESSCRN+40*ROWMAX*2       ; set end address of screen
SF66D           std H.DISPEN                    ; save end address
                bsr SF68C                       ; clear the screen
                lbsr SF778                      ; unmap text screen
                lbsr SETTEXT                    ; set up display for the text screen
                rts
COL80           lda #2                          ; mode number for 80 columns
                sta HRWIDTH                     ; set text screen mode
                lbsr SF772                      ; map the screen
                lda #80                         ; set up screen size in character cells
                ldb #ROWMAX
                std H.COLUMN
                ldd #HRESSCRN+80*ROWMAX*2       ; set end address of screen
                bra SF66D                       ; set up rest of parameters
SF68C           ldx #HRESSCRN                   ; set cursor address to top left corner
                lbrn 0
                stx H.CRSLOC
                lda #0x20                       ; use space to clear screen
                ldb H.CRSATT                    ; get current attributes
SF69B           std ,x++                        ; blank a character cell
                cmpx H.DISPEN                   ; end of screen?
                blo SF69B                       ; brif not
                ldx #HRESSCRN                   ; reset to top of screen
                clra                            ; reset cursor coordinates to 0,0
                sta H.CURSX
                sta H.CURSY
                rts
; CLS patch entered from the other patch in the ECB area
ALINK23         puls cc                         ; restore zero flag
                lbrn 0
                beq SF6E0                       ; brif no arguments
                jsr EVALEXPB                    ; get colour number
                tstb                            ; 0?
                beq SF6E0                       ; brif so - treat as no arguments
                cmpb #8                         ; valid colour?
                bhi SF6E7                       ; brif not - do the easter egg or the other easter egg
                decb                            ; zero-base the colour
                leay IM.PALET,pcr               ; point to current palette settings
                lda b,y                         ; get the real colour
                sta V.BORDER                    ; set border colour
                lbsr SF766                      ; set border colour in GIME initializers
                stb H.CRSATT                    ; set attributes to foreground 0, background as selected, no blink or underline
                lda #0x20                       ; get space character
                lbsr SF772                      ; map screen
                ldx #HRESSCRN                   ; get address of start of screen
                stx H.CRSLOC                    ; put cursor there
                bsr SF69B                       ; clear screen
SF6DC           lbsr SF778                      ; unmap screen
                rts
SF6E0           lbsr SF772                      ; map screen
                bsr SF68C                       ; clear screen
                bra SF6DC                       ; ummap screen and return
SF6E7           clr H.CRSATT                    ; reset attributes to colours 0,0, no blink or underline
                lda IM.PALET                    ; get colour in register 0
                sta V.BORDER                    ; set border colour
                bsr SF766                       ; reset border colour in GIME initializers
                cmpb #100                       ; is it CLS 100?
SF6F4           beq SF730                       ; brif so - do the easter egg
                bsr SF772                       ; map the screen
                bsr SF68C                       ; clear screen
                bsr SF778                       ; unmap screen
                ldx #MICROMS-1                  ; point to Microware commercial
                jmp STRINOUT                    ; display it
MICROMS         fcc 'Microware Systems Corp.'
                fcb 0x0d,0x00
AUTHORMS        fcb 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00     ; the ROM/RAM copy sets this to the actual easter egg text
                fcb 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
                fcb 0x00,0x00,0x00,0x00,0x00
SF730           bsr SF772                       ; map the screen
                lbsr SF68C                      ; clear it
                bsr SF778                       ; unmap the screen
                ldx #AUTHORMS-1                 ; point to the easter egg
                jsr STRINOUT                    ; display it
                pshs x                          ; save X for some reason
                leax >SF6F4,pcr                 ; point to start of easter egg code
                lda #0x12                       ; NOP opcode
                sta ,x+                         ; blank out the branch that brings us here
                sta ,x
                leax >AUTHORMS,pcr              ; point to author message
SF74D           sta ,x+                         ; blank out character in string or this code
                cmpx #SF74D                     ; end of string or display code?
                blo SF74D                       ; brif not
                puls x                          ; restore X
                rts
; Line input routine patch for handling CLEAR
ALINK27         tst HRWIDTH                     ; is it 40/80 column screen?
                bne SF761                       ; brif so
                jsr LA928                       ; clear 32 column screen
SF75E           jmp LA390                       ; go make to mainline
SF761           lbsr SF6E0                      ; clear the screen
                bra SF75E                       ; return to mainline
SF766           pshs y                          ; save register
                leay SE03B,pcr                  ; point to text initializers
                sta 3,y                         ; set border in 40 column initializer
                sta 12,y                        ; set border in 80 column initializer
                puls y,pc                       ; restore registers and return
SF772           orcc #0x50                      ; clobber interrupts
                lbsr SELTEXT                    ; map the text screen (by setting *all 16* MMU registers)
                rts
SF778           lbsr SETMMU                     ; unmap text screen (by setting *all 16* MMU registers)
                andcc #0xaf                     ; restart interrupts
                rts
; The driver for putting characters on the 40 and 80 column screen is here, modulo the WIDTH command and clear
; screen routines above.
;
; There are several major problems with this driver:
;
; * Cursor handling is overly complicated. Instead of doing what Color Basic does and only show the cursor
; when waiting for input in the generic input routine, this driver displays it almost all of the time and, thus,
; has all manner of code for managing the cursor that would not be needed otherwise.
; * The system goes out of its way to set up the screen height and width values. Then, it doesn't bother using
; them consistently, especially during the screen scrolling routine. Indeed, the screen scrolling routine could
; be made completely general purpose by using two pointers, say U for the destination and X for the source. Then
; the column count could be used to decide the line width (to calculate the offset betwen U and X) and then the
; row count could be used to set the row number after the scrolling is done. This would remove any hard coded
; offsets or screen size assumptions.
; * The routines for mapping and unmapping the text screen are inexcusably slow. Only one MMU register needs to
; be changed in either routine. However, instead of doing that, the routines use an inefficient routine that
; sets *all 16* MMU registers (both tasks!). This reduces screen output speed so much that a fast reader can
; actually keep up with the output going full speed. Simply replacing these two routines with simpler ones that
; do not do that dumbassery gets performance on par with the 32 column VDG screen.
;
; Along with the above, some of the code is far more convoluted than it needs to be, but that is relatively
; benign compared to everything else.
;
; Blink cursor patch
ALINK24         bsr SF787                       ; blink the cursor
                jsr KEYIN                       ; get keypress
                beq ALINK24                     ; brif no key pressed
                puls b,x,pc                     ; return to caller
SF787           dec BLKCNT                      ; time to blink cursor?
                bne SF7A8                       ; brif not
                ldb #11                         ; reset blink counter
                stb BLKCNT
                bsr SF772                       ; map screen
                ldx H.CRSLOC                    ; get cursor pointer
                lda 1,x                         ; get current attributes
                bita #0x40                      ; is underline on?
                beq SF79F                       ; brif not - enable it
                lda H.CRSATT                    ; use current attributes if it is
                bra SF7A4
SF79F           lda H.CRSATT                    ; get current attributes
                ora #0x40                       ; turn on underline
SF7A4           sta 1,x                         ; save new attributes
                bsr SF778                       ; unmap screen
SF7A8           ldx #DEBDEL                     ; do a delay
                jmp LA7D3
; Put character on screen patch
ALINK22         bsr SF772                       ; map the screen
                lbrn 0
                ldx H.CRSLOC                    ; get cursor location
                cmpa #0x08                      ; backspace?
                bne SF7C4                       ; brif not
                cmpx #HRESSCRN                  ; at start of screen?
                beq SF7DE                       ; brif so - do nothing
                bsr SF7E2                       ; do a backspace
                bra SF7DE                       ; finish up
SF7C4           cmpa #0x0d                      ; carriage return?
                bne SF7CC                       ; brif not
                bsr SF827                       ; do a carriage return
                bra SF7D7                       ; finish up with scroll check
SF7CC           cmpa #0x20                      ; is it a control code?
                blo SF7DE                       ; brif so - do nothing
                ldb H.CRSATT                    ; get current attributes
                std ,x                          ; put character on screen
                bsr SF807                       ; move cursor forward
SF7D7           cmpx H.DISPEN                   ; end of screen?
                blo SF7DE                       ; brif not
                bsr SF854                       ; scroll screen
SF7DE           bsr SF778                       ; unmap the screen
                puls a,b,x,pc                   ; restore registers and return
SF7E2           pshs b,a                        ; save registers
                lda #0x20                       ; space character
                ldb H.CRSATT                    ; get attributes
                std ,x                          ; turns off cursor at this position and blanks it
                orb #0x40                       ; turn on underline (we'll put a cursor in the previous position)
                std -2,x                        ; put blank and cursor back one
                leax -2,x                       ; move pointer back
                stx H.CRSLOC                    ; save new cursor pointer
                ldd H.CURSX                     ; get coordinates
                deca                            ; move horizontal back
                bpl SF802                       ; brif we didn't wrap
                decb                            ; move vertical back
                stb H.CURSY                     ; save it
                lda H.COLUMN                    ; get screen width
                deca                            ; coordinates are zero-based so now we have the max horizontal coord
SF802           sta H.CURSX                     ; save new horizontal position
                puls a,b,pc                     ; restore registers and return
SF807           pshs a,b                        ; save registers
                lda #0x20                       ; we'll blank a character for the cursor
                ldb H.CRSATT                    ; get attributes
                orb #0x40                       ; force underline for cursor
                leax 2,x                        ; move pointer forward
                std ,x                          ; put blank and cursor on screen
                stx H.CRSLOC                    ; save new cursor position
                ldd H.CURSX                     ; get coordinates
                inca                            ; move right
                cmpa H.COLUMN                   ; did we hit the edge?
                blo SF802                       ; brif not - save new horizontal coordinate and return
                incb                            ; bump line
                stb H.CURSY                     ; save new line
                clra                            ; reset to left side of screen
                bra SF802                       ; save new horizontal coordinate and return
SF827           pshs a,b                        ; save registers
                lda #0x20                       ; get space character
                ldb H.CRSATT                    ; get attributes
SF82E           std ,x++                        ; blank a character
                pshs a                          ; save character
                lda H.CURSX                     ; get horizontal position
                inca                            ; bump it
                sta H.CURSX                     ; save new position
                cmpa H.COLUMN                   ; edge of screen?
                puls a                          ; restore character
                blo SF82E                       ; brif not end of line yet
                stx H.CRSLOC                    ; save cursor location
                clr H.CURSX                     ; reset to left edge
                inc H.CURSY                     ; bump row
                lda #0x20                       ; space character
                ldb H.CRSATT                    ; get attributes
                orb #0x40                       ; turn on underline
                std ,x                          ; put a cursor on screen
                puls a,b,pc                     ; restore registers and return
SF854           pshs a,b                        ; save registers
                ldx #HRESSCRN                   ; point to start of screen
                lda H.COLUMN                    ; get screen width
                cmpa #40                        ; is it 40 columns?
                bne SF86E                       ; brif not - do 80 column scroll
SF860           ldd 2*40,x                      ; get character cell from one line down
                std ,x++                        ; move it here
                cmpx #HRESSCRN+(ROWMAX-1)*40*2  ; at start of last row?
                blo SF860                       ; brif not
SF86A           bsr SF87B                       ; fill last row with spaces
                puls a,b,pc                     ; restore registers and return
SF86E           ldd 80*2,x                      ; get a character cell from next row
                std ,x++                        ; put it here
                cmpx #HRESSCRN+(ROWMAX-1)*80*2  ; at start of last row?
                blo SF86E                       ; brif not
                bra SF86A                       ; blank out last row and finish up
SF87B           clr H.CURSX                     ; reset column to 0
                lda #ROWMAX-1                   ; reset row number to bottom of screen
                sta H.CURSY
                lda #0x20                       ; get space character
                ldb H.CRSATT                    ; get attributes
                pshs x                          ; save pointer to start of row
SF88A           std ,x++                        ; blank a character
                cmpx H.DISPEN                   ; at end of screen?
                bne SF88A                       ; brif not
                clr H.CURSX                     ; reset horizontal position to margin
                puls x                          ; get start of line pointer
                lda #0x20                       ; space haracter
                ldb H.CRSATT                    ; get attributes
                orb #0x40                       ; turn on underline
                std ,x                          ; put a bleeping cursor at start of line
                stx H.CRSLOC                    ; set cursor position
                rts
; Conditional newline patch. Note that this maps and unmaps the text screen in 40/80 column mode
; but that is completely unneeded to just test the X coordinate.
ALINK26         tst DEVNUM                      ; is it screen?
                bne SF8AB                       ; brif not
                tst HRWIDTH                     ; VDG screen?
                bne SF8B1                       ; brif not
SF8AB           jsr LA35F                       ; set up print parameters
                jmp LB95F                       ; re-enter mainline code
SF8B1           lbsr SF772                      ; map screen
                tst H.CURSX                     ; at left margin?
                pshs cc                         ; save Z flag
                lbsr SF778                      ; unmap screen
                puls cc                         ; get back Z flag
                lbne LB958                      ; brif not at left margine - do CR
                rts
; PRINT @ patch
ALINK25         tst HRWIDTH                     ; VDG screen?
                bne SF8CD                       ; brif not - raise error
                jsr LA554                       ; move cursor to specified position
                jmp LB905                       ; return to mainline code
SF8CD           ldb #39*2                       ; code for HP error
                jmp LAC46                       ; raise error
; LOCATE command
; The parameter checking here could simply use the H.COLUMN and H.ROW variables and it would
; be loads simpler. Also, if the dumbassery with the cursor wasn't a thing, this routine wouldn't
; need to mess with mapping the screen or screwing around with the cursor.
LOCATE          ldb HRWIDTH                     ; is it 40/80 column screen?
                lbrn 0
                beq SF8CD                       ; brif not - raise error
                pshs b                          ; save screen mode
                jsr SE7B2                       ; evaluate coordinates
                lda BINVAL+1                    ; get X coordinate
                puls b                          ; get back screen mode
                cmpb #1                         ; is it 40 column screen?
                bne SF8EB                       ; brif not
                cmpa #40                        ; in range for 40 columns?
                bra SF8ED
SF8EB           cmpa #80                        ; in range for 80 columns?
SF8ED           lbhs LB44A                      ; brif not - raise error
                ldb VERBEG+1                    ; get Y coordinate
                cmpb #ROWMAX                    ; is it in range?
                bhs SF8ED                       ; brif not - raise error
                pshs d                          ; save new coordinates
                lbsr SF772                      ; map screen
                std H.CURSX                     ; set screen coordinates
                ldx H.CRSLOC                    ; get pointer to old position
                lda H.CRSATT                    ; replace attributes with current ones
                sta 1,x
                lda H.COLUMN                    ; get number of columns (why not use this above?)
                asla                            ; two bytes per character cell
                mul                             ; now D is offset to start of row
                ldx #HRESSCRN                   ; get start of screen
                leax d,x                        ; now X points to the start of the line
                puls a,b                        ; get back column and row numbers
                asla                            ; two bytes per character cell
                tfr a,b                         ; need this in B since we'll overflow singed 8 bits
                abx                             ; offset to correct cursor position
                lda H.CRSATT                    ; get attributes
                ora #0x40                       ; enable underline
                sta 1,x                         ; enable cursor
                stx H.CRSLOC                    ; save new cursor pointer
                lbsr SF778                      ; unmap screen
                rts
; HSTAT command
HSTAT           tst HRWIDTH                     ; is it 40/80 column screen?
                lbrn 0
                beq SF8CD                       ; brif not - raise error
                lbsr SF772                      ; map the screen
                ldx H.CRSLOC                    ; get cursor pointer
                ldd ,x                          ; get character and attributes
                std VCB                         ; save them
                ldd H.CURSX                     ; get screen coordinates
                std VCD                         ; save them
                lbsr SF778                      ; unmap screen
                jsr LB357                       ; evaluate variable for character
                stx VARDES                      ; saveit
                jsr SYNCOMMA                    ; insist on a comma
                ldb #1                          ; make a single character string
                jsr LB56D
                lda VCB                         ; get character on screen
                jsr LB511                       ; get string details
                sta ,x                          ; save character in string
                jsr LB54C                       ; put string on string stack
                ldx VARDES                      ; point to variable descriptor
                tst -1,x                        ; is it a string? (should have checked after evaluating instead)
                lbpl LB151                      ; do type mismatch if number
                ldy FPA0+2                      ; point to destination string descriptor
                ldb #5                          ; copy 5 bytes from newly created string into variable
SF963           lda ,y+                         ; copy byte
                sta ,x+
                decb                            ; done all?
                bne SF963                       ; brif not
                LDX TEMPPT                      ; point to new string descriptor
                leax -5,x                       ; BUG: should just call LB675 to remove string from string stack
                stx TEMPPT
                jsr LB357                       ; evaluate a variable (for X coord)
                stx VARDES                      ; save pointer to it
                jsr SYNCOMMA                    ; insist on a comma after it
                clra                            ; zero extend attributes
                ldb VCB+1                       ; get attribute byte
                jsr GIVABF                      ; convert to float
                ldx VARDES                      ; point to variable
                tst -1,x                        ; test if numeric (should have tested VALTYP above)
                lbmi LB151                      ; TM error if not number
                jsr LBC35                       ; pack FPA0 to variable
                jsr LB357                       ; evaluate another variable
                stx VARDES                      ; save it
                jsr SYNCOMMA                    ; insist on a comma
                clra                            ; zero extend the X coordinate
                ldb VCD                         ; get X coordinate
                jsr GIVABF                      ; turn into a FP number
                ldx VARDES                      ; get variable
                tst -1,x                        ; is it a number (should have tested VALTYP above)
                LBMI LB151                      ; brif not - TM error
                jsr LBC35                       ; pack FPA0 to variable
                jsr LB357                       ; evaluate another variable
                stx VARDES                      ; save it
                clra                            ; zero extend Y coordinate
                ldb VCD+1                       ; get Y coordinate
                jsr GIVABF                      ; turn into a FP number
                ldx VARDES                      ; get variable descriptor back
                tst -1,x                        ; is it a number (should have tested VALTYP above)
                lbmi LB151                      ; brif not - TM error
                jsr LBC35                       ; pack FPA0 to variable
                rts
; ATTR command
ATTR            jsr EVALEXPB                    ; evaluate foreground colour
                lbrn 0
                cmpb #8                         ; there are 8 valid colours (0-7)
                lbhs LB44A                      ; brif out of range - raise error
                aslb                            ; shift over to bits 5,4,3
                aslb
                aslb
                pshs b                          ; save partial attribute byte
                jsr GETCCH                      ; fetch current character (useless call)
                jsr SYNCOMMA                    ; insist on comma
                jsr EVALEXPB                    ; evaluate background colour
                cmpb #8                         ; is it valid (0-7)?
                lbhs LB44A                      ; brif not - raise error
                orb ,s                          ; merge with partial attribute byte
                leas 1,s                        ; clean up stack (could use ,s+ above)
                andb #0x3f                      ; make sure we have zeros in bit 7,6 - unneeded
                pshs b                          ; save colour attributes
                jsr GETCCH                      ; is there mode?
SF9E3           beq SFA06                       ; brif no more flags
                jsr SYNCOMMA                    ; insist on a comma
                cmpa #'B                        ; B (blink)?
                bne SF9F6                       ; brif not
                puls b                          ; set blink bit in accumulated attributes
                orb #0x80
                pshs b
                jsr GETNCH                      ; eat the flag
                bra SF9E3                       ; look for another flag
SF9F6           cmpa #'U                        ; U (underline)?
                lbne LB44A                      ; invalid flag - raise error
                puls b                          ; get accumulated attributes and set underline bit
                orb #0x40
                pshs b
                jsr GETNCH                      ; eat the flag
                bra SF9E3                       ; look for another flag
SFA06           puls b                          ; get new attributes
                stb H.CRSATT                    ; set them as default
                rts
                fcb 0x00,0x00,0x00,0x00         ; unused bytes
; These are extra glyphs that should be part of the HPRINT font but aren't.
                fcb 0x38,0x44,0x40,0x40,0x40,0x44,0x38,0x10     ; Ç
                fcb 0x44,0x00,0x44,0x44,0x44,0x4C,0x34,0x00     ; ü
                fcb 0x08,0x10,0x38,0x44,0x7C,0x40,0x38,0x00     ; é
                fcb 0x10,0x28,0x38,0x04,0x3C,0x44,0x3C,0x00     ; â
                fcb 0x28,0x00,0x38,0x04,0x3C,0x44,0x3C,0x00     ; ä
                fcb 0x20,0x10,0x38,0x04,0x3C,0x44,0x3C,0x00     ; à
                fcb 0x10,0x00,0x38,0x04,0x3C,0x44,0x3C,0x00     ; ȧ (or å maybe?)
                fcb 0x00,0x00,0x38,0x44,0x40,0x44,0x38,0x10     ; ç
                fcb 0x10,0x28,0x38,0x44,0x7C,0x40,0x38,0x00     ; ê
                fcb 0x28,0x00,0x38,0x44,0x7C,0x40,0x38,0x00     ; ë
                fcb 0x20,0x10,0x38,0x44,0x7C,0x40,0x38,0x00     ; è
                fcb 0x28,0x00,0x30,0x10,0x10,0x10,0x38,0x00     ; ï
                fcb 0x10,0x28,0x00,0x30,0x10,0x10,0x38,0x00     ; î
                fcb 0x00,0x18,0x24,0x38,0x24,0x24,0x38,0x40     ; ẞ
                fcb 0x44,0x10,0x28,0x44,0x7C,0x44,0x44,0x00     ; Ä
                fcb 0x10,0x10,0x28,0x44,0x7C,0x44,0x44,0x00     ; Ȧ (or Å maybe?)
                fcb 0x08,0x10,0x38,0x44,0x44,0x44,0x38,0x00     ; ó
                fcb 0x00,0x00,0x68,0x14,0x3C,0x50,0x3C,0x00     ; æ
                fcb 0x3C,0x50,0x50,0x78,0x50,0x50,0x5C,0x00     ; Æ
                fcb 0x10,0x28,0x38,0x44,0x44,0x44,0x38,0x00     ; ô
                fcb 0x28,0x00,0x38,0x44,0x44,0x44,0x38,0x00     ; ö
                fcb 0x00,0x00,0x38,0x4C,0x54,0x64,0x38,0x00     ; ø
                fcb 0x10,0x28,0x00,0x44,0x44,0x4C,0x34,0x00     ; û
                fcb 0x20,0x10,0x44,0x44,0x44,0x4C,0x34,0x00     ; ù
                fcb 0x38,0x4C,0x54,0x54,0x54,0x64,0x38,0x00     ; Ø
                fcb 0x44,0x38,0x44,0x44,0x44,0x44,0x38,0x00     ; Ö
                fcb 0x28,0x44,0x44,0x44,0x44,0x44,0x38,0x00     ; Ü
                fcb 0x38,0x40,0x38,0x44,0x38,0x04,0x38,0x00     ; §
                fcb 0x08,0x14,0x10,0x38,0x10,0x50,0x3C,0x00     ; £
                fcb 0x10,0x10,0x7C,0x10,0x10,0x00,0x7C,0x00     ; ±
                fcb 0x10,0x28,0x10,0x00,0x00,0x00,0x00,0x00     ; °
                fcb 0x08,0x14,0x10,0x38,0x10,0x10,0x20,0x40     ; ſ (long s)
; These are some extra symbol glyphs
                fcb 0x00,0x10,0x18,0x1C,0x1C,0x18,0x10,0x00     ; solid right pointing triangle
                fcb 0x00,0x08,0x18,0x38,0x38,0x18,0x08,0x00     ; solid left pointing triangle
                fcb 0x00,0x00,0x00,0x7E,0x3C,0x18,0x00,0x00     ; solid down pointing triangle
                fcb 0x00,0x00,0x18,0x3C,0x7E,0x00,0x00,0x00     ; solid up pointing triangle
                fcb 0x00,0xFF,0x00,0xFF,0xFF,0x00,0xFF,0x00     ; three horizontal lines with middle one double thick
                fcb 0x00,0x00,0x30,0x3C,0x14,0x1C,0x00,0x00     ; solid square on top left of open square
                fcb 0x00,0x7E,0x42,0x5A,0x5A,0x42,0x7E,0x00     ; solid box inside larger box
                fcb 0x00,0x7E,0x7E,0x00,0x00,0x7E,0x7E,0x00     ; thick equals sign
                fcb 0x00,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x00     ; solid vertical rectangle
                fcb 0x00,0x00,0x7E,0x7E,0x7E,0x7E,0x00,0x00     ; solid horizontal rectangle
                fcb 0x00,0x7E,0x24,0x18,0x18,0x24,0x7E,0x00     ; hour glass
                fcb 0x00,0x7F,0x00,0x7F,0x7F,0x00,0x7F,0x00     ; left end three horizontal lines with middle one double thick
                fcb 0x00,0xFE,0x00,0xFE,0xFE,0x00,0xFE,0x00     ; right end three horizontal lines with middle one double thick
; The above 45 glyphs are duplicated below
                fcb 0x38,0x44,0x40,0x40,0x40,0x44,0x38,0x10
                fcb 0x44,0x00,0x44,0x44,0x44,0x4C,0x34,0x00
                fcb 0x08,0x10,0x38,0x44,0x7C,0x40,0x38,0x00
                fcb 0x10,0x28,0x38,0x04,0x3C,0x44,0x3C,0x00
                fcb 0x28,0x00,0x38,0x04,0x3C,0x44,0x3C,0x00
                fcb 0x20,0x10,0x38,0x04,0x3C,0x44,0x3C,0x00
                fcb 0x10,0x00,0x38,0x04,0x3C,0x44,0x3C,0x00
                fcb 0x00,0x00,0x38,0x44,0x40,0x44,0x38,0x10
                fcb 0x10,0x28,0x38,0x44,0x7C,0x40,0x38,0x00
                fcb 0x28,0x00,0x38,0x44,0x7C,0x40,0x38,0x00
                fcb 0x20,0x10,0x38,0x44,0x7C,0x40,0x38,0x00
                fcb 0x28,0x00,0x30,0x10,0x10,0x10,0x38,0x00
                fcb 0x10,0x28,0x00,0x30,0x10,0x10,0x38,0x00
                fcb 0x00,0x18,0x24,0x38,0x24,0x24,0x38,0x40
                fcb 0x44,0x10,0x28,0x44,0x7C,0x44,0x44,0x00
                fcb 0x10,0x10,0x28,0x44,0x7C,0x44,0x44,0x00
                fcb 0x08,0x10,0x38,0x44,0x44,0x44,0x38,0x00
                fcb 0x00,0x00,0x68,0x14,0x3C,0x50,0x3C,0x00
                fcb 0x3C,0x50,0x50,0x78,0x50,0x50,0x5C,0x00
                fcb 0x10,0x28,0x38,0x44,0x44,0x44,0x38,0x00
                fcb 0x28,0x00,0x38,0x44,0x44,0x44,0x38,0x00
                fcb 0x00,0x00,0x38,0x4C,0x54,0x64,0x38,0x00
                fcb 0x10,0x28,0x00,0x44,0x44,0x4C,0x34,0x00
                fcb 0x20,0x10,0x44,0x44,0x44,0x4C,0x34,0x00
                fcb 0x38,0x4C,0x54,0x54,0x54,0x64,0x38,0x00
                fcb 0x44,0x38,0x44,0x44,0x44,0x44,0x38,0x00
                fcb 0x28,0x44,0x44,0x44,0x44,0x44,0x38,0x00
                fcb 0x38,0x40,0x38,0x44,0x38,0x04,0x38,0x00
                fcb 0x08,0x14,0x10,0x38,0x10,0x50,0x3C,0x00
                fcb 0x10,0x10,0x7C,0x10,0x10,0x00,0x7C,0x00
                fcb 0x10,0x28,0x10,0x00,0x00,0x00,0x00,0x00
                fcb 0x08,0x14,0x10,0x38,0x10,0x10,0x20,0x40
                fcb 0x00,0x10,0x18,0x1C,0x1C,0x18,0x10,0x00
                fcb 0x00,0x08,0x18,0x38,0x38,0x18,0x08,0x00
                fcb 0x00,0x00,0x00,0x7E,0x3C,0x18,0x00,0x00
                fcb 0x00,0x00,0x18,0x3C,0x7E,0x00,0x00,0x00
                fcb 0x00,0xFF,0x00,0xFF,0xFF,0x00,0xFF,0x00
                fcb 0x00,0x00,0x30,0x3C,0x14,0x1C,0x00,0x00
                fcb 0x00,0x7E,0x42,0x5A,0x5A,0x42,0x7E,0x00
                fcb 0x00,0x7E,0x7E,0x00,0x00,0x7E,0x7E,0x00
                fcb 0x00,0x3C,0x3C,0x3C,0x3C,0x3C,0x3C,0x00
                fcb 0x00,0x00,0x7E,0x7E,0x7E,0x7E,0x00,0x00
                fcb 0x00,0x7E,0x24,0x18,0x18,0x24,0x7E,0x00
                fcb 0x00,0x7F,0x00,0x7F,0x7F,0x00,0x7F,0x00
                fcb 0x00,0xFE,0x00,0xFE,0xFE,0x00,0xFE,0x00
; The glyphs above repeat one more time here but the set is incomplete
                fcb 0x38,0x44,0x40,0x40,0x40,0x44,0x38,0x10
                fcb 0x44,0x00,0x44,0x44,0x44,0x4C,0x34,0x00
                fcb 0x08,0x10,0x38,0x44,0x7C,0x40,0x38,0x00
                fcb 0x10,0x28,0x38,0x04,0x3C,0x44,0x3C,0x00
                fcb 0x28,0x00,0x38,0x04,0x3C,0x44,0x3C,0x00
                fcb 0x20,0x10,0x38,0x04,0x3C,0x44,0x3C,0x00
                fcb 0x10,0x00,0x38,0x04,0x3C,0x44,0x3C,0x00
                fcb 0x00,0x00,0x38,0x44,0x40,0x44,0x38,0x10
                fcb 0x10,0x28,0x38,0x44,0x7C,0x40,0x38,0x00
                fcb 0x28,0x00,0x38,0x44,0x7C,0x40,0x38,0x00
                fcb 0x20,0x10,0x38,0x44,0x7C,0x40,0x38,0x00
                fcb 0x28,0x00,0x30,0x10,0x10,0x10,0x38,0x00
                fcb 0x10,0x28,0x00,0x30,0x10,0x10,0x38,0x00
                fcb 0x00,0x18,0x24,0x38,0x24,0x24,0x38,0x40
                fcb 0x44,0x10,0x28,0x44,0x7C,0x44,0x44,0x00
                fcb 0x10,0x10,0x28,0x44,0x7C,0x44,0x44,0x00
                fcb 0x08,0x10,0x38,0x44,0x44,0x44,0x38,0x00
                fcb 0x00,0x00,0x68,0x14,0x3C,0x50,0x3C,0x00
                fcb 0x3C,0x50,0x50,0x78,0x50,0x50,0x5C,0x00
                fcb 0x10,0x28,0x38,0x44,0x44,0x44,0x38,0x00
                fcb 0x28,0x00,0x38,0x44,0x44,0x44,0x38,0x00
                fcb 0x00,0x00,0x38,0x4C,0x54,0x64,0x38,0x00
                fcb 0x10,0x28,0x00,0x44,0x44,0x4C,0x34,0x00
                fcb 0x20,0x10,0x44,0x44,0x44,0x4C,0x34,0x00
                fcb 0x38,0x4C,0x54,0x54,0x54,0x64,0x38,0x00
                fcb 0x44,0x38,0x44,0x44,0x44,0x44,0x38,0x00
                fcb 0x28,0x44,0x44,0x44,0x44,0x44,0x38,0x00
                fcb 0x38,0x40,0x38,0x44,0x38,0x04,0x38,0x00
                fcb 0x08,0x14,0x10,0x38,0x10,0x50,0x3C,0x00
                fcb 0x10,0x10,0x7C,0x10,0x10,0x00,0x7C,0x00
                fcb 0x10,0x28,0x10,0x00,0x00,0x00,0x00,0x00
                fcb 0x08,0x14,0x10,0x38,0x10,0x10,0x20,0x40
                fcb 0x00,0x10,0x18,0x1C,0x1C,0x18,0x10,0x00
                fcb 0x00,0x08,0x18,0x38,0x38,0x18,0x08,0x00     ; final duplicated glyph: left pointing solid triangle
                fcb 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00     ; junk unused (or blank space)
                fcb 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF     ; junk unused (or solid block)
; This is where the constant page (FExx) would start. It's just garbage in the ROM.
                fill 0xff,8
                fill 0x00,8
                fill 0xff,8
                fill 0x00,8
                fill 0xff,8
                fill 0x00,8
                fill 0xff,8
                fill 0x00,8
                fill 0xff,8
                fill 0x00,8
                fill 0xff,8
                fill 0x00,8
                fill 0xff,8
                fill 0x00,8
                fill 0xff,8
                fill 0x00,8
                fill 0xff,8
                fill 0x00,8
                fill 0xff,8
                fill 0x00,8
                fill 0xff,8
                fill 0x00,8
                fill 0xff,8
                fill 0x00,8
                fill 0xff,8
                fill 0x00,8
                fill 0xff,8
                fill 0x00,8
                fill 0xff,8
                fill 0x00,8
                fill 0xff,8
                fill 0x00,8
; This is where the I/O page would start. It's just garbage in the ROM until the interrupt vectors.
                fill 0x00,8
                fill 0xff,8
                fill 0x00,8
                fill 0xff,8
                fill 0x00,8
                fill 0xff,8
                fill 0x00,8
                fill 0xff,8
                fill 0x00,8
                fill 0xff,8
                fill 0x00,8
                fill 0xff,8
                fill 0x00,8
                fill 0xff,8
                fill 0x00,8
                fill 0xff,8
                fill 0x00,8
                fill 0xff,8
                fill 0x00,8
                fill 0xff,8
                fill 0x00,8
                fill 0xff,8
                fill 0x00,8
                fill 0xff,8
                fill 0x00,8
                fill 0xff,8
                fill 0x00,8
                fill 0xff,8
                fill 0x00,8
                fill 0xff,8
; These are the actual CPU interrupt vectors
                fdb 0x0000                      ; would be the 6309 illegal instruction trap
                fdb INT.SWI3                    ; SWI3 bounce vector address
                fdb INT.SWI2                    ; SWI2 bounce vector address
                fdb INT.FIRQ                    ; FIRQ bounce vector address
                fdb INT.IRQ                     ; IRQ bounce vector address
                fdb INT.SWI                     ; SWI bounce vector address
                fdb INT.NMI                     ; NMI bounce vector address
                fdb L8C1B                       ; this is where execution starts on RESET or power on