Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
15847 lines (12580 sloc) 466 KB
;************************************************************************************
;************************************************************************************
; This file was included in the Project 64 Repository after all efforts to contact
; Lee Davison, the original author, were proven unsuccessful. The inclusion is meant
; to honour his sterling work on providing us with the very best document on every
; bit of the Commodore 64's firmware content. We want this to remain available to
; the public and allow other members to benefit from Lee's original, excellent job.
;************************************************************************************
; $VER:C64LD11.S, included on 2014-11-12
;************************************************************************************
;
; The almost completely commented C64 ROM disassembly. V1.01 Lee Davison 2012
;
; This is a bit correct assembly listing for the C64 BASIC and kernal ROMs as two 8K
; ROMs. You should be able to assemble the C64 ROMs from this with most 6502 assemblers,
; as no macros or 'special' features were used. This has been tested using Michal
; Kowalski's 6502 Simulator assemble function. See http://exifpro.com/utils.html for
; this program.
;
; Many references were used to complete this disassembly including, but not limited to,
; "Mapping the Vic 20", "Mapping the C64", "C64 Programmers reference", "C64 user
; guide", "The complete Commodore inner space anthology", "VIC Revealed" and various
; text files, pictures and other documents.
;************************************************************************************
;************************************************************************************
;
; first a whole load of equates
LAB_00 = $00 ; 6510 I/O port data direction register
; bit default
; --- -------
; 7 unused
; 6 unused
; 5 1 = output
; 4 0 = input
; 3 1 = output
; 2 1 = output
; 1 1 = output
; 0 1 = output
LAB_01 = $01 ; 6510 I/O port data register
; bit name function
; --- ---- --------
; 7 unused
; 6 unused
; 5 cass motor 1 = off, 0 = on
; 4 cass sw 1 = off, 0 = on
; 3 cass data
; 2 CHAREN 1 = I/O, 0 = chraracter ROM
; 1 HIRAM 1 = Kernal, 0 = RAM
; 0 LORAM 1 = BASIC, 0 = RAM
;LAB_02 = $02 ; unused
; This vector points to the address of the BASIC routine which converts a floating point
; number to an integer, however BASIC does not use this vector. It may be of assistance
; to the programmer who wishes to use data that is stored in floating point format. The
; parameter passed by the USR command is available only in that format for example.
LAB_03 = $03 ; float to fixed vector low byte
LAB_04 = $04 ; float to fixed vector high byte
; This vector points to the address of the BASIC routine which converts an integer to a
; floating point number, however BASIC does not use this vector. It may be used by the
; programmer who needs to make such a conversion for a machine language program that
; interacts with BASIC. To return an integer value with the USR command for example.
LAB_05 = $05 ; fixed to float vector low byte
LAB_06 = $06 ; fixed to float vector high byte
; These locations hold searched for characters when BASIC is searching for the end of
; a srting or crunching BASIC lines
LAB_07 = $07 ; search character
LAB_08 = $08 ; scan quotes flag
; The cursor column position prior to the TAB or SPC is moved here from $D3, and is used
; to calculate where the cursor ends up after one of these functions is invoked.
; Note that the value contained here shows the position of the cursor on a logical line.
; Since one logical line can be up to four physical lines long, the value stored here
; can range from 0 to 87.
LAB_09 = $09 ; TAB column save
; The routine that converts the text in the input buffer into lines of executable program
; tokes, and the routines that link these program lines together, use this location as an
; index into the input buffer area. After the job of converting text to tokens is done,
; the value in this location is equal to the length of the tokenized line.
; The routines which build an array or locate an element in an array use this location to
; calculate the number of DIMensions called for and the amount of storage required for a
; newly created array, or the number of subscripts when referencing an array element.
LAB_0A = $0A ; load/verify flag, 0 = load, 1 = verify
LAB_0B = $0B ; temporary byte, line crunch/array access/logic operators
; This is used as a flag by the routines that build an array or reference an existing
; array. It is used to determine whether a variable is in an array, whether the array
; has already been DIMensioned, and whether a new array should assume the default size.
LAB_0C = $0C ; DIM flag
; This flag is used to indicate whether data being operated upon is string or numeric. A
; value of $FF in this location indicates string data while a $00 indicates numeric data.
LAB_0D = $0D ; data type flag, $FF = string, $00 = numeric
; If the above flag indicates numeric then a $80 in this location identifies the number
; as an integer, and a $00 indicates a floating point number.
LAB_0E = $0E ; data type flag, $80 = integer, $00 = floating point
; The garbage collection routine uses this location as a flag to indicate that garbage
; collection has already been tried before adding a new string. If there is still not
; enough memory, an OUT OF MEMORY error message will result.
; LIST uses this byte as a flag to let it know when it has come to a character string in
; quotes. It will then print the string,rather than search it for BASIC keyword tokens.
; This location is also used during the process of converting a line of text in the BASIC
; input buffer into a linked program line of BASIC keyword tokens to flag a DATA line is
; being processed.
LAB_0F = $0F ; garbage collected/open quote/DATA flag
; If an opening parenthesis is found, this flag is set to indicate that the variable in
; question is either an array variable or a user-defined function.
LAB_10 = $10 ; subscript/FNx flag
; This location is used to determine whether the sign of the value returned by the
; functions SIN, COS, ATN or TAN is positive or negative.
; Also the comparison routines use this location to indicate the outcome of the compare.
; For A <=> B the value here will be $01 if A > B, $02 if A = B, and $04 if A < B. If
; more than one comparison operator was used to compare the two variables then the value
; here will be a combination of the above values.
LAB_11 = $11 ; input mode flag, $00 = INPUT, $40 = GET, $98 = READ
LAB_12 = $12 ; ATN sign/comparison evaluation flag
; When the default input or output device is used the value here will be a zero, and the
; format of prompting and output will be the standard screen output format. The location
; $B8 is used to decide what device actually to put input from or output to.
LAB_13 = $13 ; current I/O channel
; Used whenever a 16 bit integer is used e.g. the target line number for GOTO, LIST, ON,
; and GOSUB also the number of a BASIC line that is to be added or replaced. additionally
; PEEK, POKE, WAIT, and SYS use this location as a pointer to the address which is the
; subject of the command.
LAB_14 = $14 ; temporary integer low byte
LAB_15 = $15 ; temporary integer high byte
; This location points to the next available slot in the temporary string descriptor
; stack located at $19-$21.
LAB_16 = $16 ; descriptor stack pointer, next free
; This contains information about temporary strings which hve not yet been assigned to
; a string variable.
LAB_17 = $17 ; current descriptor stack item pointer low byte
LAB_18 = $18 ; current descriptor stack item pointer high byte
LAB_19 = $19 ; to $21, descriptor stack
; These locations are used by BASIC multiplication and division routines. They are also
; used by the routines which compute the size of the area required to store an array
; which is being created.
LAB_22 = $22 ; misc temp byte
LAB_23 = $23 ; misc temp byte
LAB_24 = $24 ; misc temp byte
LAB_25 = $25 ; misc temp byte
LAB_26 = $26 ; temp mantissa 1
LAB_27 = $27 ; temp mantissa 2
LAB_28 = $28 ; temp mantissa 3
LAB_29 = $29 ; temp mantissa 4
; Two byte pointer to where the BASIC program text is stored.
LAB_2B = $2B ; start of memory low byte
LAB_2C = $2C ; start of memory high byte
; Two byte pointer to the start of the BASIC variable storage area.
LAB_2D = $2D ; start of variables low byte
LAB_2E = $2E ; start of variables high byte
; Two byte pointer to the start of the BASIC array storage area.
LAB_2F = $2F ; end of variables low byte
LAB_30 = $30 ; end of variables high byte
; Two byte pointer to end of the start of free RAM.
LAB_31 = $31 ; end of arrays low byte
LAB_32 = $32 ; end of arrays high byte
; Two byte pointer to the bottom of the string text storage area.
LAB_33 = $33 ; bottom of string space low byte
LAB_34 = $34 ; bottom of string space high byte
; Used as a temporary pointer to the most current string added by the routines which
; build strings or move them in memory.
LAB_35 = $35 ; string utility ptr low byte
LAB_36 = $36 ; string utility ptr high byte
; Two byte pointer to the highest address used by BASIC +1.
LAB_37 = $37 ; end of memory low byte
LAB_38 = $38 ; end of memory high byte
; These locations contain the line number of the BASIC statement which is currently being
; executed. A value of $FF in location $3A means that BASIC is in immediate mode.
LAB_39 = $39 ; current line number low byte
LAB_3A = $3A ; current line number high byte
; When program execution ends or stops the last line number executed is stored here.
LAB_3B = $3B ; break line number low byte
LAB_3C = $3C ; break line number high byte
; These locations contain the address of the start of the text of the BASIC statement
; that is being executed. The value of the pointer to the address of the BASIC text
; character currently being scanned is stored here each time a new BASIC statement begins
; execution.
LAB_3D = $3D ; continue pointer low byte
LAB_3E = $3E ; continue pointer high byte
; These locations hold the line number of the current DATA statement being READ. If an
; error concerning the DATA occurs this number will be moved to $39/$3A so that the error
; message will show the line that contains the DATA statement rather than in the line that
; contains the READ statement.
LAB_3F = $3F ; current DATA line number low byte
LAB_40 = $40 ; current DATA line number high byte
; These locations point to the address where the next DATA will be READ from. RESTORE
; sets this pointer back to the address indicated by the start of BASIC pointer.
LAB_41 = $41 ; DATA pointer low byte
LAB_42 = $42 ; DATA pointer high byte
; READ, INPUT and GET all use this as a pointer to the address of the source of incoming
; data, such as DATA statements, or the text input buffer.
LAB_43 = $43 ; READ pointer low byte
LAB_44 = $44 ; READ pointer high byte
LAB_45 = $45 ; current variable name first byte
LAB_46 = $46 ; current variable name second byte
; These locations point to the value of the current BASIC variable Specifically they
; point to the byte just after the two-character variable name.
LAB_47 = $47 ; current variable address low byte
LAB_48 = $48 ; current variable address high byte
; The address of the BASIC variable which is the subject of a FOR/NEXT loop is first
; stored here before being pushed onto the stack.
LAB_49 = $49 ; FOR/NEXT variable pointer low byte
LAB_4A = $4A ; FOR/NEXT variable pointer high byte
; The expression evaluation routine creates this to let it know whether the current
; comparison operation is a < $01, = $02 or > $04 comparison or combination.
LAB_4B = $4B ; BASIC execute pointer temporary low byte/precedence flag
LAB_4C = $4C ; BASIC execute pointer temporary high byte
LAB_4D = $4D ; comparrison evaluation flag
; These locations are used as a pointer to the function that is created during function
; definition . During function execution it points to where the evaluation results should
; be saved.
LAB_4E = $4E ; FAC temp store/function/variable/garbage pointer low byte
LAB_4F = $4F ; FAC temp store/function/variable/garbage pointer high byte
; Temporary Pointer to the current string descriptor.
LAB_50 = $50 ; FAC temp store/descriptor pointer low byte
LAB_51 = $51 ; FAC temp store/descriptor pointer high byte
LAB_53 = $53 ; garbage collection step size
; The first byte is the 6502 JMP instruction $4C, followed by the address of the required
; function taken from the table at $C052.
LAB_54 = $54 ; JMP opcode for functions
LAB_55 = $55 ; functions jump vector low byte
LAB_56 = $56 ; functions jump vector high byte
LAB_57 = $57 ; FAC temp store
LAB_58 = $58 ; FAC temp store
LAB_59 = $59 ; FAC temp store
LAB_5A = $5A ; FAC temp store
LAB_5B = $5B ; block end high byte
LAB_5C = $5C ; FAC temp store
LAB_5D = $5D ; FAC temp store
LAB_5E = $5E ; FAC temp store
LAB_5F = $5F ; FAC temp store
LAB_60 = $60 ; block start high byte
; floating point accumulator 1
LAB_61 = $61 ; FAC1 exponent
LAB_62 = $62 ; FAC1 mantissa 1
LAB_63 = $63 ; FAC1 mantissa 2
LAB_64 = $64 ; FAC1 mantissa 3
LAB_65 = $65 ; FAC1 mantissa 4
LAB_66 = $66 ; FAC1 sign
LAB_67 = $67 ; constant count/-ve flag
LAB_68 = $68 ; FAC1 overflow
; floating point accumulator 2
LAB_69 = $69 ; FAC2 exponent
LAB_6A = $6A ; FAC2 mantissa 1
LAB_6B = $6B ; FAC2 mantissa 2
LAB_6C = $6C ; FAC2 mantissa 3
LAB_6D = $6D ; FAC2 mantissa 4
LAB_6E = $6E ; FAC2 sign
LAB_6F = $6F ; FAC sign comparrison
LAB_70 = $70 ; FAC1 rounding
LAB_71 = $71 ; temp BASIC execute/array pointer low byte/index
LAB_72 = $72 ; temp BASIC execute/array pointer high byte
LAB_0073 = $73 ; increment and scan memory, BASIC byte get
LAB_0079 = $79 ; scan memory, BASIC byte get
LAB_7A = $7A ; BASIC execute pointer low byte
LAB_7B = $7B ; BASIC execute pointer high byte
LAB_80 = $80 ; numeric test entry
LAB_8B = $8B ; RND() seed, five bytes
; kernal work area
LAB_90 = $90 ; serial status byte
; function
; bit casette serial bus
; --- -------- ----------
; 7 end of tape device not present
; 6 end of file EOI
; 5 checksum error
; 4 read error
; 3 long block
; 2 short block
; 1 time out read
; 0 time out write
; This location is updated every 1/60 second during the IRQ routine. The value saved is
; the keyboard c7 column byte which contains the stop key
LAB_91 = $91 ; stop key column
; bit key, 0 = pressed
; --- --------
; 7 [RUN]
; 6 Q
; 5 [CBM]
; 4 [SP]
; 3 2
; 2 [CTL]
; 1 [LFT]
; 0 1
; This location is used as an adjustable timing constant for tape reads to allow for
; slight speed variations on tapes.
LAB_92 = $92 ; timing constant for tape read
; The same routine is used for both LOAD and VERIFY, the flag here determines which
; that routine does.
LAB_93 = $93 ; load/verify flag, load = $00, verify = $01
; This location is used to indecate that a serial byte is waiting to be sent.
LAB_94 = $94 ; serial output: deferred character flag
; $00 = no character waiting, $xx = character waiting
; This location holds the serial character waiting to be sent. A value of $FF here
; means no character is waiting.
LAB_95 = $95 ; serial output: deferred character
; $FF = no character waiting, $xx = waiting character
LAB_96 = $96 ; cassette block synchronization number
; X register save location for routines that get and put an ASCII character.
LAB_97 = $97 ; X register save
; The number of currently open I/O files is stored here. The maximum number that can be
; open at one time is ten. The number stored here is used as the index to the end of the
; tables that hold the file numbers, device numbers, and secondary addresses.
LAB_98 = $98 ; open file count
; The default value of this location is 0, the keyboard.
LAB_99 = $99 ; input device number
; The default value of this location is 3, the screen.
LAB_9A = $9A ; output device number
; number device
; ------ ------
; 0 keyboard
; 1 cassette
; 2 RS-232C
; 3 screen
; 4-31 serial bus
LAB_9B = $9B ; tape character parity
LAB_9C = $9C ; tape byte received flag
LAB_9D = $9D ; message mode flag,
; $C0 = both control and kernal messages,
; $80 = control messages only,
; $40 = kernal messages only,
; $00 = neither control or kernal messages
LAB_9E = $9E ; tape Pass 1 error log/character buffer
LAB_9F = $9F ; tape Pass 1 error log/character index
; These three locations form a counter which is updated 60 times a second, and serves as
; a software clock which counts the number of jiffies that have elapsed since the computer
; was turned on. After 24 hours and one jiffy these locations are set back to $000000.
LAB_A0 = $A0 ; jiffy clock high byte
LAB_A1 = $A1 ; jiffy clock mid byte
LAB_A2 = $A2 ; jiffy clock low byte
LAB_A3 = $A3 ; EOI flag byte/tape bit count
; b0 of this location reflects the current phase of the tape output cycle.
LAB_A4 = $A4 ; tape bit cycle phase
LAB_A5 = $A5 ; cassette synchronization byte count/serial bus bit count
LAB_A6 = $A6 ; tape buffer index
LAB_A7 = $A7 ; receiver input bit temp storage
LAB_A8 = $A8 ; receiver bit count in
LAB_A9 = $A9 ; receiver start bit check flag, $90 = no start bit
; received, $00 = start bit received
LAB_AA = $AA ; receiver byte buffer/assembly location
LAB_AB = $AB ; receiver parity bit storage
LAB_AC = $AC ; tape buffer start pointer low byte
; scroll screen ?? byte
LAB_AD = $AD ; tape buffer start pointer high byte
; scroll screen ?? byte
LAB_AE = $AE ; tape buffer end pointer low byte
; scroll screen ?? byte
LAB_AF = $AF ; tape buffer end pointer high byte
; scroll screen ?? byte
LAB_B0 = $B0 ; tape timing constant min byte
LAB_B1 = $B1 ; tape timing constant max byte
; Thess two locations point to the address of the cassette buffer. This pointer must
; be greater than or equal to $0200 or an ILLEGAL DEVICE NUMBER error will be sent
; when tape I/O is tried. This pointer must also be less that $8000 or the routine
; will terminate early.
LAB_B2 = $B2 ; tape buffer start pointer low byte
LAB_B3 = $B3 ; tape buffer start pointer high byte
; RS232 routines use this to count the number of bits transmitted and for parity and
; stop bit manipulation. Tape load routines use this location to flag when they are
; ready to receive data bytes.
LAB_B4 = $B4 ; transmitter bit count out
; This location is used by the RS232 routines to hold the next bit to be sent and by the
; tape routines to indicate what part of a block the read routine is currently reading.
LAB_B5 = $B5 ; transmitter next bit to be sent
; RS232 routines use this area to disassemble each byte to be sent from the transmission
; buffer pointed to by $F9.
LAB_B6 = $B6 ; transmitter byte buffer/disassembly location
; Disk filenames may be up to 16 characters in length while tape filenames be up to 187
; characters in length.
; If a tape name is longer than 16 characters the excess will be truncated by the
; SEARCHING and FOUND messages, but will still be present on the tape.
; A disk file is always referred to by a name. This location will always be greater than
; zero if the current file is a disk file.
; An RS232 OPEN command may specify a filename of up to four characters. These characters
; are copied to locations $293 to $296 and determine baud rate, word length, and parity,
; or they would do if the feature was fully implemented.
LAB_B7 = $B7 ; file name length
LAB_B8 = $B8 ; logical file
LAB_B9 = $B9 ; secondary address
LAB_BA = $BA ; current device number
; number device
; ------ ------
; 0 keyboard
; 1 cassette
; 2 RS-232C
; 3 screen
; 4-31 serial bus
LAB_BB = $BB ; file name pointer low byte
LAB_BC = $BC ; file name pointer high byte
LAB_BD = $BD ; tape write byte/RS232 parity byte
; Used by the tape routines to count the number of copies of a data block remaining to
; be read or written.
LAB_BE = $BE ; tape copies count
LAB_BF = $BF ; tape parity count
LAB_C0 = $C0 ; tape motor interlock
LAB_C1 = $C1 ; I/O start addresses low byte
LAB_C2 = $C2 ; I/O start addresses high byte
LAB_C3 = $C3 ; kernal setup pointer low byte
LAB_C4 = $C4 ; kernal setup pointer high byte
LAB_C5 = $C5 ; current key pressed
;
; # key # key # key # key
; -- --- -- --- -- --- -- ---
; 00 1 10 none 20 [SPACE] 30 Q
; 01 3 11 A 21 Z 31 E
; 02 5 12 D 22 C 32 T
; 03 7 13 G 23 B 33 U
; 04 9 14 J 24 M 34 O
; 05 + 15 L 25 . 35 @
; 06 [UKP] 16 ; 26 none 36 ^
; 07 [DEL] 17 [CSR R] 27 [F1] 37 [F5]
; 08 [<-] 18 [STOP] 28 none 38 2
; 09 W 19 none 29 S 39 4
; 0A R 1A X 2A F 3A 6
; 0B Y 1B V 2B H 3B 8
; 0C I 1C N 2C K 3C 0
; 0D P 1D , 2D : 3D -
; 0E * 1E / 2E = 3E [HOME]
; 0F [RET] 1F [CSR D] 2F [F3] 3F [F7]
LAB_C6 = $C6 ; keyboard buffer length/index
; When the [CTRL][RVS-ON] characters are printed this flag is set to $12, and the print
; routines will add $80 to the screen code of each character which is printed, so that
; the caracter will appear on the screen with its colours reversed.
; Note that the contents of this location are cleared not only upon entry of a
; [CTRL][RVS-OFF] character but also at every carriage return.
LAB_C7 = $C7 ; reverse flag $12 = reverse, $00 = normal
; This pointer indicates the column number of the last nonblank character on the logical
; line that is to be input. Since a logical line can be up to 88 characters long this
; number can range from 0-87.
LAB_C8 = $C8 ; input [EOL] pointer
; These locations keep track of the logical line that the cursor is on and its column
; position on that logical line.
; Each logical line may contain up to four 22 column physical lines. So there may be as
; many as 23 logical lines, or as few as 6 at any one time. Therefore, the logical line
; number might be anywhere from 1-23. Depending on the length of the logical line, the
; cursor column may be from 1-22, 1-44, 1-66 or 1-88.
; For a more on logical lines, see the description of the screen line link table, $D9.
LAB_C9 = $C9 ; input cursor row
LAB_CA = $CA ; input cursor column
; The keyscan interrupt routine uses this location to indicate which key is currently
; being pressed. The value here is then used as an index into the appropriate keyboard
; table to determine which character to print when a key is struck.
; The correspondence between the key pressed and the number stored here is as follows:
; $00 1 $10 not used $20 [SPACE] $30 Q $40 [NO KEY]
; $01 3 $11 A $21 Z $31 E $xx invalid
; $02 5 $12 D $22 C $32 T
; $03 7 $13 G $23 B $33 U
; $04 9 $14 J $24 M $34 O
; $05 + $15 L $25 . $35 @
; $06 [POUND] $16 ; $26 not used $36 [U ARROW]
; $07 [DEL] $17 [RIGHT] $27 [F1] $37 [F5]
; $08 [L ARROW] $18 [STOP] $28 not used $38 2
; $09 W $19 not used $29 S $39 4
; $0A R $1A X $2A F $3A 6
; $0B Y $1B V $2B H $3B 8
; $0C I $1C N $2C K $3C 0
; $0D P $1D , $2D : $3D -
; $0E * $1E / $2E = $3E [HOME]
; $0F [RETURN] $1F [DOWN] $2F [F3] $3F [F7]
LAB_CB = $CB ; which key
; When this flag is set to a nonzero value, it indicates to the routine that normally
; flashes the cursor not to do so. The cursor blink is turned off when there are
; characters in the keyboard buffer, or when the program is running.
LAB_CC = $CC ; cursor enable, $00 = flash cursor
; The routine that blinks the cursor uses this location to tell when it's time for a
; blink. The number 20 is put here and decremented every jiffy until it reaches zero.
; Then the cursor state is changed, the number 20 is put back here, and the cycle starts
; all over again.
LAB_CD = $CD ; cursor timing countdown
; The cursor is formed by printing the inverse of the character that occupies the cursor
; position. If that characters is the letter A, for example, the flashing cursor merely
; alternates between printing an A and a reverse-A. This location keeps track of the
; normal screen code of the character that is located at the cursor position, so that it
; may be restored when the cursor moves on.
LAB_CE = $CE ; character under cursor
; This location keeps track of whether, during the current cursor blink, the character
; under the cursor was reversed, or was restored to normal. This location will contain
; $00 if the character is reversed, and $01 if the character is not reversed.
LAB_CF = $CF ; cursor blink phase
LAB_D0 = $D0 ; input from keyboard or screen, $xx = input is available
; from the screen, $00 = input should be obtained from the
; keyboard
; These locations point to the address in screen RAM of the first column of the logical
; line upon which the cursor is currently positioned.
LAB_D1 = $D1 ; current screen line pointer low byte
LAB_D2 = $D2 ; current screen line pointer high byte
; This holds the cursor column position within the logical line pointed to by LAB_D1.
; Since a logical line can comprise up to four physical lines, this value may be from
; $00 to $57.
LAB_D3 = $D3 ; cursor column
; A nonzero value in this location indicates that the editor is in quote mode. Quote
; mode is toggled every time that you type in a quotation mark on a given line, the
; first quote mark turns it on, the second turns it off, the third turns it on, etc.
; If the editor is in this mode when a cursor control character or other nonprinting
; character is entered, a printed equivalent will appear on the screen instead of the
; cursor movement or other control operation taking place. Instead, that action is
; deferred until the string is sent to the string by a PRINT statement, at which time
; the cursor movement or other control operation will take place.
; The exception to this rule is the DELETE key, which will function normally within
; quote mode. The only way to print a character which is equivalent to the DELETE key
; is by entering insert mode. Quote mode may be exited by printing a closing quote or
; by hitting the RETURN or SHIFT-RETURN keys.
LAB_D4 = $D4 ; cursor quote flag
; The line editor uses this location when the end of a line has been reached to determine
; whether another physical line can be added to the current logical line or if a new
; logical line must be started.
LAB_D5 = $D5 ; current screen line length
; This location contains the current physical screen line position of the cursor, 0 to 22.
LAB_D6 = $D6 ; cursor row
; The ASCII value of the last character printed to the screen is held here temporarily.
LAB_D7 = $D7 ; checksum byte/temporary last character
; When the INST key is pressed, the screen editor shifts the line to the right, allocates
; another physical line to the logical line if necessary (and possible), updates the
; screen line length in $D5, and adjusts the screen line link table at $D9. This location
; is used to keep track of the number of spaces that has been opened up in this way.
; Until the spaces that have been opened up are filled, the editor acts as if in quote
; mode. See location $D4, the quote mode flag. This means that cursor control characters
; that are normally nonprinting will leave a printed equivalent on the screen when
; entered, instead of having their normal effect on cursor movement, etc. The only
; difference between insert and quote mode is that the DELETE key will leave a printed
; equivalent in insert mode, while the INSERT key will insert spaces as normal.
LAB_D8 = $D8 ; insert count
; This table contains 25 entries, one for each row of the screen display. Each entry has
; two functions. Bits 0-3 indicate on which of the four pages of screen memory the first
; byte of memory for that row is located. This is used in calculating the pointer to the
; starting address of a screen line at LAB_D1.
;
; The high byte is calculated by adding the value of the starting page of screen memory
; held in $288 to the displacement page held here.
;
; The other function of this table is to establish the makeup of logical lines on the
; screen. While each screen line is only 40 characters long, BASIC allows the entry of
; program lines that contain up to 80 characters. Therefore, some method must be used
; to determine which physical lines are linked into a longer logical line, so that this
; longer logical line may be edited as a unit.
;
; The high bit of each byte here is used as a flag by the screen editor. That bit is set
; when a line is the first or only physical line in a logical line. The high bit is reset
; to 0 only when a line is an extension to this logical line.
LAB_D9 = $D9 ; to LAB_D9 + $18 inclusive, screen line link table
LAB_F3 = $F3 ; colour RAM pointer low byte
LAB_F4 = $F4 ; colour RAM pointer high byte
; This pointer points to the address of the keyboard matrix lookup table currently being
; used. Although there are only 64 keys on the keyboard matrix, each key can be used to
; print up to four different characters, depending on whether it is struck by itself or
; in combination with the SHIFT, CTRL, or C= keys.
; These tables hold the ASCII value of each of the 64 keys for one of these possible
; combinations of keypresses. When it comes time to print the character, the table that
; is used determines which character is printed.
; The addresses of the tables are:
; LAB_EB81 ; unshifted
; LAB_EBC2 ; shifted
; LAB_EC03 ; commodore
; LAB_EC78 ; control
LAB_F5 = $F5 ; keyboard pointer low byte
LAB_F6 = $F6 ; keyboard pointer high byte
; When device the RS232 channel is opened two buffers of 256 bytes each are created at
; the top of memory. These locations point to the address of the one which is used to
; store characters as they are received.
LAB_F7 = $F7 ; RS232 Rx pointer low byte
LAB_F8 = $F8 ; RS232 Rx pointer high byte
; These locations point to the address of the 256 byte output buffer that is used for
; transmitting data to RS232 devices.
LAB_F9 = $F9 ; RS232 Tx pointer low byte
LAB_FA = $FA ; RS232 Tx pointer high byte
LAB_FF = $FF ; string conversion address
LAB_0100 = $0100 ;.
LAB_0101 = $0101 ;.
LAB_0102 = $0102 ;.
LAB_0103 = $0103 ;.
LAB_0104 = $0104 ;.
LAB_0109 = $0109 ;.
LAB_010F = $010F ;.
LAB_0110 = $0110 ;.
LAB_0111 = $0111 ;.
LAB_0112 = $0112 ;.
LAB_01FC = $01FC ; start of crunched line
LAB_01FD = $01FD ;.
LAB_01FE = $01FE ;.
LAB_01FF = $01FF ; input buffer - 1
LAB_0200 = $0200 ; input buffer. for some routines the byte before the input
; buffer needs to be set to a specific value for the routine
; to work correctly
LAB_0201 = $0201 ; address for GET byte
LAB_0259 = $0259 ; .. to LAB_0262 logical file table
LAB_0263 = $0263 ; .. to LAB_026C device number table
LAB_026D = $026D ; .. to LAB_0276 secondary address table
LAB_0277 = $0277 ; .. to LAB_0280 keyboard buffer
LAB_0281 = $0281 ; OS start of memory low byte
LAB_0282 = $0282 ; OS start of memory high byte
LAB_0283 = $0283 ; OS top of memory low byte
LAB_0284 = $0284 ; OS top of memory high byte
LAB_0285 = $0285 ; serial bus timeout flag
LAB_0286 = $0286 ; current colour code
; $00 black
; $01 white
; $02 red
; $03 cyan
; $04 magents
; $05 green
; $06 blue
; $07 yellow
; $08 orange
; $09 brown
; $0A light red
; $0B dark grey
; $0C medium grey
; $0D light green
; $0E light blue
; $0F light grey
LAB_0287 = $0287 ; colour under cursor
LAB_0288 = $0288 ; screen memory page
LAB_0289 = $0289 ; maximum keyboard buffer size
LAB_028A = $028A ; key repeat. $80 = repeat all, $40 = repeat none,
; $00 = repeat cursor movement keys, insert/delete
; key and the space bar
LAB_028B = $028B ; repeat speed counter
LAB_028C = $028C ; repeat delay counter
; This flag signals which of the SHIFT, CTRL, or C= keys are currently being pressed.
; A value of $01 signifies that one of the SHIFT keys is being pressed, a $02 shows that
; the C= key is down, and $04 means that the CTRL key is being pressed. If more than one
; key is held down, these values will be added e.g $03 indicates that SHIFT and C= are
; both held down.
; Pressing the SHIFT and C= keys at the same time will toggle the character set that is
; presently being used between the uppercase/graphics set, and the lowercase/uppercase
; set.
; While this changes the appearance of all of the characters on the screen at once it
; has nothing whatever to do with the keyboard shift tables and should not be confused
; with the printing of SHIFTed characters, which affects only one character at a time.
LAB_028D = $028D ; keyboard shift/control flag
; bit key(s) 1 = down
; --- ---------------
; 7-3 unused
; 2 CTRL
; 1 C=
; 0 SHIFT
; This location, in combination with the one above, is used to debounce the special
; SHIFT keys. This will keep the SHIFT/C= combination from changing character sets
; back and forth during a single pressing of both keys.
LAB_028E = $028E ; SHIFT/CTRL/C= keypress last pattern
; This location points to the address of the Operating System routine which actually
; determines which keyboard matrix lookup table will be used.
; The routine looks at the value of the SHIFT flag at $28D, and based on what value
; it finds there, stores the address of the correct table to use at location $F5.
LAB_028F = $028F ; keyboard decode logic pointer low byte
LAB_0290 = $0290 ; keyboard decode logic pointer high byte
; This flag is used to enable or disable the feature which lets you switch between the
; uppercase/graphics and upper/lowercase character sets by pressing the SHIFT and
; Commodore logo keys simultaneously.
LAB_0291 = $0291 ; shift mode switch, $00 = enabled, $80 = locked
; This location is used to determine whether moving the cursor past the ??xx column of
; a logical line will cause another physical line to be added to the logical line.
; A value of 0 enables the screen to scroll the following lines down in order to add
; that line; any nonzero value will disable the scroll.
; This flag is set to disable the scroll temporarily when there are characters waiting
; in the keyboard buffer, these may include cursor movement characters that would
; eliminate the need for a scroll.
LAB_0292 = $0292 ; screen scrolling flag, $00 = enabled
LAB_0293 = $0293 ; pseudo 6551 control register. the first character of
; the OPEN RS232 filename will be stored here
; bit function
; --- --------
; 7 2 stop bits/1 stop bit
; 65 word length
; --- -----------
; 00 8 bits
; 01 7 bits
; 10 6 bits
; 11 5 bits
; 4 unused
; 3210 baud rate
; ---- ---------
; 0000 user rate *
; 0001 50
; 0010 75
; 0011 110
; 0100 134.5
; 0101 150
; 0110 300
; 0111 600
; 1000 1200
; 1001 1800
; 1010 2400
; 1011 3600
; 1100 4800 *
; 1101 7200 *
; 1110 9600 *
; 1111 19200 * * = not implemented
LAB_0294 = $0294 ; pseudo 6551 command register. the second character of
; the OPEN RS232 filename will be stored here
; bit function
; --- --------
; 7-5 parity
; xx0 = disabled
; 001 = odd
; 011 = even
; 101 = mark
; 111 = space
; 4 duplex half/full
; 3 unused
; 2 unused
; 1 unused
; 0 handshake - X line/3 line
LAB_0295 = $0295 ; nonstandard bit timing low byte. the third character
; of the OPEN RS232 filename will be stored here
LAB_0296 = $0296 ; nonstandard bit timing high byte. the fourth character
; of the OPEN RS232 filename will be stored here
LAB_0297 = $0297 ; RS-232 status register
; bit function
; --- --------
; 7 break
; 6 no DSR detected
; 5 unused
; 4 no CTS detected
; 3 unused
; 2 Rx buffer overrun
; 1 framing error
; 0 parity error
LAB_0298 = $0298 ; number of bits to be sent/received
LAB_0299 = $0299 ; bit time low byte
LAB_029A = $029A ; bit time high byte
; Time Required to Send a Bit
;
; This location holds the prescaler value used by CIA #2 timers A and B.
; These timers cause an NMI interrupt to drive the RS-232 receive and transmit
; routines CLOCK/PRESCALER times per second each, where CLOCK is the system 02
; frequency of 1,022,730 Hz (985,250 if you are using the European PAL
; television standard rather than the American NTSC standard), and PRESCALER is
; the value stored at 56580-1 ($DD04-5) and 56582-3 ($DD06-7), in low-byte,
; high-byte order. You can use the following formula to figure the correct
; prescaler value for a particular RS-232 baud rate:
;
; PRESCALER=((CLOCK/BAUDRATE)/2)-100
;
; The American (NTSC standard) prescaler values for the standard RS-232 baud
; rates which the control register at 659 ($293) makes available are stored in
; a table at 65218 ($FEC2), starting with the two-byte value used for 50 baud.
; The European (PAL standard) version of that table is located at 58604 ($E4EC).
;
; Location Range: 667-670 ($29B-$29E)
; Byte Indices to the Beginning and End of Receive and Transmit Buffers
;
; The two 256-byte First In, First Out (FIFO) buffers for RS-232 data reception
; and transmission are dynamic wraparound buffers. This means that the starting
; point and the ending point of the buffer can change over time, and either
; point can be anywhere withing the buffer. If, for example, the starting point
; is at byte 100, the buffer will fill towards byte 255, at which point it will
; wrap around to byte 0 again. To maintain this system, the following four
; locations are used as indices to the starting and the ending point of each
; buffer.
LAB_029B = $029B ; index to Rx buffer end
LAB_029C = $029C ; index to Rx buffer start
LAB_029D = $029D ; index to Tx buffer start
LAB_029E = $029E ; index to Tx buffer end
LAB_029F = $029F ; saved IRQ low byte
LAB_02A0 = $02A0 ; saved IRQ high byte
; This location holds the active NMI interrupt flag byte from VIA 2 ICR, LAB_DD0D
LAB_02A1 = $02A1 ; RS-232 interrupt enable byte
; bit function
; --- --------
; 7 unused
; 6 unused
; 5 unused
; 4 1 = waiting for Rx edge
; 3 unused
; 2 unused
; 1 1 = Rx data timer
; 0 1 = Tx data timer
LAB_02A2 = $02A2 ; VIA 1 CRB shadow copy
LAB_02A3 = $02A3 ; VIA 1 ICR shadow copy
LAB_02A4 = $02A4 ; VIA 1 CRA shadow copy
LAB_02A5 = $02A5 ; temp Index to the next line for scrolling
LAB_02A6 = $02A6 ; PAL/NTSC flag
; $00 = NTSC
; $01 = PAL
; $02A7 to $02FF - unused
LAB_0300 = $0300 ; vector to the print BASIC error message routine
LAB_0302 = $0302 ; Vector to the main BASIC program Loop
LAB_0304 = $0304 ; Vector to the the ASCII text to keywords routine
LAB_0306 = $0306 ; Vector to the list BASIC program as ASCII routine
LAB_0308 = $0308 ; Vector to the execute next BASIC command routine
LAB_030A = $030A ; Vector to the get value from BASIC line routine
; Before every SYS command each of the registers is loaded with the value found in the
; corresponding storage address. Upon returning to BASIC with an RTS instruction, the
; new value of each register is stored in the appropriate storage address.
; This feature allows you to place the necessary values into the registers from BASIC
; before you SYS to a Kernal or BASIC ML routine. It also enables you to examine the
; resulting effect of the routine on the registers, and to preserve the condition of
; the registers on exit for subsequent SYS calls.
LAB_030C = $030C ; A for SYS command
LAB_030D = $030D ; X for SYS command
LAB_030E = $030E ; Y for SYS command
LAB_030F = $030F ; P for SYS command
LAB_0310 = $0310 ; JMP instruction for user function
LAB_0311 = $0311 ; user function vector low byte
LAB_0312 = $0312 ; user function vector high byte
LAB_0314 = $0314 ; IRQ vector low byte
LAB_0315 = $0315 ; IRQ vector high byte
LAB_0316 = $0316 ; BRK vector
LAB_0318 = $0318 ; NMI vector
LAB_031A = $031A ; kernal vector - open a logical file
LAB_031C = $031C ; kernal vector - close a specified logical file
LAB_031E = $031E ; kernal vector - open channel for input
LAB_0320 = $0320 ; kernal vector - open channel for output
LAB_0322 = $0322 ; kernal vector - close input and output channels
LAB_0324 = $0324 ; kernal vector - input character from channel
LAB_0326 = $0326 ; kernal vector - output character to channel
LAB_0328 = $0328 ; kernal vector - scan stop key
LAB_032A = $032A ; kernal vector - get character from keyboard queue
LAB_032C = $032C ; kernal vector - close all channels and files
LAB_0330 = $0330 ; kernal vector - load
LAB_0332 = $0332 ; kernal vector - save
LAB_033C = $033C ; cassette buffer
LAB_8000 = $8000 ; autostart ROM initial entry vector
LAB_8002 = $8002 ; autostart ROM break entry
LAB_8004 = $8004 ; autostart ROM identifier string start
LAB_D000 = $D000 ; vic ii chip base address
LAB_D011 = $D011 ; vertical fine scroll and control
LAB_D012 = $D012 ; raster compare register
LAB_D016 = $D016 ; horizontal fine scroll and control
LAB_D018 = $D018 ; memory control
LAB_D019 = $D019 ; vic interrupt flag register
LAB_D418 = $D418 ; volume and filter select
LAB_D800 = $D800 ; 1K colour RAM base address
; VIA 1
LAB_DC00 = $DC00 ; VIA 1 DRA, keyboard column drive
LAB_DC01 = $DC01 ; VIA 1 DRB, keyboard row port
; keyboard matrix layout
; keyboard matrix layout
; c7 c6 c5 c4 c3 c2 c1 c0
; +------------------------------------------------
; r7| [RUN] / , N V X [LSH] [DN]
; r6| Q [UP] @ O U T E [F5]
; r5| [CBM] = : K H F S [F3]
; r4| [SP] [RSH] . M B C Z [F1]
; r3| 2 [Home]- 0 8 6 4 [F7]
; r2| [CTL] ; L J G D A [RGT]
; r1| [LFT] * P I Y R W [RET]
; r0| 1 £ + 9 7 5 3 [DEL]
LAB_DC02 = $DC02 ; VIA 1 DDRA, keyboard column
LAB_DC03 = $DC03 ; VIA 1 DDRB, keyboard row
LAB_DC04 = $DC04 ; VIA 1 timer A low byte
LAB_DC05 = $DC05 ; VIA 1 timer A high byte
LAB_DC06 = $DC06 ; VIA 1 timer B low byte
LAB_DC07 = $DC07 ; VIA 1 timer B high byte
LAB_DC0D = $DC0D ; VIA 1 ICR
; bit function
; --- --------
; 7 interrupt
; 6 unused
; 5 unused
; 4 FLAG
; 3 shift register
; 2 TOD alarm
; 1 timer B
; 0 timer A
LAB_DC0E = $DC0E ; VIA 1 CRA
; bit function
; --- --------
; 7 TOD clock, 1 = 50Hz, 0 = 60Hz
; 6 serial port direction, 1 = out, 0 = in
; 5 timer A input, 1 = phase2, 0 = CNT in
; 4 1 = force load timer A
; 3 timer A mode, 1 = single shot, 0 = continuous
; 2 PB6 mode, 1 = toggle, 0 = single shot
; 1 1 = timer A to PB6
; 0 1 = start timer A
LAB_DC0F = $DC0F ; VIA 1 CRB
; bit function
; --- --------
; 7 TOD register select, 1 = clock, 0 = alarm
; 6-5 timer B mode
; 11 = timer A with CNT enable
; 10 = timer A
; 01 = CNT in
; 00 = phase 2
; 4 1 = force load timer B
; 3 timer B mode, 1 = single shot, 0 = continuous
; 2 PB7 mode, 1 = toggle, 0 = single shot
; 1 1 = timer B to PB7
; 0 1 = start timer B
; VIA 2
LAB_DD00 = $DD00 ; VIA 2 DRA, serial port and video address
; bit function
; --- --------
; 7 serial DATA in
; 6 serial CLK in
; 5 serial DATA out
; 4 serial CLK out
; 3 serial ATN out
; 2 RS232 Tx DATA
; 1 video address 15
; 0 video address 14
LAB_DD01 = $DD01 ; VIA 2 DRB, RS232 port
; bit function
; --- --------
; 7 RS232 DSR
; 6 RS232 CTS
; 5 unused
; 4 RS232 DCD
; 3 RS232 RI
; 2 RS232 DTR
; 1 RS232 RTS
; 0 RS232 Rx DATA
LAB_DD02 = $DD02 ; VIA 2 DDRA, serial port and video address
LAB_DD03 = $DD03 ; VIA 2 DDRB, RS232 port
LAB_DD04 = $DD04 ; VIA 2 timer A low byte
LAB_DD05 = $DD05 ; VIA 2 timer A high byte
LAB_DD06 = $DD06 ; VIA 2 timer B low byte
LAB_DD07 = $DD07 ; VIA 2 timer B high byte
LAB_DD0D = $DD0D ; VIA 2 ICR
; bit function
; --- --------
; 7 interrupt
; 6 unused
; 5 unused
; 4 FLAG
; 3 shift register
; 2 TOD alarm
; 1 timer B
; 0 timer A
LAB_DD0E = $DD0E ; VIA 2 CRA
; bit function
; --- --------
; 7 TOD clock, 1 = 50Hz, 0 = 60Hz
; 6 serial port direction, 1 = out, 0 = in
; 5 timer A input, 1 = phase2, 0 = CNT in
; 4 1 = force load timer A
; 3 timer A mode, 1 = single shot, 0 = continuous
; 2 PB6 mode, 1 = toggle, 0 = single shot
; 1 1 = timer A to PB6
; 0 1 = start timer A
LAB_DD0F = $DD0F ; VIA 2 CRB
; bit function
; --- --------
; 7 TOD register select, 1 = clock, 0 = alarm
; 6-5 timer B mode
; 11 = timer A with CNT enable
; 10 = timer A
; 01 = CNT in
; 00 = phase 2
; 4 1 = force load timer B
; 3 timer B mode, 1 = single shot, 0 = continuous
; 2 PB7 mode, 1 = toggle, 0 = single shot
; 1 1 = timer B to PB7
; 0 1 = start timer B
;************************************************************************************
;
; BASIC keyword token values. tokens not used in the source are included for
; completeness but commented out
; command tokens
;TK_END = $80 ; END token
TK_FOR = $81 ; FOR token
;TK_NEXT = $82 ; NEXT token
TK_DATA = $83 ; DATA token
;TK_INFL = $84 ; INPUT# token
;TK_INPUT = $85 ; INPUT token
;TK_DIM = $86 ; DIM token
;TK_READ = $87 ; READ token
;TK_LET = $88 ; LET token
TK_GOTO = $89 ; GOTO token
;TK_RUN = $8A ; RUN token
;TK_IF = $8B ; IF token
;TK_RESTORE = $8C ; RESTORE token
TK_GOSUB = $8D ; GOSUB token
;TK_RETURN = $8E ; RETURN token
TK_REM = $8F ; REM token
;TK_STOP = $90 ; STOP token
;TK_ON = $91 ; ON token
;TK_WAIT = $92 ; WAIT token
;TK_LOAD = $93 ; LOAD token
;TK_SAVE = $94 ; SAVE token
;TK_VERIFY = $95 ; VERIFY token
;TK_DEF = $96 ; DEF token
;TK_POKE = $97 ; POKE token
;TK_PRINFL = $98 ; PRINT# token
TK_PRINT = $99 ; PRINT token
;TK_CONT = $9A ; CONT token
;TK_LIST = $9B ; LIST token
;TK_CLR = $9C ; CLR token
;TK_CMD = $9D ; CMD token
;TK_SYS = $9E ; SYS token
;TK_OPEN = $9F ; OPEN token
;TK_CLOSE = $A0 ; CLOSE token
;TK_GET = $A1 ; GET token
;TK_NEW = $A2 ; NEW token
; secondary keyword tokens
TK_TAB = $A3 ; TAB( token
TK_TO = $A4 ; TO token
TK_FN = $A5 ; FN token
TK_SPC = $A6 ; SPC( token
TK_THEN = $A7 ; THEN token
TK_NOT = $A8 ; NOT token
TK_STEP = $A9 ; STEP token
; operator tokens
TK_PLUS = $AA ; + token
TK_MINUS = $AB ; - token
;TK_MUL = $AC ; * token
;TK_DIV = $AD ; / token
;TK_POWER = $AE ; ^ token
;TK_AND = $AF ; AND token
;TK_OR = $B0 ; OR token
TK_GT = $B1 ; > token
TK_EQUAL = $B2 ; = token
;TK_LT = $B3 ; < token
; function tokens
TK_SGN = $B4 ; SGN token
;TK_INT = $B5 ; INT token
;TK_ABS = $B6 ; ABS token
;TK_USR = $B7 ; USR token
;TK_FRE = $B8 ; FRE token
;TK_POS = $B9 ; POS token
;TK_SQR = $BA ; SQR token
;TK_RND = $BB ; RND token
;TK_LOG = $BC ; LOG token
;TK_EXP = $BD ; EXP token
;TK_COS = $BE ; COS token
;TK_SIN = $BF ; SIN token
;TK_TAN = $C0 ; TAN token
;TK_ATN = $C1 ; ATN token
;TK_PEEK = $C2 ; PEEK token
;TK_LEN = $C3 ; LEN token
;TK_STRS = $C4 ; STR$ token
;TK_VAL = $C5 ; VAL token
;TK_ASC = $C6 ; ASC token
;TK_CHRS = $C7 ; CHR$ token
;TK_LEFTS = $C8 ; LEFT$ token
;TK_RIGHTS = $C9 ; RIGHT$ token
;TK_MIDS = $CA ; MID$ token
TK_GO = $CB ; GO token
TK_PI = $FF ; PI token
;************************************************************************************
;
; start of the BASIC ROM
.ORG $A000
LAB_A000
.word LAB_E394 ; BASIC cold start entry point
LAB_A002
.word LAB_E37B ; BASIC warm start entry point
;LAB_A004
.byte "CBMBASIC" ; ROM name, unreferenced
;************************************************************************************
;
; action addresses for primary commands. these are called by pushing the address
; onto the stack and doing an RTS so the actual address -1 needs to be pushed
LAB_A00C
.word LAB_A831-1 ; perform END $80
.word LAB_A742-1 ; perform FOR $81
.word LAB_AD1E-1 ; perform NEXT $82
.word LAB_A8F8-1 ; perform DATA $83
.word LAB_ABA5-1 ; perform INPUT# $84
.word LAB_ABBF-1 ; perform INPUT $85
.word LAB_B081-1 ; perform DIM $86
.word LAB_AC06-1 ; perform READ $87
.word LAB_A9A5-1 ; perform LET $88
.word LAB_A8A0-1 ; perform GOTO $89
.word LAB_A871-1 ; perform RUN $8A
.word LAB_A928-1 ; perform IF $8B
.word LAB_A81D-1 ; perform RESTORE $8C
.word LAB_A883-1 ; perform GOSUB $8D
.word LAB_A8D2-1 ; perform RETURN $8E
.word LAB_A93B-1 ; perform REM $8F
.word LAB_A82F-1 ; perform STOP $90
.word LAB_A94B-1 ; perform ON $91
.word LAB_B82D-1 ; perform WAIT $92
.word LAB_E168-1 ; perform LOAD $93
.word LAB_E156-1 ; perform SAVE $94
.word LAB_E165-1 ; perform VERIFY $95
.word LAB_B3B3-1 ; perform DEF $96
.word LAB_B824-1 ; perform POKE $97
.word LAB_AA80-1 ; perform PRINT# $98
.word LAB_AAA0-1 ; perform PRINT $99
.word LAB_A857-1 ; perform CONT $9A
.word LAB_A69C-1 ; perform LIST $9B
.word LAB_A65E-1 ; perform CLR $9C
.word LAB_AA86-1 ; perform CMD $9D
.word LAB_E12A-1 ; perform SYS $9E
.word LAB_E1BE-1 ; perform OPEN $9F
.word LAB_E1C7-1 ; perform CLOSE $A0
.word LAB_AB7B-1 ; perform GET $A1
.word LAB_A642-1 ; perform NEW $A2
;************************************************************************************
;
; action addresses for functions
LAB_A052
.word LAB_BC39 ; perform SGN() $B4
.word LAB_BCCC ; perform INT() $B5
.word LAB_BC58 ; perform ABS() $B6
.word LAB_0310 ; perform USR() $B7
.word LAB_B37D ; perform FRE() $B8
.word LAB_B39E ; perform POS() $B9
.word LAB_BF71 ; perform SQR() $BA
.word LAB_E097 ; perform RND() $BB
.word LAB_B9EA ; perform LOG() $BC
.word LAB_BFED ; perform EXP() $BD
.word LAB_E264 ; perform COS() $BE
.word LAB_E26B ; perform SIN() $BF
.word LAB_E2B4 ; perform TAN() $C0
.word LAB_E30E ; perform ATN() $C1
.word LAB_B80D ; perform PEEK() $C2
.word LAB_B77C ; perform LEN() $C3
.word LAB_B465 ; perform STR$() $C4
.word LAB_B7AD ; perform VAL() $C5
.word LAB_B78B ; perform ASC() $C6
.word LAB_B6EC ; perform CHR$() $C7
.word LAB_B700 ; perform LEFT$() $C8
.word LAB_B72C ; perform RIGHT$() $C9
.word LAB_B737 ; perform MID$() $CA
;************************************************************************************
;
; precedence byte and action addresses for operators. like the primarry commands
; these are called by pushing the address onto the stack and doing an RTS, so again
; the actual address -1 needs to be pushed
LAB_A080
.byte $79
.word LAB_B86A-1 ; +
.byte $79
.word LAB_B853-1 ; -
.byte $7B
.word LAB_BA2B-1 ; *
.byte $7B
.word LAB_BB12-1 ; /
.byte $7F
.word LAB_BF7B-1 ; ^
.byte $50
.word LAB_AFE9-1 ; AND
.byte $46
.word LAB_AFE6-1 ; OR
.byte $7D
.word LAB_BFB4-1 ; >
.byte $5A
.word LAB_AED4-1 ; =
LAB_A09B
.byte $64
.word LAB_B016-1 ; <
;************************************************************************************
;
; BASIC keywords. each word has b7 set in it's last character as an end marker, even
; the one character keywords such as "<" or "="
; first are the primary command keywords, only these can start a statement
LAB_A09E
.byte "EN",'D'+$80 ; END $80 128
.byte "FO",'R'+$80 ; FOR $81 129
.byte "NEX",'T'+$80 ; NEXT $82 130
.byte "DAT",'A'+$80 ; DATA $83 131
.byte "INPUT",'#'+$80 ; INPUT# $84 132
.byte "INPU",'T'+$80 ; INPUT $85 133
.byte "DI",'M'+$80 ; DIM $86 134
.byte "REA",'D'+$80 ; READ $87 135
.byte "LE",'T'+$80 ; LET $88 136
.byte "GOT",'O'+$80 ; GOTO $89 137
.byte "RU",'N'+$80 ; RUN $8A 138
.byte "I",'F'+$80 ; IF $8B 139
.byte "RESTOR",'E'+$80 ; RESTORE $8C 140
.byte "GOSU",'B'+$80 ; GOSUB $8D 141
.byte "RETUR",'N'+$80 ; RETURN $8E 142
.byte "RE",'M'+$80 ; REM $8F 143
.byte "STO",'P'+$80 ; STOP $90 144
.byte "O",'N'+$80 ; ON $91 145
.byte "WAI",'T'+$80 ; WAIT $92 146
.byte "LOA",'D'+$80 ; LOAD $93 147
.byte "SAV",'E'+$80 ; SAVE $94 148
.byte "VERIF",'Y'+$80 ; VERIFY $95 149
.byte "DE",'F'+$80 ; DEF $96 150
.byte "POK",'E'+$80 ; POKE $97 151
.byte "PRINT",'#'+$80 ; PRINT# $98 152
.byte "PRIN",'T'+$80 ; PRINT $99 153
.byte "CON",'T'+$80 ; CONT $9A 154
.byte "LIS",'T'+$80 ; LIST $9B 155
.byte "CL",'R'+$80 ; CLR $9C 156
.byte "CM",'D'+$80 ; CMD $9D 157
.byte "SY",'S'+$80 ; SYS $9E 158
.byte "OPE",'N'+$80 ; OPEN $9F 159
.byte "CLOS",'E'+$80 ; CLOSE $A0 160
.byte "GE",'T'+$80 ; GET $A1 161
.byte "NE",'W'+$80 ; NEW $A2 162
; next are the secondary command keywords, these can not start a statement
;LAB_A129
.byte "TAB",'('+$80 ; TAB( $A3 163
.byte "T",'O'+$80 ; TO $A4 164
.byte "F",'N'+$80 ; FN $A5 165
.byte "SPC",'('+$80 ; SPC( $A6 166
.byte "THE",'N'+$80 ; THEN $A7 167
.byte "NO",'T'+$80 ; NOT $A8 168
.byte "STE",'P'+$80 ; STEP $A9 169
; next are the operators
.byte '+'+$80 ; + $AA 170
.byte '-'+$80 ; - $AB 171
.byte '*'+$80 ; * $AC 172
.byte '/'+$80 ; / $AD 173
.byte '^'+$80 ; ^ $AE 174
.byte "AN",'D'+$80 ; AND $AF 175
.byte "O",'R'+$80 ; OR $B0 176
.byte '>'+$80 ; > $B1 177
.byte '='+$80 ; = $B2 178
.byte '<'+$80 ; < $B3 179
; and finally the functions
.byte "SG",'N'+$80 ; SGN $B4 180
.byte "IN",'T'+$80 ; INT $B5 181
.byte "AB",'S'+$80 ; ABS $B6 182
.byte "US",'R'+$80 ; USR $B7 183
.byte "FR",'E'+$80 ; FRE $B8 184
.byte "PO",'S'+$80 ; POS $B9 185
.byte "SQ",'R'+$80 ; SQR $BA 186
.byte "RN",'D'+$80 ; RND $BB 187
.byte "LO",'G'+$80 ; LOG $BC 188
.byte "EX",'P'+$80 ; EXP $BD 189
.byte "CO",'S'+$80 ; COS $BE 190
.byte "SI",'N'+$80 ; SIN $BF 191
.byte "TA",'N'+$80 ; TAN $C0 192
.byte "AT",'N'+$80 ; ATN $C1 193
.byte "PEE",'K'+$80 ; PEEK $C2 194
.byte "LE",'N'+$80 ; LEN $C3 195
.byte "STR",'$'+$80 ; STR$ $C4 196
.byte "VA",'L'+$80 ; VAL $C5 197
.byte "AS",'C'+$80 ; ASC $C6 198
.byte "CHR",'$'+$80 ; CHR$ $C7 199
.byte "LEFT",'$'+$80 ; LEFT$ $C8 200
.byte "RIGHT",'$'+$80 ; RIGHT$ $C9 201
.byte "MID",'$'+$80 ; MID$ $CA 202
; lastly is GO, this is an add on so that GO TO, as well as GOTO, will work
.byte "G",'O'+$80 ; GO $CB 203
.byte $00 ; end marker
;************************************************************************************
;
; BASIC error messages
LAB_A19E
.byte "TOO MANY FILE",'S'+$80
LAB_A1AC
.byte "FILE OPE",'N'+$80
LAB_A1B5
.byte "FILE NOT OPE",'N'+$80
LAB_A1C2
.byte "FILE NOT FOUN",'D'+$80
LAB_A1D0
.byte "DEVICE NOT PRESEN",'T'+$80
LAB_A1E2
.byte "NOT INPUT FIL",'E'+$80
LAB_A1F0
.byte "NOT OUTPUT FIL",'E'+$80
LAB_A1FF
.byte "MISSING FILE NAM",'E'+$80
LAB_A210
.byte "ILLEGAL DEVICE NUMBE",'R'+$80
LAB_A225
.byte "NEXT WITHOUT FO",'R'+$80
LAB_A235
.byte "SYNTA",'X'+$80
LAB_A23B
.byte "RETURN WITHOUT GOSU",'B'+$80
LAB_A24F
.byte "OUT OF DAT",'A'+$80
LAB_A25A
.byte "ILLEGAL QUANTIT",'Y'+$80
LAB_A26A
.byte "OVERFLO",'W'+$80
LAB_A272
.byte "OUT OF MEMOR",'Y'+$80
LAB_A27F
.byte "UNDEF'D STATEMEN",'T'+$80
LAB_A290
.byte "BAD SUBSCRIP",'T'+$80
LAB_A29D
.byte "REDIM'D ARRA",'Y'+$80
LAB_A2AA
.byte "DIVISION BY ZER",'O'+$80
LAB_A2BA
.byte "ILLEGAL DIREC",'T'+$80
LAB_A2C8
.byte "TYPE MISMATC",'H'+$80
LAB_A2D5
.byte "STRING TOO LON",'G'+$80
LAB_A2E4
.byte "FILE DAT",'A'+$80
LAB_A2ED
.byte "FORMULA TOO COMPLE",'X'+$80
LAB_A300
.byte "CAN'T CONTINU",'E'+$80
LAB_A30E
.byte "UNDEF'D FUNCTIO",'N'+$80
LAB_A31E
.byte "VERIF",'Y'+$80
LAB_A324
.byte "LOA",'D'+$80
; error message pointer table
LAB_A328
.word LAB_A19E ; $01 TOO MANY FILES
.word LAB_A1AC ; $02 FILE OPEN
.word LAB_A1B5 ; $03 FILE NOT OPEN
.word LAB_A1C2 ; $04 FILE NOT FOUND
.word LAB_A1D0 ; $05 DEVICE NOT PRESENT
.word LAB_A1E2 ; $06 NOT INPUT FILE
.word LAB_A1F0 ; $07 NOT OUTPUT FILE
.word LAB_A1FF ; $08 MISSING FILE NAME
.word LAB_A210 ; $09 ILLEGAL DEVICE NUMBER
.word LAB_A225 ; $0A NEXT WITHOUT FOR
.word LAB_A235 ; $0B SYNTAX
.word LAB_A23B ; $0C RETURN WITHOUT GOSUB
.word LAB_A24F ; $0D OUT OF DATA
.word LAB_A25A ; $0E ILLEGAL QUANTITY
.word LAB_A26A ; $0F OVERFLOW
.word LAB_A272 ; $10 OUT OF MEMORY
.word LAB_A27F ; $11 UNDEF'D STATEMENT
.word LAB_A290 ; $12 BAD SUBSCRIPT
.word LAB_A29D ; $13 REDIM'D ARRAY
.word LAB_A2AA ; $14 DIVISION BY ZERO
.word LAB_A2BA ; $15 ILLEGAL DIRECT
.word LAB_A2C8 ; $16 TYPE MISMATCH
.word LAB_A2D5 ; $17 STRING TOO LONG
.word LAB_A2E4 ; $18 FILE DATA
.word LAB_A2ED ; $19 FORMULA TOO COMPLEX
.word LAB_A300 ; $1A CAN'T CONTINUE
.word LAB_A30E ; $1B UNDEF'D FUNCTION
.word LAB_A31E ; $1C VERIFY
.word LAB_A324 ; $1D LOAD
.word LAB_A383 ; $1E BREAK
;************************************************************************************
;
; BASIC messages
LAB_A364
.byte $0D,"OK",$0D,$00
LAB_A369
.byte " ERROR",$00
LAB_A371
.byte " IN ",$00
LAB_A376
.byte $0D,$0A,"READY.",$0D,$0A,$00
LAB_A381
.byte $0D,$0A
LAB_A383
.byte "BREAK",$00
;************************************************************************************
;
; spare byte, not referenced
;LAB_A389
.byte $A0 ; unused
;************************************************************************************
;
; search the stack for FOR or GOSUB activity
; return Zb=1 if FOR variable found
LAB_A38A
TSX ; copy stack pointer
INX ; +1 pass return address
INX ; +2 pass return address
INX ; +3 pass calling routine return address
INX ; +4 pass calling routine return address
LAB_A38F
LDA LAB_0100+1,X ; get the token byte from the stack
CMP #TK_FOR ; is it the FOR token
BNE LAB_A3B7 ; if not FOR token just exit
; it was the FOR token
LDA LAB_4A ; get FOR/NEXT variable pointer high byte
BNE LAB_A3A4 ; branch if not null
LDA LAB_0100+2,X ; get FOR variable pointer low byte
STA LAB_49 ; save FOR/NEXT variable pointer low byte
LDA LAB_0100+3,X ; get FOR variable pointer high byte
STA LAB_4A ; save FOR/NEXT variable pointer high byte
LAB_A3A4
CMP LAB_0100+3,X ; compare variable pointer with stacked variable pointer
; high byte
BNE LAB_A3B0 ; branch if no match
LDA LAB_49 ; get FOR/NEXT variable pointer low byte
CMP LAB_0100+2,X ; compare variable pointer with stacked variable pointer
; low byte
BEQ LAB_A3B7 ; exit if match found
LAB_A3B0
TXA ; copy index
CLC ; clear carry for add
ADC #$12 ; add FOR stack use size
TAX ; copy back to index
BNE LAB_A38F ; loop if not at start of stack
LAB_A3B7
RTS
;************************************************************************************
;
; open up a space in the memory, set the end of arrays
LAB_A3B8
JSR LAB_A408 ; check available memory, do out of memory error if no room
STA LAB_31 ; set end of arrays low byte
STY LAB_32 ; set end of arrays high byte
; open up a space in the memory, don't set the array end
LAB_A3BF
SEC ; set carry for subtract
LDA LAB_5A ; get block end low byte
SBC LAB_5F ; subtract block start low byte
STA LAB_22 ; save MOD(block length/$100) byte
TAY ; copy MOD(block length/$100) byte to Y
LDA LAB_5B ; get block end high byte
SBC LAB_60 ; subtract block start high byte
TAX ; copy block length high byte to X
INX ; +1 to allow for count=0 exit
TYA ; copy block length low byte to A
BEQ LAB_A3F3 ; branch if length low byte=0
; block is (X-1)*256+Y bytes, do the Y bytes first
LDA LAB_5A ; get block end low byte
SEC ; set carry for subtract
SBC LAB_22 ; subtract MOD(block length/$100) byte
STA LAB_5A ; save corrected old block end low byte
BCS LAB_A3DC ; branch if no underflow
DEC LAB_5B ; else decrement block end high byte
SEC ; set carry for subtract
LAB_A3DC
LDA LAB_58 ; get destination end low byte
SBC LAB_22 ; subtract MOD(block length/$100) byte
STA LAB_58 ; save modified new block end low byte
BCS LAB_A3EC ; branch if no underflow
DEC LAB_59 ; else decrement block end high byte
BCC LAB_A3EC ; branch always
LAB_A3E8
LDA (LAB_5A),Y ; get byte from source
STA (LAB_58),Y ; copy byte to destination
LAB_A3EC
DEY ; decrement index
BNE LAB_A3E8 ; loop until Y=0
; now do Y=0 indexed byte
LDA (LAB_5A),Y ; get byte from source
STA (LAB_58),Y ; save byte to destination
LAB_A3F3
DEC LAB_5B ; decrement source pointer high byte
DEC LAB_59 ; decrement destination pointer high byte
DEX ; decrement block count
BNE LAB_A3EC ; loop until count = $0
RTS
;************************************************************************************
;
; check room on stack for A bytes
; if stack too deep do out of memory error
LAB_A3FB
ASL ; *2
ADC #$3E ; need at least $3E bytes free
BCS LAB_A435 ; if overflow go do out of memory error then warm start
STA LAB_22 ; save result in temp byte
TSX ; copy stack
CPX LAB_22 ; compare new limit with stack
BCC LAB_A435 ; if stack < limit do out of memory error then warm start
RTS
;************************************************************************************
;
; check available memory, do out of memory error if no room
LAB_A408
CPY LAB_34 ; compare with bottom of string space high byte
BCC LAB_A434 ; if less then exit (is ok)
BNE LAB_A412 ; skip next test if greater (tested <)
; high byte was =, now do low byte
CMP LAB_33 ; compare with bottom of string space low byte
BCC LAB_A434 ; if less then exit (is ok)
; address is > string storage ptr (oops!)
LAB_A412
PHA ; push address low byte
LDX #$09 ; set index to save LAB_57 to LAB_60 inclusive
TYA ; copy address high byte (to push on stack)
; save misc numeric work area
LAB_A416
PHA ; push byte
LDA LAB_57,X ; get byte from LAB_57 to LAB_60
DEX ; decrement index
BPL LAB_A416 ; loop until all done
JSR LAB_B526 ; do garbage collection routine
; restore misc numeric work area
LDX #$F7 ; set index to restore bytes
LAB_A421
PLA ; pop byte
STA LAB_60+1,X ; save byte to LAB_57 to LAB_60
INX ; increment index
BMI LAB_A421 ; loop while -ve
PLA ; pop address high byte
TAY ; copy back to Y
PLA ; pop address low byte
CPY LAB_34 ; compare with bottom of string space high byte
BCC LAB_A434 ; if less then exit (is ok)
BNE LAB_A435 ; if greater do out of memory error then warm start
; high byte was =, now do low byte
CMP LAB_33 ; compare with bottom of string space low byte
BCS LAB_A435 ; if >= do out of memory error then warm start
; ok exit, carry clear
LAB_A434
RTS
;************************************************************************************
;
; do out of memory error then warm start
LAB_A435
LDX #$10 ; error code $10, out of memory error
; do error #X then warm start
LAB_A437
JMP (LAB_0300) ; do error message
;************************************************************************************
;
; do error #X then warm start, the error message vector is initialised to point here
LAB_A43A
TXA ; copy error number
ASL ; *2
TAX ; copy to index
LDA LAB_A328-2,X ; get error message pointer low byte
STA LAB_22 ; save it
LDA LAB_A328-1,X ; get error message pointer high byte
STA LAB_23 ; save it
JSR LAB_FFCC ; close input and output channels
LDA #$00 ; clear A
STA LAB_13 ; clear current I/O channel, flag default
JSR LAB_AAD7 ; print CR/LF
JSR LAB_AB45 ; print "?"
LDY #$00 ; clear index
LAB_A456
LDA (LAB_22),Y ; get byte from message
PHA ; save status
AND #$7F ; mask 0xxx xxxx, clear b7
JSR LAB_AB47 ; output character
INY ; increment index
PLA ; restore status
BPL LAB_A456 ; loop if character was not end marker
JSR LAB_A67A ; flush BASIC stack and clear continue pointer
LDA #<LAB_A369 ; set " ERROR" pointer low byte
LDY #>LAB_A369 ; set " ERROR" pointer high byte
;************************************************************************************
;
; print string and do warm start, break entry
LAB_A469
JSR LAB_AB1E ; print null terminated string
LDY LAB_3A ; get current line number high byte
INY ; increment it
BEQ LAB_A474 ; branch if was in immediate mode
JSR LAB_BDC2 ; do " IN " line number message
;************************************************************************************
;
; do warm start
LAB_A474
LDA #<LAB_A376 ; set "READY." pointer low byte
LDY #>LAB_A376 ; set "READY." pointer high byte
JSR LAB_AB1E ; print null terminated string
LDA #$80 ; set for control messages only
JSR LAB_FF90 ; control kernal messages
LAB_A480
JMP (LAB_0302) ; do BASIC warm start
;************************************************************************************
;
; BASIC warm start, the warm start vector is initialised to point here
LAB_A483
JSR LAB_A560 ; call for BASIC input
STX LAB_7A ; save BASIC execute pointer low byte
STY LAB_7B ; save BASIC execute pointer high byte
JSR LAB_0073 ; increment and scan memory
TAX ; copy byte to set flags
BEQ LAB_A480 ; loop if no input
; got to interpret the input line now ....
LDX #$FF ; current line high byte to -1, indicates immediate mode
STX LAB_3A ; set current line number high byte
BCC LAB_A49C ; if numeric character go handle new BASIC line
; no line number .. immediate mode
JSR LAB_A579 ; crunch keywords into BASIC tokens
JMP LAB_A7E1 ; go scan and interpret code
;************************************************************************************
;
; handle new BASIC line
LAB_A49C
JSR LAB_A96B ; get fixed-point number into temporary integer
JSR LAB_A579 ; crunch keywords into BASIC tokens
STY LAB_0B ; save index pointer to end of crunched line
JSR LAB_A613 ; search BASIC for temporary integer line number
BCC LAB_A4ED ; if not found skip the line delete
; line # already exists so delete it
LDY #$01 ; set index to next line pointer high byte
LDA (LAB_5F),Y ; get next line pointer high byte
STA LAB_23 ; save it
LDA LAB_2D ; get start of variables low byte
STA LAB_22 ; save it
LDA LAB_60 ; get found line pointer high byte
STA LAB_25 ; save it
LDA LAB_5F ; get found line pointer low byte
DEY ; decrement index
SBC (LAB_5F),Y ; subtract next line pointer low byte
CLC ; clear carry for add
ADC LAB_2D ; add start of variables low byte
STA LAB_2D ; set start of variables low byte
STA LAB_24 ; save destination pointer low byte
LDA LAB_2E ; get start of variables high byte
ADC #$FF ; -1 + carry
STA LAB_2E ; set start of variables high byte
SBC LAB_60 ; subtract found line pointer high byte
TAX ; copy to block count
SEC ; set carry for subtract
LDA LAB_5F ; get found line pointer low byte
SBC LAB_2D ; subtract start of variables low byte
TAY ; copy to bytes in first block count
BCS LAB_A4D7 ; branch if no underflow
INX ; increment block count, correct for = 0 loop exit
DEC LAB_25 ; decrement destination high byte
LAB_A4D7
CLC ; clear carry for add
ADC LAB_22 ; add source pointer low byte
BCC LAB_A4DF ; branch if no overflow
DEC LAB_23 ; else decrement source pointer high byte
CLC ; clear carry
; close up memory to delete old line
LAB_A4DF
LDA (LAB_22),Y ; get byte from source
STA (LAB_24),Y ; copy to destination
INY ; increment index
BNE LAB_A4DF ; while <> 0 do this block
INC LAB_23 ; increment source pointer high byte
INC LAB_25 ; increment destination pointer high byte
DEX ; decrement block count
BNE LAB_A4DF ; loop until all done
; got new line in buffer and no existing same #
LAB_A4ED
JSR LAB_A659 ; reset execution to start, clear variables, flush stack
; and return
JSR LAB_A533 ; rebuild BASIC line chaining
LDA LAB_0200 ; get first byte from buffer
BEQ LAB_A480 ; if no line go do BASIC warm start
; else insert line into memory
CLC ; clear carry for add
LDA LAB_2D ; get start of variables low byte
STA LAB_5A ; save as source end pointer low byte
ADC LAB_0B ; add index pointer to end of crunched line
STA LAB_58 ; save as destination end pointer low byte
LDY LAB_2E ; get start of variables high byte
STY LAB_5B ; save as source end pointer high byte
BCC LAB_A508 ; branch if no carry to high byte
INY ; else increment high byte
LAB_A508
STY LAB_59 ; save as destination end pointer high byte
JSR LAB_A3B8 ; open up space in memory
; most of what remains to do is copy the crunched line into the space opened up in memory,
; however, before the crunched line comes the next line pointer and the line number. the
; line number is retrieved from the temporary integer and stored in memory, this
; overwrites the bottom two bytes on the stack. next the line is copied and the next line
; pointer is filled with whatever was in two bytes above the line number in the stack.
; this is ok because the line pointer gets fixed in the line chain re-build.
LDA LAB_14 ; get line number low byte
LDY LAB_15 ; get line number high byte
STA LAB_01FE ; save line number low byte before crunched line
STY LAB_01FF ; save line number high byte before crunched line
LDA LAB_31 ; get end of arrays low byte
LDY LAB_32 ; get end of arrays high byte
STA LAB_2D ; set start of variables low byte
STY LAB_2E ; set start of variables high byte
LDY LAB_0B ; get index to end of crunched line
DEY ; -1
LAB_A522
LDA LAB_01FC,Y ; get byte from crunched line
STA (LAB_5F),Y ; save byte to memory
DEY ; decrement index
BPL LAB_A522 ; loop while more to do
; reset execution, clear variables, flush stack, rebuild BASIC chain and do warm start
LAB_A52A
JSR LAB_A659 ; reset execution to start, clear variables and flush stack
JSR LAB_A533 ; rebuild BASIC line chaining
JMP LAB_A480 ; go do BASIC warm start
;************************************************************************************
;
; rebuild BASIC line chaining
LAB_A533
LDA LAB_2B ; get start of memory low byte
LDY LAB_2C ; get start of memory high byte
STA LAB_22 ; set line start pointer low byte
STY LAB_23 ; set line start pointer high byte
CLC ; clear carry for add
LAB_A53C
LDY #$01 ; set index to pointer to next line high byte
LDA (LAB_22),Y ; get pointer to next line high byte
BEQ LAB_A55F ; exit if null, [EOT]
LDY #$04 ; point to first code byte of line
; there is always 1 byte + [EOL] as null entries are deleted
LAB_A544
INY ; next code byte
LDA (LAB_22),Y ; get byte
BNE LAB_A544 ; loop if not [EOL]
INY ; point to byte past [EOL], start of next line
TYA ; copy it
ADC LAB_22 ; add line start pointer low byte
TAX ; copy to X
LDY #$00 ; clear index, point to this line's next line pointer
STA (LAB_22),Y ; set next line pointer low byte
LDA LAB_23 ; get line start pointer high byte
ADC #$00 ; add any overflow
INY ; increment index to high byte
STA (LAB_22),Y ; set next line pointer high byte
STX LAB_22 ; set line start pointer low byte
STA LAB_23 ; set line start pointer high byte
BCC LAB_A53C ; go do next line, branch always
LAB_A55F
RTS
; call for BASIC input
LAB_A560
LDX #$00 ; set channel $00, keyboard
LAB_A562
JSR LAB_E112 ; input character from channel with error check
CMP #$0D ; compare with [CR]
BEQ LAB_A576 ; if [CR] set XY to LAB_200 - 1, print [CR] and exit
; character was not [CR]
STA LAB_0200,X ; save character to buffer
INX ; increment buffer index
CPX #$59 ; compare with max+1
BCC LAB_A562 ; branch if < max+1
LDX #$17 ; error $17, string too long error
JMP LAB_A437 ; do error #X then warm start
LAB_A576
JMP LAB_AACA ; set XY to LAB_200 - 1 and print [CR]
;************************************************************************************
;
; crunch BASIC tokens vector
LAB_A579
JMP (LAB_0304) ; do crunch BASIC tokens
;************************************************************************************
;
; crunch BASIC tokens, the crunch BASIC tokens vector is initialised to point here
LAB_A57C
LDX LAB_7A ; get BASIC execute pointer low byte
LDY #$04 ; set save index
STY LAB_0F ; clear open quote/DATA flag
LAB_A582
LDA LAB_0200,X ; get a byte from the input buffer
BPL LAB_A58E ; if b7 clear go do crunching
CMP #TK_PI ; compare with the token for PI, this toke is input
; directly from the keyboard as the PI character
BEQ LAB_A5C9 ; if PI save byte then continue crunching
; this is the bit of code that stops you being able to enter
; some keywords as just single shifted characters. If this
; dropped through you would be able to enter GOTO as just
; [SHIFT]G
INX ; increment read index
BNE LAB_A582 ; loop if more to do, branch always
LAB_A58E
CMP #' ' ; compare with [SPACE]
BEQ LAB_A5C9 ; if [SPACE] save byte then continue crunching
STA LAB_08 ; save buffer byte as search character
CMP #$22 ; compare with quote character
BEQ LAB_A5EE ; if quote go copy quoted string
BIT LAB_0F ; get open quote/DATA token flag
BVS LAB_A5C9 ; branch if b6 of Oquote set, was DATA
; go save byte then continue crunching
CMP #'?' ; compare with "?" character
BNE LAB_A5A4 ; if not "?" continue crunching
LDA #TK_PRINT ; else the keyword token is $99, PRINT
BNE LAB_A5C9 ; go save byte then continue crunching, branch always
LAB_A5A4
CMP #'0' ; compare with "0"
BCC LAB_A5AC ; branch if <, continue crunching
CMP #'<' ; compare with "<"
BCC LAB_A5C9 ; if <, 0123456789:; go save byte then continue crunching
; gets here with next character not numeric, ";" or ":"
LAB_A5AC
STY LAB_71 ; copy save index
LDY #$00 ; clear table pointer
STY LAB_0B ; clear word index
DEY ; adjust for pre increment loop
STX LAB_7A ; save BASIC execute pointer low byte, buffer index
DEX ; adjust for pre increment loop
LAB_A5B6
INY ; next table byte
INX ; next buffer byte
LAB_A5B8
LDA LAB_0200,X ; get byte from input buffer
SEC ; set carry for subtract
SBC LAB_A09E,Y ; subtract table byte
BEQ LAB_A5B6 ; go compare next if match
CMP #$80 ; was it end marker match ?
BNE LAB_A5F5 ; branch if not, not found keyword
; actually this works even if the input buffer byte is the
; end marker, i.e. a shifted character. As you can't enter
; any keywords as a single shifted character, see above,
; you can enter keywords in shorthand by shifting any
; character after the first. so RETURN can be entered as
; R[SHIFT]E, RE[SHIFT]T, RET[SHIFT]U or RETU[SHIFT]R.
; RETUR[SHIFT]N however will not work because the [SHIFT]N
; will match the RETURN end marker so the routine will try
; to match the next character.
; else found keyword
ORA LAB_0B ; OR with word index, +$80 in A makes token
LAB_A5C7
LDY LAB_71 ; restore save index
; save byte then continue crunching
LAB_A5C9
INX ; increment buffer read index
INY ; increment save index
STA LAB_0200-5,Y ; save byte to output
LDA LAB_0200-5,Y ; get byte from output, set flags
BEQ LAB_A609 ; branch if was null [EOL]
; A holds the token here
SEC ; set carry for subtract
SBC #':' ; subtract ":"
BEQ LAB_A5DC ; branch if it was (is now $00)
; A now holds token-':'
CMP #TK_DATA-':' ; compare with the token for DATA-':'
BNE LAB_A5DE ; if not DATA go try REM
; token was : or DATA
LAB_A5DC
STA LAB_0F ; save the token-$3A
LAB_A5DE
SEC ; set carry for subtract
SBC #TK_REM-':' ; subtract the token for REM-':'
BNE LAB_A582 ; if wasn't REM crunch next bit of line
STA LAB_08 ; else was REM so set search for [EOL]
; loop for "..." etc.
LAB_A5E5
LDA LAB_0200,X ; get byte from input buffer
BEQ LAB_A5C9 ; if null [EOL] save byte then continue crunching
CMP LAB_08 ; compare with stored character
BEQ LAB_A5C9 ; if match save byte then continue crunching
LAB_A5EE
INY ; increment save index
STA LAB_0200-5,Y ; save byte to output
INX ; increment buffer index
BNE LAB_A5E5 ; loop while <> 0, should never reach 0
; not found keyword this go
LAB_A5F5
LDX LAB_7A ; restore BASIC execute pointer low byte
INC LAB_0B ; increment word index (next word)
; now find end of this word in the table
LAB_A5F9
INY ; increment table index
LDA LAB_A09E-1,Y ; get table byte
BPL LAB_A5F9 ; loop if not end of word yet
LDA LAB_A09E,Y ; get byte from keyword table
BNE LAB_A5B8 ; go test next word if not zero byte, end of table
; reached end of table with no match
LDA LAB_0200,X ; restore byte from input buffer
BPL LAB_A5C7 ; branch always, all unmatched bytes in the buffer are
; $00 to $7F, go save byte in output and continue crunching
; reached [EOL]
LAB_A609
STA LAB_01FD,Y ; save [EOL]
DEC LAB_7B ; decrement BASIC execute pointer high byte
LDA #$FF ; point to start of buffer-1
STA LAB_7A ; set BASIC execute pointer low byte
RTS
;************************************************************************************
;
; search BASIC for temporary integer line number
LAB_A613
LDA LAB_2B ; get start of memory low byte
LDX LAB_2C ; get start of memory high byte
;************************************************************************************
;
; search Basic for temp integer line number from AX
; returns carry set if found
LAB_A617
LDY #$01 ; set index to next line pointer high byte
STA LAB_5F ; save low byte as current
STX LAB_60 ; save high byte as current
LDA (LAB_5F),Y ; get next line pointer high byte from address
BEQ LAB_A640 ; pointer was zero so done, exit
INY ; increment index ...
INY ; ... to line # high byte
LDA LAB_15 ; get temporary integer high byte
CMP (LAB_5F),Y ; compare with line # high byte
BCC LAB_A641 ; exit if temp < this line, target line passed
BEQ LAB_A62E ; go check low byte if =
DEY ; else decrement index
BNE LAB_A637 ; branch always
LAB_A62E
LDA LAB_14 ; get temporary integer low byte
DEY ; decrement index to line # low byte
CMP (LAB_5F),Y ; compare with line # low byte
BCC LAB_A641 ; exit if temp < this line, target line passed
BEQ LAB_A641 ; exit if temp = (found line#)
; not quite there yet
LAB_A637
DEY ; decrement index to next line pointer high byte
LDA (LAB_5F),Y ; get next line pointer high byte
TAX ; copy to X
DEY ; decrement index to next line pointer low byte
LDA (LAB_5F),Y ; get next line pointer low byte
BCS LAB_A617 ; go search for line # in temporary integer
; from AX, carry always set
LAB_A640
CLC ; clear found flag
LAB_A641
RTS
;************************************************************************************
;
; perform NEW
LAB_A642
BNE LAB_A641 ; exit if following byte to allow syntax error
LAB_A644
LDA #$00 ; clear A
TAY ; clear index
STA (LAB_2B),Y ; clear pointer to next line low byte
INY ; increment index
STA (LAB_2B),Y ; clear pointer to next line high byte, erase program
LDA LAB_2B ; get start of memory low byte
CLC ; clear carry for add
ADC #$02 ; add null program length
STA LAB_2D ; set start of variables low byte
LDA LAB_2C ; get start of memory high byte
ADC #$00 ; add carry
STA LAB_2E ; set start of variables high byte
;************************************************************************************
;
; reset execute pointer and do CLR
LAB_A659
JSR LAB_A68E ; set BASIC execute pointer to start of memory - 1
LDA #$00 ; set Zb for CLR entry
;************************************************************************************
;
; perform CLR
LAB_A65E
BNE LAB_A68D ; exit if following byte to allow syntax error
LAB_A660
JSR LAB_FFE7 ; close all channels and files
LAB_A663
LDA LAB_37 ; get end of memory low byte
LDY LAB_38 ; get end of memory high byte
STA LAB_33 ; set bottom of string space low byte, clear strings
STY LAB_34 ; set bottom of string space high byte
LDA LAB_2D ; get start of variables low byte
LDY LAB_2E ; get start of variables high byte
STA LAB_2F ; set end of variables low byte, clear variables
STY LAB_30 ; set end of variables high byte
STA LAB_31 ; set end of arrays low byte, clear arrays
STY LAB_32 ; set end of arrays high byte
;************************************************************************************
;
; do RESTORE and clear stack
LAB_A677
JSR LAB_A81D ; perform RESTORE
;************************************************************************************
;
; flush BASIC stack and clear the continue pointer
LAB_A67A
LDX #LAB_19 ; get the descriptor stack start
STX LAB_16 ; set the descriptor stack pointer
PLA ; pull the return address low byte
TAY ; copy it
PLA ; pull the return address high byte
LDX #$FA ; set the cleared stack pointer
TXS ; set the stack
PHA ; push the return address high byte
TYA ; restore the return address low byte
PHA ; push the return address low byte
LDA #$00 ; clear A
STA LAB_3E ; clear the continue pointer high byte
STA LAB_10 ; clear the subscript/FNX flag
LAB_A68D
RTS
;************************************************************************************
;
; set BASIC execute pointer to start of memory - 1
LAB_A68E
CLC ; clear carry for add
LDA LAB_2B ; get start of memory low byte
ADC #$FF ; add -1 low byte
STA LAB_7A ; set BASIC execute pointer low byte
LDA LAB_2C ; get start of memory high byte
ADC #$FF ; add -1 high byte
STA LAB_7B ; save BASIC execute pointer high byte
RTS
;************************************************************************************
;
; perform LIST
LAB_A69C
BCC LAB_A6A4 ; branch if next character not token (LIST n...)
BEQ LAB_A6A4 ; branch if next character [NULL] (LIST)
CMP #TK_MINUS ; compare with token for -
BNE LAB_A68D ; exit if not - (LIST -m)
; LIST [[n][-m]]
; this bit sets the n , if present, as the start and end
LAB_A6A4
JSR LAB_A96B ; get fixed-point number into temporary integer
JSR LAB_A613 ; search BASIC for temporary integer line number
JSR LAB_0079 ; scan memory
BEQ LAB_A6BB ; branch if no more chrs
; this bit checks the - is present
CMP #TK_MINUS ; compare with token for -
BNE LAB_A641 ; return if not "-" (will be SN error)
; LIST [n]-m
; the - was there so set m as the end value
JSR LAB_0073 ; increment and scan memory
JSR LAB_A96B ; get fixed-point number into temporary integer
BNE LAB_A641 ; exit if not ok
LAB_A6BB
PLA ; dump return address low byte, exit via warm start
PLA ; dump return address high byte
LDA LAB_14 ; get temporary integer low byte
ORA LAB_15 ; OR temporary integer high byte
BNE LAB_A6C9 ; branch if start set
LDA #$FF ; set for -1
STA LAB_14 ; set temporary integer low byte
STA LAB_15 ; set temporary integer high byte
LAB_A6C9
LDY #$01 ; set index for line
STY LAB_0F ; clear open quote flag
LDA (LAB_5F),Y ; get next line pointer high byte
BEQ LAB_A714 ; if null all done so exit
JSR LAB_A82C ; do CRTL-C check vector
JSR LAB_AAD7 ; print CR/LF
INY ; increment index for line
LDA (LAB_5F),Y ; get line number low byte
TAX ; copy to X
INY ; increment index
LDA (LAB_5F),Y ; get line number high byte
CMP LAB_15 ; compare with temporary integer high byte
BNE LAB_A6E6 ; branch if no high byte match
CPX LAB_14 ; compare with temporary integer low byte
BEQ LAB_A6E8 ; branch if = last line to do, < will pass next branch
LAB_A6E6 ; else ...
BCS LAB_A714 ; if greater all done so exit
LAB_A6E8
STY LAB_49 ; save index for line
JSR LAB_BDCD ; print XA as unsigned integer
LDA #' ' ; space is the next character
LAB_A6EF
LDY LAB_49 ; get index for line
AND #$7F ; mask top out bit of character
LAB_A6F3
JSR LAB_AB47 ; go print the character
CMP #$22 ; was it " character
BNE LAB_A700 ; if not skip the quote handle
; we are either entering or leaving a pair of quotes
LDA LAB_0F ; get open quote flag
EOR #$FF ; toggle it
STA LAB_0F ; save it back
LAB_A700
INY ; increment index
BEQ LAB_A714 ; line too long so just bail out and do a warm start
LDA (LAB_5F),Y ; get next byte
BNE LAB_A717 ; if not [EOL] (go print character)
; was [EOL]
TAY ; else clear index
LDA (LAB_5F),Y ; get next line pointer low byte
TAX ; copy to X
INY ; increment index
LDA (LAB_5F),Y ; get next line pointer high byte
STX LAB_5F ; set pointer to line low byte
STA LAB_60 ; set pointer to line high byte
BNE LAB_A6C9 ; go do next line if not [EOT]
; else ...
LAB_A714
JMP LAB_E386 ; do warm start
LAB_A717
JMP (LAB_0306) ; do uncrunch BASIC tokens
;************************************************************************************
;
; uncrunch BASIC tokens, the uncrunch BASIC tokens vector is initialised to point here
LAB_A71A
BPL LAB_A6F3 ; just go print it if not token byte
; else was token byte so uncrunch it
CMP #TK_PI ; compare with the token for PI. in this case the token
; is the same as the PI character so it just needs printing
BEQ LAB_A6F3 ; just print it if so
BIT LAB_0F ; test the open quote flag
BMI LAB_A6F3 ; just go print character if open quote set
SEC ; else set carry for subtract
SBC #$7F ; reduce token range to 1 to whatever
TAX ; copy token # to X
STY LAB_49 ; save index for line
LDY #$FF ; start from -1, adjust for pre increment
LAB_A72C
DEX ; decrement token #
BEQ LAB_A737 ; if now found go do printing
LAB_A72F
INY ; else increment index
LDA LAB_A09E,Y ; get byte from keyword table
BPL LAB_A72F ; loop until keyword end marker
BMI LAB_A72C ; go test if this is required keyword, branch always
; found keyword, it's the next one
LAB_A737
INY ; increment keyword table index
LDA LAB_A09E,Y ; get byte from table
BMI LAB_A6EF ; go restore index, mask byte and print if
; byte was end marker
JSR LAB_AB47 ; else go print the character
BNE LAB_A737 ; go get next character, branch always
;************************************************************************************
;
; perform FOR
LAB_A742
LDA #$80 ; set FNX
STA LAB_10 ; set subscript/FNX flag
JSR LAB_A9A5 ; perform LET
JSR LAB_A38A ; search the stack for FOR or GOSUB activity
BNE LAB_A753 ; branch if FOR, this variable, not found
; FOR, this variable, was found so first we dump the old one
TXA ; copy index
ADC #$0F ; add FOR structure size-2
TAX ; copy to index
TXS ; set stack (dump FOR structure (-2 bytes))
LAB_A753
PLA ; pull return address
PLA ; pull return address
LDA #$09 ; we need 18d bytes !
JSR LAB_A3FB ; check room on stack for 2*A bytes
JSR LAB_A906 ; scan for next BASIC statement ([:] or [EOL])
CLC ; clear carry for add
TYA ; copy index to A
ADC LAB_7A ; add BASIC execute pointer low byte
PHA ; push onto stack
LDA LAB_7B ; get BASIC execute pointer high byte
ADC #$00 ; add carry
PHA ; push onto stack
LDA LAB_3A ; get current line number high byte
PHA ; push onto stack
LDA LAB_39 ; get current line number low byte
PHA ; push onto stack
LDA #TK_TO ; set "TO" token
JSR LAB_AEFF ; scan for CHR$(A), else do syntax error then warm start
JSR LAB_AD8D ; check if source is numeric, else do type mismatch
JSR LAB_AD8A ; evaluate expression and check is numeric, else do
; type mismatch
LDA LAB_66 ; get FAC1 sign (b7)
ORA #$7F ; set all non sign bits
AND LAB_62 ; and FAC1 mantissa 1
STA LAB_62 ; save FAC1 mantissa 1
LDA #<LAB_A78B ; set return address low byte
LDY #>LAB_A78B ; set return address high byte
STA LAB_22 ; save return address low byte
STY LAB_23 ; save return address high byte
JMP LAB_AE43 ; round FAC1 and put on stack, returns to next instruction
LAB_A78B
LDA #<LAB_B9BC ; set 1 pointer low address, default step size
LDY #>LAB_B9BC ; set 1 pointer high address
JSR LAB_BBA2 ; unpack memory (AY) into FAC1
JSR LAB_0079 ; scan memory
CMP #TK_STEP ; compare with STEP token
BNE LAB_A79F ; if not "STEP" continue
; was step so ....
JSR LAB_0073 ; increment and scan memory
JSR LAB_AD8A ; evaluate expression and check is numeric, else do
; type mismatch
LAB_A79F
JSR LAB_BC2B ; get FAC1 sign, return A = $FF -ve, A = $01 +ve
JSR LAB_AE38 ; push sign, round FAC1 and put on stack
LDA LAB_4A ; get FOR/NEXT variable pointer high byte
PHA ; push on stack
LDA LAB_49 ; get FOR/NEXT variable pointer low byte
PHA ; push on stack
LDA #TK_FOR ; get FOR token
PHA ; push on stack
;************************************************************************************
;
; interpreter inner loop
LAB_A7AE
JSR LAB_A82C ; do CRTL-C check vector
LDA LAB_7A ; get the BASIC execute pointer low byte
LDY LAB_7B ; get the BASIC execute pointer high byte
CPY #$02 ; compare the high byte with $02xx
NOP ; unused byte ##
BEQ LAB_A7BE ; if immediate mode skip the continue pointer save
STA LAB_3D ; save the continue pointer low byte
STY LAB_3E ; save the continue pointer high byte
LAB_A7BE
LDY #$00 ; clear the index
LDA (LAB_7A),Y ; get a BASIC byte
BNE LAB_A807 ; if not [EOL] go test for ":"
LDY #$02 ; else set the index
LDA (LAB_7A),Y ; get next line pointer high byte
CLC ; clear carry for no "BREAK" message
BNE LAB_A7CE ; branch if not end of program
JMP LAB_A84B ; else go to immediate mode,was immediate or [EOT] marker
LAB_A7CE
INY ; increment index
LDA (LAB_7A),Y ; get line number low byte
STA LAB_39 ; save current line number low byte
INY ; increment index
LDA (LAB_7A),Y ; get line # high byte
STA LAB_3A ; save current line number high byte
TYA ; A now = 4
ADC LAB_7A ; add BASIC execute pointer low byte, now points to code
STA LAB_7A ; save BASIC execute pointer low byte
BCC LAB_A7E1 ; branch if no overflow
INC LAB_7B ; else increment BASIC execute pointer high byte
LAB_A7E1
JMP (LAB_0308) ; do start new BASIC code
;************************************************************************************
;
; start new BASIC code, the start new BASIC code vector is initialised to point here
LAB_A7E4
JSR LAB_0073 ; increment and scan memory
JSR LAB_A7ED ; go interpret BASIC code from BASIC execute pointer
JMP LAB_A7AE ; loop
;************************************************************************************
;
; go interpret BASIC code from BASIC execute pointer
LAB_A7ED
BEQ LAB_A82B ; if the first byte is null just exit
LAB_A7EF
SBC #$80 ; normalise the token
BCC LAB_A804 ; if wasn't token go do LET
CMP #TK_TAB-$80 ; compare with token for TAB(-$80
BCS LAB_A80E ; branch if >= TAB(
ASL ; *2 bytes per vector
TAY ; copy to index
LDA LAB_A00C+1,Y ; get vector high byte
PHA ; push on stack
LDA LAB_A00C,Y ; get vector low byte
PHA ; push on stack
JMP LAB_0073 ; increment and scan memory and return. the return in
; this case calls the command code, the return from
; that will eventually return to the interpreter inner
; loop above
LAB_A804
JMP LAB_A9A5 ; perform LET
; was not [EOL]
LAB_A807
CMP #':' ; comapre with ":"
BEQ LAB_A7E1 ; if ":" go execute new code
; else ...
LAB_A80B
JMP LAB_AF08 ; do syntax error then warm start
; token was >= TAB(
LAB_A80E
CMP #TK_GO-$80 ; compare with the token for GO
BNE LAB_A80B ; if not "GO" do syntax error then warm start
; else was "GO"
JSR LAB_0073 ; increment and scan memory
LDA #TK_TO ; set "TO" token
JSR LAB_AEFF ; scan for CHR$(A), else do syntax error then warm start
JMP LAB_A8A0 ; perform GOTO
;************************************************************************************
;
; perform RESTORE
LAB_A81D
SEC ; set carry for subtract
LDA LAB_2B ; get start of memory low byte
SBC #$01 ; -1
LDY LAB_2C ; get start of memory high byte
BCS LAB_A827 ; branch if no rollunder
DEY ; else decrement high byte
LAB_A827
STA LAB_41 ; set DATA pointer low byte
STY LAB_42 ; set DATA pointer high byte
LAB_A82B
RTS
;************************************************************************************
;
; do CRTL-C check vector
LAB_A82C
JSR LAB_FFE1 ; scan stop key
;************************************************************************************
;
; perform STOP
LAB_A82F
BCS LAB_A832 ; if carry set do BREAK instead of just END
;************************************************************************************
;
; perform END
LAB_A831
CLC ; clear carry
LAB_A832
BNE LAB_A870 ; return if wasn't CTRL-C
LDA LAB_7A ; get BASIC execute pointer low byte
LDY LAB_7B ; get BASIC execute pointer high byte
LDX LAB_3A ; get current line number high byte
INX ; increment it
BEQ LAB_A849 ; branch if was immediate mode
STA LAB_3D ; save continue pointer low byte
STY LAB_3E ; save continue pointer high byte
LDA LAB_39 ; get current line number low byte
LDY LAB_3A ; get current line number high byte
STA LAB_3B ; save break line number low byte
STY LAB_3C ; save break line number high byte
LAB_A849
PLA ; dump return address low byte
PLA ; dump return address high byte
LAB_A84B
LDA #<LAB_A381 ; set [CR][LF]"BREAK" pointer low byte
LDY #>LAB_A381 ; set [CR][LF]"BREAK" pointer high byte
BCC LAB_A854 ; if was program end skip the print string
JMP LAB_A469 ; print string and do warm start
LAB_A854
JMP LAB_E386 ; do warm start
;************************************************************************************
;
; perform CONT
LAB_A857
BNE LAB_A870 ; exit if following byte to allow syntax error
LDX #$1A ; error code $1A, can't continue error
LDY LAB_3E ; get continue pointer high byte
BNE LAB_A862 ; go do continue if we can
JMP LAB_A437 ; else do error #X then warm start
; we can continue so ...
LAB_A862
LDA LAB_3D ; get continue pointer low byte
STA LAB_7A ; save BASIC execute pointer low byte
STY LAB_7B ; save BASIC execute pointer high byte
LDA LAB_3B ; get break line low byte
LDY LAB_3C ; get break line high byte
STA LAB_39 ; set current line number low byte
STY LAB_3A ; set current line number high byte
LAB_A870
RTS
;************************************************************************************
;
; perform RUN
LAB_A871
PHP ; save status
LDA #$00 ; no control or kernal messages
JSR LAB_FF90 ; control kernal messages
PLP ; restore status
BNE LAB_A87D ; branch if RUN n
JMP LAB_A659 ; reset execution to start, clear variables, flush stack
; and return
LAB_A87D
JSR LAB_A660 ; go do "CLEAR"
JMP LAB_A897 ; get n and do GOTO n
;************************************************************************************
;
; perform GOSUB
LAB_A883
LDA #$03 ; need 6 bytes for GOSUB
JSR LAB_A3FB ; check room on stack for 2*A bytes
LDA LAB_7B ; get BASIC execute pointer high byte
PHA ; save it
LDA LAB_7A ; get BASIC execute pointer low byte
PHA ; save it
LDA LAB_3A ; get current line number high byte
PHA ; save it
LDA LAB_39 ; get current line number low byte
PHA ; save it
LDA #TK_GOSUB ; token for GOSUB
PHA ; save it
LAB_A897
JSR LAB_0079 ; scan memory
JSR LAB_A8A0 ; perform GOTO
JMP LAB_A7AE ; go do interpreter inner loop
;************************************************************************************
;
; perform GOTO
LAB_A8A0
JSR LAB_A96B ; get fixed-point number into temporary integer
JSR LAB_A909 ; scan for next BASIC line
SEC ; set carry for subtract
LDA LAB_39 ; get current line number low byte
SBC LAB_14 ; subtract temporary integer low byte
LDA LAB_3A ; get current line number high byte
SBC LAB_15 ; subtract temporary integer high byte
BCS LAB_A8BC ; if current line number >= temporary integer, go search
; from the start of memory
TYA ; else copy line index to A
SEC ; set carry (+1)
ADC LAB_7A ; add BASIC execute pointer low byte
LDX LAB_7B ; get BASIC execute pointer high byte
BCC LAB_A8C0 ; branch if no overflow to high byte
INX ; increment high byte
BCS LAB_A8C0 ; branch always (can never be carry)
;************************************************************************************
;
; search for line number in temporary integer from start of memory pointer
LAB_A8BC
LDA LAB_2B ; get start of memory low byte
LDX LAB_2C ; get start of memory high byte
;************************************************************************************
;
; search for line # in temporary integer from (AX)
LAB_A8C0
JSR LAB_A617 ; search Basic for temp integer line number from AX
BCC LAB_A8E3 ; if carry clear go do unsdefined statement error
; carry all ready set for subtract
LDA LAB_5F ; get pointer low byte
SBC #$01 ; -1
STA LAB_7A ; save BASIC execute pointer low byte
LDA LAB_60 ; get pointer high byte
SBC #$00 ; subtract carry
STA LAB_7B ; save BASIC execute pointer high byte
LAB_A8D1
RTS
;************************************************************************************
;
; perform RETURN
LAB_A8D2
BNE LAB_A8D1 ; exit if following token to allow syntax error
LDA #$FF ; set byte so no match possible
STA LAB_4A ; save FOR/NEXT variable pointer high byte
JSR LAB_A38A ; search the stack for FOR or GOSUB activity,
; get token off stack
TXS ; correct the stack
CMP #TK_GOSUB ; compare with GOSUB token
BEQ LAB_A8EB ; if matching GOSUB go continue RETURN
LDX #$0C ; else error code $04, return without gosub error
.byte $2C ; makes next line BIT LAB_11A2
LAB_A8E3
LDX #$11 ; error code $11, undefined statement error
JMP LAB_A437 ; do error #X then warm start
LAB_A8E8
JMP LAB_AF08 ; do syntax error then warm start
; was matching GOSUB token
LAB_A8EB
PLA ; dump token byte
PLA ; pull return line low byte
STA LAB_39 ; save current line number low byte
PLA ; pull return line high byte
STA LAB_3A ; save current line number high byte
PLA ; pull return address low byte
STA LAB_7A ; save BASIC execute pointer low byte
PLA ; pull return address high byte
STA LAB_7B ; save BASIC execute pointer high byte
;************************************************************************************
;
; perform DATA
LAB_A8F8
JSR LAB_A906 ; scan for next BASIC statement ([:] or [EOL])
;************************************************************************************
;
; add Y to the BASIC execute pointer
LAB_A8FB
TYA ; copy index to A
CLC ; clear carry for add
ADC LAB_7A ; add BASIC execute pointer low byte
STA LAB_7A ; save BASIC execute pointer low byte
BCC LAB_A905 ; skip increment if no carry
INC LAB_7B ; else increment BASIC execute pointer high byte
LAB_A905
RTS
;************************************************************************************
;
; scan for next BASIC statement ([:] or [EOL])
; returns Y as index to [:] or [EOL]
LAB_A906
LDX #':' ; set look for character = ":"
.byte $2C ; makes next line BIT LAB_00A2
;************************************************************************************
;
; scan for next BASIC line
; returns Y as index to [EOL]
LAB_A909
LDX #$00 ; set alternate search character = [EOL]
STX LAB_07 ; store alternate search character
LDY #$00 ; set search character = [EOL]
STY LAB_08 ; save the search character
LAB_A911
LDA LAB_08 ; get search character
LDX LAB_07 ; get alternate search character
STA LAB_07 ; make search character = alternate search character
STX LAB_08 ; make alternate search character = search character
LAB_A919
LDA (LAB_7A),Y ; get BASIC byte
BEQ LAB_A905 ; exit if null [EOL]
CMP LAB_08 ; compare with search character
BEQ LAB_A905 ; exit if found
INY ; else increment index
CMP #$22 ; compare current character with open quote
BNE LAB_A919 ; if found go swap search character for alternate search
; character
BEQ LAB_A911 ; loop for next character, branch always
;************************************************************************************
;
; perform IF
LAB_A928
JSR LAB_AD9E ; evaluate expression
JSR LAB_0079 ; scan memory
CMP #TK_GOTO ; compare with "GOTO" token
BEQ LAB_A937 ; if it was the token for GOTO go do IF ... GOTO
; wasn't IF ... GOTO so must be IF ... THEN
LDA #TK_THEN ; set "THEN" token
JSR LAB_AEFF ; scan for CHR$(A), else do syntax error then warm start
LAB_A937
LDA LAB_61 ; get FAC1 exponent
BNE LAB_A940 ; if result was non zero continue execution
; else REM rest of line
;************************************************************************************
;
; perform REM
LAB_A93B
JSR LAB_A909 ; scan for next BASIC line
BEQ LAB_A8FB ; add Y to the BASIC execute pointer and return, branch
; always
; result was non zero so do rest of line
LAB_A940
JSR LAB_0079 ; scan memory
BCS LAB_A948 ; branch if not numeric character, is variable or keyword
JMP LAB_A8A0 ; else perform GOTO n
; is variable or keyword
LAB_A948
JMP LAB_A7ED ; interpret BASIC code from BASIC execute pointer
;************************************************************************************
;
; perform ON
LAB_A94B
JSR LAB_B79E ; get byte parameter
PHA ; push next character
CMP #TK_GOSUB ; compare with GOSUB token
BEQ LAB_A957 ; if GOSUB go see if it should be executed
LAB_A953
CMP #TK_GOTO ; compare with GOTO token
BNE LAB_A8E8 ; if not GOTO do syntax error then warm start
; next character was GOTO or GOSUB, see if it should be executed
LAB_A957
DEC LAB_65 ; decrement the byte value
BNE LAB_A95F ; if not zero go see if another line number exists
PLA ; pull keyword token
JMP LAB_A7EF ; go execute it
LAB_A95F
JSR LAB_0073 ; increment and scan memory
JSR LAB_A96B ; get fixed-point number into temporary integer
; skip this n
CMP #',' ; compare next character with ","
BEQ LAB_A957 ; loop if ","
PLA ; else pull keyword token, ran out of options
LAB_A96A
RTS
;************************************************************************************
;
; get fixed-point number into temporary integer
LAB_A96B
LDX #$00 ; clear X
STX LAB_14 ; clear temporary integer low byte
STX LAB_15 ; clear temporary integer high byte
LAB_A971
BCS LAB_A96A ; return if carry set, end of scan, character was not 0-9
SBC #'0'-1 ; subtract $30, $2F+carry, from byte
STA LAB_07 ; store #
LDA LAB_15 ; get temporary integer high byte
STA LAB_22 ; save it for now
CMP #$19 ; compare with $19
BCS LAB_A953 ; branch if >= this makes the maximum line number 63999
; because the next bit does $1900 * $0A = $FA00 = 64000
; decimal. the branch target is really the SYNTAX error
; at LAB_A8E8 but that is too far so an intermediate
; compare and branch to that location is used. the problem
; with this is that line number that gives a partial result
; from $8900 to $89FF, 35072x to 35327x, will pass the new
; target compare and will try to execute the remainder of
; the ON n GOTO/GOSUB. a solution to this is to copy the
; byte in A before the branch to X and then branch to
; LAB_A955 skipping the second compare
LDA LAB_14 ; get temporary integer low byte
ASL ; *2 low byte
ROL LAB_22 ; *2 high byte
ASL ; *2 low byte
ROL LAB_22 ; *2 high byte (*4)
ADC LAB_14 ; + low byte (*5)
STA LAB_14 ; save it
LDA LAB_22 ; get high byte temp
ADC LAB_15 ; + high byte (*5)
STA LAB_15 ; save it
ASL LAB_14 ; *2 low byte (*10d)
ROL LAB_15 ; *2 high byte (*10d)
LDA LAB_14 ; get low byte
ADC LAB_07 ; add #
STA LAB_14 ; save low byte
BCC LAB_A99F ; branch if no overflow to high byte
INC LAB_15 ; else increment high byte
LAB_A99F
JSR LAB_0073 ; increment and scan memory
JMP LAB_A971 ; loop for next character
;************************************************************************************
;
; perform LET
LAB_A9A5
JSR LAB_B08B ; get variable address
STA LAB_49 ; save variable address low byte
STY LAB_4A ; save variable address high byte
LDA #TK_EQUAL ; $B2 is "=" token
JSR LAB_AEFF ; scan for CHR$(A), else do syntax error then warm start
LDA LAB_0E ; get data type flag, $80 = integer, $00 = float
PHA ; push data type flag
LDA LAB_0D ; get data type flag, $FF = string, $00 = numeric
PHA ; push data type flag
JSR LAB_AD9E ; evaluate expression
PLA ; pop data type flag
ROL ; string bit into carry
JSR LAB_AD90 ; do type match check
BNE LAB_A9D9 ; branch if string
PLA ; pop integer/float data type flag
; assign value to numeric variable
LAB_A9C2
BPL LAB_A9D6 ; branch if float
; expression is numeric integer
JSR LAB_BC1B ; round FAC1
JSR LAB_B1BF ; evaluate integer expression, no sign check
LDY #$00 ; clear index
LDA LAB_64 ; get FAC1 mantissa 3
STA (LAB_49),Y ; save as integer variable low byte
INY ; increment index
LDA LAB_65 ; get FAC1 mantissa 4
STA (LAB_49),Y ; save as integer variable high byte
RTS
LAB_A9D6
JMP LAB_BBD0 ; pack FAC1 into variable pointer and return
; assign value to numeric variable
LAB_A9D9
PLA ; dump integer/float data type flag
LAB_A9DA
LDY LAB_4A ; get variable pointer high byte
CPY #>LAB_BF13 ; was it TI$ pointer
BNE LAB_AA2C ; branch if not
; else it's TI$ = <expr$>
JSR LAB_B6A6 ; pop string off descriptor stack, or from top of string
; space returns with A = length, X = pointer low byte,
; Y = pointer high byte
CMP #$06 ; compare length with 6
BNE LAB_AA24 ; if length not 6 do illegal quantity error then warm start
LDY #$00 ; clear index
STY LAB_61 ; clear FAC1 exponent
STY LAB_66 ; clear FAC1 sign (b7)
LAB_A9ED
STY LAB_71 ; save index
JSR LAB_AA1D ; check and evaluate numeric digit
JSR LAB_BAE2 ; multiply FAC1 by 10
INC LAB_71 ; increment index
LDY LAB_71 ; restore index
JSR LAB_AA1D ; check and evaluate numeric digit
JSR LAB_BC0C ; round and copy FAC1 to FAC2
TAX ; copy FAC1 exponent
BEQ LAB_AA07 ; branch if FAC1 zero
INX ; increment index, * 2
TXA ; copy back to A
JSR LAB_BAED ; FAC1 = (FAC1 + (FAC2 * 2)) * 2 = FAC1 * 6
LAB_AA07
LDY LAB_71 ; get index
INY ; increment index
CPY #$06 ; compare index with 6
BNE LAB_A9ED ; loop if not 6
JSR LAB_BAE2 ; multiply FAC1 by 10
JSR LAB_BC9B ; convert FAC1 floating to fixed
LDX LAB_64 ; get FAC1 mantissa 3
LDY LAB_63 ; get FAC1 mantissa 2
LDA LAB_65 ; get FAC1 mantissa 4
JMP LAB_FFDB ; set real time clock and return
;************************************************************************************
;
; check and evaluate numeric digit
LAB_AA1D
LDA (LAB_22),Y ; get byte from string
JSR LAB_80 ; clear Cb if numeric. this call should be to LAB_84
; as the code from LAB_80 first comapres the byte with
; [SPACE] and does a BASIC increment and get if it is
BCC LAB_AA27 ; branch if numeric
LAB_AA24
JMP LAB_B248 ; do illegal quantity error then warm start
LAB_AA27
SBC #'0'-1 ; subtract $2F + carry to convert ASCII to binary
JMP LAB_BD7E ; evaluate new ASCII digit and return
;************************************************************************************
;
; assign value to numeric variable, but not TI$
LAB_AA2C
LDY #$02 ; index to string pointer high byte
LDA (LAB_64),Y ; get string pointer high byte
CMP LAB_34 ; compare with bottom of string space high byte
BCC LAB_AA4B ; branch if string pointer high byte is less than bottom
; of string space high byte
BNE LAB_AA3D ; branch if string pointer high byte is greater than
; bottom of string space high byte
; else high bytes were equal
DEY ; decrement index to string pointer low byte
LDA (LAB_64),Y ; get string pointer low byte
CMP LAB_33 ; compare with bottom of string space low byte
BCC LAB_AA4B ; branch if string pointer low byte is less than bottom
; of string space low byte
LAB_AA3D
LDY LAB_65 ; get descriptor pointer high byte
CPY LAB_2E ; compare with start of variables high byte
BCC LAB_AA4B ; branch if less, is on string stack
BNE LAB_AA52 ; if greater make space and copy string
; else high bytes were equal
LDA LAB_64 ; get descriptor pointer low byte
CMP LAB_2D ; compare with start of variables low byte
BCS LAB_AA52 ; if greater or equal make space and copy string
LAB_AA4B
LDA LAB_64 ; get descriptor pointer low byte
LDY LAB_65 ; get descriptor pointer high byte
JMP LAB_AA68 ; go copy descriptor to variable
LAB_AA52
LDY #$00 ; clear index
LDA (LAB_64),Y ; get string length
JSR LAB_B475 ; copy descriptor pointer and make string space A bytes long
LDA LAB_50 ; copy old descriptor pointer low byte
LDY LAB_51 ; copy old descriptor pointer high byte
STA LAB_6F ; save old descriptor pointer low byte
STY LAB_70 ; save old descriptor pointer high byte
JSR LAB_B67A ; copy string from descriptor to utility pointer
LDA #<LAB_61 ; get descriptor pointer low byte
LDY #>LAB_61 ; get descriptor pointer high byte
LAB_AA68
STA LAB_50 ; save descriptor pointer low byte
STY LAB_51 ; save descriptor pointer high byte
JSR LAB_B6DB ; clean descriptor stack, YA = pointer
LDY #$00 ; clear index
LDA (LAB_50),Y ; get string length from new descriptor
STA (LAB_49),Y ; copy string length to variable
INY ; increment index
LDA (LAB_50),Y ; get string pointer low byte from new descriptor
STA (LAB_49),Y ; copy string pointer low byte to variable
INY ; increment index
LDA (LAB_50),Y ; get string pointer high byte from new descriptor
STA (LAB_49),Y ; copy string pointer high byte to variable
RTS
;************************************************************************************
;
; perform PRINT#
LAB_AA80
JSR LAB_AA86 ; perform CMD
JMP LAB_ABB5 ; close input and output channels and return
;************************************************************************************
;
; perform CMD
LAB_AA86
JSR LAB_B79E ; get byte parameter
BEQ LAB_AA90 ; branch if following byte is ":" or [EOT]
LDA #',' ; set ","
JSR LAB_AEFF ; scan for CHR$(A), else do syntax error then warm start
LAB_AA90
PHP ; save status
STX LAB_13 ; set current I/O channel
JSR LAB_E118 ; open channel for output with error check
PLP ; restore status
JMP LAB_AAA0 ; perform PRINT
LAB_AA9A
JSR LAB_AB21 ; print string from utility pointer
LAB_AA9D
JSR LAB_0079 ; scan memory
;************************************************************************************
;
; perform PRINT
LAB_AAA0
BEQ LAB_AAD7 ; if nothing following just print CR/LF
LAB_AAA2
BEQ LAB_AAE7 ; exit if nothing following, end of PRINT branch
CMP #TK_TAB ; compare with token for TAB(
BEQ LAB_AAF8 ; if TAB( go handle it
CMP #TK_SPC ; compare with token for SPC(
CLC ; flag SPC(
BEQ LAB_AAF8 ; if SPC( go handle it
CMP #',' ; compare with ","
BEQ LAB_AAE8 ; if "," go skip to the next TAB position
CMP #';' ; compare with ";"
BEQ LAB_AB13 ; if ";" go continue the print loop
JSR LAB_AD9E ; evaluate expression
BIT LAB_0D ; test data type flag, $FF = string, $00 = numeric
BMI LAB_AA9A ; if string go print string, scan memory and continue PRINT
JSR LAB_BDDD ; convert FAC1 to ASCII string result in (AY)
JSR LAB_B487 ; print " terminated string to utility pointer
JSR LAB_AB21 ; print string from utility pointer
JSR LAB_AB3B ; print [SPACE] or [CURSOR RIGHT]
BNE LAB_AA9D ; go scan memory and continue PRINT, branch always
;************************************************************************************
;
; set XY to LAB_0200 - 1 and print [CR]
LAB_AACA
LDA #$00 ; clear A
STA LAB_0200,X ; clear first byte of input buffer
LDX #<LAB_01FF ; LAB_0200 - 1 low byte
LDY #>LAB_01FF ; LAB_0200 - 1 high byte
LDA LAB_13 ; get current I/O channel
BNE LAB_AAE7 ; exit if not default channel
;************************************************************************************
;
; print CR/LF
LAB_AAD7
LDA #$0D ; set [CR]
JSR LAB_AB47 ; print the character
BIT LAB_13 ; test current I/O channel
BPL LAB_AAE5 ; if ?? toggle A, EOR #$FF and return
LDA #$0A ; set [LF]
JSR LAB_AB47 ; print the character
; toggle A
LAB_AAE5
EOR #$FF ; invert A
LAB_AAE7
RTS
; was ","
LAB_AAE8
SEC ; set Cb for read cursor position
JSR LAB_FFF0 ; read/set X,Y cursor position
TYA ; copy cursor Y
SEC ; set carry for subtract
LAB_AAEE
SBC #$0A ; subtract one TAB length
BCS LAB_AAEE ; loop if result was +ve
EOR #$FF ; complement it
ADC #$01 ; +1, twos complement
BNE LAB_AB0E ; always print A spaces, result is never $00
LAB_AAF8
PHP ; save TAB( or SPC( status
SEC ; set Cb for read cursor position
JSR LAB_FFF0 ; read/set X,Y cursor position
STY LAB_09 ; save current cursor position
JSR LAB_B79B ; scan and get byte parameter
CMP #')' ; compare with ")"
BNE LAB_AB5F ; if not ")" do syntax error
PLP ; restore TAB( or SPC( status
BCC LAB_AB0F ; branch if was SPC(
; else was TAB(
TXA ; copy TAB() byte to A
SBC LAB_09 ; subtract current cursor position
BCC LAB_AB13 ; go loop for next if already past requited position
LAB_AB0E
TAX ; copy [SPACE] count to X
LAB_AB0F
INX ; increment count
LAB_AB10
DEX ; decrement count
BNE LAB_AB19 ; branch if count was not zero
; was ";" or [SPACES] printed
LAB_AB13
JSR LAB_0073 ; increment and scan memory
JMP LAB_AAA2 ; continue print loop
LAB_AB19
JSR LAB_AB3B ; print [SPACE] or [CURSOR RIGHT]
BNE LAB_AB10 ; loop, branch always
;************************************************************************************
;
; print null terminated string
LAB_AB1E
JSR LAB_B487 ; print " terminated string to utility pointer
;************************************************************************************
;
; print string from utility pointer
LAB_AB21
JSR LAB_B6A6 ; pop string off descriptor stack, or from top of string
; space returns with A = length, X = pointer low byte,
; Y = pointer high byte
TAX ; copy length
LDY #$00 ; clear index
INX ; increment length, for pre decrement loop
LAB_AB28
DEX ; decrement length
BEQ LAB_AAE7 ; exit if done
LDA (LAB_22),Y ; get byte from string
JSR LAB_AB47 ; print the character
INY ; increment index
CMP #$0D ; compare byte with [CR]
BNE LAB_AB28 ; loop if not [CR]
JSR LAB_AAE5 ; toggle A, EOR #$FF. what is the point of this ??
JMP LAB_AB28 ; loop
;************************************************************************************
;
; print [SPACE] or [CURSOR RIGHT]
LAB_AB3B
LDA LAB_13 ; get current I/O channel
BEQ LAB_AB42 ; if default channel go output [CURSOR RIGHT]
LDA #' ' ; else output [SPACE]
.byte $2C ; makes next line BIT LAB_1DA9
LAB_AB42
LDA #$1D ; set [CURSOR RIGHT]
.byte $2C ; makes next line BIT LAB_3FA9
;************************************************************************************
;
; print "?"
LAB_AB45
LDA #'?' ; set "?"
;************************************************************************************
;
; print character
LAB_AB47
JSR LAB_E10C ; output character to channel with error check
AND #$FF ; set the flags on A
RTS
;************************************************************************************
;
; bad input routine
LAB_AB4D
LDA LAB_11 ; get INPUT mode flag, $00 = INPUT, $40 = GET, $98 = READ
BEQ LAB_AB62 ; branch if INPUT
BMI LAB_AB57 ; branch if READ
; else was GET
LDY #$FF ; set current line high byte to -1, indicate immediate mode
BNE LAB_AB5B ; branch always
LAB_AB57
LDA LAB_3F ; get current DATA line number low byte
LDY LAB_40 ; get current DATA line number high byte
LAB_AB5B
STA LAB_39 ; set current line number low byte
STY LAB_3A ; set current line number high byte
LAB_AB5F
JMP LAB_AF08 ; do syntax error then warm start
; was INPUT
LAB_AB62
LDA LAB_13 ; get current I/O channel
BEQ LAB_AB6B ; branch if default channel
LDX #$18 ; else error $18, file data error
JMP LAB_A437 ; do error #X then warm start
LAB_AB6B
LDA #<LAB_AD0C ; set "?REDO FROM START" pointer low byte
LDY #>LAB_AD0C ; set "?REDO FROM START" pointer high byte
JSR LAB_AB1E ; print null terminated string
LDA LAB_3D ; get continue pointer low byte
LDY LAB_3E ; get continue pointer high byte
STA LAB_7A ; save BASIC execute pointer low byte
STY LAB_7B ; save BASIC execute pointer high byte
RTS
;************************************************************************************
;
; perform GET
LAB_AB7B
JSR LAB_B3A6 ; check not Direct, back here if ok
CMP #'#' ; compare with "#"
BNE LAB_AB92 ; branch if not GET#
JSR LAB_0073 ; increment and scan memory
JSR LAB_B79E ; get byte parameter
LDA #',' ; set ","
JSR LAB_AEFF ; scan for CHR$(A), else do syntax error then warm start
STX LAB_13 ; set current I/O channel
JSR LAB_E11E ; open channel for input with error check
LAB_AB92
LDX #<LAB_0201 ; set pointer low byte
LDY #>LAB_0201 ; set pointer high byte
LDA #$00 ; clear A
STA LAB_0201 ; ensure null terminator
LDA #$40 ; input mode = GET
JSR LAB_AC0F ; perform the GET part of READ
LDX LAB_13 ; get current I/O channel
BNE LAB_ABB7 ; if not default channel go do channel close and return
RTS
;************************************************************************************
;
; perform INPUT#
LAB_ABA5
JSR LAB_B79E ; get byte parameter
LDA #',' ; set ","
JSR LAB_AEFF ; scan for CHR$(A), else do syntax error then warm start
STX LAB_13 ; set current I/O channel
JSR LAB_E11E ; open channel for input with error check
JSR LAB_ABCE ; perform INPUT with no prompt string
;************************************************************************************
;
; close input and output channels
LAB_ABB5
LDA LAB_13 ; get current I/O channel
LAB_ABB7
JSR LAB_FFCC ; close input and output channels
LDX #$00 ; clear X
STX LAB_13 ; clear current I/O channel, flag default
RTS
;************************************************************************************
;
; perform INPUT
LAB_ABBF
CMP #$22 ; compare next byte with open quote
BNE LAB_ABCE ; if no prompt string just do INPUT
JSR LAB_AEBD ; print "..." string
LDA #';' ; load A with ";"
JSR LAB_AEFF ; scan for CHR$(A), else do syntax error then warm start
JSR LAB_AB21 ; print string from utility pointer
; done with prompt, now get data
LAB_ABCE
JSR LAB_B3A6 ; check not Direct, back here if ok
LDA #',' ; set ","
STA LAB_01FF ; save to start of buffer - 1
LAB_ABD6
JSR LAB_ABF9 ; print "? " and get BASIC input
LDA LAB_13 ; get current I/O channel
BEQ LAB_ABEA ; branch if default I/O channel
JSR LAB_FFB7 ; read I/O status word
AND #$02 ; mask no DSR/timeout
BEQ LAB_ABEA ; branch if not error
JSR LAB_ABB5 ; close input and output channels
JMP LAB_A8F8 ; perform DATA
LAB_ABEA
LDA LAB_0200 ; get first byte in input buffer
BNE LAB_AC0D ; branch if not null
; else ..
LDA LAB_13 ; get current I/O channel
BNE LAB_ABD6 ; if not default channel go get BASIC input
JSR LAB_A906 ; scan for next BASIC statement ([:] or [EOL])
JMP LAB_A8FB ; add Y to the BASIC execute pointer and return
;************************************************************************************
;
; print "? " and get BASIC input
LAB_ABF9
LDA LAB_13 ; get current I/O channel
BNE LAB_AC03 ; skip "?" prompt if not default channel
JSR LAB_AB45 ; print "?"
JSR LAB_AB3B ; print [SPACE] or [CURSOR RIGHT]
LAB_AC03
JMP LAB_A560 ; call for BASIC input and return
;************************************************************************************
;
; perform READ
LAB_AC06
LDX LAB_41 ; get DATA pointer low byte
LDY LAB_42 ; get DATA pointer high byte
LDA #$98 ; set input mode = READ
.byte $2C ; makes next line BIT LAB_00A9
LAB_AC0D
LDA #$00 ; set input mode = INPUT
;************************************************************************************
;
; perform GET
LAB_AC0F
STA LAB_11 ; set input mode flag, $00 = INPUT, $40 = GET, $98 = READ
STX LAB_43 ; save READ pointer low byte
STY LAB_44 ; save READ pointer high byte
; READ, GET or INPUT next variable from list
LAB_AC15
JSR LAB_B08B ; get variable address
STA LAB_49 ; save address low byte
STY LAB_4A ; save address high byte
LDA LAB_7A ; get BASIC execute pointer low byte
LDY LAB_7B ; get BASIC execute pointer high byte
STA LAB_4B ; save BASIC execute pointer low byte
STY LAB_4C ; save BASIC execute pointer high byte
LDX LAB_43 ; get READ pointer low byte
LDY LAB_44 ; get READ pointer high byte
STX LAB_7A ; save as BASIC execute pointer low byte
STY LAB_7B ; save as BASIC execute pointer high byte
JSR LAB_0079 ; scan memory
BNE LAB_AC51 ; branch if not null
; pointer was to null entry
BIT LAB_11 ; test input mode flag, $00 = INPUT, $40 = GET, $98 = READ
BVC LAB_AC41 ; branch if not GET
; else was GET
JSR LAB_E124 ; get character from input device with error check
STA LAB_0200 ; save to buffer
LDX #<LAB_01FF ; set pointer low byte
LDY #>LAB_01FF ; set pointer high byte
BNE LAB_AC4D ; go interpret single character
LAB_AC41
BMI LAB_ACB8 ; branch if READ
; else was INPUT
LDA LAB_13 ; get current I/O channel
BNE LAB_AC4A ; skip "?" prompt if not default channel
JSR LAB_AB45 ; print "?"
LAB_AC4A
JSR LAB_ABF9 ; print "? " and get BASIC input
LAB_AC4D
STX LAB_7A ; save BASIC execute pointer low byte
STY LAB_7B ; save BASIC execute pointer high byte
LAB_AC51
JSR LAB_0073 ; increment and scan memory, execute pointer now points to
; start of next data or null terminator
BIT LAB_0D ; test data type flag, $FF = string, $00 = numeric
BPL LAB_AC89 ; branch if numeric
; type is string
BIT LAB_11 ; test INPUT mode flag, $00 = INPUT, $40 = GET, $98 = READ
BVC LAB_AC65 ; branch if not GET
; else do string GET
INX ; clear X ??
STX LAB_7A ; save BASIC execute pointer low byte
LDA #$00 ; clear A
STA LAB_07 ; clear search character
BEQ LAB_AC71 ; branch always
; is string INPUT or string READ
LAB_AC65
STA LAB_07 ; save search character
CMP #$22 ; compare with "
BEQ LAB_AC72 ; branch if quote
; string is not in quotes so ":", "," or $00 are the
; termination characters
LDA #':' ; set ":"
STA LAB_07 ; set search character
LDA #',' ; set ","
LAB_AC71
CLC ; clear carry for add
LAB_AC72
STA LAB_08 ; set scan quotes flag
LDA LAB_7A ; get BASIC execute pointer low byte
LDY LAB_7B ; get BASIC execute pointer high byte
ADC #$00 ; add to pointer low byte. this add increments the pointer
; if the mode is INPUT or READ and the data is a "..."
; string
BCC LAB_AC7D ; branch if no rollover
INY ; else increment pointer high byte
LAB_AC7D
JSR LAB_B48D ; print string to utility pointer
JSR LAB_B7E2 ; restore BASIC execute pointer from temp
JSR LAB_A9DA ; perform string LET
JMP LAB_AC91 ; continue processing command
; GET, INPUT or READ is numeric
LAB_AC89
JSR LAB_BCF3 ; get FAC1 from string
LDA LAB_0E ; get data type flag, $80 = integer, $00 = float
JSR LAB_A9C2 ; assign value to numeric variable
LAB_AC91
JSR LAB_0079 ; scan memory
BEQ LAB_AC9D ; branch if ":" or [EOL]
CMP #',' ; comparte with ","
BEQ LAB_AC9D ; branch if ","
JMP LAB_AB4D ; else go do bad input routine
; string terminated with ":", "," or $00
LAB_AC9D
LDA LAB_7A ; get BASIC execute pointer low byte
LDY LAB_7B ; get BASIC execute pointer high byte
STA LAB_43 ; save READ pointer low byte
STY LAB_44 ; save READ pointer high byte
LDA LAB_4B ; get saved BASIC execute pointer low byte
LDY LAB_4C ; get saved BASIC execute pointer high byte
STA LAB_7A ; restore BASIC execute pointer low byte
STY LAB_7B ; restore BASIC execute pointer high byte
JSR LAB_0079 ; scan memory
BEQ LAB_ACDF ; branch if ":" or [EOL]
JSR LAB_AEFD ; scan for ",", else do syntax error then warm start
JMP LAB_AC15 ; go READ or INPUT next variable from list
; was READ
LAB_ACB8
JSR LAB_A906 ; scan for next BASIC statement ([:] or [EOL])
INY ; increment index to next byte
TAX ; copy byte to X
BNE LAB_ACD1 ; branch if ":"
LDX #$0D ; else set error $0D, out of data error
INY ; increment index to next line pointer high byte
LDA (LAB_7A),Y ; get next line pointer high byte
BEQ LAB_AD32 ; branch if program end, eventually does error X
INY ; increment index
LDA (LAB_7A),Y ; get next line # low byte
STA LAB_3F ; save current DATA line low byte
INY ; increment index
LDA (LAB_7A),Y ; get next line # high byte
INY ; increment index
STA LAB_40 ; save current DATA line high byte
LAB_ACD1
JSR LAB_A8FB ; add Y to the BASIC execute pointer
JSR LAB_0079 ; scan memory
TAX ; copy the byte
CPX #TK_DATA ; compare it with token for DATA
BNE LAB_ACB8 ; loop if not DATA
JMP LAB_AC51 ; continue evaluating READ
LAB_ACDF
LDA LAB_43 ; get READ pointer low byte
LDY LAB_44 ; get READ pointer high byte
LDX LAB_11 ; get INPUT mode flag, $00 = INPUT, $40 = GET, $98 = READ
BPL LAB_ACEA ; branch if INPUT or GET
JMP LAB_A827 ; else set data pointer and exit
LAB_ACEA
LDY #$00 ; clear index
LDA (LAB_43),Y ; get READ byte
BEQ LAB_ACFB ; exit if [EOL]
LDA LAB_13 ; get current I/O channel
BNE LAB_ACFB ; exit if not default channel
LDA #<LAB_ACFC ; set "?EXTRA IGNORED" pointer low byte
LDY #>LAB_ACFC ; set "?EXTRA IGNORED" pointer high byte
JMP LAB_AB1E ; print null terminated string
LAB_ACFB
RTS
;************************************************************************************
;
; input error messages
LAB_ACFC
.byte "?EXTRA IGNORED",$0D,$00
LAB_AD0C
.byte "?REDO FROM START",$0D,$00
;************************************************************************************
;
; perform NEXT
LAB_AD1E
BNE LAB_AD24 ; branch if NEXT variable
LDY #$00 ; else clear Y
BEQ LAB_AD27 ; branch always
; NEXT variable
LAB_AD24
JSR LAB_B08B ; get variable address
LAB_AD27
STA LAB_49 ; save FOR/NEXT variable pointer low byte
STY LAB_4A ; save FOR/NEXT variable pointer high byte
; (high byte cleared if no variable defined)
JSR LAB_A38A ; search the stack for FOR or GOSUB activity
BEQ LAB_AD35 ; branch if FOR, this variable, found
LDX #$0A ; else set error $0A, next without for error
LAB_AD32
JMP LAB_A437 ; do error #X then warm start
; found this FOR variable
LAB_AD35
TXS ; update stack pointer
TXA ; copy stack pointer
CLC ; clear carry for add
ADC #$04 ; point to STEP value
PHA ; save it
ADC #$06 ; point to TO value
STA LAB_24 ; save pointer to TO variable for compare
PLA ; restore pointer to STEP value
LDY #$01 ; point to stack page
JSR LAB_BBA2 ; unpack memory (AY) into FAC1
TSX ; get stack pointer back
LDA LAB_0100+9,X ; get step sign
STA LAB_66 ; save FAC1 sign (b7)
LDA LAB_49 ; get FOR/NEXT variable pointer low byte
LDY LAB_4A ; get FOR/NEXT variable pointer high byte
JSR LAB_B867 ; add FOR variable to FAC1
JSR LAB_BBD0 ; pack FAC1 into FOR variable
LDY #$01 ; point to stack page
JSR LAB_BC5D ; compare FAC1 with TO value
TSX ; get stack pointer back
SEC ; set carry for subtract
SBC LAB_0100+9,X ; subtract step sign
BEQ LAB_AD78 ; branch if =, loop complete
; loop back and do it all again
LDA LAB_0100+$0F,X ; get FOR line low byte
STA LAB_39 ; save current line number low byte
LDA LAB_0110,X ; get FOR line high byte
STA LAB_3A ; save current line number high byte
LDA LAB_0112,X ; get BASIC execute pointer low byte
STA LAB_7A ; save BASIC execute pointer low byte
LDA LAB_0111,X ; get BASIC execute pointer high byte
STA LAB_7B ; save BASIC execute pointer high byte
LAB_AD75
JMP LAB_A7AE ; go do interpreter inner loop
; NEXT loop comlete
LAB_AD78
TXA ; stack copy to A
ADC #$11 ; add $12, $11 + carry, to dump FOR structure
TAX ; copy back to index
TXS ; copy to stack pointer
JSR LAB_0079 ; scan memory
CMP #',' ; compare with ","
BNE LAB_AD75 ; if not "," go do interpreter inner loop
; was "," so another NEXT variable to do
JSR LAB_0073 ; increment and scan memory
JSR LAB_AD24 ; do NEXT variable
;************************************************************************************
;
; evaluate expression and check type mismatch
LAB_AD8A
JSR LAB_AD9E ; evaluate expression
; check if source and destination are numeric
LAB_AD8D
CLC
.byte $24 ; makes next line BIT LAB_38
; check if source and destination are string
LAB_AD8F
SEC ; destination is string
; type match check, set C for string, clear C for numeric
LAB_AD90
BIT LAB_0D ; test data type flag, $FF = string, $00 = numeric
BMI LAB_AD97 ; branch if string
BCS LAB_AD99 ; if destiantion is numeric do type missmatch error
LAB_AD96
RTS
LAB_AD97
BCS LAB_AD96 ; exit if destination is string
; do type missmatch error
LAB_AD99
LDX #$16 ; error code $16, type missmatch error
JMP LAB_A437 ; do error #X then warm start
;************************************************************************************
;
; evaluate expression
LAB_AD9E
LDX LAB_7A ; get BASIC execute pointer low byte
BNE LAB_ADA4 ; skip next if not zero
DEC LAB_7B ; else decrement BASIC execute pointer high byte
LAB_ADA4
DEC LAB_7A ; decrement BASIC execute pointer low byte
LDX #$00 ; set null precedence, flag done
.byte $24 ; makes next line BIT LAB_48
LAB_ADA9
PHA ; push compare evaluation byte if branch to here
TXA ; copy precedence byte
PHA ; push precedence byte
LDA #$01 ; 2 bytes
JSR LAB_A3FB ; check room on stack for A*2 bytes
JSR LAB_AE83 ; get value from line
LDA #$00 ; clear A
STA LAB_4D ; clear comparrison evaluation flag
LAB_ADB8
JSR LAB_0079 ; scan memory
LAB_ADBB
SEC ; set carry for subtract
SBC #TK_GT ; subtract the token for ">"
BCC LAB_ADD7 ; branch if < ">"
CMP #$03 ; compare with ">" to +3
BCS LAB_ADD7 ; branch if >= 3
; was token for ">" "=" or "<"
CMP #$01 ; compare with token for =
ROL ; *2, b0 = carry (=1 if token was = or <)
EOR #$01 ; toggle b0
EOR LAB_4D ; EOR with comparrison evaluation flag
CMP LAB_4D ; compare with comparrison evaluation flag
BCC LAB_AE30 ; if < saved flag do syntax error then warm start
STA LAB_4D ; save new comparrison evaluation flag
JSR LAB_0073 ; increment and scan memory
JMP LAB_ADBB ; go do next character
LAB_ADD7
LDX LAB_4D ; get comparrison evaluation flag
BNE LAB_AE07 ; branch if compare function
BCS LAB_AE58 ; go do functions
; else was < TK_GT so is operator or lower
ADC #$07 ; add # of operators (+, -, *, /, ^, AND or OR)
BCC LAB_AE58 ; branch if < + operator
; carry was set so token was +, -, *, /, ^, AND or OR
ADC LAB_0D ; add data type flag, $FF = string, $00 = numeric
BNE LAB_ADE8 ; branch if not string or not + token
; will only be $00 if type is string and token was +
JMP LAB_B63D ; add strings, string 1 is in the descriptor, string 2
; is in line, and return
LAB_ADE8
ADC #$FF ; -1 (corrects for carry add)
STA LAB_22 ; save it
ASL ; *2
ADC LAB_22 ; *3
TAY ; copy to index
LAB_ADF0
PLA ; pull previous precedence
CMP LAB_A080,Y ; compare with precedence byte
BCS LAB_AE5D ; branch if A >=
JSR LAB_AD8D ; check if source is numeric, else do type mismatch
LAB_ADF9
PHA ; save precedence
LAB_ADFA
JSR LAB_AE20 ; get vector, execute function then continue evaluation
PLA ; restore precedence
LDY LAB_4B ; get precedence stacked flag
BPL LAB_AE19 ; branch if stacked values
TAX ; copy precedence, set flags
BEQ LAB_AE5B ; exit if done
BNE LAB_AE66 ; else pop FAC2 and return, branch always
LAB_AE07
LSR LAB_0D ; clear data type flag, $FF = string, $00 = numeric
TXA ; copy compare function flag
ROL ; <<1, shift data type flag into b0, 1 = string, 0 = num
LDX LAB_7A ; get BASIC execute pointer low byte
BNE LAB_AE11 ; branch if no underflow
DEC LAB_7B ; else decrement BASIC execute pointer high byte
LAB_AE11
DEC LAB_7A ; decrement BASIC execute pointer low byte
LDY #LAB_A09B-LAB_A080
; set offset to = operator precedence entry
STA LAB_4D ; save new comparrison evaluation flag
BNE LAB_ADF0 ; branch always
LAB_AE19
CMP LAB_A080,Y ; compare with stacked function precedence
BCS LAB_AE66 ; if A >=, pop FAC2 and return
BCC LAB_ADF9 ; else go stack this one and continue, branch always
;************************************************************************************
;
; get vector, execu