mirror of
https://github.com/trudnai/Steve2.git
synced 2024-12-27 09:30:26 +00:00
8a6f1654ee
Fixed some issues
6915 lines
282 KiB
ArmAsm
6915 lines
282 KiB
ArmAsm
include(`asm.m4h')
|
|
; --------------------------------
|
|
;
|
|
; Applesoft BASIC, V2
|
|
;
|
|
; Written by Marc McDonald and Randy Wigginton.
|
|
;
|
|
; Original copyright 1976 by Microsoft,
|
|
; 1977 by Apple Computer.
|
|
;
|
|
; Disassembled by (unknown).
|
|
; Fixed by Chris Mosher.
|
|
;
|
|
; For the cc65.org Assembler (ca65)
|
|
;
|
|
; Applesoft BASIC was first written by
|
|
; Marc McDonald, the first employee of Microsoft,
|
|
; in mid-1976. That version was bought by Apple
|
|
; and released (on casette) in Nov. 1977.
|
|
;
|
|
; Version 2 was written by Randy Wigginton and
|
|
; others at Apple in spring 1978. This version
|
|
; was released in several different forms. The
|
|
; one reproduced by this source assembly file is
|
|
; the main-board ROM form, which appeared in the
|
|
; Apple ][ plus ROM at $D000-$F7FF.
|
|
;
|
|
; --------------------------------
|
|
|
|
|
|
|
|
; --------------------------------
|
|
; ZERO PAGE LOCATIONS:
|
|
; --------------------------------
|
|
GOWARM = $00 ; GETS "JMP RESTART"
|
|
GOSTROUT = $03 ; GETS "JMP STROUT"
|
|
USR = $0A ; GETS "JMP <USER ADDR>"
|
|
; (INITIALLY $E199)
|
|
CHARAC = $0D ; ALTERNATE STRING TERMINATOR
|
|
ENDCHR = $0E ; STRING TERMINATOR
|
|
TKN_CNTR = $0F ; USED IN PARSE
|
|
EOL_PNTR = $0F ; USED IN NXLIN
|
|
NUMDIM = $0F ; USED IN ARRAY ROUTINES
|
|
DIMFLG = $10 ;
|
|
VALTYP = $11 ; $:VALTYP=$FF; %:VALTYP+1=$80
|
|
DATAFLG = $13 ; USED IN PARSE
|
|
GARFLG = $13 ; USED IN GARBAG
|
|
SUBFLG = $14 ;
|
|
INPUTFLG = $15 ; = $40 FOR GET, $98 FOR READ
|
|
CPRMASK = $16 ; RECEIVES CPRTYP IN FRMEVL
|
|
SIGNFLG = $16 ; FLAGS SIGN IN TAN
|
|
HGR_SHAPE = $1A ;
|
|
HGR_BITS = $1C ;
|
|
HGR_COUNT = $1D ;
|
|
MON_CH = $24 ;
|
|
MON_GBASL = $26 ;
|
|
MON_GBASH = $27 ;
|
|
MON_H2 = $2C ;
|
|
MON_V2 = $2D ;
|
|
MON_HMASK = $30 ;
|
|
MON_INVFLG = $32 ;
|
|
MON_PROMPT = $33 ;
|
|
MON_A1L = $3C ; USED BY TAPE I/O ROUTINES
|
|
MON_A1H = $3D ; "
|
|
MON_A2L = $3E ; "
|
|
MON_A2H = $3F ; "
|
|
LINNUM = $50 ; CONVERTED LINE #
|
|
TEMPPT = $52 ; LAST USED TEMP STRING DESC
|
|
LASTPT = $53 ; LAST USED TEMP STRING PNTR
|
|
TEMPST = $55 ; HOLDS UP TO 3 DESCRIPTORS
|
|
INDEX = $5E ;
|
|
DEST = $60 ;
|
|
RESULT = $62 ; RESULT OF LAST * OR /
|
|
TXTTAB = $67 ; START OF PROGRAM TEXT
|
|
VARTAB = $69 ; START OF VARIABLE STORAGE
|
|
ARYTAB = $6B ; START OF ARRAY STORAGE
|
|
STREND = $6D ; END OF ARRAY STORAGE
|
|
FRETOP = $6F ; START OF STRING STORAGE
|
|
FRESPC = $71 ; TEMP PNTR, STRING ROUTINES
|
|
MEMSIZ = $73 ; END OF STRING SPACE (HIMEM)
|
|
CURLIN = $75 ; CURRENT LINE NUMBER
|
|
; ( = $FFXX IF IN DIRECT MODE)
|
|
OLDLIN = $77 ; ADDR. OF LAST LINE EXECUTED
|
|
OLDTEXT = $79 ;
|
|
DATLIN = $7B ; LINE # OF CURRENT DATA STT.
|
|
DATPTR = $7D ; ADDR OF CURRENT DATA STT.
|
|
INPTR = $7F ;
|
|
VARNAM = $81 ; NAME OF VARIABLE
|
|
VARPNT = $83 ; ADDR OF VARIABLE
|
|
FORPNT = $85 ;
|
|
TXPSV = $87 ; USED IN INPUT
|
|
LASTOP = $87 ; SCRATCH FLAG USED IN FRMEVL
|
|
CPRTYP = $89 ; >,=,< FLAG IN FRMEVL
|
|
TEMP3 = $8A ;
|
|
FNCNAM = $8A ;
|
|
DSCPTR = $8C ;
|
|
DSCLEN = $8F ; USED IN GARBAG
|
|
JMPADRS = $90 ; GETS "JMP ...."
|
|
LENGTH = $91 ; USED IN GARBAG
|
|
ARG_EXTENSION = $92 ; FP EXTRA PRECISION
|
|
TEMP1 = $93 ; SAVE AREAS FOR FAC
|
|
ARYPNT = $94 ; USED IN GARBAG
|
|
HIGHDS = $94 ; PNTR FOR BLTU
|
|
HIGHTR = $96 ; PNTR FOR BLTU
|
|
TEMP2 = $98 ;
|
|
TMPEXP = $99 ; USED IN FIN (EVAL)
|
|
INDX = $99 ; USED BY ARRAY RTNS
|
|
EXPON = $9A ; "
|
|
DPFLG = $9B ; FLAGS DEC PNT IN FIN
|
|
LOWTR = $9B ;
|
|
EXPSGN = $9C ;
|
|
FAC = $9D ; MAIN FLT PT ACCUMULATOR
|
|
DSCTMP = $9D ;
|
|
VPNT = $A0 ; TEMP VAR PTR
|
|
FAC_SIGN = $A2 ; HOLDS UNPACKED SIGN
|
|
SERLEN = $A3 ; HOLDS LENGTH OF SERIES-1
|
|
SHIFT_SIGN_EXT = $A4 ; SIGN EXTENSION, RIGHT SHIFTS
|
|
ARG = $A5 ; SECONDARY FP ACC
|
|
ARG_SIGN = $AA ;
|
|
SGNCPR = $AB ; FLAGS OPP SIGN IN FP ROUT.
|
|
FAC_EXTENSION = $AC ; FAC EXTENSION BYTE
|
|
SERPNT = $AD ; PNTR TO SERIES DATA IN FP
|
|
STRNG1 = $AB ;
|
|
STRNG2 = $AD ;
|
|
PRGEND = $AF ;
|
|
CHRGET = $B1 ;
|
|
CHRGOT = $B7 ;
|
|
TXTPTR = $B8 ;
|
|
RNDSEED = $C9 ;
|
|
HGR_DX = $D0 ;
|
|
HGR_DY = $D2 ;
|
|
HGR_QUADRANT = $D3 ;
|
|
HGR_E = $D4 ;
|
|
LOCK = $D6 ; NO USER ACCESS IF > 127
|
|
ERRFLG = $D8 ; $80 IF ON ERR ACTIVE
|
|
ERRLIN = $DA ; LINE # WHERE ERROR OCCURRED
|
|
ERRPOS = $DC ; TXTPTR SAVE FOR HANDLERR
|
|
ERRNUM = $DE ; WHICH ERROR OCCURRED
|
|
ERRSTK = $DF ; STACK PNTR BEFORE ERROR
|
|
HGR_X = $E0 ;
|
|
HGR_Y = $E2 ;
|
|
HGR_COLOR = $E4 ;
|
|
HGR_HORIZ = $E5 ; BYTE INDEX FROM GBASH,L
|
|
HGR_PAGE = $E6 ; HGR=$20, HGR2=$40
|
|
HGR_SCALE = $E7 ;
|
|
HGR_SHAPE_PNTR = $E8 ;
|
|
HGR_COLLISIONS = $EA ;
|
|
FIRST = $F0 ;
|
|
SPEEDZ = $F1 ; OUTPUT SPEED
|
|
TRCFLG = $F2 ;
|
|
FLASH_BIT = $F3 ; = $40 FOR FLASH, ELSE =$00
|
|
TXTPSV = $F4 ;
|
|
CURLSV = $F6 ;
|
|
REMSTK = $F8 ; STACK PNTR BEFORE EACH STT.
|
|
HGR_ROTATION = $F9 ;
|
|
; $FF IS ALSO USED BY THE STRING OUT ROUTINES
|
|
; --------------------------------
|
|
STACK = $0100
|
|
INPUT_BUFFER = $0200
|
|
AMPERSAND_VECTOR = $03F5 ; - 3F7 GETS "JMP ...."
|
|
; --------------------------------
|
|
; I/O & SOFT SWITCHES
|
|
; --------------------------------
|
|
KEYBOARD = $C000
|
|
SW_TXTCLR = $C050
|
|
SW_MIXCLR = $C052
|
|
SW_MIXSET = $C053
|
|
SW_LOWSCR = $C054
|
|
SW_HISCR = $C055
|
|
SW_LORES = $C056
|
|
SW_HIRES = $C057
|
|
; --------------------------------
|
|
; MONITOR SUBROUTINES
|
|
; --------------------------------
|
|
MON_PLOT = $F800
|
|
MON_HLINE = $F819
|
|
MON_VLINE = $F828
|
|
MON_SETCOL = $F864
|
|
MON_SCRN = $F871
|
|
MON_PREAD = $FB1E
|
|
MON_SETTXT = $FB39
|
|
MON_SETGR = $FB40
|
|
MON_TABV = $FB5B
|
|
MON_HOME = $FC58
|
|
MON_WAIT = $FCA8
|
|
MON_RD2BIT = $FCFA
|
|
MON_RDKEY = $FD0C
|
|
MON_GETLN = $FD6A
|
|
MON_COUT = $FDED
|
|
MON_INPORT = $FE8B
|
|
MON_OUTPORT = $FE95
|
|
MON_WRITE = $FECD
|
|
MON_READ = $FEFD
|
|
MON_READ2 = $FF02
|
|
; --------------------------------
|
|
; --------------------------------
|
|
; APPLESOFT TOKENS
|
|
; --------------------------------
|
|
TOKEN_FOR = $81
|
|
TOKENDWTA = $83
|
|
TOKEN_POP = $A1
|
|
TOKEN_GOTO = $AB
|
|
TOKEN_GOSUB = $B0
|
|
TOKEN_REM = $B2
|
|
TOKEN_PRINT = $BA
|
|
TOKEN_TAB = $C0
|
|
TOKEN_TO = $C1
|
|
TOKEN_FN = $C2
|
|
TOKEN_SPC = $C3
|
|
TOKEN_THEN = $C4
|
|
TOKENDB = $C5
|
|
TOKEN_NOT = $C6
|
|
TOKEN_STEP = $C7
|
|
TOKEN_PLUS = $C8
|
|
TOKEN_MINUS = $C9
|
|
TOKEN_GREATER = $CF
|
|
TOKENEQUUAL = $D0
|
|
TOKEN_SGN = $D2
|
|
TOKEN_SCRN = $D7
|
|
TOKEN_LEFTSTR = $E8
|
|
; --------------------------------
|
|
; BRANCH TABLE FOR TOKENS
|
|
; --------------------------------
|
|
TOKEN_ADDRESS_TABLE ASM_ADDR(`ENDX-1') ; $80...128...END
|
|
ASM_ADDR(`FOR-1') ; $81...129...FOR
|
|
ASM_ADDR(`NEXT-1') ; $82...130...NEXT
|
|
ASM_ADDR(`DATA-1') ; $83...131..DWTA
|
|
ASM_ADDR(`INPUT-1') ; $84...132...INPUT
|
|
ASM_ADDR(`DEL-1') ; $85...133...DEL
|
|
ASM_ADDR(`DIM-1') ; $86...134...DIM
|
|
ASM_ADDR(`READ-1') ; $87...135...READ
|
|
ASM_ADDR(`GR-1') ; $88...136...GR
|
|
ASM_ADDR(`TEXT-1') ; $89...137...TEXT
|
|
ASM_ADDR(`PR_NUMBER-1') ; $8A...138...PR#
|
|
ASM_ADDR(`IN_NUMBER-1') ; $8B...139...IN#
|
|
ASM_ADDR(`CALL-1') ; $8C...140...CALL
|
|
ASM_ADDR(`PLOT-1') ; $8D...141...PLOT
|
|
ASM_ADDR(`HLIN-1') ; $8E...142...HLIN
|
|
ASM_ADDR(`VLIN-1') ; $8F...143...VLIN
|
|
ASM_ADDR(`HGR2-1') ; $90...144...HGR2
|
|
ASM_ADDR(`HGR-1') ; $91...145...HGR
|
|
ASM_ADDR(`HCOLOR-1') ; $92...146...HCOLOR=
|
|
ASM_ADDR(`HPLOT-1') ; $93...147...HPLOT
|
|
ASM_ADDR(`DRAW-1') ; $94...148...DRAW
|
|
ASM_ADDR(`XDRAW-1') ; $95...149...XDRAW
|
|
ASM_ADDR(`HTAB-1') ; $96...150...HTAB
|
|
ASM_ADDR(`MON_HOME-1') ; $97...151...HOME
|
|
ASM_ADDR(`ROT-1') ; $98...152...ROT=
|
|
ASM_ADDR(`SCALE-1') ; $99...153...SCALE=
|
|
ASM_ADDR(`SHLOAD-1') ; $9A...154...SHLOAD
|
|
ASM_ADDR(`TRACE-1') ; $9B...155...TRACE
|
|
ASM_ADDR(`NOTRACE-1') ; $9C...156...NOTRACE
|
|
ASM_ADDR(`NORMAL-1') ; $9D...157...NORMAL
|
|
ASM_ADDR(`INVERSE-1') ; $9E...158...INVERSE
|
|
ASM_ADDR(`FLASH-1') ; $9F...159...FLASH
|
|
ASM_ADDR(`COLOR-1') ; $A0...160...COLOR=
|
|
ASM_ADDR(`POP-1') ; $A1...161...POP
|
|
ASM_ADDR(`VTAB-1') ; $A2...162...VTAB
|
|
ASM_ADDR(`HIMEM-1') ; $A3...163...HIMEM:
|
|
ASM_ADDR(`LOMEM-1') ; $A4...164...LOMEM:
|
|
ASM_ADDR(`ONERR-1') ; $A5...165...ONERR
|
|
ASM_ADDR(`RESUME-1') ; $A6...166...RESUME
|
|
ASM_ADDR(`RECALL-1') ; $A7...167...RECALL
|
|
ASM_ADDR(`STORE-1') ; $A8...168...STORE
|
|
ASM_ADDR(`SPEED-1') ; $A9...169...SPEED=
|
|
ASM_ADDR(`LET-1') ; $AA...170...LET
|
|
ASM_ADDR(`GOTO-1') ; $AB...171...GOTO
|
|
ASM_ADDR(`RUN-1') ; $AC...172...RUN
|
|
ASM_ADDR(`IF-1') ; $AD...173...IF
|
|
ASM_ADDR(`RESTORE-1') ; $AE...174...RESTORE
|
|
ASM_ADDR(`AMPERSAND_VECTOR-1') ; $AF...175...&
|
|
ASM_ADDR(`GOSUB-1') ; $B0...176...GOSUB
|
|
ASM_ADDR(`POP-1') ; $B1...177...RETURN
|
|
ASM_ADDR(`REM-1') ; $B2...178...REM
|
|
ASM_ADDR(`STOP-1') ; $B3...179...STOP
|
|
ASM_ADDR(`ONGOTO-1') ; $B4...180...ON
|
|
ASM_ADDR(`WAIT-1') ; $B5...181...WAIT
|
|
ASM_ADDR(`LOAD-1') ; $B6...182...LOAD
|
|
ASM_ADDR(`SAVE-1') ; $B7...183...SAVE
|
|
ASM_ADDR(`DEF-1') ; $B8...184...DEF
|
|
ASM_ADDR(`POKE-1') ; $B9...185...POKE
|
|
ASM_ADDR(`PRINT-1') ; $BA...186...PRINT
|
|
ASM_ADDR(`CONT-1') ; $BB...187...CONT
|
|
ASM_ADDR(`LIST-1') ; $BC...188...LIST
|
|
ASM_ADDR(`CLEAR-1') ; $BD...189...CLEAR
|
|
ASM_ADDR(`GET-1') ; $BE...190...GET
|
|
ASM_ADDR(`NEW-1') ; $BF...191...NEW
|
|
; --------------------------------
|
|
UNFNC ASM_ADDR(`SGN') ; $D2...210...SGN
|
|
ASM_ADDR(`INT') ; $D3...211...INT
|
|
ASM_ADDR(`ABS') ; $D4...212...ABS
|
|
ASM_ADDR(`USR') ; $D5...213...USR
|
|
ASM_ADDR(`FRE') ; $D6...214...FRE
|
|
ASM_ADDR(`ERROR') ; $D7...215...SCRN(
|
|
ASM_ADDR(`PDL') ; $D8...216...PDL
|
|
ASM_ADDR(`POS') ; $D9...217...POS
|
|
ASM_ADDR(`SQR') ; $DA...218...SQR
|
|
ASM_ADDR(`RND') ; $DB...219...RND
|
|
ASM_ADDR(`LOG') ; $DC...220...LOG
|
|
ASM_ADDR(`EXP') ; $DD...221...EXP
|
|
ASM_ADDR(`COS') ; $DE...222...COS
|
|
ASM_ADDR(`SIN') ; $DF...223...SIN
|
|
ASM_ADDR(`TAN') ; $E0...224...TAN
|
|
ASM_ADDR(`ATN') ; $E1...225...ATN
|
|
ASM_ADDR(`PEEK') ; $E2...226...PEEK
|
|
ASM_ADDR(`LEN') ; $E3...227...LEN
|
|
ASM_ADDR(`STR') ; $E4...228...STR$
|
|
ASM_ADDR(`VAL') ; $E5...229...VAL
|
|
ASM_ADDR(`ASC') ; $E6...230...ASC
|
|
ASM_ADDR(`CHRSTR') ; $E7...231...CHR$
|
|
ASM_ADDR(`LEFTSTR') ; $E8...232...LEFT$
|
|
ASM_ADDR(`RIGHTSTR') ; $E9...233...RIGHT$
|
|
ASM_ADDR(`MIDSTR') ; $EA...234...MID$
|
|
; --------------------------------
|
|
; MATH OPERATOR BRANCH TABLE
|
|
;
|
|
; ONE-BYTE PRECEDENCE CODE
|
|
; TWO-BYTE ADDRESS
|
|
; --------------------------------
|
|
P_OR = $46 ; "OR" IS LOWEST PRECEDENCE
|
|
P_AND = $50 ;
|
|
P_REL = $64 ; RELATIONAL OPERATORS
|
|
P_ADD = $79 ; BINARY + AND -
|
|
P_MUL = $7B ; * AND /
|
|
P_PWR = $7D ; EXPONENTIATION
|
|
P_NEQ = $7F ; UNARY - AND COMPARISON =
|
|
; --------------------------------
|
|
MATHTBL ASM_DATA(`P_ADD')
|
|
ASM_ADDR(`FADDT-1') ; $C8...200...+
|
|
ASM_DATA(`P_ADD')
|
|
ASM_ADDR(`FSUBT-1') ; $C9...201...-
|
|
ASM_DATA(`P_MUL')
|
|
ASM_ADDR(`FMULTT-1') ; $CA...202...*
|
|
ASM_DATA(`P_MUL')
|
|
ASM_ADDR(`FDIVT-1') ; $CB...203.../
|
|
ASM_DATA(`P_PWR')
|
|
ASM_ADDR(`FPWRT-1') ; $CC...204...^
|
|
ASM_DATA(`P_AND')
|
|
ASM_ADDR(`ANDOP-1') ; $CD...205...AND
|
|
ASM_DATA(`P_OR')
|
|
ASM_ADDR(`OR-1') ; $CE...206...OR
|
|
M_NEG ASM_DATA(`P_NEQ')
|
|
ASM_ADDR(`NEGOP-1') ; $CF...207...>
|
|
MEQUU ASM_DATA(`P_NEQ')
|
|
ASM_ADDR(`EQUOP-1') ; $D0...208...=
|
|
M_REL ASM_DATA(`P_REL')
|
|
ASM_ADDR(`RELOPS-1') ; $D1...209...<
|
|
|
|
; --------------------------------
|
|
; TOKEN NAME TABLE
|
|
; --------------------------------
|
|
;
|
|
|
|
TOKEN_NAME_TABLE LHASCII(`END') ; $80...128
|
|
LHASCII(`FOR') ; $81...129
|
|
LHASCII(`NEXT') ; $82...130
|
|
LHASCII(`DATA') ; $83...131
|
|
LHASCII(`INPUT') ; $84...132
|
|
LHASCII(`DEL') ; $85...133
|
|
LHASCII(`DIM') ; $86...134
|
|
LHASCII(`READ') ; $87...135
|
|
LHASCII(`GR') ; $88...136
|
|
LHASCII(`TEXT') ; $89...137
|
|
LHASCII(`PR#') ; $8A...138
|
|
LHASCII(`IN#') ; $8B...139
|
|
LHASCII(`CALL') ; $8C...140
|
|
LHASCII(`PLOT') ; $8D...141
|
|
LHASCII(`HLIN') ; $8E...142
|
|
LHASCII(`VLIN') ; $8F...143
|
|
LHASCII(`HGR2') ; $90...144
|
|
LHASCII(`HGR') ; $91...145
|
|
LHASCII(`HCOLOR=') ; $92...146
|
|
LHASCII(`HPLOT') ; $93...147
|
|
LHASCII(`DRAW') ; $94...148
|
|
LHASCII(`XDRAW') ; $95...149
|
|
LHASCII(`HTAB') ; $96...150
|
|
LHASCII(`HOME') ; $97...151
|
|
LHASCII(`ROT=') ; $98...152
|
|
LHASCII(`SCALE=') ; $99...153
|
|
LHASCII(`SHLOAD') ; $9A...154
|
|
LHASCII(`TRACE') ; $9B...155
|
|
LHASCII(`NOTRACE') ; $9C...156
|
|
LHASCII(`NORMAL') ; $9D...157
|
|
LHASCII(`INVERSE') ; $9E...158
|
|
LHASCII(`FLASH') ; $9F...159
|
|
LHASCII(`COLOR=') ; $A0...160
|
|
LHASCII(`POP') ; $A1...161
|
|
LHASCII(`VTAB') ; $A2...162
|
|
LHASCII(`HIMEM:') ; $A3...163
|
|
LHASCII(`LOMEM:') ; $A4...164
|
|
LHASCII(`ONERR') ; $A5...165
|
|
LHASCII(`RESUME') ; $A6...166
|
|
LHASCII(`RECALL') ; $A7...167
|
|
LHASCII(`STORE') ; $A8...168
|
|
LHASCII(`SPEED=') ; $A9...169
|
|
LHASCII(`LET') ; $AA...170
|
|
LHASCII(`GOTO') ; $AB...171
|
|
LHASCII(`RUN') ; $AC...172
|
|
LHASCII(`IF') ; $AD...173
|
|
LHASCII(`RESTORE') ; $AE...174
|
|
LHASCII(`&') ; $AF...175
|
|
LHASCII(`GOSUB') ; $B0...176
|
|
LHASCII(`RETURN') ; $B1...177
|
|
LHASCII(`REM') ; $B2...178
|
|
LHASCII(`STOP') ; $B3...179
|
|
LHASCII(`ON') ; $B4...180
|
|
LHASCII(`WAIT') ; $B5...181
|
|
LHASCII(`LOAD') ; $B6...182
|
|
LHASCII(`SAVE') ; $B7...183
|
|
LHASCII(`DEF') ; $B8...184
|
|
LHASCII(`POKE') ; $B9...185
|
|
LHASCII(`PRINT') ; $BA...186
|
|
LHASCII(`CONT') ; $BB...187
|
|
LHASCII(`LIST') ; $BC...188
|
|
LHASCII(`CLEAR') ; $BD...189
|
|
LHASCII(`GET') ; $BE...190
|
|
LHASCII(`NEW') ; $BF...191
|
|
LOASCII(`TAB') ; $C0...192
|
|
ASM_DATA($A8)
|
|
LHASCII(`TO') ; $C1...193
|
|
LHASCII(`FN') ; $C2...194
|
|
LOASCII(`SPC') ; $C3...195
|
|
ASM_DATA($A8)
|
|
LHASCII(`THEN') ; $C4...196
|
|
LHASCII(`AT') ; $C5...197
|
|
LHASCII(`NOT') ; $C6...198
|
|
LHASCII(`STEP') ; $C7...199
|
|
LHASCII(`+') ; $C8...200
|
|
LHASCII(`-') ; $C9...201
|
|
LHASCII(`*') ; $CA...202
|
|
LHASCII(`/') ; $CB...203
|
|
ASM_DATA($DE)
|
|
; LHASCII(`^') ; $CC...204
|
|
LHASCII(`AND') ; $CD...205
|
|
LHASCII(`OR') ; $CE...206
|
|
LHASCII(`>') ; $CF...207
|
|
LHASCII(`=') ; $D0...208
|
|
LHASCII(`<') ; $D1...209
|
|
LHASCII(`SGN') ; $D2...210
|
|
LHASCII(`INT') ; $D3...211
|
|
LHASCII(`ABS') ; $D4...212
|
|
LHASCII(`USR') ; $D5...213
|
|
LHASCII(`FRE') ; $D6...214
|
|
LOASCII(`SCRN') ; $D7...215
|
|
ASM_DATA($A8)
|
|
LHASCII(`PDL') ; $D8...216
|
|
LHASCII(`POS') ; $D9...217
|
|
LHASCII(`SQR') ; $DA...218
|
|
LHASCII(`RND') ; $DB...219
|
|
LHASCII(`LOG') ; $DC...220
|
|
LHASCII(`EXP') ; $DD...221
|
|
LHASCII(`COS') ; $DE...222
|
|
LHASCII(`SIN') ; $DF...223
|
|
LHASCII(`TAN') ; $E0...224
|
|
LHASCII(`ATN') ; $E1...225
|
|
LHASCII(`PEEK') ; $E2...226
|
|
LHASCII(`LEN') ; $E3...227
|
|
LHASCII(`STR$') ; $E4...228
|
|
LHASCII(`VAL') ; $E5...229
|
|
LHASCII(`ASC') ; $E6...230
|
|
LHASCII(`CHR$') ; $E7...231
|
|
LHASCII(`LEFT$') ; $E8...232
|
|
LHASCII(`RIGHT$') ; $E9...233
|
|
LHASCII(`MID$') ; $EA...234
|
|
|
|
ASM_DATA(0) ; END OF TOKEN NAME TABLE
|
|
; --------------------------------
|
|
; --------------------------------
|
|
; ERROR MESSAGES
|
|
; --------------------------------
|
|
ERROR_MESSAGES
|
|
ERR_NOFOR = *-ERROR_MESSAGES
|
|
LHASCII(`NEXT WITHOUT FOR')
|
|
ERR_SYNTAX = *-ERROR_MESSAGES
|
|
LHASCII(`SYNTAX')
|
|
ERR_NOGOSUB = *-ERROR_MESSAGES
|
|
LHASCII(`RETURN WITHOUT GOSUB')
|
|
ERR_NODATA = *-ERROR_MESSAGES
|
|
LHASCII(`OUT OF DATA')
|
|
ERR_ILLQTY = *-ERROR_MESSAGES
|
|
LHASCII(`ILLEGAL QUANTITY')
|
|
ERR_OVERFLOW = *-ERROR_MESSAGES
|
|
LHASCII(`OVERFLOW')
|
|
ERR_MEMFULL = *-ERROR_MESSAGES
|
|
LHASCII(`OUT OF MEMORY')
|
|
ERR_UNDEFSTAT = *-ERROR_MESSAGES
|
|
LOASCII(`UNDEF')
|
|
ASM_DATA($27)
|
|
LHASCII(`D STATEMENT')
|
|
ERR_BADSUBS = *-ERROR_MESSAGES
|
|
LHASCII(`BAD SUBSCRIPT')
|
|
ERR_REDIMD = *-ERROR_MESSAGES
|
|
LOASCII(`REDIM')
|
|
ASM_DATA($27)
|
|
LHASCII(`D ARRAY')
|
|
ERR_ZERODIV = *-ERROR_MESSAGES
|
|
LHASCII(`DIVISION BY ZERO')
|
|
ERR_ILLDIR = *-ERROR_MESSAGES
|
|
LHASCII(`ILLEGAL DIRECT')
|
|
ERR_BADTYPE = *-ERROR_MESSAGES
|
|
LHASCII(`TYPE MISMATCH')
|
|
ERR_STRLONG = *-ERROR_MESSAGES
|
|
LHASCII(`STRING TOO LONG')
|
|
ERR_FRMCPX = *-ERROR_MESSAGES
|
|
LHASCII(`FORMULA TOO COMPLEX')
|
|
ERR_CANTCONT = *-ERROR_MESSAGES
|
|
LOASCII(`CAN')
|
|
ASM_DATA($27)
|
|
LHASCII(`T CONTINUE')
|
|
ERR_UNDEFFUNC = *-ERROR_MESSAGES
|
|
LOASCII(`UNDEF')
|
|
ASM_DATA($27)
|
|
LHASCII(`D FUNCTION')
|
|
; --------------------------------
|
|
|
|
QT_ERROR LOASCII(` ERROR')
|
|
ASM_DATA($07,0)
|
|
|
|
QT_IN LOASCII(` IN ')
|
|
ASM_DATA(0)
|
|
|
|
QT_BREAK ASM_DATA($0D)
|
|
LOASCII(`BREAK')
|
|
ASM_DATA($07,0)
|
|
; --------------------------------
|
|
; CALLED BY "NEXT" AND "FOR" TO SCAN THROUGH
|
|
; THE STACK FOR A FRAME WITH THE SAME VARIABLE.
|
|
;
|
|
; (FORPNT) = ADDRESS OF VARIABLE IF "FOR" OR "NEXT"
|
|
; = $XXFF IF CALLED FROM "RETURN"
|
|
; <<< BUG: SHOULD BE $FFXX >>>
|
|
;
|
|
; RETURNS .NE. IF VARIABLE NOT FOUND,
|
|
; (X) = STACK PNTR AFTER SKIPPING ALL FRAMES
|
|
;
|
|
; EQU. IF FOUND
|
|
; (X) = STACK PNTR OF FRAME FOUND
|
|
; --------------------------------
|
|
GTFORPNT
|
|
TSX
|
|
INX
|
|
INX
|
|
INX
|
|
INX
|
|
L_GTFORPNT_1 LDA STACK+1,X ; "FOR" FRAME HERE?
|
|
CMP #TOKEN_FOR ;
|
|
BNE L_GTFORPNT_4 ; NO
|
|
LDA FORPNT+1 ; YES -- "NEXT" WITH NO VARIABLE?
|
|
BNE L_GTFORPNT_2 ; NO, VARIABLE SPECIFIED
|
|
LDA STACK+2,X ; YES, SO USE THIS FRAME
|
|
STA FORPNT ;
|
|
LDA STACK+3,X ;
|
|
STA FORPNT+1 ;
|
|
L_GTFORPNT_2 CMP STACK+3,X ; IS VARIABLE IN THIS FRAME?
|
|
BNE L_GTFORPNT_3 ; NO
|
|
LDA FORPNT ; LOOK AT 2ND BYTE TOO
|
|
CMP STACK+2,X ; SAME VARIABLE?
|
|
BEQ L_GTFORPNT_4 ; YES
|
|
L_GTFORPNT_3 TXA ; NO, SO TRY NEXT FRAME (IF ANY)
|
|
CLC ; 18 BYTES PER FRAME
|
|
ADC #18 ;
|
|
TAX
|
|
BNE L_GTFORPNT_1 ; ...ALWAYS?
|
|
L_GTFORPNT_4 RTS
|
|
; --------------------------------
|
|
; MOVE BLOCK OF MEMORY UP
|
|
;
|
|
; ON ENTRY:
|
|
; (Y,A) = (HIGHDS) = DESTINATION END+1
|
|
; (LOWTR) = LOWEST ADDRESS OF SOURCE
|
|
; (HIGHTR) = HIGHEST SOURCE ADDRESS+1
|
|
; --------------------------------
|
|
BLTU JSR REASON ; BE SURE (Y,A) < FRETOP
|
|
STA STREND ; NEW TOP OF ARRAY STORAGE
|
|
STY STREND+1 ;
|
|
BLTU2 SEC ;
|
|
LDA HIGHTR ; COMPUTE # OF BYTES TO BE MOVED
|
|
SBC LOWTR ; (FROM LOWTR THRU HIGHTR-1)
|
|
STA INDEX ; PARTIAL PAGE AMOUNT
|
|
TAY ;
|
|
LDA HIGHTR+1 ;
|
|
SBC LOWTR+1 ;
|
|
TAX ; # OF WHOLE PAGES IN X-REG
|
|
INX ;
|
|
TYA ; # BYTES IN PARTIAL PAGE
|
|
BEQ L_BLTU2_4 ; NO PARTIAL PAGE
|
|
LDA HIGHTR ; BACK UP HIGHTR # BYTES IN PARTIAL PAGE
|
|
SEC ;
|
|
SBC INDEX ;
|
|
STA HIGHTR ;
|
|
BCS L_BLTU2_1 ;
|
|
DEC HIGHTR+1 ;
|
|
SEC ;
|
|
L_BLTU2_1 LDA HIGHDS ; BACK UP HIGHDS # BYTES IN PARTIAL PAGE
|
|
SBC INDEX ;
|
|
STA HIGHDS ;
|
|
BCS L_BLTU2_3 ;
|
|
DEC HIGHDS+1 ;
|
|
BCC L_BLTU2_3 ; ...ALWAYS
|
|
L_BLTU2_2 LDA (HIGHTR),Y ; MOVE THE BYTES
|
|
STA (HIGHDS),Y
|
|
L_BLTU2_3 DEY
|
|
BNE L_BLTU2_2 ; LOOP TO END OF THIS 256 BYTES
|
|
LDA (HIGHTR),Y ; MOVE ONE MORE BYTE
|
|
STA (HIGHDS),Y
|
|
L_BLTU2_4 DEC HIGHTR+1 ; DOWN TO NEXT BLOCK OF 256
|
|
DEC HIGHDS+1
|
|
DEX ; ANOTHER BLOCK OF 256 TO MOVE?
|
|
BNE L_BLTU2_3 ; YES
|
|
RTS ; NO, FINISHED
|
|
; --------------------------------
|
|
; CHECK IF ENOUGH ROOM LEFT ON STACK
|
|
; FOR "FOR", "GOSUB", OR EXPRESSION EVALUATION
|
|
; --------------------------------
|
|
CHKMEM ASL
|
|
ADC #54
|
|
BCS MEMERR ; ...MEM FULL ERR
|
|
STA INDEX
|
|
TSX
|
|
CPX INDEX
|
|
BCC MEMERR ; ...MEM FULL ERR
|
|
RTS
|
|
; --------------------------------
|
|
; CHECK IF ENOUGH ROOM BETWEEN ARRAYS AND STRINGS
|
|
; (Y,A) = ADDR ARRAYS NEED TO GROW TO
|
|
; --------------------------------
|
|
REASON CPY FRETOP+1 ; HIGH BYTE
|
|
BCC L_REASON_4 ; PLENTY OF ROOM
|
|
BNE L_REASON_1 ; NOT ENOUGH, TRY GARBAGE COLLECTION
|
|
CMP FRETOP ; LOW BYTE
|
|
BCC L_REASON_4 ; ENOUGH ROOM
|
|
; --------------------------------
|
|
L_REASON_1 PHA ; SAVE (Y,A), TEMP1, AND TEMP2
|
|
LDX #FAC-TEMP1-1
|
|
TYA
|
|
L_REASON_2 PHA
|
|
LDA TEMP1,X
|
|
DEX
|
|
BPL L_REASON_2
|
|
JSR GARBAG ; MAKE AS MUCH ROOM AS POSSIBLE
|
|
LDX #TEMP1+256-FAC+1 ; RESTORE TEMP1 AND TEMP2
|
|
L_REASON_3 PLA ; AND (Y,A)
|
|
STA FAC,X
|
|
INX
|
|
BMI L_REASON_3
|
|
PLA
|
|
TAY
|
|
PLA ; DID WE FIND ENOUGH ROOM?
|
|
CPY FRETOP+1 ; HIGH BYTE
|
|
BCC L_REASON_4 ; YES, AT LEAST A PAGE
|
|
BNE MEMERR ; NO, MEM FULL ERR
|
|
CMP FRETOP ; LOW BYTE
|
|
BCS MEMERR ; NO, MEM FULL ERR
|
|
L_REASON_4 RTS ; YES, RETURN
|
|
; --------------------------------
|
|
MEMERR LDX #ERR_MEMFULL
|
|
; --------------------------------
|
|
; HANDLE AN ERROR
|
|
;
|
|
; (X)=OFFSET IN ERROR MESSAGE TABLE
|
|
; (ERRFLG) > 128 IF "ON ERR" TURNED ON
|
|
; (CURLIN+1) = $FF IF IN DIRECT MODE
|
|
; --------------------------------
|
|
ERROR BIT ERRFLG ; "ON ERR" TURNED ON?
|
|
BPL L_ERROR_1 ; NO
|
|
JMP HANDLERR ; YES
|
|
L_ERROR_1 JSR CRDO ; PRINT <RETURN>
|
|
JSR OUTQUES ; PRINT "?"
|
|
L_ERROR_2 LDA ERROR_MESSAGES,X
|
|
PHA ; PRINT MESSAGE
|
|
JSR OUTDO
|
|
INX
|
|
PLA
|
|
BPL L_ERROR_2
|
|
JSR STKINI ; FIX STACK, ET AL
|
|
LDA #<QT_ERROR ; PRINT " ERROR" AND BELL
|
|
LDY #>QT_ERROR
|
|
; --------------------------------
|
|
; PRINT STRING AT (Y,A)
|
|
; PRINT CURRENT LINE # UNLESS IN DIRECT MODE
|
|
; FALL INTO WARM RESTART
|
|
; --------------------------------
|
|
PRINT_ERROR_LINNUM
|
|
JSR STROUT ; PRINT STRING AT (Y,A)
|
|
LDY CURLIN+1 ; RUNNING, OR DIRECT?
|
|
INY
|
|
BEQ RESTART ; WAS $FF, SO DIRECT MODE
|
|
JSR INPRT ; RUNNING, SO PRINT LINE NUMBER
|
|
; --------------------------------
|
|
; WARM RESTART ENTRY
|
|
;
|
|
; COME HERE FROM MONITOR BY CTL-C, 0G, 3D0G, OR E003G
|
|
; --------------------------------
|
|
RESTART
|
|
JSR CRDO ; PRINT <RETURN>
|
|
LDX #HICHAR(`]') ; PROMPT CHARACTER
|
|
JSR INLIN2 ; READ A LINE
|
|
STX TXTPTR ; SET UP CHRGET TO SCAN THE LINE
|
|
STY TXTPTR+1 ;
|
|
LSR ERRFLG ; CLEAR FLAG
|
|
JSR CHRGET ;
|
|
TAX ;
|
|
BEQ RESTART ; EMPTY LINE
|
|
LDX #$FF ; $FF IN HI-BYTE OF CURLIN MEANS
|
|
STX CURLIN+1 ; WE ARE IN DIRECT MODE
|
|
BCC NUMBERED_LINE ; CHRGET SAW DIGIT, NUMBERED LINE
|
|
JSR PARSE_INPUT_LINE ; NO NUMBER, SO PARSE IT
|
|
JMP TRACE_ ; AND TRY EXECUTING IT
|
|
; --------------------------------
|
|
; HANDLE NUMBERED LINE
|
|
; --------------------------------
|
|
NUMBERED_LINE
|
|
LDX PRGEND ; SQUASH VARIABLE TABLE
|
|
STX VARTAB
|
|
LDX PRGEND+1
|
|
STX VARTAB+1
|
|
JSR LINGET ; GET LINE #
|
|
JSR PARSE_INPUT_LINE ; AND PARSE THE INPUT LINE
|
|
STY EOL_PNTR ; SAVE INDEX TO INPUT BUFFER
|
|
JSR FNDLIN ; IS THIS LINE # ALREADY IN PROGRAM?
|
|
BCC PUT_NEW_LINE ; NO
|
|
LDY #1 ; YES, SO DELETE IT
|
|
LDA (LOWTR),Y ; LOWTR POINTS AT LINE
|
|
STA INDEX+1 ; GET HIGH BYTE OF FORWARD PNTR
|
|
LDA VARTAB
|
|
STA INDEX
|
|
LDA LOWTR+1
|
|
STA DEST+1
|
|
LDA LOWTR
|
|
DEY
|
|
SBC (LOWTR),Y
|
|
CLC
|
|
ADC VARTAB
|
|
STA VARTAB
|
|
STA DEST
|
|
LDA VARTAB+1
|
|
ADC #$FF
|
|
STA VARTAB+1
|
|
SBC LOWTR+1
|
|
TAX
|
|
SEC
|
|
LDA LOWTR
|
|
SBC VARTAB
|
|
TAY
|
|
BCS L_NUMBERED_LINE_1
|
|
INX
|
|
DEC DEST+1
|
|
L_NUMBERED_LINE_1 CLC
|
|
ADC INDEX
|
|
BCC L_NUMBERED_LINE_2
|
|
DEC INDEX+1
|
|
CLC
|
|
; --------------------------------
|
|
L_NUMBERED_LINE_2 LDA (INDEX),Y ; MOVE HIGHER LINES OF PROGRAM
|
|
STA (DEST),Y ; DOWN OVER THE DELETED LINE.
|
|
INY
|
|
BNE L_NUMBERED_LINE_2
|
|
INC INDEX+1
|
|
INC DEST+1
|
|
DEX
|
|
BNE L_NUMBERED_LINE_2
|
|
; --------------------------------
|
|
PUT_NEW_LINE
|
|
LDA INPUT_BUFFER ; ANY CHARACTERS AFTER LINE #?
|
|
BEQ FIX_LINKS ; NO, SO NOTHING TO INSERT.
|
|
LDA MEMSIZ ; YES, SO MAKE ROOM AND INSERT LINE
|
|
LDY MEMSIZ+1 ; WIPE STRING AREA CLEAN
|
|
STA FRETOP ;
|
|
STY FRETOP+1 ;
|
|
LDA VARTAB ; SET UP BLTU SUBROUTINE
|
|
STA HIGHTR ; INSERT NEW LINE.
|
|
ADC EOL_PNTR
|
|
STA HIGHDS
|
|
LDY VARTAB+1
|
|
STY HIGHTR+1
|
|
BCC L_PUT_NEW_LINE_1
|
|
INY
|
|
L_PUT_NEW_LINE_1 STY HIGHDS+1
|
|
JSR BLTU ; MAKE ROOM FOR THE LINE
|
|
LDA LINNUM ; PUT LINE NUMBER IN LINE IMAGE
|
|
LDY LINNUM+1
|
|
STA INPUT_BUFFER-2
|
|
STY INPUT_BUFFER-1
|
|
LDA STREND
|
|
LDY STREND+1
|
|
STA VARTAB
|
|
STY VARTAB+1
|
|
LDY EOL_PNTR
|
|
; ---COPY LINE INTO PROGRAM-------
|
|
L_PUT_NEW_LINE_2 LDA INPUT_BUFFER-5,Y
|
|
DEY
|
|
STA (LOWTR),Y
|
|
BNE L_PUT_NEW_LINE_2
|
|
; --------------------------------
|
|
; CLEAR ALL VARIABLES
|
|
; RE-ESTABLISH ALL FORWARD LINKS
|
|
; --------------------------------
|
|
FIX_LINKS
|
|
JSR SETPTRS ; CLEAR ALL VARIABLES
|
|
LDA TXTTAB ; POINT INDEX AT START OF PROGRAM
|
|
LDY TXTTAB+1
|
|
STA INDEX
|
|
STY INDEX+1
|
|
CLC
|
|
L_FIX_LINKS_1 LDY #1 ; HI-BYTE OF NEXT FORWARD PNTR
|
|
LDA (INDEX),Y ; END OF PROGRAM YET?
|
|
BNE L_FIX_LINKS_2 ; NO, KEEP GOING
|
|
LDA VARTAB ; YES
|
|
STA PRGEND
|
|
LDA VARTAB+1
|
|
STA PRGEND+1
|
|
JMP RESTART
|
|
L_FIX_LINKS_2 LDY #4 ; FIND END OF THIS LINE
|
|
L_FIX_LINKS_3 INY ; (NOTE MAXIMUM LENGTH < 256)
|
|
LDA (INDEX),Y ;
|
|
BNE L_FIX_LINKS_3 ;
|
|
INY ; COMPUTE ADDRESS OF NEXT LINE
|
|
TYA ;
|
|
ADC INDEX ;
|
|
TAX ;
|
|
LDY #0 ; STORE FORWARD PNTR IN THIS LINE
|
|
STA (INDEX),Y ;
|
|
LDA INDEX+1 ;
|
|
ADC #0 ; (NOTE: THIS CLEARS CARRY)
|
|
INY ;
|
|
STA (INDEX),Y ;
|
|
STX INDEX ;
|
|
STA INDEX+1 ;
|
|
BCC L_FIX_LINKS_1 ; ...ALWAYS
|
|
; --------------------------------
|
|
; --------------------------------
|
|
; READ A LINE, AND STRIP OFF SIGN BITS
|
|
; --------------------------------
|
|
INLIN LDX #$80 ; NULL PROMPT
|
|
INLIN2 STX MON_PROMPT
|
|
JSR MON_GETLN
|
|
CPX #239 ; MAXIMUM LINE LENGTH
|
|
BCC L_INLIN2_1
|
|
LDX #239 ; TRUNCATE AT 239 CHARS
|
|
L_INLIN2_1 LDA #0 ; MARK END OF LINE WITH $00 BYTE
|
|
STA INPUT_BUFFER,X
|
|
TXA
|
|
BEQ L_INLIN2_3 ; NULL INPUT LINE
|
|
L_INLIN2_2 LDA INPUT_BUFFER-1,X ; DROP SIGN BITS
|
|
AND #$7F
|
|
STA INPUT_BUFFER-1,X
|
|
DEX
|
|
BNE L_INLIN2_2
|
|
L_INLIN2_3 LDA #0 ; (Y,X) POINTS AT BUFFER-1
|
|
LDX #<(INPUT_BUFFER-1)
|
|
LDY #>(INPUT_BUFFER-1)
|
|
RTS
|
|
; --------------------------------
|
|
INCHR JSR MON_RDKEY ; *** OUGHT TO BE "BIT $C010" ***
|
|
AND #$7F
|
|
RTS
|
|
; --------------------------------
|
|
; TOKENIZE THE INPUT LINE
|
|
; --------------------------------
|
|
PARSE_INPUT_LINE
|
|
LDX TXTPTR ; INDEX INTO UNPARSED LINE
|
|
DEX ; PREPARE FOR INX AT "PARSE"
|
|
LDY #4 ; INDEX TO PARSED OUTPUT LINE
|
|
STY DATAFLG ; CLEAR SIGN-BIT OF DATAFLG
|
|
BIT LOCK ; IS THIS PROGRAM LOCKED?
|
|
BPL PARSE ; NO, GO AHEAD AND PARSE THE LINE
|
|
PLA ; YES, IGNORE INPUT AND "RUN"
|
|
PLA ; THE PROGRAM
|
|
JSR SETPTRS ; CLEAR ALL VARIABLES
|
|
JMP NEWSTT ; START RUNNING
|
|
; --------------------------------
|
|
PARSE INX ; NEXT INPUT CHARACTER
|
|
L_PARSE_1 LDA INPUT_BUFFER,X
|
|
BIT DATAFLG ; IN A "DATA" STATEMENT?
|
|
BVS L_PARSE_2 ; YES (DATAFLG = $49)
|
|
CMP #LOCHAR(` ') ; IGNORE BLANKS
|
|
BEQ PARSE ;
|
|
L_PARSE_2 STA ENDCHR ;
|
|
CMP #$22 ; START OF QUOTATION?
|
|
BEQ L_PARSE_13 ;
|
|
BVS L_PARSE_9 ; BRANCH IF IN "DATA" STATEMENT
|
|
CMP #LOCHAR(`?') ; SHORTHAND FOR "PRINT"?
|
|
BNE L_PARSE_3 ; NO
|
|
LDA #TOKEN_PRINT ; YES, REPLACE WITH "PRINT" TOKEN
|
|
BNE L_PARSE_9 ; ...ALWAYS
|
|
L_PARSE_3 CMP #LOCHAR(`0') ; IS IT A DIGIT, COLON, OR SEMI-COLON?
|
|
BCC L_PARSE_4 ; NO, PUNCTUATION !"#$%&'()*+,-./
|
|
CMP #LOCHAR(`;')+1
|
|
BCC L_PARSE_9 ; YES, NOT A TOKEN
|
|
; --------------------------------
|
|
; SEARCH TOKEN NAME TABLE FOR MATCH STARTING
|
|
; WITH CURRENT CHAR FROM INPUT LINE
|
|
; --------------------------------
|
|
L_PARSE_4 STY STRNG2 ; SAVE INDEX TO OUTPUT LINE
|
|
LDA #<(TOKEN_NAME_TABLE-$100)
|
|
STA FAC ; MAKE PNTR FOR SEARCH
|
|
LDA #>(TOKEN_NAME_TABLE-$100)
|
|
STA FAC+1
|
|
LDY #0 ; USE Y-REG WITH (FAC) TO ADDRESS TABLE
|
|
STY TKN_CNTR ; HOLDS CURRENT TOKEN-$80
|
|
DEY ; PREPARE FOR "INY" A FEW LINES DOWN
|
|
STX TXTPTR ; SAVE POSITION IN INPUT LINE
|
|
DEX ; PREPARE FOR "INX" A FEW LINES DOWN
|
|
L_PARSE_5 INY ; ADVANCE POINTER TO TOKEN TABLE
|
|
BNE L_PARSE_6 ; Y=Y+1 IS ENOUGH
|
|
INC FAC+1 ; ALSO NEED TO BUMP THE PAGE
|
|
L_PARSE_6 INX ; ADVANCE POINTER TO INPUT LINE
|
|
L_PARSE_7 LDA INPUT_BUFFER,X ; NEXT CHAR FROM INPUT LINE
|
|
CMP #LOCHAR(` ') ; THIS CHAR A BLANK?
|
|
BEQ L_PARSE_6 ; YES, IGNORE ALL BLANKS
|
|
SEC ; NO, COMPARE TO CHAR IN TABLE
|
|
SBC (FAC),Y ; SAME AS NEXT CHAR OF TOKEN NAME?
|
|
BEQ L_PARSE_5 ; YES, CONTINUE MATCHING
|
|
CMP #$80 ; MAYBE; WAS IT SAME EXCEPT FOR BIT 7?
|
|
BNE L_PARSE_14 ; NO, SKIP TO NEXT TOKEN
|
|
ORA TKN_CNTR ; YES, END OF TOKEN; GET TOKEN #
|
|
CMP #TOKENDB ; DID WE MATCH "AT"?
|
|
BNE L_PARSE_8 ; NO, SO NO AMBIGUITY
|
|
LDA INPUT_BUFFER+1,X ; "AT" COULD BE "ATN" OR "A TO"
|
|
CMP #LOCHAR(`N') ; "ATN" HAS PRECEDENCE OVER "AT"
|
|
BEQ L_PARSE_14 ; IT IS "ATN", FIND IT THE HARD WAY
|
|
CMP #LOCHAR(`O') ; "TO" HAS PRECEDENCE OVER "AT"
|
|
BEQ L_PARSE_14 ; IT IS "A TO", FIN IT THE HARD WAY
|
|
LDA #TOKENDB ; NOT "ATN" OR "A TO", SO USE "AT"
|
|
; --------------------------------
|
|
; STORE CHARACTER OR TOKEN IN OUTPUT LINE
|
|
; --------------------------------
|
|
L_PARSE_8 LDY STRNG2 ; GET INDEX TO OUTPUT LINE IN Y-REG
|
|
L_PARSE_9 INX ; ADVANCE INPUT INDEX
|
|
INY ; ADVANCE OUTPUT INDEX
|
|
STA INPUT_BUFFER-5,Y ; STORE CHAR OR TOKEN
|
|
LDA INPUT_BUFFER-5,Y ; TEST FOR EOL OR EOS
|
|
BEQ L_PARSE_17 ; END OF LINE
|
|
SEC ;
|
|
SBC #LOCHAR(`:') ; END OF STATEMENT?
|
|
BEQ L_PARSE_10 ; YES, CLEAR DATAFLG
|
|
CMP #TOKENDWTA+128-$BA ; "DATA" TOKEN?
|
|
BNE L_PARSE_11 ; NO, LEAVE DATAFLG ALONE
|
|
L_PARSE_10 STA DATAFLG ; DATAFLG = 0 OR $83-$3A = $49
|
|
L_PARSE_11 SEC ; IS IT A "REM" TOKEN?
|
|
SBC #TOKEN_REM+128-$BA
|
|
BNE L_PARSE_1 ; NO, CONTINUE PARSING LINE
|
|
STA ENDCHR ; YES, CLEAR LITERAL FLAG
|
|
; --------------------------------
|
|
; HANDLE LITERAL (BETWEEN QUOTES) OR REMARK,
|
|
; BY COPYING CHARS UP TO ENDCHR.
|
|
; --------------------------------
|
|
L_PARSE_12 LDA INPUT_BUFFER,X
|
|
BEQ L_PARSE_9 ; END OF LINE
|
|
CMP ENDCHR
|
|
BEQ L_PARSE_9 ; FOUND ENDCHR
|
|
L_PARSE_13 INY ; NEXT OUTPUT CHAR
|
|
STA INPUT_BUFFER-5,Y
|
|
INX ; NEXT INPUT CHAR
|
|
BNE L_PARSE_12 ; ...ALWAYS
|
|
; --------------------------------
|
|
; ADVANCE POINTER TO NEXT TOKEN NAME
|
|
; --------------------------------
|
|
L_PARSE_14 LDX TXTPTR ; GET POINTER TO INPUT LINE IN X-REG
|
|
INC TKN_CNTR ; BUMP (TOKEN # - $80)
|
|
L_PARSE_15 LDA (FAC),Y ; SCAN THROUGH TABLE FOR BIT7 = 1
|
|
INY ; NEXT TOKEN ONE BEYOND THAT
|
|
BNE L_PARSE_16 ; ...USUALLY ENOUGH TO BUMP Y-REG
|
|
INC FAC+1 ; NEXT SET OF 256 TOKEN CHARS
|
|
L_PARSE_16 ASL ; SEE IF SIGN BIT SET ON CHAR
|
|
BCC L_PARSE_15 ; NO, MORE IN THIS NAME
|
|
LDA (FAC),Y ; YES, AT NEXT NAME. END OF TABLE?
|
|
BNE L_PARSE_7 ; NO, NOT END OF TABLE
|
|
LDA INPUT_BUFFER,X ; YES, SO NOT A KEYWORD
|
|
BPL L_PARSE_8 ; ...ALWAYS, COPY CHAR AS IS
|
|
; ---END OF LINE------------------
|
|
L_PARSE_17 STA INPUT_BUFFER-3,Y ; STORE ANOTHER 00 ON END
|
|
DEC TXTPTR+1 ; SET TXTPTR = INPUT.BUFFER-1
|
|
LDA #<(INPUT_BUFFER-1)
|
|
STA TXTPTR
|
|
RTS
|
|
; --------------------------------
|
|
; SEARCH FOR LINE
|
|
;
|
|
; (LINNUM) = LINE # TO FIND
|
|
; IF NOT FOUND: CARRY = 0
|
|
; LOWTR POINTS AT NEXT LINE
|
|
; IF FOUND: CARRY = 1
|
|
; LOWTR POINTS AT LINE
|
|
; --------------------------------
|
|
FNDLIN LDA TXTTAB ; SEARCH FROM BEGINNING OF PROGRAM
|
|
LDX TXTTAB+1 ;
|
|
FL1 LDY #1 ; SEARCH FROM (X,A)
|
|
STA LOWTR ;
|
|
STX LOWTR+1 ;
|
|
LDA (LOWTR),Y ;
|
|
BEQ L_FL1_3 ; END OF PROGRAM, AND NOT FOUND
|
|
INY ;
|
|
INY ;
|
|
LDA LINNUM+1 ;
|
|
CMP (LOWTR),Y ;
|
|
BCC RTS_1 ; IF NOT FOUND
|
|
BEQ L_FL1_1 ;
|
|
DEY ;
|
|
BNE L_FL1_2 ;
|
|
L_FL1_1 LDA LINNUM ;
|
|
DEY ;
|
|
CMP (LOWTR),Y ;
|
|
BCC RTS_1 ; PAST LINE, NOT FOUND
|
|
BEQ RTS_1 ; IF FOUND
|
|
L_FL1_2 DEY ;
|
|
LDA (LOWTR),Y ;
|
|
TAX ;
|
|
DEY ;
|
|
LDA (LOWTR),Y ;
|
|
BCS FL1 ; ALWAYS
|
|
L_FL1_3 CLC ; RETURN CARRY = 0
|
|
RTS_1 RTS
|
|
; --------------------------------
|
|
; "NEW" STATEMENT
|
|
; --------------------------------
|
|
NEW BNE RTS_1 ; IGNORE IF MORE TO THE STATEMENT
|
|
SCRTCH LDA #0
|
|
STA LOCK
|
|
TAY
|
|
STA (TXTTAB),Y
|
|
INY
|
|
STA (TXTTAB),Y
|
|
LDA TXTTAB
|
|
ADC #2 ; (CARRY WASN'T CLEARED, SO "NEW" USUALLY
|
|
STA VARTAB ; ADDS 3, WHEREAS "FP" ADDS 2.)
|
|
STA PRGEND
|
|
LDA TXTTAB+1
|
|
ADC #0
|
|
STA VARTAB+1
|
|
STA PRGEND+1
|
|
; --------------------------------
|
|
SETPTRS
|
|
JSR STXTPT ; SET TXTPTR TO TXTTAB - 1
|
|
LDA #0 ; (THIS COULD HAVE BEEN ".HS 2C")
|
|
; --------------------------------
|
|
; "CLEAR" STATEMENT
|
|
; --------------------------------
|
|
CLEAR BNE RTS_2 ; IGNORE IF NOT AT END OF STATEMENT
|
|
CLEARC LDA MEMSIZ ; CLEAR STRING AREA
|
|
LDY MEMSIZ+1 ;
|
|
STA FRETOP ;
|
|
STY FRETOP+1 ;
|
|
LDA VARTAB ; CLEAR ARRAY AREA
|
|
LDY VARTAB+1 ;
|
|
STA ARYTAB ;
|
|
STY ARYTAB+1 ;
|
|
STA STREND ; LOW END OF FREE SPACE
|
|
STY STREND+1 ;
|
|
JSR RESTORE ; SET "DATA" POINTER TO BEGINNING
|
|
; --------------------------------
|
|
STKINI LDX #TEMPST
|
|
STX TEMPPT
|
|
PLA ; SAVE RETURN ADDRESS
|
|
TAY ;
|
|
PLA ;
|
|
LDX #$F8 ; START STACK AT $F8,
|
|
TXS ; LEAVING ROOM FOR PARSING LINES
|
|
PHA ; RESTORE RETURN ADDRESS
|
|
TYA
|
|
PHA
|
|
LDA #0
|
|
STA OLDTEXT+1
|
|
STA SUBFLG
|
|
RTS_2 RTS
|
|
; --------------------------------
|
|
; SET TXTPTR TO BEGINNING OF PROGRAM
|
|
; --------------------------------
|
|
STXTPT CLC ; TXTPTR = TXTTAB - 1
|
|
LDA TXTTAB
|
|
ADC #$FF
|
|
STA TXTPTR
|
|
LDA TXTTAB+1
|
|
ADC #$FF
|
|
STA TXTPTR+1
|
|
RTS
|
|
; --------------------------------
|
|
; "LIST" STATEMENT
|
|
; --------------------------------
|
|
LIST BCC L_LIST_1 ; NO LINE # SPECIFIED
|
|
BEQ L_LIST_1 ; ---DITTO---
|
|
CMP #TOKEN_MINUS ; IF DASH OR COMMA, START AT LINE 0
|
|
BEQ L_LIST_1 ; IS IS A DASH
|
|
CMP #LOCHAR(`,') ; COMMA?
|
|
BNE RTS_2 ; NO, ERROR
|
|
L_LIST_1 JSR LINGET ; CONVERT LINE NUMBER IF ANY
|
|
JSR FNDLIN ; POINT LOWTR TO 1ST LINE
|
|
JSR CHRGOT ; RANGE SPECIFIED?
|
|
BEQ L_LIST_3 ; NO
|
|
CMP #TOKEN_MINUS
|
|
BEQ L_LIST_2
|
|
CMP #LOCHAR(`,')
|
|
BNE RTS_1
|
|
L_LIST_2 JSR CHRGET ; GET NEXT CHAR
|
|
JSR LINGET ; CONVERT SECOND LINE #
|
|
BNE RTS_2 ; BRANCH IF SYNTAX ERR
|
|
L_LIST_3 PLA ; POP RETURN ADRESS
|
|
PLA ; (GET BACK BY "JMP NEWSTT")
|
|
LDA LINNUM ; IF NO SECOND NUMBER, USE $FFFF
|
|
ORA LINNUM+1 ;
|
|
BNE LIST_0 ; THERE WAS A SECOND NUMBER
|
|
LDA #$FF ; MAX END RANGE
|
|
STA LINNUM ;
|
|
STA LINNUM+1 ;
|
|
LIST_0 LDY #1 ;
|
|
LDA (LOWTR),Y ; HIGH BYTE OF LINK
|
|
BEQ LIST_3 ; END OF PROGRAM
|
|
JSR ISCNTC ; CHECK IF CONTROL-C HAS BEEN TYPED
|
|
JSR CRDO ; NO, PRINT <RETURN>
|
|
INY ;
|
|
LDA (LOWTR),Y ; GET LINE #, COMPARE WITH END RANGE
|
|
TAX ;
|
|
INY ;
|
|
LDA (LOWTR),Y ;
|
|
CMP LINNUM+1 ;
|
|
BNE L_LIST_0_5 ;
|
|
CPX LINNUM ;
|
|
BEQ L_LIST_0_6 ; ON LAST LINE OF RANGE
|
|
L_LIST_0_5 BCS LIST_3 ; FINISHED THE RANGE
|
|
; ---LIST ONE LINE----------------
|
|
L_LIST_0_6 STY FORPNT ;
|
|
JSR LINPRT ; PRINT LINE # FROM X,A
|
|
LDA #LOCHAR(` ') ; PRINT SPACE AFTER LINE #
|
|
LIST_1 LDY FORPNT ;
|
|
AND #$7F ;
|
|
LIST_2 JSR OUTDO ;
|
|
LDA MON_CH ; IF PAST COLUMN 33, START A NEW LINE
|
|
CMP #33 ;
|
|
BCC L_LIST_2_1 ; < 33
|
|
JSR CRDO ; PRINT <RETURN>
|
|
LDA #5 ; AND TAB OVER 5
|
|
STA MON_CH ;
|
|
L_LIST_2_1 INY ;
|
|
LDA (LOWTR),Y ;
|
|
BNE LIST_4 ; NOT END OF LINE YET
|
|
TAY ; END OF LINE
|
|
LDA (LOWTR),Y ; GET LINK TO NEXT LINE
|
|
TAX ;
|
|
INY ;
|
|
LDA (LOWTR),Y ;
|
|
STX LOWTR ; POINT TO NEXT LINE
|
|
STA LOWTR+1 ;
|
|
BNE LIST_0 ; BRANCH IF NOT END OF PROGRAM
|
|
LIST_3 LDA #$0D ; PRINT <RETURN>
|
|
JSR OUTDO ;
|
|
JMP NEWSTT ; TO NEXT STATEMENT
|
|
; --------------------------------
|
|
GETCHR INY ; PICK UP CHAR FROM TABLE
|
|
BNE L_GETCHR_1 ;
|
|
INC FAC+1 ;
|
|
L_GETCHR_1 LDA (FAC),Y ;
|
|
RTS ;
|
|
; --------------------------------
|
|
LIST_4 BPL LIST_2 ; BRANCH IF NOT A TOKEN
|
|
SEC ;
|
|
SBC #$7F ; CONVERT TOKEN TO INDEX
|
|
TAX ;
|
|
STY FORPNT ; SAVE LINE POINTER
|
|
LDY #<(TOKEN_NAME_TABLE-$100)
|
|
STY FAC ; POINT FAC TO TABLE
|
|
LDY #>(TOKEN_NAME_TABLE-$100)
|
|
STY FAC+1
|
|
LDY #$FF
|
|
L_LIST_4_1 DEX ; SKIP KEYWORDS UNTIL REACH THIS ONE
|
|
BEQ L_LIST_4_3 ;
|
|
L_LIST_4_2 JSR GETCHR ; BUMP Y, GET CHAR FROM TABLE
|
|
BPL L_LIST_4_2 ; NOT AT END OF KEYWORD YET
|
|
BMI L_LIST_4_1 ; END OF KEYWORD, ALWAYS BRANCHES
|
|
L_LIST_4_3 LDA #LOCHAR(` ') ; FOUND THE RIGHT KEYWORD
|
|
JSR OUTDO ; PRINT LEADING SPACE
|
|
L_LIST_4_4 JSR GETCHR ; PRINT THE KEYWORD
|
|
BMI L_LIST_4_5 ; LAST CHAR OF KEYWORD
|
|
JSR OUTDO ;
|
|
BNE L_LIST_4_4 ; ...ALWAYS
|
|
L_LIST_4_5 JSR OUTDO ; PRINT LAST CHAR OF KEYWORD
|
|
LDA #LOCHAR(` ') ; PRINT TRAILING SPACE
|
|
BNE LIST_1 ; ...ALWAYS, BACK TO ACTUAL LINE
|
|
; --------------------------------
|
|
; "FOR" STATEMENT
|
|
;
|
|
; FOR PUSHES 18 BYTES ON THE STACK:
|
|
; 2 -- TXTPTR
|
|
; 2 -- LINE NUMBER
|
|
; 5 -- INITIAL (CURRENT) FOR VARIABLE VALUE
|
|
; 1 -- STEP SIGN
|
|
; 5 -- STEP VALUE
|
|
; 2 -- ADDRESS OF FOR VARIABLE IN VARTAB
|
|
; 1 -- FOR TOKEN ($81)
|
|
; --------------------------------
|
|
FOR LDA #$80 ;
|
|
STA SUBFLG ; SUBSCRIPTS NOT ALLOWED
|
|
JSR LET ; DO <VAR> = <EXP>, STORE ADDR IN FORPNT
|
|
JSR GTFORPNT ; IS THIS FOR VARIABLE ACTIVE?
|
|
BNE L_FOR_1 ; NO
|
|
TXA ; YES, CANCEL IT AND ENCLOSED LOOPS
|
|
ADC #15 ; CARRY=1, THIS ADDS 16
|
|
TAX ; X WAS ALREADY S+2
|
|
TXS ;
|
|
L_FOR_1 PLA ; POP RETURN ADDRESS TOO
|
|
PLA ;
|
|
LDA #9 ; BE CERTAIN ENOUGH ROOM IN STACK
|
|
JSR CHKMEM ;
|
|
JSR DATAN ; SCAN AHEAD TO NEXT STATEMENT
|
|
CLC ; PUSH STATEMENT ADDRESS ON STACK
|
|
TYA ;
|
|
ADC TXTPTR ;
|
|
PHA ;
|
|
LDA TXTPTR+1 ;
|
|
ADC #0 ;
|
|
PHA ;
|
|
LDA CURLIN+1 ; PUSH LINE NUMBER ON STACK
|
|
PHA ;
|
|
LDA CURLIN ;
|
|
PHA ;
|
|
LDA #TOKEN_TO ;
|
|
JSR SYNCHR ; REQUIRE "TO"
|
|
JSR CHKNUM ; <VAR> = <EXP> MUST BE NUMERIC
|
|
JSR FRMNUM ; GET FINAL VALUE, MUST BE NUMERIC
|
|
LDA FAC_SIGN ; PUT SIGN INTO VALUE IN FAC
|
|
ORA #$7F ;
|
|
AND FAC+1 ;
|
|
STA FAC+1 ;
|
|
LDA #<STEP ; SET UP FOR RETURN
|
|
LDY #>STEP ; TO STEP
|
|
STA INDEX
|
|
STY INDEX+1
|
|
JMP FRM_STACK_3 ; RETURNS BY "JMP (INDEX)"
|
|
; --------------------------------
|
|
; "STEP" PHRASE OF "FOR" STATEMENT
|
|
; --------------------------------
|
|
STEP LDA #<CON_ONE ; STEP DEFAULT=1
|
|
LDY #>CON_ONE
|
|
JSR LOAD_FAC_FROM_YA
|
|
JSR CHRGOT
|
|
CMP #TOKEN_STEP
|
|
BNE L_STEP_1 ; USE DEFAULT VALUE OF 1.0
|
|
JSR CHRGET ; STEP SPECIFIED, GET IT
|
|
JSR FRMNUM
|
|
L_STEP_1 JSR SIGN
|
|
JSR FRM_STACK_2
|
|
LDA FORPNT+1
|
|
PHA
|
|
LDA FORPNT
|
|
PHA
|
|
LDA #TOKEN_FOR
|
|
PHA
|
|
; --------------------------------
|
|
; PERFORM NEXT STATEMENT
|
|
; --------------------------------
|
|
NEWSTT TSX ; REMEMBER THE STACK POSITION
|
|
STX REMSTK ;
|
|
JSR ISCNTC ; SEE IF CONTROL-C HAS BEEN TYPED
|
|
LDA TXTPTR ; NO, KEEP EXECUTING
|
|
LDY TXTPTR+1 ;
|
|
LDX CURLIN+1 ; =$FF IF IN DIRECT MODE
|
|
INX ; $FF TURNS INTO $00
|
|
BEQ L_NEWSTT_1 ; IN DIRECT MODE
|
|
STA OLDTEXT ; IN RUNNING MODE
|
|
STY OLDTEXT+1 ;
|
|
L_NEWSTT_1 LDY #0 ;
|
|
LDA (TXTPTR),Y ; END OF LINE YET?
|
|
BNE COLON_ ; NO
|
|
LDY #2 ; YES, SEE IF END OF PROGRAM
|
|
LDA (TXTPTR),Y ;
|
|
CLC ;
|
|
BEQ GOEND ; YES, END OF PROGRAM
|
|
INY ;
|
|
LDA (TXTPTR),Y ; GET LINE # OF NEXT LINE
|
|
STA CURLIN ;
|
|
INY ;
|
|
LDA (TXTPTR),Y ;
|
|
STA CURLIN+1 ;
|
|
TYA ; ADJUST TXTPTR TO START
|
|
ADC TXTPTR ; OF NEW LINE
|
|
STA TXTPTR
|
|
BCC L_NEWSTT_2
|
|
INC TXTPTR+1
|
|
L_NEWSTT_2
|
|
; --------------------------------
|
|
TRACE_ BIT TRCFLG ; IS TRACE ON?
|
|
BPL L_TRACE__1 ; NO
|
|
LDX CURLIN+1 ; YES, ARE WE RUNNING?
|
|
INX ;
|
|
BEQ L_TRACE__1 ; NOT RUNNING, SO DON'T TRACE
|
|
LDA #LOCHAR(`#') ; PRINT "#"
|
|
JSR OUTDO ;
|
|
LDX CURLIN ;
|
|
LDA CURLIN+1 ;
|
|
JSR LINPRT ; PRINT LINE NUMBER
|
|
JSR OUTSP ; PRINT TRAILING SPACE
|
|
L_TRACE__1 JSR CHRGET ; GET FIRST CHR OF STATEMENT
|
|
JSR EXECUTE_STATEMENT ; AND START PROCESSING
|
|
JMP NEWSTT ; BACK FOR MORE
|
|
; --------------------------------
|
|
GOEND BEQ END4
|
|
; --------------------------------
|
|
; EXECUTE A STATEMENT
|
|
;
|
|
; (A) IS FIRST CHAR OF STATEMENT
|
|
; CARRY IS SET
|
|
; --------------------------------
|
|
EXECUTE_STATEMENT
|
|
BEQ RTS_3 ; END OF LINE, NULL STATEMENT
|
|
EXECUTE_STATEMENT_1 ;
|
|
SBC #$80 ; FIRST CHAR A TOKEN?
|
|
BCC L_EXECUTE_STATEMENT_1_1 ; NOT TOKEN, MUST BE "LET"
|
|
CMP #$40 ; STATEMENT-TYPE TOKEN?
|
|
BCS SYNERR_1 ; NO, SYNTAX ERROR
|
|
ASL ; DOUBLE TO GET INDEX
|
|
TAY ; INTO ADDRESS TABLE
|
|
LDA TOKEN_ADDRESS_TABLE+1,Y
|
|
PHA ; PUT ADDRESS ON STACK
|
|
LDA TOKEN_ADDRESS_TABLE,Y
|
|
PHA
|
|
JMP CHRGET ; GET NEXT CHR & RTS TO ROUTINE
|
|
; --------------------------------
|
|
L_EXECUTE_STATEMENT_1_1 JMP LET ; MUST BE <VAR> = <EXP>
|
|
; --------------------------------
|
|
COLON_ CMP #LOCHAR(`:')
|
|
BEQ TRACE_
|
|
SYNERR_1 JMP SYNERR
|
|
; --------------------------------
|
|
; "RESTORE" STATEMENT
|
|
; --------------------------------
|
|
RESTORE
|
|
SEC ; SET DATPTR TO BEGINNING OF PROGRAM
|
|
LDA TXTTAB
|
|
SBC #1
|
|
LDY TXTTAB+1
|
|
BCS SETDA
|
|
DEY
|
|
; ---SET DATPTR TO Y,A------------
|
|
SETDA STA DATPTR
|
|
STY DATPTR+1
|
|
RTS_3 RTS
|
|
; --------------------------------
|
|
; SEE IF CONTROL-C TYPED
|
|
; --------------------------------
|
|
ISCNTC LDA KEYBOARD
|
|
CMP #$83
|
|
BEQ L_ISCNTC_1
|
|
RTS
|
|
L_ISCNTC_1 JSR INCHR ; <<< SHOULD BE "BIT $C010" >>>
|
|
CONTROL_C_TYPED
|
|
LDX #$FF ; CONTROL C ATTEMPTED
|
|
BIT ERRFLG ; "ON ERR" ENABLED?
|
|
BPL L_CONTROL_C_TYPED_2 ; NO
|
|
JMP HANDLERR ; YES, RETURN ERR CODE = 255
|
|
L_CONTROL_C_TYPED_2 CMP #3 ; SINCE IT IS CTRL-C, SET Z AND C BITS
|
|
; --------------------------------
|
|
; "STOP" STATEMENT
|
|
; --------------------------------
|
|
STOP BCS END2 ; CARRY=1 TO FORCE PRINTING "BREAK AT.."
|
|
; --------------------------------
|
|
; "END" STATEMENT
|
|
; --------------------------------
|
|
ENDX CLC ; CARRY=0 TO AVOID PRINTING MESSAGE
|
|
END2 BNE RTS_4 ; IF NOT END OF STATEMENT, DO NOTHING
|
|
LDA TXTPTR
|
|
LDY TXTPTR+1
|
|
LDX CURLIN+1
|
|
INX ; RUNNING?
|
|
BEQ L_END2_1 ; NO, DIRECT MODE
|
|
STA OLDTEXT
|
|
STY OLDTEXT+1
|
|
LDA CURLIN
|
|
LDY CURLIN+1
|
|
STA OLDLIN
|
|
STY OLDLIN+1
|
|
L_END2_1 PLA
|
|
PLA
|
|
END4 LDA #<QT_BREAK ; " BREAK" AND BELL
|
|
LDY #>QT_BREAK
|
|
BCC L_END4_1
|
|
JMP PRINT_ERROR_LINNUM
|
|
L_END4_1 JMP RESTART
|
|
; --------------------------------
|
|
; "CONT" COMMAND
|
|
; --------------------------------
|
|
CONT BNE RTS_4 ; IF NOT END OF STATEMENT, DO NOTHING
|
|
LDX #ERR_CANTCONT
|
|
LDY OLDTEXT+1 ; MEANINGFUL RE-ENTRY?
|
|
BNE L_CONT_1 ; YES
|
|
JMP ERROR ; NO
|
|
L_CONT_1 LDA OLDTEXT ; RESTORE TXTPTR
|
|
STA TXTPTR ;
|
|
STY TXTPTR+1 ;
|
|
LDA OLDLIN ; RESTORE LINE NUMBER
|
|
LDY OLDLIN+1
|
|
STA CURLIN
|
|
STY CURLIN+1
|
|
RTS_4 RTS
|
|
; --------------------------------
|
|
; "SAVE" COMMAND
|
|
; WRITES PROGRAM ON CASSETTE TAPE
|
|
; --------------------------------
|
|
SAVE SEC
|
|
LDA PRGEND ; COMPUTE PROGRAM LENGTH
|
|
SBC TXTTAB
|
|
STA LINNUM
|
|
LDA PRGEND+1
|
|
SBC TXTTAB+1
|
|
STA LINNUM+1
|
|
JSR VARTIO ; SET UP TO WRITE 3 BYTE HEADER
|
|
JSR MON_WRITE ; WRITE 'EM
|
|
JSR PROGIO ; SET UP TO WRITE THE PROGRAM
|
|
JMP MON_WRITE ; WRITE IT
|
|
; --------------------------------
|
|
; "LOAD" COMMAND
|
|
; READS A PROGRAM FROM CASSETTE TAPE
|
|
; --------------------------------
|
|
LOAD JSR VARTIO ; SET UP TO READ 3 BYTE HEADER
|
|
JSR MON_READ ; READ LENGTH, LOCK BYTE
|
|
CLC ;
|
|
LDA TXTTAB ; COMPUTE END ADDRESS
|
|
ADC LINNUM ;
|
|
STA VARTAB ;
|
|
LDA TXTTAB+1 ;
|
|
ADC LINNUM+1 ;
|
|
STA VARTAB+1 ;
|
|
LDA TEMPPT ; LOCK BYTE
|
|
STA LOCK ;
|
|
JSR PROGIO ; SET UP TO READ PROGRAM
|
|
JSR MON_READ ; READ IT
|
|
BIT LOCK ; IF LOCKED, START RUNNING NOW
|
|
BPL L_LOAD_1 ; NOT LOCKED
|
|
JMP SETPTRS ; LOCKED, START RUNNING
|
|
L_LOAD_1 JMP FIX_LINKS ; JUST FIX FORWARD POINTERS
|
|
; --------------------------------
|
|
VARTIO LDA #LINNUM ; SET UP TO READ/WRITE 3 BYTE HEADER
|
|
LDY #0
|
|
STA MON_A1L
|
|
STY MON_A1H
|
|
LDA #TEMPPT
|
|
STA MON_A2L
|
|
STY MON_A2H
|
|
STY LOCK
|
|
RTS
|
|
; --------------------------------
|
|
PROGIO LDA TXTTAB ; SET UP TO READ/WRITE PROGRAM
|
|
LDY TXTTAB+1
|
|
STA MON_A1L
|
|
STY MON_A1H
|
|
LDA VARTAB
|
|
LDY VARTAB+1
|
|
STA MON_A2L
|
|
STY MON_A2H
|
|
RTS
|
|
; --------------------------------
|
|
; --------------------------------
|
|
; "RUN" COMMAND
|
|
; --------------------------------
|
|
RUN PHP ; SAVE STATUS WHILE SUBTRACTING
|
|
DEC CURLIN+1 ; IF WAS $FF (MEANING DIRECT MODE)
|
|
; MAKE IT "RUNNING MODE"
|
|
PLP ; GET STATUS AGAIN (FROM CHRGET)
|
|
BNE L_RUN_1 ; PROBABLY A LINE NUMBER
|
|
JMP SETPTRS ; START AT BEGINNING OF PROGRAM
|
|
L_RUN_1 JSR CLEARC ; CLEAR VARIABLES
|
|
JMP GO_TO_LINE ; JOIN GOSUB STATEMENT
|
|
; --------------------------------
|
|
; "GOSUB" STATEMENT
|
|
;
|
|
; LEAVES 7 BYTES ON STACK:
|
|
; 2 -- RETURN ADDRESS (NEWSTT)
|
|
; 2 -- TXTPTR
|
|
; 2 -- LINE #
|
|
; 1 -- GOSUB TOKEN ($B0)
|
|
; --------------------------------
|
|
GOSUB LDA #3 ; BE SURE ENOUGH ROOM ON STACK
|
|
JSR CHKMEM
|
|
LDA TXTPTR+1
|
|
PHA
|
|
LDA TXTPTR
|
|
PHA
|
|
LDA CURLIN+1
|
|
PHA
|
|
LDA CURLIN
|
|
PHA
|
|
LDA #TOKEN_GOSUB
|
|
PHA
|
|
GO_TO_LINE
|
|
JSR CHRGOT
|
|
JSR GOTO
|
|
JMP NEWSTT
|
|
; --------------------------------
|
|
; "GOTO" STATEMENT
|
|
; ALSO USED BY "RUN" AND "GOSUB"
|
|
; --------------------------------
|
|
GOTO JSR LINGET ; GET GOTO LINE
|
|
JSR REMN ; POINT Y TO EOL
|
|
LDA CURLIN+1 ; IS CURRENT PAGE < GOTO PAGE?
|
|
CMP LINNUM+1 ;
|
|
BCS L_GOTO_1 ; SEARCH FROM PROG START IF NOT
|
|
TYA ; OTHERWISE SEARCH FROM NEXT LINE
|
|
SEC ;
|
|
ADC TXTPTR ;
|
|
LDX TXTPTR+1 ;
|
|
BCC L_GOTO_2 ;
|
|
INX ;
|
|
BCS L_GOTO_2 ;
|
|
L_GOTO_1 LDA TXTTAB ; GET PROGRAM BEGINNING
|
|
LDX TXTTAB+1 ;
|
|
L_GOTO_2 JSR FL1 ; SEARCH FOR GOTO LINE
|
|
BCC UNDERR ; ERROR IF NOT THERE
|
|
LDA LOWTR ; TXTPTR = START OF THE DESTINATION LINE
|
|
SBC #1 ;
|
|
STA TXTPTR ;
|
|
LDA LOWTR+1 ;
|
|
SBC #0 ;
|
|
STA TXTPTR+1 ;
|
|
RTS_5 RTS ; RETURN TO NEWSTT OR GOSUB
|
|
; --------------------------------
|
|
; "POP" AND "RETURN" STATEMENTS
|
|
; --------------------------------
|
|
POP BNE RTS_5
|
|
LDA #$FF
|
|
STA FORPNT ; <<< BUG: SHOULD BE FORPNT+1 >>>
|
|
; <<< SEE "ALL ABOUT APPLESOFT", PAGES 100,101 >>>
|
|
JSR GTFORPNT ; TO CANCEL FOR/NEXT IN SUB
|
|
TXS
|
|
CMP #TOKEN_GOSUB ; LAST GOSUB FOUND?
|
|
BEQ RETURN
|
|
LDX #ERR_NOGOSUB
|
|
ASM_DATA($2C) ; FAKE
|
|
UNDERR LDX #ERR_UNDEFSTAT
|
|
JMP ERROR
|
|
; --------------------------------
|
|
SYNERR_2 JMP SYNERR
|
|
; --------------------------------
|
|
RETURN PLA ; DISCARD GOSUB TOKEN
|
|
PLA
|
|
CPY #<(TOKEN_POP*2)
|
|
BEQ PULL3 ; BRANCH IF A POP
|
|
STA CURLIN ; PULL LINE #
|
|
PLA
|
|
STA CURLIN+1
|
|
PLA
|
|
STA TXTPTR ; PULL TXTPTR
|
|
PLA
|
|
STA TXTPTR+1
|
|
; --------------------------------
|
|
; "DATA" STATEMENT
|
|
; EXECUTED BY SKIPPING TO NEXT COLON OR EOL
|
|
; --------------------------------
|
|
DATA JSR DATAN ; MOVE TO NEXT STATEMENT
|
|
; --------------------------------
|
|
; ADD (Y) TO TXTPTR
|
|
; --------------------------------
|
|
ADDON TYA
|
|
CLC
|
|
ADC TXTPTR
|
|
STA TXTPTR
|
|
BCC L_ADDON_1
|
|
INC TXTPTR+1
|
|
L_ADDON_1
|
|
RTS_6 RTS
|
|
; --------------------------------
|
|
; SCAN AHEAD TO NEXT ":" OR EOL
|
|
; --------------------------------
|
|
DATAN LDX #LOCHAR(`:') ; GET OFFSET IN Y TO EOL OR ":"
|
|
ASM_DATA($2C) ; FAKE
|
|
; --------------------------------
|
|
REMN LDX #0 ; TO EOL ONLY
|
|
STX CHARAC
|
|
LDY #0
|
|
STY ENDCHR
|
|
L_REMN_1 LDA ENDCHR ; TRICK TO COUNT QUOTE PARITY
|
|
LDX CHARAC
|
|
STA CHARAC
|
|
STX ENDCHR
|
|
L_REMN_2 LDA (TXTPTR),Y
|
|
BEQ RTS_6 ; END OF LINE
|
|
CMP ENDCHR
|
|
BEQ RTS_6 ; COLON IF LOOKING FOR COLONS
|
|
INY
|
|
CMP #$22
|
|
BNE L_REMN_2
|
|
BEQ L_REMN_1 ; ...ALWAYS
|
|
; --------------------------------
|
|
PULL3 PLA
|
|
PLA
|
|
PLA
|
|
RTS
|
|
; --------------------------------
|
|
; "IF" STATEMENT
|
|
; --------------------------------
|
|
IF JSR FRMEVL
|
|
JSR CHRGOT
|
|
CMP #TOKEN_GOTO
|
|
BEQ L_IF_1
|
|
LDA #TOKEN_THEN
|
|
JSR SYNCHR
|
|
L_IF_1 LDA FAC ; CONDITION TRUE OR FALSE?
|
|
BNE IF_TRUE ; BRANCH IF TRUE
|
|
; --------------------------------
|
|
; "REM" STATEMENT, OR FALSE "IF" STATEMENT
|
|
; --------------------------------
|
|
REM JSR REMN ; SKIP REST OF LINE
|
|
BEQ ADDON ; ...ALWAYS
|
|
; --------------------------------
|
|
IF_TRUE
|
|
JSR CHRGOT ; COMMAND OR NUMBER?
|
|
BCS L_IF_TRUE_1 ; COMMAND
|
|
JMP GOTO ; NUMBER
|
|
L_IF_TRUE_1 JMP EXECUTE_STATEMENT
|
|
; --------------------------------
|
|
; "ON" STATEMENT
|
|
;
|
|
; ON <EXP> GOTO <LIST>
|
|
; ON <EXP> GOSUB <LIST>
|
|
; --------------------------------
|
|
ONGOTO JSR GETBYT ; EVALUATE <EXP>, AS BYTE IN FAC+4
|
|
PHA ; SAVE NEXT CHAR ON STACK
|
|
CMP #TOKEN_GOSUB
|
|
BEQ ON_2
|
|
ON_1 CMP #TOKEN_GOTO
|
|
BNE SYNERR_2
|
|
ON_2 DEC FAC+4 ; COUNTED TO RIGHT ONE YET?
|
|
BNE L_ON_2_3 ; NO, KEEP LOOKING
|
|
PLA ; YES, RETRIEVE CMD
|
|
JMP EXECUTE_STATEMENT_1 ; AND GO.
|
|
L_ON_2_3 JSR CHRGET ; PRIME CONVERT SUBROUTINE
|
|
JSR LINGET ; CONVERT LINE #
|
|
CMP #LOCHAR(`,') ; TERMINATE WITH COMMA?
|
|
BEQ ON_2 ; YES
|
|
PLA ; NO, END OF LIST, SO IGNORE
|
|
RTS_7 RTS
|
|
; --------------------------------
|
|
; CONVERT LINE NUMBER
|
|
; --------------------------------
|
|
LINGET LDX #0 ; ASC # TO HEX ADDRESS
|
|
STX LINNUM ; IN LINNUM.
|
|
STX LINNUM+1 ;
|
|
L_LINGET_1 BCS RTS_7 ; NOT A DIGIT
|
|
SBC #LOCHAR(`0')-1 ; CONVERT DIGIT TO BINARY
|
|
STA CHARAC ; SAVE THE DIGIT
|
|
LDA LINNUM+1 ; CHECK RANGE
|
|
STA INDEX ;
|
|
CMP #>6400 ; LINE # TOO LARGE?
|
|
BCS ON_1 ; YES, > 63999, GO INDIRECTLY TO
|
|
; "SYNTAX ERROR".
|
|
; <<<<<DANGEROUS CODE>>>>>
|
|
; NOTE THAT IF (A) = $AB ON THE LINE ABOVE,
|
|
; ON_1 WILL COMPARE = AND CAUSE A CATASTROPHIC
|
|
; JUMP TO $22D9 (FOR GOTO), OR OTHER LOCATIONS
|
|
; FOR OTHER CALLS TO LINGET.
|
|
;
|
|
; YOU CAN SEE THIS IS YOU FIRST PUT "BRK" IN $22D9,
|
|
; THEN TYPE "GO TO 437761".
|
|
;
|
|
; ANY VALUE FROM 437760 THROUGH 440319 WILL CAUSE
|
|
; THE PROBLEM. ($AB00 - $ABFF)
|
|
; <<<<<DANGEROUS CODE>>>>>
|
|
LDA LINNUM ; MULTIPLY BY TEN
|
|
ASL
|
|
ROL INDEX
|
|
ASL
|
|
ROL INDEX
|
|
ADC LINNUM
|
|
STA LINNUM
|
|
LDA INDEX
|
|
ADC LINNUM+1
|
|
STA LINNUM+1
|
|
ASL LINNUM
|
|
ROL LINNUM+1
|
|
LDA LINNUM
|
|
ADC CHARAC ; ADD DIGIT
|
|
STA LINNUM
|
|
BCC L_LINGET_2
|
|
INC LINNUM+1
|
|
L_LINGET_2 JSR CHRGET ; GET NEXT CHAR
|
|
JMP L_LINGET_1 ; MORE CONVERTING
|
|
; --------------------------------
|
|
; "LET" STATEMENT
|
|
;
|
|
; LET <VAR> = <EXP>
|
|
; <VAR> = <EXP>
|
|
; --------------------------------
|
|
LET JSR PTRGET ; GET <VAR>
|
|
STA FORPNT
|
|
STY FORPNT+1
|
|
LDA #TOKENEQUUAL
|
|
JSR SYNCHR
|
|
LDA VALTYP+1 ; SAVE VARIABLE TYPE
|
|
PHA
|
|
LDA VALTYP
|
|
PHA
|
|
JSR FRMEVL ; EVALUATE <EXP>
|
|
PLA
|
|
ROL
|
|
JSR CHKVAL
|
|
BNE LET_STRING
|
|
PLA
|
|
; --------------------------------
|
|
LET2 BPL L_LET2_1 ; REAL VARIABLE
|
|
JSR ROUND_FAC ; INTEGER VAR: ROUND TO 32 BITS
|
|
JSR AYINT ; TRUNCATE TO 16-BITS
|
|
LDY #0
|
|
LDA FAC+3
|
|
STA (FORPNT),Y
|
|
INY
|
|
LDA FAC+4
|
|
STA (FORPNT),Y
|
|
RTS
|
|
; --------------------------------
|
|
; REAL VARIABLE = EXPRESSION
|
|
; --------------------------------
|
|
L_LET2_1 JMP SETFOR
|
|
; --------------------------------
|
|
LET_STRING
|
|
PLA
|
|
; --------------------------------
|
|
; INSTALL STRING, DESCRIPTOR ADDRESS IS AT FAC+3,4
|
|
; --------------------------------
|
|
PUTSTR LDY #2 ; STRING DATA ALREADY IN STRING AREA?
|
|
LDA (FAC+3),Y ; (STRING AREA IS BTWN FRETOP
|
|
CMP FRETOP+1 ; HIMEM)
|
|
BCC L_PUTSTR_2 ; YES, DATA ALREADY UP THERE
|
|
BNE L_PUTSTR_1 ; NO
|
|
DEY ; MAYBE, TEST LOW BYTE OF POINTER
|
|
LDA (FAC+3),Y ;
|
|
CMP FRETOP ;
|
|
BCC L_PUTSTR_2 ; YES, ALREADY THERE
|
|
L_PUTSTR_1 LDY FAC+4 ; NO. DESCRIPTOR ALREADY AMONG VARIABLES?
|
|
CPY VARTAB+1 ;
|
|
BCC L_PUTSTR_2 ; NO
|
|
BNE L_PUTSTR_3 ; YES
|
|
LDA FAC+3 ; MAYBE, COMPARE LO-BYTE
|
|
CMP VARTAB ;
|
|
BCS L_PUTSTR_3 ; YES, DESCRIPTOR IS AMONG VARIABLES
|
|
L_PUTSTR_2 LDA FAC+3 ; EITHER STRING ALREADY ON TOP, OR
|
|
LDY FAC+4 ; DESCRIPTOR IS NOT A VARIABLE
|
|
JMP L_PUTSTR_4 ; SO JUST STORE THE DESCRIPTOR
|
|
; --------------------------------
|
|
; STRING NOT YET IN STRING AREA,
|
|
; AND DESCRIPTOR IS A VARIABLE
|
|
; --------------------------------
|
|
L_PUTSTR_3 LDY #0 ; POINT AT LENGTH IN DESCRIPTOR
|
|
LDA (FAC+3),Y ; GET LENGTH
|
|
JSR STRINI ; MAKE A STRING THAT LONG UP ABOVE
|
|
LDA DSCPTR ; SET UP SOURCE PNTR FOR MONINS
|
|
LDY DSCPTR+1 ;
|
|
STA STRNG1 ;
|
|
STY STRNG1+1 ;
|
|
JSR MOVINS ; MOVE STRING DATA TO NEW AREA
|
|
LDA #<FAC ; ADDRESS OF DESCRIPTOR IS IN FAC
|
|
LDY #>FAC ;
|
|
L_PUTSTR_4 STA DSCPTR ;
|
|
STY DSCPTR+1 ;
|
|
JSR FRETMS ; DISCARD DESCRIPTOR IF 'TWAS TEMPORARY
|
|
LDY #0 ; COPY STRING DESCRIPTOR
|
|
LDA (DSCPTR),Y
|
|
STA (FORPNT),Y
|
|
INY
|
|
LDA (DSCPTR),Y
|
|
STA (FORPNT),Y
|
|
INY
|
|
LDA (DSCPTR),Y
|
|
STA (FORPNT),Y
|
|
RTS
|
|
; --------------------------------
|
|
PR_STRING
|
|
JSR STRPRT
|
|
JSR CHRGOT
|
|
; --------------------------------
|
|
; "PRINT" STATEMENT
|
|
; --------------------------------
|
|
PRINT BEQ CRDO ; NO MORE LIST, PRINT <RETURN>
|
|
; --------------------------------
|
|
PRINT2 BEQ RTS_8 ; NO MORE LIST, DON'T PRINT <RETURN>
|
|
CMP #TOKEN_TAB
|
|
BEQ PR_TAB_OR_SPC ; C=1 FOR TAB(
|
|
CMP #TOKEN_SPC
|
|
CLC
|
|
BEQ PR_TAB_OR_SPC ; C=0 FOR SPC(
|
|
CMP #LOCHAR(`,')
|
|
CLC ; <<< NO PURPOSE TO THIS >>>
|
|
BEQ PR_COMMA ;
|
|
CMP #LOCHAR(`;')
|
|
BEQ PR_NEXT_CHAR ;
|
|
JSR FRMEVL ; EVALUATE EXPRESSION
|
|
BIT VALTYP ; STRING OR FP VALUE?
|
|
BMI PR_STRING ; STRING
|
|
JSR FOUT ; FP: CONVERT INTO BUFFER
|
|
JSR STRLIT ; MAKE BUFFER INTO STRING
|
|
JMP PR_STRING ; PRINT THE STRING
|
|
; --------------------------------
|
|
CRDO LDA #$0D ; PRINT <RETURN>
|
|
JSR OUTDO
|
|
NEGATE EOR #$FF ; <<< WHY??? >>>
|
|
RTS_8 RTS
|
|
; --------------------------------
|
|
; TAB TO NEXT COMMA COLUMN
|
|
; <<< NOTE BUG IF WIDTH OF WINDOW LESS THAN 33 >>>
|
|
PR_COMMA
|
|
LDA MON_CH
|
|
CMP #24 ; <<< BUG: IT SHOULD BE 32 >>>
|
|
BCC L_PR_COMMA_1 ; NEXT COLUMN, SAME LINE
|
|
JSR CRDO ; FIRST COLUMN, NEXT LINT
|
|
BNE PR_NEXT_CHAR ; ...ALWAYS
|
|
L_PR_COMMA_1 ADC #16
|
|
AND #$F0 ; ROUND TO 16 OR 32
|
|
STA MON_CH
|
|
BCC PR_NEXT_CHAR ; ...ALWAYS
|
|
; --------------------------------
|
|
PR_TAB_OR_SPC
|
|
PHP ; C=0 FOR SPC(, C=1 FOR TAB(
|
|
JSR GTBYTC ; GET VALUE
|
|
CMP #LOCHAR(`)') ; TRAILING PARENTHESIS
|
|
BEQ L_PR_TAB_OR_SPC_1 ; GOOD
|
|
JMP SYNERR ; NO, SYNTAX ERROR
|
|
L_PR_TAB_OR_SPC_1 PLP ; TAB( OR SPC(
|
|
BCC L_PR_TAB_OR_SPC_2 ; SPC(
|
|
DEX ; TAB(
|
|
TXA ; CALCULATE SPACES NEEDED FOR TAB(
|
|
SBC MON_CH
|
|
BCC PR_NEXT_CHAR ; ALREADY PAST THAT COLUMN
|
|
TAX ; NOW DO A SPC( TO THE SPECIFIED COLUMN
|
|
L_PR_TAB_OR_SPC_2 INX
|
|
NXSPC DEX
|
|
BNE DOSPC ; MORE SPACES TO PRINT
|
|
; --------------------------------
|
|
PR_NEXT_CHAR
|
|
JSR CHRGET
|
|
JMP PRINT2 ; CONTINUE PARSING PRINT LIST
|
|
; --------------------------------
|
|
DOSPC JSR OUTSP
|
|
BNE NXSPC ; ...ALWAYS
|
|
; --------------------------------
|
|
; PRINT STRING AT (Y,A)
|
|
STROUT JSR STRLIT ; MAKE (Y,A) PRINTABLE
|
|
; --------------------------------
|
|
; PRINT STRING AT (FACMO,FACLO)
|
|
; --------------------------------
|
|
STRPRT JSR FREFAC ; GET ADDRESS INTO INDEX, (A)=LENGTH
|
|
TAX ; USE X-REG FOR COUNTER
|
|
LDY #0 ; USE Y-REG FOR SCANNER
|
|
INX ;
|
|
L_STRPRT_1 DEX ;
|
|
BEQ RTS_8 ; FINISHED
|
|
LDA (INDEX),Y ; NEXT CHAR FROM STRING
|
|
JSR OUTDO ; PRINT THE CHAR
|
|
INY ;
|
|
; <<< NEXT THREE LINES ARE USELESS >>>
|
|
CMP #$0D ; WAS IT <RETURN>?
|
|
BNE L_STRPRT_1 ; NO
|
|
JSR NEGATE ; EOR #$FF WOULD DO IT, BUT WHY?
|
|
; <<< ABOVE THREE LINES ARE USELESS >>>
|
|
JMP L_STRPRT_1
|
|
; --------------------------------
|
|
OUTSP LDA #LOCHAR(` ') ; PRINT A SPACE
|
|
ASM_DATA($2C) ; SKIP OVER NEXT LINE
|
|
OUTQUES LDA #LOCHAR(`?') ; PRINT QUESTION MARK
|
|
; --------------------------------
|
|
; PRINT CHAR FROM (A)
|
|
;
|
|
; NOTE: POKE 243,32 ($20 IN $F3) WILL CONVERT
|
|
; OUTPUT TO LOWER CASE. THIS CAN BE CANCELLED
|
|
; BY NORMAL, INVERSE, OR FLASH OR POKE 243,0.
|
|
; --------------------------------
|
|
OUTDO ORA #$80 ; PRINT (A)
|
|
CMP #$A0 ; CONTROL CHR?
|
|
BCC L_OUTDO_1 ; SKIP IF SO
|
|
ORA FLASH_BIT ; =$40 FOR FLASH, ELSE $00
|
|
L_OUTDO_1 JSR MON_COUT ; "AND"S WITH $3F (INVERSE), $7F (FLASH)
|
|
AND #$7F ;
|
|
PHA ;
|
|
LDA SPEEDZ ; COMPLEMENT OF SPEED #
|
|
JSR MON_WAIT ; SO SPEED=255 BECOMES (A)=1
|
|
PLA
|
|
RTS
|
|
; --------------------------------
|
|
; INPUT CONVERSION ERROR: ILLEGAL CHARACTER
|
|
; IN NUMERIC FIELD. MUST DISTINGUISH
|
|
; BETWEEN INPUT, READ, AND GET
|
|
; --------------------------------
|
|
INPUTERR
|
|
LDA INPUTFLG
|
|
BEQ RESPERR ; TAKEN IF INPUT
|
|
BMI READERR ; TAKEN IF READ
|
|
LDY #$FF ; FROM A GET
|
|
BNE ERLIN ; ...ALWAYS
|
|
; --------------------------------
|
|
READERR
|
|
LDA DATLIN ; TELL WHERE THE "DATA" IS, RATHER
|
|
LDY DATLIN+1 ; THAN THE "READ"
|
|
; --------------------------------
|
|
ERLIN STA CURLIN
|
|
STY CURLIN+1
|
|
JMP SYNERR
|
|
; --------------------------------
|
|
INPERR PLA
|
|
; --------------------------------
|
|
RESPERR
|
|
BIT ERRFLG ; "ON ERR" TURNED ON?
|
|
BPL L_RESPERR_1 ; NO, GIVE REENTRY A TRY
|
|
LDX #254 ; ERROR CODE = 254
|
|
JMP HANDLERR
|
|
L_RESPERR_1 LDA #<ERR_REENTRY ; "?REENTER"
|
|
LDY #>ERR_REENTRY
|
|
JSR STROUT
|
|
LDA OLDTEXT ; RE-EXECUTE THE WHOLE INPUT STATEMENT
|
|
LDY OLDTEXT+1
|
|
STA TXTPTR
|
|
STY TXTPTR+1
|
|
RTS
|
|
; --------------------------------
|
|
; "GET" STATEMENT
|
|
; --------------------------------
|
|
GET JSR ERRDIR ; ILLEGAL IF IN DIRECT MODE
|
|
LDX #<(INPUT_BUFFER+1) ; SIMULATE INPUT
|
|
LDY #>(INPUT_BUFFER+1)
|
|
LDA #0
|
|
STA INPUT_BUFFER+1
|
|
LDA #$40 ; SET UP INPUTFLG
|
|
JSR PROCESS_INPUT_LIST ; <<< CAN SAVE 1 BYTE HERE>>>
|
|
RTS ; <<<BY "JMP PROCESS.INPUT.LIST">>>
|
|
; --------------------------------
|
|
; "INPUT" STATEMENT
|
|
; --------------------------------
|
|
INPUT CMP #$22 ; CHECK FOR OPTIONAL PROMPT STRING
|
|
BNE L_INPUT_1 ; NO, PRINT "?" PROMPT
|
|
JSR STRTXT ; MAKE A PRINTABLE STRING OUT OF IT
|
|
LDA #LOCHAR(`;') ; MUST HAVE ; NOW
|
|
JSR SYNCHR ;
|
|
JSR STRPRT ; PRINT THE STRING
|
|
JMP L_INPUT_2 ;
|
|
L_INPUT_1 JSR OUTQUES ; NO STRING, PRINT "?"
|
|
L_INPUT_2 JSR ERRDIR ; ILLEGAL IF IN DIRECT MODE
|
|
LDA #LOCHAR(`,') ; PRIME THE BUFFER
|
|
STA INPUT_BUFFER-1
|
|
JSR INLIN
|
|
LDA INPUT_BUFFER
|
|
CMP #$03 ; CONTROL C?
|
|
BNE INPUT_FLAG_ZERO ; NO
|
|
JMP CONTROL_C_TYPED
|
|
; --------------------------------
|
|
NXIN JSR OUTQUES ; PRINT "?"
|
|
JMP INLIN
|
|
; --------------------------------
|
|
; "READ" STATEMENT
|
|
; --------------------------------
|
|
READ LDX DATPTR ; Y,X POINTS AT NEXT DATA STATEMENT
|
|
LDY DATPTR+1 ;
|
|
LDA #$98 ; SET INPUTFLG = $98
|
|
ASM_DATA($2C) ; TRICK TO PROCESS.INPUT.LIST
|
|
; --------------------------------
|
|
INPUT_FLAG_ZERO LDA #0 ; SET INPUTFLG = $00
|
|
; --------------------------------
|
|
; PROCESS INPUT LIST
|
|
;
|
|
; (Y,X) IS ADDRESS OF INPUT DATA STRING
|
|
; (A) = VALUE FOR INPUTFLG: $00 FOR INPUT
|
|
; $40 FOR GET
|
|
; $98 FOR READ
|
|
; --------------------------------
|
|
PROCESS_INPUT_LIST STA INPUTFLG
|
|
STX INPTR ; ADDRESS OF INPUT STRING
|
|
STY INPTR+1
|
|
; --------------------------------
|
|
PROCESS_INPUT_ITEM JSR PTRGET ; GET ADDRESS OF VARIABLE
|
|
STA FORPNT ;
|
|
STY FORPNT+1 ;
|
|
LDA TXTPTR ; SAVE CURRENT TXTPTR,
|
|
LDY TXTPTR+1 ; WHICH POINTS INTO PROGRAM
|
|
STA TXPSV ;
|
|
STY TXPSV+1 ;
|
|
LDX INPTR ; SET TXTPTR TO POINT AT INPUT BUFFER
|
|
LDY INPTR+1 ; OR "DATA" LINE
|
|
STX TXTPTR ;
|
|
STY TXTPTR+1 ;
|
|
JSR CHRGOT ; GET CHAR AT PNTR
|
|
BNE INSTART ; NOT END OF LINE OR COLON
|
|
BIT INPUTFLG ; DOING A "GET"?
|
|
BVC L_PROCESS_INPUT_ITEM_1 ; NO
|
|
JSR MON_RDKEY ; YES, GET CHAR
|
|
AND #$7F
|
|
STA INPUT_BUFFER
|
|
LDX #<(INPUT_BUFFER-1)
|
|
LDY #>(INPUT_BUFFER-1)
|
|
BNE L_PROCESS_INPUT_ITEM_2 ; ...ALWAYS
|
|
; --------------------------------
|
|
L_PROCESS_INPUT_ITEM_1 BMI FINDATA ; DOING A "READ"
|
|
JSR OUTQUES ; DOING AN "INPUT", PRINT "?"
|
|
JSR NXIN ; PRINT ANOTHER "?", AND INPUT A LINE
|
|
L_PROCESS_INPUT_ITEM_2 STX TXTPTR
|
|
STY TXTPTR+1
|
|
; --------------------------------
|
|
INSTART
|
|
JSR CHRGET ; GET NEXT INPUT CHAR
|
|
BIT VALTYP ; STRING OR NUMERIC?
|
|
BPL L_INSTART_5 ; NUMERIC
|
|
BIT INPUTFLG ; STRING -- NOW WHAT INPUT TYPE?
|
|
BVC L_INSTART_1 ; NOT A "GET"
|
|
INX ; "GET"
|
|
STX TXTPTR
|
|
LDA #0
|
|
STA CHARAC ; NO OTHER TERMINATORS THAN $00
|
|
BEQ L_INSTART_2 ; ...ALWAYS
|
|
; --------------------------------
|
|
L_INSTART_1 STA CHARAC
|
|
CMP #$22 ; TERMINATE ON $00 OR QUOTE
|
|
BEQ L_INSTART_3
|
|
LDA #LOCHAR(`:') ; TERMINATE ON $00, COLON, OR COMMA
|
|
STA CHARAC
|
|
LDA #LOCHAR(`,')
|
|
L_INSTART_2 CLC
|
|
L_INSTART_3 STA ENDCHR
|
|
LDA TXTPTR
|
|
LDY TXTPTR+1
|
|
ADC #0 ; SKIP OVER QUOTATION MARK, IF
|
|
BCC L_INSTART_4 ; THERE WAS ONE
|
|
INY
|
|
L_INSTART_4 JSR STRLT2 ; BUILD STRING STARTING AT (Y,A)
|
|
; TERMINATED BY $00, (CHARAC), OR (ENDCHR)
|
|
JSR POINT ; SET TXTPTR TO POINT AT STRING
|
|
JSR PUTSTR ; STORE STRING IN VARIABLE
|
|
JMP INPUT_MORE
|
|
; --------------------------------
|
|
L_INSTART_5 PHA
|
|
LDA INPUT_BUFFER ; ANYTHING IN BUFFER?
|
|
BEQ INPFIN ; NO, SEE IF READ OR INPUT
|
|
; --------------------------------
|
|
INPUTDWTA
|
|
PLA ; "READ"
|
|
JSR FIN ; GET FP NUMBER AT TXTPTR
|
|
LDA VALTYP+1 ;
|
|
JSR LET2 ; STORE RESULT IN VARIABLE
|
|
; --------------------------------
|
|
INPUT_MORE
|
|
JSR CHRGOT
|
|
BEQ L_INPUT_MORE_1 ; END OF LINE OR COLON
|
|
CMP #LOCHAR(`,') ; COMMA IN INPUT?
|
|
BEQ L_INPUT_MORE_1 ; YES
|
|
JMP INPUTERR ; NOTHING ELSE WILL DO
|
|
L_INPUT_MORE_1 LDA TXTPTR ; SAVE POSITION IN INPUT BUFFER
|
|
LDY TXTPTR+1 ;
|
|
STA INPTR ;
|
|
STY INPTR+1 ;
|
|
LDA TXPSV ; RESTORE PROGRAM POINTER
|
|
LDY TXPSV+1 ;
|
|
STA TXTPTR ;
|
|
STY TXTPTR+1 ;
|
|
JSR CHRGOT ; NEXT CHAR FROM PROGRAM
|
|
BEQ INPDONE ; END OF STATEMENT
|
|
JSR CHKCOM ; BETTER BE A COMMA THEN
|
|
JMP PROCESS_INPUT_ITEM
|
|
; --------------------------------
|
|
INPFIN LDA INPUTFLG ; "INPUT" OR "READ"
|
|
BNE INPUTDWTA ; "READ"
|
|
JMP INPERR
|
|
; --------------------------------
|
|
FINDATA
|
|
JSR DATAN ; GET OFFSET TO NEXT COLON OR EOL
|
|
INY ; TO FIRST CHAR OF NEXT LINE
|
|
TAX ; WHICH: EOL OR COLON?
|
|
BNE L_FINDATA_1 ; COLON
|
|
LDX #ERR_NODATA ; EOL: MIGHT BE OUT OF DATA
|
|
INY ; CHECK HI-BYTE OF FORWARD PNTR
|
|
LDA (TXTPTR),Y ; END OF PROGRAM?
|
|
BEQ GERR ; YES, WE ARE OUT OF DATA
|
|
INY ; PICK UP THE LINE #
|
|
LDA (TXTPTR),Y
|
|
STA DATLIN
|
|
INY
|
|
LDA (TXTPTR),Y
|
|
INY ; POINT AT FIRST TEXT CHAR IN LINE
|
|
STA DATLIN+1
|
|
L_FINDATA_1 LDA (TXTPTR),Y ; GET 1ST TOKEN OF STATEMENT
|
|
TAX ; SAVE TOKEN IN X-REG
|
|
JSR ADDON ; ADD (Y) TO TXTPTR
|
|
CPX #TOKENDWTA ; DID WE FIND A "DATA" STATEMENT?
|
|
BNE FINDATA ; NOT YET
|
|
JMP INSTART ; YES, READ IT
|
|
; ---NO MORE INPUT REQUESTED------
|
|
INPDONE
|
|
LDA INPTR ; GET POINTER IN CASE IT WAS "READ"
|
|
LDY INPTR+1
|
|
LDX INPUTFLG ; "READ" OR "INPUT"?
|
|
BPL L_INPDONE_1 ; "INPUT"
|
|
JMP SETDA ; "DATA", SO STORE (Y,X) AT DATPTR
|
|
L_INPDONE_1 LDY #0 ; "INPUT": ANY MORE CHARS ON LINE?
|
|
LDA (INPTR),Y
|
|
BEQ L_INPDONE_2 ; NO, ALL IS WELL
|
|
LDA #<ERR_EXTRA ; YES, ERROR
|
|
LDY #>ERR_EXTRA ; "EXTRA IGNORED"
|
|
JMP STROUT
|
|
L_INPDONE_2 RTS
|
|
; --------------------------------
|
|
ERR_EXTRA LOASCII(`?EXTRA IGNORED')
|
|
ASM_DATA($0D,0)
|
|
|
|
ERR_REENTRY LOASCII(`?REENTER')
|
|
ASM_DATA($0D,0)
|
|
; --------------------------------
|
|
; --------------------------------
|
|
; "NEXT" STATEMENT
|
|
; --------------------------------
|
|
NEXT BNE NEXT_1 ; VARIABLE AFTER "NEXT"
|
|
LDY #0 ; FLAG BY SETTING FORPNT+1 = 0
|
|
BEQ NEXT_2 ; ...ALWAYS
|
|
; --------------------------------
|
|
NEXT_1 JSR PTRGET ; GET PNTR TO VARIABLE IN (Y,A)
|
|
NEXT_2 STA FORPNT
|
|
STY FORPNT+1
|
|
JSR GTFORPNT ; FIND FOR-FRAME FOR THIS VARIABLE
|
|
BEQ NEXT_3 ; FOUND IT
|
|
LDX #ERR_NOFOR ; NOT THERE, ABORT
|
|
GERR BEQ JERROR ; ...ALWAYS
|
|
NEXT_3 TXS ; SET STACK PTR TO POINT TO THIS FRAME,
|
|
INX ; WHICH TRIMS OFF ANY INNER LOOPS
|
|
INX
|
|
INX
|
|
INX
|
|
TXA ; LOW BYTE OF ADRS OF STEP VALUE
|
|
INX
|
|
INX
|
|
INX
|
|
INX
|
|
INX
|
|
INX
|
|
STX DEST ; LOW BYTE ADRS OF FOR VAR VALUE
|
|
LDY #>STACK ; (Y,A) IS ADDRESS OF STEP VALUE
|
|
JSR LOAD_FAC_FROM_YA ; STEP TO FAC
|
|
TSX
|
|
LDA STACK+9,X
|
|
STA FAC_SIGN
|
|
LDA FORPNT
|
|
LDY FORPNT+1
|
|
JSR FADD ; ADD TO FOR VALUE
|
|
JSR SETFOR ; PUT NEW VALUE BACK
|
|
LDY #>STACK ; (Y,A) IS ADDRESS OF END VALUE
|
|
JSR FCOMP2 ; COMPARE TO END VALUE
|
|
TSX
|
|
SEC
|
|
SBC STACK+9,X ; SIGN OF STEP
|
|
BEQ L_NEXT_3_2 ; BRANCH IF FOR COMPLETE
|
|
LDA STACK+15,X ; OTHERWISE SET UP
|
|
STA CURLIN ; FOR LINE #
|
|
LDA STACK+16,X
|
|
STA CURLIN+1
|
|
LDA STACK+18,X ; AND SET TXTPTR TO JUST
|
|
STA TXTPTR ; AFTER FOR STATEMENT
|
|
LDA STACK+17,X
|
|
STA TXTPTR+1
|
|
L_NEXT_3_1 JMP NEWSTT
|
|
L_NEXT_3_2 TXA ; POP OFF FOR-FRAME, LOOP IS DONE
|
|
ADC #17 ; CARRY IS SET, SO ADDS 18
|
|
TAX
|
|
TXS
|
|
JSR CHRGOT ; CHAR AFTER VARIABLE
|
|
CMP #LOCHAR(`,') ; ANOTHER VARIABLE IN NEXT_
|
|
BNE L_NEXT_3_1 ; NO, GO TO NEXT STATEMENT
|
|
JSR CHRGET ; YES, PRIME FOR NEXT VARIABLE
|
|
JSR NEXT_1 ; (DOES NOT RETURN)
|
|
; --------------------------------
|
|
; EVALUATE EXPRESSION, MAKE SURE IT IS NUMERIC
|
|
; --------------------------------
|
|
FRMNUM JSR FRMEVL
|
|
; --------------------------------
|
|
; MAKE SURE (FAC) IS NUMERIC
|
|
; --------------------------------
|
|
CHKNUM CLC
|
|
ASM_DATA($24) ; DUMMY FOR SKIP
|
|
; --------------------------------
|
|
; MAKE SURE (FAC) IS STRING
|
|
; --------------------------------
|
|
CHKSTR SEC
|
|
; --------------------------------
|
|
; MAKE SURE (FAC) IS CORRECT TYPE
|
|
; IF C=0, TYPE MUST BE NUMERIC
|
|
; IF C=1, TYPE MUST BE STRING
|
|
; --------------------------------
|
|
CHKVAL BIT VALTYP ; $00 IF NUMERIC, $FF IF STRING
|
|
BMI L_CHKVAL_2 ; TYPE IS STRING
|
|
BCS L_CHKVAL_3 ; NOT STRING, BUT WE NEED STRING
|
|
L_CHKVAL_1 RTS ; TYPE IS CORRECT
|
|
L_CHKVAL_2 BCS L_CHKVAL_1 ; IS STRING AND WE WANTED STRING
|
|
L_CHKVAL_3 LDX #ERR_BADTYPE ; TYPE MISMATCH
|
|
JERROR JMP ERROR
|
|
; --------------------------------
|
|
; EVALUATE THE EXPRESSION AT TXTPTR, LEAVING THE
|
|
; RESULT IN FAC. WORKS FOR BOTH STRING AND NUMERIC
|
|
; EXPRESSIONS.
|
|
; --------------------------------
|
|
FRMEVL LDX TXTPTR ; DECREMENT TXTPTR
|
|
BNE L_FRMEVL_1
|
|
DEC TXTPTR+1
|
|
L_FRMEVL_1 DEC TXTPTR
|
|
LDX #0 ; START WITH PRECEDENCE = 0
|
|
ASM_DATA($24) ; TRICK TO SKIP FOLLOWING "PHA"
|
|
; --------------------------------
|
|
FRMEVL_1
|
|
PHA ; PUSH RELOPS FLAGS
|
|
TXA ;
|
|
PHA ; SAVE LAST PRECEDENCE
|
|
LDA #1 ;
|
|
JSR CHKMEM ; CHECK IF ENOUGH ROOM ON STACK
|
|
JSR FRM_ELEMENT ; GET AN ELEMENT
|
|
LDA #0
|
|
STA CPRTYP ; CLEAR COMPARISON OPERATOR FLAGS
|
|
; --------------------------------
|
|
FRMEVL_2
|
|
JSR CHRGOT ; CHECK FOR RELATIONAL OPERATORS
|
|
L_FRMEVL_2_1 SEC ; > IS $CF, = IS $D0, < IS $D1
|
|
SBC #TOKEN_GREATER ; > IS 0, = IS 1, < IS 2
|
|
BCC L_FRMEVL_2_2 ; NOT RELATIONAL OPERATOR
|
|
CMP #3 ;
|
|
BCS L_FRMEVL_2_2 ; NOT RELATIONAL OPERATOR
|
|
CMP #1 ; SET CARRY IF "=" OR "<"
|
|
ROL ; NOW > IS 0, = IS 3, < IS 5
|
|
EOR #1 ; NOW > IS 1, = IS 2, < IS 4
|
|
EOR CPRTYP ; SET BITS OF CPRTYP: 00000<=>
|
|
CMP CPRTYP ; CHECK FOR ILLEGAL COMBINATIONS
|
|
BCC SNTXERR ; IF LESS THAN, A RELOP WAS REPEATED
|
|
STA CPRTYP ;
|
|
JSR CHRGET ; ANOTHER OPERATOR?
|
|
JMP L_FRMEVL_2_1 ; CHECK FOR <,=,> AGAIN
|
|
; --------------------------------
|
|
L_FRMEVL_2_2 LDX CPRTYP ; DID WE FIND A RELATIONAL OPERATOR?
|
|
BNE FRM_RELATIONAL ; YES
|
|
BCS NOTMATH ; NO, AND NEXT TOKEN IS > $D1
|
|
ADC #$CF-TOKEN_PLUS ; NO, AND NEXT TOKEN < $CF
|
|
BCC NOTMATH ; IF NEXT TOKEN < "+"
|
|
ADC VALTYP ; + AND LAST RESULT A STRING?
|
|
BNE L_FRMEVL_2_3 ; BRANCH IF NOT
|
|
JMP CAT ; CONCATENATE IF SO.
|
|
; --------------------------------
|
|
L_FRMEVL_2_3 ADC #$FF ; +-*/ IS 0123
|
|
STA INDEX
|
|
ASL ; MULTIPLY BY 3
|
|
ADC INDEX ; +-*/ IS 0,3,6,9
|
|
TAY
|
|
; --------------------------------
|
|
FRM_PRECEDENCE_TEST
|
|
PLA ; GET LAST PRECEDENCE
|
|
CMP MATHTBL,Y
|
|
BCS FRM_PERFORM_1 ; DO NOW IF HIGHER PRECEDENCE
|
|
JSR CHKNUM ; WAS LAST RESULT A #?
|
|
NXOP PHA ; YES, SAVE PRECEDENCE ON STACK
|
|
SAVOP JSR FRM_RECURSE ; SAVE REST, CALL FRMEVL RECURSIVELY
|
|
PLA
|
|
LDY LASTOP
|
|
BPL PREFNC
|
|
TAX
|
|
BEQ GOEX ; EXIT IF NO MATH IN EXPRESSION
|
|
BNE FRM_PERFORM_2 ; ...ALWAYS
|
|
; --------------------------------
|
|
; FOUND ONE OR MORE RELATIONAL OPERATORS <,=,>
|
|
; --------------------------------
|
|
FRM_RELATIONAL
|
|
LSR VALTYP ; (VALTYP) = 0 (NUMERIC), = $FF (STRING)
|
|
TXA ; SET CPRTYP TO 0000<=>C
|
|
ROL ; WHERE C=0 IF #, C=1 IF STRING
|
|
LDX TXTPTR ; BACK UP TXTPTR
|
|
BNE L_FRM_RELATIONAL_1
|
|
DEC TXTPTR+1
|
|
L_FRM_RELATIONAL_1 DEC TXTPTR
|
|
LDY #M_REL-MATHTBL ; POINT AT RELOPS ENTRY
|
|
STA CPRTYP
|
|
BNE FRM_PRECEDENCE_TEST ; ...ALWAYS
|
|
; --------------------------------
|
|
PREFNC CMP MATHTBL,Y
|
|
BCS FRM_PERFORM_2 ; DO NOW IF HIGHER PRECEDENCE
|
|
BCC NXOP ; ...ALWAYS
|
|
; --------------------------------
|
|
; STACK THIS OPERATION AND CALL FRMEVL FOR
|
|
; ANOTHER ONE
|
|
; --------------------------------
|
|
FRM_RECURSE
|
|
LDA MATHTBL+2,Y
|
|
PHA ; PUSH ADDRESS OF OPERATION PERFORMER
|
|
LDA MATHTBL+1,Y
|
|
PHA
|
|
JSR FRM_STACK_1 ; STACK FAC.SIGN AND FAC
|
|
LDA CPRTYP ; A=RELOP FLAGS, X=PRECEDENCE BYTE
|
|
JMP FRMEVL_1 ; RECURSIVELY CALL FRMEVL
|
|
; --------------------------------
|
|
SNTXERR JMP SYNERR
|
|
; --------------------------------
|
|
; STACK (FAC)
|
|
;
|
|
; THREE ENTRY POINTS:
|
|
; L_SNTXERR_1, FROM FRMEVL
|
|
; L_SNTXERR_2, FROM "STEP"
|
|
; L_SNTXERR_3, FROM "FOR"
|
|
; --------------------------------
|
|
FRM_STACK_1
|
|
LDA FAC_SIGN ; GET FAC.SIGN TO PUSH IT
|
|
; Note: XA65 assembler (Andre Fachat) requires ! here when asm with "xa -R -bt 0" for some reason:
|
|
LDX !MATHTBL,Y ; PRECEDENCE BYTE FROM MATHTBL
|
|
; --------------------------------
|
|
; ENTER HERE FROM "STEP", TO PUSH STEP SIGN AND VALUE
|
|
; --------------------------------
|
|
FRM_STACK_2
|
|
TAY ; FAC.SIGN OR SGN(STEP VALUE)
|
|
PLA ; PULL RETURN ADDRESS AND ADD 1
|
|
STA INDEX ; <<< ASSUMES NOT ON PAGE BOUNDARY! >>>
|
|
INC INDEX ; PLACE BUMPED RETURN ADDRESS IN
|
|
PLA ; INDEX,INDEX+1
|
|
STA INDEX+1 ;
|
|
TYA ; FAC.SIGN OR SGN(STEP VALUE)
|
|
PHA ; PUSH FAC.SIGN OR SGN(STEP VALUE)
|
|
; --------------------------------
|
|
; ENTER HERE FROM "FOR", WITH (INDEX) = STEP,
|
|
; TO PUSH INITIAL VALUE OF "FOR" VARIABLE
|
|
; --------------------------------
|
|
FRM_STACK_3
|
|
JSR ROUND_FAC ; ROUND TO 32 BITS
|
|
LDA FAC+4 ; PUSH (FAC)
|
|
PHA
|
|
LDA FAC+3
|
|
PHA
|
|
LDA FAC+2
|
|
PHA
|
|
LDA FAC+1
|
|
PHA
|
|
LDA FAC
|
|
PHA
|
|
JMP (INDEX) ; DO RTS FUNNY WAY
|
|
; --------------------------------
|
|
;
|
|
; --------------------------------
|
|
NOTMATH LDY #$FF ; SET UP TO EXIT ROUTINE
|
|
PLA
|
|
GOEX BEQ EXIT ; EXIT IF NO MATH TO DO
|
|
; --------------------------------
|
|
; PERFORM STACKED OPERATION
|
|
;
|
|
; (A) = PRECEDENCE BYTE
|
|
; STACK: 1 -- CPRMASK
|
|
; 5 -- (ARG)
|
|
; 2 -- ADDR OF PERFORMER
|
|
; --------------------------------
|
|
FRM_PERFORM_1
|
|
CMP #P_REL ; WAS IT RELATIONAL OPERATOR?
|
|
BEQ L_FRM_PERFORM_1_1 ; YES, ALLOW STRING COMPARE
|
|
JSR CHKNUM ; MUST BE NUMERIC VALUE
|
|
L_FRM_PERFORM_1_1 STY LASTOP ;
|
|
; --------------------------------
|
|
FRM_PERFORM_2 ;
|
|
PLA ; GET 0000<=>C FROM STACK
|
|
LSR ; SHIFT TO 00000<=> FORM
|
|
STA CPRMASK ; 00000<=>
|
|
PLA ;
|
|
STA ARG ; GET FLOATING POINT VALUE OFF STACK,
|
|
PLA ; AND PUT IT IN ARG
|
|
STA ARG+1 ;
|
|
PLA ;
|
|
STA ARG+2 ;
|
|
PLA ;
|
|
STA ARG+3 ;
|
|
PLA ;
|
|
STA ARG+4 ;
|
|
PLA ;
|
|
STA ARG+5 ;
|
|
EOR FAC_SIGN ; SAVE EOR OF SIGNS OF THE OPERANDS,
|
|
STA SGNCPR ; IN CASE OF MULTIPLY OR DIVIDE
|
|
EXIT LDA FAC ; FAC EXPONENT IN A-REG
|
|
RTS ; STATUS EQU. IF (FAC)=0
|
|
; RTS GOES TO PERFORM OPERATION
|
|
; --------------------------------
|
|
; GET ELEMENT IN EXPRESSION
|
|
;
|
|
; GET VALUE OF VARIABLE OR NUMBER AT TXTPNT, OR POINT
|
|
; TO STRING DESCRIPTOR IF A STRING, AND PUT IN FAC.
|
|
; --------------------------------
|
|
FRM_ELEMENT ;
|
|
LDA #0 ; ASSUME NUMERIC
|
|
STA VALTYP ;
|
|
L_FRM_ELEMENT_1 JSR CHRGET ;
|
|
BCS L_FRM_ELEMENT_3 ; NOT A DIGIT
|
|
L_FRM_ELEMENT_2 JMP FIN ; NUMERIC CONSTANT
|
|
L_FRM_ELEMENT_3 JSR ISLETC ; VARIABLE NAME?
|
|
BCS FRM_VARIABLE ; YES
|
|
CMP #LOCHAR(`.') ; DECIMAL POINT
|
|
BEQ L_FRM_ELEMENT_2 ; YES, NUMERIC CONSTANT
|
|
CMP #TOKEN_MINUS ; UNARY MINUS?
|
|
BEQ MIN ; YES
|
|
CMP #TOKEN_PLUS ; UNARY PLUS
|
|
BEQ L_FRM_ELEMENT_1 ; YES
|
|
CMP #$22 ; STRING CONSTANT?
|
|
BNE NOT_ ; NO
|
|
; --------------------------------
|
|
; STRING CONSTANT ELEMENT
|
|
;
|
|
; SET Y,A = (TXTPTR)+CARRY
|
|
; --------------------------------
|
|
STRTXT LDA TXTPTR ; ADD (CARRY) TO GET ADDRESS OF 1ST CHAR
|
|
LDY TXTPTR+1 ; OF STRING IN Y,A
|
|
ADC #0 ;
|
|
BCC L_STRTXT_1 ;
|
|
INY ;
|
|
L_STRTXT_1 JSR STRLIT ; BUILD DESCRIPTOR TO STRING
|
|
; GET ADDRESS OF DESCRIPTOR IN FAC
|
|
JMP POINT ; POINT TXTPTR AFTER TRAILING QUOTE
|
|
; --------------------------------
|
|
; "NOT" FUNCTION
|
|
; IF FAC=0, RETURN FAC=1
|
|
; IF FAC<>0, RETURN FAC=0
|
|
; --------------------------------
|
|
NOT_ CMP #TOKEN_NOT
|
|
BNE FN_ ; NOT "NOT", TRY "FN"
|
|
LDY #MEQUU-MATHTBL ; POINT AT = COMPARISON
|
|
BNE EQUL ; ...ALWAYS
|
|
; --------------------------------
|
|
; COMPARISON FOR EQUALITY (= OPERATOR)
|
|
; ALSO USED TO EVALUATE "NOT" FUNCTION
|
|
; --------------------------------
|
|
EQUOP LDA FAC ; SET "TRUE" IF (FAC) = ZERO
|
|
BNE L_EQUOP_1 ; FALSE
|
|
LDY #1 ; TRUE
|
|
ASM_DATA($2C) ; TRICK TO SKIP NEXT 2 BYTES
|
|
L_EQUOP_1 LDY #0 ; FALSE
|
|
JMP SNGFLT ;
|
|
; --------------------------------
|
|
FN_ CMP #TOKEN_FN
|
|
BNE SGN_
|
|
JMP FUNCT
|
|
; --------------------------------
|
|
SGN_ CMP #TOKEN_SGN
|
|
BCC PARCHK
|
|
JMP UNARY
|
|
; --------------------------------
|
|
; EVALUATE "(EXPRESSION)"
|
|
; --------------------------------
|
|
PARCHK JSR CHKOPN ; IS THERE A '(' AT TXTPTR?
|
|
JSR FRMEVL ; YES, EVALUATE EXPRESSION
|
|
; --------------------------------
|
|
CHKCLS LDA #$29 ; CHECK FOR ')'
|
|
ASM_DATA($2C) ; TRICK
|
|
; --------------------------------
|
|
CHKOPN LDA #$28 ;
|
|
ASM_DATA($2C) ; TRICK
|
|
; --------------------------------
|
|
CHKCOM LDA #LOCHAR(`,') ; COMMA AT TXTPTR?
|
|
; --------------------------------
|
|
; UNLESS CHAR AT TXTPTR = (A), SYNTAX ERROR
|
|
; --------------------------------
|
|
SYNCHR LDY #0
|
|
CMP (TXTPTR),Y
|
|
BNE SYNERR
|
|
JMP CHRGET ; MATCH, GET NEXT CHAR & RETURN
|
|
; --------------------------------
|
|
SYNERR LDX #ERR_SYNTAX
|
|
JMP ERROR
|
|
; --------------------------------
|
|
MIN LDY #M_NEG-MATHTBL ; POINT AT UNARY MINUS
|
|
EQUL PLA
|
|
PLA
|
|
JMP SAVOP
|
|
; --------------------------------
|
|
FRM_VARIABLE
|
|
JSR PTRGET
|
|
FRM_VARIABLE_CALL = *-1 ; SO PTRGET CAN TELL WE CALLED
|
|
STA VPNT ; ADDRESS OF VARIABLE
|
|
STY VPNT+1 ;
|
|
LDX VALTYP ; NUMERIC OR STRING?
|
|
BEQ L_FRM_VARIABLE_CALL_1 ; NUMERIC
|
|
LDX #0 ; STRING
|
|
STX STRNG1+1 ;
|
|
RTS ;
|
|
L_FRM_VARIABLE_CALL_1 LDX VALTYP+1 ; NUMERIC, WHICH TYPE?
|
|
BPL L_FRM_VARIABLE_CALL_2 ; FLOATING POINT
|
|
LDY #0 ; INTEGER
|
|
LDA (VPNT),Y ;
|
|
TAX ; GET VALUE IN A,Y
|
|
INY ;
|
|
LDA (VPNT),Y ;
|
|
TAY ;
|
|
TXA ;
|
|
JMP GIVAYF ; CONVERT A,Y TO FLOATING POINT
|
|
L_FRM_VARIABLE_CALL_2 JMP LOAD_FAC_FROM_YA
|
|
; --------------------------------
|
|
; --------------------------------
|
|
; "SCRN(" FUNCTION
|
|
; --------------------------------
|
|
SCREEN JSR CHRGET
|
|
JSR PLOTFNS ; GET COLUMN AND ROW
|
|
TXA ; ROW
|
|
LDY FIRST ; COLUMN
|
|
JSR MON_SCRN ; GET 4-BIT COLOR THERE
|
|
TAY ;
|
|
JSR SNGFLT ; CONVERT (Y) TO REAL IN FAC
|
|
JMP CHKCLS ; REQUIRE ")"
|
|
; --------------------------------
|
|
; PROCESS UNARY OPERATORS (FUNCTIONS)
|
|
; --------------------------------
|
|
UNARY CMP #TOKEN_SCRN ; NOT UNARY, DO SPECIAL
|
|
BEQ SCREEN
|
|
ASL ; DOUBLE TOKEN TO GET INDEX
|
|
PHA
|
|
TAX
|
|
JSR CHRGET
|
|
CPX #<(TOKEN_LEFTSTR*2-1) ; LEFT$, RIGHT$, AND MID$
|
|
BCC L_UNARY_1 ; NOT ONE OF THE STRING FUNCTIONS
|
|
JSR CHKOPN ; STRING FUNCTION, NEED "("
|
|
JSR FRMEVL ; EVALUATE EXPRESSION FOR STRING
|
|
JSR CHKCOM ; REQUIRE A COMMA
|
|
JSR CHKSTR ; MAKE SURE EXPRESSION IS A STRING
|
|
PLA ;
|
|
TAX ; RETRIEVE ROUTINE POINTER
|
|
LDA VPNT+1 ; STACK ADDRESS OF STRING
|
|
PHA ;
|
|
LDA VPNT ;
|
|
PHA ;
|
|
TXA ;
|
|
PHA ; STACK DOUBLED TOKEN
|
|
JSR GETBYT ; CONVERT NEXT EXPRESSION TO BYTE IN X-REG
|
|
PLA ; GET DOUBLED TOKEN OFF STACK
|
|
TAY ; USE AS INDEX TO BRANCH
|
|
TXA ; VALUE OF SECOND PARAMETER
|
|
PHA ; PUSH 2ND PARAM
|
|
JMP L_UNARY_2 ; JOIN UNARY FUNCTIONS
|
|
L_UNARY_1 JSR PARCHK ; REQUIRE "(EXPRESSION)"
|
|
PLA
|
|
TAY ; INDEX INTO FUNCTION ADDRESS TABLE
|
|
L_UNARY_2 LDA UNFNC-TOKEN_SGN-TOKEN_SGN+$100,Y
|
|
STA JMPADRS+1 ; PREPARE TO JSR TO ADDRESS
|
|
LDA UNFNC-TOKEN_SGN-TOKEN_SGN+$101,Y
|
|
STA JMPADRS+2
|
|
JSR JMPADRS ; DOES NOT RETURN FOR
|
|
; CHR$, LEFT$, RIGHT$, OR MID$
|
|
JMP CHKNUM ; REQUIRE NUMERIC RESULT
|
|
; --------------------------------
|
|
OR LDA ARG ; "OR" OPERATOR
|
|
ORA FAC ; IF RESULT NONZERO, IT IS TRUE
|
|
BNE TRUE ;
|
|
; --------------------------------
|
|
ANDOP LDA ARG ; "AND" OPERATOR
|
|
BEQ FALSE ; IF EITHER IS ZERO, RESULT IS FALSE
|
|
LDA FAC ;
|
|
BNE TRUE ;
|
|
; --------------------------------
|
|
FALSE LDY #0 ; RETURN FAC=0
|
|
ASM_DATA($2C) ; TRICK
|
|
; --------------------------------
|
|
TRUE LDY #1 ; RETURN FAC=1
|
|
JMP SNGFLT ;
|
|
; --------------------------------
|
|
; PERFORM RELATIONAL OPERATIONS
|
|
; --------------------------------
|
|
RELOPS JSR CHKVAL ; MAKE SURE FAC IS CORRECT TYPE
|
|
BCS STRCMP ; TYPE MATCHES, BRANCH IF STRINGS
|
|
LDA ARG_SIGN ; NUMERIC COMPARISON
|
|
ORA #$7F ; RE-PACK VALUE IN ARG FOR FCOMP
|
|
AND ARG+1 ;
|
|
STA ARG+1 ;
|
|
LDA #<ARG ;
|
|
LDY #>ARG ;
|
|
JSR FCOMP ; RETURN A-REG = -1,0,1
|
|
TAX ; AS ARG <,=,> FAC
|
|
JMP NUMCMP ;
|
|
; --------------------------------
|
|
; STRING COMPARISON
|
|
; --------------------------------
|
|
STRCMP LDA #0 ; SET RESULT TYPE TO NUMERIC
|
|
STA VALTYP ;
|
|
DEC CPRTYP ; MAKE CPRTYP 0000<=>0
|
|
JSR FREFAC ;
|
|
STA FAC ; STRING LENGTH
|
|
STX FAC+1
|
|
STY FAC+2
|
|
LDA ARG+3
|
|
LDY ARG+4
|
|
JSR FRETMP
|
|
STX ARG+3
|
|
STY ARG+4
|
|
TAX ; LEN (ARG) STRING
|
|
SEC ;
|
|
SBC FAC ; SET X TO SMALLER LEN
|
|
BEQ L_STRCMP_1 ;
|
|
LDA #1 ;
|
|
BCC L_STRCMP_1 ;
|
|
LDX FAC ;
|
|
LDA #$FF ;
|
|
L_STRCMP_1 STA FAC_SIGN ; FLAG WHICH SHORTER
|
|
LDY #$FF ;
|
|
INX ;
|
|
STRCMP_1 ;
|
|
INY ;
|
|
DEX ;
|
|
BNE STRCMP_2 ; MORE CHARS IN BOTH STRINGS
|
|
LDX FAC_SIGN ; IF = SO FAR, DECIDE BY LENGTH
|
|
; --------------------------------
|
|
NUMCMP BMI CMPDONE ;
|
|
CLC ;
|
|
BCC CMPDONE ; ...ALWAYS
|
|
; --------------------------------
|
|
STRCMP_2 ;
|
|
LDA (ARG+3),Y ;
|
|
CMP (FAC+1),Y ;
|
|
BEQ STRCMP_1 ; SAME, KEEP COMPARING
|
|
LDX #$FF ; IN CASE ARG GREATER
|
|
BCS CMPDONE ; IT IS
|
|
LDX #1 ; FAC GREATER
|
|
; --------------------------------
|
|
CMPDONE ;
|
|
INX ; CONVERT FF,0,1 TO 0,1,2
|
|
TXA ;
|
|
ROL ; AND TO 0,2,4 IF C=0, ELSE 1,2,5
|
|
AND CPRMASK ; 00000<=>
|
|
BEQ L_CMPDONE_1 ; IF NO MATCH: FALSE
|
|
LDA #1 ; AT LEAST ONE MATCH: TRUE
|
|
L_CMPDONE_1 JMP FLOAT ;
|
|
; --------------------------------
|
|
; "PDL" FUNCTION
|
|
; <<< NOTE: ARG<4 IS NOT CHECKED >>>
|
|
; --------------------------------
|
|
PDL JSR CONINT ; GET # IN X
|
|
JSR MON_PREAD ; READ PADDLE
|
|
JMP SNGFLT ; FLOAT RESULT
|
|
; --------------------------------
|
|
; "DIM" STATEMENT
|
|
; --------------------------------
|
|
NXDIM JSR CHKCOM ; SEPARATED BY COMMAS
|
|
DIM TAX ; NON-ZERO, FLAGS PTRGET DIM CALLED
|
|
JSR PTRGET2 ; ALLOCATE THE ARRAY
|
|
JSR CHRGOT ; NEXT CHAR
|
|
BNE NXDIM ; NOT END OF STATEMENT
|
|
RTS ;
|
|
; --------------------------------
|
|
; PTRGET -- GENERAL VARIABLE SCAN
|
|
;
|
|
; SCANS VARIABLE NAME AT TXTPTR, AND SEARCHES THE
|
|
; VARTAB AND ARYTAB FOR THE NAME.
|
|
; IF NOT FOUND, CREATE VARIABLE OF APPROPRIATE TYPE.
|
|
; RETURN WITH ADDRESS IN VARPNT AND Y,A
|
|
;
|
|
; ACTUAL ACTIVITY CONTROLLED SOMEWHAT BY TWO FLAGS:
|
|
; DIMFLG -- NONZERO IF CALLED FROM "DIM"
|
|
; ELSE = 0
|
|
;
|
|
; SUBFLG -- = $00
|
|
; = $40 IF CALLED FROM "GETARYPT"
|
|
; = $80 IF CALLED FROM "DEF FN"
|
|
; = $C1-DA IF CALLED FROM "FN"
|
|
; --------------------------------
|
|
PTRGET LDX #0 ;
|
|
JSR CHRGOT ; GET FIRST CHAR OF VARIABLE NAME
|
|
; --------------------------------
|
|
PTRGET2 ;
|
|
STX DIMFLG ; X IS NONZERO IF FROM DIM
|
|
; --------------------------------
|
|
PTRGET3 ;
|
|
STA VARNAM ;
|
|
JSR CHRGOT ;
|
|
JSR ISLETC ; IS IT A LETTER?
|
|
BCS NAMOK ; YES, OKAY SO FAR
|
|
BADNAM JMP SYNERR ; NO, SYNTAX ERROR
|
|
NAMOK LDX #0 ;
|
|
STX VALTYP ;
|
|
STX VALTYP+1 ;
|
|
JMP PTRGET4 ; TO BRANCH ACROSS $E000 VECTORS
|
|
; --------------------------------
|
|
; DOS AND MONITOR CALL BASIC AT $E000 AND $E003
|
|
; --------------------------------
|
|
BASIC JMP COLD_START
|
|
BASIC2 JMP RESTART
|
|
BRK ; <<< WASTED BYTE >>>
|
|
; --------------------------------
|
|
PTRGET4
|
|
JSR CHRGET ; SECOND CHAR OF VARIABLE NAME
|
|
BCC L_PTRGET4_1 ; NUMERIC
|
|
JSR ISLETC ; LETTER?
|
|
BCC L_PTRGET4_3 ; NO, END OF NAME
|
|
L_PTRGET4_1 TAX ; SAVE SECOND CHAR OF NAME IN X
|
|
L_PTRGET4_2 JSR CHRGET ; SCAN TO END OF VARIABLE NAME
|
|
BCC L_PTRGET4_2 ; NUMERIC
|
|
JSR ISLETC ;
|
|
BCS L_PTRGET4_2 ; ALPHA
|
|
L_PTRGET4_3 CMP #LOCHAR(`$') ; STRING?
|
|
BNE L_PTRGET4_4 ; NO
|
|
LDA #$FF ;
|
|
STA VALTYP ;
|
|
BNE L_PTRGET4_5 ; ...ALWAYS
|
|
L_PTRGET4_4 CMP #LOCHAR(`%') ; INTEGER?
|
|
BNE L_PTRGET4_6 ; NO
|
|
LDA SUBFLG ; YES; INTEGER VARIABLE ALLOWED?
|
|
BMI BADNAM ; NO, SYNTAX ERROR
|
|
LDA #$80 ; YES
|
|
STA VALTYP+1 ; FLAG INTEGER MODE
|
|
ORA VARNAM ;
|
|
STA VARNAM ; SET SIGN BIT ON VARNAME
|
|
L_PTRGET4_5 TXA ; SECOND CHAR OF NAME
|
|
ORA #$80 ; SET SIGN
|
|
TAX ;
|
|
JSR CHRGET ; GET TERMINATING CHAR
|
|
L_PTRGET4_6 STX VARNAM+1 ; STORE SECOND CHAR OF NAME
|
|
SEC ;
|
|
ORA SUBFLG ; $00 OR $40 IF SUBSCRIPTS OK, ELSE $80
|
|
SBC #$28 ; IF SUBFLG=$00 AND CHAR="("...
|
|
BNE L_PTRGET4_8 ; NOPE
|
|
L_PTRGET4_7 JMP ARRAY ; YES
|
|
L_PTRGET4_8 BIT SUBFLG ; CHECK TOP TWO BITS OF SUBFLG
|
|
BMI L_PTRGET4_9 ; $80
|
|
BVS L_PTRGET4_7 ; $40, CALLED FROM GETARYPT
|
|
L_PTRGET4_9 LDA #0 ; CLEAR SUBFLG
|
|
STA SUBFLG ;
|
|
LDA VARTAB ; START LOWTR AT SIMPLE VARIABLE TABLE
|
|
LDX VARTAB+1 ;
|
|
LDY #0 ;
|
|
L_PTRGET4_10 STX LOWTR+1 ;
|
|
L_PTRGET4_11 STA LOWTR ;
|
|
CPX ARYTAB+1 ; END OF SIMPLE VARIABLES?
|
|
BNE L_PTRGET4_12 ; NO, GO ON
|
|
CMP ARYTAB ; YES; END OF ARRAYS?
|
|
BEQ NAME_NOT_FOUND ; YES, MAKE ONE
|
|
L_PTRGET4_12 LDA VARNAM ; SAME FIRST LETTER?
|
|
CMP (LOWTR),Y ;
|
|
BNE L_PTRGET4_13 ; NOT SAME FIRST LETTER
|
|
LDA VARNAM+1 ; SAME SECOND LETTER?
|
|
INY
|
|
CMP (LOWTR),Y
|
|
BEQ SET_VARPNT_AND_YA ; YES, SAME VARIABLE NAME
|
|
DEY ; NO, BUMP TO NEXT NAME
|
|
L_PTRGET4_13 CLC
|
|
LDA LOWTR
|
|
ADC #7
|
|
BCC L_PTRGET4_11
|
|
INX
|
|
BNE L_PTRGET4_10 ; ...ALWAYS
|
|
; --------------------------------
|
|
; CHECK IF (A) IS ASCII LETTER A-Z
|
|
;
|
|
; RETURN CARRY = 1 IF A-Z
|
|
; = 0 IF NOT
|
|
;
|
|
; <<<NOTE FASTER AND SHORTER CODE: >>>
|
|
; <<< CMP #LOCHAR(`Z')+1 COMPARE HI END
|
|
; <<< BCS L_PTRGET4_1 ABOVE A-Z
|
|
; <<< CMP #LOCHAR(`A') COMPARE LO END
|
|
; <<< RTS C=0 IF LO, C=1 IF A-Z
|
|
; <<<L_PTRGET4_1 CLC C=0 IF HI
|
|
; <<< RTS
|
|
; --------------------------------
|
|
ISLETC CMP #LOCHAR(`A') ; COMPARE LO END
|
|
BCC L_ISLETC_1 ; C=0 IF LOW
|
|
SBC #LOCHAR(`Z')+1 ; PREPARE HI END TEST
|
|
SEC ; TEST HI END, RESTORING (A)
|
|
SBC #255-'Z' ; C=0 IF LO, C=1 IF A-Z
|
|
L_ISLETC_1 RTS
|
|
; --------------------------------
|
|
; VARIABLE NOT FOUND, SO MAKE ONE
|
|
; --------------------------------
|
|
NAME_NOT_FOUND
|
|
PLA ; LOOK AT RETURN ADDRESS ON STACK TO
|
|
PHA ; SEE IF CALLED FROM FRM.VARIABLE
|
|
CMP #<FRM_VARIABLE_CALL
|
|
BNE MAKE_NEW_VARIABLE ; NO
|
|
TSX
|
|
LDA STACK+2,X
|
|
CMP #>FRM_VARIABLE_CALL
|
|
BNE MAKE_NEW_VARIABLE ; NO
|
|
LDA #<C_ZERO ; YES, CALLED FROM FRM.VARIABLE
|
|
LDY #>C_ZERO ; POINT TO A CONSTANT ZERO
|
|
RTS ; NEW VARIABLE USED IN EXPRESSION = 0
|
|
; --------------------------------
|
|
C_ZERO ASM_DATA(00,00) ; INTEGER OR REAL ZERO, OR NULL STRING
|
|
; --------------------------------
|
|
; MAKE A NEW SIMPLE VARIABLE
|
|
;
|
|
; MOVE ARRAYS UP 7 BYTES TO MAKE ROOM FOR NEW VARIABLE
|
|
; ENTER 7-BYTE VARIABLE DATA IN THE HOLE
|
|
; --------------------------------
|
|
MAKE_NEW_VARIABLE
|
|
LDA ARYTAB ; SET UP CALL TO BLTU TO
|
|
LDY ARYTAB+1 ; TO MOVE FROM ARYTAB THRU STREND-1
|
|
STA LOWTR ; 7 BYTES HIGHER
|
|
STY LOWTR+1 ;
|
|
LDA STREND ;
|
|
LDY STREND+1 ;
|
|
STA HIGHTR ;
|
|
STY HIGHTR+1 ;
|
|
CLC ;
|
|
ADC #7 ;
|
|
BCC L_MAKE_NEW_VARIABLE_1 ;
|
|
INY ;
|
|
L_MAKE_NEW_VARIABLE_1 STA ARYPNT ;
|
|
STY ARYPNT+1 ;
|
|
JSR BLTU ; MOVE ARRAY BLOCK UP
|
|
LDA ARYPNT ; STORE NEW START OF ARRAYS
|
|
LDY ARYPNT+1 ;
|
|
INY ;
|
|
STA ARYTAB ;
|
|
STY ARYTAB+1 ;
|
|
LDY #0 ;
|
|
LDA VARNAM ; FIRST CHAR OF NAME
|
|
STA (LOWTR),Y ;
|
|
INY ;
|
|
LDA VARNAM+1 ; SECOND CHAR OF NAME
|
|
STA (LOWTR),Y ;
|
|
LDA #0 ; SET FIVE-BYTE VALUE TO 0
|
|
INY ;
|
|
STA (LOWTR),Y ;
|
|
INY ;
|
|
STA (LOWTR),Y ;
|
|
INY ;
|
|
STA (LOWTR),Y ;
|
|
INY ;
|
|
STA (LOWTR),Y ;
|
|
INY ;
|
|
STA (LOWTR),Y ;
|
|
; --------------------------------
|
|
; PUT ADDRESS OF VALUE OF VARIABLE IN VARPNT AND Y,A
|
|
; --------------------------------
|
|
SET_VARPNT_AND_YA ;
|
|
LDA LOWTR ; LOWTR POINTS AT NAME OF VARIABLE,
|
|
CLC ; SO ADD 2 TO GET TO VALUE
|
|
ADC #2 ;
|
|
LDY LOWTR+1 ;
|
|
BCC L_SET_VARPNT_AND_YA_1 ;
|
|
INY ;
|
|
L_SET_VARPNT_AND_YA_1 STA VARPNT ; ADDRESS IN VARPNT AND Y,A
|
|
STY VARPNT+1 ;
|
|
RTS ;
|
|
; --------------------------------
|
|
; COMPUTE ADDRESS OF FIRST VALUE IN ARRAY
|
|
; ARYPNT = (LOWTR) + #DIMS*2 + 5
|
|
; --------------------------------
|
|
GETARY LDA NUMDIM ; GET # OF DIMENSIONS
|
|
; --------------------------------
|
|
GETARY2 ;
|
|
ASL ; #DIMS*2 (SIZE OF EACH DIM IN 2 BYTES)
|
|
ADC #5 ; + 5 (2 FOR NAME, 2 FOR OFFSET TO NEXT
|
|
; ARRAY, AND 1 FOR #DIMS
|
|
ADC LOWTR ; ADDRESS OF TH IS ARRAY IN ARYTAB
|
|
LDY LOWTR+1 ;
|
|
BCC L_GETARY2_1 ;
|
|
INY ;
|
|
L_GETARY2_1 STA ARYPNT ; ADDRESS OF FIRST VALUE IN ARRAY
|
|
STY ARYPNT+1 ;
|
|
RTS ;
|
|
; --------------------------------
|
|
|
|
NEG32768 ASM_DATA($90,$80,$00,$00) ; -32768.00049 IN FLOATING POINT
|
|
; <<< MEANT TO BE -32768, WHICH WOULD BE 9080000000 >>>
|
|
; <<< 1 BYTE SHORT, SO PICKS UP $20 FROM NEXT INSTRUCTION
|
|
; --------------------------------
|
|
; EVALUATE NUMERIC FORMULA AT TXTPTR
|
|
; CONVERTING RESULT TO INTEGER 0 <= X <= 32767
|
|
; IN FAC+3,4
|
|
; --------------------------------
|
|
MAKINT JSR CHRGET
|
|
JSR FRMNUM
|
|
; --------------------------------
|
|
; CONVERT FAC TO INTEGER
|
|
; MUST BE POSITIVE AND LESS THAN 32768
|
|
; --------------------------------
|
|
MKINT LDA FAC_SIGN ; ERROR IF -
|
|
BMI MI1
|
|
; --------------------------------
|
|
; CONVERT FAC TO INTEGER
|
|
; MUST BE -32767 <= FAC <= 32767
|
|
; --------------------------------
|
|
AYINT LDA FAC ; EXPONENT OF VALUE IN FAC
|
|
CMP #$90 ; ABS(VALUE) < 32768?
|
|
BCC MI2 ; YES, OK FOR INTEGER
|
|
LDA #<NEG32768 ; NO; NEXT FEW LINES ARE SUPPOSED TO
|
|
LDY #>NEG32768 ; ALLOW -32768 ($8000), BUT DO NOT!
|
|
JSR FCOMP ; BECAUSE COMPARED TO -32768.00049
|
|
; <<< BUG: A=-32768.00049:A%=A IS ACCEPTED >>>
|
|
; <<< BUT PRINT A,A% SHOWS THAT >>>
|
|
; <<< A=-32768.0005 (OK), A%=32767 >>>
|
|
; <<< WRONG! WRONG! WRONG! >>>
|
|
; --------------------------------
|
|
MI1 BNE IQERR ; ILLEGAL QUANTITY
|
|
MI2 JMP QINT ; CONVERT TO INTEGER
|
|
; --------------------------------
|
|
; LOCATE ARRAY ELEMENT OR CREATE AN ARRAY
|
|
; --------------------------------
|
|
ARRAY LDA SUBFLG ; SUBSCRIPTS GIVEN?
|
|
BNE L_ARRAY_2 ; NO
|
|
; --------------------------------
|
|
; PARSE THE SUBSCRIPT LIST
|
|
; --------------------------------
|
|
LDA DIMFLG ; YES
|
|
ORA VALTYP+1 ; SET HIGH BIT IF %
|
|
PHA ; SAVE VALTYP AND DIMFLG ON STACK
|
|
LDA VALTYP ;
|
|
PHA ;
|
|
LDY #0 ; COUNT # DIMENSIONS IN Y-REG
|
|
L_ARRAY_1 TYA ; SAVE #DIMS ON STACK
|
|
PHA ;
|
|
LDA VARNAM+1 ; SAVE VARIABLE NAME ON STACK
|
|
PHA ;
|
|
LDA VARNAM ;
|
|
PHA ;
|
|
JSR MAKINT ; EVALUATE SUBSCRIPT AS INTEGER
|
|
PLA ; RESTORE VARIABLE NAME
|
|
STA VARNAM ;
|
|
PLA ;
|
|
STA VARNAM+1 ;
|
|
PLA ; RESTORE # DIMS TO Y-REG
|
|
TAY ;
|
|
TSX ; COPY VALTYP AND DIMFLG ON STACK
|
|
LDA STACK+2,X ; TO LEAVE ROOM FOR THE SUBSCRIPT
|
|
PHA ;
|
|
LDA STACK+1,X ;
|
|
PHA ;
|
|
LDA FAC+3 ; GET SUBSCRIPT VALUE AND PLACE IN THE
|
|
STA STACK+2,X ; STACK WHERE VALTYP & DIMFLG WERE
|
|
LDA FAC+4 ;
|
|
STA STACK+1,X ;
|
|
INY ; COUNT THE SUBSCRIPT
|
|
JSR CHRGOT ; NEXT CHAR
|
|
CMP #LOCHAR(`,') ;
|
|
BEQ L_ARRAY_1 ; COMMA, PARSE ANOTHER SUBSCRIPT
|
|
STY NUMDIM ; NO MORE SUBSCRIPTS, SAVE #
|
|
JSR CHKCLS ; NOW NEED ")"
|
|
PLA ; RESTORE VALTYPE AND DIMFLG
|
|
STA VALTYP ;
|
|
PLA ;
|
|
STA VALTYP+1 ;
|
|
AND #$7F ; ISOLATE DIMFLG
|
|
STA DIMFLG ;
|
|
; --------------------------------
|
|
; SEARCH ARRAY TABLE FOR THIS ARRAY NAME
|
|
; --------------------------------
|
|
L_ARRAY_2 LDX ARYTAB ; (A,X) = START OF ARRAY TABLE
|
|
LDA ARYTAB+1 ;
|
|
L_ARRAY_3 STX LOWTR ; USE LOWTR FOR RUNNING POINTER
|
|
STA LOWTR+1 ;
|
|
CMP STREND+1 ; DID WE REACH THE END OF ARRAYS YET?
|
|
BNE L_ARRAY_4 ; NO, KEEP SEARCHING
|
|
CPX STREND ;
|
|
BEQ MAKE_NEW_ARRAY ; YES, THIS IS A NEW ARRAY NAME
|
|
L_ARRAY_4 LDY #0 ; POINT AT 1ST CHAR OF ARRAY NAME
|
|
LDA (LOWTR),Y ; GET 1ST CHAR OF NAME
|
|
INY ; POINT AT 2ND CHAR
|
|
CMP VARNAM ; 1ST CHAR SAME?
|
|
BNE L_ARRAY_5 ; NO, MOVE TO NEXT ARRAY
|
|
LDA VARNAM+1 ; YES, TRY 2ND CHAR
|
|
CMP (LOWTR),Y ; SAME?
|
|
BEQ USE_OLD_ARRAY ; YES, ARRAY FOUND
|
|
L_ARRAY_5 INY ; POINT AT OFFSET TO NEXT ARRAY
|
|
LDA (LOWTR),Y ; ADD OFFSET TO RUNNING POINTER
|
|
CLC
|
|
ADC LOWTR
|
|
TAX
|
|
INY
|
|
LDA (LOWTR),Y
|
|
ADC LOWTR+1
|
|
BCC L_ARRAY_3 ; ...ALWAYS
|
|
; --------------------------------
|
|
; ERROR: BAD SUBSCRIPTS
|
|
; --------------------------------
|
|
SUBERR LDX #ERR_BADSUBS
|
|
ASM_DATA($2C) ; TRICK TO SKIP NEXT LINE
|
|
; --------------------------------
|
|
; ERROR: ILLEGAL QUANTITY
|
|
; --------------------------------
|
|
IQERR LDX #ERR_ILLQTY
|
|
JER JMP ERROR
|
|
; --------------------------------
|
|
; FOUND THE ARRAY
|
|
; --------------------------------
|
|
USE_OLD_ARRAY
|
|
LDX #ERR_REDIMD ; SET UP FOR REDIM'D ARRAY ERROR
|
|
LDA DIMFLG ; CALLED FROM "DIM" STATEMENT?
|
|
BNE JER ; YES, ERROR
|
|
LDA SUBFLG ; NO, CHECK IF ANY SUBSCRIPTS
|
|
BEQ L_USE_OLD_ARRAY_1 ; YES, NEED TO CHECK THE NUMBER
|
|
SEC ; NO, SIGNAL ARRAY FOUND
|
|
RTS
|
|
; --------------------------------
|
|
L_USE_OLD_ARRAY_1 JSR GETARY ; SET (ARYPNT) = ADDR OF FIRST ELEMENT
|
|
LDA NUMDIM ; COMPARE NUMBER OF DIMENSIONS
|
|
LDY #4
|
|
CMP (LOWTR),Y
|
|
BNE SUBERR ; NOT SAME, SUBSCRIPT ERROR
|
|
JMP FIND_ARRAY_ELEMENT
|
|
; --------------------------------
|
|
; --------------------------------
|
|
; CREATE A NEW ARRAY, UNLESS CALLED FROM GETARYPT
|
|
; --------------------------------
|
|
MAKE_NEW_ARRAY
|
|
LDA SUBFLG ; CALLED FROM GETARYPT?
|
|
BEQ L_MAKE_NEW_ARRAY_1 ; NO
|
|
LDX #ERR_NODATA ; YES, GIVE "OUT OF DATA" ERROR
|
|
JMP ERROR
|
|
L_MAKE_NEW_ARRAY_1 JSR GETARY ; PUT ADDR OF 1ST ELEMENT IN ARYPNT
|
|
JSR REASON ; MAKE SURE ENOUGH MEMORY LEFT
|
|
; --------------------------------
|
|
; <<< NEXT 3 LINES COULD BE WRITTEN: >>>
|
|
; LDY #0
|
|
; STY STRNG2+1
|
|
; --------------------------------
|
|
LDA #0 ; POINT Y-REG AT VARIABLE NAME SLOT
|
|
TAY ;
|
|
STA STRNG2+1 ; START SIZE COMPUTATION
|
|
LDX #5 ; ASSUME 5-BYTES PER ELEMENT
|
|
LDA VARNAM ; STUFF VARIABLE NAME IN ARRAY
|
|
STA (LOWTR),Y ;
|
|
BPL L_MAKE_NEW_ARRAY_2 ; NOT INTEGER ARRAY
|
|
DEX ; INTEGER ARRAY, DECR. SIZE TO 4-BYTES
|
|
L_MAKE_NEW_ARRAY_2 INY ; POINT Y-REG AT NEXT CHAR OF NAME
|
|
LDA VARNAM+1 ; REST OF ARRAY NAME
|
|
STA (LOWTR),Y ;
|
|
BPL L_MAKE_NEW_ARRAY_3 ; REAL ARRAY, STICK WITH SIZE = 5 BYTES
|
|
DEX ; INTEGER OR STRING ARRAY, ADJUST SIZE
|
|
DEX ; TO INTEGER=3, STRING=2 BYTES
|
|
L_MAKE_NEW_ARRAY_3 STX STRNG2 ; STORE LOW-BYTE OF ARRAY ELEMENT SIZE
|
|
LDA NUMDIM ; STORE NUMBER OF DIMENSIONS
|
|
INY ; IN 5TH BYTE OF ARRAY
|
|
INY ;
|
|
INY ;
|
|
STA (LOWTR),Y ;
|
|
L_MAKE_NEW_ARRAY_4 LDX #11 ; DEFAULT DIMENSION = 11 ELEMENTS
|
|
LDA #0 ; FOR HI-BYTE OF DIMENSION IF DEFAULT
|
|
BIT DIMFLG ; DIMENSIONED ARRAY?
|
|
BVC L_MAKE_NEW_ARRAY_5 ; NO, USE DEFAULT VALUE
|
|
PLA ; GET SPECIFIED DIM IN A,X
|
|
CLC ; # ELEMENTS IS 1 LARGER THAN
|
|
ADC #1 ; DIMENSION VALUE
|
|
TAX ;
|
|
PLA ;
|
|
ADC #0 ;
|
|
L_MAKE_NEW_ARRAY_5 INY ; ADD THIS DIMENSION TO ARRAY DESCRIPTOR
|
|
STA (LOWTR),Y
|
|
INY
|
|
TXA
|
|
STA (LOWTR),Y
|
|
JSR MULTIPLY_SUBSCRIPT ; MULTIPLY THIS
|
|
; DIMENSION BY RUNNING SIZE
|
|
; ((LOWTR)) * (STRNG2) --> A,X
|
|
STX STRNG2 ; STORE RUNNING SIZE IN STRNG2
|
|
STA STRNG2+1 ;
|
|
LDY INDEX ; RETRIEVE Y SAVED BY MULTIPLY.SUBSCRIPT
|
|
DEC NUMDIM ; COUNT DOWN # DIMS
|
|
BNE L_MAKE_NEW_ARRAY_4 ; LOOP TILL DONE
|
|
; --------------------------------
|
|
; NOW A,X HAS TOTAL # BYTES OF ARRAY ELEMENTS
|
|
; --------------------------------
|
|
ADC ARYPNT+1 ; COMPUTE ADDRESS OF END OF THIS ARRAY
|
|
BCS GME ; ...TOO LARGE, ERROR
|
|
STA ARYPNT+1 ;
|
|
TAY ;
|
|
TXA ;
|
|
ADC ARYPNT ;
|
|
BCC L_MAKE_NEW_ARRAY_6 ;
|
|
INY ;
|
|
BEQ GME ; ...TOO LARGE, ERROR
|
|
L_MAKE_NEW_ARRAY_6 JSR REASON ; MAKE SURE THERE IS ROOM UP TO Y,A
|
|
STA STREND ; THERE IS ROOM SO SAVE NEW END OF TABLE
|
|
STY STREND+1 ; AND ZERO THE ARRAY
|
|
LDA #0 ;
|
|
INC STRNG2+1 ; PREPARE FOR FAST ZEROING LOOP
|
|
LDY STRNG2 ; # BYTES MOD 256
|
|
BEQ L_MAKE_NEW_ARRAY_8 ; FULL PAGE
|
|
L_MAKE_NEW_ARRAY_7 DEY ; CLEAR PAGE FULL
|
|
STA (ARYPNT),Y
|
|
BNE L_MAKE_NEW_ARRAY_7
|
|
L_MAKE_NEW_ARRAY_8 DEC ARYPNT+1 ; POINT TO NEXT PAGE
|
|
DEC STRNG2+1 ; COUNT THE PAGES
|
|
BNE L_MAKE_NEW_ARRAY_7 ; STILL MORE TO CLEAR
|
|
INC ARYPNT+1 ; RECOVER LAST DEC, POINT AT 1ST ELEMENT
|
|
SEC ;
|
|
LDA STREND ; COMPUTE OFFSET TO END OF ARRAYS
|
|
SBC LOWTR ; AND STORE IN ARRAY DESCRIPTOR
|
|
LDY #2 ;
|
|
STA (LOWTR),Y ;
|
|
LDA STREND+1 ;
|
|
INY ;
|
|
SBC LOWTR+1 ;
|
|
STA (LOWTR),Y ;
|
|
LDA DIMFLG ; WAS THIS CALLED FROM "DIM" STATEMENT?
|
|
BNE RTS_9 ; YES, WE ARE FINISHED
|
|
INY ; NO, NOW NEED TO FIND THE ELEMENT
|
|
; --------------------------------
|
|
; FIND SPECIFIED ARRAY ELEMENT
|
|
;
|
|
; (LOWTR),Y POINTS AT # OF DIMS IN ARRAY DESCRIPTOR
|
|
; THE SUBSCRIPTS ARE ALL ON THE STACK AS INTEGERS
|
|
; --------------------------------
|
|
FIND_ARRAY_ELEMENT
|
|
LDA (LOWTR),Y ; GET # OF DIMENSIONS
|
|
STA NUMDIM ;
|
|
LDA #0 ; ZERO SUBSCRIPT ACCUMULATOR
|
|
STA STRNG2 ;
|
|
FAE_1 STA STRNG2+1 ;
|
|
INY ;
|
|
PLA ; PULL NEXT SUBSCRIPT FROM STACK
|
|
TAX ; SAVE IN FAC+3,4
|
|
STA FAC+3 ; AND COMPARE WITH DIMENSIONED SIZE
|
|
PLA ;
|
|
STA FAC+4 ;
|
|
CMP (LOWTR),Y ;
|
|
BCC FAE_2 ; SUBSCRIPT NOT TOO LARGE
|
|
BNE GSE ; SUBSCRIPT IS TOO LARGE
|
|
INY ; CHECK LOW-BYTE OF SUBSCRIPT
|
|
TXA ;
|
|
CMP (LOWTR),Y ;
|
|
BCC FAE_3 ; NOT TOO LARGE
|
|
; --------------------------------
|
|
GSE JMP SUBERR ; BAD SUBSCRIPTS ERROR
|
|
GME JMP MEMERR ; MEM FULL ERROR
|
|
; --------------------------------
|
|
FAE_2 INY ; BUMP POINTER INTO DESCRIPTOR
|
|
FAE_3 LDA STRNG2+1 ; BYPASS MULTIPLICATION IF VALUE SO
|
|
ORA STRNG2 ; FAR = 0
|
|
CLC ;
|
|
BEQ L_FAE_3_1 ; IT IS ZERO SO FAR
|
|
JSR MULTIPLY_SUBSCRIPT ; NOT ZERO, SO MULTIPLY
|
|
TXA ; ADD CURRENT SUBSCRIPT
|
|
ADC FAC+3 ;
|
|
TAX ;
|
|
TYA ;
|
|
LDY INDEX ; RETRIEVE Y SAVED BY MULTIPLY.SUBSCRIPT
|
|
L_FAE_3_1 ADC FAC+4 ; FINISH ADDING CURRENT SUBSCRIPT
|
|
STX STRNG2 ; STORE ACCUMULATED OFFSET
|
|
DEC NUMDIM ; LAST SUBSCRIPT YET?
|
|
BNE FAE_1 ; NO, LOOP TILL DONE
|
|
STA STRNG2+1 ; YES, NOW MULTIPLY BE ELEMENT SIZE
|
|
LDX #5 ; START WITH SIZE = 5
|
|
LDA VARNAM ; DETERMINE VARIABLE TYPE
|
|
BPL L_FAE_3_2 ; NOT INTEGER
|
|
DEX ; INTEGER, BACK DOWN SIZE TO 4 BYTES
|
|
L_FAE_3_2 LDA VARNAM+1 ; DISCRIMINATE BETWEEN REAL AND STR
|
|
BPL L_FAE_3_3 ; IT IS REAL
|
|
DEX ; SIZE = 3 IF STRING, =2 IF INTEGER
|
|
DEX ;
|
|
L_FAE_3_3 STX RESULT+2 ; SET UP MULTIPLIER
|
|
LDA #0 ; HI-BYTE OF MULTIPLIER
|
|
JSR MULTIPLY_SUBS_1 ; (STRNG2) BY ELEMENT SIZE
|
|
TXA ; ADD ACCUMULATED OFFSET
|
|
ADC ARYPNT ; TO ADDRESS OF 1ST ELEMENT
|
|
STA VARPNT ; TO GET ADDRESS OF SPECIFIED ELEMENT
|
|
TYA ;
|
|
ADC ARYPNT+1 ;
|
|
STA VARPNT+1 ;
|
|
TAY ; RETURN WITH ADDR IN VARPNT
|
|
LDA VARPNT ; AND IN Y,A
|
|
RTS_9 RTS ;
|
|
; --------------------------------
|
|
; MULTIPLY (STRNG2) BY ((LOWTR),Y)
|
|
; LEAVING PRODUCT IN A,X. (HI-BYTE ALSO IN Y.)
|
|
; USED ONLY BY ARRAY SUBSCRIPT ROUTINES
|
|
; --------------------------------
|
|
MULTIPLY_SUBSCRIPT
|
|
STY INDEX ; SAVE Y-REG
|
|
LDA (LOWTR),Y ; GET MULTIPLIER
|
|
STA RESULT+2 ; SAVE IN RESULT+2,3
|
|
DEY ;
|
|
LDA (LOWTR),Y ;
|
|
; --------------------------------
|
|
MULTIPLY_SUBS_1 ;
|
|
STA RESULT+3 ; LOW BYTE OF MULTIPLIER
|
|
LDA #16 ; MULTIPLY 16 BITS
|
|
STA INDX ;
|
|
LDX #0 ; PRODUCT = 0 INITIALLY
|
|
LDY #0 ;
|
|
L_MULTIPLY_SUBS_1_1 TXA ; DOUBLE PRODUCT
|
|
ASL ; LOW BYTE
|
|
TAX ;
|
|
TYA ; HIGH BYTE
|
|
ROL ; IF TOO LARGE, SET CARRY
|
|
TAY ;
|
|
BCS GME ; TOO LARGE, "MEM FULL ERROR"
|
|
ASL STRNG2 ; NEXT BIT OF MUTLPLICAND
|
|
ROL STRNG2+1 ; INTO CARRY
|
|
BCC L_MULTIPLY_SUBS_1_2 ; BIT=0, DON'T NEED TO ADD
|
|
CLC ; BIT=1, ADD INTO PARTIAL PRODUCT
|
|
TXA ;
|
|
ADC RESULT+2 ;
|
|
TAX ;
|
|
TYA ;
|
|
ADC RESULT+3 ;
|
|
TAY ;
|
|
BCS GME ; TOO LARGE, "MEM FULL ERROR"
|
|
L_MULTIPLY_SUBS_1_2 DEC INDX ; 16-BITS YET?
|
|
BNE L_MULTIPLY_SUBS_1_1 ; NO, KEEP SHUFFLING
|
|
RTS ; YES, PRODUCT IN Y,X AND A,X
|
|
; --------------------------------
|
|
; "FRE" FUNCTION
|
|
;
|
|
; COLLECTS GARBAGE AND RETURNS # BYTES OF MEMORY LEFT
|
|
; --------------------------------
|
|
FRE LDA VALTYP ; LOOK AT VALUE OF ARGUMENT
|
|
BEQ L_FRE_1 ; =0 MEANS REAL, =$FF MEANS STRING
|
|
JSR FREFAC ; STRING, SO SET IT FREE IS TEMP
|
|
L_FRE_1 JSR GARBAG ; COLLECT ALL THE GARBAGE IN SIGHT
|
|
SEC ; COMPUTE SPACE BETWEEN ARRAYS AND
|
|
LDA FRETOP ; STRING TEMP AREA
|
|
SBC STREND ;
|
|
TAY ;
|
|
LDA FRETOP+1 ;
|
|
SBC STREND+1 ; FREE SPACE IN Y,A
|
|
; FALL INTO GIVAYF TO FLOAT THE VALUE
|
|
; NOTE THAT VALUES OVER 32767 WILL RETURN AS NEGATIVE
|
|
; --------------------------------
|
|
; FLOAT THE SIGNED INTEGER IN A,Y
|
|
; --------------------------------
|
|
GIVAYF LDX #0 ; MARK FAC VALUE TYPE REAL
|
|
STX VALTYP ;
|
|
STA FAC+1 ; SAVE VALUE FROM A,Y IN MANTISSA
|
|
STY FAC+2 ;
|
|
LDX #$90 ; SET EXPONENT TO 2^16
|
|
JMP FLOAT_1 ; CONVERT TO SIGNED FP
|
|
; --------------------------------
|
|
; "POS" FUNCTION
|
|
;
|
|
; RETURNS CURRENT LINE POSITION FROM MON.CH
|
|
; --------------------------------
|
|
POS LDY MON_CH ; GET A,Y = (MON.CH, GO TO GIVAYF
|
|
; --------------------------------
|
|
; FLOAT (Y) INTO FAC, GIVING VALUE 0-255
|
|
; --------------------------------
|
|
SNGFLT LDA #0 ; MSB = 0
|
|
SEC ; <<< NO PURPOSE WHATSOEVER >>>
|
|
BEQ GIVAYF ; ...ALWAYS
|
|
; --------------------------------
|
|
; CHECK FOR DIRECT OR RUNNING MODE
|
|
; GIVING ERROR IF DIRECT MODE
|
|
; --------------------------------
|
|
ERRDIR LDX CURLIN+1 ; =$FF IF DIRECT MODE
|
|
INX ; MAKES $FF INTO ZERO
|
|
BNE RTS_9 ; RETURN IF RUNNING MODE
|
|
LDX #ERR_ILLDIR ; DIRECT MODE, GIVE ERROR
|
|
ASM_DATA($2C) ; TRICK TO SKIP NEXT 2 BYTES
|
|
; --------------------------------
|
|
UNDFNC LDX #ERR_UNDEFFUNC ; UNDEFINDED FUNCTION ERROR
|
|
JMP ERROR
|
|
; --------------------------------
|
|
; "DEF" STATEMENT
|
|
; --------------------------------
|
|
DEF JSR FNC_ ; PARSE "FN", FUNCTION NAME
|
|
JSR ERRDIR ; ERROR IF IN DIRECT MODE
|
|
JSR CHKOPN ; NEED "("
|
|
LDA #$80 ; FLAG PTRGET THAT CALLED FROM "DEF FN"
|
|
STA SUBFLG ; ALLOW ONLY SIMPLE FP VARIABLE FOR ARG
|
|
JSR PTRGET ; GET PNTR TO ARGUMENT
|
|
JSR CHKNUM ; MUST BE NUMERIC
|
|
JSR CHKCLS ; MUST HAVE ")" NOW
|
|
LDA #TOKENEQUUAL ; NOW NEED "="
|
|
JSR SYNCHR ; OR ELSE SYNTAX ERROR
|
|
PHA ; SAVE CHAR AFTER "="
|
|
LDA VARPNT+1 ; SAVE PNTR TO ARGUMENT
|
|
PHA
|
|
LDA VARPNT
|
|
PHA
|
|
LDA TXTPTR+1 ; SAVE TXTPTR
|
|
PHA
|
|
LDA TXTPTR
|
|
PHA
|
|
JSR DATA ; SCAN TO NEXT STATEMENT
|
|
JMP FNCDATA ; STORE ABOVE 5 BYTES IN "VALUE"
|
|
; --------------------------------
|
|
; COMMON ROUTINE FOR "DEFFN" AND "FN", TO
|
|
; PARSE "FN" AND THE FUNCTION NAME
|
|
; --------------------------------
|
|
FNC_ LDA #TOKEN_FN ; MUST NOW SEE "FN" TOKEN
|
|
JSR SYNCHR ; OR ELSE SYNTAX ERROR
|
|
ORA #$80 ; SET SIGN BIT ON 1ST CHAR OF NAME,
|
|
STA SUBFLG ; MAKING $C0 < SUBFLG < $DB
|
|
JSR PTRGET3 ; WHICH TELLS PTRGET WHO CALLED
|
|
STA FNCNAM ; FOUND VALID FUNCTION NAME, SO
|
|
STY FNCNAM+1 ; SAVE ADDRESS
|
|
JMP CHKNUM ; MUST BE NUMERIC
|
|
; --------------------------------
|
|
; "FN" FUNCTION CALL
|
|
; --------------------------------
|
|
FUNCT JSR FNC_ ; PARSE "FN", FUNCTION NAME
|
|
LDA FNCNAM+1 ; STACK FUNCTION ADDRESS
|
|
PHA ; IN CASE OF A NESTED FN CALL
|
|
LDA FNCNAM ;
|
|
PHA ;
|
|
JSR PARCHK ; MUST NOW HAVE "(EXPRESSION)"
|
|
JSR CHKNUM ; MUST BE NUMERIC EXPRESSION
|
|
PLA ; GET FUNCTION ADDRESS BACK
|
|
STA FNCNAM ;
|
|
PLA ;
|
|
STA FNCNAM+1 ;
|
|
LDY #2 ; POINT AT ADD OF ARGUMENT VARIABLE
|
|
LDA (FNCNAM),Y
|
|
STA VARPNT
|
|
TAX
|
|
INY
|
|
LDA (FNCNAM),Y
|
|
BEQ UNDFNC ; UNDEFINED FUNCTION
|
|
STA VARPNT+1
|
|
INY ; Y=4 NOW
|
|
L_FUNCT_1 LDA (VARPNT),Y ; SAVE OLD VALUE OF ARGUMENT VARIABLE
|
|
PHA ; ON STACK, IN CASE ALSO USED AS
|
|
DEY ; A NORMAL VARIABLE!
|
|
BPL L_FUNCT_1
|
|
LDY VARPNT+1 ; (Y,X)= ADDRESS, STORE FAC IN VARIABLE
|
|
JSR STORE_FACDB_YX_ROUNDED
|
|
LDA TXTPTR+1 ; REMEMBER TXTPTR AFTER FN CALL
|
|
PHA
|
|
LDA TXTPTR
|
|
PHA
|
|
LDA (FNCNAM),Y ; Y=0 FROM MOVMF
|
|
STA TXTPTR ; POINT TO FUNCTION DEF'N
|
|
INY
|
|
LDA (FNCNAM),Y
|
|
STA TXTPTR+1
|
|
LDA VARPNT+1 ; SAVE ADDRESS OF ARGUMENT VARIABLE
|
|
PHA ;
|
|
LDA VARPNT ;
|
|
PHA ;
|
|
JSR FRMNUM ; EVALUATE THE FUNCTION EXPRESSION
|
|
PLA ; GET ADDRESS OF ARGUMENT VARIABLE
|
|
STA FNCNAM ; AND SAVE IT
|
|
PLA ;
|
|
STA FNCNAM+1 ;
|
|
JSR CHRGOT ; MUST BE AT ":" OR EOL
|
|
BEQ L_FUNCT_2 ; WE ARE
|
|
JMP SYNERR ; WE ARE NOT, SLYNTAX ERROR
|
|
L_FUNCT_2 PLA ; RETRIEVE TXTPTR AFTER "FN" CALL
|
|
STA TXTPTR
|
|
PLA
|
|
STA TXTPTR+1
|
|
; STACK NOW HAS 5-BYTE VALUE
|
|
; OF THE ARGUMENT VARIABLE,
|
|
; AND FNCNAM POINTS AT THE VARIABLE
|
|
; --------------------------------
|
|
; STORE FIVE BYTES FROM STACK AT (FNCNAM)
|
|
; --------------------------------
|
|
FNCDATA
|
|
LDY #0
|
|
PLA
|
|
STA (FNCNAM),Y
|
|
PLA
|
|
INY
|
|
STA (FNCNAM),Y
|
|
PLA
|
|
INY
|
|
STA (FNCNAM),Y
|
|
PLA
|
|
INY
|
|
STA (FNCNAM),Y
|
|
PLA
|
|
INY
|
|
STA (FNCNAM),Y
|
|
RTS
|
|
; --------------------------------
|
|
; "STR$" FUNCTION
|
|
; --------------------------------
|
|
STR JSR CHKNUM ; EXPRESSION MUST BE NUMERIC
|
|
LDY #0 ; START STRING AT STACK-1 ($00FF)
|
|
; SO STRLIT CAN DIFFRENTIATE STR$ CALLS
|
|
JSR FOUT_1 ; CONVERT FAC TO STRING
|
|
PLA ; POP RETURN OFF STACK
|
|
PLA ;
|
|
LDA #<STACK-1 ; POINT TO STACK-1
|
|
LDY #>STACK-1 ; (WHICH=0)
|
|
BEQ STRLIT ; ...ALWAYS, CREATE DESC & MOVE STRING
|
|
; --------------------------------
|
|
; GET SPACE AND MAKE DESCRIPTOR FOR STRING WHOSE
|
|
; ADDRESS IS IN FAC+3,4 AND WHOSE LENGTH IS IN A-REG
|
|
; --------------------------------
|
|
STRINI LDX FAC+3 ; Y,X = STRING ADDRESS
|
|
LDY FAC+4 ;
|
|
STX DSCPTR ;
|
|
STY DSCPTR+1 ;
|
|
; --------------------------------
|
|
; GET SPACE AND MAKE DESCRIPTOR FOR STRING WHOSE
|
|
; ADDRESS IS IN Y,X AND WHOSE LENGTH IS IN A-REG
|
|
; --------------------------------
|
|
STRSPA JSR GETSPA ; A HOLDS LENGTH
|
|
STX FAC+1 ; SAVE DESCRIPTOR IN FAC
|
|
STY FAC+2 ; ---FAC--- --FAC+1-- --FAC+2--
|
|
STA FAC ; <LENGTH> <ADDR-LO> <ADDR-HI>
|
|
RTS ;
|
|
; --------------------------------
|
|
; BUILD A DESCRIPTOR FOR STRING STARTING AT Y,A
|
|
; AND TERMINATED BY $00 OR QUOTATION MARK
|
|
; RETURN WITH DESCRIPTOR IN A TEMPORARY
|
|
; AND ADDRESS OF DESCRIPTOR IN FAC+3,4
|
|
; --------------------------------
|
|
STRLIT LDX #$22 ; SET UP LITERAL SCAN TO STOP ON
|
|
STX CHARAC ; QUOTATION MARK OR $00
|
|
STX ENDCHR ;
|
|
; --------------------------------
|
|
; BUILD A DESCRIPTOR FOR STRING STARTING AT Y,A
|
|
; AND TERMINATED BY $00, (CHARAC), OR (ENDCHR)
|
|
;
|
|
; RETURN WITH DESCRIPTOR IN A TEMPORARY
|
|
; AND ADDRESS OF DESCRIPTOR IN FAC+3,4
|
|
; --------------------------------
|
|
STRLT2 STA STRNG1 ; SAVE ADDRESS OF STRING
|
|
STY STRNG1+1 ;
|
|
STA FAC+1 ; ...AGAIN
|
|
STY FAC+2 ;
|
|
LDY #$FF ;
|
|
L_STRLT2_1 INY ; FIND END OF STRING
|
|
LDA (STRNG1),Y ; NEXT STRING CHAR
|
|
BEQ L_STRLT2_3 ; END OF STRING
|
|
CMP CHARAC ; ALTERNATE TERMINATOR # 1?
|
|
BEQ L_STRLT2_2 ; YES
|
|
CMP ENDCHR ; ALTERNATE TERMINATOR # 2?
|
|
BNE L_STRLT2_1 ; NO, KEEP SCANNING
|
|
L_STRLT2_2 CMP #$22 ; IS STRING ENDED WITH QUOTE MARK?
|
|
BEQ L_STRLT2_4 ; YES, C=1 TO INCLUDE " IN STRING
|
|
L_STRLT2_3 CLC ;
|
|
L_STRLT2_4 STY FAC ; SAVE LENGTH
|
|
TYA ;
|
|
ADC STRNG1 ; COMPUTE ADDRESS OF END OF STRING
|
|
STA STRNG2 ; (OF 00 BYTE, OR JUST AFTER ")
|
|
LDX STRNG1+1 ;
|
|
BCC L_STRLT2_5 ;
|
|
INX ;
|
|
L_STRLT2_5 STX STRNG2+1 ;
|
|
LDA STRNG1+1 ; WHERE DOES THE STRING START?
|
|
BEQ L_STRLT2_6 ; PAGE 0, MUST BE FROM STR$ FUNCTION
|
|
CMP #2 ; PAGE 2?
|
|
BNE PUTNEW ; NO, NOT PAGE 0 OR 2
|
|
L_STRLT2_6 TYA ; LENGTH OF STRING
|
|
JSR STRINI ; MAKE SPACE FOR STRING
|
|
LDX STRNG1 ;
|
|
LDY STRNG1+1 ;
|
|
JSR MOVSTR ; MOVE IT IN
|
|
; --------------------------------
|
|
; STORE DESCRIPTOR IN TEMPORARY DESCRIPTOR STACK
|
|
;
|
|
; THE DESCRIPTOR IS NOW IN FAC, FAC+1, FAC+2
|
|
; PUT ADDRESS OF TEMP DESCRIPTOR IN FAC+3,4
|
|
; --------------------------------
|
|
PUTNEW LDX TEMPPT ; POINTER TO NEXT TEMP STRING SLOT
|
|
CPX #TEMPST+9 ; MAX OF 3 TEMP STRINGS
|
|
BNE PUTEMP ; ROOM FOR ANOTHER ONE
|
|
LDX #ERR_FRMCPX ; TOO MANY, FORMULA TOO COMPLEX
|
|
JERR JMP ERROR
|
|
; --------------------------------
|
|
PUTEMP LDA FAC ; COPY TEMP DESCRIPTOR INTO TEMP STACK
|
|
STA 0,X
|
|
LDA FAC+1
|
|
STA 1,X
|
|
LDA FAC+2
|
|
STA 2,X
|
|
LDY #0
|
|
STX FAC+3 ; ADDRESS OF TEMP DESCRIPTOR
|
|
STY FAC+4 ; IN Y,X AND FAC+3,4
|
|
DEY ; Y=$FF
|
|
STY VALTYP ; FLAG (FAC ) AS STRING
|
|
STX LASTPT ; INDEX OF LAST POINTER
|
|
INX ; UPDATE FOR NEXT TEMP ENTRY
|
|
INX
|
|
INX
|
|
STX TEMPPT
|
|
RTS
|
|
; --------------------------------
|
|
; MAKE SPACE FOR STRING AT BOTTOM OF STRING SPACE
|
|
; (A)=# BYTES SPACE TO MAKE
|
|
;
|
|
; RETURN WITH (A) SAME,
|
|
; AND Y,X = ADDRESS OF SPACE ALLOCATED
|
|
; --------------------------------
|
|
GETSPA LSR GARFLG ; CLEAR SIGNBIT OF FLAG
|
|
L_GETSPA_1 PHA ; A HOLDS LENGTH
|
|
EOR #$FF ; GET -LENGTH
|
|
SEC ;
|
|
ADC FRETOP ; COMPUTE STARTING ADDRESS OF SPACE
|
|
LDY FRETOP+1 ; FOR THE STRING
|
|
BCS L_GETSPA_2 ;
|
|
DEY ;
|
|
L_GETSPA_2 CPY STREND+1 ; SEE IF FITS IN REMAINING MEMORY
|
|
BCC L_GETSPA_4 ; NO, TRY GARBAGE
|
|
BNE L_GETSPA_3 ; YES, IT FITS
|
|
CMP STREND ; HAVE TO CHECK LOWER BYTES
|
|
BCC L_GETSPA_4 ; NOT ENUF ROOM YET
|
|
L_GETSPA_3 STA FRETOP ; THERE IS ROOM SO SAVE NEW FRETOP
|
|
STY FRETOP+1 ;
|
|
STA FRESPC ;
|
|
STY FRESPC+1 ;
|
|
TAX ; ADDR IN Y,X
|
|
PLA ; LENGTH IN A
|
|
RTS
|
|
L_GETSPA_4 LDX #ERR_MEMFULL
|
|
LDA GARFLG ; GARBAGE DONE YET?
|
|
BMI JERR ; YES, MEMORY IS REALLY FULL
|
|
JSR GARBAG ; NO, TRY COLLECTING NOW
|
|
LDA #$80 ; FLAG THAT COLLECTED GARBAGE ALREADY
|
|
STA GARFLG ;
|
|
PLA ; GET STRING LENGTH AGAIN
|
|
BNE L_GETSPA_1 ; ...ALWAYS
|
|
; --------------------------------
|
|
; SHOVE ALL REFERENCED STRINGS AS HIGH AS POSSIBLE
|
|
; IN MEMORY (AGAINST HIMEM), FREEING UP SPACE
|
|
; BELOW STRING AREA DOWN TO STREND.
|
|
; --------------------------------
|
|
GARBAG LDX MEMSIZ ; COLLECT FROM TOP DOWN
|
|
LDA MEMSIZ+1 ;
|
|
FIND_HIGHEST_STRING ;
|
|
STX FRETOP ; ONE PASS THROUGH ALL VARS
|
|
STA FRETOP+1 ; FOR EACH ACTIVE STRING!
|
|
LDY #0 ;
|
|
STY FNCNAM+1 ; FLAG IN CASE NO STRINGS TO COLLECT
|
|
LDA STREND ;
|
|
LDX STREND+1 ;
|
|
STA LOWTR ;
|
|
STX LOWTR+1 ;
|
|
; --------------------------------
|
|
; START BY COLLECTING TEMPORARIES
|
|
; --------------------------------
|
|
LDA #<TEMPST ;
|
|
LDX #>TEMPST ;
|
|
STA INDEX ;
|
|
STX INDEX+1 ;
|
|
L_FIND_HIGHEST_STRING_1 CMP TEMPPT ; FINISHED WITH TEMPS YET?
|
|
BEQ L_FIND_HIGHEST_STRING_2 ; YES, NOW DO SIMPLE VARIABLES
|
|
JSR CHECK_VARIABLE ; DO A TEMP
|
|
BEQ L_FIND_HIGHEST_STRING_1 ; ...ALWAYS
|
|
; --------------------------------
|
|
; NOW COLLECT SIMPLE VARIABLES
|
|
; --------------------------------
|
|
L_FIND_HIGHEST_STRING_2 LDA #7 ; LENGTH OF EACH VARIABLE IS 7 BYTES
|
|
STA DSCLEN ;
|
|
LDA VARTAB ; START AT BEGINNING OF VARTAB
|
|
LDX VARTAB+1
|
|
STA INDEX
|
|
STX INDEX+1
|
|
L_FIND_HIGHEST_STRING_3 CPX ARYTAB+1 ; FINISHED WITH SIMPLE VARIABLES?
|
|
BNE L_FIND_HIGHEST_STRING_4 ; NO
|
|
CMP ARYTAB ; MAYBE, CHECK LO-BYTE
|
|
BEQ L_FIND_HIGHEST_STRING_5 ; YES, NOW DO ARRAYS
|
|
L_FIND_HIGHEST_STRING_4 JSR CHECK_SIMPLE_VARIABLE
|
|
BEQ L_FIND_HIGHEST_STRING_3 ; ...ALWAYS
|
|
; --------------------------------
|
|
; NOW COLLECT ARRAY VARIABLES
|
|
; --------------------------------
|
|
L_FIND_HIGHEST_STRING_5 STA ARYPNT
|
|
STX ARYPNT+1
|
|
LDA #3 ; DESCRIPTORS IN ARRAYS ARE 3-BYTES EACH
|
|
STA DSCLEN ;
|
|
L_FIND_HIGHEST_STRING_6 LDA ARYPNT ; COMPARE TO END OF ARRAYS
|
|
LDX ARYPNT+1 ;
|
|
L_FIND_HIGHEST_STRING_7 CPX STREND+1 ; FINISHED WITH ARRAYS YET?
|
|
BNE L_FIND_HIGHEST_STRING_8 ; NOT YET
|
|
CMP STREND ; MAYBE, CHECK LO-BYTE
|
|
BNE L_FIND_HIGHEST_STRING_8 ; NOT FINISHED YET
|
|
JMP MOVE_HIGHEST_STRING_TO_TOP ; FINISHED
|
|
L_FIND_HIGHEST_STRING_8 STA INDEX ; SET UP PNTR TO START OF ARRAY
|
|
STX INDEX+1 ;
|
|
LDY #0 ; POINT AT NAME OF ARRAY
|
|
LDA (INDEX),Y ;
|
|
TAX ; 1ST LETTER OF NAME IN X-REG
|
|
INY ;
|
|
LDA (INDEX),Y ;
|
|
PHP ; STATUS FROM SECOND LETTER OF NAME
|
|
INY ;
|
|
LDA (INDEX),Y ; OFFSET TO NEXT ARRAY
|
|
ADC ARYPNT ; (CARRY ALWAYS CLEAR)
|
|
STA ARYPNT ; CALCULATE START OF NEXT ARRAY
|
|
INY ;
|
|
LDA (INDEX),Y ; HI-BYTE OF OFFSET
|
|
ADC ARYPNT+1 ;
|
|
STA ARYPNT+1 ;
|
|
PLP ; GET STATUS FROM 2ND CHAR OF NAME
|
|
BPL L_FIND_HIGHEST_STRING_6 ; NOT A STRING ARRAY
|
|
TXA ; SET STATUS WITH 1ST CHAR OF NAME
|
|
BMI L_FIND_HIGHEST_STRING_6 ; NOT A STRING ARRAY
|
|
INY ;
|
|
LDA (INDEX),Y ; # OF DIMENSIONS FOR THIS ARRAY
|
|
LDY #0 ;
|
|
ASL ; PREAMBLE SIZE = 2*#DIMS + 5
|
|
ADC #5 ;
|
|
ADC INDEX ; MAKE INDEX POINT AT FIRST ELEMENT
|
|
STA INDEX ; IN THE ARRAY
|
|
BCC L_FIND_HIGHEST_STRING_9 ;
|
|
INC INDEX+1 ;
|
|
L_FIND_HIGHEST_STRING_9 ;
|
|
LDX INDEX+1 ; STEP THRU EACH STRING IN THIS ARRAY
|
|
L_FIND_HIGHEST_STRING_10 CPX ARYPNT+1 ; ARRAY DONE?
|
|
BNE L_FIND_HIGHEST_STRING_11 ; NO, PROCESS NEXT ELEMENT
|
|
CMP ARYPNT ; MAYBE, CHECK LO-BYTE
|
|
BEQ L_FIND_HIGHEST_STRING_7 ; YES, MOVE TO NEXT ARRAY
|
|
L_FIND_HIGHEST_STRING_11 JSR CHECK_VARIABLE ; PROCESS THE ARRAY
|
|
BEQ L_FIND_HIGHEST_STRING_10 ; ...ALWAYS
|
|
; --------------------------------
|
|
; PROCESS A SIMPLE VARIABLE
|
|
; --------------------------------
|
|
CHECK_SIMPLE_VARIABLE
|
|
LDA (INDEX),Y ; LOOK AT 1ST CHAR OF NAME
|
|
BMI CHECK_BUMP ; NOT A STRING VARIABLE
|
|
INY ;
|
|
LDA (INDEX),Y ; LOOK AT 2ND CHAR OF NAME
|
|
BPL CHECK_BUMP ; NOT A STRING VARIABLE
|
|
INY ;
|
|
; --------------------------------
|
|
; IF STRING IS NOT EMPTY, CHECK IF IT IS HIGHEST
|
|
; --------------------------------
|
|
CHECK_VARIABLE ;
|
|
LDA (INDEX),Y ; GET LENGTH OF STRING
|
|
BEQ CHECK_BUMP ; IGNORE STRING IF LENGTH IS ZERO
|
|
INY ;
|
|
LDA (INDEX),Y ; GET ADDRESS OF STRING
|
|
TAX ;
|
|
INY ;
|
|
LDA (INDEX),Y ;
|
|
CMP FRETOP+1 ; CHECK IF ALREADY COLLECTED
|
|
BCC L_CHECK_VARIABLE_1 ; NO, BELOW FRETOP
|
|
BNE CHECK_BUMP ; YES, ABOVE FRETOP
|
|
CPX FRETOP ; MAYBE, CHECK LO-BYTE
|
|
BCS CHECK_BUMP ; YES, ABOVE FRETOP
|
|
L_CHECK_VARIABLE_1 CMP LOWTR+1 ; ABOVE HIGHEST STRING FOUND?
|
|
BCC CHECK_BUMP ; NO, IGNORE FOR NOW
|
|
BNE L_CHECK_VARIABLE_2 ; YES, THIS IS THE NEW HIGHEST
|
|
CPX LOWTR ; MAYBE, TRY LO-BYTE
|
|
BCC CHECK_BUMP ; NO, IGNORE FOR NOW
|
|
L_CHECK_VARIABLE_2 STX LOWTR ; MAKE THIS THE HIGHEST STRING
|
|
STA LOWTR+1
|
|
LDA INDEX ; SAVE ADDRESS OF DESCRIPTOR TOO
|
|
LDX INDEX+1
|
|
STA FNCNAM
|
|
STX FNCNAM+1
|
|
LDA DSCLEN
|
|
STA LENGTH
|
|
; --------------------------------
|
|
; ADD (DSCLEN) TO PNTR IN INDEX
|
|
; RETURN WITH Y=0, PNTR ALSO IN X,A
|
|
; --------------------------------
|
|
CHECK_BUMP
|
|
LDA DSCLEN ; BUMP TO NEXT VARIABLE
|
|
CLC
|
|
ADC INDEX
|
|
STA INDEX
|
|
BCC CHECK_EXIT
|
|
INC INDEX+1
|
|
; --------------------------------
|
|
CHECK_EXIT
|
|
LDX INDEX+1
|
|
LDY #0
|
|
RTS
|
|
; --------------------------------
|
|
; FOUND HIGHEST NON-EMPTY STRING, SO MOVE IT
|
|
; TO TOP AND GO BACK FOR ANOTHER
|
|
; --------------------------------
|
|
MOVE_HIGHEST_STRING_TO_TOP
|
|
LDX FNCNAM+1 ; ANY STRING FOUND?
|
|
BEQ CHECK_EXIT ; NO, RETURN
|
|
LDA LENGTH ; GET LENGTH OF VARIABLE ELEMENT
|
|
AND #4 ; WAS 7 OR 3, MAKE 4 OR 0
|
|
LSR ; 2 0R 0; IN SIMPLE VARIABLES,
|
|
TAY ; NAME PRECEDES DESCRIPTOR
|
|
STA LENGTH ; 2 OR 0
|
|
LDA (FNCNAM),Y ; GET LENGTH FROM DESCRIPTOR
|
|
ADC LOWTR ; CARRY ALREADY CLEARED BY LSR
|
|
STA HIGHTR ; STRING IS BTWN (LOWTR) AND (HIGHTR)
|
|
LDA LOWTR+1 ;
|
|
ADC #0 ;
|
|
STA HIGHTR+1 ;
|
|
LDA FRETOP ; HIGH END DESTINATION
|
|
LDX FRETOP+1 ;
|
|
STA HIGHDS ;
|
|
STX HIGHDS+1 ;
|
|
JSR BLTU2 ; MOVE STRING UP
|
|
LDY LENGTH ; FIX ITS DESCRIPTOR
|
|
INY ; POINT AT ADDRESS IN DESCRIPTOR
|
|
LDA HIGHDS ; STORE NEW ADDRESS
|
|
STA (FNCNAM),Y
|
|
TAX
|
|
INC HIGHDS+1 ; CORRECT BLTU'S OVERSHOOT
|
|
LDA HIGHDS+1
|
|
INY
|
|
STA (FNCNAM),Y
|
|
JMP FIND_HIGHEST_STRING
|
|
; --------------------------------
|
|
; --------------------------------
|
|
; CONCATENATE TWO STRINGS
|
|
; --------------------------------
|
|
CAT LDA FAC+4 ; SAVE ADDRESS OF FIRST DESCRIPTOR
|
|
PHA
|
|
LDA FAC+3
|
|
PHA
|
|
JSR FRM_ELEMENT ; GET SECOND STRING ELEMENT
|
|
JSR CHKSTR ; MUST BE A STRING
|
|
PLA ; RECOVER ADDRES OF 1ST DESCRIPTOR
|
|
STA STRNG1
|
|
PLA
|
|
STA STRNG1+1
|
|
LDY #0
|
|
LDA (STRNG1),Y ; ADD LENGTHS, GET CONCATENATED SIZE
|
|
CLC
|
|
ADC (FAC+3),Y
|
|
BCC L_CAT_1 ; OK IF < $100
|
|
LDX #ERR_STRLONG
|
|
JMP ERROR
|
|
L_CAT_1 JSR STRINI ; GET SPACE FOR CONCATENATED STRINGS
|
|
JSR MOVINS ; MOVE 1ST STRING
|
|
LDA DSCPTR ;
|
|
LDY DSCPTR+1 ;
|
|
JSR FRETMP ;
|
|
JSR MOVSTR_1 ; MOVE 2ND STRING
|
|
LDA STRNG1 ;
|
|
LDY STRNG1+1 ;
|
|
JSR FRETMP ;
|
|
JSR PUTNEW ; SET UP DESCRIPTOR
|
|
JMP FRMEVL_2 ; FINISH EXPRESSION
|
|
; --------------------------------
|
|
; GET STRING DESCRIPTOR POINTED AT BY (STRNG1)
|
|
; AND MOVE DESCRIBED STRING TO (FRESPC)
|
|
; --------------------------------
|
|
MOVINS LDY #0
|
|
LDA (STRNG1),Y
|
|
PHA ; LENGTH
|
|
INY
|
|
LDA (STRNG1),Y
|
|
TAX ; PUT STRING POINTER IN X,Y
|
|
INY
|
|
LDA (STRNG1),Y
|
|
TAY
|
|
PLA ; RETRIEVE LENGTH
|
|
; --------------------------------
|
|
; MOVE STRING AT (Y,X) WITH LENGTH (A)
|
|
; TO DESTINATION WHOSE ADDRESS IS IN FRESPC,FRESPC+1
|
|
; --------------------------------
|
|
MOVSTR STX INDEX ; PUT POINTER IN INDEX
|
|
STY INDEX+1 ;
|
|
MOVSTR_1 ;
|
|
TAY ; LENGTH TO Y-REG
|
|
BEQ L_MOVSTR_1_2 ; IF LENGTH IS ZERO, FINISHED
|
|
PHA ; SAVE LENGTH ON STACK
|
|
L_MOVSTR_1_1 DEY ; MOVE BYTES FROM (INDEX) TO (FRESPC)
|
|
LDA (INDEX),Y
|
|
STA (FRESPC),Y
|
|
TYA ; TEST IF ANY LEFT TO MOVE
|
|
BNE L_MOVSTR_1_1 ; YES, KEEP MOVING
|
|
PLA ; NO, FINISHED. GET LENGTH
|
|
L_MOVSTR_1_2 CLC ; AND ADD TO FRESPC, SO
|
|
ADC FRESPC ; FRESPC POINTS TO NEXT HIGHER
|
|
STA FRESPC ; BYTE. (USED BY CONCATENATION)
|
|
BCC L_MOVSTR_1_3
|
|
INC FRESPC+1
|
|
L_MOVSTR_1_3 RTS
|
|
; --------------------------------
|
|
; IF (FAC) IS A TEMPORARY STRING, RELEASE DESCRIPTOR
|
|
; --------------------------------
|
|
FRESTR JSR CHKSTR ; LAST RESULT A STRING?
|
|
; --------------------------------
|
|
; IF STRING DESCRIPTOR POINTED TO BY FAC+3,4 IS
|
|
; A TEMPORARY STRING, RELEASE IT.
|
|
; --------------------------------
|
|
FREFAC LDA FAC+3 ; GET DESCRIPTOR POINTER
|
|
LDY FAC+4
|
|
; --------------------------------
|
|
; IF STRING DESCRIPTOR WHOSE ADDRESS IS IN Y,A IS
|
|
; A TEMPORARY STRING, RELEASE IT.
|
|
; --------------------------------
|
|
FRETMP STA INDEX ; SAVE THE ADDRESS OF THE DESCRIPTOR
|
|
STY INDEX+1 ;
|
|
JSR FRETMS ; FREE DESCRIPTOR IF IT IS TEMPORARY
|
|
PHP ; REMEMBER IF TEMP
|
|
LDY #0 ; POINT AT LENGTH OF STRING
|
|
LDA (INDEX),Y ;
|
|
PHA ; SAVE LENGTH ON STACK
|
|
INY ;
|
|
LDA (INDEX),Y ;
|
|
TAX ; GET ADDRESS OF STRING IN Y,X
|
|
INY ;
|
|
LDA (INDEX),Y ;
|
|
TAY ;
|
|
PLA ; LENGTH IN A
|
|
PLP ; RETRIEVE STATUS, Z=1 IF TEMP
|
|
BNE L_FRETMP_2 ; NOT A TEMPORARY STRING
|
|
CPY FRETOP+1 ; IS IT THE LOWEST STRING?
|
|
BNE L_FRETMP_2 ; NO
|
|
CPX FRETOP ;
|
|
BNE L_FRETMP_2 ; NO
|
|
PHA ; YES, PUSH LENGTH AGAIN
|
|
CLC ; RECOVER THE SPACE USED BY
|
|
ADC FRETOP ; THE STRING
|
|
STA FRETOP ;
|
|
BCC L_FRETMP_1 ;
|
|
INC FRETOP+1 ;
|
|
L_FRETMP_1 PLA ; RETRIEVE LENGTH AGAIN
|
|
L_FRETMP_2 STX INDEX ; ADDRESS OF STRING IN Y,X
|
|
STY INDEX+1 ; LENGTH OF STRING IN A-REG
|
|
RTS ;
|
|
; --------------------------------
|
|
; RELEASE TEMPORARY DESCRIPTOR IF Y,A = LASTPT
|
|
; --------------------------------
|
|
FRETMS CPY LASTPT+1 ; COMPARE Y,A TO LATEST TEMP
|
|
BNE L_FRETMS_1 ; NOT SAME ONE, CANNOT RELEASE
|
|
CMP LASTPT ;
|
|
BNE L_FRETMS_1 ; NOT SAME ONE, CANNOT RELEASE
|
|
STA TEMPPT ; UPDATE TEMPT FOR NEXT TEMP
|
|
SBC #3 ; BACK OFF LASTPT
|
|
STA LASTPT ;
|
|
LDY #0 ; NOW Y,A POINTS TO TOP TEMP
|
|
L_FRETMS_1 RTS ; Z=0 IF NOT TEMP, Z=1 IF TEMP
|
|
; --------------------------------
|
|
; "CHR$" FUNCTION
|
|
; --------------------------------
|
|
CHRSTR JSR CONINT ; CONVERT ARGUMENT TO BYTE IN X
|
|
TXA ;
|
|
PHA ; SAVE IT
|
|
LDA #1 ; GET SPACE FOR STRING OF LENGTH 1
|
|
JSR STRSPA ;
|
|
PLA ; RECALL THE CHARACTER
|
|
LDY #0 ; PUT IN STRING
|
|
STA (FAC+1),Y ;
|
|
PLA ; POP RETURN ADDRESS
|
|
PLA ;
|
|
JMP PUTNEW ; MAKE IT A TEMPORARY STRING
|
|
; --------------------------------
|
|
; "LEFT$" FUNCTION
|
|
; --------------------------------
|
|
LEFTSTR
|
|
JSR SUBSTRING_SETUP
|
|
CMP (DSCPTR),Y ; COMPARE 1ST PARAMETER TO LENGTH
|
|
TYA ; Y=A=0
|
|
SUBSTRING_1 ;
|
|
BCC L_SUBSTRING_1_1 ; 1ST PARAMETER SMALLER, USE IT
|
|
LDA (DSCPTR),Y ; 1ST IS LONGER, USE STRING LENGTH
|
|
TAX ; IN X-REG
|
|
TYA ; Y=A=0 AGAIN
|
|
L_SUBSTRING_1_1 PHA ; PUSH LEFT END OF SUBSTRING
|
|
SUBSTRING_2 ;
|
|
TXA ;
|
|
SUBSTRING_3 ;
|
|
PHA ; PUSH LENGTH OF SUBSTRING
|
|
JSR STRSPA ; MAKE ROOM FOR STRING OF (A) BYTES
|
|
LDA DSCPTR ; RELEASE PARAMETER STRING IF TEMP
|
|
LDY DSCPTR+1 ;
|
|
JSR FRETMP ;
|
|
PLA ; GET LENGTH OF SUBSTRING
|
|
TAY ; IN Y-REG
|
|
PLA ; GET LEFT END OF SUBSTRING
|
|
CLC ; ADD TO POINTER TO STRING
|
|
ADC INDEX ;
|
|
STA INDEX ;
|
|
BCC L_SUBSTRING_3_1 ;
|
|
INC INDEX+1 ;
|
|
L_SUBSTRING_3_1 TYA ; LENGTH
|
|
JSR MOVSTR_1 ; COPY STRING INTO SPACE
|
|
JMP PUTNEW ; ADD TO TEMPS
|
|
; --------------------------------
|
|
; "RIGHT$" FUNCTION
|
|
; --------------------------------
|
|
RIGHTSTR
|
|
JSR SUBSTRING_SETUP
|
|
CLC ; COMPUTE LENGTH-WIDTH OF SUBSTRING
|
|
SBC (DSCPTR),Y ; TO GET STARTING POINT IN STRING
|
|
EOR #$FF
|
|
JMP SUBSTRING_1 ; JOIN LEFT$
|
|
; --------------------------------
|
|
; "MID$" FUNCTION
|
|
; --------------------------------
|
|
MIDSTR LDA #$FF ; FLAG WHETHER 2ND PARAMETER
|
|
STA FAC+4 ;
|
|
JSR CHRGOT ; SEE IF ")" YET
|
|
CMP #LOCHAR(`)') ;
|
|
BEQ L_MIDSTR_1 ; YES, NO 2ND PARAMETER
|
|
JSR CHKCOM ; NO, MUST HAVE COMMA
|
|
JSR GETBYT ; GET 2ND PARAM IN X-REG
|
|
L_MIDSTR_1 JSR SUBSTRING_SETUP
|
|
DEX ; 1ST PARAMETER - 1
|
|
TXA
|
|
PHA
|
|
CLC
|
|
LDX #0
|
|
SBC (DSCPTR),Y
|
|
BCS SUBSTRING_2
|
|
EOR #$FF
|
|
CMP FAC+4 ; USE SMALLER OF TWO
|
|
BCC SUBSTRING_3
|
|
LDA FAC+4
|
|
BCS SUBSTRING_3 ; ...ALWAYS
|
|
; --------------------------------
|
|
; COMMON SETUP ROUTINE FOR LEFT$, RIGHT$, MID$:
|
|
; REQUIRE ")"; POP RETURN ADRS, GET DESCRIPTOR
|
|
; ADDRESS, GET 1ST PARAMETER OF COMMAND
|
|
; --------------------------------
|
|
SUBSTRING_SETUP
|
|
JSR CHKCLS ; REQUIRE ")"
|
|
PLA ; SAVE RETURN ADDRESS
|
|
TAY ; IN Y-REG AND LENGTH
|
|
PLA ;
|
|
STA LENGTH ;
|
|
PLA ; POP PREVIOUS RETURN ADDRESS
|
|
PLA ; (FROM GOROUT).
|
|
PLA ; RETRIEVE 1ST PARAMETER
|
|
TAX ;
|
|
PLA ; GET ADDRESS OF STRING DESCRIPTOR
|
|
STA DSCPTR ;
|
|
PLA ;
|
|
STA DSCPTR+1 ;
|
|
LDA LENGTH ; RESTORE RETURN ADDRESS
|
|
PHA ;
|
|
TYA ;
|
|
PHA ;
|
|
LDY #0 ;
|
|
TXA ; GET 1ST PARAMETER IN A-REG
|
|
BEQ GOIQ ; ERROR IF 0
|
|
RTS
|
|
; --------------------------------
|
|
; "LEN" FUNCTION
|
|
; --------------------------------
|
|
LEN JSR GETSTR ; GET LENTGH IN Y-REG, MAKE FAC NUMERIC
|
|
JMP SNGFLT ; FLOAT Y-REG INTO FAC
|
|
; --------------------------------
|
|
; IF LAST RESULT IS A TEMPORARY STRING, FREE IT
|
|
; MAKE VALTYP NUMERIC, RETURN LENGTH IN Y-REG
|
|
; --------------------------------
|
|
GETSTR JSR FRESTR ; IF LAST RESULT IS A STRING, FREE IT
|
|
LDX #0 ; MAKE VALTYP NUMERIC
|
|
STX VALTYP ;
|
|
TAY ; LENGTH OF STRING TO Y-REG
|
|
RTS
|
|
; --------------------------------
|
|
; "ASC" FUNCTION
|
|
; --------------------------------
|
|
ASC JSR GETSTR ; GET STRING, GET LENGTH IN Y-REG
|
|
BEQ GOIQ ; ERROR IF LENGTH 0
|
|
LDY #0 ;
|
|
LDA (INDEX),Y ; GET 1ST CHAR OF STRING
|
|
TAY ;
|
|
JMP SNGFLT ; FLOAT Y-REG INTO FAC
|
|
; --------------------------------
|
|
GOIQ JMP IQERR ; ILLEGAL QUANTITY ERROR
|
|
; --------------------------------
|
|
; SCAN TO NEXT CHARACTER AND CONVERT EXPRESSION
|
|
; TO SINGLE BYTE IN X-REG
|
|
; --------------------------------
|
|
GTBYTC JSR CHRGET
|
|
; --------------------------------
|
|
; EVALUATE EXPRESSION AT TXTPTR, AND
|
|
; CONVERT IT TO SINGLE BYTE IN X-REG
|
|
; --------------------------------
|
|
GETBYT JSR FRMNUM
|
|
; --------------------------------
|
|
; CONVERT (FAC) TO SINGLE BYTE INTEGER IN X-REG
|
|
; --------------------------------
|
|
CONINT JSR MKINT ; CONVERT IF IN RANGE -32767 TO +32767
|
|
LDX FAC+3 ; HI-BYTE MUST BE ZERO
|
|
BNE GOIQ ; VALUE > 255, ERROR
|
|
LDX FAC+4 ; VALUE IN X-REG
|
|
JMP CHRGOT ; GET NEXT CHAR IN A-REG
|
|
; --------------------------------
|
|
; "VAL" FUNCTION
|
|
; --------------------------------
|
|
VAL JSR GETSTR ; GET POINTER TO STRING IN INDEX
|
|
BNE L_VAL_1 ; LENGTH NON-ZERO
|
|
JMP ZERO_FAC ; RETURN 0 IF LENGTH=0
|
|
L_VAL_1 LDX TXTPTR ; SAVE CURRENT TXTPTR
|
|
LDY TXTPTR+1 ;
|
|
STX STRNG2 ;
|
|
STY STRNG2+1 ;
|
|
LDX INDEX ;
|
|
STX TXTPTR ; POINT TXTPTR TO START OF STRING
|
|
CLC ;
|
|
ADC INDEX ; ADD LENGTH
|
|
STA DEST ; POINT DEST TO END OF STRING + 1
|
|
LDX INDEX+1 ;
|
|
STX TXTPTR+1 ;
|
|
BCC L_VAL_2 ;
|
|
INX ;
|
|
L_VAL_2 STX DEST+1 ;
|
|
LDY #0 ; SAVE BYTE THAT FOLLOWS STRING
|
|
LDA (DEST),Y ; ON STACK
|
|
PHA ;
|
|
LDA #0 ; AND STORE $00 IN ITS PLACE
|
|
STA (DEST),Y ;
|
|
; <<< THAT CAUSES A BUG IF HIMEM = $BFFF, >>>
|
|
; <<< BECAUSE STORING $00 AT $C000 IS NO >>>
|
|
; <<< USE; $C000 WILL ALWAYS BE LAST CHAR >>>
|
|
; <<< TYPED, SO FIN WON'T TERMINATE UNTIL >>>
|
|
; <<< IT SEES A ZERO AT $C010! >>>
|
|
JSR CHRGOT ; PRIME THE PUMP
|
|
JSR FIN ; EVALUATE STRING
|
|
PLA ; GET BYTE THAT SHOULD FOLLOW STRING
|
|
LDY #0 ; AND PUT IT BACK
|
|
STA (DEST),Y ;
|
|
; RESTORE TXTPTR
|
|
; --------------------------------
|
|
; COPY STRNG2 INTO TXTPTR
|
|
; --------------------------------
|
|
POINT LDX STRNG2 ;
|
|
LDY STRNG2+1 ;
|
|
STX TXTPTR ;
|
|
STY TXTPTR+1 ;
|
|
RTS ;
|
|
; --------------------------------
|
|
; EVALUATE "EXP1,EXP2"
|
|
;
|
|
; CONVERT EXP1 TO 16-BIT NUMBER IN LINNUM
|
|
; CONVERT EXP2 TO 8-BIT NUMBER IN X-REG
|
|
; --------------------------------
|
|
GTNUM JSR FRMNUM ;
|
|
JSR GETADR ;
|
|
; --------------------------------
|
|
; EVALUATE ",EXPRESSION"
|
|
; CONVERT EXPRESSION TO SINGLE BYTE IN X-REG
|
|
; --------------------------------
|
|
COMBYTE ;
|
|
JSR CHKCOM ; MUST HAVE COMMA FIRST
|
|
JMP GETBYT ; CONVERT EXPRESSION TO BYTE IN X-REG
|
|
; --------------------------------
|
|
; CONVERT (FAC) TO A 16-BIT VALUE IN LINNUM
|
|
; --------------------------------
|
|
GETADR LDA FAC ; FAC < 2^16?
|
|
CMP #$91 ;
|
|
BCS GOIQ ; NO, ILLEGAL QUANTITY
|
|
JSR QINT ; CONVERT TO INTEGER
|
|
LDA FAC+3 ; COPY IT INTO LINNUM
|
|
LDY FAC+4 ;
|
|
STY LINNUM ; TO LINNUM
|
|
STA LINNUM+1 ;
|
|
RTS ;
|
|
; --------------------------------
|
|
; "PEEK" FUNCTION
|
|
; --------------------------------
|
|
PEEK LDA LINNUM ; SAVE (LINNUM) ON STACK DURING PEEK
|
|
PHA ;
|
|
LDA LINNUM+1 ;
|
|
PHA ;
|
|
JSR GETADR ; GET ADDRESS PEEKING AT
|
|
LDY #0
|
|
LDA (LINNUM),Y ; TAKE A QUICK LOOK
|
|
TAY ; VALUE IN Y-REG
|
|
PLA ; RESTORE LINNUM FROM STACK
|
|
STA LINNUM+1 ;
|
|
PLA ;
|
|
STA LINNUM ;
|
|
JMP SNGFLT ; FLOAT Y-REG INTO FAC
|
|
; --------------------------------
|
|
; "POKE" STATEMENT
|
|
; --------------------------------
|
|
POKE JSR GTNUM ; GET THE ADDRESS AND VALUE
|
|
TXA ; VALUE IN A,
|
|
LDY #0 ;
|
|
STA (LINNUM),Y ; STORE IT AWAY,
|
|
RTS ; AND THAT'S ALL FOR TODAY
|
|
; --------------------------------
|
|
; "WAIT" STATEMENT
|
|
; --------------------------------
|
|
WAIT JSR GTNUM ; GET ADDRESS IN LINNUM, MASK IN X
|
|
STX FORPNT ; SAVE MASK
|
|
LDX #0 ;
|
|
JSR CHRGOT ; ANOTHER PARAMETER?
|
|
BEQ L_WAIT_1 ; NO, USE $00 FOR EXCLUSIVE-OR
|
|
JSR COMBYTE ; GET XOR-MASK
|
|
L_WAIT_1 STX FORPNT+1 ; SAVE XOR-MASK HERE
|
|
LDY #0
|
|
L_WAIT_2 LDA (LINNUM),Y ; GET BYTE AT ADDRESS
|
|
EOR FORPNT+1 ; INVERT SPECIFIED BITS
|
|
AND FORPNT ; SELECT SPECIFIED BITS
|
|
BEQ L_WAIT_2 ; LOOP TILL NOT 0
|
|
RTS_10 RTS
|
|
; --------------------------------
|
|
; ADD 0L_RTS_10_5 TO FAC
|
|
; --------------------------------
|
|
FADDH LDA #<CON_HALF ; FAC+1/2 -> FAC
|
|
LDY #>CON_HALF
|
|
JMP FADD
|
|
; --------------------------------
|
|
; FAC = (Y,A) - FAC
|
|
; --------------------------------
|
|
FSUB JSR LOAD_ARG_FROM_YA
|
|
; --------------------------------
|
|
; FAC = ARG - FAC
|
|
; --------------------------------
|
|
FSUBT LDA FAC_SIGN ; COMPLEMENT FAC AND ADD
|
|
EOR #$FF ;
|
|
STA FAC_SIGN ;
|
|
EOR ARG_SIGN ; FIX SGNCPR TOO
|
|
STA SGNCPR ;
|
|
LDA FAC ; MAKE STATUS SHOW FAC EXPONENT
|
|
JMP FADDT ; JOIN FADD
|
|
; --------------------------------
|
|
; SHIFT SMALLER ARGUMENT MORE THAN 7 BITS
|
|
; --------------------------------
|
|
FADD_1 JSR SHIFT_RIGHT ; ALIGN RADIX BY SHIFTING
|
|
BCC FADD_3 ; ...ALWAYS
|
|
; --------------------------------
|
|
; FAC = (Y,A) + FAC
|
|
; --------------------------------
|
|
FADD JSR LOAD_ARG_FROM_YA
|
|
; --------------------------------
|
|
; FAC = ARG + FAC
|
|
; --------------------------------
|
|
FADDT BNE L_FADDT_1 ; FAC IS NON-ZERO
|
|
JMP COPY_ARG_TO_FAC ; FAC = 0 + ARG
|
|
L_FADDT_1 LDX FAC_EXTENSION
|
|
STX ARG_EXTENSION
|
|
LDX #ARG ; SET UP TO SHIFT ARG
|
|
LDA ARG ; EXPONENT
|
|
; --------------------------------
|
|
FADD_2 TAY
|
|
BEQ RTS_10 ; IF ARG=0, WE ARE FINISHED
|
|
SEC ;
|
|
SBC FAC ; GET DIFFNCE OF EXP
|
|
BEQ FADD_3 ; GO ADD IF SAME EXP
|
|
BCC L_FADD_2_1 ; ARG HAS SMALLER EXPONENT
|
|
STY FAC ; EXP HAS SMALLER EXPONENT
|
|
LDY ARG_SIGN ;
|
|
STY FAC_SIGN ;
|
|
EOR #$FF ; COMPLEMENT SHIFT COUNT
|
|
ADC #0 ; CARRY WAS SET
|
|
LDY #0
|
|
STY ARG_EXTENSION
|
|
LDX #FAC ; SET UP TO SHIFT FAC
|
|
BNE L_FADD_2_2 ; ...ALWAYS
|
|
L_FADD_2_1 LDY #0
|
|
STY FAC_EXTENSION
|
|
L_FADD_2_2 CMP #$F9 ; SHIFT MORE THAN 7 BITS?
|
|
BMI FADD_1 ; YES
|
|
TAY ; INDEX TO # OF SHIFTS
|
|
LDA FAC_EXTENSION
|
|
LSR 1,X ; START SHIFTING...
|
|
JSR SHIFT_RIGHT_4 ; ...COMPLETE SHIFTING
|
|
FADD_3 BIT SGNCPR ; DO FAC AND ARG HAVE SAME SIGNS?
|
|
BPL FADD_4 ; YES, ADD THE MANTISSAS
|
|
LDY #FAC ; NO, SUBTRACT SMALLER FROM LARGER
|
|
CPX #ARG ; WHICH WAS ADJUSTED?
|
|
BEQ L_FADD_3_1 ; IF ARG, DO FAC-ARG
|
|
LDY #ARG ; IF FAC, DO ARG-FAC
|
|
L_FADD_3_1 SEC ; SUBTRACT SMALLER FROM LARGER (WE HOPE)
|
|
EOR #$FF ; (IF EXPONENTS WERE EQUAL, WE MIGHT BE
|
|
ADC ARG_EXTENSION ; SUBTRACTING LARGER FROM SMALLER)
|
|
STA FAC_EXTENSION
|
|
LDA 4,Y
|
|
SBC 4,X
|
|
STA FAC+4
|
|
LDA 3,Y
|
|
SBC 3,X
|
|
STA FAC+3
|
|
LDA 2,Y
|
|
SBC 2,X
|
|
STA FAC+2
|
|
LDA 1,Y
|
|
SBC 1,X
|
|
STA FAC+1
|
|
; --------------------------------
|
|
; NORMALIZE VALUE IN FAC
|
|
; --------------------------------
|
|
NORMALIZE_FAC_1
|
|
BCS NORMALIZE_FAC_2
|
|
JSR COMPLEMENT_FAC
|
|
; --------------------------------
|
|
NORMALIZE_FAC_2
|
|
LDY #0 ; SHIFT UP SIGNIF DIGIT
|
|
TYA ; START A=0, COUNT SHIFTS IN A-REG
|
|
CLC
|
|
L_NORMALIZE_FAC_2_1 LDX FAC+1 ; LOOK AT MOST SIGNIFICANT BYTE
|
|
BNE NORMALIZE_FAC_4 ; SOME 1-BITS HERE
|
|
LDX FAC+2 ; HI-BYTE OF MANTISSA STILL ZERO,
|
|
STX FAC+1 ; SO DO A FAST 8-BIT SHUFFLE
|
|
LDX FAC+3
|
|
STX FAC+2
|
|
LDX FAC+4
|
|
STX FAC+3
|
|
LDX FAC_EXTENSION
|
|
STX FAC+4
|
|
STY FAC_EXTENSION ; ZERO EXTENSION BYTE
|
|
ADC #8 ; BUMP SHIFT COUNT
|
|
CMP #32 ; DONE 4 TIMES YET?
|
|
BNE L_NORMALIZE_FAC_2_1 ; NO, STILL MIGHT BE SOME 1'S
|
|
; YES, VALUE OF FAC IS ZERO
|
|
; --------------------------------
|
|
; SET FAC = 0
|
|
; (ONLY NECESSARY TO ZERO EXPONENT AND SIGN CELLS)
|
|
; --------------------------------
|
|
ZERO_FAC
|
|
LDA #0
|
|
; --------------------------------
|
|
STA_IN_FAC_SIGN_AND_EXP
|
|
STA FAC
|
|
; --------------------------------
|
|
STA_IN_FAC_SIGN
|
|
STA FAC_SIGN
|
|
RTS
|
|
; --------------------------------
|
|
; ADD MANTISSAS OF FAC AND ARG INTO FAC
|
|
; --------------------------------
|
|
FADD_4 ADC ARG_EXTENSION
|
|
STA FAC_EXTENSION
|
|
LDA FAC+4
|
|
ADC ARG+4
|
|
STA FAC+4
|
|
LDA FAC+3
|
|
ADC ARG+3
|
|
STA FAC+3
|
|
LDA FAC+2
|
|
ADC ARG+2
|
|
STA FAC+2
|
|
LDA FAC+1
|
|
ADC ARG+1
|
|
STA FAC+1
|
|
JMP NORMALIZE_FAC_5
|
|
; --------------------------------
|
|
; FINISH NORMALIZING FAC
|
|
; --------------------------------
|
|
NORMALIZE_FAC_3
|
|
ADC #1 ; COUNT BITS SHIFTED
|
|
ASL FAC_EXTENSION
|
|
ROL FAC+4
|
|
ROL FAC+3
|
|
ROL FAC+2
|
|
ROL FAC+1
|
|
; --------------------------------
|
|
NORMALIZE_FAC_4
|
|
BPL NORMALIZE_FAC_3 ; UNTIL TOP BIT = 1
|
|
SEC
|
|
SBC FAC ; ADJUST EXPONENT BY BITS SHIFTED
|
|
BCS ZERO_FAC ; UNDERFLOW, RETURN ZERO
|
|
EOR #$FF ;
|
|
ADC #1 ; 2'S COMPLEMENT
|
|
STA FAC ; CARRY=0 NOW
|
|
; --------------------------------
|
|
NORMALIZE_FAC_5 ;
|
|
BCC RTS_11 ; UNLESS MANTISSA CARRIED
|
|
; --------------------------------
|
|
NORMALIZE_FAC_6 ;
|
|
INC FAC ; MANTISSA CARRIED, SO SHIFT RIGHT
|
|
BEQ OVERFLOW ; OVERFLOW IF EXPONENT TOO BIG
|
|
ROR FAC+1
|
|
ROR FAC+2
|
|
ROR FAC+3
|
|
ROR FAC+4
|
|
ROR FAC_EXTENSION
|
|
RTS_11 RTS
|
|
; --------------------------------
|
|
; 2'S COMPLEMENT OF FAC
|
|
; --------------------------------
|
|
COMPLEMENT_FAC
|
|
LDA FAC_SIGN
|
|
EOR #$FF
|
|
STA FAC_SIGN
|
|
; --------------------------------
|
|
; 2'S COMPLEMENT OF FAC MANTISSA ONLY
|
|
; --------------------------------
|
|
COMPLEMENT_FAC_MANTISSA
|
|
LDA FAC+1
|
|
EOR #$FF
|
|
STA FAC+1
|
|
LDA FAC+2
|
|
EOR #$FF
|
|
STA FAC+2
|
|
LDA FAC+3
|
|
EOR #$FF
|
|
STA FAC+3
|
|
LDA FAC+4
|
|
EOR #$FF
|
|
STA FAC+4
|
|
LDA FAC_EXTENSION
|
|
EOR #$FF
|
|
STA FAC_EXTENSION
|
|
INC FAC_EXTENSION ; START INCREMENTING MANTISSA
|
|
BNE RTS_12
|
|
; --------------------------------
|
|
; INCREMENT FAC MANTISSA
|
|
; --------------------------------
|
|
INCREMENT_FAC_MANTISSA
|
|
INC FAC+4 ; ADD CARRY FROM EXTRA
|
|
BNE RTS_12
|
|
INC FAC+3
|
|
BNE RTS_12
|
|
INC FAC+2
|
|
BNE RTS_12
|
|
INC FAC+1
|
|
RTS_12 RTS
|
|
; --------------------------------
|
|
OVERFLOW
|
|
LDX #ERR_OVERFLOW
|
|
JMP ERROR
|
|
; --------------------------------
|
|
; SHIFT 1,X THRU 5,X RIGHT
|
|
; (A) = NEGATIVE OF SHIFT COUNT
|
|
; (X) = POINTER TO BYTES TO BE SHIFTED
|
|
;
|
|
; RETURN WITH (Y)=0, CARRY=0, EXTENSION BITS IN A-REG
|
|
; --------------------------------
|
|
SHIFT_RIGHT_1
|
|
LDX #RESULT-1 ; SHIFT RESULT RIGHT
|
|
SHIFT_RIGHT_2 ;
|
|
LDY 4,X ; SHIFT 8 BITS RIGHT
|
|
STY FAC_EXTENSION ;
|
|
LDY 3,X ;
|
|
STY 4,X ;
|
|
LDY 2,X ;
|
|
STY 3,X ;
|
|
LDY 1,X ;
|
|
STY 2,X ;
|
|
LDY SHIFT_SIGN_EXT ; $00 IF +, $FF IF -
|
|
STY 1,X
|
|
; --------------------------------
|
|
; MAIN ENTRY TO RIGHT SHIFT SUBROUTINE
|
|
; --------------------------------
|
|
SHIFT_RIGHT
|
|
ADC #8
|
|
BMI SHIFT_RIGHT_2 ; STILL MORE THAN 8 BITS TO GO
|
|
BEQ SHIFT_RIGHT_2 ; EXACTLY 8 MORE BITS TO GO
|
|
SBC #8 ; UNDO ADC ABOVE
|
|
TAY ; REMAINING SHIFT COUNT
|
|
LDA FAC_EXTENSION ;
|
|
BCS SHIFT_RIGHT_5 ; FINISHED SHIFTING
|
|
SHIFT_RIGHT_3 ;
|
|
L ASL 1,X ; SIGN -> CARRY (SIGN EXTENSION)
|
|
BCC L_L_1 ; SIGN +
|
|
INC 1,X ; PUT SIGN IN LSB
|
|
L_L_1 ROR 1,X ; RESTORE VALUE, SIGN STILL IN CARRY
|
|
ROR 1,X ; START RIGHT SHIFT, INSERTING SIGN
|
|
; --------------------------------
|
|
; ENTER HERE FOR SHORT SHIFTS WITH NO SIGN EXTENSION
|
|
; --------------------------------
|
|
SHIFT_RIGHT_4
|
|
ROR 2,X
|
|
ROR 3,X
|
|
ROR 4,X
|
|
ROR ; EXTENSION
|
|
INY ; COUNT THE SHIFT
|
|
BNE SHIFT_RIGHT_3 ;
|
|
SHIFT_RIGHT_5 ;
|
|
CLC ; RETURN WITH CARRY CLEAR
|
|
RTS
|
|
; --------------------------------
|
|
; --------------------------------
|
|
|
|
CON_ONE ASM_DATA($81,$00,$00,$00,$00)
|
|
; --------------------------------
|
|
POLY_LOG ASM_DATA(3) ; # OF COEFFICIENTS - 1
|
|
ASM_DATA($7F,$5E,$56,$CB,$79) ; * X^7 +
|
|
ASM_DATA($80,$13,$9B,$0B,$64) ; * X^5 +
|
|
ASM_DATA($80,$76,$38,$93,$16) ; * X^3 +
|
|
ASM_DATA($82,$38,$AA,$3B,$20) ; * X
|
|
; --------------------------------
|
|
|
|
CON_SQR_HALF ASM_DATA($80,$35,$04,$F3,$34)
|
|
CON_SQR_TWO ASM_DATA($81,$35,$04,$F3,$34)
|
|
CON_NEG_HALF ASM_DATA($80,$80,$00,$00,$00)
|
|
CON_LOG_TWO ASM_DATA($80,$31,$72,$17,$F8)
|
|
; --------------------------------
|
|
; "LOG" FUNCTION
|
|
; --------------------------------
|
|
LOG JSR SIGN ; GET -1,0,+1 IN A-REG FOR FAC
|
|
BEQ GIQ ; LOG (0) IS ILLEGAL
|
|
BPL LOG_2 ; >0 IS OK
|
|
GIQ JMP IQERR ; <= 0 IS NO GOOD
|
|
LOG_2 LDA FAC ; FIRST GET LOG BASE 2
|
|
SBC #$7F ; SAVE UNBIASED EXPONENT
|
|
PHA ;
|
|
LDA #$80 ; NORMALIZE BETWEEN L_LOG_2_5 AND 1
|
|
STA FAC
|
|
LDA #<CON_SQR_HALF
|
|
LDY #>CON_SQR_HALF
|
|
JSR FADD ; COMPUTE VIA SERIES OF ODD
|
|
LDA #<CON_SQR_TWO ; POWERS OF
|
|
LDY #>CON_SQR_TWO ; (SQR(2)X-1)/(SQR(2)X+1)
|
|
JSR FDIV
|
|
LDA #<CON_ONE
|
|
LDY #>CON_ONE
|
|
JSR FSUB
|
|
LDA #<POLY_LOG
|
|
LDY #>POLY_LOG
|
|
JSR POLYNOMIAL_ODD
|
|
LDA #<CON_NEG_HALF
|
|
LDY #>CON_NEG_HALF
|
|
JSR FADD
|
|
PLA
|
|
JSR ADDACC ; ADD ORIGINAL EXPONENT
|
|
LDA #<CON_LOG_TWO ; MULTIPLY BY LOG(2) TO FORM
|
|
LDY #>CON_LOG_TWO ; NATURAL LOG OF X
|
|
; --------------------------------
|
|
; FAC = (Y,A) * FAC
|
|
; --------------------------------
|
|
FMULT JSR LOAD_ARG_FROM_YA
|
|
; --------------------------------
|
|
; FAC = ARG * FAC
|
|
; --------------------------------
|
|
FMULTT BNE L_FMULTT_1 ; FAC .NE. ZERO
|
|
JMP RTS_13 ; FAC = 0 * ARG = 0
|
|
; <<< WHY IS LINE ABOVE JUST "RTS"? >>>
|
|
; --------------------------------
|
|
;
|
|
; --------------------------------
|
|
L_FMULTT_1 JSR ADD_EXPONENTS
|
|
LDA #0
|
|
STA RESULT ; INIT PRODUCT = 0
|
|
STA RESULT+1
|
|
STA RESULT+2
|
|
STA RESULT+3
|
|
LDA FAC_EXTENSION
|
|
JSR MULTIPLY_1
|
|
LDA FAC+4
|
|
JSR MULTIPLY_1
|
|
LDA FAC+3
|
|
JSR MULTIPLY_1
|
|
LDA FAC+2
|
|
JSR MULTIPLY_1
|
|
LDA FAC+1
|
|
JSR MULTIPLY_2
|
|
JMP COPY_RESULT_INTO_FAC
|
|
; --------------------------------
|
|
; MULTIPLY ARG BY (A) INTO RESULT
|
|
; --------------------------------
|
|
MULTIPLY_1
|
|
BNE MULTIPLY_2 ; THIS BYTE NON-ZERO
|
|
JMP SHIFT_RIGHT_1 ; (A)=0, JUST SHIFT ARG RIGHT 8
|
|
; --------------------------------
|
|
MULTIPLY_2 ;
|
|
LSR ; SHIFT BIT INTO CARRY
|
|
ORA #$80 ; SUPPLY SENTINEL BIT
|
|
L_MULTIPLY_2_1 TAY ; REMAINING MULTIPLIER TO Y
|
|
BCC L_MULTIPLY_2_2 ; THIS MULTIPLIER BIT = 0
|
|
CLC ; = 1, SO ADD ARG TO RESULT
|
|
LDA RESULT+3
|
|
ADC ARG+4
|
|
STA RESULT+3
|
|
LDA RESULT+2
|
|
ADC ARG+3
|
|
STA RESULT+2
|
|
LDA RESULT+1
|
|
ADC ARG+2
|
|
STA RESULT+1
|
|
LDA RESULT
|
|
ADC ARG+1
|
|
STA RESULT
|
|
L_MULTIPLY_2_2 ROR RESULT ; SHIFT RESULT RIGHT 1
|
|
ROR RESULT+1 ;
|
|
ROR RESULT+2 ;
|
|
ROR RESULT+3 ;
|
|
ROR FAC_EXTENSION ;
|
|
TYA ; REMAINING MULTIPLIER
|
|
LSR ; LSB INTO CARRY
|
|
BNE L_MULTIPLY_2_1 ; IF SENTINEL STILL HERE, MULTIPLY
|
|
RTS_13 RTS ; 8 X 32 COMPLETED
|
|
; --------------------------------
|
|
; UNPACK NUMBER AT (Y,A) INTO ARG
|
|
; --------------------------------
|
|
LOAD_ARG_FROM_YA
|
|
STA INDEX ; USE INDEX FOR PNTR
|
|
STY INDEX+1 ;
|
|
LDY #4 ; FIVE BYTES TO MOVE
|
|
LDA (INDEX),Y ;
|
|
STA ARG+4 ;
|
|
DEY ;
|
|
LDA (INDEX),Y ;
|
|
STA ARG+3 ;
|
|
DEY ;
|
|
LDA (INDEX),Y ;
|
|
STA ARG+2 ;
|
|
DEY ;
|
|
LDA (INDEX),Y ;
|
|
STA ARG_SIGN ;
|
|
EOR FAC_SIGN ; SET COMBINED SIGN FOR MULT/DIV
|
|
STA SGNCPR ;
|
|
LDA ARG_SIGN ; TURN ON NORMALIZED INVISIBLE BIT
|
|
ORA #$80 ; TO COMPLETE MANTISSA
|
|
STA ARG+1 ;
|
|
DEY ;
|
|
LDA (INDEX),Y ;
|
|
STA ARG ; EXPONENT
|
|
LDA FAC ; SET STATUS BITS ON FAC EXPONENT
|
|
RTS ;
|
|
; --------------------------------
|
|
; ADD EXPONENTS OF ARG AND FAC
|
|
; (CALLED BY FMULT AND FDIV)
|
|
;
|
|
; ALSO CHECK FOR OVERFLOW, AND SET RESULT SIGN
|
|
; --------------------------------
|
|
ADD_EXPONENTS
|
|
LDA ARG
|
|
; --------------------------------
|
|
ADD_EXPONENTS_1
|
|
BEQ ZERO ; IF ARG=0, RESULT IS ZERO
|
|
CLC ;
|
|
ADC FAC ;
|
|
BCC L_ADD_EXPONENTS_1_1 ; IN RANGE
|
|
BMI JOV ; OVERFLOW
|
|
CLC ;
|
|
ASM_DATA($2C) ; TRICK TO SKIP
|
|
L_ADD_EXPONENTS_1_1 BPL ZERO ; OVERFLOW
|
|
ADC #$80 ; RE-BIAS
|
|
STA FAC ; RESULT
|
|
BNE L_ADD_EXPONENTS_1_2
|
|
JMP STA_IN_FAC_SIGN ; RESULT IS ZERO
|
|
; <<< CRAZY TO JUMP WAY BACK THERE! >>>
|
|
; <<< SAME IDENTICAL CODE IS BELOW! >>>
|
|
; <<< INSTEAD OF BNE L_ADD_EXPONENTS_1_2, JMP STA.IN.FAC.SIGN >>>
|
|
; <<< ONLY NEEDED BEQ L_ADD_EXPONENTS_1_3 >>>
|
|
L_ADD_EXPONENTS_1_2 LDA SGNCPR ; SET SIGN OF RESULT
|
|
L_ADD_EXPONENTS_1_3 STA FAC_SIGN
|
|
RTS
|
|
; --------------------------------
|
|
; IF (FAC) IS POSITIVE, GIVE "OVERFLOW" ERROR
|
|
; IF (FAC) IS NEGATIVE, SET FAC=0, POP ONE RETURN, AND RTS
|
|
; CALLED FROM "EXP" FUNCTION
|
|
; --------------------------------
|
|
OUTOFRNG
|
|
LDA FAC_SIGN
|
|
EOR #$FF
|
|
BMI JOV ; ERROR IF POSITIVE #
|
|
; --------------------------------
|
|
; POP RETURN ADDRESS AND SET FAC=0
|
|
; --------------------------------
|
|
ZERO PLA
|
|
PLA
|
|
JMP ZERO_FAC
|
|
; --------------------------------
|
|
JOV JMP OVERFLOW
|
|
; --------------------------------
|
|
; MULTIPLY FAC BY 10
|
|
; --------------------------------
|
|
MUL10 JSR COPY_FAC_TO_ARG_ROUNDED
|
|
TAX ; TEXT FAC EXPONENT
|
|
BEQ L_MUL10_1 ; FINISHED IF FAC=0
|
|
CLC ;
|
|
ADC #2 ; ADD 2 TO EXPONENT GIVES (FAC)*4
|
|
BCS JOV ; OVERFLOW
|
|
LDX #0 ;
|
|
STX SGNCPR ;
|
|
JSR FADD_2 ; MAKES (FAC)*5
|
|
INC FAC ; *2, MAKES (FAC)*10
|
|
BEQ JOV ; OVERFLOW
|
|
L_MUL10_1 RTS
|
|
; --------------------------------
|
|
|
|
CON_TEN ASM_DATA($84,$20,$00,$00,$00)
|
|
; --------------------------------
|
|
; DIVIDE FAC BY 10
|
|
; --------------------------------
|
|
DIV10 JSR COPY_FAC_TO_ARG_ROUNDED
|
|
LDA #<CON_TEN ; SET UP TO PUT
|
|
LDY #>CON_TEN ; 10 IN FAC
|
|
LDX #0
|
|
; --------------------------------
|
|
; FAC = ARG / (Y,A)
|
|
; --------------------------------
|
|
DIV STX SGNCPR
|
|
JSR LOAD_FAC_FROM_YA
|
|
JMP FDIVT ; DIVIDE ARG BY FAC
|
|
; --------------------------------
|
|
; FAC = (Y,A) / FAC
|
|
; --------------------------------
|
|
FDIV JSR LOAD_ARG_FROM_YA
|
|
; --------------------------------
|
|
; FAC = ARG / FAC
|
|
; --------------------------------
|
|
FDIVT BEQ L_FDIVT_8 ; FAC = 0, DIVIDE BY ZERO ERROR
|
|
JSR ROUND_FAC ;
|
|
LDA #0 ; NEGATE FAC EXPONENT, SO
|
|
SEC ; ADD.EXPONENTS FORMS DIFFERENCE
|
|
SBC FAC
|
|
STA FAC
|
|
JSR ADD_EXPONENTS
|
|
INC FAC
|
|
BEQ JOV ; OVERFLOW
|
|
LDX #$FC ; INDEX FOR RESULT
|
|
LDA #1 ; SENTINEL
|
|
L_FDIVT_1 LDY ARG+1 ; SEE IF FAC CAN BE SUBTRACTED
|
|
CPY FAC+1
|
|
BNE L_FDIVT_2
|
|
LDY ARG+2
|
|
CPY FAC+2
|
|
BNE L_FDIVT_2
|
|
LDY ARG+3
|
|
CPY FAC+3
|
|
BNE L_FDIVT_2
|
|
LDY ARG+4
|
|
CPY FAC+4
|
|
L_FDIVT_2 PHP ; SAVE THE ANSWER, AND ALSO ROLL THE
|
|
ROL ; BIT INTO THE QUOTIENT, SENTINEL OUT
|
|
BCC L_FDIVT_3 ; NO SENTINEL, STILL NOT 8 TRIPS
|
|
INX ; 8 TRIPS, STORE BYTE OF QUOTIENT
|
|
STA RESULT+3,X
|
|
BEQ L_FDIVT_6 ; 32-BITS COMPLETED
|
|
BPL L_FDIVT_7 ; FINAL EXIT WHEN X=1
|
|
LDA #1 ; RE-START SENTINEL
|
|
L_FDIVT_3 PLP ; GET ANSWER, CAN FAC BE SUBTRACTED?
|
|
BCS L_FDIVT_5 ; YES, DO IT
|
|
L_FDIVT_4 ASL ARG+4 ; NO, SHIFT ARG LEFT
|
|
ROL ARG+3 ;
|
|
ROL ARG+2 ;
|
|
ROL ARG+1 ;
|
|
BCS L_FDIVT_2 ; ANOTHER TRIP
|
|
BMI L_FDIVT_1 ; HAVE TO COMPARE FIRST
|
|
BPL L_FDIVT_2 ; ...ALWAYS
|
|
L_FDIVT_5 TAY ; SAVE QUOTIENT/SENTINEL BYTE
|
|
LDA ARG+4 ; SUBTRACT FAC FROM ARG ONCE
|
|
SBC FAC+4 ;
|
|
STA ARG+4 ;
|
|
LDA ARG+3 ;
|
|
SBC FAC+3 ;
|
|
STA ARG+3 ;
|
|
LDA ARG+2 ;
|
|
SBC FAC+2 ;
|
|
STA ARG+2 ;
|
|
LDA ARG+1 ;
|
|
SBC FAC+1 ;
|
|
STA ARG+1 ;
|
|
TYA ; RESTORE QUOTIENT/SENTINEL BYTE
|
|
JMP L_FDIVT_4 ; GO TO SHIFT ARG AND CONTINUE
|
|
; --------------------------------
|
|
L_FDIVT_6 LDA #$40 ; DO A FEW EXTENSION BITS
|
|
BNE L_FDIVT_3 ; ...ALWAYS
|
|
; --------------------------------
|
|
L_FDIVT_7 ASL ; LEFT JUSTIFY THE EXTENSION BITS WE DID
|
|
ASL
|
|
ASL
|
|
ASL
|
|
ASL
|
|
ASL
|
|
STA FAC_EXTENSION
|
|
PLP
|
|
JMP COPY_RESULT_INTO_FAC
|
|
; --------------------------------
|
|
L_FDIVT_8 LDX #ERR_ZERODIV
|
|
JMP ERROR
|
|
; --------------------------------
|
|
; COPY RESULT INTO FAC MANTISSA, AND NORMALIZE
|
|
; --------------------------------
|
|
COPY_RESULT_INTO_FAC
|
|
LDA RESULT
|
|
STA FAC+1
|
|
LDA RESULT+1
|
|
STA FAC+2
|
|
LDA RESULT+2
|
|
STA FAC+3
|
|
LDA RESULT+3
|
|
STA FAC+4
|
|
JMP NORMALIZE_FAC_2
|
|
; --------------------------------
|
|
; UNPACK (Y,A) INTO FAC
|
|
; --------------------------------
|
|
LOAD_FAC_FROM_YA
|
|
STA INDEX ; USE INDEX FOR PNTR
|
|
STY INDEX+1 ;
|
|
LDY #4 ; PICK UP 5 BYTES
|
|
LDA (INDEX),Y ;
|
|
STA FAC+4 ;
|
|
DEY ;
|
|
LDA (INDEX),Y ;
|
|
STA FAC+3 ;
|
|
DEY ;
|
|
LDA (INDEX),Y ;
|
|
STA FAC+2 ;
|
|
DEY ;
|
|
LDA (INDEX),Y ;
|
|
STA FAC_SIGN ; FIRST BIT IS SIGN
|
|
ORA #$80 ; SET NORMALIZED INVISIBLE BIT
|
|
STA FAC+1 ;
|
|
DEY ;
|
|
LDA (INDEX),Y ;
|
|
STA FAC ; EXPONENT
|
|
STY FAC_EXTENSION ; Y=0
|
|
RTS
|
|
; --------------------------------
|
|
; ROUND FAC, STORE IN TEMP2
|
|
; --------------------------------
|
|
STORE_FAC_IN_TEMP2_ROUNDED
|
|
LDX #TEMP2 ; PACK FAC INTO TEMP2
|
|
ASM_DATA($2C) ; TRICK TO BRANCH
|
|
; --------------------------------
|
|
; ROUND FAC, STORE IN TEMP1
|
|
; --------------------------------
|
|
STORE_FAC_IN_TEMP1_ROUNDED
|
|
LDX #<TEMP1 ; PACK FAC INTO TEMP1
|
|
LDY #>TEMP1 ; HI-BYTE OF TEMP1 SAME AS TEMP2
|
|
BEQ STORE_FACDB_YX_ROUNDED ; ...ALWAYS
|
|
; --------------------------------
|
|
; ROUND FAC, AND STORE WHERE FORPNT POINTS
|
|
; --------------------------------
|
|
SETFOR LDX FORPNT
|
|
LDY FORPNT+1
|
|
; --------------------------------
|
|
; ROUND FAC, AND STORE AT (Y,X)
|
|
; --------------------------------
|
|
STORE_FACDB_YX_ROUNDED
|
|
JSR ROUND_FAC ; ROUND VALUE IN FAC USING EXTENSION
|
|
STX INDEX ; USE INDEX FOR PNTR
|
|
STY INDEX+1 ;
|
|
LDY #4 ; STORING 5 PACKED BYTES
|
|
LDA FAC+4 ;
|
|
STA (INDEX),Y ;
|
|
DEY ;
|
|
LDA FAC+3 ;
|
|
STA (INDEX),Y ;
|
|
DEY ;
|
|
LDA FAC+2 ;
|
|
STA (INDEX),Y ;
|
|
DEY ;
|
|
LDA FAC_SIGN ; PACK SIGN IN TOP BIT OF MANTISSA
|
|
ORA #$7F ;
|
|
AND FAC+1 ;
|
|
STA (INDEX),Y ;
|
|
DEY ;
|
|
LDA FAC ; EXPONENT
|
|
STA (INDEX),Y ;
|
|
STY FAC_EXTENSION ; ZERO THE EXTENSION
|
|
RTS
|
|
; --------------------------------
|
|
; COPY ARG INTO FAC
|
|
; --------------------------------
|
|
COPY_ARG_TO_FAC
|
|
LDA ARG_SIGN ; COPY SIGN
|
|
MFA STA FAC_SIGN ;
|
|
LDX #5 ; MOVE 5 BYTES
|
|
L_MFA_1 LDA ARG-1,X ;
|
|
STA FAC-1,X ;
|
|
DEX ;
|
|
BNE L_MFA_1 ;
|
|
STX FAC_EXTENSION ; ZERO EXTENSION
|
|
RTS ;
|
|
; --------------------------------
|
|
; ROUND FAC AND COPY TO ARG
|
|
; --------------------------------
|
|
COPY_FAC_TO_ARG_ROUNDED
|
|
JSR ROUND_FAC ; ROUND FAC USING EXTENSION
|
|
MAF LDX #6 ; COPY 6 BYTES, INCLUDES SIGN
|
|
L_MAF_1 LDA FAC-1,X ;
|
|
STA ARG-1,X ;
|
|
DEX ;
|
|
BNE L_MAF_1 ;
|
|
STX FAC_EXTENSION ; ZERO FAC EXTENSION
|
|
RTS_14 RTS ;
|
|
; --------------------------------
|
|
; ROUND FAC USING EXTENSION BYTE
|
|
; --------------------------------
|
|
ROUND_FAC
|
|
LDA FAC
|
|
BEQ RTS_14 ; FAC = 0, RETURN
|
|
ASL FAC_EXTENSION ; IS FAC.EXTENSION >= 128?
|
|
BCC RTS_14 ; NO, FINISHED
|
|
; --------------------------------
|
|
; INCREMENT MANTISSA AND RE-NORMALIZE IF CARRY
|
|
; --------------------------------
|
|
INCREMENT_MANTISSA
|
|
JSR INCREMENT_FAC_MANTISSA ; YES, INCREMENT FAC
|
|
BNE RTS_14 ; HIGH BYTE HAS BITS, FINISHED
|
|
JMP NORMALIZE_FAC_6 ; HI-BYTE=0, SO SHIFT LEFT
|
|
; --------------------------------
|
|
; TEST FAC FOR ZERO AND SIGN
|
|
;
|
|
; FAC > 0, RETURN +1
|
|
; FAC = 0, RETURN 0
|
|
; FAC < 0, RETURN -1
|
|
; --------------------------------
|
|
SIGN LDA FAC ; CHECK SIGN OF FAC AND
|
|
BEQ RTS_15 ; RETURN -1,0,1 IN A-REG
|
|
; --------------------------------
|
|
SIGN1 LDA FAC_SIGN ;
|
|
; --------------------------------
|
|
SIGN2 ROL ; MSBIT TO CARRY
|
|
LDA #$FF ; -1
|
|
BCS RTS_15 ; MSBIT = 1
|
|
LDA #1 ; +1
|
|
RTS_15 RTS ;
|
|
; --------------------------------
|
|
; "SGN" FUNCTION
|
|
; --------------------------------
|
|
SGN JSR SIGN ; CONVERT FAC TO -1,0,1
|
|
; --------------------------------
|
|
; CONVERT (A) INTO FAC, AS SIGNED VALUE -128 TO +127
|
|
; --------------------------------
|
|
FLOAT STA FAC+1 ; PUT IN HIGH BYTE OF MANTISSA
|
|
LDA #0 ; CLEAR 2ND BYTE OF MANTISSA
|
|
STA FAC+2 ;
|
|
LDX #$88 ; USE EXPONENT 2^9
|
|
; --------------------------------
|
|
; FLOAT UNSIGNED VALUE IN FAC+1,2
|
|
; (X) = EXPONENT
|
|
; --------------------------------
|
|
FLOAT_1 ;
|
|
LDA FAC+1 ; MSBIT=0, SET CARRY; =1, CLEAR CARRY
|
|
EOR #$FF ;
|
|
ROL ;
|
|
; --------------------------------
|
|
; FLOAT UNSIGNED VALUE IN FAC+1,2
|
|
; (X) = EXPONENT
|
|
; C=0 TO MAKE VALUE NEGATIVE
|
|
; C=1 TO MAKE VALUE POSITIVE
|
|
; --------------------------------
|
|
FLOAT_2 ;
|
|
LDA #0 ; CLEAR LOWER 16-BITS OF MANTISSA
|
|
STA FAC+4 ;
|
|
STA FAC+3 ;
|
|
STX FAC ; STORE EXPONENT
|
|
STA FAC_EXTENSION ; CLEAR EXTENSION
|
|
STA FAC_SIGN ; MAKE SIGN POSITIVE
|
|
JMP NORMALIZE_FAC_1 ; IF C=0, WILL NEGATE FAC
|
|
; --------------------------------
|
|
; "ABS" FUNCTION
|
|
; --------------------------------
|
|
ABS LSR FAC_SIGN ; CHANGE SIGN TO +
|
|
RTS
|
|
; --------------------------------
|
|
; COMPARE FAC WITH PACKED # AT (Y,A)
|
|
; RETURN A=1,0,-1 AS (Y,A) IS <,=,> FAC
|
|
; --------------------------------
|
|
FCOMP STA DEST ; USE DEST FOR PNTR
|
|
; --------------------------------
|
|
; SPECIAL ENTRY FROM "NEXT" PROCESSOR
|
|
; "DEST" ALREADY SET UP
|
|
; --------------------------------
|
|
FCOMP2 STY DEST+1 ;
|
|
LDY #0 ; GET EXPONENT OF COMPARAND
|
|
LDA (DEST),Y ;
|
|
INY ; POINT AT NEXT BYTE
|
|
TAX ; EXPONENT TO X-REG
|
|
BEQ SIGN ; IF COMPARAND=0, "SIGN" COMPARES FAC
|
|
LDA (DEST),Y ; GET HI-BYTE OF MANTISSA
|
|
EOR FAC_SIGN ; COMPARE WITH FAC SIGN
|
|
BMI SIGN1 ; DIFFERENT SIGNS, "SIGN" GIVES ANSWER
|
|
CPX FAC ; SAME SIGN, SO COMPARE EXPONENTS
|
|
BNE L_FCOMP2_1 ; DIFFERENT, SO SUFFICIENT TEST
|
|
LDA (DEST),Y ; SAME EXPONENT, COMPARE MANTISSA
|
|
ORA #$80 ; SET INVISIBLE NORMALIZED BIT
|
|
CMP FAC+1 ;
|
|
BNE L_FCOMP2_1 ; NOT SAME, SO SUFFICIENT
|
|
INY ; SAME, COMPARE MORE MANTISSA
|
|
LDA (DEST),Y ;
|
|
CMP FAC+2 ;
|
|
BNE L_FCOMP2_1 ; NOT SAME, SO SUFFICIENT
|
|
INY ; SAME, COMPARE MORE MANTISSA
|
|
LDA (DEST),Y ;
|
|
CMP FAC+3 ;
|
|
BNE L_FCOMP2_1 ; NOT SAME, SO SUFFICIENT
|
|
INY ; SAME, COMPARE REST OF MANTISSA
|
|
LDA #$7F ; ARTIFICIAL EXTENSION BYTE FOR COMPARAND
|
|
CMP FAC_EXTENSION
|
|
LDA (DEST),Y
|
|
SBC FAC+4
|
|
BEQ RTS_16 ; NUMBERS ARE EQUAL, RETURN (A)=0
|
|
L_FCOMP2_1 LDA FAC_SIGN ; NUMBERS ARE DIFFERENT
|
|
BCC L_FCOMP2_2 ; FAC IS LARGER MAGNITUDE
|
|
EOR #$FF ; FAC IS SMALLER MAGNITUDE
|
|
; <<< NOTE THAT ABOVE THREE LINES CAN BE SHORTENED: >>>
|
|
; <<< L_FCOMP2_1 ROR PUT CARRY INTO SIGN BIT >>>
|
|
; <<< EOR FAC.SIGN TOGGLE WITH SIGN OF FAC >>>
|
|
L_FCOMP2_2 JMP SIGN2 ; CONVERT +1 OR -1
|
|
; --------------------------------
|
|
; QUICK INTEGER FUNCTION
|
|
;
|
|
; CONVERTS FP VALUE IN FAC TO INTEGER VALUE
|
|
; IN FAC+1...FAC+4, BY SHIFTING RIGHT WITH SIGN
|
|
; EXTENSION UNTIL FRACTIONAL BITS ARE OUT.
|
|
;
|
|
; THIS SUBROUTINE ASSUMES THE EXPONENT < 32.
|
|
; --------------------------------
|
|
QINT LDA FAC ; LOOK AT FAC EXPONENT
|
|
BEQ QINT_3 ; FAC=0, SO FINISHED
|
|
SEC ; GET -(NUMBER OF FRACTIONAL BITS)
|
|
SBC #$A0 ; IN A-REG FOR SHIFT COUNT
|
|
BIT FAC_SIGN ; CHECK SIGN OF FAC
|
|
BPL L_QINT_1 ; POSITIVE, CONTINUE
|
|
TAX ; NEGATIVE, SO COMPLEMENT MANTISSA
|
|
LDA #$FF ; AND SET SIGN EXTENSION FOR SHIFT
|
|
STA SHIFT_SIGN_EXT
|
|
JSR COMPLEMENT_FAC_MANTISSA
|
|
TXA ; RESTORE BIT COUNT TO A-REG
|
|
L_QINT_1 LDX #FAC ; POINT SHIFT SUBROUTINE AT FAC
|
|
CMP #$F9 ; MORE THAN 7 BITS TO SHIFT?
|
|
BPL QINT_2 ; NO, SHORT SHIFT
|
|
JSR SHIFT_RIGHT ; YES, USE GENERAL ROUTINE
|
|
STY SHIFT_SIGN_EXT ; Y=0, CLEAR SIGN EXTENSION
|
|
RTS_16 RTS
|
|
; --------------------------------
|
|
QINT_2 TAY ; SAVE SHIFT COUNT
|
|
LDA FAC_SIGN ; GET SIGN BIT
|
|
AND #$80 ;
|
|
LSR FAC+1 ; START RIGHT SHIFT
|
|
ORA FAC+1 ; AND MERGE WITH SIGN
|
|
STA FAC+1
|
|
JSR SHIFT_RIGHT_4 ; JUMP INTO MIDDLE OF SHIFTER
|
|
STY SHIFT_SIGN_EXT ; Y=0, CLEAR SIGN EXTENSION
|
|
RTS
|
|
; --------------------------------
|
|
; "INT" FUNCTION
|
|
;
|
|
; USES QINT TO CONVERT (FAC) TO INTEGER FORM,
|
|
; AND THEN REFLOATS THE INTEGER.
|
|
; <<< A FASTER APPROACH WOULD SIMPLY CLEAR >>>
|
|
; <<< THE FRACTIONAL BITS BY ZEROING THEM >>>
|
|
; --------------------------------
|
|
INT LDA FAC ; CHECK IF EXPONENT < 32
|
|
CMP #$A0 ; BECAUSE IF > 31 THERE IS NO FRACTION
|
|
BCS RTS_17 ; NO FRACTION, WE ARE FINISHED
|
|
JSR QINT ; USE GENERAL INTEGER CONVERSION
|
|
STY FAC_EXTENSION ; Y=0, CLEAR EXTENSION
|
|
LDA FAC_SIGN ; GET SIGN OF VALUE
|
|
STY FAC_SIGN ; Y=0, CLEAR SIGN
|
|
EOR #$80 ; TOGGLE ACTUAL SIGN
|
|
ROL ; AND SAVE IN CARRY
|
|
LDA #$A0 ; SET EXPONENT TO 32
|
|
STA FAC ; BECAUSE 4-BYTE INTEGER NOW
|
|
LDA FAC+4 ; SAVE LOW 8-BITS OF INTEGER FORM
|
|
STA CHARAC ; FOR EXP AND POWER
|
|
JMP NORMALIZE_FAC_1 ; NORMALIZE TO FINISH CONVERSION
|
|
; --------------------------------
|
|
QINT_3 STA FAC+1 ; FAC=0, SO CLEAR ALL 4 BYTES FOR
|
|
STA FAC+2 ; INTEGER VERSION
|
|
STA FAC+3 ;
|
|
STA FAC+4 ;
|
|
TAY ; Y=0 TOO
|
|
RTS_17 RTS ;
|
|
; --------------------------------
|
|
; CONVERT STRING TO FP VALUE IN FAC
|
|
;
|
|
; STRING POINTED TO BY TXTPTR
|
|
; FIRST CHAR ALREADY SCANNED BY CHRGET
|
|
; (A) = FIRST CHAR, C=0 IF DIGIT.
|
|
; --------------------------------
|
|
FIN LDY #0 ; CLEAR WORKING AREA ($99...$A3)
|
|
LDX #10 ; TMPEXP, EXPON, DPFLG, EXPSGN, FAC, SERLEN
|
|
L_FIN_1 STY TMPEXP,X
|
|
DEX
|
|
BPL L_FIN_1
|
|
; --------------------------------
|
|
BCC FIN_2 ; FIRST CHAR IS A DIGIT
|
|
CMP #LOCHAR(`-') ; CHECK FOR LEADING SIGN
|
|
BNE L_FIN_2 ; NOT MINUS
|
|
STX SERLEN ; MINUS, SET SERLEN = $FF FOR FLAG
|
|
BEQ FIN_1 ; ...ALWAYS
|
|
L_FIN_2 CMP #LOCHAR(`+') ; MIGHT BE PLUS
|
|
BNE FIN_3 ; NOT PLUS EITHER, CHECK DECIMAL POINT
|
|
; --------------------------------
|
|
FIN_1 JSR CHRGET ; GET NEXT CHAR OF STRING
|
|
; --------------------------------
|
|
FIN_2 BCC FIN_9 ; INSERT THIS DIGIT
|
|
; --------------------------------
|
|
FIN_3 CMP #LOCHAR(`.') ; CHECK FOR DECIMAL POINT
|
|
BEQ FIN_10 ; YES
|
|
CMP #LOCHAR(`E') ; CHECK FOR EXPONENT PART
|
|
BNE FIN_7 ; NO, END OF NUMBER
|
|
JSR CHRGET ; YES, START CONVERTING EXPONENT
|
|
BCC FIN_5 ; EXPONENT DIGIT
|
|
CMP #TOKEN_MINUS ; NEGATIVE EXPONENT?
|
|
BEQ L_FIN_3_1 ; YES
|
|
CMP #LOCHAR(`-') ; MIGHT NOT BE TOKENIZED YET
|
|
BEQ L_FIN_3_1 ; YES, IT IS NEGATIVE
|
|
CMP #TOKEN_PLUS ; OPTIONAL "+"
|
|
BEQ FIN_4 ; YES
|
|
CMP #LOCHAR(`+') ; MIGHT NOT BE TOKENIZED YET
|
|
BEQ FIN_4 ; YES, FOUND "+"
|
|
BNE FIN_6 ; ...ALWAYS, NUMBER COMPLETED
|
|
L_FIN_3_1 ROR EXPSGN ; C=1, SET FLAG NEGATIVE
|
|
; --------------------------------
|
|
FIN_4 JSR CHRGET ; GET NEXT DIGIT OF EXPONENT
|
|
; --------------------------------
|
|
FIN_5 BCC GETEXP ; CHAR IS A DIGIT OF EXPONENT
|
|
; --------------------------------
|
|
FIN_6 BIT EXPSGN ; END OF NUMBER, CHECK EXP SIGN
|
|
BPL FIN_7 ; POSITIVE EXPONENT
|
|
LDA #0 ; NEGATIVE EXPONENT
|
|
SEC ; MAKE 2'S COMPLEMENT OF EXPONENT
|
|
SBC EXPON ;
|
|
JMP FIN_8 ;
|
|
; --------------------------------
|
|
; FOUND A DECIMAL POINT
|
|
; --------------------------------
|
|
FIN_10 ROR DPFLG ; C=1, SET DPFLG FOR DECIMAL POINT
|
|
BIT DPFLG ; CHECK IF PREVIOUS DEC. PT.
|
|
BVC FIN_1 ; NO PREVIOUS DECIMAL POINT
|
|
; A SECOND DECIMAL POINT IS TAKEN AS A TERMINATOR
|
|
; TO THE NUMERIC STRING.
|
|
; "A=11..22" WILL GIVE A SYNTAX ERROR, BECAUSE
|
|
; IT IS TWO NUMBERS WITH NO OPERATOR BETWEEN.
|
|
; "PRINT 11..22" GIVES NO ERROR, BECAUSE IT IS
|
|
; JUST THE CONCATENATION OF TWO NUMBERS.
|
|
; --------------------------------
|
|
; NUMBER TERMINATED, ADJUST EXPONENT NOW
|
|
; --------------------------------
|
|
FIN_7 LDA EXPON ; E-VALUE
|
|
FIN_8 SEC ; MODIFY WITH COUNT OF DIGITS
|
|
SBC TMPEXP ; AFTER THE DECIMAL POINT
|
|
STA EXPON ; COMPLETE CURRENT EXPONENT
|
|
BEQ L_FIN_8_15 ; NO ADJUST NEEDED IF EXP=0
|
|
BPL L_FIN_8_14 ; EXP>0, MULTIPLY BY TEN
|
|
L_FIN_8_13 JSR DIV10 ; EXP<0, DIVIDE BY TEN
|
|
INC EXPON ; UNTIL EXP=0
|
|
BNE L_FIN_8_13 ;
|
|
BEQ L_FIN_8_15 ; ...ALWAYS, WE ARE FINISHED
|
|
L_FIN_8_14 JSR MUL10 ; EXP>0, MULTIPLY BKY TEN
|
|
DEC EXPON ; UNTIL EXP=0
|
|
BNE L_FIN_8_14 ;
|
|
L_FIN_8_15 LDA SERLEN ; IS WHOLE NUMBER NEGATIVE?
|
|
BMI L_FIN_8_16 ; YES
|
|
RTS ; NO, RETURN, WHOLE JOB DONE!
|
|
L_FIN_8_16 JMP NEGOP ; NEGATIVE NUMBER, SO NEGATE FAC
|
|
; --------------------------------
|
|
; ACCUMULATE A DIGIT INTO FAC
|
|
; --------------------------------
|
|
FIN_9 PHA ; SAVE DIGIT
|
|
BIT DPFLG ; SEEN A DECIMAL POINT YET?
|
|
BPL L_FIN_9_1 ; NO, STILL IN INTEGER PART
|
|
INC TMPEXP ; YES, COUNT THE FRACTIONAL DIGIT
|
|
L_FIN_9_1 JSR MUL10 ; FAC = FAC * 10
|
|
PLA ; CURRENT DIGIT
|
|
SEC ; <<<SHORTER HERE TO JUST "AND #$0F">>>
|
|
SBC #LOCHAR(`0') ; <<<TO CONVERT ASCII TO BINARY FORM>>>
|
|
JSR ADDACC ; ADD THE DIGIT
|
|
JMP FIN_1 ; GO BACK FOR MORE
|
|
; --------------------------------
|
|
; ADD (A) TO FAC
|
|
; --------------------------------
|
|
ADDACC PHA ; SAVE ADDEND
|
|
JSR COPY_FAC_TO_ARG_ROUNDED
|
|
PLA ; GET ADDEND AGAIN
|
|
JSR FLOAT ; CONVERT TO FP VALUE IN FAC
|
|
LDA ARG_SIGN ;
|
|
EOR FAC_SIGN ;
|
|
STA SGNCPR ;
|
|
LDX FAC ; TO SIGNAL IF FAC=0
|
|
JMP FADDT ; PERFORM THE ADDITION
|
|
; --------------------------------
|
|
; ACCUMULATE DIGIT OF EXPONENT
|
|
; --------------------------------
|
|
GETEXP LDA EXPON ; CHECK CURRENT VALUE
|
|
CMP #10 ; FOR MORE THAN 2 DIGITS
|
|
BCC L_GETEXP_1 ; NO, THIS IS 1ST OR 2ND DIGIT
|
|
LDA #100 ; EXPONENT TOO BIG
|
|
BIT EXPSGN ; UNLESS IT IS NEGATIVE
|
|
BMI L_GETEXP_2 ; LARGE NEGATIVE EXPONENT MAKES FAC=0
|
|
JMP OVERFLOW ; LARGE POSITIVE EXPONENT IS ERROR
|
|
L_GETEXP_1 ASL ; EXPONENT TIMES 10
|
|
ASL ;
|
|
CLC ;
|
|
ADC EXPON ;
|
|
ASL ;
|
|
CLC ; <<< ASL ALREADY DID THIS! >>>
|
|
LDY #0 ; ADD THE NEW DIGIT
|
|
ADC (TXTPTR),Y ; BUT THIS IS IN ASCII,
|
|
SEC ; SO ADJUST BACK TO BINARY
|
|
SBC #LOCHAR(`0')
|
|
L_GETEXP_2 STA EXPON ; NEW VALUE
|
|
JMP FIN_4 ; BACK FOR MORE
|
|
; --------------------------------
|
|
; --------------------------------
|
|
|
|
CON_99999999P9 ASM_DATA($9B,$3E,$BC,$1F,$FD) ; 99,999,999.9
|
|
CON_999999999 ASM_DATA($9E,$6E,$6B,$27,$FD) ; 999,999,999
|
|
CON_BILLION ASM_DATA($9E,$6E,$6B,$28,$00) ; 1,000,000,000
|
|
; --------------------------------
|
|
; PRINT "IN <LINE #>"
|
|
; --------------------------------
|
|
INPRT LDA #<QT_IN ; PRINT " IN "
|
|
LDY #>QT_IN
|
|
JSR GO_STROUT
|
|
LDA CURLIN+1
|
|
LDX CURLIN
|
|
; --------------------------------
|
|
; PRINT A,X AS DECIMAL INTEGER
|
|
; --------------------------------
|
|
LINPRT STA FAC+1 ; PRINT A,X IN DECIMAL
|
|
STX FAC+2 ;
|
|
LDX #$90 ; EXPONENT = 2^16
|
|
SEC ; CONVERT UNSIGNED
|
|
JSR FLOAT_2 ; CONVERT LINE # TO FP
|
|
; --------------------------------
|
|
; CONVERT (FAC) TO STRING, AND PRINT IT
|
|
; --------------------------------
|
|
PRINT_FAC ;
|
|
JSR FOUT ; CONVERT (FAC) TO STRING AT STACK
|
|
; --------------------------------
|
|
; PRINT STRING STARTING AT Y,A
|
|
; --------------------------------
|
|
GO_STROUT ;
|
|
JMP STROUT ; PRINT STRING AT A,Y
|
|
; --------------------------------
|
|
; CONVERT (FAC) TO STRING STARTING AT STACK
|
|
; RETURN WITH (Y,A) POINTING AT STRING
|
|
; --------------------------------
|
|
FOUT LDY #1 ; NORMAL ENTRY PUTS STRING AT STACK...
|
|
; --------------------------------
|
|
; "STR$" FUNCTION ENTERS HERE, WITH (Y)=0
|
|
; SO THAT RESULT STRING STARTS AT STACK-1
|
|
; (THIS IS USED AS A FLAG)
|
|
; --------------------------------
|
|
FOUT_1 LDA #LOCHAR(`-') ; IN CASE VALUE NEGATIVE
|
|
DEY ; BACK UP PNTR
|
|
BIT FAC_SIGN ;
|
|
BPL L_FOUT_1_1 ; VALUE IS +
|
|
INY ; VALUE IS -
|
|
STA STACK-1,Y ; EMIT "-"
|
|
L_FOUT_1_1 STA FAC_SIGN ; MAKE FAC.SIGN POSITIVE ($2D)
|
|
STY STRNG2 ; SAVE STRING PNTR
|
|
INY ;
|
|
LDA #LOCHAR(`0') ; IN CASE (FAC)=0
|
|
LDX FAC ; NUMBER=0?
|
|
BNE L_FOUT_1_2 ; NO, (FAC) NOT ZERO
|
|
JMP FOUT_4 ; YES, FINISHED
|
|
; --------------------------------
|
|
L_FOUT_1_2 LDA #0 ; STARTING VALUE FOR TMPEXP
|
|
CPX #$80 ; ANY INTEGER PART?
|
|
BEQ L_FOUT_1_3 ; NO, BTWN L_FOUT_1_5 AND L_FOUT_1_999999999
|
|
BCS L_FOUT_1_4 ; YES
|
|
; --------------------------------
|
|
L_FOUT_1_3 LDA #<CON_BILLION ; MULTIPLY BY 1E9
|
|
LDY #>CON_BILLION ; TO GIVE ADJUSTMENT A HEAD START
|
|
JSR FMULT ;
|
|
LDA #$100-9 ; EXPONENT ADJUSTMENT
|
|
L_FOUT_1_4 STA TMPEXP ; 0 OR -9
|
|
; --------------------------------
|
|
; ADJUST UNTIL 1E8 <= (FAC) <1E9
|
|
; --------------------------------
|
|
L_FOUT_1_5 LDA #<CON_999999999
|
|
LDY #>CON_999999999
|
|
JSR FCOMP ; COMPARE TO 1E9-1
|
|
BEQ L_FOUT_1_10 ; (FAC) = 1E9-1
|
|
BPL L_FOUT_1_8 ; TOO LARGE, DIVIDE BY TEN
|
|
L_FOUT_1_6 LDA #<CON_99999999P9 ; COMPARE TO 1E8-L_FOUT_1_1
|
|
LDY #>CON_99999999P9
|
|
JSR FCOMP ; COMPARE TO 1E8-L_FOUT_1_1
|
|
BEQ L_FOUT_1_7 ; (FAC) = 1E8-L_FOUT_1_1
|
|
BPL L_FOUT_1_9 ; IN RANGE, ADJUSTMENT FINISHED
|
|
L_FOUT_1_7 JSR MUL10 ; TOO SMALL, MULTIPLY BY TEN
|
|
DEC TMPEXP ; KEEP TRACK OF MULTIPLIES
|
|
BNE L_FOUT_1_6 ; ...ALWAYS
|
|
L_FOUT_1_8 JSR DIV10 ; TOO LARGE, DIVIDE BY TEN
|
|
INC TMPEXP ; KEEP TRACK OF DIVISIONS
|
|
BNE L_FOUT_1_5 ; ...ALWAYS
|
|
; --------------------------------
|
|
L_FOUT_1_9 JSR FADDH ; ROUND ADJUSTED RESULT
|
|
L_FOUT_1_10 JSR QINT ; CONVERT ADJUSTED VALUE TO 32-BIT INTEGER
|
|
; --------------------------------
|
|
; FAC+1...FAC+4 IS NOW IN INTEGER FORM
|
|
; WITH POWER OF TEN ADJUSTMENT IN TMPEXP
|
|
;
|
|
; IF -10 < TMPEXP > 1, PRINT IN DECIMAL FORM
|
|
; OTHERWISE, PRINT IN EXPONENTIAL FORM
|
|
; --------------------------------
|
|
FOUT_2 LDX #1 ; ASSUME 1 DIGIT BEFORE "."
|
|
LDA TMPEXP ; CHECK RANGE
|
|
CLC ;
|
|
ADC #10 ;
|
|
BMI L_FOUT_2_1 ; < .01, USE EXPONENTIAL FORM
|
|
CMP #11 ;
|
|
BCS L_FOUT_2_2 ; >= 1E10, USE EXPONENTIAL FORM
|
|
ADC #$FF ; LESS 1 GIVES INDEX FOR "."
|
|
TAX ;
|
|
LDA #2 ; SET REMAINING EXPONENT = 0
|
|
L_FOUT_2_1 SEC ; COMPUTE REMAINING EXPONENT
|
|
L_FOUT_2_2 SBC #2 ;
|
|
STA EXPON ; VALUE FOR "E+XX" OR "E-XX"
|
|
STX TMPEXP ; INDEX FOR DECIMAL POINT
|
|
TXA ; SEE IF "." COMES FIRST
|
|
BEQ L_FOUT_2_3 ; YES
|
|
BPL L_FOUT_2_5 ; NO, LATER
|
|
L_FOUT_2_3 LDY STRNG2 ; GET INDEX INTO STRING BEING BUILT
|
|
LDA #LOCHAR(`.') ; STORE A DECIMAL POINT
|
|
INY ;
|
|
STA STACK-1,Y ;
|
|
TXA ; SEE IF NEED ".0"
|
|
BEQ L_FOUT_2_4 ; NO
|
|
LDA #LOCHAR(`0') ; YES, STORE "0"
|
|
INY ;
|
|
STA STACK-1,Y ;
|
|
L_FOUT_2_4 STY STRNG2 ; SAVE OUTPUT INDEX AGAIN
|
|
; --------------------------------
|
|
; NOW DIVIDE BY POWERS OF TEN TO GET SUCCESSIVE DIGITS
|
|
; --------------------------------
|
|
L_FOUT_2_5 LDY #0 ; INDEX TO TABLE OF POWERS OF TEN
|
|
LDX #$80 ; STARTING VALUE FOR DIGIT WITH DIRECTION
|
|
L_FOUT_2_6 LDA FAC+4 ; START BY ADDING -100000000 UNTIL
|
|
CLC ; OVERSHOOT. THEN ADD +10000000,
|
|
ADC DECTBL+3,Y ; THEN ADD -1000000, THEN ADD
|
|
STA FAC+4 ; +100000, AND SO ON.
|
|
LDA FAC+3 ; THE # OF TIMES EACH POWER IS ADDED
|
|
ADC DECTBL+2,Y ; IS 1 MORE THAN CORRESPONDING DIGIT
|
|
STA FAC+3
|
|
LDA FAC+2
|
|
ADC DECTBL+1,Y
|
|
STA FAC+2
|
|
LDA FAC+1
|
|
ADC DECTBL,Y
|
|
STA FAC+1
|
|
INX ; COUNT THE ADD
|
|
BCS L_FOUT_2_7 ; IF C=1 AND X NEGATIVE, KEEP ADDING
|
|
BPL L_FOUT_2_6 ; IF C=0 AND X POSITIVE, KEEP ADDING
|
|
BMI L_FOUT_2_8 ; IF C=0 AND X NEGATIVE, WE OVERSHOT
|
|
L_FOUT_2_7 BMI L_FOUT_2_6 ; IF C=1 AND X POSITIVE, WE OVERSHOT
|
|
L_FOUT_2_8 TXA ; OVERSHOT, SO MAKE X INTO A DIGIT
|
|
BCC L_FOUT_2_9 ; HOW DEPENDS ON DIRECTION WE WERE GOING
|
|
EOR #$FF ; DIGIT = 9-X
|
|
ADC #10 ;
|
|
L_FOUT_2_9 ADC #LOCHAR(`0')-1 ; MAKE DIGIT INTO ASCII
|
|
INY ; ADVANCE TO NEXT SMALLER POWER OF TEN
|
|
INY ;
|
|
INY ;
|
|
INY ;
|
|
STY VARPNT ; SAVE PNTR TO POWERS
|
|
LDY STRNG2 ; GET OUTPUT PNTR
|
|
INY ; STORE THE DIGIT
|
|
TAX ; SAVE DIGIT, HI-BIT IS DIRECTION
|
|
AND #$7F ; MAKE SURE $30...$39 FOR STRING
|
|
STA STACK-1,Y ;
|
|
DEC TMPEXP ; COUNT THE DIGIT
|
|
BNE L_FOUT_2_10 ; NOT TIME FOR "." YET
|
|
LDA #LOCHAR(`.') ; TIME, SO STORE THE DECIMAL POINT
|
|
INY ;
|
|
STA STACK-1,Y ;
|
|
L_FOUT_2_10 STY STRNG2 ; SAVE OUTPUT PNTR AGAIN
|
|
LDY VARPNT ; GET PNTR TO POWERS
|
|
TXA ; GET DIGIT WITH HI-BIT = DIRECTION
|
|
EOR #$FF ; CHANGE DIRECTION
|
|
AND #$80 ; $00 IF ADDING, $80 IF SUBTRACTING
|
|
TAX
|
|
CPY #DECTBL_END-DECTBL
|
|
BNE L_FOUT_2_6 ; NOT FINISHED YET
|
|
; --------------------------------
|
|
; NINE DIGITS HAVE BEEN STORED IN STRING. NOW LOOK
|
|
; BACK AND LOP OFF TRAILING ZEROES AND A TRAILING
|
|
; DECIMAL POINT.
|
|
; --------------------------------
|
|
FOUT_3 LDY STRNG2 ; POINTS AT LAST STORED CHAR
|
|
L_FOUT_3_1 LDA STACK-1,Y ; SEE IF LOPPABLE
|
|
DEY ;
|
|
CMP #LOCHAR(`0') ; SUPPRESS TRAILING ZEROES
|
|
BEQ L_FOUT_3_1 ; YES, KEEP LOOPING
|
|
CMP #LOCHAR(`.') ; SUPPRESS TRAILING DECIMAL POINT
|
|
BEQ L_FOUT_3_2 ; ".", SO WRITE OVER IT
|
|
INY ; NOT ".", SO INCLUDE IN STRING AGAIN
|
|
L_FOUT_3_2 LDA #LOCHAR(`+') ; PREPARE FOR POSITIVE EXPONENT "E+XX"
|
|
LDX EXPON ; SEE IF ANY E-VALUE
|
|
BEQ FOUT_5 ; NO, JUST MARK END OF STRING
|
|
BPL L_FOUT_3_3 ; YES, AND IT IS POSITIVE
|
|
LDA #0 ; YES, AND IT IS NEGATIVE
|
|
SEC ; COMPLEMENT THE VALUE
|
|
SBC EXPON ;
|
|
TAX ; GET MAGNITUDE IN X
|
|
LDA #LOCHAR(`-') ; E SIGN
|
|
L_FOUT_3_3 STA STACK+1,Y ; STORE SIGN IN STRING
|
|
LDA #LOCHAR(`E') ; STORE "E" IN STRING BEFORE SIGN
|
|
STA STACK,Y ;
|
|
TXA ; EXPONENT MAGNITUDE IN A-REG
|
|
LDX #LOCHAR(`0')-1 ; SEED FOR EXPONENT DIGIT
|
|
SEC ; CONVERT TO DECIMAL
|
|
L_FOUT_3_4 INX ; COUNT THE SUBTRACTION
|
|
SBC #10 ; TEN'S DIGIT
|
|
BCS L_FOUT_3_4 ; MORE TENS TO SUBTRACT
|
|
ADC #LOCHAR(`0')+10 ; CONVERT REMAINDER TO ONE'S DIGIT
|
|
STA STACK+3,Y ; STORE ONE'S DIGIT
|
|
TXA ;
|
|
STA STACK+2,Y ; STORE TEN'S DIGIT
|
|
LDA #0 ; MARK END OF STRING WITH $00
|
|
STA STACK+4,Y ;
|
|
BEQ FOUT_6 ; ...ALWAYS
|
|
FOUT_4 STA STACK-1,Y ; STORE "0" IN ASCII
|
|
FOUT_5 LDA #0 ; STORE $00 ON END OF STRING
|
|
STA STACK,Y ;
|
|
FOUT_6 LDA #<STACK ; POINT Y,A AT BEGINNING OF STRING
|
|
LDY #>STACK ; (STR$ STARTED STRING AT STACK-1, BUT
|
|
RTS ; STR$ DOESN'T USE Y,A ANYWAY.)
|
|
; --------------------------------
|
|
|
|
CON_HALF ASM_DATA($80,$00,$00,$00,$00) ; FP CONSTANT 0L_CON_HALF_5
|
|
; --------------------------------
|
|
; POWERS OF 10 FROM 1E8 DOWN TO 1,
|
|
; AS 32-BIT INTEGERS, WITH ALTERNATING SIGNS
|
|
; --------------------------------
|
|
|
|
DECTBL ASM_DATA($FA,$0A,$1F,$00) ; -100000000
|
|
ASM_DATA($00,$98,$96,$80) ; 10000000
|
|
ASM_DATA($FF,$F0,$BD,$C0) ; -1000000
|
|
ASM_DATA($00,$01,$86,$A0) ; 100000
|
|
ASM_DATA($FF,$FF,$D8,$F0) ; -10000
|
|
ASM_DATA($00,$00,$03,$E8) ; 1000
|
|
ASM_DATA($FF,$FF,$FF,$9C) ; -100
|
|
ASM_DATA($00,$00,$00,$0A) ; 10
|
|
ASM_DATA($FF,$FF,$FF,$FF) ; -1
|
|
DECTBL_END
|
|
; --------------------------------
|
|
; --------------------------------
|
|
; "SQR" FUNCTION
|
|
;
|
|
; <<< UNFORTUNATELY, RATHER THAN A NEWTON-RAPHSON >>>
|
|
; <<< ITERATION, APPLESOFT USES EXPONENTIATION >>>
|
|
; <<< SQR(X) = X^L_DECTBL_END_5 >>>
|
|
; --------------------------------
|
|
SQR JSR COPY_FAC_TO_ARG_ROUNDED
|
|
LDA #<CON_HALF ; SET UP POWER OF 0L_SQR_5
|
|
LDY #>CON_HALF
|
|
JSR LOAD_FAC_FROM_YA
|
|
; --------------------------------
|
|
; EXPONENTIATION OPERATION
|
|
;
|
|
; ARG ^ FAC = EXP( LOG(ARG) * FAC )
|
|
; --------------------------------
|
|
FPWRT BEQ EXP ; IF FAC=0, ARG^FAC=EXP(0)
|
|
LDA ARG ; IF ARG=0, ARG^FAC=0
|
|
BNE L_FPWRT_1 ; NEITHER IS ZERO
|
|
JMP STA_IN_FAC_SIGN_AND_EXP ; SET FAC = 0
|
|
L_FPWRT_1 LDX #TEMP3 ; SAVE FAC IN TEMP3
|
|
LDY #0
|
|
JSR STORE_FACDB_YX_ROUNDED
|
|
LDA ARG_SIGN ; NORMALLY, ARG MUST BE POSITIVE
|
|
BPL L_FPWRT_2 ; IT IS POSITIVE, SO ALL IS WELL
|
|
JSR INT ; NEGATIVE, BUT OK IF INTEGRAL POWER
|
|
LDA #TEMP3 ; SEE IF INT(FAC)=FAC
|
|
LDY #0 ;
|
|
JSR FCOMP ; IS IT AN INTEGER POWER?
|
|
BNE L_FPWRT_2 ; NOT INTEGRAL, WILL CAUSE ERROR LATER
|
|
TYA ; MAKE ARG SIGN + AS IT IS MOVED TO FAC
|
|
LDY CHARAC ; INTEGRAL, SO ALLOW NEGATIVE ARG
|
|
L_FPWRT_2 JSR MFA ; MOVE ARGUMENT TO FAC
|
|
TYA ; SAVE FLAG FOR NEGATIVE ARG (0=+)
|
|
PHA ;
|
|
JSR LOG ; GET LOG(ARG)
|
|
LDA #TEMP3 ; MULTIPLY BY POWER
|
|
LDY #0 ;
|
|
JSR FMULT ;
|
|
JSR EXP ; E ^ LOG(FAC)
|
|
PLA ; GET FLAG FOR NEGATIVE ARG
|
|
LSR ; <<<LSR,BCC COULD BE MERELY BPL>>>
|
|
BCC RTS_18 ; NOT NEGATIVE, FINISHED
|
|
; NEGATIVE ARG, SO NEGATE RESULT
|
|
; --------------------------------
|
|
; NEGATE VALUE IN FAC
|
|
; --------------------------------
|
|
NEGOP LDA FAC ; IF FAC=0, NO NEED TO COMPLEMENT
|
|
BEQ RTS_18 ; YES, FAC=0
|
|
LDA FAC_SIGN ; NO, SO TOGGLE SIGN
|
|
EOR #$FF
|
|
STA FAC_SIGN
|
|
RTS_18 RTS
|
|
; --------------------------------
|
|
|
|
CON_LOG_E ASM_DATA($81,$38,$AA,$3B,$29) ; LOG(E) TO BASE 2
|
|
; --------------------------------
|
|
POLY_EXP ASM_DATA(7) ; ( # OF TERMS IN POLYNOMIAL) - 1
|
|
ASM_DATA($71,$34,$58,$3E,$56) ; (LOG(2)^7)/8!
|
|
ASM_DATA($74,$16,$7E,$B3,$1B) ; (LOG(2)^6)/7!
|
|
ASM_DATA($77,$2F,$EE,$E3,$85) ; (LOG(2)^5)/6!
|
|
ASM_DATA($7A,$1D,$84,$1C,$2A) ; (LOG(2)^4)/5!
|
|
ASM_DATA($7C,$63,$59,$58,$0A) ; (LOG(2)^3)/4!
|
|
ASM_DATA($7E,$75,$FD,$E7,$C6) ; (LOG(2)^2)/3!
|
|
ASM_DATA($80,$31,$72,$18,$10) ; LOG(2)/2!
|
|
ASM_DATA($81,$00,$00,$00,$00) ; 1
|
|
; --------------------------------
|
|
; "EXP" FUNCTION
|
|
;
|
|
; FAC = E ^ FAC
|
|
; --------------------------------
|
|
EXP LDA #<CON_LOG_E ; CONVERT TO POWER OF TWO PROBLEM
|
|
LDY #>CON_LOG_E ; E^X = 2^(LOG2(E)*X)
|
|
JSR FMULT ;
|
|
LDA FAC_EXTENSION ; NON-STANDARD ROUNDING HERE
|
|
ADC #$50 ; ROUND UP IF EXTENSION > $AF
|
|
BCC L_EXP_1 ; NO, DON'T ROUND UP
|
|
JSR INCREMENT_MANTISSA
|
|
L_EXP_1 STA ARG_EXTENSION ; STRANGE VALUE
|
|
JSR MAF ; COPY FAC INTO ARG
|
|
LDA FAC ; MAXIMUM EXPONENT IS < 128
|
|
CMP #$88 ; WITHIN RANGE?
|
|
BCC L_EXP_3 ; YES
|
|
L_EXP_2 JSR OUTOFRNG ; OVERFLOW IF +, RETURN 0.0 IF -
|
|
L_EXP_3 JSR INT ; GET INT(FAC)
|
|
LDA CHARAC ; THIS IS THE INETGRAL PART OF THE POWER
|
|
CLC ; ADD TO EXPONENT BIAS + 1
|
|
ADC #$81 ;
|
|
BEQ L_EXP_2 ; OVERFLOW
|
|
SEC ; BACK OFF TO NORMAL BIAS
|
|
SBC #1 ;
|
|
PHA ; SAVE EXPONENT
|
|
; --------------------------------
|
|
LDX #5 ; SWAP ARG AND FAC
|
|
L_EXP_4 LDA ARG,X ; <<< WHY SWAP? IT IS DOING >>>
|
|
LDY FAC,X ; <<< -(A-B) WHEN (B-A) IS THE >>>
|
|
STA FAC,X ; <<< SAME THING! >>>
|
|
STY ARG,X
|
|
DEX
|
|
BPL L_EXP_4
|
|
LDA ARG_EXTENSION
|
|
STA FAC_EXTENSION
|
|
JSR FSUBT ; POWER-INT(POWER) --> FRACTIONAL PART
|
|
JSR NEGOP
|
|
LDA #<POLY_EXP
|
|
LDY #>POLY_EXP
|
|
JSR POLYNOMIAL ; COMPUTE F(X) ON FRACTIONAL PART
|
|
LDA #0
|
|
STA SGNCPR
|
|
PLA ; GET EXPONENT
|
|
JSR ADD_EXPONENTS_1
|
|
RTS ; <<< WASTED BYTE HERE, COULD HAVE >>>
|
|
; <<< JUST USED "JMP ADD.EXPO..." >>>
|
|
; --------------------------------
|
|
; ODD POLYNOMIAL SUBROUTINE
|
|
;
|
|
; F(X) = X * P(X^2)
|
|
;
|
|
; WHERE: X IS VALUE IN FAC
|
|
; Y,A POINTS AT COEFFICIENT TABLE
|
|
; FIRST BYTE OF COEFF. TABLE IS N
|
|
; COEFFICIENTS FOLLOW, HIGHEST POWER FIRST
|
|
;
|
|
; P(X^2) COMPUTED USING NORMAL POLYNOMIAL SUBROUTINE
|
|
;
|
|
; --------------------------------
|
|
POLYNOMIAL_ODD
|
|
STA SERPNT ; SAVE ADDRESS OF COEFFICIENT TABLE
|
|
STY SERPNT+1
|
|
JSR STORE_FAC_IN_TEMP1_ROUNDED
|
|
LDA #TEMP1 ; Y=0 ALREADY, SO Y,A POINTS AT TEMP1
|
|
JSR FMULT ; FORM X^2
|
|
JSR SERMAIN ; DO SERIES IN X^2
|
|
LDA #<TEMP1 ; GET X AGAIN
|
|
LDY #>TEMP1 ;
|
|
JMP FMULT ; MULTIPLY X BY P(X^2) AND EXIT
|
|
; --------------------------------
|
|
; NORMAL POLYNOMIAL SUBROUTINE
|
|
;
|
|
; P(X) = C(0)*X^N + C(1)*X^(N-1) + ... + C(N)
|
|
;
|
|
; WHERE: X IS VALUE IN FAC
|
|
; Y,A POINTS AT COEFFICIENT TABLE
|
|
; FIRST BYTE OF COEFF. TABLE IS N
|
|
; COEFFICIENTS FOLLOW, HIGHEST POWER FIRST
|
|
;
|
|
; --------------------------------
|
|
POLYNOMIAL
|
|
STA SERPNT ; POINTER TO COEFFICIENT TABLE
|
|
STY SERPNT+1
|
|
; --------------------------------
|
|
SERMAIN
|
|
JSR STORE_FAC_IN_TEMP2_ROUNDED
|
|
LDA (SERPNT),Y ; GET N
|
|
STA SERLEN ; SAVE N
|
|
LDY SERPNT ; BUMP PNTR TO HIGHEST COEFFICIENT
|
|
INY ; AND GET PNTR INTO Y,A
|
|
TYA
|
|
BNE L_SERMAIN_1
|
|
INC SERPNT+1
|
|
L_SERMAIN_1 STA SERPNT
|
|
LDY SERPNT+1
|
|
L_SERMAIN_2 JSR FMULT ; ACCUMULATE SERIES TERMS
|
|
LDA SERPNT ; BUMP PNTR TO NEXT COEFFICIENT
|
|
LDY SERPNT+1
|
|
CLC
|
|
ADC #5
|
|
BCC L_SERMAIN_3
|
|
INY
|
|
L_SERMAIN_3 STA SERPNT
|
|
STY SERPNT+1
|
|
JSR FADD ; ADD NEXT COEFFICIENT
|
|
LDA #TEMP2 ; POINT AT X AGAIN
|
|
LDY #0 ;
|
|
DEC SERLEN ; IF SERIES NOT FINISHED,
|
|
BNE L_SERMAIN_2 ; THEN ADD ANOTHER TERM
|
|
RTS_19 RTS ; FINISHED
|
|
; --------------------------------
|
|
|
|
CON_RND_1 ASM_DATA($98,$35,$44,$7A) ; <<< THESE ARE MISSING ONE BYTE >>>
|
|
CON_RND_2 ASM_DATA($68,$28,$B1,$46) ; <<< FOR FP VALUES >>>
|
|
; --------------------------------
|
|
; "RND" FUNCTION
|
|
; --------------------------------
|
|
RND JSR SIGN ; REDUCE ARGUMENT TO -1, 0, OR +1
|
|
TAX ; SAVE ARGUMENT
|
|
BMI L_RND_1 ; = -1, USE CURRENT ARGUMENT FOR SEED
|
|
LDA #<RNDSEED ; USE CURRENT SEED
|
|
LDY #>RNDSEED
|
|
JSR LOAD_FAC_FROM_YA
|
|
TXA ; RECALL SIGN OF ARGUMENT
|
|
BEQ RTS_19 ; =0, RETURN SEED UNCHANGED
|
|
LDA #<CON_RND_1 ; VERY POOR RND ALGORITHM
|
|
LDY #>CON_RND_1
|
|
JSR FMULT
|
|
LDA #<CON_RND_2 ; ALSO, CONSTANTS ARE TRUNCATED
|
|
LDY #>CON_RND_2 ; <<<THIS DOES NOTHING, DUE TO >>>
|
|
; <<<SMALL EXPONENT >>>
|
|
JSR FADD
|
|
L_RND_1 LDX FAC+4 ; SHUFFLE HI AND LO BYTES
|
|
LDA FAC+1 ; TO SUPPOSEDLY MAKE IT MORE RANDOM
|
|
STA FAC+4 ;
|
|
STX FAC+1 ;
|
|
LDA #0 ; MAKE IT POSITIVE
|
|
STA FAC_SIGN ;
|
|
LDA FAC ; A SOMEWHAT RANDOM EXTENSION
|
|
STA FAC_EXTENSION
|
|
LDA #$80 ; EXPONENT TO MAKE VALUE < 1.0
|
|
STA FAC
|
|
JSR NORMALIZE_FAC_2
|
|
LDX #<RNDSEED ; MOVE FAC TO RND SEED
|
|
LDY #>RNDSEED
|
|
GO_MOVMF JMP STORE_FACDB_YX_ROUNDED
|
|
; --------------------------------
|
|
; --------------------------------
|
|
; "COS" FUNCTION
|
|
; --------------------------------
|
|
COS LDA #<CON_PI_HALF ; COS(X)=SIN(X + PI/2)
|
|
LDY #>CON_PI_HALF
|
|
JSR FADD
|
|
; --------------------------------
|
|
; "SIN" FUNCTION
|
|
; --------------------------------
|
|
SIN JSR COPY_FAC_TO_ARG_ROUNDED
|
|
LDA #<CON_PI_DOUB ; REMOVE MULTIPLES OF 2*PI
|
|
LDY #>CON_PI_DOUB ; BY DIVIDING AND SAVING
|
|
LDX ARG_SIGN ; THE FRACTIONAL PART
|
|
JSR DIV ; USE SIGN OF ARGUMENT
|
|
JSR COPY_FAC_TO_ARG_ROUNDED
|
|
JSR INT ; TAKE INTEGER PART
|
|
LDA #0 ; <<< WASTED LINES, BECAUSE FSUBT >>>
|
|
STA SGNCPR ; <<< CHANGES SGNCPR AGAIN >>>
|
|
JSR FSUBT ; SUBTRACT TO GET FRACTIONAL PART
|
|
; --------------------------------
|
|
; (FAC) = ANGLE AS A FRACTION OF A FULL CIRCLE
|
|
;
|
|
; NOW FOLD THE RANGE INTO A QUARTER CIRCLE
|
|
;
|
|
; <<< THERE ARE MUCH SIMPLER WAYS TO DO THIS >>>
|
|
; --------------------------------
|
|
LDA #<QUARTER ; 1/4 - FRACTION MAKES
|
|
LDY #>QUARTER ; -3/4 <= FRACTION < 1/4
|
|
JSR FSUB ;
|
|
LDA FAC_SIGN ; TEST SIGN OF RESULT
|
|
PHA ; SAVE SIGN FOR LATER UNFOLDING
|
|
BPL SIN_1 ; ALREADY 0...1/4
|
|
JSR FADDH ; ADD 1/2 TO SHIFT TO -1/4...1/2
|
|
LDA FAC_SIGN ; TEST SIGN
|
|
BMI SIN_2 ; -1/4...0
|
|
; 0...1/2
|
|
LDA SIGNFLG ; SIGNFLG INITIALIZED = 0 IN "TAN"
|
|
EOR #$FF ; FUNCTION
|
|
STA SIGNFLG ; "TAN" IS ONLY USER OF SIGNFLG TOO
|
|
; --------------------------------
|
|
; IF FALL THRU, RANGE IS 0...1/2
|
|
; IF BRANCH HERE, RANGE IS 0...1/4
|
|
; --------------------------------
|
|
SIN_1 JSR NEGOP
|
|
; --------------------------------
|
|
; IF FALL THRU, RANGE IS -1/2...0
|
|
; IF BRANCH HERE, RANGE IS -1/4...0
|
|
; --------------------------------
|
|
SIN_2 LDA #<QUARTER ; ADD 1/4 TO SHIFT RANGE
|
|
LDY #>QUARTER ; TO -1/4...1/4
|
|
JSR FADD ;
|
|
PLA ; GET SAVED SIGN FROM ABOVE
|
|
BPL L_SIN_2_1 ;
|
|
JSR NEGOP ; MAKE RANGE 0...1/4
|
|
L_SIN_2_1 LDA #<POLY_SIN ; DO STANDARD SIN SERIES
|
|
LDY #>POLY_SIN ;
|
|
JMP POLYNOMIAL_ODD ;
|
|
; --------------------------------
|
|
; "TAN" FUNCTION
|
|
;
|
|
; COMPUTE TAN(X) = SIN(X) / COS(X)
|
|
; --------------------------------
|
|
TAN JSR STORE_FAC_IN_TEMP1_ROUNDED
|
|
LDA #0 ; SIGNFLG WILL BE TOGGLED IF 2ND OR 3RD
|
|
STA SIGNFLG ; QUADRANT
|
|
JSR SIN ; GET SIN(X)
|
|
LDX #<TEMP3 ; SAVE SIN(X) IN TEMP3
|
|
LDY #>TEMP3 ;
|
|
JSR GO_MOVMF ; <<<FUNNY WAY TO CALL MOVMF! >>>
|
|
LDA #<TEMP1 ; RETRIEVE X
|
|
LDY #>TEMP1 ;
|
|
JSR LOAD_FAC_FROM_YA
|
|
LDA #0 ; AND COMPUTE COS(X)
|
|
STA FAC_SIGN ;
|
|
LDA SIGNFLG ;
|
|
JSR TAN_1 ; WEIRD & DANGEROUS WAY TO GET INTO SIN
|
|
LDA #<TEMP3 ; NOW FORM SIN/COS
|
|
LDY #>TEMP3 ;
|
|
JMP FDIV ;
|
|
; --------------------------------
|
|
TAN_1 PHA ; SHAME, SHAME!
|
|
JMP SIN_1
|
|
; --------------------------------
|
|
|
|
CON_PI_HALF ASM_DATA($81,$49,$0F,$DA,$A2)
|
|
CON_PI_DOUB ASM_DATA($83,$49,$0F,$DA,$A2)
|
|
QUARTER ASM_DATA($7F,$00,$00,$00,$00)
|
|
; --------------------------------
|
|
POLY_SIN ASM_DATA(5) ; POWER OF POLYNOMIAL
|
|
ASM_DATA($84,$E6,$1A,$2D,$1B) ; (2PI)^11/11!
|
|
ASM_DATA($86,$28,$07,$FB,$F8) ; (2PI)^9/9!
|
|
ASM_DATA($87,$99,$68,$89,$01) ; (2PI)^7/7!
|
|
ASM_DATA($87,$23,$35,$DF,$E1) ; (2PI)^5/5!
|
|
ASM_DATA($86,$A5,$5D,$E7,$28) ; (2PI)^3/3!
|
|
ASM_DATA($83,$49,$0F,$DA,$A2) ; 2PI
|
|
|
|
|
|
|
|
; --------------------------------
|
|
; <<< NEXT TEN BYTES ARE NEVER REFERENCED >>>
|
|
; OBFUSCATED "MICROSOFT!" BY BILL GATES
|
|
; (REVERSED, HIGH BIT SET, XOR 7)
|
|
; --------------------------------
|
|
|
|
define(`GATES_OBFUSCATE',
|
|
`STR_FORCHAR(__,STR_REVERSE($1),`ASM_DATA(HICHAR(__)^7) NL()')')
|
|
|
|
|
|
GATES_OBFUSCATE(`MICROSOFT!')
|
|
|
|
|
|
|
|
|
|
|
|
; --------------------------------
|
|
; "ATN" FUNCTION
|
|
; --------------------------------
|
|
ATN LDA FAC_SIGN ; FOLD THE ARGUMENT RANGE FIRST
|
|
PHA ; SAVE SIGN FOR LATER UNFOLDING
|
|
BPL L_ATN_1 ; .GE. 0
|
|
JSR NEGOP ; .LT. 0, SO COMPLEMENT
|
|
L_ATN_1 LDA FAC ; IF .GE. 1, FORM RECIPROCAL
|
|
PHA ; SAVE FOR LATER UNFOLDING
|
|
CMP #$81 ; (EXPONENT FOR .GE. 1
|
|
BCC L_ATN_2 ; X < 1
|
|
LDA #<CON_ONE ; FORM 1/X
|
|
LDY #>CON_ONE
|
|
JSR FDIV
|
|
; --------------------------------
|
|
; 0 <= X <= 1
|
|
; 0 <= ATN(X) <= PI/8
|
|
; --------------------------------
|
|
L_ATN_2 LDA #<POLY_ATN ; COMPUTE POLYNOMIAL APPROXIMATION
|
|
LDY #>POLY_ATN
|
|
JSR POLYNOMIAL_ODD
|
|
PLA ; START TO UNFOLD
|
|
CMP #$81 ; WAS IT .GE. 1?
|
|
BCC L_ATN_3 ; NO
|
|
LDA #<CON_PI_HALF ; YES, SUBTRACT FROM PI/2
|
|
LDY #>CON_PI_HALF ;
|
|
JSR FSUB ;
|
|
L_ATN_3 PLA ; WAS IT NEGATIVE?
|
|
BPL RTS_20 ; NO
|
|
JMP NEGOP ; YES, COMPLEMENT
|
|
RTS_20 RTS
|
|
; --------------------------------
|
|
POLY_ATN ASM_DATA(11) ; POWER OF POLYNOMIAL
|
|
ASM_DATA($76,$B3,$83,$BD,$D3)
|
|
ASM_DATA($79,$1E,$F4,$A6,$F5)
|
|
ASM_DATA($7B,$83,$FC,$B0,$10)
|
|
ASM_DATA($7C,$0C,$1F,$67,$CA)
|
|
ASM_DATA($7C,$DE,$53,$CB,$C1)
|
|
ASM_DATA($7D,$14,$64,$70,$4C)
|
|
ASM_DATA($7D,$B7,$EA,$51,$7A)
|
|
ASM_DATA($7D,$63,$30,$88,$7E)
|
|
ASM_DATA($7E,$92,$44,$99,$3A)
|
|
ASM_DATA($7E,$4C,$CC,$91,$C7)
|
|
ASM_DATA($7F,$AA,$AA,$AA,$13)
|
|
ASM_DATA($81,$00,$00,$00,$00)
|
|
; --------------------------------
|
|
; GENERIC COPY OF CHRGET SUBROUTINE, WHICH
|
|
; IS COPIED INTO $00B1...$00C8 DURING INITIALIZATION
|
|
;
|
|
; CORNELIS BONGERS DESCRIBED SEVERAL IMPROVEMENTS
|
|
; TO CHRGET IN MICRO MAGAZINE OR CALL A.P.P.L.E.
|
|
; (I DON'T REMEMBER WHICH OR EXACTLY WHEN)
|
|
; --------------------------------
|
|
GENERIC_CHRGET
|
|
INC TXTPTR
|
|
BNE L_GENERIC_CHRGET_1
|
|
INC TXTPTR+1
|
|
L_GENERIC_CHRGET_1 LDA $EA60 ; <<< ACTUAL ADDRESS FILLED IN LATER >>>
|
|
CMP #LOCHAR(`:') ; EOS, ALSO TOP OF NUMERIC RANGE
|
|
BCS L_GENERIC_CHRGET_2 ; NOT NUMBER, MIGHT BE EOS
|
|
CMP #LOCHAR(` ') ; IGNORE BLANKS
|
|
BEQ GENERIC_CHRGET
|
|
SEC ; TEST FOR NUMERIC RANGE IN WAY THAT
|
|
SBC #LOCHAR(`0') ; CLEARS CARRY IF CHAR IS DIGIT
|
|
SEC ; AND LEAVES CHAR IN A-REG
|
|
SBC #$D0
|
|
L_GENERIC_CHRGET_2 RTS
|
|
; --------------------------------
|
|
; INITIAL VALUE FOR RANDOM NUMBER, ALSO COPIED
|
|
; IN ALONG WITH CHRGET, BUT ERRONEOUSLY:
|
|
; <<< THE LAST BYTE IS NOT COPIED >>>
|
|
; --------------------------------
|
|
|
|
ASM_DATA($80,$4F,$C7,$52,$58) ; APPROX. = L_GENERIC_CHRGET_811635157
|
|
GENERIC_END
|
|
; --------------------------------
|
|
COLD_START
|
|
LDX #$FF ; SET DIRECT MODE FLAG
|
|
STX CURLIN+1 ;
|
|
LDX #$FB ; SET STACK POINTER, LEAVING ROOM FOR
|
|
TXS ; LINE BUFFER DURING PARSING
|
|
LDA #<COLD_START ; SET RESTART TO COLD.START
|
|
LDY #>COLD_START ; UNTIL COLDSTART IS COMPLETED
|
|
STA GOWARM+1 ;
|
|
STY GOWARM+2 ;
|
|
STA GOSTROUT+1 ; ALSO SECOND USER VECTOR...
|
|
STY GOSTROUT+2 ; ..WE SIMPLY MUST FINISH COLD.START!
|
|
JSR NORMAL ; SET NORMAL DISPLAY MODE
|
|
LDA #$4C ; "JMP" OPCODE FOR 4 VECTORS
|
|
STA GOWARM ; WARM START
|
|
STA GOSTROUT ; ANYONE EVER USE THIS ONE?
|
|
STA JMPADRS ; USED BY FUNCTIONS (JSR JMPADRS)
|
|
STA USR ; "USR" FUNCTION VECTOR
|
|
LDA #<IQERR ; POINT "USR" TO ILLEGAL QUANTITY
|
|
LDY #>IQERR ; ERROR, UNTIL USER SETS IT UP
|
|
STA USR+1
|
|
STY USR+2
|
|
; --------------------------------
|
|
; MOVE GENERIC CHRGET AND RANDOM SEED INTO PLACE
|
|
;
|
|
; <<< NOTE THAT LOOP VALUE IS WRONG! >>>
|
|
; <<< THE LAST BYTE OF THE RANDOM SEED IS NOT >>>
|
|
; <<< COPIED INTO PAGE ZERO! >>>
|
|
; --------------------------------
|
|
LDX #GENERIC_END-GENERIC_CHRGET-1
|
|
L_COLD_START_1 LDA GENERIC_CHRGET-1,X
|
|
STA CHRGET-1,X
|
|
STX SPEEDZ ; ON LAST PASS STORES $01)
|
|
DEX
|
|
BNE L_COLD_START_1
|
|
; --------------------------------
|
|
STX TRCFLG ; X=0, TURN OFF TRACING
|
|
TXA ; A=0
|
|
STA SHIFT_SIGN_EXT
|
|
STA LASTPT+1
|
|
PHA ; PUT $00 ON STACK (WHAT FOR?)
|
|
LDA #3 ; SET LENGTH OF TEMP. STRING DESCRIPTORS
|
|
STA DSCLEN ; FOR GARBAGE COLLECTION SUBROUTINE
|
|
JSR CRDO ; PRINT <RETURN>
|
|
LDA #1 ; SET UP FAKE FORWARD LINK
|
|
STA INPUT_BUFFER-3
|
|
STA INPUT_BUFFER-4
|
|
LDX #TEMPST ; INIT INDEX TO TEMP STRING DESCRIPTORS
|
|
STX TEMPPT
|
|
; --------------------------------
|
|
; FIND HIGH END OF RAM
|
|
; --------------------------------
|
|
LDA #<$0800 ; SET UP POINTER TO LOW END OF RAM
|
|
LDY #>$0800
|
|
STA LINNUM
|
|
STY LINNUM+1
|
|
LDY #0
|
|
L_COLD_START_2 INC LINNUM+1 ; TEST FIRST BYTE OF EACH PAGE
|
|
LDA (LINNUM),Y ; BY COMPLEMENTING IT AND WATCHING
|
|
EOR #$FF ; IT CHANGE THE SAME WAY
|
|
STA (LINNUM),Y ;
|
|
CMP (LINNUM),Y ; ROM OR EMPTY SOCKETS WON'T TRACK
|
|
BNE L_COLD_START_3 ; NOT RAM HERE
|
|
EOR #$FF ; RESTORE ORIGINAL VALUE
|
|
STA (LINNUM),Y ;
|
|
CMP (LINNUM),Y ; DID IT TRACK AGAIN?
|
|
BEQ L_COLD_START_2 ; YES, STILL IN RAM
|
|
L_COLD_START_3 LDY LINNUM ; NO, END OF RAM
|
|
LDA LINNUM+1 ;
|
|
AND #$F0 ; FORCE A MULTIPLE OF 4096 BYTES
|
|
STY MEMSIZ ; (BAD RAM MAY HAVE YIELDED NON-MULTIPLE)
|
|
STA MEMSIZ+1 ;
|
|
STY FRETOP ; SET HIMEM AND BOTTOM OF STRINGS
|
|
STA FRETOP+1 ;
|
|
LDX #<$0800 ; SET PROGRAM POINTER TO $0800
|
|
LDY #>$0800 ;
|
|
STX TXTTAB ;
|
|
STY TXTTAB+1 ;
|
|
LDY #0 ; TURN OFF SEMI-SECRET LOCK FLAG
|
|
STY LOCK ;
|
|
TYA ; A=0 TOO
|
|
STA (TXTTAB),Y ; FIRST BYTE IN PROGRAM SPACE = 0
|
|
INC TXTTAB ; ADVANCE PAST THE $00
|
|
BNE L_COLD_START_4 ;
|
|
INC TXTTAB+1 ;
|
|
L_COLD_START_4 LDA TXTTAB ;
|
|
LDY TXTTAB+1 ;
|
|
JSR REASON ; SET REST OF POINTERS UP
|
|
JSR SCRTCH ; MORE POINTERS
|
|
LDA #<STROUT ; PUT CORRECT ADDRESSES IN TWO
|
|
LDY #>STROUT ; USER VECTORS
|
|
STA GOSTROUT+1
|
|
STY GOSTROUT+2
|
|
LDA #<RESTART
|
|
LDY #>RESTART
|
|
STA GOWARM+1
|
|
STY GOWARM+2
|
|
JMP (GOWARM+1) ; SILLY, WHY NOT JUST "JMP RESTART"
|
|
; --------------------------------
|
|
; --------------------------------
|
|
; "CALL" STATEMENT
|
|
;
|
|
; EFFECTIVELY PERFORMS A "JSR" TO THE SPECIFIED
|
|
; ADDRESS, WITH THE FOLLOWING REGISTER CONTENTS:
|
|
; (A,Y) = CALL ADDRESS
|
|
; (X) = $9D
|
|
;
|
|
; THE CALLED ROUTINE CAN RETURN WITH "RTS",
|
|
; AND APPLESOFT WILL CONTINUE WITH THE NEXT
|
|
; STATEMENT.
|
|
; --------------------------------
|
|
CALL JSR FRMNUM ; EVALUATE EXPRESSION FOR CALL ADDRESS
|
|
JSR GETADR ; CONVERT EXPRESSION TO 16-BIT INTEGER
|
|
JMP (LINNUM) ; IN LINNUM, AND JUMP THERE.
|
|
; --------------------------------
|
|
; "IN#" STATEMENT
|
|
;
|
|
; NOTE: NO CHECK FOR VALID SLOT #, AS LONG
|
|
; AS VALUE IS < 256 IT IS ACCEPTED.
|
|
; MONITOR MASKS VALUE TO 4 BITS (0-15).
|
|
; --------------------------------
|
|
IN_NUMBER
|
|
JSR GETBYT ; GET SLOT NUMBER IN X-REG
|
|
TXA ; MONITOR WILL INSTALL IN VECTOR
|
|
JMP MON_INPORT ; AT $38,39.
|
|
; --------------------------------
|
|
; "PR#" STATEMENT
|
|
;
|
|
; NOTE: NO CHECK FOR VALID SLOT #, AS LONG
|
|
; AS VALUE IS < 256 IT IS ACCEPTED.
|
|
; MONITOR MASKS VALUE TO 4 BITS (0-15).
|
|
; --------------------------------
|
|
PR_NUMBER
|
|
JSR GETBYT ; GET SLOT NUMBER IN X-REG
|
|
TXA ; MONITOR WILL INSTALL IN VECTOR
|
|
JMP MON_OUTPORT ; AT $36,37
|
|
; --------------------------------
|
|
; GET TWO VALUES < 48, WITH COMMA SEPARATOR
|
|
;
|
|
; CALLED FOR "PLOT X,Y"
|
|
; AND "HLIN A,B AT Y"
|
|
; AND "VLIN A,B AT X"
|
|
;
|
|
; --------------------------------
|
|
PLOTFNS
|
|
JSR GETBYT ; GET FIRST VALUE IN X-REG
|
|
CPX #48 ; MUST BE < 48
|
|
BCS GOERR ; TOO LARGE
|
|
STX FIRST ; SAVE FIRST VALUE
|
|
LDA #LOCHAR(`,') ; MUST HAVE A COMMA
|
|
JSR SYNCHR ;
|
|
JSR GETBYT ; GET SECOND VALUE IN X-REG
|
|
CPX #48 ; MUST BE < 48
|
|
BCS GOERR ; TOO LARGE
|
|
STX MON_H2 ; SAVE SECOND VALUE
|
|
STX MON_V2 ;
|
|
RTS ; SECOND VALUE STILL IN X-REG
|
|
; --------------------------------
|
|
GOERR JMP IQERR ; ILLEGAL QUANTITY ERROR
|
|
; --------------------------------
|
|
; GET "A,B AT C" VALUES FOR "HLIN" AND "VLIN"
|
|
;
|
|
; PUT SMALLER OF (A,B) IN FIRST,
|
|
; AND LARGER OF (A,B) IN H2 AND V2.
|
|
; RETURN WITH (X) = C-VALUE.
|
|
; --------------------------------
|
|
LINCOOR
|
|
JSR PLOTFNS ; GET A,B VALUES
|
|
CPX FIRST ; IS A < B?
|
|
BCS L_LINCOOR_1 ; YES, IN RIGHT ORDER
|
|
LDA FIRST ; NO, INTERCHANGE THEM
|
|
STA MON_H2 ;
|
|
STA MON_V2 ;
|
|
STX FIRST ;
|
|
L_LINCOOR_1 LDA #TOKENDB ; MUST HAVE "AT" NEXT
|
|
JSR SYNCHR ;
|
|
JSR GETBYT ; GET C-VALUE IN X-REG
|
|
CPX #48 ; MUST BE < 48
|
|
BCS GOERR ; TOO LARGE
|
|
RTS ; C-VALUE IN X-REG
|
|
; --------------------------------
|
|
; "PLOT" STATEMENT
|
|
; --------------------------------
|
|
PLOT JSR PLOTFNS ; GET X,Y VALUES
|
|
TXA ; Y-COORD TO A-REG FOR MONITOR
|
|
LDY FIRST ; X-COORD TO Y-YEG FOR MONITOR
|
|
CPY #40 ; X-COORD MUST BE < 40
|
|
BCS GOERR ; X-COORD IS TOO LARGE
|
|
JMP MON_PLOT ; PLOT!
|
|
; --------------------------------
|
|
; "HLIN" STATEMENT
|
|
; --------------------------------
|
|
HLIN JSR LINCOOR ; GET "A,B AT C"
|
|
TXA ; Y-COORD IN A-REG
|
|
LDY MON_H2 ; RIGHT END OF LINE
|
|
CPY #40 ; MUST BE < 40
|
|
BCS GOERR ; TOO LARGE
|
|
LDY FIRST ; LEFT END OF LINE IN Y-REG
|
|
JMP MON_HLINE ; LET MONITOR DRAW LINE
|
|
; --------------------------------
|
|
; "VLIN" STATEMENT
|
|
; --------------------------------
|
|
VLIN JSR LINCOOR ; GET "A,B AT C"
|
|
TXA ; X-COORD IN Y-REG
|
|
TAY ;
|
|
CPY #40 ; X-COORD MUST BE < 40
|
|
BCS GOERR ; TOO LARGE
|
|
LDA FIRST ; TOP END OF LINE IN A-REG
|
|
JMP MON_VLINE ; LET MONITOR DRAW LINE
|
|
; --------------------------------
|
|
; "COLOR=" STATEMENT
|
|
; --------------------------------
|
|
COLOR JSR GETBYT ; GET COLOR VALUE IN X-REG
|
|
TXA ;
|
|
JMP MON_SETCOL ; LET MONITOR STORE COLOR
|
|
; --------------------------------
|
|
; "VTAB" STATEMENT
|
|
; --------------------------------
|
|
VTAB JSR GETBYT ; GET LINE # IN X-REG
|
|
DEX ; CONVERT TO ZERO BASE
|
|
TXA ;
|
|
CMP #24 ; MUST BE 0-23
|
|
BCS GOERR ; TOO LARGE, OR WAS "VTAB 0"
|
|
JMP MON_TABV ; LET MONITOR COMPUTE BASE
|
|
; --------------------------------
|
|
; "SPEED=" STATEMENT
|
|
; --------------------------------
|
|
SPEED JSR GETBYT ; GET SPEED SETTING IN X-REG
|
|
TXA ; SPEEDZ = $100-SPEED
|
|
EOR #$FF ; SO "SPEED=255" IS FASTEST
|
|
TAX ;
|
|
INX ;
|
|
STX SPEEDZ ;
|
|
RTS ;
|
|
; --------------------------------
|
|
; "TRACE" STATEMENT
|
|
; SET SIGN BIT IN TRCFLG
|
|
; --------------------------------
|
|
TRACE SEC ;
|
|
ASM_DATA($90) ; FAKE BCC TO SKIP NEXT OPCODE
|
|
; --------------------------------
|
|
; "NOTRACE" STATEMENT
|
|
; CLEAR SIGN BIT IN TRCFLG
|
|
; --------------------------------
|
|
NOTRACE ;
|
|
CLC ;
|
|
ROR TRCFLG ; SHIFT CARRY INTO TRCFLG
|
|
RTS ;
|
|
; --------------------------------
|
|
; "NORMAL" STATEMENT
|
|
; --------------------------------
|
|
NORMAL LDA #$FF ; SET INVFLG = $FF
|
|
BNE N_I_ ; AND FLASH.BIT = $00
|
|
; --------------------------------
|
|
; "INVERSE" STATEMENT
|
|
; --------------------------------
|
|
INVERSE ;
|
|
LDA #$3F ; SET INVFLG = $3F
|
|
N_I_ LDX #0 ; AND FLASH.BIT = $00
|
|
N_I_F_ STA MON_INVFLG
|
|
STX FLASH_BIT
|
|
RTS
|
|
; --------------------------------
|
|
; "FLASH" STATEMENT
|
|
; --------------------------------
|
|
FLASH LDA #$7F ; SET INVFLG = $7F
|
|
LDX #$40 ; AND FLASH.BIT = $40
|
|
BNE N_I_F_ ; ...ALWAYS
|
|
; --------------------------------
|
|
; "HIMEM:" STATEMENT
|
|
; --------------------------------
|
|
HIMEM JSR FRMNUM ; GET VALUE SPECIFIED FOR HIMEM
|
|
JSR GETADR ; AS 16-BIT INTEGER
|
|
LDA LINNUM ; MUST BE ABOVE VARIABLES AND ARRAYS
|
|
CMP STREND ;
|
|
LDA LINNUM+1 ;
|
|
SBC STREND+1 ;
|
|
BCS SETHI ; IT IS ABOVE THEM
|
|
JMM JMP MEMERR ; NOT ENOUGH MEMORY
|
|
SETHI LDA LINNUM ; STORE NEW HIMEM: VALUE
|
|
STA MEMSIZ ;
|
|
STA FRETOP ; <<<NOTE THAT "HIMEM:" DOES NOT>>>
|
|
LDA LINNUM+1 ; <<<CLEAR STRING VARIABLES. >>>
|
|
STA MEMSIZ+1 ; <<<THIS COULD BE DISASTROUS. >>>
|
|
STA FRETOP+1 ;
|
|
RTS ;
|
|
; --------------------------------
|
|
; "LOMEM:" STATEMENT
|
|
; --------------------------------
|
|
LOMEM JSR FRMNUM ; GET VALUE SPECIFIED FOR LOMEM
|
|
JSR GETADR ; AS 16-BIT INTEGER IN LINNUM
|
|
LDA LINNUM ; MUST BE BELOW HIMEM
|
|
CMP MEMSIZ ;
|
|
LDA LINNUM+1 ;
|
|
SBC MEMSIZ+1 ;
|
|
BCS JMM ; ABOVE HIMEM, MEMORY ERROR
|
|
LDA LINNUM ; MUST BE ABOVE PROGRAM
|
|
CMP VARTAB ;
|
|
LDA LINNUM+1 ;
|
|
SBC VARTAB+1 ;
|
|
BCC JMM ; NOT ABOVE PROGRAM, ERROR
|
|
LDA LINNUM ; STORE NEW LOMEM VALUE
|
|
STA VARTAB ;
|
|
LDA LINNUM+1 ;
|
|
STA VARTAB+1 ;
|
|
JMP CLEARC ; LOMEM CLEARS VARIABLES AND ARRAYS
|
|
; --------------------------------
|
|
; "ON ERR GO TO" STATEMENT
|
|
; --------------------------------
|
|
ONERR LDA #TOKEN_GOTO ; MUST BE "GOTO" NEXT
|
|
JSR SYNCHR
|
|
LDA TXTPTR ; SAVE TXTPTR FOR HANDLERR
|
|
STA TXTPSV ;
|
|
LDA TXTPTR+1 ;
|
|
STA TXTPSV+1 ;
|
|
SEC ; SET SIGN BIT OF ERRFLG
|
|
ROR ERRFLG ;
|
|
LDA CURLIN ; SAVE LINE # OF CURRENT LINE
|
|
STA CURLSV ;
|
|
LDA CURLIN+1 ;
|
|
STA CURLSV+1 ;
|
|
JSR REMN ; IGNORE REST OF LINE <<<WHY?>>>
|
|
JMP ADDON ; CONTINUE PROGRAM
|
|
; --------------------------------
|
|
; ROUTINE TO HANDLE ERRORS IF ONERR GOTO ACTIVE
|
|
; --------------------------------
|
|
HANDLERR ;
|
|
STX ERRNUM ; SAVE ERROR CODE NUMBER
|
|
LDX REMSTK ; GET STACK PNTR SAVED AT NEWSTT
|
|
STX ERRSTK ; REMEMBER IT
|
|
; <<<COULD ALSO HAVE DONE TXS >>>
|
|
; <<<HERE; SEE ONERR CORRECTION>>>
|
|
; <<<IN APPLESOFT MANUAL. >>>
|
|
LDA CURLIN ; GET LINE # OF OFFENDING STATEMENT
|
|
STA ERRLIN ; SO USER CAN SEE IT IF DESIRED
|
|
LDA CURLIN+1 ;
|
|
STA ERRLIN+1 ;
|
|
LDA OLDTEXT ; ALSO THE POSITION IN THE LINE
|
|
STA ERRPOS ; IN CASE USER WANTS TO "RESUME"
|
|
LDA OLDTEXT+1 ;
|
|
STA ERRPOS+1 ;
|
|
LDA TXTPSV ; SET UP TXTPTR TO READ TARGET LINE #
|
|
STA TXTPTR ; IN "ON ERR GO TO XXXX"
|
|
LDA TXTPSV+1 ;
|
|
STA TXTPTR+1 ;
|
|
LDA CURLSV ;
|
|
STA CURLIN ; LINE # OF "ON ERR" STATEMENT
|
|
LDA CURLSV+1 ;
|
|
STA CURLIN+1 ;
|
|
JSR CHRGOT ; START CONVERSION
|
|
JSR GOTO ; GOTO SPECIFIED ONERR LINE
|
|
JMP NEWSTT ;
|
|
; --------------------------------
|
|
; "RESUME" STATEMENT
|
|
; --------------------------------
|
|
RESUME LDA ERRLIN ; RESTORE LINE # AND TXTPTR
|
|
STA CURLIN ; TO RE-TRY OFFENDING LINE
|
|
LDA ERRLIN+1 ;
|
|
STA CURLIN+1 ;
|
|
LDA ERRPOS ;
|
|
STA TXTPTR ;
|
|
LDA ERRPOS+1 ;
|
|
STA TXTPTR+1 ;
|
|
; <<< ONERR CORRECTION IN MANUAL IS EASILY >>>
|
|
; <<< BY "CALL -3288", WHICH IS $F328 HERE >>>
|
|
LDX ERRSTK ; RETRIEVE STACK PNTR AS IT WAS
|
|
TXS ; BEFORE STATEMENT SCANNED
|
|
JMP NEWSTT ; DO STATEMENT AGAIN
|
|
; --------------------------------
|
|
JSYN JMP SYNERR ;
|
|
; --------------------------------
|
|
; "DEL" STATEMENT
|
|
; --------------------------------
|
|
DEL BCS JSYN ; ERROR IF # NOT SPECIFIED
|
|
LDX PRGEND ;
|
|
STX VARTAB ;
|
|
LDX PRGEND+1 ;
|
|
STX VARTAB+1 ;
|
|
JSR LINGET ; GET BEGINNING OF RANGE
|
|
JSR FNDLIN ; FIND THIS LINE OR NEXT
|
|
LDA LOWTR ; UPPER PORTION OF PROGRAM WILL
|
|
STA DEST ; BE MOVED DOWN TO HERE
|
|
LDA LOWTR+1 ;
|
|
STA DEST+1 ;
|
|
LDA #LOCHAR(`,') ; MUST HAVE A COMMA NEXT
|
|
JSR SYNCHR ;
|
|
JSR LINGET ; GET END RANGE
|
|
; (DOES NOTHING IF END RANGE
|
|
; IS NOT SPECIFIED)
|
|
INC LINNUM ; POINT ONE PAST IT
|
|
BNE L_DEL_1 ;
|
|
INC LINNUM+1 ;
|
|
L_DEL_1 JSR FNDLIN ; FIND START LINE AFTER SPECIFIED LINE
|
|
LDA LOWTR ; WHICH IS BEGINNING OF PORTION
|
|
CMP DEST ; TO BE MOVED DOWN
|
|
LDA LOWTR+1 ; IT MUST BE ABOVE THE TARGET
|
|
SBC DEST+1 ;
|
|
BCS L_DEL_2 ; IT IS OKAY
|
|
RTS ; NOTHING TO DELETE
|
|
L_DEL_2 LDY #0 ; MOVE UPPER PORTION DOWN NOW
|
|
L_DEL_3 LDA (LOWTR),Y ; SOURCE . . .
|
|
STA (DEST),Y ; ...TO DESTINATION
|
|
INC LOWTR ; BUMP SOURCE PNTR
|
|
BNE L_DEL_4 ;
|
|
INC LOWTR+1 ;
|
|
L_DEL_4 INC DEST ; BUMP DESTINATION PNTR
|
|
BNE L_DEL_5 ;
|
|
INC DEST+1 ;
|
|
L_DEL_5 LDA VARTAB ; REACHED END OF PROGRAM YET?
|
|
CMP LOWTR ;
|
|
LDA VARTAB+1 ;
|
|
SBC LOWTR+1 ;
|
|
BCS L_DEL_3 ; NO, KEEP MOVING
|
|
LDX DEST+1 ; STORE NEW END OF PROGRAM
|
|
LDY DEST ; MUST SUBTRACT 1 FIRST
|
|
BNE L_DEL_6 ;
|
|
DEX ;
|
|
L_DEL_6 DEY ;
|
|
STX VARTAB+1 ;
|
|
STY VARTAB ;
|
|
JMP FIX_LINKS ; RESET LINKS AFTER A DELETE
|
|
; --------------------------------
|
|
; "GR" STATEMENT
|
|
; --------------------------------
|
|
GR LDA SW_LORES
|
|
LDA SW_MIXSET
|
|
JMP MON_SETGR
|
|
; --------------------------------
|
|
; "TEXT" STATEMENT
|
|
; --------------------------------
|
|
TEXT LDA SW_LOWSCR ; JMP $FB36 WOULD HAVE
|
|
JMP MON_SETTXT ; DONE BOTH OF THESE
|
|
; <<< BETTER CODE WOULD BE: >>>
|
|
; <<< LDA SW.MIXSET >>>
|
|
; <<< JMP $FB33 >>>
|
|
; --------------------------------
|
|
; "STORE" STATEMENT
|
|
; --------------------------------
|
|
STORE JSR GETARYPT ; GET ADDRESS OF ARRAY TO BE SAVED
|
|
LDY #3 ; FORWARD OFFSET - 1 IS SIZE OF
|
|
LDA (LOWTR),Y ; THIS ARRAY
|
|
TAX
|
|
DEY
|
|
LDA (LOWTR),Y
|
|
SBC #1
|
|
BCS L_STORE_1
|
|
DEX
|
|
L_STORE_1 STA LINNUM
|
|
STX LINNUM+1
|
|
JSR MON_WRITE
|
|
JSR TAPEPNT
|
|
JMP MON_WRITE
|
|
; --------------------------------
|
|
; "RECALL" STATEMENT
|
|
; --------------------------------
|
|
RECALL JSR GETARYPT ; FIND ARRAY IN MEMORY
|
|
JSR MON_READ ; READ HEADER
|
|
LDY #2 ; MAKE SURE THE NEW DATA FITS
|
|
LDA (LOWTR),Y ;
|
|
CMP LINNUM ;
|
|
INY ;
|
|
LDA (LOWTR),Y ;
|
|
SBC LINNUM+1 ;
|
|
BCS L_RECALL_1 ; IT FITS
|
|
JMP MEMERR ; DOESN'T FIT
|
|
L_RECALL_1 JSR TAPEPNT ; READ THE DATA
|
|
JMP MON_READ ;
|
|
; --------------------------------
|
|
; "HGR" AND "HGR2" STATEMENTS
|
|
; --------------------------------
|
|
HGR2 BIT SW_HISCR ; SELECT PAGE 2 ($4000-5FFF)
|
|
BIT SW_MIXCLR ; DEFAULT TO FULL SCREEN
|
|
LDA #>$4000 ; SET STARTING PAGE FOR HIRES
|
|
BNE SETHPG ; ...ALWAYS
|
|
HGR LDA #>$2000 ; SET STARTING PAGE FOR HIRES
|
|
BIT SW_LOWSCR ; SELECT PAGE 1 ($2000-3FFF)
|
|
BIT SW_MIXSET ; DEFAULT TO MIXED SCREEN
|
|
SETHPG STA HGR_PAGE ; BASE PAGE OF HIRES BUFFER
|
|
LDA SW_HIRES ; TURN ON HIRES
|
|
LDA SW_TXTCLR ; TURN ON GRAPHICS
|
|
; --------------------------------
|
|
; CLEAR SCREEN
|
|
; --------------------------------
|
|
HCLR LDA #0 ; SET FOR BLACK BACKGROUND
|
|
STA HGR_BITS
|
|
; --------------------------------
|
|
; FILL SCREEN WITH (HGR.BITS)
|
|
; --------------------------------
|
|
BKGND LDA HGR_PAGE ; PUT BUFFER ADDRESS IN HGR.SHAPE
|
|
STA HGR_SHAPE+1
|
|
LDY #0
|
|
STY HGR_SHAPE
|
|
L_BKGND_1 LDA HGR_BITS ; COLOR BYTE
|
|
STA (HGR_SHAPE),Y ; CLEAR HIRES TO HGR.BITS
|
|
JSR COLOR_SHIFT ; CORRECT FOR COLOR SHIFT
|
|
INY ; (SLOWS CLEAR BY FACTOR OF 2)
|
|
BNE L_BKGND_1
|
|
INC HGR_SHAPE+1
|
|
LDA HGR_SHAPE+1
|
|
AND #$1F ; DONE? ($40 OR$60)
|
|
BNE L_BKGND_1 ; NO
|
|
RTS ; YES, RETURN
|
|
; --------------------------------
|
|
; SET THE HIRES CURSOR POSITION
|
|
;
|
|
; (Y,X) = HORIZONTAL COORDINATE (0-279)
|
|
; (A) = VERTICAL COORDINATE (0-191)
|
|
; --------------------------------
|
|
HPOSN STA HGR_Y ; SAVE Y- AND X-POSITIONS
|
|
STX HGR_X ;
|
|
STY HGR_X+1 ;
|
|
PHA ; Y-POS ALSO ON STACK
|
|
AND #$C0 ; CALCULATE BASE ADDRESS FOR Y-POS
|
|
STA MON_GBASL ; FOR Y=ABCDEFGH
|
|
LSR ; GBASL=ABAB0000
|
|
LSR ;
|
|
ORA MON_GBASL ;
|
|
STA MON_GBASL ;
|
|
PLA ; (A) (GBASH) (GBASL)
|
|
STA MON_GBASH ; ?-ABCDEFGH ABCDEFGH ABAB0000
|
|
ASL ; A-BCDEFGH0 ABCDEFGH ABAB0000
|
|
ASL ; B-CDEFGH00 ABCDEFGH ABAB0000
|
|
ASL ; C-DEFGH000 ABCDEFGH ABAB0000
|
|
ROL MON_GBASH ; A-DEFGH000 BCDEFGHC ABAB0000
|
|
ASL ; D-EFGH0000 BCDEFGHC ABAB0000
|
|
ROL MON_GBASH ; B-EFGH0000 CDEFGHCD ABAB0000
|
|
ASL ; E-FGH00000 CDEFGHCD ABAB0000
|
|
ROR MON_GBASL ; 0-FGH00000 CDEFGHCD EABAB000
|
|
LDA MON_GBASH ; 0-CDEFGHCD CDEFGHCD EABAB000
|
|
AND #$1F ; 0-000FGHCD CDEFGHCD EABAB000
|
|
ORA HGR_PAGE ; 0-PPPFGHCD CDEFGHCD EABAB000
|
|
STA MON_GBASH ; 0-PPPFGHCD PPPFGHCD EABAB000
|
|
TXA ; DIVIDE X-POS BY 7 FOR INDEX FROM BASE
|
|
CPY #0 ; IS X-POS < 256?
|
|
BEQ L_HPOSN_2 ; YES
|
|
LDY #35 ; NO: 256/7 = 36 REM 4
|
|
; CARRY=1, SO ADC #4 IS TOO LARGE;
|
|
; HOWEVER, ADC #4 CLEARS CARRY
|
|
; WHICH MAKES SBC #7 ONLY -6
|
|
; BALANCING IT OUT.
|
|
ADC #4 ; FOLLOWING INY MAKES Y=36
|
|
L_HPOSN_1 INY
|
|
L_HPOSN_2 SBC #7
|
|
BCS L_HPOSN_1
|
|
STY HGR_HORIZ ; HORIZONTAL INDEX
|
|
TAX ; USE REMAINDER-7 TO LOOK UP THE
|
|
LDA MSKTBL-$100+7,X ; BIT MASK
|
|
STA MON_HMASK
|
|
TYA ; QUOTIENT GIVES BYTE INDEX
|
|
LSR ; ODD OR EVEN COLUMN?
|
|
LDA HGR_COLOR ; IF ON ODD BYTE (CARRY SET)
|
|
STA HGR_BITS ; THEN ROTATE BITS
|
|
BCS COLOR_SHIFT ; ODD COLUMN
|
|
RTS ; EVEN COLUMN
|
|
; --------------------------------
|
|
; PLOT A DOT
|
|
;
|
|
; (Y,X) = HORIZONTAL POSITION
|
|
; (A) = VERTICAL POSITION
|
|
; --------------------------------
|
|
HPLOT0 JSR HPOSN
|
|
LDA HGR_BITS ; CALCULATE BIT POSN IN GBAS,
|
|
EOR (MON_GBASL),Y ; HGR.HORIZ, AND HMASK FROM
|
|
AND MON_HMASK ; Y-COOR IN A-REG,
|
|
EOR (MON_GBASL),Y ; X-COOR IN X,Y REGS.
|
|
STA (MON_GBASL),Y ; FOR ANY 1-BITS, SUBSTITUTE
|
|
RTS ; CORRESPONDING BIT OF HGR.BITS
|
|
; --------------------------------
|
|
; MOVE LEFT OR RIGHT ONE PIXEL
|
|
;
|
|
; IF STATUS IS +, MOVE RIGHT; IF -, MOVE LEFT
|
|
; IF ALREADY AT LEFT OR RIGHT EDGE, WRAP AROUND
|
|
;
|
|
; REMEMBER BITS IN HI-RES BYTE ARE BACKWARDS ORDER:
|
|
; BYTE N BYTE N+1
|
|
; S7654321 SEDCBA98
|
|
; --------------------------------
|
|
MOVE_LEFT_OR_RIGHT
|
|
BPL MOVE_RIGHT ; + MOVE RIGHT, - MOVE LEFT
|
|
LDA MON_HMASK ; MOVE LEFT ONE PIXEL
|
|
LSR ; SHIFT MASK RIGHT, MOVES DOT LEFT
|
|
BCS LR_2 ; ...DOT MOVED TO NEXT BYTE
|
|
EOR #$C0 ; MOVE SIGN BIT BACK WHERE IT WAS
|
|
LR_1 STA MON_HMASK ; NEW MASK VALUE
|
|
RTS ;
|
|
LR_2 DEY ; MOVED TO NEXT BYTE, SO DECR INDEX
|
|
BPL LR_3 ; STILL NOT PAST EDGE
|
|
LDY #39 ; OFF LEFT EDGE, SO WRAP AROUND SCREEN
|
|
LR_3 LDA #$C0 ; NEW HMASK, RIGHTMOST BIT ON SCREEN
|
|
LR_4 STA MON_HMASK ; NEW MASK AND INDEX
|
|
STY HGR_HORIZ ;
|
|
LDA HGR_BITS ; ALSO NEED TO ROTATE COLOR
|
|
; --------------------------------
|
|
COLOR_SHIFT
|
|
ASL ; ROTATE LOW-ORDER 7 BITS
|
|
CMP #$C0 ; OF HGR.BITS ONE BIT POSN.
|
|
BPL L_COLOR_SHIFT_1
|
|
LDA HGR_BITS
|
|
EOR #$7F
|
|
STA HGR_BITS
|
|
L_COLOR_SHIFT_1 RTS
|
|
; --------------------------------
|
|
; MOVE RIGHT ONE PIXEL
|
|
; IF ALREADY AT RIGHT EDGE, WRAP AROUND
|
|
; --------------------------------
|
|
MOVE_RIGHT
|
|
LDA MON_HMASK
|
|
ASL ; SHIFTING BYTE LEFT MOVES PIXEL RIGHT
|
|
EOR #$80 ;
|
|
; ORIGINAL: C0 A0 90 88 84 82 81
|
|
; SHIFTED: 80 40 20 10 08 02 01
|
|
; EOR #$80: 00 C0 A0 90 88 84 82
|
|
BMI LR_1 ; FINISHED
|
|
LDA #$81 ; NEW MASK VALUE
|
|
INY ; MOVE TO NEXT BYTE RIGHT
|
|
CPY #40 ; UNLESS THAT IS TOO FAR
|
|
BCC LR_4 ; NOT TOO FAR
|
|
LDY #0 ; TOO FAR, SO WRAP AROUND
|
|
BCS LR_4 ; ...ALWAYS
|
|
; --------------------------------
|
|
; --------------------------------
|
|
; "XDRAW" ONE BIT
|
|
; --------------------------------
|
|
LRUDX1 CLC ; C=0 MEANS NO 90 DEGREE ROTATION
|
|
LRUDX2 LDA HGR_DX+1 ; C=1 MEANS ROTATE 90 DEGREES
|
|
AND #4 ; IF BIT2=0 THEN DON'T PLOT
|
|
BEQ LRUD4 ; YES, DO NOT PLOT
|
|
LDA #$7F ; NO, LOOK AT WHAT IS ALREADY THERE
|
|
AND MON_HMASK
|
|
AND (MON_GBASL),Y ; SCREEN BIT = 1?
|
|
BNE LRUD3 ; YES, GO CLEAR IT
|
|
INC HGR_COLLISIONS ; NO, COUNT THE COLLISION
|
|
LDA #$7F ; AND TURN THE BIT ON
|
|
AND MON_HMASK ;
|
|
BPL LRUD3 ; ...ALWAYS
|
|
; --------------------------------
|
|
; "DRAW" ONE BIT
|
|
; --------------------------------
|
|
LRUD1 CLC ; C=0 MEANS NO 90 DEGREE ROTATION
|
|
LRUD2 LDA HGR_DX+1 ; C=1 MEANS ROTATE
|
|
AND #4 ; IF BIT2=0 THEN DO NOT PLOT
|
|
BEQ LRUD4 ; DO NOT PLOT
|
|
LDA (MON_GBASL),Y
|
|
EOR HGR_BITS ; 1'S WHERE ANY BITS NOT IN COLOR
|
|
AND MON_HMASK ; LOOK AT JUST THIS BIT POSITION
|
|
BNE LRUD3 ; THE BIT WAS ZERO, SO PLOT IT
|
|
INC HGR_COLLISIONS ; BIT IS ALREADY 1; COUNT COLLSN
|
|
; --------------------------------
|
|
; TOGGLE BIT ON SCREEN WITH (A)
|
|
; --------------------------------
|
|
LRUD3 EOR (MON_GBASL),Y
|
|
STA (MON_GBASL),Y
|
|
; --------------------------------
|
|
; DETERMINE WHERE NEXT POINT WILL BE, AND MOVE THERE
|
|
; C=0 IF NO 90 DEGREE ROTATION
|
|
; C=1 ROTATES 90 DEGREES
|
|
; --------------------------------
|
|
LRUD4 LDA HGR_DX+1 ; CALCULATE THE DIRECTION TO MOVE
|
|
ADC HGR_QUADRANT
|
|
AND #3 ; WRAP AROUND THE CIRCLE
|
|
CON_03 = *-1 ; (( A CONSTANT ))
|
|
;
|
|
; 00 -- UP
|
|
; 01 -- DOWN
|
|
; 10 -- RIGHT
|
|
; 11 -- LEFT
|
|
;
|
|
CMP #2 ; C=0 IF 0 OR 1, C=1 IF 2 OR 3
|
|
ROR ; PUT C INTO SIGN, ODD/EVEN INTO C
|
|
BCS MOVE_LEFT_OR_RIGHT
|
|
; --------------------------------
|
|
MOVE_UP_OR_DOWN
|
|
BMI MOVE_DOWN ; SIGN FOR UP/DOWN SELECT_
|
|
; --------------------------------
|
|
; MOVE UP ONE PIXEL
|
|
; IF ALREADY AT TOP, GO TO BOTTOM
|
|
;
|
|
; REMEMBER: Y-COORD GBASH GBASL
|
|
; ABCDEFGH PPPFGHCD EABAB000
|
|
; --------------------------------
|
|
CLC ; MOVE UP
|
|
LDA MON_GBASH ; CALC. BASE ADDRESS OF PREV. LINE
|
|
BIT CON_1C ; LOOK AT BITS 000FGH00 IN GBASH
|
|
BNE L_MOVE_UP_OR_DOWN_5 ; SIMPLE, JUST FGH=FGH-1
|
|
; GBASH=PPP000CD, GBASL=EABAB000
|
|
ASL MON_GBASL ; WHAT IS "E"?
|
|
BCS L_MOVE_UP_OR_DOWN_3 ; E=1, THEN EFGH=EFGH-1
|
|
BIT CON_03 ; LOOK AT 000000CD IN GBASH
|
|
BEQ L_MOVE_UP_OR_DOWN_1 ; Y-POS IS AB000000 FORM
|
|
ADC #$1F ; CD <> 0, SO CDEFGH=CDEFGH-1
|
|
SEC ;
|
|
BCS L_MOVE_UP_OR_DOWN_4 ; ...ALWAYS
|
|
L_MOVE_UP_OR_DOWN_1 ADC #$23 ; ENOUGH TO MAKE GBASH=PPP11111 LATER
|
|
PHA ; SAVE FOR LATER
|
|
LDA MON_GBASL ; GBASL IS NOW ABAB0000 (AB=00,01,10)
|
|
ADC #$B0 ; 0000+1011=1011 AND CARRY CLEAR
|
|
; OR 0101+1011=0000 AND CARRY SET
|
|
; OR 1010+1011=0101 AND CARRY SET
|
|
BCS L_MOVE_UP_OR_DOWN_2 ; NO WRAP-AROUND NEEDED
|
|
ADC #$F0 ; CHANGE 1011 TO 1010 (WRAP-AROUND)
|
|
L_MOVE_UP_OR_DOWN_2 STA MON_GBASL ; FORM IS NOW STILL ABAB0000
|
|
PLA ; PARTIALLY MODIFIED GBASH
|
|
BCS L_MOVE_UP_OR_DOWN_4 ; ...ALWAYS
|
|
L_MOVE_UP_OR_DOWN_3 ADC #$1F ;
|
|
L_MOVE_UP_OR_DOWN_4 ROR MON_GBASL ; SHIFT IN E, TO GET EABAB000 FORM
|
|
L_MOVE_UP_OR_DOWN_5 ADC #$FC ; FINISH GBASH MODS
|
|
UD_1 STA MON_GBASH ;
|
|
RTS
|
|
; --------------------------------
|
|
CLC ; <<<NEVER USED>>>
|
|
; --------------------------------
|
|
; MOVE DOWN ONE PIXEL
|
|
; IF ALREADY AT BOTTOM, GO TO TOP
|
|
;
|
|
; REMEMBER: Y-COORD GBASH GBASL
|
|
; ABCDEFGH PPPFGHCD EABAB000
|
|
; --------------------------------
|
|
MOVE_DOWN
|
|
LDA MON_GBASH ; TRY IT FIRST, BY FGH=FGH+1
|
|
ADC #4 ; GBASH = PPPFGHCD
|
|
CON_04 = *-1 ; (( CONSTANT ))
|
|
BIT CON_1C ; IS FGH FIELD NOW ZERO?
|
|
BNE UD_1 ; NO, SO WE ARE FINISHED
|
|
; YES, RIPPLE THE CARRY AS HIGH
|
|
; AS NECESSARY
|
|
ASL MON_GBASL ; LOOK AT "E" BIT
|
|
BCC L_CON_04_2 ; NOW ZERO; MAKE IT 1 AND LEAVE
|
|
ADC #$E0 ; CARRY = 1, SO ADDS $E1
|
|
CLC ; IS "CD" NOT ZERO?
|
|
BIT CON_04 ; TESTS BIT 2 FOR CARRY OUT OF "CD"
|
|
BEQ L_CON_04_3 ; NO CARRY, FINISHED
|
|
; INCREMENT "AB" THEN
|
|
; 0000 --> 0101
|
|
; 0101 --> 1010
|
|
; 1010 --> WRAP AROUND TO LINE 0
|
|
LDA MON_GBASL ; 0000 0101 1010
|
|
ADC #$50 ; 0101 1010 1111
|
|
EOR #$F0 ; 1010 0101 0000
|
|
BEQ L_CON_04_1 ;
|
|
EOR #$F0 ; 0101 1010
|
|
L_CON_04_1 STA MON_GBASL ; NEW ABAB0000
|
|
LDA HGR_PAGE ; WRAP AROUND TO LINE ZERO OF GROUP
|
|
BCC L_CON_04_3 ; ...ALWAYS
|
|
L_CON_04_2 ADC #$E0
|
|
L_CON_04_3 ROR MON_GBASL
|
|
BCC UD_1 ; ...ALWAYS
|
|
; --------------------------------
|
|
; HLINRL IS NEVER CALLED BY APPLESOFT
|
|
;
|
|
; ENTER WITH: (A,X) = DX FROM CURRENT POINT
|
|
; (Y) = DY FROM CURRENT POINT
|
|
; --------------------------------
|
|
HLINRL PHA ; SAVE (A)
|
|
LDA #0 ; CLEAR CURRENT POINT SO HGLIN WILL
|
|
STA HGR_X ; ACT RELATIVELY
|
|
STA HGR_X+1 ;
|
|
STA HGR_Y ;
|
|
PLA ; RESTORE (A)
|
|
; --------------------------------
|
|
; DRAW LINE FROM LAST PLOTTED POINT TO (A,X),(Y)
|
|
;
|
|
; ENTER WITH: (A,X) = X OF TARGET POINT
|
|
; (Y) = Y OF TARGET POINT
|
|
; --------------------------------
|
|
HGLIN PHA ; COMPUTE DX = X- X0
|
|
SEC
|
|
SBC HGR_X
|
|
PHA
|
|
TXA
|
|
SBC HGR_X+1
|
|
STA HGR_QUADRANT ; SAVE DX SIGN (+ = RIGHT, - = LEFT)
|
|
BCS L_HGLIN_1 ; NOW FIND ABS (DX)
|
|
PLA ; FORMS 2'S COMPLEMENT
|
|
EOR #$FF
|
|
ADC #1
|
|
PHA
|
|
LDA #0
|
|
SBC HGR_QUADRANT
|
|
L_HGLIN_1 STA HGR_DX+1
|
|
STA HGR_E+1 ; INIT HGR.E TO ABS(X-X0)
|
|
PLA
|
|
STA HGR_DX
|
|
STA HGR_E
|
|
PLA
|
|
STA HGR_X ; TARGET X POINT
|
|
STX HGR_X+1 ;
|
|
TYA ; TARGET Y POINT
|
|
CLC ; COMPUTE DY = Y-HGR.Y
|
|
SBC HGR_Y ; AND SAVE -ABS(Y-HGR.Y)-1 IN HGR.DY
|
|
BCC L_HGLIN_2 ; (SO + MEANS UP, - MEANS DOWN)
|
|
EOR #$FF ; 2'S COMPLEMENT OF DY
|
|
ADC #$FE ;
|
|
L_HGLIN_2 STA HGR_DY ;
|
|
STY HGR_Y ; TARGET Y POINT
|
|
ROR HGR_QUADRANT ; SHIFT Y-DIRECTION INTO QUADRANT
|
|
SEC ; COUNT = DX -(-DY) = # OF DOTS NEEDED
|
|
SBC HGR_DX ;
|
|
TAX ; COUNTL IS IN X-REG
|
|
LDA #$FF
|
|
SBC HGR_DX+1
|
|
STA HGR_COUNT
|
|
LDY HGR_HORIZ ; HORIZONTAL INDEX
|
|
BCS MOVEX2 ; ...ALWAYS
|
|
; --------------------------------
|
|
; MOVE LEFT OR RIGHT ONE PIXEL
|
|
; (A) BIT 6 HAS DIRECTION
|
|
; --------------------------------
|
|
MOVEX ASL ; PUT BIT 6 INTO SIGN POSITION
|
|
JSR MOVE_LEFT_OR_RIGHT
|
|
SEC
|
|
; --------------------------------
|
|
; DRAW LINE NOW
|
|
; --------------------------------
|
|
MOVEX2 LDA HGR_E ; CARRY IS SET
|
|
ADC HGR_DY ; E = E-DELTY
|
|
STA HGR_E ; NOTE: DY IS (-DELTA Y)-1
|
|
LDA HGR_E+1 ; CARRY CLR IF HGR.E GOES NEGATIVE
|
|
SBC #0
|
|
L_MOVEX2_1 STA HGR_E+1
|
|
LDA (MON_GBASL),Y
|
|
EOR HGR_BITS ; PLOT A DOT
|
|
AND MON_HMASK
|
|
EOR (MON_GBASL),Y
|
|
STA (MON_GBASL),Y
|
|
INX ; FINISHED ALL THE DOTS?
|
|
BNE L_MOVEX2_2 ; NO
|
|
INC HGR_COUNT ; TEST REST OF COUNT
|
|
BEQ RTS_22 ; YES, FINISHED.
|
|
L_MOVEX2_2 LDA HGR_QUADRANT ; TEST DIRECTION
|
|
BCS MOVEX ; NEXT MOVE IS IN THE X DIRECTION
|
|
JSR MOVE_UP_OR_DOWN ; IF CLR, NEG, MOVE
|
|
CLC ; E = E+DX
|
|
LDA HGR_E
|
|
ADC HGR_DX
|
|
STA HGR_E
|
|
LDA HGR_E+1
|
|
ADC HGR_DX+1
|
|
BVC L_MOVEX2_1 ; ...ALWAYS
|
|
; --------------------------------
|
|
|
|
|
|
MSKTBL ASM_DATA(%10000001)
|
|
ASM_DATA(%10000010)
|
|
ASM_DATA(%10000100)
|
|
ASM_DATA(%10001000)
|
|
ASM_DATA(%10010000)
|
|
ASM_DATA(%10100000)
|
|
ASM_DATA(%11000000)
|
|
; --------------------------------
|
|
CON_1C ASM_DATA(%00011100) ; MASK FOR "FGH" BITS
|
|
; --------------------------------
|
|
|
|
; --------------------------------
|
|
; TABLE OF COS(90*X/16 DEGREES)*$100 - 1
|
|
; WITH ONE BYTE PRECISION, X=0 TO 16:
|
|
; --------------------------------
|
|
COSINE_TABLE ASM_DATA($FF,$FE,$FA,$F4,$EC,$E1,$D4,$C5)
|
|
ASM_DATA($B4,$A1,$8D,$78,$61,$49,$31,$18)
|
|
ASM_DATA($FF)
|
|
; --------------------------------
|
|
; HFIND -- CALCULATES CURRENT POSITION OF HI-RES CURSOR
|
|
; (NOT CALLED BY ANY APPLESOFT ROUTINE)
|
|
;
|
|
; CALCULATE Y-COORD FROM GBASL,H
|
|
; AND X-COORD FROM HORIZ AND HMASK
|
|
; --------------------------------
|
|
HFIND LDA MON_GBASL ; GBASL = EABAB000
|
|
ASL ; E INTO CARRY
|
|
LDA MON_GBASH ; GBASH = PPPFGHCD
|
|
AND #3 ; 000000CD
|
|
ROL ; 00000CDE
|
|
ORA MON_GBASL ; EABABCDE
|
|
ASL ; ABABCDE0
|
|
ASL ; BABCDE00
|
|
ASL ; ABCDE000
|
|
STA HGR_Y ; ALL BUT FGH
|
|
LDA MON_GBASH ; PPPFGHCD
|
|
LSR ; 0PPPFGHC
|
|
LSR ; 00PPPFGH
|
|
AND #7 ; 00000FGH
|
|
ORA HGR_Y ; ABCDEFGH
|
|
STA HGR_Y ; THAT TAKES CARE OF Y-COORDINATE!
|
|
LDA HGR_HORIZ ; X = 7*HORIZ + BIT POS. IN HMASK
|
|
ASL ; MULTIPLY BY 7
|
|
ADC HGR_HORIZ ; 3* SO FAR
|
|
ASL ; 6*
|
|
TAX ; SINCE 7* MIGHT NOT FIT IN 1 BYTE,
|
|
; WAIT TILL LATER FOR LAST ADD
|
|
DEX ;
|
|
LDA MON_HMASK ; NOW FIND BIT POSITION IN HMASK
|
|
AND #$7F ; ONLY LOOK AT LOW SEVEN
|
|
L_HFIND_1 INX ; COUNT A SHIFT
|
|
LSR ;
|
|
BNE L_HFIND_1 ; STILL IN THERE
|
|
STA HGR_X+1 ; ZERO TO HI-BYTE
|
|
TXA ; 6*HORIZ+LOG2(HMASK)
|
|
CLC ; ADD HORIZ ONE MORE TIME
|
|
ADC HGR_HORIZ ; 7*HORIZ+LOG2(HMASK)
|
|
BCC L_HFIND_2 ; UPPER BYTE = 0
|
|
INC HGR_X+1 ; UPPER BYTE = 1
|
|
L_HFIND_2 STA HGR_X ; STORE LOWER BYTE
|
|
RTS_22 RTS
|
|
; --------------------------------
|
|
; DRAW A SHAPE
|
|
;
|
|
; (Y,X) = SHAPE STARTING ADDRESS
|
|
; (A) = ROTATION (0-3F)
|
|
; --------------------------------
|
|
; APPLESOFT DOES NOT CALL DRAW0
|
|
; --------------------------------
|
|
DRAW0 STX HGR_SHAPE ; SAVE SHAPE ADDRESS
|
|
STY HGR_SHAPE+1
|
|
; --------------------------------
|
|
; APPLESOFT ENTERS HERE
|
|
; --------------------------------
|
|
DRAW1 TAX ; SAVE ROTATION (0-$3F)
|
|
LSR ; DIVIDE ROTATION BY 16 TO GET
|
|
LSR ; QUADRANT (0=UP, 1=RT, 2=DWN, 3=LFT)
|
|
LSR
|
|
LSR
|
|
STA HGR_QUADRANT
|
|
TXA ; USE LOW 4 BITS OF ROTATION TO INDEX
|
|
AND #$0F ; THE TRIG TABLE
|
|
TAX
|
|
LDY COSINE_TABLE,X ; SAVE COSINE IN HGR.DX
|
|
STY HGR_DX ;
|
|
EOR #$F ; AND SINE IN DY
|
|
TAX
|
|
LDY COSINE_TABLE+1,X
|
|
INY
|
|
STY HGR_DY
|
|
LDY HGR_HORIZ ; INDEX FROM GBASL,H TO BYTE WE'RE IN
|
|
LDX #0
|
|
STX HGR_COLLISIONS ; CLEAR COLLISION COUNTER
|
|
LDA (HGR_SHAPE,X) ; GET FIRST BYTE OF SHAPE DEFN
|
|
L_DRAW1_1 STA HGR_DX+1 ; KEEP SHAPE BYTE IN HGR.DX+1
|
|
LDX #$80 ; INITIAL VALUES FOR FRACTIONAL VECTORS
|
|
STX HGR_E ; L_DRAW1_5 IN COSINE COMPONENT
|
|
STX HGR_E+1 ; L_DRAW1_5 IN SINE COMPONENT
|
|
LDX HGR_SCALE ; SCALE FACTOR
|
|
L_DRAW1_2 LDA HGR_E ; ADD COSINE VALUE TO X-VALUE
|
|
SEC ; IF >= 1, THEN DRAW
|
|
ADC HGR_DX ;
|
|
STA HGR_E ; ONLY SAVE FRACTIONAL PART
|
|
BCC L_DRAW1_3 ; NO INTEGRAL PART
|
|
JSR LRUD1 ; TIME TO PLOT COSINE COMPONENT
|
|
CLC ;
|
|
L_DRAW1_3 LDA HGR_E+1 ; ADD SINE VALUE TO Y-VALUE
|
|
ADC HGR_DY ; IF >= 1, THEN DRAW
|
|
STA HGR_E+1 ; ONLY SAVE FRACTIONAL PART
|
|
BCC L_DRAW1_4 ; NO INTEGRAL PART
|
|
JSR LRUD2 ; TIME TO PLOT SINE COMPONENT
|
|
L_DRAW1_4 DEX ; LOOP ON SCALE FACTOR.
|
|
BNE L_DRAW1_2 ; STILL ON SAME SHAPE ITEM
|
|
LDA HGR_DX+1 ; GET NEXT SHAPE ITEM
|
|
LSR ; NEXT 3 BIT VECTOR
|
|
LSR ;
|
|
LSR ;
|
|
BNE L_DRAW1_1 ; MORE IN THIS SHAPE BYTE
|
|
INC HGR_SHAPE ; GO TO NEXT SHAPE BYTE
|
|
BNE L_DRAW1_5
|
|
INC HGR_SHAPE+1
|
|
L_DRAW1_5 LDA (HGR_SHAPE,X) ; NEXT BYTE OF SHAPE DEFINITION
|
|
BNE L_DRAW1_1 ; PROCESS IF NOT ZERO
|
|
RTS ; FINISHED
|
|
; --------------------------------
|
|
; XDRAW A SHAPE (SAME AS DRAW, EXCEPT TOGGLES SCREEN)
|
|
;
|
|
; (Y,X) = SHAPE STARTING ADDRESS
|
|
; (A) = ROTATION (0-3F)
|
|
; --------------------------------
|
|
; APPLESOFT DOES NOT CALL XDRAW0
|
|
; --------------------------------
|
|
XDRAW0 STX HGR_SHAPE ; SAVE SHAPE ADDRESS
|
|
STY HGR_SHAPE+1
|
|
; --------------------------------
|
|
; APPLESOFT ENTERS HERE
|
|
; --------------------------------
|
|
XDRAW1 TAX ; SAVE ROTATION (0-$3F)
|
|
LSR ; DIVIDE ROTATION BY 16 TO GET
|
|
LSR ; QUADRANT (0=UP, 1=RT, 2=DWN, 3=LFT)
|
|
LSR
|
|
LSR
|
|
STA HGR_QUADRANT
|
|
TXA ; USE LOW 4 BITS OF ROTATION TO INDEX
|
|
AND #$0F ; THE TRIG TABLE
|
|
TAX
|
|
LDY COSINE_TABLE,X ; SAVE COSINE IN HGR.DX
|
|
STY HGR_DX ;
|
|
EOR #$F ; AND SINE IN DY
|
|
TAX
|
|
LDY COSINE_TABLE+1,X
|
|
INY
|
|
STY HGR_DY
|
|
LDY HGR_HORIZ ; INDEX FROM GBASL,H TO BYTE WE'RE IN
|
|
LDX #0
|
|
STX HGR_COLLISIONS ; CLEAR COLLISION COUNTER
|
|
LDA (HGR_SHAPE,X) ; GET FIRST BYTE OF SHAPE DEFN
|
|
L_XDRAW1_1 STA HGR_DX+1 ; KEEP SHAPE BYTE IN HGR.DX+1
|
|
LDX #$80 ; INITIAL VALUES FOR FRACTIONAL VECTORS
|
|
STX HGR_E ; L_XDRAW1_5 IN COSINE COMPONENT
|
|
STX HGR_E+1 ; L_XDRAW1_5 IN SINE COMPONENT
|
|
LDX HGR_SCALE ; SCALE FACTOR
|
|
L_XDRAW1_2 LDA HGR_E ; ADD COSINE VALUE TO X-VALUE
|
|
SEC ; IF >= 1, THEN DRAW
|
|
ADC HGR_DX ;
|
|
STA HGR_E ; ONLY SAVE FRACTIONAL PART
|
|
BCC L_XDRAW1_3 ; NO INTEGRAL PART
|
|
JSR LRUDX1 ; TIME TO PLOT COSINE COMPONENT
|
|
CLC ;
|
|
L_XDRAW1_3 LDA HGR_E+1 ; ADD SINE VALUE TO Y-VALUE
|
|
ADC HGR_DY ; IF >= 1, THEN DRAW
|
|
STA HGR_E+1 ; ONLY SAVE FRACTIONAL PART
|
|
BCC L_XDRAW1_4 ; NO INTEGRAL PART
|
|
JSR LRUDX2 ; TIME TO PLOT SINE COMPONENT
|
|
L_XDRAW1_4 DEX ; LOOP ON SCALE FACTOR.
|
|
BNE L_XDRAW1_2 ; STILL ON SAME SHAPE ITEM
|
|
LDA HGR_DX+1 ; GET NEXT SHAPE ITEM
|
|
LSR ; NEXT 3 BIT VECTOR
|
|
LSR ;
|
|
LSR ;
|
|
BNE L_XDRAW1_1 ; MORE IN THIS SHAPE BYTE
|
|
INC HGR_SHAPE ; GO TO NEXT SHAPE BYTE
|
|
BNE L_XDRAW1_5
|
|
INC HGR_SHAPE+1
|
|
L_XDRAW1_5 LDA (HGR_SHAPE,X) ; NEXT BYTE OF SHAPE DEFINITION
|
|
BNE L_XDRAW1_1 ; PROCESS IF NOT ZERO
|
|
RTS ; FINISHED
|
|
; --------------------------------
|
|
; GET HI-RES PLOTTING COORDINATES (0-279,0-191) FROM
|
|
; TXTPTR. LEAVE REGISTERS SET UP FOR HPOSN:
|
|
; (Y,X)=X-COORD
|
|
; (A) =Y-COORD
|
|
; --------------------------------
|
|
HFNS JSR FRMNUM ; EVALUATE EXPRESSION, MUST BE NUMERIC
|
|
JSR GETADR ; CONVERT TO 2-BYTE INTEGER IN LINNUM
|
|
LDY LINNUM+1 ; GET HORIZ COOR IN X,Y
|
|
LDX LINNUM ;
|
|
CPY #>280 ; MAKE SURE IT IS < 280
|
|
BCC L_HFNS_1 ; IN RANGE
|
|
BNE GGERR ;
|
|
CPX #<280 ;
|
|
BCS GGERR ;
|
|
L_HFNS_1 TXA ; SAVE HORIZ COOR ON STACK
|
|
PHA ;
|
|
TYA ;
|
|
PHA ;
|
|
LDA #LOCHAR(`,') ; REQUIRE A COMMA
|
|
JSR SYNCHR ;
|
|
JSR GETBYT ; EVAL EXP TO SINGLE BYTE IN X-REG
|
|
CPX #192 ; CHECK FOR RANGE
|
|
BCS GGERR ; TOO BIG
|
|
STX FAC ; SAVE Y-COORD
|
|
PLA ; RETRIEVE HORIZONTAL COORDINATE
|
|
TAY ;
|
|
PLA ;
|
|
TAX ;
|
|
LDA FAC ; AND VERTICAL COORDINATE
|
|
RTS ;
|
|
; --------------------------------
|
|
GGERR JMP GOERR ; ILLEGAL QUANTITY ERROR
|
|
; --------------------------------
|
|
; "HCOLOR=" STATEMENT
|
|
; --------------------------------
|
|
HCOLOR JSR GETBYT ; EVAL EXP TO SINGLE BYTE IN X
|
|
CPX #8 ; VALUE MUST BE 0-7
|
|
BCS GGERR ; TOO BIG
|
|
LDA COLORTBL,X ; GET COLOR PATTERN
|
|
STA HGR_COLOR
|
|
RTS_23 RTS
|
|
; --------------------------------
|
|
|
|
|
|
COLORTBL ASM_DATA(%00000000)
|
|
ASM_DATA(%00101010)
|
|
ASM_DATA(%01010101)
|
|
ASM_DATA(%01111111)
|
|
ASM_DATA(%00000000 | %10000000)
|
|
ASM_DATA(%00101010 | %10000000)
|
|
ASM_DATA(%01010101 | %10000000)
|
|
ASM_DATA(%01111111 | %10000000)
|
|
|
|
; --------------------------------
|
|
; "HPLOT" STATEMENT
|
|
;
|
|
; HPLOT X,Y
|
|
; HPLOT TO X,Y
|
|
; HPLOT X1,Y1 TO X2,Y2
|
|
; --------------------------------
|
|
HPLOT CMP #TOKEN_TO ; "PLOT TO" FORM?
|
|
BEQ L_HPLOT_2 ; YES, START FROM CURRENT LOCATION
|
|
JSR HFNS ; NO, GET STARTING POINT OF LINE
|
|
JSR HPLOT0 ; PLOT THE POINT, AND SET UP FOR
|
|
; DRAWING A LINE FROM THAT POINT
|
|
L_HPLOT_1 JSR CHRGOT ; CHARACTER AT END OF EXPRESSION
|
|
CMP #TOKEN_TO ; IS A LINE SPECIFIED?
|
|
BNE RTS_23 ; NO, EXIT
|
|
L_HPLOT_2 JSR SYNCHR ; YES. ADV. TXTPTR (WHY NOT CHRGET)
|
|
JSR HFNS ; GET COORDINATES OF LINE END
|
|
STY DSCTMP ; SET UP FOR LINE
|
|
TAY ;
|
|
TXA ;
|
|
LDX DSCTMP ;
|
|
JSR HGLIN ; PLOT LINE
|
|
JMP L_HPLOT_1 ; LOOP TILL NO MORE "TO" PHRASES
|
|
; --------------------------------
|
|
; "ROT=" STATEMENT
|
|
; --------------------------------
|
|
ROT JSR GETBYT ; EVAL EXP TO A BYTE IN X-REG
|
|
STX HGR_ROTATION
|
|
RTS
|
|
; --------------------------------
|
|
; "SCALE=" STATEMENT
|
|
; --------------------------------
|
|
SCALE JSR GETBYT ; EVAL EXP TO A BYTE IN X-REG
|
|
STX HGR_SCALE
|
|
RTS
|
|
; --------------------------------
|
|
; SET UP FOR DRAW AND XDRAW
|
|
; --------------------------------
|
|
DRWPNT JSR GETBYT ; GET SHAPE NUMBER IN X-REG
|
|
LDA HGR_SHAPE_PNTR ; SEARCH FOR THAT SHAPE
|
|
STA HGR_SHAPE ; SET UP PNTR TO BEGINNING OF TABLE
|
|
LDA HGR_SHAPE_PNTR+1
|
|
STA HGR_SHAPE+1
|
|
TXA
|
|
LDX #0
|
|
CMP (HGR_SHAPE,X) ; COMPARE TO # OF SHAPES IN TABLE
|
|
BEQ L_DRWPNT_1 ; LAST SHAPE IN TABLE
|
|
BCS GGERR ; SHAPE # TOO LARGE
|
|
L_DRWPNT_1 ASL ; DOUBLE SHAPE# TO MAKE AN INDEX
|
|
BCC L_DRWPNT_2 ; ADD 256 IF SHAPE # > 127
|
|
INC HGR_SHAPE+1
|
|
CLC
|
|
L_DRWPNT_2 TAY ; USE INDEX TO LOOK UP OFFSET FOR SHAPE
|
|
LDA (HGR_SHAPE),Y ; IN OFFSET TABLE
|
|
ADC HGR_SHAPE
|
|
TAX
|
|
INY
|
|
LDA (HGR_SHAPE),Y
|
|
ADC HGR_SHAPE_PNTR+1
|
|
STA HGR_SHAPE+1 ; SAVE ADDRESS OF SHAPE
|
|
STX HGR_SHAPE
|
|
JSR CHRGOT ; IS THERE ANY "AT" PHRASE?
|
|
CMP #TOKENDB ;
|
|
BNE L_DRWPNT_3 ; NO, DRAW RIGHT WHERE WE ARE
|
|
JSR SYNCHR ; SCAN OVER "AT"
|
|
JSR HFNS ; GET X- AND Y-COORDS TO START DRAWING AT
|
|
JSR HPOSN ; SET UP CURSOR THERE
|
|
L_DRWPNT_3 LDA HGR_ROTATION ; ROTATION VALUE
|
|
RTS
|
|
; --------------------------------
|
|
; "DRAW" STATEMENT
|
|
; --------------------------------
|
|
DRAW JSR DRWPNT
|
|
JMP DRAW1
|
|
; --------------------------------
|
|
; "XDRAW" STATEMENT
|
|
; --------------------------------
|
|
XDRAW JSR DRWPNT
|
|
JMP XDRAW1
|
|
; --------------------------------
|
|
; "SHLOAD" STATEMENT
|
|
;
|
|
; READS A SHAPE TABLE FROM CASSETTE TAPE
|
|
; TO A POSITION JUST BELOW HIMEM.
|
|
; HIMEM IS THEN MOVED TO JUST BELOW THE TABLE
|
|
; --------------------------------
|
|
SHLOAD LDA #>LINNUM ; SET UP TO READ TWO BYTES
|
|
STA MON_A1H ; INTO LINNUM,LINNUM+1
|
|
STA MON_A2H ;
|
|
LDY #LINNUM ;
|
|
STY MON_A1L ;
|
|
INY ; LINNUM+1
|
|
STY MON_A2L ;
|
|
JSR MON_READ ; READ TAPE
|
|
CLC ; SETUP TO READ (LINNUM) BYTES
|
|
LDA MEMSIZ ; ENDING AT HIMEM-1
|
|
TAX ;
|
|
DEX ; FORMING HIMEM-1
|
|
STX MON_A2L ;
|
|
SBC LINNUM ; FORMING HIMEM-(LINNUM)
|
|
PHA ;
|
|
LDA MEMSIZ+1 ;
|
|
TAY ;
|
|
INX ; SEE IF HIMEM LOW-BYTE WAS ZERO
|
|
BNE L_SHLOAD_1 ; NO
|
|
DEY ; YES, HAVE TO DECREMENT HIGH BYTE
|
|
L_SHLOAD_1 STY MON_A2H ;
|
|
SBC LINNUM+1 ;
|
|
CMP STREND+1 ; RUNNING INTO VARIABLES?
|
|
BCC L_SHLOAD_2 ; YES, OUT OF MEMORY
|
|
BNE L_SHLOAD_3 ; NO, STILL ROOM
|
|
L_SHLOAD_2 JMP MEMERR ; MEM FULL ERR
|
|
L_SHLOAD_3 STA MEMSIZ+1 ;
|
|
STA FRETOP+1 ; CLEAR STRING SPACE
|
|
STA MON_A1H ; (BUT NAMES ARE STILL IN VARTBL!)
|
|
STA HGR_SHAPE_PNTR+1
|
|
PLA
|
|
STA HGR_SHAPE_PNTR
|
|
STA MEMSIZ
|
|
STA FRETOP
|
|
STA MON_A1L
|
|
JSR MON_RD2BIT ; READ TO TAPE TRANSITIONS
|
|
LDA #3 ; SHORT DELAY FOR INTERMEDIATE HEADER
|
|
JMP MON_READ2 ; READ SHAPES
|
|
; --------------------------------
|
|
; CALLED FROM STORE AND RECALL
|
|
; --------------------------------
|
|
TAPEPNT
|
|
CLC
|
|
LDA LOWTR
|
|
ADC LINNUM
|
|
STA MON_A2L
|
|
LDA LOWTR+1
|
|
ADC LINNUM+1
|
|
STA MON_A2H
|
|
LDY #4
|
|
LDA (LOWTR),Y
|
|
JSR GETARY2
|
|
LDA HIGHDS
|
|
STA MON_A1L
|
|
LDA HIGHDS+1
|
|
STA MON_A1H
|
|
RTS
|
|
; --------------------------------
|
|
; CALLED FROM STORE AND RECALL
|
|
; --------------------------------
|
|
GETARYPT
|
|
LDA #$40
|
|
STA SUBFLG
|
|
JSR PTRGET
|
|
LDA #0
|
|
STA SUBFLG
|
|
JMP VARTIO
|
|
; --------------------------------
|
|
; "HTAB" STATEMENT
|
|
;
|
|
; NOTE THAT IF WNDLEFT IS NOT 0, HTAB CAN PRINT
|
|
; OUTSIDE THE SCREEN (EG., IN THE PROGRAM)
|
|
; --------------------------------
|
|
HTAB JSR GETBYT
|
|
DEX
|
|
TXA
|
|
L_HTAB_1 CMP #40
|
|
BCC L_HTAB_2
|
|
SBC #40
|
|
PHA
|
|
JSR CRDO
|
|
PLA
|
|
JMP L_HTAB_1
|
|
L_HTAB_2 STA MON_CH
|
|
RTS
|
|
; --------------------------------
|
|
HIASCII(`KRW') ; UNKNOWN
|