Mercurial > hg > index.cgi
diff exbas10.s @ 0:605ff82c4618
Initial check in with cleaned up sources
This is the initial check in the source code in a state where it builds byte
accurate copies of all the various ROM versions included.
author | William Astle <lost@l-w.ca> |
---|---|
date | Sat, 08 Dec 2018 19:57:01 -0700 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/exbas10.s Sat Dec 08 19:57:01 2018 -0700 @@ -0,0 +1,4033 @@ + *pragma nolist + include defs.s +; These are the entry points in the Color Basic ROM which are used the the Extended Basic ROM. +; They are included here in order to keep the Extended Basic ROM separate from the Color Basic +; ROM. +BAWMST EQU 0xA0E8 +CLOAD EQU 0xA498 +CSAVE EQU 0xA44C +DATA EQU 0xAEE0 +EVALEXPB EQU 0xB70B +GIVABF EQU 0xB4F4 +INT EQU 0xBCEE +LA0E2 EQU 0xA0E2 +LA171 EQU 0xA171 +LA176 EQU 0xA176 +LA35F EQU 0xA35F +LA3ED EQU 0xA3ED +LA406 EQU 0xA406 +LA429 EQU 0xA429 +LA42D EQU 0xA42D +LA444 EQU 0xA444 +LA491 EQU 0xA491 +LA505 EQU 0xA505 +LA578 EQU 0xA578 +LA59A EQU 0xA59A +LA5A5 EQU 0xA5A5 +LA5AE EQU 0xA5AE +LA5C7 EQU 0xA5C7 +LA5E4 EQU 0xA5E4 +LA616 EQU 0xA616 +LA619 EQU 0xA619 +LA635 EQU 0xA635 +LA644 EQU 0xA644 +LA648 EQU 0xA648 +LA65F EQU 0xA65F +LA7E9 EQU 0xA7E9 +LA974 EQU 0xA974 +LA976 EQU 0xA976 +LA9A2 EQU 0xA9A2 +LA9BB EQU 0xA9BB +LAC1E EQU 0xAC1E +LAC33 EQU 0xAC33 +LAC46 EQU 0xAC46 +LAC60 EQU 0xAC60 +LAC73 EQU 0xAC73 +LAC7C EQU 0xAC7C +LAC9D EQU 0xAC9D +LACA8 EQU 0xACA8 +LACEF EQU 0xACEF +LACF1 EQU 0xACF1 +LAD01 EQU 0xAD01 +LAD19 EQU 0xAD19 +LAD21 EQU 0xAD21 +LAD26 EQU 0xAD26 +LAD33 EQU 0xAD33 +LAD9E EQU 0xAD9E +LADC6 EQU 0xADC6 +LADD4 EQU 0xADD4 +LADEB EQU 0xADEB +LAE15 EQU 0xAE15 +LAED2 EQU 0xAED2 +LAF67 EQU 0xAF67 +LAFA4 EQU 0xAFA4 +LB035 EQU 0xB035 +LB141 EQU 0xB141 +LB143 EQU 0xB143 +LB146 EQU 0xB146 +LB156 EQU 0xB156 +LB158 EQU 0xB158 +LB244 EQU 0xB244 +LB262 EQU 0xB262 +LB267 EQU 0xB267 +LB26A EQU 0xB26A +LB26F EQU 0xB26F +LB277 EQU 0xB277 +LB284 EQU 0xB284 +LB2CE EQU 0xB2CE +LB357 EQU 0xB357 +LB35C EQU 0xB35C +LB3A2 EQU 0xB3A2 +LB44A EQU 0xB44A +LB4F3 EQU 0xB4F3 +LB50F EQU 0xB50F +LB518 EQU 0xB518 +LB51A EQU 0xB51A +LB56D EQU 0xB56D +LB643 EQU 0xB643 +LB654 EQU 0xB654 +LB657 EQU 0xB657 +LB659 EQU 0xB659 +LB69B EQU 0xB69B +LB6A4 EQU 0xB6A4 +LB6AD EQU 0xB6AD +LB70E EQU 0xB70E +LB734 EQU 0xB734 +LB738 EQU 0xB738 +LB73D EQU 0xB73D +LB740 EQU 0xB740 +LB7C2 EQU 0xB7C2 +LB958 EQU 0xB958 +LB95C EQU 0xB95C +LB99F EQU 0xB99F +LB9AC EQU 0xB9AC +LB9AF EQU 0xB9AF +LB9B4 EQU 0xB9B4 +LB9B9 EQU 0xB9B9 +LB9C2 EQU 0xB9C2 +LBA1C EQU 0xBA1C +LBA3A EQU 0xBA3A +LBA92 EQU 0xBA92 +LBAC5 EQU 0xBAC5 +LBACA EQU 0xBACA +LBB48 EQU 0xBB48 +LBB5C EQU 0xBB5C +LBB6A EQU 0xBB6A +LBB82 EQU 0xBB82 +LBB8F EQU 0xBB8F +LBC14 EQU 0xBC14 +LBC2F EQU 0xBC2F +LBC35 EQU 0xBC35 +LBC4C EQU 0xBC4C +LBC5F EQU 0xBC5F +LBC6D EQU 0xBC6D +LBCA0 EQU 0xBCA0 +LBCC8 EQU 0xBCC8 +LBD99 EQU 0xBD99 +LBDB6 EQU 0xBDB6 +LBDBB EQU 0xBDBB +LBDC0 EQU 0xBDC0 +LBDC5 EQU 0xBDC5 +LBDCC EQU 0xBDCC +LBDD9 EQU 0xBDD9 +LBEC0 EQU 0xBEC0 +LBEC5 EQU 0xBEC5 +LBEE9 EQU 0xBEE9 +LBEF0 EQU 0xBEF0 +LBEFF EQU 0xBEFF +LBFA6 EQU 0xBFA6 +LET EQU 0xAF89 +PUTCHR EQU 0xA282 +SIN EQU 0xBF78 +SNDBLK EQU 0xA7F4 +STRINOUT EQU 0xB99C +SYNCOMMA EQU 0xB26D +WRLDR EQU 0xA7D8 + *pragma list +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; EXTENDED COLOR BASIC ROM +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + 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 + ldx #L80E8-1 ; show sign on message + jsr STRINOUT + 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 nop ; flag to mark routine as valid + 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 routine is dead code that is never used by any Basic ROMs. +L80D0 lda PIA1+2 ; check memory size jump + bita #2 + bne L80DA ; brif high + sta SAMREG+29 ; set SAM for 64K memory size +L80DA jmp ,x ; jump to address in X + fcb 0,0 ; dead space +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 1.0' + fcb 0x0d + fcc 'COPYRIGHT (C) 1980 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 + 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 + 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)? + 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 + 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 +DLOAD jsr LA429 ; close files +L8C1B clr ,-s ; save default token (not DLOADM) + cmpa #'M ; is it DLOADM? + bne L8C25 ; brif not + sta ,s ; save the "M" + jsr GETNCH ; eat the "M" +L8C25 jsr LA578 ; parse the file name + jsr GETCCH ; get character after file name + beq L8C44 ; brif end of line + jsr SYNCOMMA ; make sure we have a comma + cmpa #', ; do we have 2 commas? + beq L8C44 ; brif so - use default baud rate + jsr EVALEXPB ; evaluate baud rate +L8C36 lda #44*4 ; delay for 300 baud + tstb ; was argument 0? + beq L8C42 ; brif so - 300 baud + lda #44 ; constant for 1200 baud + decb ; was it 1? + lbne LB44A ; raise error if not +L8C42 sta DLBAUD ; save baud rate constant +L8C44 jsr L8CD0 ; transmit file name and read in file status + pshs a ; save register + lda #-3 ; set input to DLOAD + sta DEVNUM + puls a ; restore register + tst ,s+ ; is it DLOADM? + bne L8C85 ; brif so + jsr LA5C7 ; check for end of line - error if not + 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 #12 ; are we at the right digit? + bcc L9177 ; brif not + addb #'0+12 ; 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 #6 ; 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? + lblo LB44A ; brif so + 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 + addd #200 ; make some extra space (for stack) + subd FRETOP ; see if new top of program fits + bhs L966D ; brif there isn't enough space + 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