;***********************************************************************************;
;***********************************************************************************;
;
; The almost completely commented Vic 20 ROM disassembly. V1.01 Lee Davison 2005-2012.

; This is a bit correct assembly listing for the Vic 20 BASIC and kernal ROMs as one 16K
; ROM. You should be able to assemble the Vic 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", "Vic 20 Programmers reference", "Vic 20 user
; guide", "The complete Commodore inner space anthology", "VIC Revealed" and various
; text files, pictures and other documents.


;***********************************************************************************;
;***********************************************************************************;
;
; first a whole load of equates

; These locations contain the JMP instruction target address of the USR command. They
; are initialised so that if you try to execute a USR call without changing them you
; wil receive an ILLEGAL QUANTITY error message.

LAB_00    = $00            ; USR() JMP instruction
LAB_01    = $01            ; USR() vector low byte
LAB_02    = $02            ; USR() vector high byte

; 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

; 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_07    = $07            ; search character
LAB_08    = $08            ; scan quotes flag
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.

; The print CR/LF code at LAB_CAD7 suggests that b7 of this byte is an AutoLF flag bit
; but if it is used as such it would break lots of other parts of the code

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
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
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_008B    = $8B            ; RND() seed, five bytes

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
LAB_91    = $91            ; keyboard row, bx = 0 = key down
                   ; bit    key
                   ; ---    ------
                   ; 7    [DOWN]
                   ; 6    /
                   ; 5    ,
                   ; 4    N
                   ; 3    V
                   ; 2    X
                   ; 1    [L SHIFT]
                   ; 0    [STOP]
LAB_92    = $92            ; timing constant for tape read
LAB_93    = $93            ; load/verify flag, load = $00, verify = $01
LAB_94    = $94            ; serial output: deferred character flag
                   ; $00 = no character waiting, $xx = character waiting
LAB_95    = $95            ; serial output: deferred character
                   ; $FF = no character waiting, $xx = waiting character
LAB_96    = $96            ; cassette block synchronization number
LAB_97    = $97            ; 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.

LAB_99    = $99            ; input device number

; The default value of this location is 3.

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            ; 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 2 error log corrected

; 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            ; 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 23 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 $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 22 characters long, BASIC allows the entry of
; program lines that contain up to 88 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

; This pointer is synchronized with the pointer to the address of the first byte of
; screen RAM for the current line kept in location $D1. It holds the address of the
; first byte of colour RAM for the corresponding screen line.

LAB_F2    = $F2            ; screen row marker
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_EC5E            ; unshifted
;    LAB_EC9F            ; shifted
;    LAB_ECE0            ; commodore
;    LAB_EDA3            ; 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_00FF    = $FF            ; FAC1 to string output base

LAB_0100    = $0100        ; bottom of the stack page

LAB_01FC    = $01FC        ; chain link pointer high byte
LAB_01FD    = $01FD        ; chain link pointer low byte

LAB_01FE    = $01FE        ; line number low byte before crunched line
LAB_01FF    = $01FF        ; line number high byte before crunched line

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        ; input buffer + 1

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
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
                   ; ---    --------
                   ; 765    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        ; time of one bit cell low byte
LAB_029A    = $029A        ; time of one bit cell high byte
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

; $02A1 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_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        ; to $03FB - cassette buffer


;***********************************************************************************;
;***********************************************************************************;
;
; hardware equates

LAB_9000    = $9000        ; Vic chip base address
LAB_9002    = $9002        ; video address and colums
                   ; bit    function
                   ; ---    --------
                   ; 7    video address va9
                   ; 6-0    number of columns
LAB_9005    = $9005        ; video memory addresses ($1E00)
                   ; bit    function
                   ; ---    --------
                   ; 7    must be 1
                   ; 6-4    video memory address va12-va10
                   ; 3-0    character memory start address

                   ; 0000 ROM    $8000    set 1
                   ; 0001 "    $8400
                   ; 0010 "    $8800 set 2
                   ; 0011 "    $8C00
                   ; 1100 RAM    $1000
                   ; 1101 "    $1400
                   ; 1110 "    $1800
                   ; 1111 "    $1C00

LAB_9110    = $9110        ; VIA 1 DRB
                   ; bit    function
                   ; ---    --------
                   ; 7    DSR in
                   ; 6    CTS in
                   ; 5    
                   ; 4    DCD in
                   ; 3    RI in
                   ; 2    DTR out
                   ; 1    RTS out
                   ; 0    data in
LAB_9111    = $9111        ; VIA 1 DRA
                   ; bit    function
                   ; ---    --------
                   ; 7    serial ATN out
                   ; 6    cassette switch
                   ; 5    light pen
                   ; 4    joy 2
                   ; 3    joy 1
                   ; 2    joy 0
                   ; 1    serial DATA in
                   ; 0    serial CLK in
LAB_9112    = $9112        ; VIA 1 DDRB
LAB_9113    = $9113        ; VIA 1 DDRA
LAB_9114    = $9114        ; VIA 1 T1C_l
LAB_9115    = $9115        ; VIA 1 T1C_h
LAB_9118    = $9118        ; VIA 1 T2C_l
LAB_9119    = $9119        ; VIA 1 T2C_h
LAB_911B    = $911B        ; VIA 1 ACR
                   ; bit    function
                   ; ---    --------
                   ; 7    T1 PB7 enabled/disabled
                   ; 6    T1 free run/one shot
                   ; 5    T2 clock PB6/�2
                   ; 432    function
                   ; ---    --------
                   ; 000    shift register disabled
                   ; 001    shift in, rate controlled by T2
                   ; 010    shift in, rate controlled by �2
                   ; 011    shift in, rate controlled by externak clock
                   ; 100    shift out, rate controlled by T2, free run mode
                   ; 101    shift out, rate controlled by T2
                   ; 110    shift out, rate controlled by �2
                   ; 111    shift out, rate controlled by externak clock
                   ; 1    PB latch enabled/disabled
                   ; 0    PA latch enabled/disabled
LAB_911C    = $911C        ; VIA 1 PCR
                   ; bit    function
                   ; ---    --------
                   ; 765    CB2 control
                   ; ---    -----------
                   ; 000    Interrupt Input Mode
                   ; 001    Independent Interrupt Input Mode
                   ; 010    Input Mode
                   ; 011    Independent Input Mode
                   ; 100    Handshake Output Mode
                   ; 101    Pulse Output Mode
                   ; 110    Manual Output Mode, CB2 low
                   ; 111    Manual Output Mode, CB2 high
                   ; 4    CB1 edge positive/negative
                   ; 321    CA2 control
                   ; ---    -----------
                   ; 000    Interrupt Input Mode
                   ; 001    Independent Interrupt Input Mode
                   ; 010    Input Mode
                   ; 011    Independent Input Mode
                   ; 100    Handshake Output Mode
                   ; 101    Pulse Output Mode
                   ; 110    Manual Output Mode, CA2 low
                   ; 111    Manual Output Mode, CA2 high
                   ; 0    CA1 edge positive/negative

; the status bit is a not normal flag. it goes high if both an interrupt flag in the IFR
; and the corresponding enable bit in the IER are set. it can be cleared only by clearing
; all the active flags in the IFR or disabling all active interrupts in the IER

LAB_911D    = $911D        ; VIA 1 IFR
                   ; bit    function        cleared by
                   ; ---    --------        ----------
                   ; 7    interrupt status    clearing all enabled interrupts
                   ; 6    T1 interrupt    read T1C_l, write T1C_h
                   ; 5    T2 interrupt    read T2C_l, write T2C_h
                   ; 4    CB1 transition    read or write port B
                   ; 3    CB2 transition    read or write port B
                   ; 2    8 shifts done    read or write the shift register
                   ; 1    CA1 transition    read or write port A
                   ; 0    CA2 transition    read or write port A

; If enable/disable bit is a zero during a write to this register, each 1 in bits 0-6
; clears the corresponding bit in the IER. if this bit is a one during a write to this
; register, each 1 in bits 0-6 will set the corresponding IER bit

LAB_911E    = $911E        ; VIA 1 IER
                   ; bit    function
                   ; ---    --------
                   ; 7    enable/disable
                   ; 6    T1 interrupt
                   ; 5    T2 interrupt
                   ; 4    CB1 transition
                   ; 3    CB2 transition
                   ; 2    8 shifts done
                   ; 1    CA1 transition
                   ; 0    CA2 transition

LAB_911F    = $911F        ; VIA 1 DRA, no handshake
                   ; bit    function
                   ; ---    --------
                   ; 7    ATN out
                   ; 6    cassette switch
                   ; 5    joystick fire, light pen
                   ; 4    joystick left
                   ; 3    joystick down
                   ; 2    joystick up
                   ; 1    serial dat in
                   ; 0    serial clk in

LAB_9120    = $9120        ; VIA 2 DRB, keyboard column drive
LAB_9121    = $9121        ; VIA 2 DRA, keyboard row port
                   ; Vic 20 keyboard matrix layout
                   ;    c7    c6    c5    c4    c3    c2    c1    c0
                   ; +------------------------------------------------
                   ; r7|    [F7]    [F5]    [F3]    [F1]    [DN]    [RGT]    [RET]    [DEL]
                   ; r6|    [Home][UP] =    [RSH]    /    ;    *    �
                   ; r5|    -    @    :    .    ,    L    P    +
                   ; r4|    0    O    K    M    N    J    I    9
                   ; r3|    8    U    H    B    V    G    Y    7
                   ; r2|    6    T    F    C    X    D    R    5
                   ; r1|    4    E    S    Z    [LSH]    A    W    3
                   ; r0|    2    Q    [CBM]    [SP]    [RUN]    [CTL]    [LFT]    1

LAB_9122    = $9122        ; VIA 2 DDRB
LAB_9123    = $9123        ; VIA 2 DDRA
LAB_9124    = $9124        ; VIA 2 T1C_l
LAB_9125    = $9125        ; VIA 2 T1C_h
LAB_9128    = $9128        ; VIA 2 T2C_l
LAB_9129    = $9129        ; VIA 2 T2C_h
LAB_912B    = $912B        ; VIA 2 ACR
LAB_912C    = $912C        ; VIA 2 PCR

; the status bit is a not normal flag. it goes high if both an interrupt flag in the IFR
; and the corresponding enable bit in the IER are set. it can be cleared only by clearing
; all the active flags in the IFR or disabling all active interrupts in the IER

LAB_912D    = $912D        ; VIA 1 IFR
                   ; bit    function        cleared by
                   ; ---    --------        ----------
                   ; 7    interrupt status    clearing all enabled interrupts
                   ; 6    T1 interrupt    read T1C_l, write T1C_h
                   ; 5    T2 interrupt    read T2C_l, write T2C_h
                   ; 4    CB1 transition    read or write port B
                   ; 3    CB2 transition    read or write port B
                   ; 2    8 shifts done    read or write the shift register
                   ; 1    CA1 transition    read or write port A
                   ; 0    CA2 transition    read or write port A

; If enable/disable bit is a zero during a write to this register, each 1 in bits 0-6
; clears the corresponding bit in the IER. if this bit is a one during a write to this
; register, each 1 in bits 0-6 will set the corresponding IER bit

LAB_912E    = $912E        ; VIA 1 IER
                   ; bit    function
                   ; ---    --------
                   ; 7    enable/disable
                   ; 6    T1 interrupt
                   ; 5    T2 interrupt
                   ; 4    CB1 transition
                   ; 3    CB2 transition
                   ; 2    8 shifts done
                   ; 1    CA1 transition
                   ; 0    CA2 transition

LAB_912F    = $912F        ; VIA 2 DRA, keyboard row, no handshake

LAB_A000    = $A000        ; autostart ROM initial entry vector
LAB_A002    = $A002        ; autostart ROM break entry
LAB_A004    = $A004        ; autostart ROM identifier string start


;***********************************************************************************;
;
; 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


;***********************************************************************************;
;***********************************************************************************;
;
; ROM start

   .ORG    $C000

LAB_C000
   .word    LAB_E378        ; BASIC cold start entry point

LAB_C002
   .word    LAB_E467        ; BASIC warm start entry point

;LAB_C004
   .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_C00C
   .word    LAB_C831-1        ; perform END
   .word    LAB_C742-1        ; perform FOR
   .word    LAB_CD1E-1        ; perform NEXT
   .word    LAB_C8F8-1        ; perform DATA
   .word    LAB_CBA5-1        ; perform INPUT#
   .word    LAB_CBBF-1        ; perform INPUT
   .word    LAB_D081-1        ; perform DIM
   .word    LAB_CC06-1        ; perform READ

   .word    LAB_C9A5-1        ; perform LET
   .word    LAB_C8A0-1        ; perform GOTO
   .word    LAB_C871-1        ; perform RUN
   .word    LAB_C928-1        ; perform IF
   .word    LAB_C81D-1        ; perform RESTORE
   .word    LAB_C883-1        ; perform GOSUB
   .word    LAB_C8D2-1        ; perform RETURN
   .word    LAB_C93B-1        ; perform REM

   .word    LAB_C82F-1        ; perform STOP
   .word    LAB_C94B-1        ; perform ON
   .word    LAB_D82D-1        ; perform WAIT
   .word    LAB_E165-1        ; perform LOAD
   .word    LAB_E153-1        ; perform SAVE
   .word    LAB_E162-1        ; perform VERIFY
   .word    LAB_D3B3-1        ; perform DEF
   .word    LAB_D824-1        ; perform POKE

   .word    LAB_CA80-1        ; perform PRINT#
   .word    LAB_CAA0-1        ; perform PRINT
   .word    LAB_C857-1        ; perform CONT
   .word    LAB_C69C-1        ; perform LIST
   .word    LAB_C65E-1        ; perform CLR
   .word    LAB_CA86-1        ; perform CMD
   .word    LAB_E127-1        ; perform SYS
   .word    LAB_E1BB-1        ; perform OPEN

   .word    LAB_E1C4-1        ; perform CLOSE
   .word    LAB_CB7B-1        ; perform GET
   .word    LAB_C642-1        ; perform NEW


;***********************************************************************************;
;
; action addresses for functions

LAB_C052
   .word    LAB_DC39        ; perform SGN()
   .word    LAB_DCCC        ; perform INT()
   .word    LAB_DC58        ; perform ABS()
   .word    LAB_00        ; perform USR()

   .word    LAB_D37D        ; perform FRE()
   .word    LAB_D39E        ; perform POS()
   .word    LAB_DF71        ; perform SQR()
   .word    LAB_E094        ; perform RND()
   .word    LAB_D9EA        ; perform LOG()
   .word    LAB_DFED        ; perform EXP()
   .word    LAB_E261        ; perform COS()
   .word    LAB_E268        ; perform SIN()

   .word    LAB_E2B1        ; perform TAN()
   .word    LAB_E30B        ; perform ATN()
   .word    LAB_D80D        ; perform PEEK()
   .word    LAB_D77C        ; perform LEN()
   .word    LAB_D465        ; perform STR$()
   .word    LAB_D7AD        ; perform VAL()
   .word    LAB_D78B        ; perform ASC()
   .word    LAB_D6EC        ; perform CHR$()

   .word    LAB_D700        ; perform LEFT$()
   .word    LAB_D72C        ; perform RIGHT$()
   .word    LAB_D737        ; perform MID$()


;***********************************************************************************;
;
; 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_C080
   .byte    $79
   .word    LAB_D86A-1        ; +
   .byte    $79
   .word    LAB_D853-1        ; -
   .byte    $7B
   .word    LAB_DA2B-1        ; *
   .byte    $7B
   .word    LAB_DB12-1        ; /
   .byte    $7F
   .word    LAB_DF7B-1        ; ^
   .byte    $50
   .word    LAB_CFE9-1        ; AND
   .byte    $46
   .word    LAB_CFE6-1        ; OR
   .byte    $7D
   .word    LAB_DFB4-1        ; >
   .byte    $5A
   .word    LAB_CED4-1        ; =
LAB_C09B
   .byte    $64
   .word    LAB_D016-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_C09E
   .byte    "EN",'D'+$80    ; END
   .byte    "FO",'R'+$80    ; FOR
   .byte    "NEX",'T'+$80    ; NEXT
   .byte    "DAT",'A'+$80    ; DATA
   .byte    "INPUT",'#'+$80    ; INPUT#
   .byte    "INPU",'T'+$80    ; INPUT
   .byte    "DI",'M'+$80    ; DIM
   .byte    "REA",'D'+$80    ; READ

   .byte    "LE",'T'+$80    ; LET
   .byte    "GOT",'O'+$80    ; GOTO
   .byte    "RU",'N'+$80    ; RUN
   .byte    "I",'F'+$80        ; IF
   .byte    "RESTOR",'E'+$80    ; RESTORE
   .byte    "GOSU",'B'+$80    ; GOSUB
   .byte    "RETUR",'N'+$80    ; RETURN
   .byte    "RE",'M'+$80    ; REM

   .byte    "STO",'P'+$80    ; STOP
   .byte    "O",'N'+$80        ; ON
   .byte    "WAI",'T'+$80    ; WAIT
   .byte    "LOA",'D'+$80    ; LOAD
   .byte    "SAV",'E'+$80    ; SAVE
   .byte    "VERIF",'Y'+$80    ; VERIFY
   .byte    "DE",'F'+$80    ; DEF
   .byte    "POK",'E'+$80    ; POKE

   .byte    "PRINT",'#'+$80    ; PRINT#
   .byte    "PRIN",'T'+$80    ; PRINT
   .byte    "CON",'T'+$80    ; CONT
   .byte    "LIS",'T'+$80    ; LIST
   .byte    "CL",'R'+$80    ; CLR
   .byte    "CM",'D'+$80    ; CMD
   .byte    "SY",'S'+$80    ; SYS
   .byte    "OPE",'N'+$80    ; OPEN

   .byte    "CLOS",'E'+$80    ; CLOSE
   .byte    "GE",'T'+$80    ; GET
   .byte    "NE",'W'+$80    ; NEW

; next are the secondary command keywords, these can not start a statement

   .byte    "TAB",'('+$80    ; TAB(
   .byte    "T",'O'+$80        ; TO
   .byte    "F",'N'+$80        ; FN
   .byte    "SPC",'('+$80    ; SPC(
   .byte    "THE",'N'+$80    ; THEN

   .byte    "NO",'T'+$80    ; NOT
   .byte    "STE",'P'+$80    ; STEP

; the operators

   .byte    '+'+$80        ; +
   .byte    '-'+$80        ; -
   .byte    '*'+$80        ; *
   .byte    '/'+$80        ; /
   .byte    '^'+$80        ; ^
   .byte    "AN",'D'+$80    ; AND

   .byte    "O",'R'+$80        ; OR
   .byte    '>'+$80        ; >
   .byte    '='+$80        ; =
   .byte    '<'+$80        ; <

; the functions

   .byte    "SG",'N'+$80    ; SGN
   .byte    "IN",'T'+$80    ; INT
   .byte    "AB",'S'+$80    ; ABS
   .byte    "US",'R'+$80    ; USR

   .byte    "FR",'E'+$80    ; FRE
   .byte    "PO",'S'+$80    ; POS
   .byte    "SQ",'R'+$80    ; SQR
   .byte    "RN",'D'+$80    ; RND
   .byte    "LO",'G'+$80    ; LOG
   .byte    "EX",'P'+$80    ; EXP
   .byte    "CO",'S'+$80    ; COS
   .byte    "SI",'N'+$80    ; SIN

   .byte    "TA",'N'+$80    ; TAN
   .byte    "AT",'N'+$80    ; ATN
   .byte    "PEE",'K'+$80    ; PEEK
   .byte    "LE",'N'+$80    ; LEN
   .byte    "STR",'$'+$80    ; STR$
   .byte    "VA",'L'+$80    ; VAL
   .byte    "AS",'C'+$80    ; ASC
   .byte    "CHR",'$'+$80    ; CHR$

   .byte    "LEFT",'$'+$80    ; LEFT$
   .byte    "RIGHT",'$'+$80    ; RIGHT$
   .byte    "MID",'$'+$80    ; MID$

; lastly is GO, this is an add on so that GO TO, as well as GOTO, will work

   .byte    "G",'O'+$80        ; GO

   .byte    $00            ; end marker


;***********************************************************************************;
;
; error messages

LAB_C19E
   .byte    "TOO MANY FILE",'S'+$80
LAB_C1AC
   .byte    "FILE OPE",'N'+$80
LAB_C1B5
   .byte    "FILE NOT OPE",'N'+$80
LAB_C1C2
   .byte    "FILE NOT FOUN",'D'+$80
LAB_C1D0
   .byte    "DEVICE NOT PRESEN",'T'+$80
LAB_C1E2
   .byte    "NOT INPUT FIL",'E'+$80
LAB_C1F0
   .byte    "NOT OUTPUT FIL",'E'+$80
LAB_C1FF
   .byte    "MISSING FILE NAM",'E'+$80
LAB_C210
   .byte    "ILLEGAL DEVICE NUMBE",'R'+$80
LAB_C225
   .byte    "NEXT WITHOUT FO",'R'+$80
LAB_C235
   .byte    "SYNTA",'X'+$80
LAB_C23B
   .byte    "RETURN WITHOUT GOSU",'B'+$80
LAB_C24F
   .byte    "OUT OF DAT",'A'+$80
LAB_C25A
   .byte    "ILLEGAL QUANTIT",'Y'+$80
LAB_C26A
   .byte    "OVERFLO",'W'+$80
LAB_C272
   .byte    "OUT OF MEMOR",'Y'+$80
LAB_C27F
   .byte    "UNDEF'D STATEMEN",'T'+$80
LAB_C290
   .byte    "BAD SUBSCRIP",'T'+$80
LAB_C29D
   .byte    "REDIM'D ARRA",'Y'+$80
LAB_C2AA
   .byte    "DIVISION BY ZER",'O'+$80
LAB_C2BA
   .byte    "ILLEGAL DIREC",'T'+$80
LAB_C2C8
   .byte    "TYPE MISMATC",'H'+$80
LAB_C2D5
   .byte    "STRING TOO LON",'G'+$80
LAB_C2E4
   .byte    "FILE DAT",'A'+$80
LAB_C2ED
   .byte    "FORMULA TOO COMPLE",'X'+$80
LAB_C300
   .byte    "CAN'T CONTINU",'E'+$80
LAB_C30E
   .byte    "UNDEF'D FUNCTIO",'N'+$80
LAB_C31E
   .byte    "VERIF",'Y'+$80
LAB_C324
   .byte    "LOA",'D'+$80

; error message pointer table

LAB_C328
   .word    LAB_C19E        ; $01    TOO MANY FILES
   .word    LAB_C1AC        ; $02    FILE OPEN
   .word    LAB_C1B5        ; $03    FILE NOT OPEN
   .word    LAB_C1C2        ; $04    FILE NOT FOUND
   .word    LAB_C1D0        ; $05    DEVICE NOT PRESENT
   .word    LAB_C1E2        ; $06    NOT INPUT FILE
   .word    LAB_C1F0        ; $07    NOT OUTPUT FILE
   .word    LAB_C1FF        ; $08    MISSING FILE NAME
   .word    LAB_C210        ; $09    ILLEGAL DEVICE NUMBER
   .word    LAB_C225        ; $0A    NEXT WITHOUT FOR
   .word    LAB_C235        ; $0B    SYNTAX
   .word    LAB_C23B        ; $0C    RETURN WITHOUT GOSUB
   .word    LAB_C24F        ; $0D    OUT OF DATA
   .word    LAB_C25A        ; $0E    ILLEGAL QUANTITY
   .word    LAB_C26A        ; $0F    OVERFLOW
   .word    LAB_C272        ; $10    OUT OF MEMORY
   .word    LAB_C27F        ; $11    UNDEF'D STATEMENT
   .word    LAB_C290        ; $12    BAD SUBSCRIPT
   .word    LAB_C29D        ; $13    REDIM'D ARRAY
   .word    LAB_C2AA        ; $14    DIVISION BY ZERO
   .word    LAB_C2BA        ; $15    ILLEGAL DIRECT
   .word    LAB_C2C8        ; $16    TYPE MISMATCH
   .word    LAB_C2D5        ; $17    STRING TOO LONG
   .word    LAB_C2E4        ; $18    FILE DATA
   .word    LAB_C2ED        ; $19    FORMULA TOO COMPLEX
   .word    LAB_C300        ; $1A    CAN'T CONTINUE
   .word    LAB_C30E        ; $1B    UNDEF'D FUNCTION
   .word    LAB_C31E        ; $1C    VERIFY
   .word    LAB_C324        ; $1D    LOAD
   .word    LAB_C383        ; $1E    BREAK


;***********************************************************************************;
;
; BASIC messages

LAB_C364
   .byte    $0D,"OK",$0D,$00
LAB_C369
   .byte    $0D," ERROR",$00
LAB_C371
   .byte    " IN ",$00
LAB_C376
   .byte    $0D,$0A,"READY.",$0D,$0A,$00
LAB_C381
   .byte    $0D,$0A
LAB_C383
   .byte    "BREAK",$00


;***********************************************************************************;
;
; spare byte, not referenced

;LAB_C389
   .byte    $A0


;***********************************************************************************;
;
; search the stack for FOR or GOSUB activity
; return Zb=1 if FOR variable found

LAB_C38A
   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_C38F
   LDA    LAB_0100+1,X    ; get token byte from stack
   CMP    #TK_FOR        ; is it FOR token
   BNE    LAB_C3B7        ; exit if not FOR token

                   ; was FOR token
   LDA    LAB_4A        ; get FOR/NEXT variable pointer high byte
   BNE    LAB_C3A4        ; 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_C3A4
   CMP    LAB_0100+3,X    ; compare variable pointer with stacked variable pointer
                   ; high byte
   BNE    LAB_C3B0        ; 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_C3B7        ; exit if match found

LAB_C3B0
   TXA                ; copy index
   CLC                ; clear carry for add
   ADC    #$12            ; add FOR stack use size
   TAX                ; copy back to index
   BNE    LAB_C38F        ; loop if not at start of stack

LAB_C3B7
   RTS


;***********************************************************************************;
;
; open up space in memory, set end of arrays

LAB_C3B8
   JSR    LAB_C408        ; 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 space in memory, don't set array end

LAB_C3BF
   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_C3F3        ; 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_C3DC        ; if no underflow skip the high byte decrement

   DEC    LAB_5B        ; else decrement block end high byte
   SEC                ; set carry for subtract
LAB_C3DC
   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_C3EC        ; if no underflow skip the high byte decrement

   DEC    LAB_59        ; else decrement block end high byte
   BCC    LAB_C3EC        ; branch always

LAB_C3E8
   LDA    (LAB_5A),Y        ; get byte from source
   STA    (LAB_58),Y        ; copy byte to destination
LAB_C3EC
   DEY                ; decrement index
   BNE    LAB_C3E8        ; 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_C3F3
   DEC    LAB_5B        ; decrement source pointer high byte
   DEC    LAB_59        ; decrement destination pointer high byte
   DEX                ; decrement block count
   BNE    LAB_C3EC        ; loop until count = $0

   RTS


;***********************************************************************************;
;
; check there is room on the stack for A bytes
; if the stack is too deep do an out of memory error

LAB_C3FB
   ASL                ; *2
   ADC    #$3E            ; need at least $3E bytes free
   BCS    LAB_C435        ; 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_C435        ; if stack < limit do out of memory error then warm start

   RTS


;***********************************************************************************;
;
; check available memory, do out of memory error if no room

LAB_C408
   CPY    LAB_34        ; compare with bottom of string space high byte
   BCC    LAB_C434        ; if less then exit (is ok)

   BNE    LAB_C412        ; 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_C434        ; if less then exit (is ok)

                   ; address is > string storage ptr (oops!)
LAB_C412
   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_C416
   PHA                ; push byte
   LDA    LAB_57,X        ; get byte from LAB_57 to LAB_60
   DEX                ; decrement index
   BPL    LAB_C416        ; loop until all done

   JSR    LAB_D526        ; do garbage collection routine

                   ; restore misc numeric work area
   LDX    #$F7            ; set index to restore bytes
LAB_C421
   PLA                ; pop byte
   STA    LAB_60+1,X        ; save byte to LAB_57 to LAB_60
   INX                ; increment index
   BMI    LAB_C421        ; 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_C434        ; if less then exit (is ok)

   BNE    LAB_C435        ; 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_C435        ; if >= do out of memory error then warm start

                   ; ok exit, carry clear
LAB_C434
   RTS


;***********************************************************************************;
;
; do out of memory error then warm start

LAB_C435
   LDX    #$10            ; error code $10, out of memory error

; do error #X then warm start

LAB_C437
   JMP    (LAB_0300)        ; do error message

; do error #X then warm start, the error message vector is initialised to point here

LAB_C43A
   TXA                ; copy error number
   ASL                ; *2
   TAX                ; copy to index
   LDA    LAB_C328-2,X    ; get error message pointer low byte
   STA    LAB_22        ; save it
   LDA    LAB_C328-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_CAD7        ; print CR/LF
   JSR    LAB_CB45        ; print "?"
   LDY    #$00            ; clear index
LAB_C456
   LDA    (LAB_22),Y        ; get byte from message
   PHA                ; save status
   AND    #$7F            ; mask 0xxx xxxx, clear b7
   JSR    LAB_CB47        ; output character
   INY                ; increment index
   PLA                ; restore status
   BPL    LAB_C456        ; loop if character was not end marker

   JSR    LAB_C67A        ; flush BASIC stack and clear continue pointer
   LDA    #    LDY    #>LAB_C369        ; set " ERROR" pointer high byte


;***********************************************************************************;
;
; print string and do warm start, break entry

LAB_C469
   JSR    LAB_CB1E        ; print null terminated string
   LDY    LAB_3A        ; get current line number high byte
   INY                ; increment it
   BEQ    LAB_C474        ; branch if was in immediate mode

   JSR    LAB_DDC2        ; do " IN " line number message


;***********************************************************************************;
;
; do warm start

LAB_C474
   LDA    #    LDY    #>LAB_C376        ; set "READY." pointer high byte
   JSR    LAB_CB1E        ; print null terminated string
   LDA    #$80            ; set for control messages only
   JSR    LAB_FF90        ; control kernal messages
LAB_C480
   JMP    (LAB_0302)        ; do BASIC warm start


;***********************************************************************************;
;
; BASIC warm start, the warm start vector is initialised to point here

LAB_C483
   JSR    LAB_C560        ; 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_C480        ; loop if no input

; got to interpret 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_C49C        ; if numeric character go handle new BASIC line

                   ; no line number .. immediate mode
   JSR    LAB_C579        ; crunch keywords into BASIC tokens
   JMP    LAB_C7E1        ; go scan and interpret code

; handle new BASIC line

LAB_C49C
   JSR    LAB_C96B        ; get fixed-point number into temporary integer
   JSR    LAB_C579        ; crunch keywords into BASIC tokens
   STY    LAB_0B        ; save index pointer to end of crunched line
   JSR    LAB_C613        ; search BASIC for temporary integer line number
   BCC    LAB_C4ED        ; 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_C4D7        ; if no underflow skip the high byte decrement

   INX                ; increment block count, correct for = 0 loop exit
   DEC    LAB_25        ; decrement destination high byte
LAB_C4D7
   CLC                ; clear carry for add
   ADC    LAB_22        ; add source pointer low byte
   BCC    LAB_C4DF        ; if no underflow skip the high byte decrement

   DEC    LAB_23        ; else decrement source pointer high byte
   CLC                ; clear carry

                   ; close up memory to delete old line
LAB_C4DF
   LDA    (LAB_22),Y        ; get byte from source
   STA    (LAB_24),Y        ; copy to destination
   INY                ; increment index
   BNE    LAB_C4DF        ; 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_C4DF        ; loop until all done

                   ; got new line in buffer and no existing same #
LAB_C4ED
   JSR    LAB_C659        ; reset execution to start, clear variables, flush stack
                   ; and return
   JSR    LAB_C533        ; rebuild BASIC line chaining
   LDA    LAB_0200        ; get first byte from buffer
   BEQ    LAB_C480        ; 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_C508        ; if no carry skip the high byte increment

   INY                ; else increment the high byte
LAB_C508
   STY    LAB_59        ; save as destination end pointer high byte
   JSR    LAB_C3B8        ; 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_C522
   LDA    LAB_01FC,Y        ; get byte from crunched line
   STA    (LAB_5F),Y        ; save byte to memory
   DEY                ; decrement index
   BPL    LAB_C522        ; loop while more to do

; reset execution, clear variables, flush stack, rebuild BASIC chain and do warm start

LAB_C52A
   JSR    LAB_C659        ; reset execution to start, clear variables and flush stack
   JSR    LAB_C533        ; rebuild BASIC line chaining
   JMP    LAB_C480        ; go do BASIC warm start


;***********************************************************************************;
;
; rebuild BASIC line chaining

LAB_C533
   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_C53C
   LDY    #$01            ; set index to pointer to next line high byte
   LDA    (LAB_22),Y        ; get pointer to next line high byte
   BEQ    LAB_C55F        ; 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_C544
   INY                ; next code byte
   LDA    (LAB_22),Y        ; get byte
   BNE    LAB_C544        ; 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_C53C        ; go do next line, branch always

LAB_C55F
   RTS


;***********************************************************************************;
;
; call for BASIC input

LAB_C560
   LDX    #$00            ; set channel $00, keyboard
LAB_C562
   JSR    LAB_E10F        ; input character from channel with error check
   CMP    #$0D            ; compare with [CR]
   BEQ    LAB_C576        ; 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_C562        ; branch if < max+1

   LDX    #$17            ; error $17, string too long error
   JMP    LAB_C437        ; do error #X then warm start

LAB_C576
   JMP    LAB_CACA        ; set XY to LAB_200 - 1 and print [CR]


;***********************************************************************************;
;
; crunch BASIC tokens vector

LAB_C579
   JMP    (LAB_0304)        ; do crunch BASIC tokens


;***********************************************************************************;
;
; crunch BASIC tokens, the crunch BASIC tokens vector is initialised to point here

LAB_C57C
   LDX    LAB_7A        ; get BASIC execute pointer low byte
   LDY    #$04            ; set save index
   STY    LAB_0F        ; clear open quote/DATA flag
LAB_C582
   LDA    LAB_0200,X        ; get a byte from the input buffer
   BPL    LAB_C58E        ; 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_C5C9        ; 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_C582        ; loop if more to do, branch always

LAB_C58E
   CMP    #' '            ; compare with [SPACE]
   BEQ    LAB_C5C9        ; if [SPACE] save byte then continue crunching

   STA    LAB_08        ; save buffer byte as search character
   CMP    #$22            ; compare with quote character
   BEQ    LAB_C5EE        ; if quote go copy quoted string

   BIT    LAB_0F        ; get open quote/DATA token flag
   BVS    LAB_C5C9        ; branch if b6 of Oquote set, was DATA
                   ; go save byte then continue crunching

   CMP    #'?'            ; compare with "?" character
   BNE    LAB_C5A4        ; if not "?" continue crunching

   LDA    #TK_PRINT        ; else set the token for PRINT
   BNE    LAB_C5C9        ; go save byte then continue crunching ,branch always

LAB_C5A4
   CMP    #'0'            ; compare with "0"
   BCC    LAB_C5AC        ; if < "0" continue crunching

   CMP    #'<'            ; compare with "<"
   BCC    LAB_C5C9        ; if <, 0123456789:; go save byte then continue crunching

                   ; gets here with next character not numeric, ";" or ":"
LAB_C5AC
   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_C5B6
   INY                ; next table byte
   INX                ; next buffer byte
LAB_C5B8
   LDA    LAB_0200,X        ; get byte from input buffer
   SEC                ; set carry for subtract
   SBC    LAB_C09E,Y        ; subtract table byte
   BEQ    LAB_C5B6        ; go compare next if match

   CMP    #$80            ; was it end marker match ?
   BNE    LAB_C5F5        ; if not go try the next 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_C5C7
   LDY    LAB_71        ; restore save index

; save byte then continue crunching

LAB_C5C9
   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_C609        ; branch if was null [EOL]

                   ; A holds the token here
   SEC                ; set carry for subtract
   SBC    #':'            ; subtract ":"
   BEQ    LAB_C5DC        ; branch if it was (is now $00)

                   ; A now holds token-':'
   CMP    #TK_DATA-':'    ; compare with the token for DATA-':'
   BNE    LAB_C5DE        ; if not DATA go try REM

                   ; token was : or DATA
LAB_C5DC
   STA    LAB_0F        ; save token-':'
LAB_C5DE
   SEC                ; set carry for subtract
   SBC    #TK_REM-':'        ; subtract the token for REM-':'
   BNE    LAB_C582        ; if wasn't REM go crunch next bit of line

   STA    LAB_08        ; else was REM so set search for [EOL]

                   ; loop for "..." etc.
LAB_C5E5
   LDA    LAB_0200,X        ; get byte from input buffer
   BEQ    LAB_C5C9        ; if null [EOL] save byte then continue crunching

   CMP    LAB_08        ; compare with stored character
   BEQ    LAB_C5C9        ; if match save byte then continue crunching

LAB_C5EE
   INY                ; increment save index
   STA    LAB_0200-5,Y    ; save byte to output
   INX                ; increment buffer index
   BNE    LAB_C5E5        ; loop while <> 0, should never reach 0

                   ; not found keyword this go
LAB_C5F5
   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_C5F9
   INY                ; increment table index
   LDA    LAB_C09E-1,Y    ; get table byte
   BPL    LAB_C5F9        ; loop if not end of word yet

   LDA    LAB_C09E,Y        ; get byte from keyword table
   BNE    LAB_C5B8        ; 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_C5C7        ; branch always, all unmatched bytes in the buffer are
                   ; $00 to $7F, go save byte in output and continue crunching

                   ; reached [EOL]
LAB_C609
   STA    LAB_0200-3,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_C613
   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_C617
   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_C640        ; 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_C641        ; exit if temp < this line, target line passed

   BEQ    LAB_C62E        ; go check low byte if =

   DEY                ; else decrement index
   BNE    LAB_C637        ; branch always

LAB_C62E
   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_C641        ; exit if temp < this line, target line passed

   BEQ    LAB_C641        ; exit if temp = (found line#)

                   ; not quite there yet
LAB_C637
   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_C617        ; go search for line # in temporary integer
                   ; from AX, carry always set

LAB_C640
   CLC                ; clear found flag
LAB_C641
   RTS


;***********************************************************************************;
;
; perform NEW

LAB_C642
   BNE    LAB_C641        ; exit if following byte to allow syntax error

LAB_C644
   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_C659
   JSR    LAB_C68E        ; set BASIC execute pointer to start of memory - 1
   LDA    #$00            ; set Zb for CLR entry


;***********************************************************************************;
;
; perform CLR

LAB_C65E
   BNE    LAB_C68D        ; exit if following byte to allow syntax error

LAB_C660
   JSR    LAB_FFE7        ; close all channels and files
LAB_C663
   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 the stack

LAB_C677
   JSR    LAB_C81D        ; perform RESTORE

; flush BASIC stack and clear the continue pointer

LAB_C67A
   LDX    #LAB_19        ; get descriptor stack start
   STX    LAB_16        ; set descriptor stack pointer
   PLA                ; pull return address low byte
   TAY                ; copy it
   PLA                ; pull return address high byte
   LDX    #$FA            ; set cleared stack pointer
   TXS                ; set stack
   PHA                ; push return address high byte
   TYA                ; restore return address low byte
   PHA                ; push return address low byte
   LDA    #$00            ; clear A
   STA    LAB_3E        ; clear continue pointer high byte
   STA    LAB_10        ; clear subscript/FNX flag
LAB_C68D
   RTS


;***********************************************************************************;
;
; set BASIC execute pointer to start of memory - 1

LAB_C68E
   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_C69C
   BCC    LAB_C6A4        ; branch if next character not token (LIST n...)

   BEQ    LAB_C6A4        ; branch if next character [NULL] (LIST)

   CMP    #TK_MINUS        ; compare with token for -
   BNE    LAB_C68D        ; exit if not - (LIST -m)

                   ; LIST [[n][-m]]
                   ; this bit sets the n , if present, as the start and end
LAB_C6A4
   JSR    LAB_C96B        ; get fixed-point number into temporary integer
   JSR    LAB_C613        ; search BASIC for temporary integer line number
   JSR    LAB_0079        ; scan memory
   BEQ    LAB_C6BB        ; branch if no more chrs

                   ; this bit checks the - is present
   CMP    #TK_MINUS        ; compare with "-"
   BNE    LAB_C641        ; 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_C96B        ; get fixed-point number into temporary integer
   BNE    LAB_C641        ; exit if not ok

LAB_C6BB
   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_C6C9        ; 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_C6C9
   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_C714        ; if null all done so exit

   JSR    LAB_C82C        ; do CRTL-C check vector
   JSR    LAB_CAD7        ; 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_C6E6        ; branch if no high byte match

   CPX    LAB_14        ; compare with temporary integer low byte
   BEQ    LAB_C6E8        ; branch if = last line to do, < will pass next branch

LAB_C6E6                ; else ...
   BCS    LAB_C714        ; if greater all done so exit

LAB_C6E8
   STY    LAB_49        ; save index for line
   JSR    LAB_DDCD        ; print XA as unsigned integer
   LDA    #' '            ; space is the next character
LAB_C6EF
   LDY    LAB_49        ; get index for line
   AND    #$7F            ; mask top out bit of character
LAB_C6F3
   JSR    LAB_CB47        ; go print the character
   CMP    #$22            ; was it " character
   BNE    LAB_C700        ; 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_C700
   INY                ; increment index
   BEQ    LAB_C714        ; line too long so just bail out and do a warm start

   LDA    (LAB_5F),Y        ; get next byte
   BNE    LAB_C717        ; 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_C6C9        ; go do next line if not [EOT]
                   ; else ...
LAB_C714
   JMP    LAB_C474        ; do warm start


;***********************************************************************************;
;
LAB_C717
   JMP    (LAB_0306)        ; do uncrunch BASIC tokens


;***********************************************************************************;
;
; uncrunch BASIC tokens, the uncrunch BASIC tokens vector is initialised to point here

LAB_C71A
   BPL    LAB_C6F3        ; 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_C6F3        ; just print it if so

   BIT    LAB_0F        ; test the open quote flag
   BMI    LAB_C6F3        ; 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_C72C
   DEX                ; decrement token #
   BEQ    LAB_C737        ; if now found go do printing

LAB_C72F
   INY                ; else increment index
   LDA    LAB_C09E,Y        ; get byte from keyword table
   BPL    LAB_C72F        ; loop until keyword end marker

   BMI    LAB_C72C        ; go test if this is required keyword, branch always

                   ; found keyword, it's the next one
LAB_C737
   INY                ; increment keyword table index
   LDA    LAB_C09E,Y        ; get byte from table
   BMI    LAB_C6EF        ; go restore index, mask byte and print if
                   ; byte was end marker

   JSR    LAB_CB47        ; else go print the character
   BNE    LAB_C737        ; go get next character, branch always


;***********************************************************************************;
;
; perform FOR

LAB_C742
   LDA    #$80            ; set FNX
   STA    LAB_10        ; set subscript/FNX flag
   JSR    LAB_C9A5        ; perform LET
   JSR    LAB_C38A        ; search the stack for FOR or GOSUB activity
   BNE    LAB_C753        ; 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_C753
   PLA                ; pull return address
   PLA                ; pull return address
   LDA    #$09            ; we need 18d bytes !
   JSR    LAB_C3FB        ; check room on stack for 2*A bytes
   JSR    LAB_C906        ; 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_CEFF        ; scan for CHR$(A), else do syntax error then warm start
   JSR    LAB_CD8D        ; check if source is numeric, else do type mismatch
   JSR    LAB_CD8A        ; 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    #    LDY    #>LAB_C78B        ; set return address high byte
   STA    LAB_22        ; save return address low byte
   STY    LAB_23        ; save return address high byte
   JMP    LAB_CE43        ; round FAC1 and put on stack, returns to next instruction

LAB_C78B
   LDA    #    LDY    #>LAB_D9BC        ; set 1 pointer high address
   JSR    LAB_DBA2        ; unpack memory (AY) into FAC1
   JSR    LAB_0079        ; scan memory
   CMP    #TK_STEP        ; compare with STEP token
   BNE    LAB_C79F        ; branch if not "STEP"

                   ; was step so ....
   JSR    LAB_0073        ; increment and scan memory
   JSR    LAB_CD8A        ; evaluate expression and check is numeric, else do
                   ; type mismatch
LAB_C79F
   JSR    LAB_DC2B        ; get FAC1 sign, return A = $FF -ve, A = $01 +ve
   JSR    LAB_CE38        ; 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_C7AE
   JSR    LAB_C82C        ; do CRTL-C check vector
   LDA    LAB_7A        ; get BASIC execute pointer low byte
   LDY    LAB_7B        ; get BASIC execute pointer high byte
   CPY    #$02            ; compare with $02xx
   NOP                ; unused byte                            ##
   BEQ    LAB_C7BE        ; 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_C7BE
   LDY    #$00            ; clear the index
   LDA    (LAB_7A),Y        ; get BASIC byte
   BNE    LAB_C807        ; 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_C7CE        ; branch if not end of program

   JMP    LAB_C84B        ; else go to immediate mode,was immediate or [EOT] marker

LAB_C7CE
   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_C7E1        ; if no overflow skip the high byte increment

   INC    LAB_7B        ; else increment BASIC execute pointer high byte
LAB_C7E1
   JMP    (LAB_0308)        ; do start new BASIC code


;***********************************************************************************;
;
; start new BASIC code, the start new BASIC code vector is initialised to point here

LAB_C7E4
   JSR    LAB_0073        ; increment and scan memory
   JSR    LAB_C7ED        ; go interpret BASIC code from BASIC execute pointer
   JMP    LAB_C7AE        ; loop


;***********************************************************************************;
;
; go interpret BASIC code from BASIC execute pointer

LAB_C7ED
   BEQ    LAB_C82B        ; if the first byte is null just exit

LAB_C7EF
   SBC    #$80            ; normalise the token
   BCC    LAB_C804        ; if wasn't token go do LET

   CMP    #TK_TAB-$80        ; compare with token for TAB(-$80
   BCS    LAB_C80E        ; branch if >= TAB(

   ASL                ; *2 bytes per vector
   TAY                ; copy to index
   LDA    LAB_C00C+1,Y    ; get vector high byte
   PHA                ; push on stack
   LDA    LAB_C00C,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_C804
   JMP    LAB_C9A5        ; perform LET

                   ; was not [EOL]
LAB_C807
   CMP    #':'            ; comapre with ":"
   BEQ    LAB_C7E1        ; if ":" go execute new code

                   ; else ...
LAB_C80B
   JMP    LAB_CF08        ; do syntax error then warm start

                   ; token was >= TAB(
LAB_C80E
   CMP    #TK_GO-$80        ; compare with token for GO
   BNE    LAB_C80B        ; 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_CEFF        ; scan for CHR$(A), else do syntax error then warm start
   JMP    LAB_C8A0        ; perform GOTO


;***********************************************************************************;
;
; perform RESTORE

LAB_C81D
   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_C827        ; if no rollunder skip the high byte decrement

   DEY                ; else decrement high byte
LAB_C827
   STA    LAB_41        ; set DATA pointer low byte
   STY    LAB_42        ; set DATA pointer high byte
LAB_C82B
   RTS


;***********************************************************************************;
;
; do CRTL-C check vector

LAB_C82C
   JSR    LAB_FFE1        ; scan stop key


;***********************************************************************************;
;
; perform STOP

LAB_C82F
   BCS    LAB_C832        ; if carry set do BREAK instead of just END


;***********************************************************************************;
;
; perform END

LAB_C831
   CLC                ; clear carry
LAB_C832
   BNE    LAB_C870        ; 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_C849        ; 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_C849
   PLA                ; dump return address low byte
   PLA                ; dump return address high byte
LAB_C84B
   LDA    #    LDY    #>LAB_C381        ; set [CR][LF]"BREAK" pointer high byte
   BCC    LAB_C854        ; branch if was program end

   JMP    LAB_C469        ; print string and do warm start

LAB_C854
   JMP    LAB_C474        ; do warm start


;***********************************************************************************;
;
; perform CONT

LAB_C857
   BNE    LAB_C870        ; 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_C862        ; go do continue if we can

   JMP    LAB_C437        ; else do error #X then warm start

                   ; we can continue so ...
LAB_C862
   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_C870
   RTS


;***********************************************************************************;
;
; perform RUN

LAB_C871
   PHP                ; save status
   LDA    #$00            ; no control or kernal messages
   JSR    LAB_FF90        ; control kernal messages
   PLP                ; restore status
   BNE    LAB_C87D        ; branch if RUN n

   JMP    LAB_C659        ; reset execution to start, clear variables, flush stack
                   ; and return
LAB_C87D
   JSR    LAB_C660        ; go do "CLEAR"
   JMP    LAB_C897        ; get n and do GOTO n


;***********************************************************************************;
;
; perform GOSUB

LAB_C883
   LDA    #$03            ; need 6 bytes for GOSUB
   JSR    LAB_C3FB        ; 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_C897
   JSR    LAB_0079        ; scan memory
   JSR    LAB_C8A0        ; perform GOTO
   JMP    LAB_C7AE        ; go do interpreter inner loop


;***********************************************************************************;
;
; perform GOTO

LAB_C8A0
   JSR    LAB_C96B        ; get fixed-point number into temporary integer
   JSR    LAB_C909        ; 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_C8BC        ; 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_C8C0        ; if no overflow skip the high byte increment

   INX                ; increment high byte
   BCS    LAB_C8C0        ; go find the line, branch always


;***********************************************************************************;
;
; search for line number in temporary integer from start of memory pointer

LAB_C8BC
   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_C8C0
   JSR    LAB_C617        ; search Basic for temp integer line number from AX
   BCC    LAB_C8E3        ; 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_C8D1
   RTS


;***********************************************************************************;
;
; perform RETURN

LAB_C8D2
   BNE    LAB_C8D1        ; 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_C38A        ; 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_C8EB        ; 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_C8E3
   LDX    #$11            ; error code $11, undefined statement error
   JMP    LAB_C437        ; do error #X then warm start

LAB_C8E8
   JMP    LAB_CF08        ; do syntax error then warm start

                   ; was matching GOSUB token
LAB_C8EB
   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_C8F8
   JSR    LAB_C906        ; scan for next BASIC statement ([:] or [EOL])

; add Y to the BASIC execute pointer

LAB_C8FB
   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_C905        ; skip increment if no carry

   INC    LAB_7B        ; else increment BASIC execute pointer high byte
LAB_C905
   RTS


;***********************************************************************************;
;
; scan for next BASIC statement ([:] or [EOL])
; returns Y as index to [:] or [EOL]

LAB_C906
   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_C909
   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_C911
   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_C919
   LDA    (LAB_7A),Y        ; get BASIC byte
   BEQ    LAB_C905        ; exit if null [EOL]

   CMP    LAB_08        ; compare with search character
   BEQ    LAB_C905        ; exit if found

   INY                ; else increment index
   CMP    #$22            ; compare current character with open quote
   BNE    LAB_C919        ; if found go swap search character for alternate search
                   ; character

   BEQ    LAB_C911        ; loop for next character, branch always


;***********************************************************************************;
;
; perform IF

LAB_C928
   JSR    LAB_CD9E        ; evaluate expression
   JSR    LAB_0079        ; scan memory
   CMP    #TK_GOTO        ; compare with "GOTO" token
   BEQ    LAB_C937        ; if it was the token for GOTO go do IF ... GOTO

                   ; wasn't IF ... GOTO so must be IF ... THEN
   LDA    #TK_THEN        ; $A7 = "THEN" token
   JSR    LAB_CEFF        ; scan for CHR$(A), else do syntax error then warm start
LAB_C937
   LDA    LAB_61        ; get FAC1 exponent
   BNE    LAB_C940        ; if result was non zero continue execution
                   ; else REM the rest of the line


;***********************************************************************************;
;
; perform REM

LAB_C93B
   JSR    LAB_C909        ; scan for next BASIC line
   BEQ    LAB_C8FB        ; add Y to the BASIC execute pointer and return, branch
                   ; always


;***********************************************************************************;
;
; IF continued .. result was non zero so do rest of line

LAB_C940
   JSR    LAB_0079        ; scan memory
   BCS    LAB_C948        ; if not numeric character, is variable or keyword

   JMP    LAB_C8A0        ; else perform GOTO n

                   ; is variable or keyword
LAB_C948
   JMP    LAB_C7ED        ; interpret BASIC code from BASIC execute pointer


;***********************************************************************************;
;
; perform ON

LAB_C94B
   JSR    LAB_D79E        ; get byte parameter
   PHA                ; push next character
   CMP    #TK_GOSUB        ; compare with GOSUB token
   BEQ    LAB_C957        ; if GOSUB go see if it should be executed

LAB_C953
   CMP    #TK_GOTO        ; compare with GOTO token
   BNE    LAB_C8E8        ; if not GOTO do syntax error then warm start

; next character was GOTO or GOSUB, see if it should be executed

LAB_C957
   DEC    LAB_65        ; decrement the byte value
   BNE    LAB_C95F        ; if not zero go see if another line number exists

   PLA                ; pull keyword token
   JMP    LAB_C7EF        ; go execute it

LAB_C95F
   JSR    LAB_0073        ; increment and scan memory
   JSR    LAB_C96B        ; get fixed-point number into temporary integer
                   ; skip this n
   CMP    #','            ; compare next character with ","
   BEQ    LAB_C957        ; loop if ","

   PLA                ; else pull keyword token, ran out of options
LAB_C96A
   RTS


;***********************************************************************************;
;
; get fixed-point number into temporary integer

LAB_C96B
   LDX    #$00            ; clear X
   STX    LAB_14        ; clear temporary integer low byte
   STX    LAB_15        ; clear temporary integer high byte
LAB_C971
   BCS    LAB_C96A        ; return if carry set, end of scan, character was not 0-9

   SBC    #$2F            ; 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_C953        ; 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_C8E8 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_C955 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_C99F        ; if no overflow skip high byte increment

   INC    LAB_15        ; else increment high byte
LAB_C99F
   JSR    LAB_0073        ; increment and scan memory
   JMP    LAB_C971        ; loop for next character


;***********************************************************************************;
;
; perform LET

LAB_C9A5
   JSR    LAB_D08B        ; 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_CEFF        ; 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_CD9E        ; evaluate expression
   PLA                ; pop data type flag
   ROL                ; string bit into carry
   JSR    LAB_CD90        ; do type match check
   BNE    LAB_C9D9        ; if string go assign a string value

   PLA                ; pop integer/float data type flag

; assign value to numeric variable

LAB_C9C2
   BPL    LAB_C9D6        ; if float go assign a floating value

                   ; expression is numeric integer
   JSR    LAB_DC1B        ; round FAC1
   JSR    LAB_D1BF        ; 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_C9D6
   JMP    LAB_DBD0        ; pack FAC1 into variable pointer and return

; assign value to string variable

LAB_C9D9
   PLA                ; dump integer/float data type flag
LAB_C9DA
   LDY    LAB_4A        ; get variable pointer high byte
   CPY    #>LAB_DF13        ; was it TI$ pointer
   BNE    LAB_CA2C        ; branch if not

                   ; else it's TI$ =
   JSR    LAB_D6A6        ; 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_CA24        ; 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_C9ED
   STY    LAB_71        ; save index
   JSR    LAB_CA1D        ; check and evaluate numeric digit
   JSR    LAB_DAE2        ; multiply FAC1 by 10
   INC    LAB_71        ; increment index
   LDY    LAB_71        ; restore index
   JSR    LAB_CA1D        ; check and evaluate numeric digit
   JSR    LAB_DC0C        ; round and copy FAC1 to FAC2
   TAX                ; copy FAC1 exponent
   BEQ    LAB_CA07        ; branch if FAC1 zero

   INX                ; increment index, * 2
   TXA                ; copy back to A
   JSR    LAB_DAED        ; FAC1 = (FAC1 + (FAC2 * 2)) * 2 = FAC1 * 6
LAB_CA07
   LDY    LAB_71        ; get index
   INY                ; increment index
   CPY    #$06            ; compare index with 6
   BNE    LAB_C9ED        ; loop if not 6

   JSR    LAB_DAE2        ; multiply FAC1 by 10
   JSR    LAB_DC9B        ; 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_CA1D
   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_CA27        ; branch if numeric

LAB_CA24
   JMP    LAB_D248        ; do illegal quantity error then warm start

LAB_CA27
   SBC    #$2F            ; subtract $2F + carry to convert ASCII to binary
   JMP    LAB_DD7E        ; evaluate new ASCII digit and return

; assign value to string variable, but not TI$

LAB_CA2C
   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_CA4B        ; branch if string pointer high byte is less than bottom
                   ; of string space high byte

   BNE    LAB_CA3D        ; 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_CA4B        ; branch if string pointer low byte is less than bottom
                   ; of string space low byte

LAB_CA3D
   LDY    LAB_65        ; get descriptor pointer high byte
   CPY    LAB_2E        ; compare with start of variables high byte
   BCC    LAB_CA4B        ; branch if less, is on string stack

   BNE    LAB_CA52        ; 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_CA52        ; if greater or equal make space and copy string

LAB_CA4B
   LDA    LAB_64        ; get descriptor pointer low byte
   LDY    LAB_65        ; get descriptor pointer high byte
   JMP    LAB_CA68        ; go copy descriptor to variable

LAB_CA52
   LDY    #$00            ; clear index
   LDA    (LAB_64),Y        ; get string length
   JSR    LAB_D475        ; 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_D67A        ; copy string from descriptor to utility pointer
   LDA    #    LDY    #>LAB_61        ; get descriptor pointer high byte
LAB_CA68
   STA    LAB_50        ; save descriptor pointer low byte
   STY    LAB_51        ; save descriptor pointer high byte
   JSR    LAB_D6DB        ; 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_CA80
   JSR    LAB_CA86        ; perform CMD
   JMP    LAB_CBB5        ; close input and output channels and return


;***********************************************************************************;
;
; perform CMD

LAB_CA86
   JSR    LAB_D79E        ; get byte parameter
   BEQ    LAB_CA90        ; branch if following byte is ":" or [EOT]

   LDA    #','            ; set ","
   JSR    LAB_CEFF        ; scan for CHR$(A), else do syntax error then warm start
LAB_CA90
   PHP                ; save status
   STX    LAB_13        ; set current I/O channel
   JSR    LAB_E115        ; open channel for output with error check
   PLP                ; restore status
   JMP    LAB_CAA0        ; perform PRINT


;***********************************************************************************;
;
; print string, scan memory and continue PRINT

LAB_CA9A
   JSR    LAB_CB21        ; print string from utility pointer

; scan memory and continue PRINT

LAB_CA9D
   JSR    LAB_0079        ; scan memory


;***********************************************************************************;
;
; perform PRINT

LAB_CAA0
   BEQ    LAB_CAD7        ; if nothing following just print CR/LF

LAB_CAA2
   BEQ    LAB_CAE7        ; if nothing following exit, end of PRINT branch

   CMP    #TK_TAB        ; compare with token for TAB(
   BEQ    LAB_CAF8        ; if TAB( go handle it

   CMP    #TK_SPC        ; compare with token for SPC(
   CLC                ; flag SPC(
   BEQ    LAB_CAF8        ; if SPC( go handle it

   CMP    #','            ; compare with ","
   BEQ    LAB_CAE8        ; if "," go skip to the next TAB position

   CMP    #$3B            ; compare with ";"
   BEQ    LAB_CB13        ; if ";" go continue the print loop

   JSR    LAB_CD9E        ; evaluate expression
   BIT    LAB_0D        ; test data type flag, $FF = string, $00 = numeric
   BMI    LAB_CA9A        ; if string go print string, scan memory and continue PRINT

   JSR    LAB_DDDD        ; convert FAC1 to ASCII string result in (AY)
   JSR    LAB_D487        ; print " terminated string to utility pointer
   JSR    LAB_CB21        ; print string from utility pointer
   JSR    LAB_CB3B        ; print [SPACE] or [CURSOR RIGHT]
   BNE    LAB_CA9D        ; go scan memory and continue PRINT, branch always


;***********************************************************************************;
;
; set XY to LAB_0200 - 1 and print [CR]

LAB_CACA
   LDA    #$00            ; clear A
   STA    LAB_0200,X        ; clear first byte of input buffer
   LDX    #LAB_0200 - 1 low byte
   LDY    #>LAB_01FF        ; LAB_0200 - 1 high byte
   LDA    LAB_13        ; get current I/O channel
   BNE    LAB_CAE7        ; exit if not default channel


;***********************************************************************************;
;
; print CR/LF

LAB_CAD7
   LDA    #$0D            ; set [CR]
   JSR    LAB_CB47        ; print the character
   BIT    LAB_13        ; test current I/O channel
   BPL    LAB_CAE5        ; if the AutoLF bit is not set skip the LF

; it would seem from other parts of the code that using b7 as an AutoLF flag bit is
; no longer supported and setting this bit would break things in a lot of places

   LDA    #$0A            ; set [LF]
   JSR    LAB_CB47        ; print the character


;***********************************************************************************;
;
; toggle A

LAB_CAE5
   EOR    #$FF            ; invert A
LAB_CAE7
   RTS


;***********************************************************************************;
;
; continuing PRINT, the character was ","

LAB_CAE8
   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_CAEE
   SBC    #$0B            ; subtract one TAB length
   BCS    LAB_CAEE        ; loop if result was +ve

   EOR    #$FF            ; complement it
   ADC    #$01            ; +1, twos complement
   BNE    LAB_CB0E        ; print A spaces, branch always, result is never $00


;***********************************************************************************;
;
; handle TAB( or SPC(

LAB_CAF8
   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_D79B        ; scan and get byte parameter
   CMP    #$29            ; compare with ")"
   BNE    LAB_CB5F        ; if not ")" do syntax error

   PLP                ; restore TAB( or SPC( status
   BCC    LAB_CB0F        ; branch if was SPC(

                   ; else was TAB(
   TXA                ; copy TAB() byte to A
   SBC    LAB_09        ; subtract current cursor position
   BCC    LAB_CB13        ; go loop for next if already past requited position

LAB_CB0E
   TAX                ; copy [SPACE] count to X
LAB_CB0F
   INX                ; increment count
LAB_CB10
   DEX                ; decrement count
   BNE    LAB_CB19        ; branch if count was not zero

                   ; was ";" or [SPACES] printed
LAB_CB13
   JSR    LAB_0073        ; increment and scan memory
   JMP    LAB_CAA2        ; continue print loop

LAB_CB19
   JSR    LAB_CB3B        ; print [SPACE] or [CURSOR RIGHT]
   BNE    LAB_CB10        ; loop, branch always


;***********************************************************************************;
;
; print null terminated string

LAB_CB1E
   JSR    LAB_D487        ; print " terminated string to utility pointer

; print string from utility pointer

LAB_CB21
   JSR    LAB_D6A6        ; 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_CB28
   DEX                ; decrement length
   BEQ    LAB_CAE7        ; exit if done

   LDA    (LAB_22),Y        ; get byte from string
   JSR    LAB_CB47        ; print the character
   INY                ; increment index
   CMP    #$0D            ; compare byte with [CR]
   BNE    LAB_CB28        ; loop if not [CR]

   JSR    LAB_CAE5        ; toggle A, EOR #$FF. what is the point of this ??
   JMP    LAB_CB28        ; loop


;***********************************************************************************;
;
; print [SPACE] or [CURSOR RIGHT]

LAB_CB3B
   LDA    LAB_13        ; get current I/O channel
   BEQ    LAB_CB42        ; if default channel go output [CURSOR RIGHT]

   LDA    #' '            ; else output [SPACE]
   .byte    $2C            ; makes next line BIT LAB_1DA9
LAB_CB42
   LDA    #$1D            ; set [CURSOR RIGHT]
   .byte    $2C            ; makes next line BIT LAB_3FA9


;***********************************************************************************;
;
; print "?"

LAB_CB45
   LDA    #'?'            ; set "?"


;***********************************************************************************;
;
; print a character

LAB_CB47
   JSR    LAB_E109        ; output character to channel with error check
   AND    #$FF            ; set the flags on A
   RTS


;***********************************************************************************;
;
; bad input routine

LAB_CB4D
   LDA    LAB_11        ; get INPUT mode flag, $00 = INPUT, $40 = GET, $98 = READ
   BEQ    LAB_CB62        ; branch if INPUT

   BMI    LAB_CB57        ; branch if READ

                   ; else was GET
   LDY    #$FF            ; set current line high byte to -1, indicate immediate mode
   BNE    LAB_CB5B        ; branch always

LAB_CB57
   LDA    LAB_3F        ; get current DATA line number low byte
   LDY    LAB_40        ; get current DATA line number high byte
LAB_CB5B
   STA    LAB_39        ; set current line number low byte
   STY    LAB_3A        ; set current line number high byte
LAB_CB5F
   JMP    LAB_CF08        ; do syntax error then warm start

                   ; was INPUT
LAB_CB62
   LDA    LAB_13        ; get current I/O channel
   BEQ    LAB_CB6B        ; if default channel go do "?REDO FROM START" message

   LDX    #$18            ; else error $18, file data error
   JMP    LAB_C437        ; do error #X then warm start

LAB_CB6B
   LDA    #    LDY    #>LAB_CD0C        ; set "?REDO FROM START" pointer high byte
   JSR    LAB_CB1E        ; 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_CB7B
   JSR    LAB_D3A6        ; check not Direct, back here if ok
   CMP    #'#'            ; compare with "#"
   BNE    LAB_CB92        ; branch if not GET#

   JSR    LAB_0073        ; increment and scan memory
   JSR    LAB_D79E        ; get byte parameter
   LDA    #','            ; set ","
   JSR    LAB_CEFF        ; scan for CHR$(A), else do syntax error then warm start
   STX    LAB_13        ; set current I/O channel
   JSR    LAB_E11B        ; open channel for input with error check
LAB_CB92
   LDX    #LAB_0200+1 pointer low byte
   LDY    #>LAB_0201        ; set LAB_0200+1 pointer high byte
   LDA    #$00            ; clear A
   STA    LAB_0200+1        ; ensure null terminator
   LDA    #$40            ; input mode = GET
   JSR    LAB_CC0F        ; perform GET part of READ
   LDX    LAB_13        ; get current I/O channel
   BNE    LAB_CBB7        ; if not default channel go do channel close and return

   RTS


;***********************************************************************************;
;
; perform INPUT#

LAB_CBA5
   JSR    LAB_D79E        ; get byte parameter
   LDA    #','            ; set ","
   JSR    LAB_CEFF        ; scan for CHR$(A), else do syntax error then warm start
   STX    LAB_13        ; set current I/O channel
   JSR    LAB_E11B        ; open channel for input with error check
   JSR    LAB_CBCE        ; perform INPUT with no prompt string

; close input and output channels

LAB_CBB5
   LDA    LAB_13        ; get current I/O channel
LAB_CBB7
   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_CBBF
   CMP    #$22            ; compare next byte with open quote
   BNE    LAB_CBCE        ; if no prompt string just do INPUT

   JSR    LAB_CEBD        ; print "..." string
   LDA    #$3B            ; load A with ";"
   JSR    LAB_CEFF        ; scan for CHR$(A), else do syntax error then warm start
   JSR    LAB_CB21        ; print string from utility pointer

                   ; done with prompt, now get data
LAB_CBCE
   JSR    LAB_D3A6        ; check not Direct, back here if ok
   LDA    #','            ; set ","
   STA    LAB_0200-1        ; save to start of buffer - 1
LAB_CBD6
   JSR    LAB_CBF9        ; print "? " and get BASIC input
   LDA    LAB_13        ; get current I/O channel
   BEQ    LAB_CBEA        ; branch if default I/O channel

   JSR    LAB_FFB7        ; read I/O status word
   AND    #$02            ; mask no DSR/timeout
   BEQ    LAB_CBEA        ; branch if not error

   JSR    LAB_CBB5        ; close input and output channels
   JMP    LAB_C8F8        ; perform DATA

LAB_CBEA
   LDA    LAB_0200        ; get first byte in input buffer
   BNE    LAB_CC0D        ; branch if not null

                   ; else ..
   LDA    LAB_13        ; get current I/O channel
   BNE    LAB_CBD6        ; if not default channel go get BASIC input

   JSR    LAB_C906        ; scan for next BASIC statement ([:] or [EOL])
   JMP    LAB_C8FB        ; add Y to the BASIC execute pointer and return


;***********************************************************************************;
;
; print "? " and get BASIC input

LAB_CBF9
   LDA    LAB_13        ; get current I/O channel
   BNE    LAB_CC03        ; skip "?" prompt if not default channel

   JSR    LAB_CB45        ; print "?"
   JSR    LAB_CB3B        ; print [SPACE] or [CURSOR RIGHT]
LAB_CC03
   JMP    LAB_C560        ; call for BASIC input and return


;***********************************************************************************;
;
; perform READ

LAB_CC06
   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_CC0D
   LDA    #$00            ; set input mode = INPUT


;***********************************************************************************;
;
; perform GET

LAB_CC0F
   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_CC15
   JSR    LAB_D08B        ; 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_CC51        ; branch if not null

                   ; pointer was to null entry
   BIT    LAB_11        ; test input mode flag, $00 = INPUT, $40 = GET, $98 = READ
   BVC    LAB_CC41        ; branch if not GET

                   ; else was GET
   JSR    LAB_E121        ; get character from input device with error check
   STA    LAB_0200        ; save to buffer
   LDX    #LAB_0200-1 pointer low byte
   LDY    #>LAB_01FF        ; set LAB_0200-1 pointer high byte
   BNE    LAB_CC4D        ; go interpret single character

LAB_CC41
   BMI    LAB_CCB8        ; if READ go get some DATA

; else it was INPUT

   LDA    LAB_13        ; get current I/O channel
   BNE    LAB_CC4A        ; skip "?" prompt if not default channel

   JSR    LAB_CB45        ; print "?"
LAB_CC4A
   JSR    LAB_CBF9        ; print "? " and get BASIC input
LAB_CC4D
   STX    LAB_7A        ; save BASIC execute pointer low byte
   STY    LAB_7B        ; save BASIC execute pointer high byte
LAB_CC51
   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_CC89        ; branch if numeric

                   ; type is string
   BIT    LAB_11        ; test INPUT mode flag, $00 = INPUT, $40 = GET, $98 = READ
   BVC    LAB_CC65        ; 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_CC71        ; branch always

                   ; is string INPUT or string READ
LAB_CC65
   STA    LAB_07        ; save search character
   CMP    #$22            ; compare with "
   BEQ    LAB_CC72        ; if quote only search for "..." string

                   ; else the string is not in quotes so ":", "," or $00 are
                   ; the termination characters
   LDA    #':'            ; set ":"
   STA    LAB_07        ; set search character
   LDA    #','            ; set ","
LAB_CC71
   CLC                ; clear carry for add
LAB_CC72
   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_CC7D        ; if no rollover skip the high byte increment

   INY                ; else increment pointer high byte
LAB_CC7D
   JSR    LAB_D48D        ; print string to utility pointer
   JSR    LAB_D7E2        ; restore BASIC execute pointer from temp
   JSR    LAB_C9DA        ; perform string LET
   JMP    LAB_CC91        ; continue processing command

                   ; GET, INPUT or READ is numeric
LAB_CC89
   JSR    LAB_DCF3        ; get FAC1 from string
   LDA    LAB_0E        ; get data type flag, $80 = integer, $00 = float
   JSR    LAB_C9C2        ; assign value to numeric variable
LAB_CC91
   JSR    LAB_0079        ; scan memory
   BEQ    LAB_CC9D        ; if ":" or [EOL] go handle the string end

   CMP    #','            ; comparte with ","
   BEQ    LAB_CC9D        ; if "," go handle the string end

   JMP    LAB_CB4D        ; else go do bad input routine

                   ; string terminated with ":", "," or $00
LAB_CC9D
   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_CCDF        ; branch if ":" or [EOL]

   JSR    LAB_CEFD        ; scan for ",", else do syntax error then warm start
   JMP    LAB_CC15        ; go READ or INPUT next variable from list

                   ; was READ
LAB_CCB8
   JSR    LAB_C906        ; scan for next BASIC statement ([:] or [EOL])
   INY                ; increment index to next byte
   TAX                ; copy byte to X
   BNE    LAB_CCD1        ; if ":" go look for the next DATA

   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_CD32        ; if program end go do error, 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_CCD1
   JSR    LAB_C8FB        ; add Y to the BASIC execute pointer
   JSR    LAB_0079        ; scan memory
   TAX                ; copy byte
   CPX    #TK_DATA        ; compare with token for DATA
   BNE    LAB_CCB8        ; loop if not DATA

   JMP    LAB_CC51        ; continue evaluating READ

LAB_CCDF
   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_CCEA        ; if INPUT or GET go exit or ignore extra input

   JMP    LAB_C827        ; else set data pointer and exit

LAB_CCEA
   LDY    #$00            ; clear index
   LDA    (LAB_43),Y        ; get READ byte
   BEQ    LAB_CCFB        ; exit if [EOL]

   LDA    LAB_13        ; get current I/O channel
   BNE    LAB_CCFB        ; exit if not default channel

   LDA    #    LDY    #>LAB_CCFC        ; set "?EXTRA IGNORED" pointer high byte
   JMP    LAB_CB1E        ; print null terminated string

LAB_CCFB
   RTS


;***********************************************************************************;
;
; input error messages

LAB_CCFC
   .byte    "?EXTRA IGNORED",$0D,$00

LAB_CD0C
   .byte    "?REDO FROM START",$0D,$00


;***********************************************************************************;
;
; perform NEXT

LAB_CD1E
   BNE    LAB_CD24        ; if NEXT variable go find the variable

   LDY    #$00            ; else clear Y
   BEQ    LAB_CD27        ; use any variable, branch always

; NEXT variable

LAB_CD24
   JSR    LAB_D08B        ; get variable address
LAB_CD27
   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_C38A        ; search the stack for FOR or GOSUB activity
   BEQ    LAB_CD35        ; if FOR found continue

   LDX    #$0A            ; else set error $0A, next without for error
LAB_CD32
   JMP    LAB_C437        ; do error #X then warm start

; found this FOR variable

LAB_CD35
   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_DBA2        ; 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_D867        ; add FOR variable to FAC1
   JSR    LAB_DBD0        ; pack FAC1 into FOR variable
   LDY    #$01            ; point to stack page
   JSR    LAB_DC5D        ; 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_CD78        ; if = loop complete, go unstack the FOR

                   ; 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_0100+$10,X    ; get FOR line high byte
   STA    LAB_3A        ; save current line number high byte
   LDA    LAB_0100+$12,X    ; get BASIC execute pointer low byte
   STA    LAB_7A        ; save BASIC execute pointer low byte
   LDA    LAB_0100+$11,X    ; get BASIC execute pointer high byte
   STA    LAB_7B        ; save BASIC execute pointer high byte
LAB_CD75
   JMP    LAB_C7AE        ; go do interpreter inner loop

; NEXT loop comlete

LAB_CD78
   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_CD75        ; if not "," go do interpreter inner loop

                   ; was "," so another NEXT variable to do
   JSR    LAB_0073        ; increment and scan memory
   JSR    LAB_CD24        ; do NEXT variable


;***********************************************************************************;
;
; evaluate expression and check type mismatch

LAB_CD8A
   JSR    LAB_CD9E        ; evaluate expression

; check if source and destination are numeric

LAB_CD8D
   CLC
   .byte    $24            ; makes next line BIT LAB_38

; check if source and destination are string

LAB_CD8F
   SEC                ; destination is string

; type match check, set C for string, clear C for numeric

LAB_CD90
   BIT    LAB_0D        ; test data type flag, $FF = string, $00 = numeric
   BMI    LAB_CD97        ; if string go check string is required

; type found is numeric, check required

   BCS    LAB_CD99        ; if string is required go do type missmatch error
LAB_CD96
   RTS

; type found is string, check required

LAB_CD97
   BCS    LAB_CD96        ; exit if string is required

; do type missmatch error

LAB_CD99
   LDX    #$16            ; error code $16, type missmatch error
   JMP    LAB_C437        ; do error #X then warm start


;***********************************************************************************;
;
; evaluate expression

LAB_CD9E
   LDX    LAB_7A        ; get BASIC execute pointer low byte
   BNE    LAB_CDA4        ; skip next if not zero

   DEC    LAB_7B        ; else decrement BASIC execute pointer high byte
LAB_CDA4
   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_CDA9
   PHA                ; push compare evaluation byte if branch to here
   TXA                ; copy precedence byte
   PHA                ; push precedence byte
   LDA    #$01            ; 2 bytes
   JSR    LAB_C3FB        ; check room on stack for A*2 bytes
   JSR    LAB_CE83        ; get value from line
   LDA    #$00            ; clear A
   STA    LAB_4D        ; clear comparrison evaluation flag
LAB_CDB8
   JSR    LAB_0079        ; scan memory
LAB_CDBB
   SEC                ; set carry for subtract
   SBC    #TK_GT        ; subtract token for ">"
   BCC    LAB_CDD7        ; if < ">" skip comparrison test check

   CMP    #$03            ; compare with ">" to +3
   BCS    LAB_CDD7        ; if >= 3 skip comparrison test check

                   ; 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_CE30        ; 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_CDBB        ; go do next character

LAB_CDD7
   LDX    LAB_4D        ; get comparrison evaluation flag
   BNE    LAB_CE07        ; if compare function flagged go evaluate right hand side

   BCS    LAB_CE58        ; go do functions

                   ; else was < TK_GT so is operator or lower
   ADC    #$07            ; add # of operators (+, -, *, /, ^, AND or OR)
   BCC    LAB_CE58        ; if < + operator go do the function

                   ; carry was set so token was +, -, *, /, ^, AND or OR
   ADC    LAB_0D        ; add data type flag, $FF = string, $00 = numeric
   BNE    LAB_CDE8        ; if not string or not + token skip concatenate

                   ; will only be $00 if type is string and token was +
   JMP    LAB_D63D        ; add strings, string 1 is in the descriptor, string 2
                   ; is in line, and return

LAB_CDE8
   ADC    #$FF            ; -1 (corrects for carry add)
   STA    LAB_22        ; save it
   ASL                ; *2
   ADC    LAB_22        ; *3
   TAY                ; copy to index
LAB_CDF0
   PLA                ; pull previous precedence
   CMP    LAB_C080,Y        ; compare with precedence byte
   BCS    LAB_CE5D        ; if A >= go do the function

   JSR    LAB_CD8D        ; check if source is numeric, else do type mismatch
LAB_CDF9
   PHA                ; save precedence
LAB_CDFA
   JSR    LAB_CE20        ; get vector, execute function then continue evaluation
   PLA                ; restore precedence
   LDY    LAB_4B        ; get precedence stacked flag
   BPL    LAB_CE19        ; if stacked values go check the precedence

   TAX                ; copy precedence, set flags
   BEQ    LAB_CE5B        ; exit if done

   BNE    LAB_CE66        ; else pop FAC2 and return, branch always

LAB_CE07
   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_CE11        ; if no underflow skip the high byte decrement

   DEC    LAB_7B        ; else decrement BASIC execute pointer high byte
LAB_CE11
   DEC    LAB_7A        ; decrement BASIC execute pointer low byte
   LDY    #LAB_C09B-LAB_C080
                   ; set offset to = operator precedence entry
   STA    LAB_4D        ; save new comparrison evaluation flag
   BNE    LAB_CDF0        ; branch always

LAB_CE19
   CMP    LAB_C080,Y        ; compare with stacked function precedence
   BCS    LAB_CE66        ; if A >=, pop FAC2 and return

   BCC    LAB_CDF9        ; else go stack this one and continue, branch always


;***********************************************************************************;
;
; get vector, execute function then continue evaluation

LAB_CE20
   LDA    LAB_C080+2,Y    ; get function vector high byte
   PHA                ; onto stack
   LDA    LAB_C080+1,Y    ; get function vector low byte
   PHA                ; onto stack
                   ; now push sign, round FAC1 and put on stack
   JSR    LAB_CE33        ; function will return here, then the next RTS will call
                   ; the function
   LDA    LAB_4D        ; get comparrison evaluation flag
   JMP    LAB_CDA9        ; continue evaluating expression

LAB_CE30
   JMP    LAB_CF08        ; do syntax error then warm start

LAB_CE33
   LDA    LAB_66        ; get FAC1 sign (b7)
   LDX    LAB_C080,Y        ; get precedence byte


;***********************************************************************************;
;
; push sign, round FAC1 and put on stack

LAB_CE38
   TAY                ; copy sign
   PLA                ; get return address low byte
   STA    LAB_22        ; save it
   INC    LAB_22        ; increment it as return-1 is pushed
                   ; note, no check is made on the high byte so if the calling
                   ; routine ever assembles to a page edge then this all goes
                   ; horribly wrong!
   PLA                ; get return address high byte
   STA    LAB_23        ; save it
   TYA                ; restore sign
   PHA                ; push sign


;***********************************************************************************;
;
; round FAC1 and put on stack

LAB_CE43
   JSR    LAB_DC1B        ; round FAC1
   LDA    LAB_65        ; get FAC1 mantissa 4
   PHA                ; save it
   LDA    LAB_64        ; get FAC1 mantissa 3
   PHA                ; save it
   LDA    LAB_63        ; get FAC1 mantissa 2
   PHA                ; save it
   LDA    LAB_62        ; get FAC1 mantissa 1
   PHA                ; save it
   LDA    LAB_61        ; get FAC1 exponent
   PHA                ; save it
   JMP    (LAB_22)        ; return, sort of


;***********************************************************************************;
;
; do functions

LAB_CE58
   LDY    #$FF            ; flag function
   PLA                ; pull precedence byte
LAB_CE5B
   BEQ    LAB_CE80        ; exit if done

LAB_CE5D
   CMP    #$64            ; compare previous precedence with $64
   BEQ    LAB_CE64        ; if was $64 (< function) skip the type check

   JSR    LAB_CD8D        ; check if source is numeric, else do type mismatch
LAB_CE64
   STY    LAB_4B        ; save precedence stacked flag

                   ; pop FAC2 and return
LAB_CE66
   PLA                ; pop byte
   LSR                ; shift out comparison evaluation lowest bit
   STA    LAB_12        ; save the comparison evaluation flag
   PLA                ; pop exponent
   STA    LAB_69        ; save FAC2 exponent
   PLA                ; pop mantissa 1
   STA    LAB_6A        ; save FAC2 mantissa 1
   PLA                ; pop mantissa 2
   STA    LAB_6B        ; save FAC2 mantissa 2
   PLA                ; pop mantissa 3
   STA    LAB_6C        ; save FAC2 mantissa 3
   PLA                ; pop mantissa 4
   STA    LAB_6D        ; save FAC2 mantissa 4
   PLA                ; pop sign
   STA    LAB_6E        ; save FAC2 sign (b7)
   EOR    LAB_66        ; EOR FAC1 sign (b7)
   STA    LAB_6F        ; save sign compare (FAC1 EOR FAC2)
LAB_CE80
   LDA    LAB_61        ; get FAC1 exponent
   RTS


;***********************************************************************************;
;
; get value from line

LAB_CE83
   JMP    (LAB_030A)        ; get arithmetic element


;***********************************************************************************;
;
; get arithmetic element, the get arithmetic element vector is initialised to point here

LAB_CE86
   LDA    #$00            ; clear byte
   STA    LAB_0D        ; clear data type flag, $FF = string, $00 = numeric
LAB_CE8A
   JSR    LAB_0073        ; increment and scan memory
   BCS    LAB_CE92        ; if not numeric character continue

; else numeric string found (e.g. 123)

LAB_CE8F
   JMP    LAB_DCF3        ; get FAC1 from string and return

; get value from line .. continued, wasn't a number so ...

LAB_CE92
   JSR    LAB_D113        ; check byte, return Cb = 0 if<"A" or >"Z"
   BCC    LAB_CE9A        ; if not variable name continue

   JMP    LAB_CF28        ; variable name set-up and return

; get value from line .. continued, wasn't a variable name so ...

LAB_CE9A
   CMP    #TK_PI        ; compare with token for PI
   BNE    LAB_CEAD        ; if not PI continue

; else return PI in FAC1

   LDA    #    LDY    #>LAB_CEA8        ; get PI pointer high byte
   JSR    LAB_DBA2        ; unpack memory (AY) into FAC1
   JMP    LAB_0073        ; increment and scan memory and return


;***********************************************************************************;
;
; PI as floating number

LAB_CEA8
   .byte    $82,$49,$0F,$DA,$A1
                   ; 3.141592653


;***********************************************************************************;
;
; get value from line .. continued, wasn't PI so ...

LAB_CEAD
   CMP    #'.'            ; compare with "."
   BEQ    LAB_CE8F        ; if so get FAC1 from string and return, e.g. was .123

                   ; wasn't .123 so ...
   CMP    #TK_MINUS        ; compare with token for -
   BEQ    LAB_CF0D        ; if - token, do set-up for functions

                   ; wasn't -123 so ...
   CMP    #TK_PLUS        ; compare with token for +
   BEQ    LAB_CE8A        ; if + token ignore the leading +, +1 = 1

                   ; it wasn't any sort of number so ...
   CMP    #$22            ; compare with "
   BNE    LAB_CECC        ; if not open quote continue

                   ; was open quote so get the enclosed string

; print "..." string to string utility area

LAB_CEBD
   LDA    LAB_7A        ; get BASIC execute pointer low byte
   LDY    LAB_7B        ; get BASIC execute pointer high byte
   ADC    #$00            ; add carry to low byte
   BCC    LAB_CEC6        ; branch if no overflow

   INY                ; increment high byte
LAB_CEC6
   JSR    LAB_D487        ; print " terminated string to utility pointer
   JMP    LAB_D7E2        ; restore BASIC execute pointer from temp and return

; get value from line .. continued, wasn't a string so ...

LAB_CECC
   CMP    #TK_NOT        ; compare with token for NOT
   BNE    LAB_CEE3        ; if not token for NOT continue

; was NOT token

   LDY    #$18            ; offset to NOT function
   BNE    LAB_CF0F        ; do set-up for function then execute, branch always

; do = compare

LAB_CED4
   JSR    LAB_D1BF        ; evaluate integer expression, no sign check
   LDA    LAB_65        ; get FAC1 mantissa 4
   EOR    #$FF            ; invert it
   TAY                ; copy it
   LDA    LAB_64        ; get FAC1 mantissa 3
   EOR    #$FF            ; invert it
   JMP    LAB_D391        ; convert fixed integer AY to float FAC1 and return

; get value from line .. continued, wasn't NOT so ...

LAB_CEE3
   CMP    #TK_FN        ; compare with token for FN
   BNE    LAB_CEEA        ; if not token for FN continue

   JMP    LAB_D3F4        ; else go evaluate FNx

; get value from line .. continued, wasn't FN so ...

LAB_CEEA
   CMP    #TK_SGN        ; compare with token for SGN
   BCC    LAB_CEF1        ; if less than SGN token go evaluate expression in ()

                   ; else was a function token
   JMP    LAB_CFA7        ; go set up function references, branch always


;***********************************************************************************;
;
; get value from line .. continued
; if here it can only be something in brackets so ....

; evaluate expression within parentheses

LAB_CEF1
   JSR    LAB_CEFA        ; scan for "(", else do syntax error then warm start
   JSR    LAB_CD9E        ; evaluate expression


;***********************************************************************************;
;
; all the 'scan for' routines return the character after the sought character

; scan for ")", else do syntax error then warm start

LAB_CEF7
   LDA    #$29            ; load A with ")"
   .byte    $2C            ; makes next line BIT LAB_28A9

; scan for "(", else do syntax error then warm start

LAB_CEFA
   LDA    #$28            ; load A with "("
   .byte    $2C            ; makes next line BIT LAB_2CA9

; scan for ",", else do syntax error then warm start

LAB_CEFD
   LDA    #','            ; load A with ","

; scan for CHR$(A), else do syntax error then warm start

LAB_CEFF
   LDY    #$00            ; clear index
   CMP    (LAB_7A),Y        ; compare with BASIC byte
   BNE    LAB_CF08        ; if not expected byte do syntax error then warm start

   JMP    LAB_0073        ; else increment and scan memory and return


;***********************************************************************************;
;
; syntax error then warm start

LAB_CF08
   LDX    #$0B            ; error code $0B, syntax error
   JMP    LAB_C437        ; do error #X then warm start

LAB_CF0D
   LDY    #$15            ; set offset from base to > operator
LAB_CF0F
   PLA                ; dump return address low byte
   PLA                ; dump return address high byte
   JMP    LAB_CDFA        ; execute function then continue evaluation


;***********************************************************************************;
;
; check address range, return Cb = 1 if address in BASIC ROM

LAB_CF14
   SEC                ; set carry for subtract
   LDA    LAB_64        ; get variable address low byte
   SBC    #$00            ; subtract $C000 low byte
   LDA    LAB_65        ; get variable address high byte
   SBC    #$C0            ; subtract $C000 high byte
   BCC    LAB_CF27        ; exit if address < $C000

   LDA    #    SBC    LAB_64        ; subtract variable address low byte
   LDA    #>LAB_E387        ; get end of BASIC marker high byte
   SBC    LAB_65        ; subtract variable address high byte
LAB_CF27
   RTS


;***********************************************************************************;
;
; variable name set-up

LAB_CF28
   JSR    LAB_D08B        ; get variable address
   STA    LAB_64        ; save variable pointer low byte
   STY    LAB_65        ; save variable pointer high byte
   LDX    LAB_45        ; get current variable name first character
   LDY    LAB_46        ; get current variable name second character
   LDA    LAB_0D        ; get data type flag, $FF = string, $00 = numeric
   BEQ    LAB_CF5D        ; if numeric go handle a numeric variable

; variable is string

   LDA    #$00            ; else clear A
   STA    LAB_70        ; clear FAC1 rounding byte
   JSR    LAB_CF14        ; check address range
   BCC    LAB_CF5C        ; exit if not in BASIC ROM

   CPX    #'T'            ; compare variable name first character with "T"
   BNE    LAB_CF5C        ; exit if not "T"

   CPY    #'I'+$80        ; compare variable name second character with "I$"
   BNE    LAB_CF5C        ; exit if not "I$"

                   ; variable name was "TI$"
   JSR    LAB_CF84        ; read real time clock into FAC1 mantissa, 0HML
   STY    LAB_5E        ; clear exponent count adjust
   DEY                ; Y = $FF
   STY    LAB_71        ; set output string index, -1 to allow for pre increment
   LDY    #$06            ; HH:MM:SS is six digits
   STY    LAB_5D        ; set number of characters before the decimal point
   LDY    #LAB_DF3A-LAB_DF16
                   ; index to jiffy conversion table
   JSR    LAB_DE68        ; convert jiffy count to string
   JMP    LAB_D46F        ; exit via STR$() code tail

LAB_CF5C
   RTS

; variable name set-up, variable is numeric

LAB_CF5D
   BIT    LAB_0E        ; test data type flag, $80 = integer, $00 = float
   BPL    LAB_CF6E        ; if float go handle float

; else handle integer variable

   LDY    #$00            ; clear index
   LDA    (LAB_64),Y        ; get integer variable low byte
   TAX                ; copy to X
   INY                ; increment index
   LDA    (LAB_64),Y        ; get integer variable high byte
   TAY                ; copy to Y
   TXA                ; copy loa byte to A
   JMP    LAB_D391        ; convert fixed integer AY to float FAC1 and return

; variable name set-up, variable is float

LAB_CF6E
   JSR    LAB_CF14        ; check address range
   BCC    LAB_CFA0        ; if not in BASIC ROM get pointer and unpack into FAC1

   CPX    #'T'            ; compare variable name first character with "T"
   BNE    LAB_CF92        ; if not "T" skip Tx variables

   CPY    #'I'            ; compare variable name second character with "I"
   BNE    LAB_CFA0        ; if not "I" go do plain float

                   ; variable name was "TI"
   JSR    LAB_CF84        ; read real time clock into FAC1 mantissa, 0HML
   TYA                ; clear A
   LDX    #$A0            ; set exponent to 32 bit value
   JMP    LAB_DC4F        ; set exponent = X and normalise FAC1


;***********************************************************************************;
;
; read real time clock into FAC1 mantissa, 0HML

LAB_CF84
   JSR    LAB_FFDE        ; read real time clock
   STX    LAB_64        ; save jiffy clock mid byte as FAC1 mantissa 3
   STY    LAB_63        ; save jiffy clock high byte as FAC1 mantissa 2
   STA    LAB_65        ; save jiffy clock low byte as FAC1 mantissa 4
   LDY    #$00            ; clear Y
   STY    LAB_62        ; clear FAC1 mantissa 1
   RTS


;***********************************************************************************;
;
; variable name set-up, variable is float and not "Tx"

LAB_CF92
   CPX    #'S'            ; compare variable name first character with "S"
   BNE    LAB_CFA0        ; if not "S" go do normal floating variable

   CPY    #'T'            ; compare variable name second character with "
   BNE    LAB_CFA0        ; if not "T" go do normal floating variable

                   ; variable name was "ST"
   JSR    LAB_FFB7        ; read I/O status word
   JMP    LAB_DC3C        ; save A as integer byte and return

; variable is plain float

LAB_CFA0
   LDA    LAB_64        ; get variable pointer low byte
   LDY    LAB_65        ; get variable pointer high byte
   JMP    LAB_DBA2        ; unpack memory (AY) into FAC1


;***********************************************************************************;
;
; get value from line continued
; only functions left so ..

; set up function references

LAB_CFA7
   ASL                ; *2 (2 bytes per function address)
   PHA                ; save function offset
   TAX                ; copy function offset
   JSR    LAB_0073        ; increment and scan memory
   CPX    #$8F            ; compare function offset to CHR$ token offset+1
   BCC    LAB_CFD1        ; if < LEFT$ (can not be =) go do function setup

; get value from line .. continued
; was LEFT$, RIGHT$ or MID$ so..

   JSR    LAB_CEFA        ; scan for "(", else do syntax error then warm start
   JSR    LAB_CD9E        ; evaluate, should be string, expression
   JSR    LAB_CEFD        ; scan for ",", else do syntax error then warm start
   JSR    LAB_CD8F        ; check if source is string, else do type mismatch
   PLA                ; restore function offset
   TAX                ; copy it
   LDA    LAB_65        ; get descriptor pointer high byte
   PHA                ; push string pointer high byte
   LDA    LAB_64        ; get descriptor pointer low byte
   PHA                ; push string pointer low byte
   TXA                ; restore function offset
   PHA                ; save function offset
   JSR    LAB_D79E        ; get byte parameter
   PLA                ; restore function offset
   TAY                ; copy function offset
   TXA                ; copy byte parameter to A
   PHA                ; push byte parameter
   JMP    LAB_CFD6        ; go call function

; get value from line .. continued
; was SGN() to CHR$() so..

LAB_CFD1
   JSR    LAB_CEF1        ; evaluate expression within parentheses
   PLA                ; restore function offset
   TAY                ; copy to index
LAB_CFD6
   LDA    LAB_C052-$68,Y    ; get function jump vector low byte
   STA    LAB_55        ; save functions jump vector low byte
   LDA    LAB_C052-$67,Y    ; get function jump vector high byte
   STA    LAB_56        ; save functions jump vector high byte
   JSR    LAB_54        ; do function call
   JMP    LAB_CD8D        ; check if source is numeric and RTS, else do type mismatch
                   ; string functions avoid this by dumping the return address


;***********************************************************************************;
;
; perform OR
; this works because NOT(NOT(x) AND NOT(y)) = x OR y

LAB_CFE6
   LDY    #$FF            ; set Y for OR
   .byte    $2C            ; makes next line BIT LAB_00A0


;***********************************************************************************;
;
; perform AND

LAB_CFE9
   LDY    #$00            ; clear Y for AND
   STY    LAB_0B        ; set AND/OR invert value
   JSR    LAB_D1BF        ; evaluate integer expression, no sign check
   LDA    LAB_64        ; get FAC1 mantissa 3
   EOR    LAB_0B        ; EOR low byte
   STA    LAB_07        ; save it
   LDA    LAB_65        ; get FAC1 mantissa 4
   EOR    LAB_0B        ; EOR high byte
   STA    LAB_08        ; save it
   JSR    LAB_DBFC        ; copy FAC2 to FAC1, get 2nd value in expression
   JSR    LAB_D1BF        ; evaluate integer expression, no sign check
   LDA    LAB_65        ; get FAC1 mantissa 4
   EOR    LAB_0B        ; EOR high byte
   AND    LAB_08        ; AND with expression 1 high byte
   EOR    LAB_0B        ; EOR result high byte
   TAY                ; save in Y
   LDA    LAB_64        ; get FAC1 mantissa 3
   EOR    LAB_0B        ; EOR low byte
   AND    LAB_07        ; AND with expression 1 low byte
   EOR    LAB_0B        ; EOR result low byte
   JMP    LAB_D391        ; convert fixed integer AY to float FAC1 and return


;***********************************************************************************;
;
; perform comparisons

; do < compare

LAB_D016
   JSR    LAB_CD90        ; type match check, set C for string
   BCS    LAB_D02E        ; if string go do string compare

                   ; do numeric < compare
   LDA    LAB_6E        ; get FAC2 sign (b7)
   ORA    #$7F            ; set all non sign bits
   AND    LAB_6A        ; and FAC2 mantissa 1 (AND in sign bit)
   STA    LAB_6A        ; save FAC2 mantissa 1
   LDA    #    LDY    #>LAB_69        ; set pointer high byte to FAC2
   JSR    LAB_DC5B        ; compare FAC1 with (AY)
   TAX                ; copy the result
   JMP    LAB_D061        ; go evaluate result

; do string < compare

LAB_D02E
   LDA    #$00            ; clear byte
   STA    LAB_0D        ; clear data type flag, $FF = string, $00 = numeric
   DEC    LAB_4D        ; clear < bit in comparrison evaluation flag
   JSR    LAB_D6A6        ; pop string off descriptor stack, or from top of string
                   ; space returns with A = length, X = pointer low byte,
                   ; Y = pointer high byte
   STA    LAB_61        ; save length
   STX    LAB_62        ; save string pointer low byte
   STY    LAB_63        ; save string pointer high byte
   LDA    LAB_6C        ; get descriptor pointer low byte
   LDY    LAB_6D        ; get descriptor pointer high byte
   JSR    LAB_D6AA        ; pop (YA) descriptor off stack or from top of string space
                   ; returns with A = length, X = pointer low byte,
                   ; Y = pointer high byte
   STX    LAB_6C        ; save string pointer low byte
   STY    LAB_6D        ; save string pointer high byte
   TAX                ; copy length
   SEC                ; set carry for subtract
   SBC    LAB_61        ; subtract string 1 length
   BEQ    LAB_D056        ; if str 1 length = string 2 length go compare the strings

   LDA    #$01            ; set str 1 length > string 2 length
   BCC    LAB_D056        ; if so return + 1 if otherwise equal

   LDX    LAB_61        ; get string 1 length
   LDA    #$FF            ; set str 1 length < string 2 length
LAB_D056
   STA    LAB_66        ; save length compare
   LDY    #$FF            ; set index
   INX                ; adjust for loop
LAB_D05B
   INY                ; increment index
   DEX                ; decrement count
   BNE    LAB_D066        ; if still bytes to do go compare them

   LDX    LAB_66        ; get length compare back
LAB_D061
   BMI    LAB_D072        ; branch if str 1 < str 2

   CLC                ; flag str 1 <= str 2
   BCC    LAB_D072        ; go evaluate result, branch always

LAB_D066
   LDA    (LAB_6C),Y        ; get string 2 byte
   CMP    (LAB_62),Y        ; compare with string 1 byte
   BEQ    LAB_D05B        ; loop if bytes =

   LDX    #$FF            ; set str 1 < string 2
   BCS    LAB_D072        ; branch if so

   LDX    #$01            ; set str 1 > string 2
LAB_D072
   INX                ; x = 0, 1 or 2
   TXA                ; copy to A
   ROL                ; * 2 (1, 2 or 4)
   AND    LAB_12        ; AND with the comparison evaluation flag
   BEQ    LAB_D07B        ; branch if 0 (compare is false)

   LDA    #$FF            ; else set result true
LAB_D07B
   JMP    LAB_DC3C        ; save A as integer byte and return

LAB_D07E
   JSR    LAB_CEFD        ; scan for ",", else do syntax error then warm start


;***********************************************************************************;
;
; perform DIM

LAB_D081
   TAX                ; copy "DIM" flag to X
   JSR    LAB_D090        ; search for variable
   JSR    LAB_0079        ; scan memory
   BNE    LAB_D07E        ; scan for "," and loop if not null

   RTS


;***********************************************************************************;
;
; search for variable

LAB_D08B
   LDX    #$00            ; set DIM flag = $00
   JSR    LAB_0079        ; scan memory, 1st character
LAB_D090
   STX    LAB_0C        ; save DIM flag
LAB_D092
   STA    LAB_45        ; save 1st character
   JSR    LAB_0079        ; scan memory
   JSR    LAB_D113        ; check byte, return Cb = 0 if<"A" or >"Z"
   BCS    LAB_D09F        ; if ok continue

LAB_D09C
   JMP    LAB_CF08        ; else syntax error then warm start

; was variable name so ...

LAB_D09F
   LDX    #$00            ; clear 2nd character temp
   STX    LAB_0D        ; clear data type flag, $FF = string, $00 = numeric
   STX    LAB_0E        ; clear data type flag, $80 = integer, $00 = float
   JSR    LAB_0073        ; increment and scan memory, 2nd character
   BCC    LAB_D0AF        ; if character = "0"-"9" (ok) go save 2nd character

                   ; 2nd character wasn't "0" to "9" so ...
   JSR    LAB_D113        ; check byte, return Cb = 0 if<"A" or >"Z"
   BCC    LAB_D0BA        ; if <"A" or >"Z" go check if string

LAB_D0AF
   TAX                ; copy 2nd character

                   ; ignore further (valid) characters in the variable name
LAB_D0B0
   JSR    LAB_0073        ; increment and scan memory, 3rd character
   BCC    LAB_D0B0        ; loop if character = "0"-"9" (ignore)

   JSR    LAB_D113        ; check byte, return Cb = 0 if<"A" or >"Z"
   BCS    LAB_D0B0        ; loop if character = "A"-"Z" (ignore)

                   ; check if string variable
LAB_D0BA
   CMP    #'$'            ; compare with "$"
   BNE    LAB_D0C4        ; if not string go check integer

                   ; type is string
   LDA    #$FF            ; set data type = string
   STA    LAB_0D        ; set data type flag, $FF = string, $00 = numeric
   BNE    LAB_D0D4        ; branch always

LAB_D0C4
   CMP    #$25            ; compare with "%"
   BNE    LAB_D0DB        ; if not integer go check for an array

   LDA    LAB_10        ; get subscript/FNX flag
   BNE    LAB_D09C        ; if ?? do syntax error then warm start

   LDA    #$80            ; set integer type
   STA    LAB_0E        ; set data type = integer
   ORA    LAB_45        ; OR current variable name first byte
   STA    LAB_45        ; save current variable name first byte
LAB_D0D4
   TXA                ; get 2nd character back
   ORA    #$80            ; set top bit, indicate string or integer variable
   TAX                ; copy back to 2nd character temp
   JSR    LAB_0073        ; increment and scan memory
LAB_D0DB
   STX    LAB_46        ; save 2nd character
   SEC                ; set carry for subtract
   ORA    LAB_10        ; or with subscript/FNX flag - or FN name
   SBC    #$28            ; subtract "("
   BNE    LAB_D0E7        ; if not "(" go find a plain numeric variable

   JMP    LAB_D1D1        ; else go find, or make, array

; either find or create variable

                   ; variable name wasn't xx(.... so look for plain variable
LAB_D0E7
   LDY    #$00            ; clear A
   STY    LAB_10        ; clear subscript/FNX flag
   LDA    LAB_2D        ; get start of variables low byte
   LDX    LAB_2E        ; get start of variables high byte
LAB_D0EF
   STX    LAB_60        ; save search address high byte
LAB_D0F1
   STA    LAB_5F        ; save search address low byte
   CPX    LAB_30        ; compare with end of variables high byte
   BNE    LAB_D0FB        ; skip next compare if <>

                   ; high addresses were = so compare low addresses
   CMP    LAB_2F        ; compare low address with end of variables low byte
   BEQ    LAB_D11D        ; if not found go make new variable

LAB_D0FB
   LDA    LAB_45        ; get 1st character of variable to find
   CMP    (LAB_5F),Y        ; compare with variable name 1st character
   BNE    LAB_D109        ; if no match go try the next variable

                   ; 1st characters match so compare 2nd character
   LDA    LAB_46        ; get 2nd character of variable to find
   INY                ; index to point to variable name 2nd character
   CMP    (LAB_5F),Y        ; compare with variable name 2nd character
   BEQ    LAB_D185        ; if match go return the variable

   DEY                ; else decrement index (now = $00)
LAB_D109
   CLC                ; clear carry for add
   LDA    LAB_5F        ; get search address low byte
   ADC    #$07            ; +7, offset to next variable name
   BCC    LAB_D0F1        ; loop if no overflow to high byte

   INX                ; else increment high byte
   BNE    LAB_D0EF        ; loop always, RAM doesn't extend to $FFFF


;***********************************************************************************;
;
; check byte, return Cb = 0 if<"A" or >"Z"

LAB_D113
   CMP    #$41            ; compare with "A"
   BCC    LAB_D11C        ; exit if less

                   ; carry is set
   SBC    #$5B            ; subtract "Z"+1
   SEC                ; set carry
   SBC    #$A5            ; subtract $A5 (restore byte)
                   ; carry clear if byte > $5A
LAB_D11C
   RTS


;***********************************************************************************;
;
                   ; reached end of variable memory without match
                   ; ... so create new variable
LAB_D11D
   PLA                ; pop return address low byte
   PHA                ; push return address low byte
   CMP    #$2A            ; compare with expected calling routine return low byte
   BNE    LAB_D128        ; if not get variable go create new variable

; this will only drop through if the call was from LAB_xxxx and is only called
; from there if it is searching for a variable from the right hand side of a LET a=b
; statement, it prevents the creation of variables not assigned a value.

; value returned by this is either numeric zero, exponent byte is $00, or null string,
; descriptor length byte is $00. in fact a pointer to any $00 byte would have done.

                   ; else return dummy null value
LAB_D123
   LDA    #    LDY    #>LAB_DF13        ; set result pointer high byte
   RTS

                   ; create new numeric variable
LAB_D128
   LDA    LAB_45        ; get variable name first character
   LDY    LAB_46        ; get variable name second character
   CMP    #'T'            ; compare first character with "T"
   BNE    LAB_D13B        ; if not "T" continue

   CPY    #'I'+$80        ; compare second character with "I$"
   BEQ    LAB_D123        ; if "I$" return null value

   CPY    #'I'            ; compare second character with "I"
   BNE    LAB_D13B        ; if not "I" continue

                   ; if name is "TI" do syntax error
LAB_D138
   JMP    LAB_CF08        ; do syntax error then warm start

LAB_D13B
   CMP    #'S'            ; compare first character with "S"
   BNE    LAB_D143        ; if not "S" continue

   CPY    #'T'            ; compare second character with "T"
   BEQ    LAB_D138        ; if name is "ST" do syntax error

LAB_D143
   LDA    LAB_2F        ; get end of variables low byte
   LDY    LAB_30        ; get end of variables high byte
   STA    LAB_5F        ; save old block start low byte
   STY    LAB_60        ; save old block start high byte
   LDA    LAB_31        ; get end of arrays low byte
   LDY    LAB_32        ; get end of arrays high byte
   STA    LAB_5A        ; save old block end low byte
   STY    LAB_5B        ; save old block end high byte
   CLC                ; clear carry for add
   ADC    #$07            ; +7, space for one variable
   BCC    LAB_D159        ; if no overflow skip the high byte increment

   INY                ; else increment high byte
LAB_D159
   STA    LAB_58        ; set new block end low byte
   STY    LAB_59        ; set new block end high byte
   JSR    LAB_C3B8        ; open up space in memory
   LDA    LAB_58        ; get new start low byte
   LDY    LAB_59        ; get new start high byte (-$100)
   INY                ; correct high byte
   STA    LAB_2F        ; set end of variables low byte
   STY    LAB_30        ; set end of variables high byte
   LDY    #$00            ; clear index
   LDA    LAB_45        ; get variable name 1st character
   STA    (LAB_5F),Y        ; save variable name 1st character
   INY                ; increment index
   LDA    LAB_46        ; get variable name 2nd character
   STA    (LAB_5F),Y        ; save variable name 2nd character
   LDA    #$00            ; clear A
   INY                ; increment index
   STA    (LAB_5F),Y        ; initialise variable byte
   INY                ; increment index
   STA    (LAB_5F),Y        ; initialise variable byte
   INY                ; increment index
   STA    (LAB_5F),Y        ; initialise variable byte
   INY                ; increment index
   STA    (LAB_5F),Y        ; initialise variable byte
   INY                ; increment index
   STA    (LAB_5F),Y        ; initialise variable byte

                   ; found a match for variable
LAB_D185
   LDA    LAB_5F        ; get variable address low byte
   CLC                ; clear carry for add
   ADC    #$02            ; +2, offset past variable name bytes
   LDY    LAB_60        ; get variable address high byte
   BCC    LAB_D18F        ; if no overflow skip the high byte increment

   INY                ; else increment high byte
LAB_D18F
   STA    LAB_47        ; save current variable pointer low byte
   STY    LAB_48        ; save current variable pointer high byte
   RTS


;***********************************************************************************;
;
; set-up array pointer to first element in array

LAB_D194
   LDA    LAB_0B        ; get # of dimensions (1, 2 or 3)
   ASL                ; *2 (also clears the carry !)
   ADC    #$05            ; +5 (result is 7, 9 or 11 here)
   ADC    LAB_5F        ; add array start pointer low byte
   LDY    LAB_60        ; get array pointer high byte
   BCC    LAB_D1A0        ; if no overflow skip the high byte increment

   INY                ; else increment high byte
LAB_D1A0
   STA    LAB_58        ; save array data pointer low byte
   STY    LAB_59        ; save array data pointer high byte
   RTS


;***********************************************************************************;
;
; -32768 as floating value

LAB_D1A5
   .byte    $90,$80,$00,$00,$00    ; -32768


;***********************************************************************************;
;
; convert float to fixed

LAB_D1AA
   JSR    LAB_D1BF        ; evaluate integer expression, no sign check
   LDA    LAB_64        ; get result low byte
   LDY    LAB_65        ; get result high byte
   RTS


;***********************************************************************************;
;
; evaluate integer expression

LAB_D1B2
   JSR    LAB_0073        ; increment and scan memory
   JSR    LAB_CD9E        ; evaluate expression

; evaluate integer expression, sign check

LAB_D1B8
   JSR    LAB_CD8D        ; check if source is numeric, else do type mismatch
   LDA    LAB_66        ; get FAC1 sign (b7)
   BMI    LAB_D1CC        ; do illegal quantity error if -ve

; evaluate integer expression, no sign check

LAB_D1BF
   LDA    LAB_61        ; get FAC1 exponent
   CMP    #$90            ; compare with exponent = 2^16 (n>2^15)
   BCC    LAB_D1CE        ; if n<2^16 go convert FAC1 floating to fixed and return

   LDA    #    LDY    #>LAB_D1A5        ; set pointer high byte to -32768
   JSR    LAB_DC5B        ; compare FAC1 with (AY)
LAB_D1CC
   BNE    LAB_D248        ; if <> do illegal quantity error then warm start

LAB_D1CE
   JMP    LAB_DC9B        ; convert FAC1 floating to fixed and return


;***********************************************************************************;
;
; an array is stored as follows
;
; array name            ; two bytes with the following patterns for different types
;                    ; 1st char    2nd char
;                    ; b7     b7        type            element size
;                    ; --------    --------    -----            ------------
;                    ; 0         0        floating point     5
;                    ; 0         1        string         3
;                    ; 1         1        integer         2
; offset to next array        ; word
; dimension count            ; byte
; 1st dimension size        ; word, this is the number of elements including 0
; 2nd dimension size        ; word, only here if the array has a second dimension
; 2nd dimension size        ; word, only here if the array has a third dimension
;                    ; note: the dimension size word is in high byte low byte
;                    ; format, not like most 6502 words
; then for each element the required number of bytes given as the element size above

; find or make array

LAB_D1D1
   LDA    LAB_0C        ; get DIM flag
   ORA    LAB_0E        ; OR with data type flag
   PHA                ; push it
   LDA    LAB_0D        ; get data type flag, $FF = string, $00 = numeric
   PHA                ; push it
   LDY    #$00            ; clear dimensions count

; now get the array dimension(s) and stack it (them) before the data type and DIM flag

LAB_D1DB
   TYA                ; copy dimensions count
   PHA                ; save it
   LDA    LAB_46        ; get array name 2nd byte
   PHA                ; save it
   LDA    LAB_45        ; get array name 1st byte
   PHA                ; save it
   JSR    LAB_D1B2        ; evaluate integer expression
   PLA                ; pull array name 1st byte
   STA    LAB_45        ; restore array name 1st byte
   PLA                ; pull array name 2nd byte
   STA    LAB_46        ; restore array name 2nd byte
   PLA                ; pull dimensions count
   TAY                ; restore it
   TSX                ; copy stack pointer
   LDA    LAB_0100+2,X    ; get DIM flag
   PHA                ; push it
   LDA    LAB_0100+1,X    ; get data type flag
   PHA                ; push it
   LDA    LAB_64        ; get this dimension size high byte
   STA    LAB_0100+2,X    ; stack before flag bytes
   LDA    LAB_65        ; get this dimension size low byte
   STA    LAB_0100+1,X    ; stack before flag bytes
   INY                ; increment dimensions count
   JSR    LAB_0079        ; scan memory
   CMP    #','            ; compare with ","
   BEQ    LAB_D1DB        ; if found go do next dimension

   STY    LAB_0B        ; store dimensions count
   JSR    LAB_CEF7        ; scan for ")", else do syntax error then warm start
   PLA                ; pull data type flag
   STA    LAB_0D        ; restore data type flag, $FF = string, $00 = numeric
   PLA                ; pull data type flag
   STA    LAB_0E        ; restore data type flag, $80 = integer, $00 = float
   AND    #$7F            ; mask dim flag
   STA    LAB_0C        ; restore DIM flag
   LDX    LAB_2F        ; set end of variables low byte
                   ; (array memory start low byte)
   LDA    LAB_30        ; set end of variables high byte
                   ; (array memory start high byte)

; now check to see if we are at the end of array memory, we would be if there were
; no arrays.

LAB_D21C
   STX    LAB_5F        ; save as array start pointer low byte
   STA    LAB_60        ; save as array start pointer high byte
   CMP    LAB_32        ; compare with end of arrays high byte
   BNE    LAB_D228        ; if not reached array memory end continue searching

   CPX    LAB_31        ; else compare with end of arrays low byte
   BEQ    LAB_D261        ; go build array if not found

                   ; search for array
LAB_D228
   LDY    #$00            ; clear index
   LDA    (LAB_5F),Y        ; get array name first byte
   INY                ; increment index to second name byte
   CMP    LAB_45        ; compare with this array name first byte
   BNE    LAB_D237        ; if no match go try the next array

   LDA    LAB_46        ; else get this array name second byte
   CMP    (LAB_5F),Y        ; compare with array name second byte
   BEQ    LAB_D24D        ; array found so branch

                   ; no match
LAB_D237
   INY                ; increment index
   LDA    (LAB_5F),Y        ; get array size low byte
   CLC                ; clear carry for add
   ADC    LAB_5F        ; add array start pointer low byte
   TAX                ; copy low byte to X
   INY                ; increment index
   LDA    (LAB_5F),Y        ; get array size high byte
   ADC    LAB_60        ; add array memory pointer high byte
   BCC    LAB_D21C        ; if no overflow go check next array

; do bad subscript error

LAB_D245
   LDX    #$12            ; error $12, bad subscript error
   .byte    $2C            ; makes next line BIT LAB_0EA2


;***********************************************************************************;
;
; do illegal quantity error

LAB_D248
   LDX    #$0E            ; error $0E, illegal quantity error
LAB_D24A
   JMP    LAB_C437        ; do error #X then warm start


;***********************************************************************************;
;
; array found

LAB_D24D
   LDX    #$13            ; set error $13, double dimension error
   LDA    LAB_0C        ; get DIM flag
   BNE    LAB_D24A        ; if we are trying to dimension it do error #X then warm
                   ; start

; found the array and we're not dimensioning it so we must find an element in it

   JSR    LAB_D194        ; set-up array pointer to first element in array
   LDA    LAB_0B        ; get dimensions count
   LDY    #$04            ; set index to array's # of dimensions
   CMP    (LAB_5F),Y        ; compare with no of dimensions
   BNE    LAB_D245        ; if wrong do bad subscript error

   JMP    LAB_D2EA        ; found array so go get element

                   ; array not found, so build it
LAB_D261
   JSR    LAB_D194        ; set-up array pointer to first element in array
   JSR    LAB_C408        ; check available memory, do out of memory error if no room
   LDY    #$00            ; clear Y
   STY    LAB_72        ; clear array data size high byte
   LDX    #$05            ; set default element size
   LDA    LAB_45        ; get variable name 1st byte
   STA    (LAB_5F),Y        ; save array name 1st byte
   BPL    LAB_D274        ; branch if not string or floating point array

   DEX                ; decrement element size, $04
LAB_D274
   INY                ; increment index
   LDA    LAB_46        ; get variable name 2nd byte
   STA    (LAB_5F),Y        ; save array name 2nd byte
   BPL    LAB_D27D        ; branch if not integer or string

   DEX                ; decrement element size, $03
   DEX                ; decrement element size, $02
LAB_D27D
   STX    LAB_71        ; save element size
   LDA    LAB_0B        ; get dimensions count
   INY                ; increment index ..
   INY                ; .. to array ..
   INY                ; .. dimension count
   STA    (LAB_5F),Y        ; save array dimension count
LAB_D286
   LDX    #$0B            ; set default dimension size low byte
   LDA    #$00            ; set default dimension size high byte
   BIT    LAB_0C        ; test DIM flag
   BVC    LAB_D296        ; if default to be used don't pull a dimension

   PLA                ; pull dimension size low byte
   CLC                ; clear carry for add
   ADC    #$01            ; add 1, allow for zeroeth element
   TAX                ; copy low byte to X
   PLA                ; pull dimension size high byte
   ADC    #$00            ; add carry to high byte
LAB_D296
   INY                ; incement index to dimension size high byte
   STA    (LAB_5F),Y        ; save dimension size high byte
   INY                ; incement index to dimension size low byte
   TXA                ; copy dimension size low byte
   STA    (LAB_5F),Y        ; save dimension size low byte
   JSR    LAB_D34C        ; compute array size
   STX    LAB_71        ; save result low byte
   STA    LAB_72        ; save result high byte
   LDY    LAB_22        ; restore index
   DEC    LAB_0B        ; decrement dimensions count
   BNE    LAB_D286        ; loop if not all done

   ADC    LAB_59        ; add array data pointer high byte
   BCS    LAB_D30B        ; if overflow do out of memory error then warm start

   STA    LAB_59        ; save array data pointer high byte
   TAY                ; copy array data pointer high byte
   TXA                ; copy array size low byte
   ADC    LAB_58        ; add array data pointer low byte
   BCC    LAB_D2B9        ; if no rollover skip the high byte increment

   INY                ; else increment next array pointer high byte
   BEQ    LAB_D30B        ; if rolled over do out of memory error then warm start

LAB_D2B9
   JSR    LAB_C408        ; 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

; now the aray is created we need to zero all the elements in it

   LDA    #$00            ; clear A for array clear
   INC    LAB_72        ; increment array size high byte, now block count
   LDY    LAB_71        ; get array size low byte, now index to block
   BEQ    LAB_D2CD        ; if $00 go do the high byte decrement
LAB_D2C8
   DEY                ; decrement index, do 0 to n-1
   STA    (LAB_58),Y        ; clear array element byte
   BNE    LAB_D2C8        ; loop until this block done

LAB_D2CD
   DEC    LAB_59        ; decrement array pointer high byte
   DEC    LAB_72        ; decrement block count high byte
   BNE    LAB_D2C8        ; loop until all blocks done

   INC    LAB_59        ; correct for last loop
   SEC                ; set carry for subtract
   LDA    LAB_31        ; get end of arrays low byte
   SBC    LAB_5F        ; subtract array start low byte
   LDY    #$02            ; index to array size low byte
   STA    (LAB_5F),Y        ; save array size low byte
   LDA    LAB_32        ; get end of arrays high byte
   INY                ; index to array size high byte
   SBC    LAB_60        ; subtract array start high byte
   STA    (LAB_5F),Y        ; save array size high byte
   LDA    LAB_0C        ; get default DIM flag
   BNE    LAB_D34B        ; exit if this was a DIM command

                   ; else, find element
   INY                ; set index to # of dimensions, the dimension indeces
                   ; are on the stack and will be removed as the position
                   ; of the array element is calculated

LAB_D2EA
   LDA    (LAB_5F),Y        ; get array's dimension count
   STA    LAB_0B        ; save it
   LDA    #$00            ; clear byte
   STA    LAB_71        ; clear array data pointer low byte
LAB_D2F2
   STA    LAB_72        ; save array data pointer high byte
   INY                ; increment index, point to array bound high byte
   PLA                ; pull array index low byte
   TAX                ; copy to X
   STA    LAB_64        ; save index low byte to FAC1 mantissa 3
   PLA                ; pull array index high byte
   STA    LAB_65        ; save index high byte to FAC1 mantissa 4
   CMP    (LAB_5F),Y        ; compare with array bound high byte
   BCC    LAB_D30E        ; if within bounds continue

   BNE    LAB_D308        ; if outside bounds do bad subscript error

                   ; else high byte was = so test low bytes
   INY                ; index to array bound low byte
   TXA                ; get array index low byte
   CMP    (LAB_5F),Y        ; compare with array bound low byte
   BCC    LAB_D30F        ; if within bounds continue

LAB_D308
   JMP    LAB_D245        ; do bad subscript error

LAB_D30B
   JMP    LAB_C435        ; do out of memory error then warm start

LAB_D30E
   INY                ; index to array bound low byte
LAB_D30F
   LDA    LAB_72        ; get array data pointer high byte
   ORA    LAB_71        ; OR with array data pointer low byte
   CLC                ; clear carry for either add, carry always clear here ??
   BEQ    LAB_D320        ; if array data pointer = null skip the multiply

   JSR    LAB_D34C        ; compute array size
   TXA                ; get result low byte
   ADC    LAB_64        ; add index low byte from FAC1 mantissa 3
   TAX                ; save result low byte
   TYA                ; get result high byte
   LDY    LAB_22        ; restore index
LAB_D320
   ADC    LAB_65        ; add index high byte from FAC1 mantissa 4
   STX    LAB_71        ; save array data pointer low byte
   DEC    LAB_0B        ; decrement dimensions count
   BNE    LAB_D2F2        ; loop if dimensions still to do

   STA    LAB_72        ; save array data pointer high byte
   LDX    #$05            ; set default element size
   LDA    LAB_45        ; get variable name 1st byte
   BPL    LAB_D331        ; branch if not string or floating point array

   DEX                ; decrement element size, $04
LAB_D331
   LDA    LAB_46        ; get variable name 2nd byte
   BPL    LAB_D337        ; branch if not integer or string

   DEX                ; decrement element size, $03
   DEX                ; decrement element size, $02
LAB_D337
   STX    LAB_28        ; save dimension size low byte
   LDA    #$00            ; clear dimension size high byte
   JSR    LAB_D355        ; compute array size
   TXA                ; copy array size low byte
   ADC    LAB_58        ; add array data start pointer low byte
   STA    LAB_47        ; save as current variable pointer low byte
   TYA                ; copy array size high byte
   ADC    LAB_59        ; add array data start pointer high byte
   STA    LAB_48        ; save as current variable pointer high byte
   TAY                ; copy high byte to Y
   LDA    LAB_47        ; get current variable pointer low byte
                   ; pointer to element is now in AY
LAB_D34B
   RTS


;***********************************************************************************;
;
; compute array size, result in XY

LAB_D34C
   STY    LAB_22        ; save index
   LDA    (LAB_5F),Y        ; get dimension size low byte
   STA    LAB_28        ; save dimension size low byte
   DEY                ; decrement index
   LDA    (LAB_5F),Y        ; get dimension size high byte
LAB_D355
   STA    LAB_29        ; save dimension size high byte
   LDA    #$10            ; count = $10 (16 bit multiply)
   STA    LAB_5D        ; save bit count
   LDX    #$00            ; clear result low byte
   LDY    #$00            ; clear result high byte
LAB_D35F
   TXA                ; get result low byte
   ASL                ; *2
   TAX                ; save result low byte
   TYA                ; get result high byte
   ROL                ; *2
   TAY                ; save result high byte
   BCS    LAB_D30B        ; if overflow go do "Out of memory" error

   ASL    LAB_71        ; shift element size low byte
   ROL    LAB_72        ; shift element size high byte
   BCC    LAB_D378        ; skip add if no carry

   CLC                ; else clear carry for add
   TXA                ; get result low byte
   ADC    LAB_28        ; add dimension size low byte
   TAX                ; save result low byte
   TYA                ; get result high byte
   ADC    LAB_29        ; add dimension size high byte
   TAY                ; save result high byte
   BCS    LAB_D30B        ; if overflow go do "Out of memory" error

LAB_D378
   DEC    LAB_5D        ; decrement bit count
   BNE    LAB_D35F        ; loop until all done

   RTS


;***********************************************************************************;
;
; perform FRE()

LAB_D37D
   LDA    LAB_0D        ; get data type flag, $FF = string, $00 = numeric
   BEQ    LAB_D384        ; if numeric don't pop the string

   JSR    LAB_D6A6        ; pop string off descriptor stack, or from top of string
                   ; space returns with A = length, X=$71=pointer low byte,
                   ; Y=$72=pointer high byte

                   ; FRE(n) was numeric so do this
LAB_D384
   JSR    LAB_D526        ; go do garbage collection
   SEC                ; set carry for subtract
   LDA    LAB_33        ; get bottom of string space low byte
   SBC    LAB_31        ; subtract end of arrays low byte
   TAY                ; copy result to Y
   LDA    LAB_34        ; get bottom of string space high byte
   SBC    LAB_32        ; subtract end of arrays high byte


;***********************************************************************************;
;
; convert fixed integer AY to float FAC1

LAB_D391
   LDX    #$00            ; set type = numeric
   STX    LAB_0D        ; clear data type flag, $FF = string, $00 = numeric
   STA    LAB_62        ; save FAC1 mantissa 1
   STY    LAB_63        ; save FAC1 mantissa 2
   LDX    #$90            ; set exponent=2^16 (integer)
   JMP    LAB_DC44        ; set exp = X, clear FAC1 3 and 4, normalise and return


;***********************************************************************************;
;
; perform POS()

LAB_D39E
   SEC                ; set Cb for read cursor position
   JSR    LAB_FFF0        ; read/set X,Y cursor position
LAB_D3A2
   LDA    #$00            ; clear high byte
   BEQ    LAB_D391        ; convert fixed integer AY to float FAC1, branch always


;***********************************************************************************;
;
; check not Direct, used by DEF and INPUT

LAB_D3A6
   LDX    LAB_3A        ; get current line number high byte
   INX                ; increment it
   BNE    LAB_D34B        ; return if not direct mode

                   ; else do illegal direct error
   LDX    #$15            ; error $15, illegal direct error
   .byte    $2C            ; makes next line BIT LAB_1BA2
LAB_D3AE
   LDX    #$1B            ; error $1B, undefined function error
   JMP    LAB_C437        ; do error #X then warm start


;***********************************************************************************;
;
; perform DEF

LAB_D3B3
   JSR    LAB_D3E1        ; check FNx syntax
   JSR    LAB_D3A6        ; check not direct, back here if ok
   JSR    LAB_CEFA        ; scan for "(", else do syntax error then warm start
   LDA    #$80            ; set flag for FNx
   STA    LAB_10        ; save subscript/FNx flag
   JSR    LAB_D08B        ; get variable address
   JSR    LAB_CD8D        ; check if source is numeric, else do type mismatch
   JSR    LAB_CEF7        ; scan for ")", else do syntax error then warm start
   LDA    #TK_EQUAL        ; get = token
   JSR    LAB_CEFF        ; scan for CHR$(A), else do syntax error then warm start
   PHA                ; push next character
   LDA    LAB_48        ; get current variable pointer high byte
   PHA                ; push it
   LDA    LAB_47        ; get current variable pointer low byte
   PHA                ; push it
   LDA    LAB_7B        ; get BASIC execute pointer high byte
   PHA                ; push it
   LDA    LAB_7A        ; get BASIC execute pointer low byte
   PHA                ; push it
   JSR    LAB_C8F8        ; perform DATA
   JMP    LAB_D44F        ; put execute pointer and variable pointer into function
                   ; and return


;***********************************************************************************;
;
; check FNx syntax

LAB_D3E1
   LDA    #TK_FN        ; set FN token
   JSR    LAB_CEFF        ; scan for CHR$(A), else do syntax error then warm start
   ORA    #$80            ; set FN flag bit
   STA    LAB_10        ; save FN name
   JSR    LAB_D092        ; search for FN variable
   STA    LAB_4E        ; save function pointer low byte
   STY    LAB_4F        ; save function pointer high byte
   JMP    LAB_CD8D        ; check if source is numeric and return, else do type
                   ; mismatch


;***********************************************************************************;
;
; Evaluate FNx

LAB_D3F4
   JSR    LAB_D3E1        ; check FNx syntax
   LDA    LAB_4F        ; get function pointer high byte
   PHA                ; push it
   LDA    LAB_4E        ; get function pointer low byte
   PHA                ; push it
   JSR    LAB_CEF1        ; evaluate expression within parentheses
   JSR    LAB_CD8D        ; check if source is numeric, else do type mismatch
   PLA                ; pop function pointer low byte
   STA    LAB_4E        ; restore it
   PLA                ; pop function pointer high byte
   STA    LAB_4F        ; restore it
   LDY    #$02            ; index to variable pointer high byte
   LDA    (LAB_4E),Y        ; get variable address low byte
   STA    LAB_47        ; save current variable pointer low byte
   TAX                ; copy address low byte
   INY                ; index to variable address high byte
   LDA    (LAB_4E),Y        ; get variable pointer high byte
   BEQ    LAB_D3AE        ; if high byte zero go do undefined function error

   STA    LAB_48        ; save current variable pointer high byte
   INY                ; index to mantissa 3

                   ; now stack the function variable value before use
LAB_D418
   LDA    (LAB_47),Y        ; get byte from variable
   PHA                ; stack it
   DEY                ; decrement index
   BPL    LAB_D418        ; loop until variable stacked

   LDY    LAB_48        ; get current variable pointer high byte
   JSR    LAB_DBD4        ; pack FAC1 into (XY)
   LDA    LAB_7B        ; get BASIC execute pointer high byte
   PHA                ; push it
   LDA    LAB_7A        ; get BASIC execute pointer low byte
   PHA                ; push it
   LDA    (LAB_4E),Y        ; get function execute pointer low byte
   STA    LAB_7A        ; save BASIC execute pointer low byte
   INY                ; index to high byte
   LDA    (LAB_4E),Y        ; get function execute pointer high byte
   STA    LAB_7B        ; save BASIC execute pointer high byte
   LDA    LAB_48        ; get current variable pointer high byte
   PHA                ; push it
   LDA    LAB_47        ; get current variable pointer low byte
   PHA                ; push it
   JSR    LAB_CD8A        ; evaluate expression and check is numeric, else do
                   ; type mismatch
   PLA                ; pull variable address low byte
   STA    LAB_4E        ; save variable address low byte
   PLA                ; pull variable address high byte
   STA    LAB_4F        ; save variable address high byte
   JSR    LAB_0079        ; scan memory
   BEQ    LAB_D449        ; if null (should be [EOL] marker) continue

   JMP    LAB_CF08        ; else syntax error then warm start

; restore BASIC execute pointer and function variable from stack

LAB_D449
   PLA                ; pull BASIC execute pointer low byte
   STA    LAB_7A        ; save BASIC execute pointer low byte
   PLA                ; pull BASIC execute pointer high byte
   STA    LAB_7B        ; save BASIC execute pointer high byte

; put execute pointer and variable pointer into function

LAB_D44F
   LDY    #$00            ; clear index
   PLA                ; pull BASIC execute pointer low byte
   STA    (LAB_4E),Y        ; save to function
   PLA                ; pull BASIC execute pointer high byte
   INY                ; increment index
   STA    (LAB_4E),Y        ; save to function
   PLA                ; pull current variable address low byte
   INY                ; increment index
   STA    (LAB_4E),Y        ; save to function
   PLA                ; pull current variable address high byte
   INY                ; increment index
   STA    (LAB_4E),Y        ; save to function
   PLA                ; pull ??
   INY                ; increment index
   STA    (LAB_4E),Y        ; save to function
   RTS


;***********************************************************************************;
;
; perform STR$()

LAB_D465
   JSR    LAB_CD8D        ; check if source is numeric, else do type mismatch
   LDY    #$00            ; set string index
   JSR    LAB_DDDF        ; convert FAC1 to string
   PLA                ; dump return address (skip type check)
   PLA                ; dump return address (skip type check)
LAB_D46F
   LDA    #    LDY    #>LAB_00FF        ; set result string high pointer
   BEQ    LAB_D487        ; print null terminated string to utility pointer


;***********************************************************************************;
;
; do string vector
; copy descriptor pointer and make string space A bytes long

LAB_D475
   LDX    LAB_64        ; get descriptor pointer low byte
   LDY    LAB_65        ; get descriptor pointer high byte
   STX    LAB_50        ; save descriptor pointer low byte
   STY    LAB_51        ; save descriptor pointer high byte


;***********************************************************************************;
;
; make string space A bytes long

LAB_D47D
   JSR    LAB_D4F4        ; make space in string memory for string A long
   STX    LAB_62        ; save string pointer low byte
   STY    LAB_63        ; save string pointer high byte
   STA    LAB_61        ; save length
   RTS


;***********************************************************************************;
;
; scan, set up string
; print " terminated string to utility pointer

LAB_D487
   LDX    #$22            ; set terminator to "
   STX    LAB_07        ; set search character, terminator 1
   STX    LAB_08        ; set terminator 2

; print search or alternate terminated string to utility pointer
; source is AY

LAB_D48D
   STA    LAB_6F        ; store string start low byte
   STY    LAB_70        ; store string start high byte
   STA    LAB_62        ; save string pointer low byte
   STY    LAB_63        ; save string pointer high byte
   LDY    #$FF            ; set length to -1
LAB_D497
   INY                ; increment length
   LDA    (LAB_6F),Y        ; get byte from string
   BEQ    LAB_D4A8        ; exit loop if null byte [EOS]

   CMP    LAB_07        ; compare with search character, terminator 1
   BEQ    LAB_D4A4        ; branch if terminator

   CMP    LAB_08        ; compare with terminator 2
   BNE    LAB_D497        ; loop if not terminator 2

LAB_D4A4
   CMP    #$22            ; compare with "
   BEQ    LAB_D4A9        ; branch if " (carry set if = !)

LAB_D4A8
   CLC                ; clear carry for add (only if [EOL] terminated string)
LAB_D4A9
   STY    LAB_61        ; save length in FAC1 exponent
   TYA                ; copy length to A
   ADC    LAB_6F        ; add string start low byte
   STA    LAB_71        ; save string end low byte
   LDX    LAB_70        ; get string start high byte
   BCC    LAB_D4B5        ; if no low byte overflow skip the high byte increment

   INX                ; else increment high byte
LAB_D4B5
   STX    LAB_72        ; save string end high byte
   LDA    LAB_70        ; get string start high byte
   BEQ    LAB_D4BF        ; branch if in utility area

   CMP    #$02            ; compare with input buffer memory high byte
   BNE    LAB_D4CA        ; branch if not in input buffer memory

                   ; string in input buffer or utility area, move to string
                   ; memory
LAB_D4BF
   TYA                ; copy length to A
   JSR    LAB_D475        ; copy descriptor pointer and make string space A bytes long
   LDX    LAB_6F        ; get string start low byte
   LDY    LAB_70        ; get string start high byte
   JSR    LAB_D688        ; store string A bytes long from XY to utility pointer

; check for space on descriptor stack then ...
; put string address and length on descriptor stack and update stack pointers

LAB_D4CA
   LDX    LAB_16        ; get descriptor stack pointer
   CPX    #$22            ; compare with max+1
   BNE    LAB_D4D5        ; branch if space on string stack

                   ; else do string too complex error
   LDX    #$19            ; error $19, string too complex error
LAB_D4D2
   JMP    LAB_C437        ; do error #X then warm start

; put string address and length on descriptor stack and update stack pointers

LAB_D4D5
   LDA    LAB_61        ; get string length
   STA    LAB_00,X        ; put on string stack
   LDA    LAB_62        ; get string pointer low byte
   STA    LAB_01,X        ; put on string stack
   LDA    LAB_63        ; get string pointer high byte
   STA    LAB_02,X        ; put on string stack
   LDY    #$00            ; clear Y
   STX    LAB_64        ; save string descriptor pointer low byte
   STY    LAB_65        ; save string descriptor pointer high byte, always $00
   STY    LAB_70        ; clear FAC1 rounding byte
   DEY                ; Y = $FF
   STY    LAB_0D        ; save data type flag, $FF = string
   STX    LAB_17        ; save current descriptor stack item pointer low byte
   INX                ; update stack pointer
   INX                ; update stack pointer
   INX                ; update stack pointer
   STX    LAB_16        ; set new descriptor stack pointer
   RTS

; make space in string memory for string A long
; return X = pointer low byte, Y = pointer high byte

LAB_D4F4
   LSR    LAB_0F        ; clear garbage collected flag (b7)

                   ; make space for string A long
LAB_D4F6
   PHA                ; save string length
   EOR    #$FF            ; complement it
   SEC                ; set carry for subtract, two's complement add
   ADC    LAB_33        ; add bottom of string space low byte, subtract length
   LDY    LAB_34        ; get bottom of string space high byte
   BCS    LAB_D501        ; skip decrement if no underflow

   DEY                ; decrement bottom of string space high byte
LAB_D501
   CPY    LAB_32        ; compare with end of arrays high byte
   BCC    LAB_D516        ; do out of memory error if less

   BNE    LAB_D50B        ; if not = skip next test

   CMP    LAB_31        ; compare with end of arrays low byte
   BCC    LAB_D516        ; do out of memory error if less

LAB_D50B
   STA    LAB_33        ; save bottom of string space low byte
   STY    LAB_34        ; save bottom of string space high byte
   STA    LAB_35        ; save string utility ptr low byte
   STY    LAB_36        ; save string utility ptr high byte
   TAX                ; copy low byte to X
   PLA                ; get string length back
   RTS

LAB_D516
   LDX    #$10            ; error code $10, out of memory error
   LDA    LAB_0F        ; get garbage collected flag
   BMI    LAB_D4D2        ; if set then do error code X

   JSR    LAB_D526        ; else go do garbage collection
   LDA    #$80            ; flag for garbage collected
   STA    LAB_0F        ; set garbage collected flag
   PLA                ; pull length
   BNE    LAB_D4F6        ; go try again (loop always, length should never be = $00)


;***********************************************************************************;
;
; garbage collection routine

LAB_D526
   LDX    LAB_37        ; get end of memory low byte
   LDA    LAB_38        ; get end of memory high byte

; re-run routine from last ending

LAB_D52A
   STX    LAB_33        ; set bottom of string space low byte
   STA    LAB_34        ; set bottom of string space high byte
   LDY    #$00            ; clear index
   STY    LAB_4F        ; clear working pointer high byte
   STY    LAB_4E        ; clear working pointer low byte
   LDA    LAB_31        ; get end of arrays low byte
   LDX    LAB_32        ; get end of arrays high byte
   STA    LAB_5F        ; save as highest uncollected string pointer low byte
   STX    LAB_60        ; save as highest uncollected string pointer high byte
   LDA    #LAB_19        ; set descriptor stack pointer
   LDX    #$00            ; clear X
   STA    LAB_22        ; save descriptor stack pointer low byte
   STX    LAB_23        ; save descriptor stack pointer high byte ($00)
LAB_D544
   CMP    LAB_16        ; compare with descriptor stack pointer
   BEQ    LAB_D54D        ; branch if =

   JSR    LAB_D5C7        ; check string salvageability
   BEQ    LAB_D544        ; loop always

                   ; done stacked strings, now do string variables
LAB_D54D
   LDA    #$07            ; set step size = $07, collecting variables
   STA    LAB_53        ; save garbage collection step size
   LDA    LAB_2D        ; get start of variables low byte
   LDX    LAB_2E        ; get start of variables high byte
   STA    LAB_22        ; save as pointer low byte
   STX    LAB_23        ; save as pointer high byte
LAB_D559
   CPX    LAB_30        ; compare end of variables high byte,
                   ; start of arrays high byte
   BNE    LAB_D561        ; branch if no high byte match

   CMP    LAB_2F        ; else compare end of variables low byte,
                   ; start of arrays low byte
   BEQ    LAB_D566        ; branch if = variable memory end

LAB_D561
   JSR    LAB_D5BD        ; check variable salvageability
   BEQ    LAB_D559        ; loop always

                   ; done string variables, now do string arrays
LAB_D566
   STA    LAB_58        ; save start of arrays low byte as working pointer
   STX    LAB_59        ; save start of arrays high byte as working pointer
   LDA    #$03            ; set step size, collecting descriptors
   STA    LAB_53        ; save step size
LAB_D56E
   LDA    LAB_58        ; get pointer low byte
   LDX    LAB_59        ; get pointer high byte
LAB_D572
   CPX    LAB_32        ; compare with end of arrays high byte
   BNE    LAB_D57D        ; branch if not at end

   CMP    LAB_31        ; else compare with end of arrays low byte
   BNE    LAB_D57D        ; branch if not at end

   JMP    LAB_D606        ; collect string, tidy up and exit if at end ??

LAB_D57D
   STA    LAB_22        ; save pointer low byte
   STX    LAB_23        ; save pointer high byte
   LDY    #$00            ; set index
   LDA    (LAB_22),Y        ; get array name first byte
   TAX                ; copy it
   INY                ; increment index
   LDA    (LAB_22),Y        ; get array name second byte
   PHP                ; push the flags
   INY                ; increment index
   LDA    (LAB_22),Y        ; get array size low byte
   ADC    LAB_58        ; add start of this array low byte
   STA    LAB_58        ; save start of next array low byte
   INY                ; increment index
   LDA    (LAB_22),Y        ; get array size high byte
   ADC    LAB_59        ; add start of this array high byte
   STA    LAB_59        ; save start of next array high byte
   PLP                ; restore the flags
   BPL    LAB_D56E        ; skip if not string array

; was possibly string array so ...

   TXA                ; get name first byte back
   BMI    LAB_D56E        ; skip if not string array

   INY                ; increment index
   LDA    (LAB_22),Y        ; get # of dimensions
   LDY    #$00            ; clear index
   ASL                ; *2
   ADC    #$05            ; +5 (array header size)
   ADC    LAB_22        ; add pointer low byte
   STA    LAB_22        ; save pointer low byte
   BCC    LAB_D5AE        ; if no rollover skip the high byte increment

   INC    LAB_23        ; else increment pointer hgih byte
LAB_D5AE
   LDX    LAB_23        ; get pointer high byte
LAB_D5B0
   CPX    LAB_59        ; compare pointer high byte with end of this array high byte
   BNE    LAB_D5B8        ; branch if not there yet

   CMP    LAB_58        ; compare pointer low byte with end of this array low byte
   BEQ    LAB_D572        ; if at end of this array go check next array

LAB_D5B8
   JSR    LAB_D5C7        ; check string salvageability
   BEQ    LAB_D5B0        ; loop

; check variable salvageability

LAB_D5BD
   LDA    (LAB_22),Y        ; get variable name first byte
   BMI    LAB_D5F6        ; add step and exit if not string

   INY                ; increment index
   LDA    (LAB_22),Y        ; get variable name second byte
   BPL    LAB_D5F6        ; add step and exit if not string

   INY                ; increment index

; check string salvageability

LAB_D5C7
   LDA    (LAB_22),Y        ; get string length
   BEQ    LAB_D5F6        ; add step and exit if null string

   INY                ; increment index
   LDA    (LAB_22),Y        ; get string pointer low byte
   TAX                ; copy to X
   INY                ; increment index
   LDA    (LAB_22),Y        ; get string pointer high byte
   CMP    LAB_34        ; compare string pointer high byte with bottom of string
                   ; space high byte
   BCC    LAB_D5DC        ; if bottom of string space greater go test against highest
                   ; uncollected string

   BNE    LAB_D5F6        ; if bottom of string space less string has been collected
                   ; so go update pointers, step to next and return

                   ; high bytes were equal so test low bytes
   CPX    LAB_33        ; compare string pointer low byte with bottom of string
                   ; space low byte
   BCS    LAB_D5F6        ; if bottom of string space less string has been collected
                   ; so go update pointers, step to next and return

                   ; else test string against highest uncollected string so far
LAB_D5DC
   CMP    LAB_60        ; compare string pointer high byte with highest uncollected
                   ; string high byte
   BCC    LAB_D5F6        ; if highest uncollected string is greater then go update
                   ; pointers, step to next and return

   BNE    LAB_D5E6        ; if highest uncollected string is less then go set this
                   ; string as highest uncollected so far

                   ; high bytes were equal so test low bytes
   CPX    LAB_5F        ; compare string pointer low byte with highest uncollected
                   ; string low byte
   BCC    LAB_D5F6        ; if highest uncollected string is greater then go update
                   ; pointers, step to next and return

                   ; else set current string as highest uncollected string
LAB_D5E6
   STX    LAB_5F        ; save string pointer low byte as highest uncollected string
                   ; low byte
   STA    LAB_60        ; save string pointer high byte as highest uncollected
                   ; string high byte
   LDA    LAB_22        ; get descriptor pointer low byte
   LDX    LAB_23        ; get descriptor pointer high byte
   STA    LAB_4E        ; save working pointer high byte
   STX    LAB_4F        ; save working pointer low byte
   LDA    LAB_53        ; get step size
   STA    LAB_55        ; copy step size
LAB_D5F6
   LDA    LAB_53        ; get step size
   CLC                ; clear carry for add
   ADC    LAB_22        ; add pointer low byte
   STA    LAB_22        ; save pointer low byte
   BCC    LAB_D601        ; if no rollover skip the high byte increment

   INC    LAB_23        ; else increment pointer high byte
LAB_D601
   LDX    LAB_23        ; get pointer high byte
   LDY    #$00            ; flag not moved
   RTS


;***********************************************************************************;
;
; collect string

LAB_D606
   LDA    LAB_4F        ; get working pointer low byte
   ORA    LAB_4E        ; OR working pointer high byte
   BEQ    LAB_D601        ; exit if nothing to collect

   LDA    LAB_55        ; get copied step size
   AND    #$04            ; mask step size, $04 for variables, $00 for array or stack
   LSR                ; >> 1
   TAY                ; copy to index
   STA    LAB_55        ; save offset to descriptor start
   LDA    (LAB_4E),Y        ; get string length low byte
   ADC    LAB_5F        ; add string start low byte
   STA    LAB_5A        ; set block end low byte
   LDA    LAB_60        ; get string start high byte
   ADC    #$00            ; add carry
   STA    LAB_5B        ; set block end high byte
   LDA    LAB_33        ; get bottom of string space low byte
   LDX    LAB_34        ; get bottom of string space high byte
   STA    LAB_58        ; save destination end low byte
   STX    LAB_59        ; save destination end high byte
   JSR    LAB_C3BF        ; open up space in memory, don't set array end. this
                   ; copies the string from where it is to the end of the
                   ; uncollected string memory
   LDY    LAB_55        ; restore offset to descriptor start
   INY                ; increment index to string pointer low byte
   LDA    LAB_58        ; get new string pointer low byte
   STA    (LAB_4E),Y        ; save new string pointer low byte
   TAX                ; copy string pointer low byte
   INC    LAB_59        ; increment new string pointer high byte
   LDA    LAB_59        ; get new string pointer high byte
   INY                ; increment index to string pointer high byte
   STA    (LAB_4E),Y        ; save new string pointer high byte
   JMP    LAB_D52A        ; re-run routine from last ending, XA holds new bottom
                   ; of string memory pointer


;***********************************************************************************;
;
; concatenate
; add strings, the first string is in the descriptor, the second string is in line

LAB_D63D
   LDA    LAB_65        ; get descriptor pointer high byte
   PHA                ; put on stack
   LDA    LAB_64        ; get descriptor pointer low byte
   PHA                ; put on stack
   JSR    LAB_CE83        ; get value from line
   JSR    LAB_CD8F        ; check if source is string, else do type mismatch
   PLA                ; get descriptor pointer low byte back
   STA    LAB_6F        ; set pointer low byte
   PLA                ; get descriptor pointer high byte back
   STA    LAB_70        ; set pointer high byte
   LDY    #$00            ; clear index
   LDA    (LAB_6F),Y        ; get length of first string from descriptor
   CLC                ; clear carry for add
   ADC    (LAB_64),Y        ; add length of second string
   BCC    LAB_D65D        ; if no overflow continue

   LDX    #$17            ; else error $17, string too long error
   JMP    LAB_C437        ; do error #X then warm start

LAB_D65D
   JSR    LAB_D475        ; copy descriptor pointer and make string space A bytes long
   JSR    LAB_D67A        ; copy string from descriptor to utility pointer
   LDA    LAB_50        ; get descriptor pointer low byte
   LDY    LAB_51        ; get descriptor pointer high byte
   JSR    LAB_D6AA        ; pop (YA) descriptor off stack or from top of string space
                   ; returns with A = length, X = pointer low byte,
                   ; Y = pointer high byte
   JSR    LAB_D68C        ; store string from pointer to utility pointer
   LDA    LAB_6F        ; get descriptor pointer low byte
   LDY    LAB_70        ; get descriptor pointer high byte
   JSR    LAB_D6AA        ; pop (YA) descriptor off stack or from top of string space
                   ; returns with A = length, X = pointer low byte,
                   ; Y = pointer high byte
   JSR    LAB_D4CA        ; check space on descriptor stack then put string address
                   ; and length on descriptor stack and update stack pointers
   JMP    LAB_CDB8        ; continue evaluation


;***********************************************************************************;
;
; copy string from descriptor to utility pointer

LAB_D67A
   LDY    #$00            ; clear index
   LDA    (LAB_6F),Y        ; get string length
   PHA                ; save it
   INY                ; increment index
   LDA    (LAB_6F),Y        ; get string pointer low byte
   TAX                ; copy to X
   INY                ; increment index
   LDA    (LAB_6F),Y        ; get string pointer high byte
   TAY                ; copy to Y
   PLA                ; get length back
LAB_D688
   STX    LAB_22        ; save string pointer low byte
   STY    LAB_23        ; save string pointer high byte


;***********************************************************************************;
;
; store string from pointer to utility pointer

LAB_D68C
   TAY                ; copy length as index
   BEQ    LAB_D699        ; branch if null string

   PHA                ; save length
LAB_D690
   DEY                ; decrement length/index
   LDA    (LAB_22),Y        ; get byte from string
   STA    (LAB_35),Y        ; save byte to destination
   TYA                ; copy length/index
   BNE    LAB_D690        ; loop if not all done yet

   PLA                ; restore length
LAB_D699
   CLC                ; clear carry for add
   ADC    LAB_35        ; add string utility ptr low byte
   STA    LAB_35        ; save string utility ptr low byte
   BCC    LAB_D6A2        ; if no rollover skip the high byte increment

   INC    LAB_36        ; increment string utility ptr high byte
LAB_D6A2
   RTS


;***********************************************************************************;
;
; evaluate string

LAB_D6A3
   JSR    LAB_CD8F        ; check if source is string, else do type mismatch

; pop string off descriptor stack, or from top of string space
; returns with A = length, X = pointer low byte, Y = pointer high byte

LAB_D6A6
   LDA    LAB_64        ; get descriptor pointer low byte
   LDY    LAB_65        ; get descriptor pointer high byte

; pop (YA) descriptor off stack or from top of string space
; returns with A = length, X = pointer low byte, Y = pointer high byte

LAB_D6AA
   STA    LAB_22        ; save string pointer low byte
   STY    LAB_23        ; save string pointer high byte
   JSR    LAB_D6DB        ; clean descriptor stack, YA = pointer
   PHP                ; save status flags
   LDY    #$00            ; clear index
   LDA    (LAB_22),Y        ; get length from string descriptor
   PHA                ; put on stack
   INY                ; increment index
   LDA    (LAB_22),Y        ; get string pointer low byte from descriptor
   TAX                ; copy to X
   INY                ; increment index
   LDA    (LAB_22),Y        ; get string pointer high byte from descriptor
   TAY                ; copy to Y
   PLA                ; get string length back
   PLP                ; restore status
   BNE    LAB_D6D6        ; branch if pointer <> last_sl,last_sh

   CPY    LAB_34        ; compare with bottom of string space high byte
   BNE    LAB_D6D6        ; branch if <>

   CPX    LAB_33        ; else compare with bottom of string space low byte
   BNE    LAB_D6D6        ; branch if <>

   PHA                ; save string length
   CLC                ; clear carry for add
   ADC    LAB_33        ; add bottom of string space low byte
   STA    LAB_33        ; set bottom of string space low byte
   BCC    LAB_D6D5        ; skip increment if no overflow

   INC    LAB_34        ; increment bottom of string space high byte
LAB_D6D5
   PLA                ; restore string length
LAB_D6D6
   STX    LAB_22        ; save string pointer low byte
   STY    LAB_23        ; save string pointer high byte
   RTS


;***********************************************************************************;
;
; clean descriptor stack, YA = pointer
; checks if AY is on the descriptor stack, if so does a stack discard

LAB_D6DB
   CPY    LAB_18        ; compare high byte with current descriptor stack item
                   ; pointer high byte
   BNE    LAB_D6EB        ; exit if <>

   CMP    LAB_17        ; compare low byte with current descriptor stack item
                   ; pointer low byte
   BNE    LAB_D6EB        ; exit if <>

   STA    LAB_16        ; set descriptor stack pointer
   SBC    #$03            ; update last string pointer low byte
   STA    LAB_17        ; save current descriptor stack item pointer low byte
   LDY    #$00            ; clear high byte
LAB_D6EB
   RTS


;***********************************************************************************;
;
; perform CHR$()

LAB_D6EC
   JSR    LAB_D7A1        ; evaluate byte expression, result in X
   TXA                ; copy to A
   PHA                ; save character
   LDA    #$01            ; string is single byte
   JSR    LAB_D47D        ; make string space A bytes long
   PLA                ; get character back
   LDY    #$00            ; clear index
   STA    (LAB_62),Y        ; save byte in string - byte IS string!
   PLA                ; dump return address (skip type check)
   PLA                ; dump return address (skip type check)
   JMP    LAB_D4CA        ; check space on descriptor stack then put string address
                   ; and length on descriptor stack and update stack pointers


;***********************************************************************************;
;
; perform LEFT$()

LAB_D700
   JSR    LAB_D761        ; pull string data and byte parameter from stack
                   ; return pointer in descriptor, byte in A (and X), Y=0
   CMP    (LAB_50),Y        ; compare byte parameter with string length
   TYA                ; clear A
LAB_D706
   BCC    LAB_D70C        ; branch if string length > byte parameter

   LDA    (LAB_50),Y        ; else make parameter = length
   TAX                ; copy to byte parameter copy
   TYA                ; clear string start offset
LAB_D70C
   PHA                ; save string start offset
LAB_D70D
   TXA                ; copy byte parameter (or string length if <)
LAB_D70E
   PHA                ; save string length
   JSR    LAB_D47D        ; make string space A bytes long
   LDA    LAB_50        ; get descriptor pointer low byte
   LDY    LAB_51        ; get descriptor pointer high byte
   JSR    LAB_D6AA        ; pop (YA) descriptor off stack or from top of string space
                   ; returns with A = length, X = pointer low byte,
                   ; Y = pointer high byte
   PLA                ; get string length back
   TAY                ; copy length to Y
   PLA                ; get string start offset back
   CLC                ; clear carry for add
   ADC    LAB_22        ; add start offset to string start pointer low byte
   STA    LAB_22        ; save string start pointer low byte
   BCC    LAB_D725        ; if no overflow skip the high byte increment

   INC    LAB_23        ; else increment string start pointer high byte
LAB_D725
   TYA                ; copy length to A
   JSR    LAB_D68C        ; store string from pointer to utility pointer
   JMP    LAB_D4CA        ; check space on descriptor stack then put string address
                   ; and length on descriptor stack and update stack pointers


;***********************************************************************************;
;
; perform RIGHT$()

LAB_D72C
   JSR    LAB_D761        ; pull string data and byte parameter from stack
                   ; return pointer in descriptor, byte in A (and X), Y=0
   CLC                ; clear carry for add-1
   SBC    (LAB_50),Y        ; subtract string length
   EOR    #$FF            ; invert it (A=LEN(expression$)-l)
   JMP    LAB_D706        ; go do rest of LEFT$()


;***********************************************************************************;
;
; perform MID$()

LAB_D737
   LDA    #$FF            ; set default length = 255
   STA    LAB_65        ; save default length
   JSR    LAB_0079        ; scan memory
   CMP    #$29            ; compare with ")"
   BEQ    LAB_D748        ; branch if = ")" (skip second byte get)

   JSR    LAB_CEFD        ; scan for ",", else do syntax error then warm start
   JSR    LAB_D79E        ; get byte parameter
LAB_D748
   JSR    LAB_D761        ; pull string data and byte parameter from stack
                   ; return pointer in descriptor, byte in A (and X), Y=0
   BEQ    LAB_D798        ; if null do illegal quantity error then warm start

   DEX                ; decrement start index
   TXA                ; copy to A
   PHA                ; save string start offset
   CLC                ; clear carry for sub-1
   LDX    #$00            ; clear output string length
   SBC    (LAB_50),Y        ; subtract string length
   BCS    LAB_D70D        ; if start>string length go do null string

   EOR    #$FF            ; complement -length
   CMP    LAB_65        ; compare byte parameter
   BCC    LAB_D70E        ; if length>remaining string go do RIGHT$

   LDA    LAB_65        ; get length byte
   BCS    LAB_D70E        ; go do string copy, branch always


;***********************************************************************************;
;
; pull string data and byte parameter from stack
; return pointer in descriptor, byte in A (and X), Y=0

LAB_D761
   JSR    LAB_CEF7        ; scan for ")", else do syntax error then warm start
   PLA                ; pull return address low byte
   TAY                ; save return address low byte
   PLA                ; pull return address high byte
   STA    LAB_55        ; save return address high byte
   PLA                ; dump call to function vector low byte
   PLA                ; dump call to function vector high byte
   PLA                ; pull byte parameter
   TAX                ; copy byte parameter to X
   PLA                ; pull string pointer low byte
   STA    LAB_50        ; save it
   PLA                ; pull string pointer high byte
   STA    LAB_51        ; save it
   LDA    LAB_55        ; get return address high byte
   PHA                ; back on stack
   TYA                ; get return address low byte
   PHA                ; back on stack
   LDY    #$00            ; clear index
   TXA                ; copy byte parameter
   RTS


;***********************************************************************************;
;
; perform LEN()

LAB_D77C
   JSR    LAB_D782        ; evaluate string, get length in A (and Y)
   JMP    LAB_D3A2        ; convert Y to byte in FAC1 and return


;***********************************************************************************;
;
; evaluate string, get length in Y

LAB_D782
   JSR    LAB_D6A3        ; evaluate string
   LDX    #$00            ; set data type = numeric
   STX    LAB_0D        ; clear data type flag, $FF = string, $00 = numeric
   TAY                ; copy length to Y
   RTS


;***********************************************************************************;
;
; perform ASC()

LAB_D78B
   JSR    LAB_D782        ; evaluate string, get length in A (and Y)
   BEQ    LAB_D798        ; if null do illegal quantity error then warm start

   LDY    #$00            ; set index to first character
   LDA    (LAB_22),Y        ; get byte
   TAY                ; copy to Y
   JMP    LAB_D3A2        ; convert Y to byte in FAC1 and return


;***********************************************************************************;
;
; do illegal quantity error then warm start

LAB_D798
   JMP    LAB_D248        ; do illegal quantity error then warm start


;***********************************************************************************;
;
; scan and get byte parameter

LAB_D79B
   JSR    LAB_0073        ; increment and scan memory

; get byte parameter

LAB_D79E
   JSR    LAB_CD8A        ; evaluate expression and check is numeric, else do
                   ; type mismatch

; evaluate byte expression, result in X

LAB_D7A1
   JSR    LAB_D1B8        ; evaluate integer expression, sign check

   LDX    LAB_64        ; get FAC1 mantissa 3
   BNE    LAB_D798        ; if not null do illegal quantity error then warm start

   LDX    LAB_65        ; get FAC1 mantissa 4
   JMP    LAB_0079        ; scan memory and return


;***********************************************************************************;
;
; perform VAL()

LAB_D7AD
   JSR    LAB_D782        ; evaluate string, get length in A (and Y)
   BNE    LAB_D7B5        ; if not a null string go evaluate it

                   ; string was null so set result = $00
   JMP    LAB_D8F7        ; clear FAC1 exponent and sign and return

LAB_D7B5
   LDX    LAB_7A        ; get BASIC execute pointer low byte
   LDY    LAB_7B        ; get BASIC execute pointer high byte
   STX    LAB_71        ; save BASIC execute pointer low byte
   STY    LAB_72        ; save BASIC execute pointer high byte
   LDX    LAB_22        ; get string pointer low byte
   STX    LAB_7A        ; save BASIC execute pointer low byte
   CLC                ; clear carry for add
   ADC    LAB_22        ; add string length
   STA    LAB_24        ; save string end low byte
   LDX    LAB_23        ; get string pointer high byte
   STX    LAB_7B        ; save BASIC execute pointer high byte
   BCC    LAB_D7CD        ; if no rollover skip the high byte increment

   INX                ; increment string end high byte
LAB_D7CD
   STX    LAB_25        ; save string end high byte
   LDY    #$00            ; set index to $00
   LDA    (LAB_24),Y        ; get string end byte
   PHA                ; push it
   TYA                ; clear A
   STA    (LAB_24),Y        ; terminate string with $00
   JSR    LAB_0079        ; scan memory
   JSR    LAB_DCF3        ; get FAC1 from string
   PLA                ; restore string end byte
   LDY    #$00            ; clear index
   STA    (LAB_24),Y        ; put string end byte back

; restore BASIC execute pointer from temp

LAB_D7E2
   LDX    LAB_71        ; get BASIC execute pointer low byte back
   LDY    LAB_72        ; get BASIC execute pointer high byte back
   STX    LAB_7A        ; save BASIC execute pointer low byte
   STY    LAB_7B        ; save BASIC execute pointer high byte
   RTS


;***********************************************************************************;
;
; get parameters for POKE/WAIT

LAB_D7EB
   JSR    LAB_CD8A        ; evaluate expression and check is numeric, else do
                   ; type mismatch
   JSR    LAB_D7F7        ; convert FAC_1 to integer in temporary integer
LAB_D7F1
   JSR    LAB_CEFD        ; scan for ",", else do syntax error then warm start
   JMP    LAB_D79E        ; get byte parameter and return


;***********************************************************************************;
;
; convert FAC_1 to integer in temporary integer

LAB_D7F7
   LDA    LAB_66        ; get FAC1 sign
   BMI    LAB_D798        ; if -ve do illegal quantity error then warm start

   LDA    LAB_61        ; get FAC1 exponent
   CMP    #$91            ; compare with exponent = 2^16
   BCS    LAB_D798        ; if >= do illegal quantity error then warm start

   JSR    LAB_DC9B        ; convert FAC1 floating to fixed
   LDA    LAB_64        ; get FAC1 mantissa 3
   LDY    LAB_65        ; get FAC1 mantissa 4
   STY    LAB_14        ; save temporary integer low byte
   STA    LAB_15        ; save temporary integer high byte
   RTS


;***********************************************************************************;
;
; perform PEEK()

LAB_D80D
   LDA    LAB_15        ; get line number high byte
   PHA                ; save line number high byte
   LDA    LAB_14        ; get line number low byte
   PHA                ; save line number low byte
   JSR    LAB_D7F7        ; convert FAC_1 to integer in temporary integer
   LDY    #$00            ; clear index
   LDA    (LAB_14),Y        ; read byte
   TAY                ; copy byte to A
   PLA                ; pull byte
   STA    LAB_14        ; restore line number low byte
   PLA                ; pull byte
   STA    LAB_15        ; restore line number high byte
   JMP    LAB_D3A2        ; convert Y to byte in FAC_1 and return


;***********************************************************************************;
;
; perform POKE

LAB_D824
   JSR    LAB_D7EB        ; get parameters for POKE/WAIT
   TXA                ; copy byte to A
   LDY    #$00            ; clear index
   STA    (LAB_14),Y        ; write byte
   RTS


;***********************************************************************************;
;
; perform WAIT

LAB_D82D
   JSR    LAB_D7EB        ; get parameters for POKE/WAIT
   STX    LAB_49        ; save byte
   LDX    #$00            ; clear mask
   JSR    LAB_0079        ; scan memory
   BEQ    LAB_D83C        ; skip if no third argument

   JSR    LAB_D7F1        ; scan for "," and get byte, else syntax error then
                   ; warm start
LAB_D83C
   STX    LAB_4A        ; save EOR argument
   LDY    #$00            ; clear index
LAB_D840
   LDA    (LAB_14),Y        ; get byte via temporary integer    (address)
   EOR    LAB_4A        ; EOR with second argument        (mask)
   AND    LAB_49        ; AND with first argument        (byte)
   BEQ    LAB_D840        ; loop if result is zero

LAB_D848
   RTS


;***********************************************************************************;
;
; add 0.5 to FAC1 (round FAC1)

LAB_D849
   LDA    #    LDY    #>LAB_DF11        ; set 0.5 pointer high byte
   JMP    LAB_D867        ; add (AY) to FAC1


;***********************************************************************************;
;
; perform subtraction, FAC1 from (AY)

LAB_D850
   JSR    LAB_DA8C        ; unpack memory (AY) into FAC2

; perform subtraction, FAC1 from FAC2

LAB_D853
   LDA    LAB_66        ; get FAC1 sign (b7)
   EOR    #$FF            ; complement it
   STA    LAB_66        ; save FAC1 sign (b7)
   EOR    LAB_6E        ; EOR with FAC2 sign (b7)
   STA    LAB_6F        ; save sign compare (FAC1 EOR FAC2)
   LDA    LAB_61        ; get FAC1 exponent
   JMP    LAB_D86A        ; add FAC2 to FAC1 and return

LAB_D862
   JSR    LAB_D999        ; shift FACX A times right (>8 shifts)
   BCC    LAB_D8A3        ; go subtract the mantissas, branch always


;***********************************************************************************;
;
; add (AY) to FAC1

LAB_D867
   JSR    LAB_DA8C        ; unpack memory (AY) into FAC2

; add FAC2 to FAC1

LAB_D86A
   BNE    LAB_D86F        ; if FAC1 is not zero go do the add

   JMP    LAB_DBFC        ; FAC1 was zero so copy FAC2 to FAC1 and return

                   ; FAC1 is non zero
LAB_D86F
   LDX    LAB_70        ; get FAC1 rounding byte
   STX    LAB_56        ; save as FAC2 rounding byte
   LDX    #LAB_69        ; set index to FAC2 exponent address
   LDA    LAB_69        ; get FAC2 exponent
LAB_D877
   TAY                ; copy exponent
   BEQ    LAB_D848        ; exit if zero

   SEC                ; set carry for subtract
   SBC    LAB_61        ; subtract FAC1 exponent
   BEQ    LAB_D8A3        ; if equal go add mantissas

   BCC    LAB_D893        ; if FAC2 < FAC1 then go shift FAC2 right

                   ; else FAC2 > FAC1
   STY    LAB_61        ; save FAC1 exponent
   LDY    LAB_6E        ; get FAC2 sign (b7)
   STY    LAB_66        ; save FAC1 sign (b7)
   EOR    #$FF            ; complement A
   ADC    #$00            ; +1, twos complement, carry is set
   LDY    #$00            ; clear Y
   STY    LAB_56        ; clear FAC2 rounding byte
   LDX    #LAB_61        ; set index to FAC1 exponent address
   BNE    LAB_D897        ; branch always

                   ; FAC2 < FAC1
LAB_D893
   LDY    #$00            ; clear Y
   STY    LAB_70        ; clear FAC1 rounding byte
LAB_D897
   CMP    #$F9            ; compare exponent diff with $F9
   BMI    LAB_D862        ; branch if range $79-$F8

   TAY                ; copy exponent difference to Y
   LDA    LAB_70        ; get FAC1 rounding byte
   LSR    LAB_01,X        ; shift FAC? mantissa 1
   JSR    LAB_D9B0        ; shift FACX Y times right

                   ; exponents are equal now do mantissa subtract
LAB_D8A3
   BIT    LAB_6F        ; test sign compare (FAC1 EOR FAC2)
   BPL    LAB_D8FE        ; if = add FAC2 mantissa to FAC1 mantissa and return

   LDY    #LAB_61        ; set index to FAC1 exponent address
   CPX    #LAB_69        ; compare X to FAC2 exponent address
   BEQ    LAB_D8AF        ; branch if =

   LDY    #LAB_69        ; else set index to FAC2 exponent address

                   ; subtract smaller from bigger (take sign of bigger)
LAB_D8AF
   SEC                ; set carry for subtract
   EOR    #$FF            ; ones complement A
   ADC    LAB_56        ; add FAC2 rounding byte
   STA    LAB_70        ; save FAC1 rounding byte
   LDA    LAB_04,Y        ; get FACY mantissa 4
   SBC    LAB_04,X        ; subtract FACX mantissa 4
   STA    LAB_65        ; save FAC1 mantissa 4
   LDA    LAB_03,Y        ; get FACY mantissa 3
   SBC    LAB_03,X        ; subtract FACX mantissa 3
   STA    LAB_64        ; save FAC1 mantissa 3
   LDA    LAB_02,Y        ; get FACY mantissa 2
   SBC    LAB_02,X        ; subtract FACX mantissa 2
   STA    LAB_63        ; save FAC1 mantissa 2
   LDA    LAB_01,Y        ; get FACY mantissa 1
   SBC    LAB_01,X        ; subtract FACX mantissa 1
   STA    LAB_62        ; save FAC1 mantissa 1


;***********************************************************************************;
;
; do ABS and normalise FAC1

LAB_D8D2
   BCS    LAB_D8D7        ; branch if number is +ve

   JSR    LAB_D947        ; negate FAC1

; normalise FAC1

LAB_D8D7
   LDY    #$00            ; clear Y
   TYA                ; clear A
   CLC                ; clear carry for add
LAB_D8DB
   LDX    LAB_62        ; get FAC1 mantissa 1
   BNE    LAB_D929        ; if not zero normalise FAC1

   LDX    LAB_63        ; get FAC1 mantissa 2
   STX    LAB_62        ; save FAC1 mantissa 1
   LDX    LAB_64        ; get FAC1 mantissa 3
   STX    LAB_63        ; save FAC1 mantissa 2
   LDX    LAB_65        ; get FAC1 mantissa 4
   STX    LAB_64        ; save FAC1 mantissa 3
   LDX    LAB_70        ; get FAC1 rounding byte
   STX    LAB_65        ; save FAC1 mantissa 4
   STY    LAB_70        ; clear FAC1 rounding byte
   ADC    #$08            ; add x to exponent offset
   CMP    #$20            ; compare with $20, max offset, all bits would be = 0
   BNE    LAB_D8DB        ; loop if not max


;***********************************************************************************;
;
; clear FAC1 exponent and sign

LAB_D8F7
   LDA    #$00            ; clear A
LAB_D8F9
   STA    LAB_61        ; set FAC1 exponent

; save FAC1 sign

LAB_D8FB
   STA    LAB_66        ; save FAC1 sign (b7)
   RTS


;***********************************************************************************;
;
; add FAC2 mantissa to FAC1 mantissa

LAB_D8FE
   ADC    LAB_56        ; add FAC2 rounding byte
   STA    LAB_70        ; save FAC1 rounding byte
   LDA    LAB_65        ; get FAC1 mantissa 4
   ADC    LAB_6D        ; add FAC2 mantissa 4
   STA    LAB_65        ; save FAC1 mantissa 4
   LDA    LAB_64        ; get FAC1 mantissa 3
   ADC    LAB_6C        ; add FAC2 mantissa 3
   STA    LAB_64        ; save FAC1 mantissa 3
   LDA    LAB_63        ; get FAC1 mantissa 2
   ADC    LAB_6B        ; add FAC2 mantissa 2
   STA    LAB_63        ; save FAC1 mantissa 2
   LDA    LAB_62        ; get FAC1 mantissa 1
   ADC    LAB_6A        ; add FAC2 mantissa 1
   STA    LAB_62        ; save FAC1 mantissa 1
   JMP    LAB_D936        ; test and normalise FAC1 for C=0/1

LAB_D91D
   ADC    #$01            ; add 1 to exponent offset
   ASL    LAB_70        ; shift FAC1 rounding byte
   ROL    LAB_65        ; shift FAC1 mantissa 4
   ROL    LAB_64        ; shift FAC1 mantissa 3
   ROL    LAB_63        ; shift FAC1 mantissa 2
   ROL    LAB_62        ; shift FAC1 mantissa 1


;***********************************************************************************;
;
; normalise FAC1

LAB_D929
   BPL    LAB_D91D        ; loop if not normalised

   SEC                ; set carry for subtract
   SBC    LAB_61        ; subtract FAC1 exponent
   BCS    LAB_D8F7        ; branch if underflow (set result = $0)

   EOR    #$FF            ; complement exponent
   ADC    #$01            ; +1 (twos complement)
   STA    LAB_61        ; save FAC1 exponent

; test and normalise FAC1 for C=0/1

LAB_D936
   BCC    LAB_D946        ; exit if no overflow

; normalise FAC1 for C=1

LAB_D938
   INC    LAB_61        ; increment FAC1 exponent
   BEQ    LAB_D97E        ; if zero do overflow error then warm start

   ROR    LAB_62        ; shift FAC1 mantissa 1
   ROR    LAB_63        ; shift FAC1 mantissa 2
   ROR    LAB_64        ; shift FAC1 mantissa 3
   ROR    LAB_65        ; shift FAC1 mantissa 4
   ROR    LAB_70        ; shift FAC1 rounding byte
LAB_D946
   RTS


;***********************************************************************************;
;
; negate FAC1

LAB_D947
   LDA    LAB_66        ; get FAC1 sign (b7)
   EOR    #$FF            ; complement it
   STA    LAB_66        ; save FAC1 sign (b7)

; twos complement FAC1 mantissa

LAB_D94D
   LDA    LAB_62        ; get FAC1 mantissa 1
   EOR    #$FF            ; complement it
   STA    LAB_62        ; save FAC1 mantissa 1
   LDA    LAB_63        ; get FAC1 mantissa 2
   EOR    #$FF            ; complement it
   STA    LAB_63        ; save FAC1 mantissa 2
   LDA    LAB_64        ; get FAC1 mantissa 3
   EOR    #$FF            ; complement it
   STA    LAB_64        ; save FAC1 mantissa 3
   LDA    LAB_65        ; get FAC1 mantissa 4
   EOR    #$FF            ; complement it
   STA    LAB_65        ; save FAC1 mantissa 4
   LDA    LAB_70        ; get FAC1 rounding byte
   EOR    #$FF            ; complement it
   STA    LAB_70        ; save FAC1 rounding byte
   INC    LAB_70        ; increment FAC1 rounding byte
   BNE    LAB_D97D        ; exit if no overflow

; increment FAC1 mantissa

LAB_D96F
   INC    LAB_65        ; increment FAC1 mantissa 4
   BNE    LAB_D97D        ; finished if no rollover

   INC    LAB_64        ; increment FAC1 mantissa 3
   BNE    LAB_D97D        ; finished if no rollover

   INC    LAB_63        ; increment FAC1 mantissa 2
   BNE    LAB_D97D        ; finished if no rollover

   INC    LAB_62        ; increment FAC1 mantissa 1
LAB_D97D
   RTS


;***********************************************************************************;
;
; do overflow error then warm start

LAB_D97E
   LDX    #$0F            ; error $0F, overflow error
   JMP    LAB_C437        ; do error #X then warm start


;***********************************************************************************;
;
; shift FCAtemp << A+8 times

LAB_D983
   LDX    #$25            ; set offset to FACtemp
LAB_D985
   LDY    LAB_04,X        ; get FACX mantissa 4
   STY    LAB_70        ; save as FAC1 rounding byte
   LDY    LAB_03,X        ; get FACX mantissa 3
   STY    LAB_04,X        ; save FACX mantissa 4
   LDY    LAB_02,X        ; get FACX mantissa 2
   STY    LAB_03,X        ; save FACX mantissa 3
   LDY    LAB_01,X        ; get FACX mantissa 1
   STY    LAB_02,X        ; save FACX mantissa 2
   LDY    LAB_68        ; get FAC1 overflow byte
   STY    LAB_01,X        ; save FACX mantissa 1

; shift FACX -A times right (> 8 shifts)

LAB_D999
   ADC    #$08            ; add 8 to shift count
   BMI    LAB_D985        ; go do 8 shift if still -ve

   BEQ    LAB_D985        ; go do 8 shift if zero

   SBC    #$08            ; else subtract 8 again
   TAY                ; save count to Y
   LDA    LAB_70        ; get FAC1 rounding byte
   BCS    LAB_D9BA        ;.

LAB_D9A6
   ASL    LAB_01,X        ; shift FACX mantissa 1
   BCC    LAB_D9AC        ; branch if +ve

   INC    LAB_01,X        ; this sets b7 eventually
LAB_D9AC
   ROR    LAB_01,X        ; shift FACX mantissa 1 (correct for ASL)
   ROR    LAB_01,X        ; shift FACX mantissa 1 (put carry in b7)

; shift FACX Y times right

LAB_D9B0
   ROR    LAB_02,X        ; shift FACX mantissa 2
   ROR    LAB_03,X        ; shift FACX mantissa 3
   ROR    LAB_04,X        ; shift FACX mantissa 4
   ROR                ; shift FACX rounding byte
   INY                ; increment exponent diff
   BNE    LAB_D9A6        ; branch if range adjust not complete

LAB_D9BA
   CLC                ; just clear it
   RTS


;***********************************************************************************;
;
; constants and series for LOG(n)

LAB_D9BC
   .byte    $81,$00,$00,$00,$00    ; 1

LAB_D9C1
   .byte    $03                ; series counter
   .byte    $7F,$5E,$56,$CB,$79
   .byte    $80,$13,$9B,$0B,$64
   .byte    $80,$76,$38,$93,$16
   .byte    $82,$38,$AA,$3B,$20

LAB_D9D6
   .byte    $80,$35,$04,$F3,$34    ; 0.70711    1/root 2
LAB_D9DB
   .byte    $81,$35,$04,$F3,$34    ; 1.41421    root 2
LAB_D9E0
   .byte    $80,$80,$00,$00,$00    ; -0.5    1/2
LAB_D9E5
   .byte    $80,$31,$72,$17,$F8    ; 0.69315    LOG(2)


;***********************************************************************************;
;
; perform LOG()

LAB_D9EA
   JSR    LAB_DC2B        ; test sign and zero
   BEQ    LAB_D9F1        ; if zero do illegal quantity error then warm start

   BPL    LAB_D9F4        ; skip error if +ve

LAB_D9F1
   JMP    LAB_D248        ; do illegal quantity error then warm start

LAB_D9F4
   LDA    LAB_61        ; get FAC1 exponent
   SBC    #$7F            ; normalise it
   PHA                ; save it
   LDA    #$80            ; set exponent to zero
   STA    LAB_61        ; save FAC1 exponent
   LDA    #    LDY    #>LAB_D9D6        ; pointer to 1/root 2 high byte
   JSR    LAB_D867        ; add (AY) to FAC1 (1/root2)
   LDA    #    LDY    #>LAB_D9DB        ; pointer to root 2 high byte
   JSR    LAB_DB0F        ; convert AY and do (AY)/FAC1 (root2/(x+(1/root2)))
   LDA    #    LDY    #>LAB_D9BC        ; pointer to 1 high byte
   JSR    LAB_D850        ; subtract FAC1 ((root2/(x+(1/root2)))-1) from (AY)
   LDA    #    LDY    #>LAB_D9C1        ; pointer to series for LOG(n) high byte
   JSR    LAB_E040        ; ^2 then series evaluation
   LDA    #    LDY    #>LAB_D9E0        ; pointer to -0.5 high byte
   JSR    LAB_D867        ; add (AY) to FAC1
   PLA                ; restore FAC1 exponent
   JSR    LAB_DD7E        ; evaluate new ASCII digit
   LDA    #    LDY    #>LAB_D9E5        ; pointer to LOG(2) high byte

; do convert AY, FCA1*(AY)

LAB_DA28
   JSR    LAB_DA8C        ; unpack memory (AY) into FAC2
LAB_DA2B
   BNE    LAB_DA30        ; multiply FAC1 by FAC2 ??

   JMP    LAB_DA8B        ; exit if zero

LAB_DA30
   JSR    LAB_DAB7        ; test and adjust accumulators
   LDA    #$00            ; clear A
   STA    LAB_26        ; clear temp mantissa 1
   STA    LAB_27        ; clear temp mantissa 2
   STA    LAB_28        ; clear temp mantissa 3
   STA    LAB_29        ; clear temp mantissa 4
   LDA    LAB_70        ; get FAC1 rounding byte
   JSR    LAB_DA59        ; go do shift/add FAC2
   LDA    LAB_65        ; get FAC1 mantissa 4
   JSR    LAB_DA59        ; go do shift/add FAC2
   LDA    LAB_64        ; get FAC1 mantissa 3
   JSR    LAB_DA59        ; go do shift/add FAC2
   LDA    LAB_63        ; get FAC1 mantissa 2
   JSR    LAB_DA59        ; go do shift/add FAC2
   LDA    LAB_62        ; get FAC1 mantissa 1
   JSR    LAB_DA5E        ; go do shift/add FAC2
   JMP    LAB_DB8F        ; copy temp to FAC1, normalise and return

LAB_DA59
   BNE    LAB_DA5E        ; branch if byte <> zero

   JMP    LAB_D983        ; shift FCAtemp << A+8 times

                   ; else do shift and add
LAB_DA5E
   LSR                ; shift byte
   ORA    #$80            ; set top bit (mark for 8 times)
LAB_DA61
   TAY                ; copy result
   BCC    LAB_DA7D        ; skip next if bit was zero

   CLC                ; clear carry for add
   LDA    LAB_29        ; get temp mantissa 4
   ADC    LAB_6D        ; add FAC2 mantissa 4
   STA    LAB_29        ; save temp mantissa 4
   LDA    LAB_28        ; get temp mantissa 3
   ADC    LAB_6C        ; add FAC2 mantissa 3
   STA    LAB_28        ; save temp mantissa 3
   LDA    LAB_27        ; get temp mantissa 2
   ADC    LAB_6B        ; add FAC2 mantissa 2
   STA    LAB_27        ; save temp mantissa 2
   LDA    LAB_26        ; get temp mantissa 1
   ADC    LAB_6A        ; add FAC2 mantissa 1
   STA    LAB_26        ; save temp mantissa 1
LAB_DA7D
   ROR    LAB_26        ; shift temp mantissa 1
   ROR    LAB_27        ; shift temp mantissa 2
   ROR    LAB_28        ; shift temp mantissa 3
   ROR    LAB_29        ; shift temp mantissa 4
   ROR    LAB_70        ; shift temp rounding byte
   TYA                ; get byte back
   LSR                ; shift byte
   BNE    LAB_DA61        ; loop if all bits not done

LAB_DA8B
   RTS


;***********************************************************************************;
;
; unpack memory (AY) into FAC2

LAB_DA8C
   STA    LAB_22        ; save pointer low byte
   STY    LAB_23        ; save pointer high byte
   LDY    #$04            ; 5 bytes to get (0-4)
   LDA    (LAB_22),Y        ; get mantissa 4
   STA    LAB_6D        ; save FAC2 mantissa 4
   DEY                ; decrement index
   LDA    (LAB_22),Y        ; get mantissa 3
   STA    LAB_6C        ; save FAC2 mantissa 3
   DEY                ; decrement index
   LDA    (LAB_22),Y        ; get mantissa 2
   STA    LAB_6B        ; save FAC2 mantissa 2
   DEY                ; decrement index
   LDA    (LAB_22),Y        ; get mantissa 1 + sign
   STA    LAB_6E        ; save FAC2 sign (b7)
   EOR    LAB_66        ; EOR with FAC1 sign (b7)
   STA    LAB_6F        ; save sign compare (FAC1 EOR FAC2)
   LDA    LAB_6E        ; recover FAC2 sign (b7)
   ORA    #$80            ; set 1xxx xxx (set normal bit)
   STA    LAB_6A        ; save FAC2 mantissa 1
   DEY                ; decrement index
   LDA    (LAB_22),Y        ; get exponent byte
   STA    LAB_69        ; save FAC2 exponent
   LDA    LAB_61        ; get FAC1 exponent
   RTS


;***********************************************************************************;
;
; test and adjust accumulators

LAB_DAB7
   LDA    LAB_69        ; get FAC2 exponent

LAB_DAB9
   BEQ    LAB_DADA        ; branch if FAC2 = $00 (handle underflow)

   CLC                ; clear carry for add
   ADC    LAB_61        ; add FAC1 exponent
   BCC    LAB_DAC4        ; branch if sum of exponents < $0100

   BMI    LAB_DADF        ; do overflow error

   CLC                ; clear carry for the add
   .byte    $2C            ; makes next line BIT LAB_1410
LAB_DAC4
   BPL    LAB_DADA        ; if +ve go handle underflow

   ADC    #$80            ; adjust exponent
   STA    LAB_61        ; save FAC1 exponent
   BNE    LAB_DACF        ; branch if not zero

   JMP    LAB_D8FB        ; save FAC1 sign and return


LAB_DACF
   LDA    LAB_6F        ; get sign compare (FAC1 EOR FAC2)
   STA    LAB_66        ; save FAC1 sign (b7)
   RTS


;***********************************************************************************;
;
; handle overflow and underflow

LAB_DAD4
   LDA    LAB_66        ; get FAC1 sign (b7)
   EOR    #$FF            ; complement it
   BMI    LAB_DADF        ; do overflow error

                   ; handle underflow
LAB_DADA
   PLA                ; pop return address low byte
   PLA                ; pop return address high byte
   JMP    LAB_D8F7        ; clear FAC1 exponent and sign and return

LAB_DADF
   JMP    LAB_D97E        ; do overflow error then warm start


;***********************************************************************************;
;
; multiply FAC1 by 10

LAB_DAE2
   JSR    LAB_DC0C        ; round and copy FAC1 to FAC2
   TAX                ; copy exponent (set the flags)
   BEQ    LAB_DAF8        ; exit if zero

   CLC                ; clear carry for add
   ADC    #$02            ; add two to exponent (*4)
   BCS    LAB_DADF        ; do overflow error if > $FF

; FAC1 = (FAC1 + FAC2) * 2

LAB_DAED
   LDX    #$00            ; clear byte
   STX    LAB_6F        ; clear sign compare (FAC1 EOR FAC2)
   JSR    LAB_D877        ; add FAC2 to FAC1 (*5)
   INC    LAB_61        ; increment FAC1 exponent (*10)
   BEQ    LAB_DADF        ; if exponent now zero go do overflow error

LAB_DAF8
   RTS


;***********************************************************************************;
;
; 10 as a floating value

LAB_DAF9
   .byte    $84,$20,$00,$00,$00    ; 10


;***********************************************************************************;
;
; divide FAC1 by 10

LAB_DAFE
   JSR    LAB_DC0C        ; round and copy FAC1 to FAC2
   LDA    #    LDY    #>LAB_DAF9        ; set 10 pointer high byte
   LDX    #$00            ; clear sign

; divide by (AY) (X=sign)

LAB_DB07
   STX    LAB_6F        ; save sign compare (FAC1 EOR FAC2)
   JSR    LAB_DBA2        ; unpack memory (AY) into FAC1
   JMP    LAB_DB12        ; do FAC2/FAC1

                   ; Perform divide-by

; convert AY and do (AY)/FAC1

LAB_DB0F
   JSR    LAB_DA8C        ; unpack memory (AY) into FAC2
LAB_DB12
   BEQ    LAB_DB8A        ; if zero go do /0 error

   JSR    LAB_DC1B        ; round FAC1
   LDA    #$00            ; clear A
   SEC                ; set carry for subtract
   SBC    LAB_61        ; subtract FAC1 exponent (2s complement)
   STA    LAB_61        ; save FAC1 exponent
   JSR    LAB_DAB7        ; test and adjust accumulators
   INC    LAB_61        ; increment FAC1 exponent
   BEQ    LAB_DADF        ; if zero do overflow error

   LDX    #$FC            ; set index to FAC temp
   LDA    #$01            ;.set byte
LAB_DB29
   LDY    LAB_6A        ; get FAC2 mantissa 1
   CPY    LAB_62        ; compare FAC1 mantissa 1
   BNE    LAB_DB3F        ; if <> go use the result

   LDY    LAB_6B        ; get FAC2 mantissa 2
   CPY    LAB_63        ; compare FAC1 mantissa 2
   BNE    LAB_DB3F        ; if <> go use the result

   LDY    LAB_6C        ; get FAC2 mantissa 3
   CPY    LAB_64        ; compare FAC1 mantissa 3
   BNE    LAB_DB3F        ; if <> go use the result

   LDY    LAB_6D        ; get FAC2 mantissa 4
   CPY    LAB_65        ; compare FAC1 mantissa 4
LAB_DB3F
   PHP                ; save the FAC2-FAC1 compare status
   ROL                ;.shift byte
   BCC    LAB_DB4C        ; skip next if no carry

   INX                ; increment index to FAC temp
   STA    LAB_29,X        ;.
   BEQ    LAB_DB7A        ;.

   BPL    LAB_DB7E        ;.

   LDA    #$01            ;.
LAB_DB4C
   PLP                ; restore FAC2-FAC1 compare status
   BCS    LAB_DB5D        ; if FAC2 >= FAC1 then do subtract

                   ; FAC2 = FAC2*2
LAB_DB4F
   ASL    LAB_6D        ; shift FAC2 mantissa 4
   ROL    LAB_6C        ; shift FAC2 mantissa 3
   ROL    LAB_6B        ; shift FAC2 mantissa 2
   ROL    LAB_6A        ; shift FAC2 mantissa 1
   BCS    LAB_DB3F        ; loop with no compare

   BMI    LAB_DB29        ; loop with compare

   BPL    LAB_DB3F        ; loop always with no compare

LAB_DB5D
   TAY                ; save FAC2-FAC1 compare status
   LDA    LAB_6D        ; get FAC2 mantissa 4
   SBC    LAB_65        ; subtract FAC1 mantissa 4
   STA    LAB_6D        ; save FAC2 mantissa 4
   LDA    LAB_6C        ; get FAC2 mantissa 3
   SBC    LAB_64        ; subtract FAC1 mantissa 3
   STA    LAB_6C        ; save FAC2 mantissa 3
   LDA    LAB_6B        ; get FAC2 mantissa 2
   SBC    LAB_63        ; subtract FAC1 mantissa 2
   STA    LAB_6B        ; save FAC2 mantissa 2
   LDA    LAB_6A        ; get FAC2 mantissa 1
   SBC    LAB_62        ; subtract FAC1 mantissa 1
   STA    LAB_6A        ; save FAC2 mantissa 1
   TYA                ; restore FAC2-FAC1 compare status
   JMP    LAB_DB4F        ; go shift FAC2

LAB_DB7A
   LDA    #$40            ;.
   BNE    LAB_DB4C        ; branch always

; do A<<6, save as FAC1 rounding byte, normalise and return

LAB_DB7E
   ASL                ;
   ASL                ;
   ASL                ;
   ASL                ;
   ASL                ;
   ASL                ;
   STA    LAB_70        ; save FAC1 rounding byte
   PLP                ; dump FAC2-FAC1 compare status
   JMP    LAB_DB8F        ; copy temp to FAC1, normalise and return

; do "Divide by zero" error

LAB_DB8A
   LDX    #$14            ; error $14, divide by zero error
   JMP    LAB_C437        ; do error #X then warm start

LAB_DB8F
   LDA    LAB_26        ; get temp mantissa 1
   STA    LAB_62        ; save FAC1 mantissa 1
   LDA    LAB_27        ; get temp mantissa 2
   STA    LAB_63        ; save FAC1 mantissa 2
   LDA    LAB_28        ; get temp mantissa 3
   STA    LAB_64        ; save FAC1 mantissa 3
   LDA    LAB_29        ; get temp mantissa 4
   STA    LAB_65        ; save FAC1 mantissa 4
   JMP    LAB_D8D7        ; normalise FAC1 and return


;***********************************************************************************;
;
; unpack memory (AY) into FAC1

LAB_DBA2
   STA    LAB_22        ; save pointer low byte
   STY    LAB_23        ; save pointer high byte
   LDY    #$04            ; 5 bytes to do
   LDA    (LAB_22),Y        ; get fifth byte
   STA    LAB_65        ; save FAC1 mantissa 4
   DEY                ; decrement index
   LDA    (LAB_22),Y        ; get fourth byte
   STA    LAB_64        ; save FAC1 mantissa 3
   DEY                ; decrement index
   LDA    (LAB_22),Y        ; get third byte
   STA    LAB_63        ; save FAC1 mantissa 2
   DEY                ; decrement index
   LDA    (LAB_22),Y        ; get second byte
   STA    LAB_66        ; save FAC1 sign (b7)
   ORA    #$80            ; set 1xxx xxxx (add normal bit)
   STA    LAB_62        ; save FAC1 mantissa 1
   DEY                ; decrement index
   LDA    (LAB_22),Y        ; get first byte (exponent)
   STA    LAB_61        ; save FAC1 exponent
   STY    LAB_70        ; clear FAC1 rounding byte
   RTS


;***********************************************************************************;
;
; pack FAC1 into LAB_5C

LAB_DBC7
   LDX    #    .byte    $2C            ; makes next line BIT LAB_57A2

; pack FAC1 into LAB_57

LAB_DBCA
   LDX    #    LDY    #>LAB_57        ; set pointer high byte
   BEQ    LAB_DBD4        ; pack FAC1 into (XY) and return, branch always

; pack FAC1 into variable pointer

LAB_DBD0
   LDX    LAB_49        ; get destination pointer low byte
   LDY    LAB_4A        ; get destination pointer high byte

; pack FAC1 into (XY)

LAB_DBD4
   JSR    LAB_DC1B        ; round FAC1
   STX    LAB_22        ; save pointer low byte
   STY    LAB_23        ; save pointer high byte
   LDY    #$04            ; set index
   LDA    LAB_65        ; get FAC1 mantissa 4
   STA    (LAB_22),Y        ; store in destination
   DEY                ; decrement index
   LDA    LAB_64        ; get FAC1 mantissa 3
   STA    (LAB_22),Y        ; store in destination
   DEY                ; decrement index
   LDA    LAB_63        ; get FAC1 mantissa 2
   STA    (LAB_22),Y        ; store in destination
   DEY                ; decrement index
   LDA    LAB_66        ; get FAC1 sign (b7)
   ORA    #$7F            ; set bits x111 1111
   AND    LAB_62        ; AND in FAC1 mantissa 1
   STA    (LAB_22),Y        ; store in destination
   DEY                ; decrement index
   LDA    LAB_61        ; get FAC1 exponent
   STA    (LAB_22),Y        ; store in destination
   STY    LAB_70        ; clear FAC1 rounding byte
   RTS


;***********************************************************************************;
;
; copy FAC2 to FAC1

LAB_DBFC
   LDA    LAB_6E        ; get FAC2 sign (b7)

; save FAC1 sign and copy ABS(FAC2) to FAC1

LAB_DBFE
   STA    LAB_66        ; save FAC1 sign (b7)
   LDX    #$05            ; 5 bytes to copy
LAB_DC02
   LDA    LAB_68,X        ; get byte from FAC2,X
   STA    LAB_60,X        ; save byte at FAC1,X
   DEX                ; decrement count
   BNE    LAB_DC02        ; loop if not all done

   STX    LAB_70        ; clear FAC1 rounding byte
   RTS


;***********************************************************************************;
;
; round and copy FAC1 to FAC2

LAB_DC0C
   JSR    LAB_DC1B        ; round FAC1

; copy FAC1 to FAC2

LAB_DC0F
   LDX    #$06            ; 6 bytes to copy
LAB_DC11
   LDA    LAB_60,X        ; get byte from FAC1,X
   STA    LAB_68,X        ; save byte at FAC2,X
   DEX                ; decrement count
   BNE    LAB_DC11        ; loop if not all done

   STX    LAB_70        ; clear FAC1 rounding byte
LAB_DC1A
   RTS


;***********************************************************************************;
;
; round FAC1

LAB_DC1B
   LDA    LAB_61        ; get FAC1 exponent
   BEQ    LAB_DC1A        ; exit if zero

   ASL    LAB_70        ; shift FAC1 rounding byte
   BCC    LAB_DC1A        ; exit if no overflow

; round FAC1 (no check)

LAB_DC23
   JSR    LAB_D96F        ; increment FAC1 mantissa
   BNE    LAB_DC1A        ; branch if no overflow

   JMP    LAB_D938        ; nornalise FAC1 for C=1 and return

; get FAC1 sign
; return A = $FF, Cb = 1/-ve A = $01, Cb = 0/+ve, A = $00, Cb = ?/0

LAB_DC2B
   LDA    LAB_61        ; get FAC1 exponent
   BEQ    LAB_DC38        ; exit if zero (allready correct SGN(0)=0)

; return A = $FF, Cb = 1/-ve A = $01, Cb = 0/+ve
; no = 0 check

LAB_DC2F
   LDA    LAB_66        ; else get FAC1 sign (b7)

; return A = $FF, Cb = 1/-ve A = $01, Cb = 0/+ve
; no = 0 check, sign in A

LAB_DC31
   ROL                ; move sign bit to carry
   LDA    #$FF            ; set byte for -ve result
   BCS    LAB_DC38        ; return if sign was set (-ve)

   LDA    #$01            ; else set byte for +ve result
LAB_DC38
   RTS


;***********************************************************************************;
;
; perform SGN()

LAB_DC39
   JSR    LAB_DC2B        ; get FAC1 sign, return A = $FF -ve, A = $01 +ve

; save A as integer byte

LAB_DC3C
   STA    LAB_62        ; save FAC1 mantissa 1
   LDA    #$00            ; clear A
   STA    LAB_63        ; clear FAC1 mantissa 2
   LDX    #$88            ; set exponent

; set exponent = X, clear FAC1 3 and 4 and normalise

LAB_DC44
   LDA    LAB_62        ; get FAC1 mantissa 1
   EOR    #$FF            ; complement it
   ROL                ; sign bit into carry

; set exponent = X, clear mantissa 4 and 3 and normalise FAC1

LAB_DC49
   LDA    #$00            ; clear A
   STA    LAB_65        ; clear FAC1 mantissa 4
   STA    LAB_64        ; clear FAC1 mantissa 3

; set exponent = X and normalise FAC1

LAB_DC4F
   STX    LAB_61        ; set FAC1 exponent
   STA    LAB_70        ; clear FAC1 rounding byte
   STA    LAB_66        ; clear FAC1 sign (b7)
   JMP    LAB_D8D2        ; do ABS and normalise FAC1

; perform ABS()

LAB_DC58
   LSR    LAB_66        ; clear FAC1 sign, put zero in b7
   RTS


;***********************************************************************************;
;
; compare FAC1 with (AY)
; returns A=$00 if FAC1 = (AY)
; returns A=$01 if FAC1 > (AY)
; returns A=$FF if FAC1 < (AY)

LAB_DC5B
   STA    LAB_24        ; save pointer low byte
LAB_DC5D
   STY    LAB_25        ; save pointer high byte
   LDY    #$00            ; clear index
   LDA    (LAB_24),Y        ; get exponent
   INY                ; increment index
   TAX                ; copy (AY) exponent to X
   BEQ    LAB_DC2B        ; branch if (AY) exponent=0 and get FAC1 sign
                   ; A = $FF, Cb = 1/-ve A = $01, Cb = 0/+ve

   LDA    (LAB_24),Y        ; get (AY) mantissa 1, with sign
   EOR    LAB_66        ; EOR FAC1 sign (b7)
   BMI    LAB_DC2F        ; if signs <> do return A = $FF, Cb = 1/-ve
                   ; A = $01, Cb = 0/+ve and return

   CPX    LAB_61        ; compare (AY) exponent with FAC1 exponent
   BNE    LAB_DC92        ; branch if different

   LDA    (LAB_24),Y        ; get (AY) mantissa 1, with sign
   ORA    #$80            ; normalise top bit
   CMP    LAB_62        ; compare with FAC1 mantissa 1
   BNE    LAB_DC92        ; branch if different

   INY                ; increment index
   LDA    (LAB_24),Y        ; get mantissa 2
   CMP    LAB_63        ; compare with FAC1 mantissa 2
   BNE    LAB_DC92        ; branch if different

   INY                ; increment index
   LDA    (LAB_24),Y        ; get mantissa 3
   CMP    LAB_64        ; compare with FAC1 mantissa 3
   BNE    LAB_DC92        ; branch if different

   INY                ; increment index
   LDA    #$7F            ; set for 1/2 value rounding byte
   CMP    LAB_70        ; compare with FAC1 rounding byte (set carry)
   LDA    (LAB_24),Y        ; get mantissa 4
   SBC    LAB_65        ; subtract FAC1 mantissa 4
   BEQ    LAB_DCBA        ; exit if mantissa 4 equal

; gets here if number <> FAC1

LAB_DC92
   LDA    LAB_66        ; get FAC1 sign (b7)
   BCC    LAB_DC98        ; branch if FAC1 > (AY)

   EOR    #$FF            ; else toggle FAC1 sign
LAB_DC98
   JMP    LAB_DC31        ; return A = $FF, Cb = 1/-ve A = $01, Cb = 0/+ve


;***********************************************************************************;
;
; convert FAC1 floating to fixed

LAB_DC9B
   LDA    LAB_61        ; get FAC1 exponent
   BEQ    LAB_DCE9        ; if zero go clear FAC1 and return

   SEC                ; set carry for subtract
   SBC    #$A0            ; subtract maximum integer range exponent
   BIT    LAB_66        ; test FAC1 sign (b7)
   BPL    LAB_DCAF        ; branch if FAC1 +ve

                   ; FAC1 was -ve
   TAX                ; copy subtracted exponent
   LDA    #$FF            ; overflow for -ve number
   STA    LAB_68        ; set FAC1 overflow byte
   JSR    LAB_D94D        ; twos complement FAC1 mantissa
   TXA                ; restore subtracted exponent
LAB_DCAF
   LDX    #$61            ; set index to FAC1
   CMP    #$F9            ; compare exponent result
   BPL    LAB_DCBB        ; if < 8 shifts shift FAC1 A times right and return

   JSR    LAB_D999        ; shift FAC1 A times right (> 8 shifts)
   STY    LAB_68        ; clear FAC1 overflow byte
LAB_DCBA
   RTS


;***********************************************************************************;
;
; shift FAC1 A times right

LAB_DCBB
   TAY                ; copy shift count
   LDA    LAB_66        ; get FAC1 sign (b7)
   AND    #$80            ; mask sign bit only (x000 0000)
   LSR    LAB_62        ; shift FAC1 mantissa 1
   ORA    LAB_62        ; OR sign in b7 FAC1 mantissa 1
   STA    LAB_62        ; save FAC1 mantissa 1
   JSR    LAB_D9B0        ; shift FAC1 Y times right
   STY    LAB_68        ; clear FAC1 overflow byte
   RTS


;***********************************************************************************;
;
; perform INT()

LAB_DCCC
   LDA    LAB_61        ; get FAC1 exponent
   CMP    #$A0            ; compare with max int
   BCS    LAB_DCF2        ; exit if >= (allready int, too big for fractional part!)

   JSR    LAB_DC9B        ; convert FAC1 floating to fixed
   STY    LAB_70        ; save FAC1 rounding byte
   LDA    LAB_66        ; get FAC1 sign (b7)
   STY    LAB_66        ; save FAC1 sign (b7)
   EOR    #$80            ; toggle FAC1 sign
   ROL                ; shift into carry
   LDA    #$A0            ; set new exponent
   STA    LAB_61        ; save FAC1 exponent
   LDA    LAB_65        ; get FAC1 mantissa 4
   STA    LAB_07        ; save FAC1 mantissa 4 for power function
   JMP    LAB_D8D2        ; do ABS and normalise FAC1


;***********************************************************************************;
;
; clear FAC1 and return

LAB_DCE9
   STA    LAB_62        ; clear FAC1 mantissa 1
   STA    LAB_63        ; clear FAC1 mantissa 2
   STA    LAB_64        ; clear FAC1 mantissa 3
   STA    LAB_65        ; clear FAC1 mantissa 4
   TAY                ; clear Y
LAB_DCF2
   RTS


;***********************************************************************************;
;
; get FAC1 from string

LAB_DCF3
   LDY    #$00            ; clear Y
   LDX    #$0A            ; set index
LAB_DCF7
   STY    LAB_5D,X        ; clear byte
   DEX                ; decrement index
   BPL    LAB_DCF7        ; loop until numexp to negnum (and FAC1) = $00

   BCC    LAB_DD0D        ; branch if first character is numeric

   CMP    #'-'            ; else compare with "-"
   BNE    LAB_DD06        ; branch if not "-"

   STX    LAB_67        ; set flag for -ve n (negnum = $FF)
   BEQ    LAB_DD0A        ; branch always

LAB_DD06
   CMP    #'+'            ; else compare with "+"
   BNE    LAB_DD0F        ; branch if not "+"

LAB_DD0A
   JSR    LAB_0073        ; increment and scan memory
LAB_DD0D
   BCC    LAB_DD6A        ; branch if numeric character

LAB_DD0F
   CMP    #'.'            ; else compare with "."
   BEQ    LAB_DD41        ; branch if "."

   CMP    #'E'            ; else compare with "E"
   BNE    LAB_DD47        ; branch if not "E"

                   ; was "E" so evaluate exponential part
   JSR    LAB_0073        ; increment and scan memory
   BCC    LAB_DD33        ; branch if numeric character

   CMP    #TK_MINUS        ; else compare with token for -
   BEQ    LAB_DD2E        ; branch if token for -

   CMP    #'-'            ; else compare with "-"
   BEQ    LAB_DD2E        ; branch if "-"

   CMP    #TK_PLUS        ; else compare with token for +
   BEQ    LAB_DD30        ; branch if token for +

   CMP    #'+'            ; else compare with "+"
   BEQ    LAB_DD30        ; branch if "+"

   BNE    LAB_DD35        ; branch always

LAB_DD2E
   ROR    LAB_60        ; set exponent -ve flag (C, which=1, into b7)
LAB_DD30
   JSR    LAB_0073        ; increment and scan memory
LAB_DD33
   BCC    LAB_DD91        ; branch if numeric character

LAB_DD35
   BIT    LAB_60        ; test exponent -ve flag
   BPL    LAB_DD47        ; if +ve go evaluate exponent

                   ; else do exponent = -exponent
   LDA    #$00            ; clear result
   SEC                ; set carry for subtract
   SBC    LAB_5E        ; subtract exponent byte
   JMP    LAB_DD49        ; go evaluate exponent

LAB_DD41
   ROR    LAB_5F        ; set decimal point flag
   BIT    LAB_5F        ; test decimal point flag
   BVC    LAB_DD0A        ; branch if only one decimal point so far

                   ; evaluate exponent
LAB_DD47
   LDA    LAB_5E        ; get exponent count byte
LAB_DD49
   SEC                ; set carry for subtract
   SBC    LAB_5D        ; subtract numerator exponent
   STA    LAB_5E        ; save exponent count byte
   BEQ    LAB_DD62        ; branch if no adjustment

   BPL    LAB_DD5B        ; else if +ve go do FAC1*10^expcnt

                   ; else go do FAC1/10^(0-expcnt)
LAB_DD52
   JSR    LAB_DAFE        ; divide FAC1 by 10
   INC    LAB_5E        ; increment exponent count byte
   BNE    LAB_DD52        ; loop until all done

   BEQ    LAB_DD62        ; branch always

LAB_DD5B
   JSR    LAB_DAE2        ; multiply FAC1 by 10
   DEC    LAB_5E        ; decrement exponent count byte
   BNE    LAB_DD5B        ; loop until all done

LAB_DD62
   LDA    LAB_67        ; get -ve flag
   BMI    LAB_DD67        ; if -ve do - FAC1 and return

   RTS

; do - FAC1 and return

LAB_DD67
   JMP    LAB_DFB4        ; do - FAC1

; do unsigned FAC1*10+number

LAB_DD6A
   PHA                ; save character
   BIT    LAB_5F        ; test decimal point flag
   BPL    LAB_DD71        ; skip exponent increment if not set

   INC    LAB_5D        ; else increment number exponent
LAB_DD71
   JSR    LAB_DAE2        ; multiply FAC1 by 10
   PLA                ; restore character
   SEC                ; set carry for subtract
   SBC    #'0'            ; convert to binary
   JSR    LAB_DD7E        ; evaluate new ASCII digit
   JMP    LAB_DD0A        ; go do next character

; evaluate new ASCII digit
; multiply FAC1 by 10 then (ABS) add in new digit

LAB_DD7E
   PHA                ; save digit
   JSR    LAB_DC0C        ; round and copy FAC1 to FAC2
   PLA                ; restore digit
   JSR    LAB_DC3C        ; save A as integer byte
   LDA    LAB_6E        ; get FAC2 sign (b7)
   EOR    LAB_66        ; toggle with FAC1 sign (b7)
   STA    LAB_6F        ; save sign compare (FAC1 EOR FAC2)
   LDX    LAB_61        ; get FAC1 exponent
   JMP    LAB_D86A        ; add FAC2 to FAC1 and return

; evaluate next character of exponential part of number

LAB_DD91
   LDA    LAB_5E        ; get exponent count byte
   CMP    #$0A            ; compare with 10 decimal
   BCC    LAB_DDA0        ; branch if less

   LDA    #$64            ; make all -ve exponents = -100 decimal (causes underflow)
   BIT    LAB_60        ; test exponent -ve flag
   BMI    LAB_DDAE        ; branch if -ve

   JMP    LAB_D97E        ; else do overflow error then warm start

LAB_DDA0
   ASL                ; *2
   ASL                ; *4
   CLC                ; clear carry for add
   ADC    LAB_5E        ; *5
   ASL                ; *10
   CLC                ; clear carry for add
   LDY    #$00            ; set index
   ADC    (LAB_7A),Y        ; add character (will be $30 too much!)
   SEC                ; set carry for subtract
   SBC    #'0'            ; convert character to binary
LAB_DDAE
   STA    LAB_5E        ; save exponent count byte
   JMP    LAB_DD30        ; go get next character


;***********************************************************************************;
;
LAB_DDB3
   .byte    $9B,$3E,$BC,$1F,$FD
                   ; 99999999.90625, maximum value with at least one decimal
LAB_DDB8
   .byte    $9E,$6E,$6B,$27,$FD
                   ; 999999999.25, maximum value before scientific notation
LAB_DDBD
   .byte    $9E,$6E,$6B,$28,$00
                   ; 1000000000


;***********************************************************************************;
;
; do " IN " line number message

LAB_DDC2
   LDA    #    LDY    #>LAB_C371        ; set " IN " pointer high byte
   JSR    LAB_DDDA        ; print null terminated string
   LDA    LAB_3A        ; get the current line number high byte
   LDX    LAB_39        ; get the current line number low byte


;***********************************************************************************;
;
; print XA as unsigned integer

LAB_DDCD
   STA    LAB_62        ; save high byte as FAC1 mantissa1
   STX    LAB_63        ; save low byte as FAC1 mantissa2
   LDX    #$90            ; set exponent to 16d bits
   SEC                ; set integer is +ve flag
   JSR    LAB_DC49        ; set exponent = X, clear mantissa 4 and 3 and normalise
                   ; FAC1
   JSR    LAB_DDDF        ; convert FAC1 to string
LAB_DDDA
   JMP    LAB_CB1E        ; print null terminated string


;***********************************************************************************;
;
; convert FAC1 to ASCII string result in (AY)

LAB_DDDD
   LDY    #$01            ; set index = 1
LAB_DDDF
   LDA    #' '            ; character = " " (assume +ve)
   BIT    LAB_66        ; test FAC1 sign (b7)
   BPL    LAB_DDE7        ; if +ve skip the - sign set

   LDA    #'-'            ; else character = "-"
LAB_DDE7
   STA    LAB_00FF,Y        ; save leading character (" " or "-")
   STA    LAB_66        ; save FAC1 sign (b7)
   STY    LAB_71        ; save the index
   INY                ; increment index
   LDA    #'0'            ; set character = "0"
   LDX    LAB_61        ; get FAC1 exponent
   BNE    LAB_DDF8        ; if FAC1<>0 go convert it

                   ; exponent was $00 so FAC1 is 0
   JMP    LAB_DF04        ; save last character, [EOT] and exit

; FAC1 is some non zero value

LAB_DDF8
   LDA    #$00            ; clear (number exponent count)
   CPX    #$80            ; compare FAC1 exponent with $80 (<1.00000)
   BEQ    LAB_DE00        ; branch if 0.5 <= FAC1 < 1.0

   BCS    LAB_DE09        ; branch if FAC1=>1

LAB_DE00
   LDA    #    LDY    #>LAB_DDBD        ; set 1000000000 pointer high byte
   JSR    LAB_DA28        ; do convert AY, FCA1*(AY)
   LDA    #$F7            ; set number exponent count
LAB_DE09
   STA    LAB_5D        ; save number exponent count
LAB_DE0B
   LDA    #    LDY    #>LAB_DDB8        ; set 999999999.25 pointer high byte
   JSR    LAB_DC5B        ; compare FAC1 with (AY)
   BEQ    LAB_DE32        ; exit if FAC1 = (AY)

   BPL    LAB_DE28        ; go do /10 if FAC1 > (AY)

                   ; FAC1 < (AY)
LAB_DE16
   LDA    #    LDY    #>LAB_DDB3        ; set 99999999.90625 pointer high byte
   JSR    LAB_DC5B        ; compare FAC1 with (AY)
   BEQ    LAB_DE21        ; branch if FAC1 = (AY) (allow decimal places)

   BPL    LAB_DE2F        ; branch if FAC1 > (AY) (no decimal places)

                   ; FAC1 <= (AY)
LAB_DE21
   JSR    LAB_DAE2        ; multiply FAC1 by 10
   DEC    LAB_5D        ; decrement number exponent count
   BNE    LAB_DE16        ; go test again, branch always

LAB_DE28
   JSR    LAB_DAFE        ; divide FAC1 by 10
   INC    LAB_5D        ; increment number exponent count
   BNE    LAB_DE0B        ; go test again, branch always

; now we have just the digits to do

LAB_DE2F
   JSR    LAB_D849        ; add 0.5 to FAC1 (round FAC1)
LAB_DE32
   JSR    LAB_DC9B        ; convert FAC1 floating to fixed
   LDX    #$01            ; set default digits before dp = 1
   LDA    LAB_5D        ; get number exponent count
   CLC                ; clear carry for add
   ADC    #$0A            ; up to 9 digits before point
   BMI    LAB_DE47        ; if -ve then 1 digit before dp

   CMP    #$0B            ; A>=$0B if n>=1E9
   BCS    LAB_DE48        ; branch if >= $0B

                   ; carry is clear
   ADC    #$FF            ; take 1 from digit count
   TAX                ; copy to X
   LDA    #$02            ; set the exponent adjust
LAB_DE47
   SEC                ; set carry for subtract
LAB_DE48
   SBC    #$02            ; -2
   STA    LAB_5E        ; save the exponent adjust
   STX    LAB_5D        ; save digits before dp count
   TXA                ; copy digits before dp count to A
   BEQ    LAB_DE53        ; if no digits before the dp go do the "."

   BPL    LAB_DE66        ; if there are digits before the dp go do them

LAB_DE53
   LDY    LAB_71        ; get the output string index
   LDA    #'.'            ; character "."
   INY                ; increment the index
   STA    LAB_0100-1,Y    ; save the "." to the output string
   TXA                ; copy digits before dp count to A
   BEQ    LAB_DE64        ; if no digits before the dp skip the "0"

   LDA    #'0'            ; character "0"
   INY                ; increment index
   STA    LAB_0100-1,Y    ; save the "0" to the output string
LAB_DE64
   STY    LAB_71        ; save the output string index
LAB_DE66
   LDY    #$00            ; clear the powers of 10 index (point to -100,000,000)
LAB_DE68
   LDX    #$80            ; clear the digit, set the test sense
LAB_DE6A
   LDA    LAB_65        ; get FAC1 mantissa 4
   CLC                ; clear carry for add
   ADC    LAB_DF16+3,Y    ; add byte 4, least significant
   STA    LAB_65        ; save FAC1 mantissa4
   LDA    LAB_64        ; get FAC1 mantissa 3
   ADC    LAB_DF16+2,Y    ; add byte 3
   STA    LAB_64        ; save FAC1 mantissa3
   LDA    LAB_63        ; get FAC1 mantissa 2
   ADC    LAB_DF16+1,Y    ; add byte 2
   STA    LAB_63        ; save FAC1 mantissa2
   LDA    LAB_62        ; get FAC1 mantissa 1
   ADC    LAB_DF16+0,Y    ; add byte 1, most significant
   STA    LAB_62        ; save FAC1 mantissa1
   INX                ; increment the digit, set the sign on the test sense bit
   BCS    LAB_DE8E        ; if the carry is set go test if the result was positive

                   ; else the result needs to be negative
   BPL    LAB_DE6A        ; not -ve so try again

   BMI    LAB_DE90        ; else done so return the digit

LAB_DE8E
   BMI    LAB_DE6A        ; not +ve so try again

; else done so return the digit

LAB_DE90
   TXA                ; copy the digit
   BCC    LAB_DE97        ; if Cb=0 just use it

   EOR    #$FF            ; else make the 2's complement ..
   ADC    #$0A            ; .. and subtract it from 10
LAB_DE97
   ADC    #'0'-1        ; add "0"-1 to result
   INY                ; increment ..
   INY                ; .. index to..
   INY                ; .. next less ..
   INY                ; .. power of ten
   STY    LAB_47        ; save the powers of ten table index
   LDY    LAB_71        ; get output string index
   INY                ; increment output string index
   TAX                ; copy character to X
   AND    #$7F            ; mask out top bit
   STA    LAB_0100-1,Y    ; save to output string
   DEC    LAB_5D        ; decrement # of characters before the dp
   BNE    LAB_DEB2        ; if still characters to do skip the decimal point

                   ; else output the point
   LDA    #'.'            ; character "."
   INY                ; increment output string index
   STA    LAB_0100-1,Y    ; save to output string
LAB_DEB2
   STY    LAB_71        ; save the output string index
   LDY    LAB_47        ; get the powers of ten table index
   TXA                ; get the character back
   EOR    #$FF            ; toggle the test sense bit
   AND    #$80            ; clear the digit
   TAX                ; copy it to the new digit
   CPY    #LAB_DF3A-LAB_DF16            
                   ; compare the table index with the max for decimal numbers
   BEQ    LAB_DEC4        ; if at the max exit the digit loop

   CPY    #LAB_DF52-LAB_DF16
                   ; compare the table index with the max for time
   BNE    LAB_DE6A        ; loop if not at the max

; now remove trailing zeroes

LAB_DEC4
   LDY    LAB_71        ; restore the output string index
LAB_DEC6
   LDA    LAB_0100-1,Y    ; get character from output string
   DEY                ; decrement output string index
   CMP    #'0'            ; compare with "0"
   BEQ    LAB_DEC6        ; loop until non "0" character found

   CMP    #'.'            ; compare with "."
   BEQ    LAB_DED3        ; branch if was dp

                   ; restore last character
   INY                ; increment output string index
LAB_DED3
   LDA    #'+'            ; character "+"
   LDX    LAB_5E        ; get exponent count
   BEQ    LAB_DF07        ; if zero go set null terminator and exit

                   ; exponent isn't zero so write exponent
   BPL    LAB_DEE3        ; branch if exponent count +ve

   LDA    #$00            ; clear A
   SEC                ; set carry for subtract
   SBC    LAB_5E        ; subtract exponent count adjust (convert -ve to +ve)
   TAX                ; copy exponent count to X
   LDA    #'-'            ; character "-"
LAB_DEE3
   STA    LAB_0100+1,Y    ; save to output string
   LDA    #'E'            ; character "E"
   STA    LAB_0100,Y        ; save exponent sign to output string
   TXA                ; get exponent count back
   LDX    #$2F            ; one less than "0" character
   SEC                ; set carry for subtract
LAB_DEEF
   INX                ; increment 10's character
   SBC    #$0A            ; subtract 10 from exponent count
   BCS    LAB_DEEF        ; loop while still >= 0

   ADC    #':'            ; add character ":" ($30+$0A, result is 10 less that value)
   STA    LAB_0100+3,Y    ; save to output string
   TXA                ; copy 10's character
   STA    LAB_0100+2,Y    ; save to output string
   LDA    #$00            ; set null terminator
   STA    LAB_0100+4,Y    ; save to output string
   BEQ    LAB_DF0C        ; go set string pointer (AY) and exit, branch always

                   ; save last character, [EOT] and exit
LAB_DF04
   STA    LAB_0100-1,Y    ; save last character to output string

                   ; set null terminator and exit
LAB_DF07
   LDA    #$00            ; set null terminator
   STA    LAB_0100,Y        ; save after last character

                   ; set string pointer (AY) and exit
LAB_DF0C
   LDA    #    LDY    #>LAB_0100        ; set result string pointer high byte
   RTS


;***********************************************************************************;
;

LAB_DF11
   .byte    $80,$00        ; 0.5, first two bytes
LAB_DF13
   .byte    $00,$00,$00        ; null return for undefined variables

; decimal conversion tabls

LAB_DF16
   .byte    $FA,$0A,$1F,$00    ; -100000000
   .byte    $00,$98,$96,$80    ; +10000000
   .byte    $FF,$F0,$BD,$C0    ; -1000000
   .byte    $00,$01,$86,$A0    ; +100000
   .byte    $FF,$FF,$D8,$F0    ; -10000
   .byte    $00,$00,$03,$E8    ; +1000
   .byte    $FF,$FF,$FF,$9C    ; -100
   .byte    $00,$00,$00,$0A    ; +10
   .byte    $FF,$FF,$FF,$FF    ; -1

; jiffy count conversion table

LAB_DF3A
   .byte    $FF,$DF,$0A,$80    ; -2160000    10s hours
   .byte    $00,$03,$4B,$C0    ; +216000     hours
   .byte    $FF,$FF,$73,$60    ; -36000    10s mins
   .byte    $00,$00,$0E,$10    ; +3600     mins
   .byte    $FF,$FF,$FD,$A8    ; -600    10s secs
   .byte    $00,$00,$00,$3C    ; +60     secs
LAB_DF52


;***********************************************************************************;
;
; spare bytes, not referenced

   .byte    $BF,$AA,$AA,$AA,$AA,$AA,$AA,$AA,$AA,$AA,$AA,$AA,$AA,$AA,$AA,$AA
   .byte    $AA,$AA,$AA,$AA,$AA,$AA,$AA,$AA,$AA,$AA,$AA,$AA,$AA,$AA,$AA


;***********************************************************************************;
;
; perform SQR()

LAB_DF71
   JSR    LAB_DC0C        ; round and copy FAC1 to FAC2
   LDA    #    LDY    #>LAB_DF11        ; set 0.5 pointer high address
   JSR    LAB_DBA2        ; unpack memory (AY) into FAC1


;***********************************************************************************;
;
; perform power function

LAB_DF7B
   BEQ    LAB_DFED        ; perform EXP()

   LDA    LAB_69        ; get FAC2 exponent
   BNE    LAB_DF84        ; branch if FAC2<>0

   JMP    LAB_D8F9        ; clear FAC1 exponent and sign and return

LAB_DF84
   LDX    #    LDY    #>LAB_4E        ; set destination pointer high byte
   JSR    LAB_DBD4        ; pack FAC1 into (XY)
   LDA    LAB_6E        ; get FAC2 sign (b7)
   BPL    LAB_DF9E        ; branch if FAC2>0

                   ; else FAC2 is -ve and can only be raised to an
                   ; integer power which gives an x + j0 result
   JSR    LAB_DCCC        ; perform INT()
   LDA    #    LDY    #>LAB_4E        ; set source pointer high byte
   JSR    LAB_DC5B        ; compare FAC1 with (AY)
   BNE    LAB_DF9E        ; branch if FAC1 <> (AY) to allow Function Call error
                   ; this will leave FAC1 -ve and cause a Function Call
                   ; error when LOG() is called

   TYA                ; clear sign b7
   LDY    LAB_07        ; get FAC1 mantissa 4 from INT() function as sign in
                   ; Y for possible later negation, b0 only needed
LAB_DF9E
   JSR    LAB_DBFE        ; save FAC1 sign and copy ABS(FAC2) to FAC1
   TYA                ; copy sign back ..
   PHA                ; .. and save it
   JSR    LAB_D9EA        ; perform LOG()
   LDA    #    LDY    #>LAB_4E        ; set pointer high byte
   JSR    LAB_DA28        ; do convert AY, FCA1*(AY)
   JSR    LAB_DFED        ; perform EXP()
   PLA                ; pull sign from stack
   LSR                ; b0 is to be tested
   BCC    LAB_DFBE        ; if no bit then exit

; do - FAC1

LAB_DFB4
   LDA    LAB_61        ; get FAC1 exponent
   BEQ    LAB_DFBE        ; exit if FAC1_e = $00

   LDA    LAB_66        ; get FAC1 sign (b7)
   EOR    #$FF            ; complement it
   STA    LAB_66        ; save FAC1 sign (b7)
LAB_DFBE
   RTS


;***********************************************************************************;
;
; exp(n) constant and series

LAB_DFBF
   .byte    $81,$38,$AA,$3B,$29    ; 1.443

LAB_DFC4
   .byte    $07                ; series count
   .byte    $71,$34,$58,$3E,$56    ; 2.14987637E-5
   .byte    $74,$16,$7E,$B3,$1B    ; 1.43523140E-4
   .byte    $77,$2F,$EE,$E3,$85    ; 1.34226348E-3
   .byte    $7A,$1D,$84,$1C,$2A    ; 9.61401701E-3
   .byte    $7C,$63,$59,$58,$0A    ; 5.55051269E-2
   .byte    $7E,$75,$FD,$E7,$C6    ; 2.40226385E-1
   .byte    $80,$31,$72,$18,$10    ; 6.93147186E-1
   .byte    $81,$00,$00,$00,$00    ; 1.00000000


;***********************************************************************************;
;
; perform EXP()

LAB_DFED
   LDA    #    LDY    #>LAB_DFBF        ; set 1.443 pointer high byte
   JSR    LAB_DA28        ; do convert AY, FCA1*(AY)
   LDA    LAB_70        ; get FAC1 rounding byte
   ADC    #$50            ; +$50/$100
   BCC    LAB_DFFD        ; skip rounding if no carry

   JSR    LAB_DC23        ; round FAC1 (no check)
LAB_DFFD
   STA    LAB_56        ; save FAC2 rounding byte
   JSR    LAB_DC0F        ; copy FAC1 to FAC2
   LDA    LAB_61        ; get FAC1 exponent
   CMP    #$88            ; compare with EXP limit (256d)
   BCC    LAB_E00B        ; branch if less

LAB_E008
   JSR    LAB_DAD4        ; handle overflow and underflow
LAB_E00B
   JSR    LAB_DCCC        ; perform INT()
   LDA    LAB_07        ; get mantissa 4 from INT()
   CLC                ; clear carry for add
   ADC    #$81            ; normalise +1
   BEQ    LAB_E008        ; if $00 result has overflowed so go handle it

   SEC                ; set carry for subtract
   SBC    #$01            ; exponent now correct
   PHA                ; save FAC2 exponent
                   ; swap FAC1 and FAC2
   LDX    #$05            ; 4 bytes to do
LAB_E01B
   LDA    LAB_69,X        ; get FAC2,X
   LDY    LAB_61,X        ; get FAC1,X
   STA    LAB_61,X        ; save FAC1,X
   STY    LAB_69,X        ; save FAC2,X
   DEX                ; decrement count/index
   BPL    LAB_E01B        ; loop if not all done

   LDA    LAB_56        ; get FAC2 rounding byte
   STA    LAB_70        ; save as FAC1 rounding byte
   JSR    LAB_D853        ; perform subtraction, FAC2 from FAC1
   JSR    LAB_DFB4        ; do - FAC1
   LDA    #    LDY    #>LAB_DFC4        ; set counter pointer high byte
   JSR    LAB_E056        ; go do series evaluation
   LDA    #$00            ; clear A
   STA    LAB_6F        ; clear sign compare (FAC1 EOR FAC2)
   PLA                ; pull the saved FAC2 exponent
   JSR    LAB_DAB9        ; test and adjust accumulators
   RTS


;***********************************************************************************;
;
; ^2 then series evaluation

LAB_E040
   STA    LAB_71        ; save count pointer low byte
   STY    LAB_72        ; save count pointer high byte
   JSR    LAB_DBCA        ; pack FAC1 into LAB_57
   LDA    #    JSR    LAB_DA28        ; do convert AY, FCA1*(AY)
   JSR    LAB_E05A        ; go do series evaluation
   LDA    #    LDY    #>LAB_57        ; pointer to original # high byte
   JMP    LAB_DA28        ; do convert AY, FCA1*(AY)


;***********************************************************************************;
;
; do series evaluation

LAB_E056
   STA    LAB_71        ; save count pointer low byte
   STY    LAB_72        ; save count pointer high byte

; do series evaluation

LAB_E05A
   JSR    LAB_DBC7        ; pack FAC1 into LAB_5C
   LDA    (LAB_71),Y        ; get constants count
   STA    LAB_67        ; save constants count
   LDY    LAB_71        ; get count pointer low byte
   INY                ; increment it (now constants pointer)
   TYA                ; copy it
   BNE    LAB_E069        ; skip next if no overflow

   INC    LAB_72        ; else increment high byte
LAB_E069
   STA    LAB_71        ; save low byte
   LDY    LAB_72        ; get high byte
LAB_E06D
   JSR    LAB_DA28        ; do convert AY, FCA1*(AY)
   LDA    LAB_71        ; get constants pointer low byte
   LDY    LAB_72        ; get constants pointer high byte
   CLC                ; clear carry for add
   ADC    #$05            ; +5 to low pointer (5 bytes per constant)
   BCC    LAB_E07A        ; skip next if no overflow

   INY                ; increment high byte
LAB_E07A
   STA    LAB_71        ; save pointer low byte
   STY    LAB_72        ; save pointer high byte
   JSR    LAB_D867        ; add (AY) to FAC1
   LDA    #    LDY    #>LAB_5C        ; set pointer high byte to partial
   DEC    LAB_67        ; decrement constants count
   BNE    LAB_E06D        ; loop until all done

   RTS


;***********************************************************************************;
;
; RND values

LAB_E08A
   .byte    $98,$35,$44,$7A,$00
                   ; 11879546            multiplier
LAB_E08F
   .byte    $68,$28,$B1,$46,$00
                   ; 3.927677739E-8        offset


;***********************************************************************************;
;
; perform RND()

LAB_E094
   JSR    LAB_DC2B        ; get FAC1 sign
                   ; return A = $FF -ve, A = $01 +ve
   BMI    LAB_E0D0        ; if n<0 copy byte swapped FAC1 into RND() seed

   BNE    LAB_E0BB        ; if n>0 get next number in RND() sequence

                   ; else n=0 so get the RND() number from VIA 1 timers
   JSR    LAB_FFF3        ; return base address of I/O devices
   STX    LAB_22        ; save pointer low byte
   STY    LAB_23        ; save pointer high byte
   LDY    #$04            ; set index to T1 low byte
   LDA    (LAB_22),Y        ; get T1 low byte
   STA    LAB_62        ; save FAC1 mantissa 1
   INY                ; increment index
   LDA    (LAB_22),Y        ; get T1 high byte
   STA    LAB_64        ; save FAC1 mantissa 3
   LDY    #$08            ; set index to T2 low byte
   LDA    (LAB_22),Y        ; get T2 low byte
   STA    LAB_63        ; save FAC1 mantissa 2
   INY                ; increment index
   LDA    (LAB_22),Y        ; get T2 high byte
   STA    LAB_65        ; save FAC1 mantissa 4
   JMP    LAB_E0E0        ; set exponent and exit

LAB_E0BB
   LDA    #    LDY    #>LAB_008B        ; set seed pointer high address
   JSR    LAB_DBA2        ; unpack memory (AY) into FAC1
   LDA    #    LDY    #>LAB_E08A        ; set 11879546 pointer high byte
   JSR    LAB_DA28        ; do convert AY, FCA1*(AY)
   LDA    #    LDY    #>LAB_E08F        ; set 3.927677739E-8 pointer high byte
   JSR    LAB_D867        ; add (AY) to FAC1
LAB_E0D0
   LDX    LAB_65        ; get FAC1 mantissa 4
   LDA    LAB_62        ; get FAC1 mantissa 1
   STA    LAB_65        ; save FAC1 mantissa 4
   STX    LAB_62        ; save FAC1 mantissa 1
   LDX    LAB_63        ; get FAC1 mantissa 2
   LDA    LAB_64        ; get FAC1 mantissa 3
   STA    LAB_63        ; save FAC1 mantissa 2
   STX    LAB_64        ; save FAC1 mantissa 3
LAB_E0E0
   LDA    #$00            ; clear byte
   STA    LAB_66        ; clear FAC1 sign (always +ve)
   LDA    LAB_61        ; get FAC1 exponent
   STA    LAB_70        ; save FAC1 rounding byte
   LDA    #$80            ; set exponent = $80
   STA    LAB_61        ; save FAC1 exponent
   JSR    LAB_D8D7        ; normalise FAC1
   LDX    #    LDY    #>LAB_008B        ; set seed pointer high address


;***********************************************************************************;
;
; pack FAC1 into (XY)

LAB_E0F3
   JMP    LAB_DBD4        ; pack FAC1 into (XY)


;***********************************************************************************;
;
; handle BASIC I/O error

LAB_E0F6
   CMP    #$F0            ; compare error with $F0
   BNE    LAB_E101        ; branch if not $F0

   STY    LAB_38        ; set end of memory high byte
   STX    LAB_37        ; set end of memory low byte
   JMP    LAB_C663        ; clear from start to end and return

                   ; error was not $F0
LAB_E101
   TAX                ; copy error #
   BNE    LAB_E106        ; branch if not $00

   LDX    #$1E            ; else error $1E, break error
LAB_E106
   JMP    LAB_C437        ; do error #X then warm start


;***********************************************************************************;
;
; output character to channel with error check

LAB_E109
   JSR    LAB_FFD2        ; output character to channel
   BCS    LAB_E0F6        ; if error go handle BASIC I/O error

   RTS


;***********************************************************************************;
;
; input character from channel with error check

LAB_E10F
   JSR    LAB_FFCF        ; input character from channel
   BCS    LAB_E0F6        ; if error go handle BASIC I/O error

   RTS


;***********************************************************************************;
;
; open channel for output with error check

LAB_E115
   JSR    LAB_FFC9        ; open channel for output
   BCS    LAB_E0F6        ; if error go handle BASIC I/O error

   RTS


;***********************************************************************************;
;
; open channel for input with error check

LAB_E11B
   JSR    LAB_FFC6        ; open channel for input
   BCS    LAB_E0F6        ; if error go handle BASIC I/O error

   RTS


;***********************************************************************************;
;
; get character from input device with error check

LAB_E121
   JSR    LAB_FFE4        ; get character from input device
   BCS    LAB_E0F6        ; if error go handle BASIC I/O error

   RTS


;***********************************************************************************;
;
; perform SYS

LAB_E127
   JSR    LAB_CD8A        ; evaluate expression and check is numeric, else do
                   ; type mismatch
   JSR    LAB_D7F7        ; convert FAC_1 to integer in temporary integer
   LDA    #>LAB_E143        ; get return address high byte
   PHA                ; push as return address
   LDA    #    PHA                ; push as return address
   LDA    LAB_030F        ; get saved status register
   PHA                ; put on stack
   LDA    LAB_030C        ; get saved A
   LDX    LAB_030D        ; get saved X
   LDY    LAB_030E        ; get saved Y
   PLP                ; pull processor status
   JMP    (LAB_14)        ; call SYS address

; tail end of the SYS code
;
; the LAB_E143 is needed because the following code is to be executed once the user code
; returns. this is done by pushing the target return address - 1 onto the stack

LAB_E143    = *-1
;LAB_E144
   PHP                ; save status
   STA    LAB_030C        ; save returned A
   STX    LAB_030D        ; save returned X
   STY    LAB_030E        ; save returned Y
   PLA                ; restore saved status
   STA    LAB_030F        ; save status
   RTS


;***********************************************************************************;
;
; perform SAVE

LAB_E153
   JSR    LAB_E1D1        ; get parameters for LOAD/SAVE
   LDX    LAB_2D        ; get start of variables low byte
   LDY    LAB_2E        ; get start of variables high byte
   LDA    #LAB_2B        ; index to start of program memory
   JSR    LAB_FFD8        ; save RAM to device, A = index to start address, XY = end
                   ; address low/high
   BCS    LAB_E0F6        ; if error go handle BASIC I/O error

   RTS


;***********************************************************************************;
;
; perform VERIFY

LAB_E162
   LDA    #$01            ; flag verify
   .byte    $2C            ; makes next line BIT LAB_00A9


;***********************************************************************************;
;
; perform LOAD

LAB_E165
   LDA    #$00            ; flag load
   STA    LAB_0A        ; set load/verify flag
   JSR    LAB_E1D1        ; get parameters for LOAD/SAVE
   LDA    LAB_0A        ; get load/verify flag
   LDX    LAB_2B        ; get start of memory low byte
   LDY    LAB_2C        ; get start of memory high byte
   JSR    LAB_FFD5        ; load RAM from a device
   BCS    LAB_E1CE        ; if error go handle BASIC I/O error

   LDA    LAB_0A        ; get load/verify flag
   BEQ    LAB_E195        ; branch if load

   LDX    #$1C            ; error $1C, verify error
   JSR    LAB_FFB7        ; read I/O status word
   AND    #$10            ; mask for tape read error
   BEQ    LAB_E187        ; branch if no read error

   JMP    LAB_C437        ; do error #X then warm start

LAB_E187
   LDA    LAB_7A        ; get BASIC execute pointer low byte
                   ; is this correct ?? won't this mean the "OK" prompt
                   ; when doing a load from within a program ?
   CMP    #$02            ;.
   BEQ    LAB_E194        ; if ?? skip "OK" prompt

   LDA    #    LDY    #>LAB_C364        ; set "OK" pointer high byte
   JMP    LAB_CB1E        ; print null terminated string

LAB_E194
   RTS


;***********************************************************************************;
;
; do READY return to BASIC ??

LAB_E195
   JSR    LAB_FFB7        ; read I/O status word
   AND    #$BF            ; mask x0xx xxxx, clear read error
   BEQ    LAB_E1A1        ; branch if no errors

   LDX    #$1D            ; error $1D, load error
   JMP    LAB_C437        ; do error #X then warm start

LAB_E1A1
   LDA    LAB_7B        ; get BASIC execute pointer high byte
   CMP    #$02            ; compare with $02xx
   BNE    LAB_E1B5        ; branch if not immediate mode

   STX    LAB_2D        ; set start of variables low byte
   STY    LAB_2E        ; set start of variables high byte
   LDA    #    LDY    #>LAB_C376        ; set "READY." pointer high byte
   JSR    LAB_CB1E        ; print null terminated string
   JMP    LAB_C52A        ; reset execution, clear variables, flush stack,
                   ; rebuild BASIC chain and do warm start

LAB_E1B5
   JSR    LAB_C68E        ; set BASIC execute pointer to start of memory - 1
   JMP    LAB_E476        ; rebuild BASIC line chaining, do RESTORE and return


;***********************************************************************************;
;
; perform OPEN

LAB_E1BB
   JSR    LAB_E216        ; get parameters for OPEN/CLOSE
   JSR    LAB_FFC0        ; open a logical file
   BCS    LAB_E1CE        ; branch if error

   RTS


;***********************************************************************************;
;
; perform CLOSE

LAB_E1C4
   JSR    LAB_E216        ; get parameters for OPEN/CLOSE
   LDA    LAB_49        ; get logical file number
   JSR    LAB_FFC3        ; close a specified logical file
   BCC    LAB_E194        ; exit if no error

LAB_E1CE
   JMP    LAB_E0F6        ; go handle BASIC I/O error


;***********************************************************************************;
;
; get parameters for LOAD/SAVE

LAB_E1D1
   LDA    #$00            ; clear file name length
   JSR    LAB_FFBD        ; clear filename
   LDX    #$01            ; set default device number, cassette
   LDY    #$00            ; set default command
   JSR    LAB_FFBA        ; set logical, first and second addresses
   JSR    LAB_E203        ; exit function if [EOT] or ":"
   JSR    LAB_E254        ; set filename
   JSR    LAB_E203        ; exit function if [EOT] or ":"
   JSR    LAB_E1FD        ; scan and get byte, else do syntax error then warm start
   LDY    #$00            ; clear command
   STX    LAB_49        ; save device number
   JSR    LAB_FFBA        ; set logical, first and second addresses
   JSR    LAB_E203        ; exit function if [EOT] or ":"
   JSR    LAB_E1FD        ; scan and get byte, else do syntax error then warm start
   TXA                ; copy command to A
   TAY                ; copy command to Y
   LDX    LAB_49        ; get device number back
   JMP    LAB_FFBA        ; set logical, first and second addresses and return


;***********************************************************************************;
;
; scan and get byte, else do syntax error then warm start

LAB_E1FD
   JSR    LAB_E20B        ; scan for ",byte", else do syntax error then warm start
   JMP    LAB_D79E        ; get byte parameter and return


;***********************************************************************************;
;
; exit function if [EOT] or ":"

LAB_E203
   JSR    LAB_0079        ; scan memory
   BNE    LAB_E20A        ; branch if not [EOL] or ":"

   PLA                ; dump return address low byte
   PLA                ; dump return address high byte
LAB_E20A
   RTS


;***********************************************************************************;
;
; scan for ",valid byte", else do syntax error then warm start

LAB_E20B
   JSR    LAB_CEFD        ; scan for ",", else do syntax error then warm start

; scan for valid byte, not [EOL] or ":", else do syntax error then warm start

LAB_E20E
   JSR    LAB_0079        ; scan memory
   BNE    LAB_E20A        ; exit if following byte

   JMP    LAB_CF08        ; else do syntax error then warm start


;***********************************************************************************;
;
; get parameters for OPEN/CLOSE

LAB_E216
   LDA    #$00            ; clear file name length
   JSR    LAB_FFBD        ; clear filename
   JSR    LAB_E20E        ; scan for valid byte, else do syntax error then warm start
   JSR    LAB_D79E        ; get byte parameter, logical file number
   STX    LAB_49        ; save logical file number
   TXA                ; copy logical file number to A
   LDX    #$01            ; set default device number, cassette
   LDY    #$00            ; set default command
   JSR    LAB_FFBA        ; set logical, first and second addresses
   JSR    LAB_E203        ; exit function if [EOT] or ":"
   JSR    LAB_E1FD        ; scan and get byte, else do syntax error then warm start
   STX    LAB_4A        ; save device number
   LDY    #$00            ; clear command
   LDA    LAB_49        ; get logical file number
   CPX    #$03            ; compare device number with screen
   BCC    LAB_E23C        ; branch if less than screen

   DEY                ; else decrement command
LAB_E23C
   JSR    LAB_FFBA        ; set logical, first and second addresses
   JSR    LAB_E203        ; exit function if [EOT] or ":"
   JSR    LAB_E1FD        ; scan and get byte, else do syntax error then warm start
   TXA                ; copy command to A
   TAY                ; copy command to Y
   LDX    LAB_4A        ; get device number
   LDA    LAB_49        ; get logical file number
   JSR    LAB_FFBA        ; set logical, first and second addresses
   JSR    LAB_E203        ; exit function if [EOT] or ":"
   JSR    LAB_E20B        ; scan for ",byte", else do syntax error then warm start


;***********************************************************************************;
;
; set filename

LAB_E254
   JSR    LAB_CD9E        ; evaluate expression
   JSR    LAB_D6A3        ; evaluate string
   LDX    LAB_22        ; get string pointer low byte
   LDY    LAB_23        ; get string pointer high byte
   JMP    LAB_FFBD        ; set filename and return


;***********************************************************************************;
;
; perform COS()

LAB_E261
   LDA    #    LDY    #>LAB_E2DD        ; set pi/2 pointer high byte
   JSR    LAB_D867        ; add (AY) to FAC1


;***********************************************************************************;
;
; perform SIN()

LAB_E268
   JSR    LAB_DC0C        ; round and copy FAC1 to FAC2
   LDA    #    LDY    #>LAB_E2E2        ; set 2*pi pointer high byte
   LDX    LAB_6E        ; get FAC2 sign (b7)
   JSR    LAB_DB07        ; divide by (AY) (X=sign)
   JSR    LAB_DC0C        ; round and copy FAC1 to FAC2
   JSR    LAB_DCCC        ; perform INT()
   LDA    #$00            ; clear byte
   STA    LAB_6F        ; clear sign compare (FAC1 EOR FAC2)
   JSR    LAB_D853        ; perform subtraction, FAC2 from FAC1
   LDA    #    LDY    #>LAB_E2E7        ; set 0.25 pointer high byte
   JSR    LAB_D850        ; perform subtraction, FAC1 from (AY)
   LDA    LAB_66        ; get FAC1 sign (b7)
   PHA                ; save FAC1 sign
   BPL    LAB_E29A        ; branch if +ve

                   ; FAC1 sign was -ve
   JSR    LAB_D849        ; add 0.5 to FAC1 (round FAC1)
   LDA    LAB_66        ; get FAC1 sign (b7)
   BMI    LAB_E29D        ; branch if -ve

   LDA    LAB_12        ; get the comparison evaluation flag
   EOR    #$FF            ; toggle flag
   STA    LAB_12        ; save the comparison evaluation flag
LAB_E29A
   JSR    LAB_DFB4        ; do - FAC1
LAB_E29D
   LDA    #    LDY    #>LAB_E2E7        ; set 0.25 pointer high byte
   JSR    LAB_D867        ; add (AY) to FAC1
   PLA                ; restore FAC1 sign
   BPL    LAB_E2AA        ; branch if was +ve

                   ; else correct FAC1
   JSR    LAB_DFB4        ; do - FAC1
LAB_E2AA
   LDA    #    LDY    #>LAB_E2EC        ; set pointer high byte to counter
   JMP    LAB_E040        ; ^2 then series evaluation and return


;***********************************************************************************;
;
; perform TAN()

LAB_E2B1
   JSR    LAB_DBCA        ; pack FAC1 into LAB_57
   LDA    #$00            ; clear A
   STA    LAB_12        ; clear the comparison evaluation flag
   JSR    LAB_E268        ; perform SIN()
   LDX    #    LDY    #>LAB_4E        ; set sin(n) pointer high byte
   JSR    LAB_E0F3        ; pack FAC1 into (XY)
   LDA    #    LDY    #>LAB_57        ; set n pointer high byte
   JSR    LAB_DBA2        ; unpack memory (AY) into FAC1
   LDA    #$00            ; clear byte
   STA    LAB_66        ; clear FAC1 sign (b7)
   LDA    LAB_12        ; get the comparison evaluation flag
   JSR    LAB_E2D9        ; save flag and go do series evaluation
   LDA    #    LDY    #>LAB_4E        ; set sin(n) pointer high byte
   JMP    LAB_DB0F        ; convert AY and do (AY)/FAC1


;***********************************************************************************;
;
; save comparison flag and do series evaluation

LAB_E2D9
   PHA                ; save comparison flag
   JMP    LAB_E29A        ; add 0.25, ^2 then series evaluation


;***********************************************************************************;
;
; constants and series for SIN/COS(n)

LAB_E2DD
   .byte    $81,$49,$0F,$DA,$A2    ; 1.570796371, pi/2, as floating number
LAB_E2E2
   .byte    $83,$49,$0F,$DA,$A2    ; 6.28319, 2*pi, as floating number
LAB_E2E7
   .byte    $7F,$00,$00,$00,$00    ; 0.25

LAB_E2EC
   .byte    $05                ; series counter
   .byte    $84,$E6,$1A,$2D,$1B    ; -14.3813907
   .byte    $86,$28,$07,$FB,$F8    ; 42.0077971
   .byte    $87,$99,$68,$89,$01    ; -76.7041703
   .byte    $87,$23,$35,$DF,$E1    ; 81.6052237
   .byte    $86,$A5,$5D,$E7,$28    ; -41.3417021
   .byte    $83,$49,$0F,$DA,$A2    ; 6.28318531


;***********************************************************************************;
;
; perform ATN()

LAB_E30B
   LDA    LAB_66        ; get FAC1 sign (b7)
   PHA                ; save sign
   BPL    LAB_E313        ; branch if +ve

   JSR    LAB_DFB4        ; else do - FAC1
LAB_E313
   LDA    LAB_61        ; get FAC1 exponent
   PHA                ; push exponent
   CMP    #$81            ; compare with 1
   BCC    LAB_E321        ; branch if FAC1 < 1

   LDA    #    LDY    #>LAB_D9BC        ; pointer to 1 high byte
   JSR    LAB_DB0F        ; convert AY and do (AY)/FAC1
LAB_E321
   LDA    #    LDY    #>LAB_E33B        ; pointer to series high byte
   JSR    LAB_E040        ; ^2 then series evaluation
   PLA                ; restore old FAC1 exponent
   CMP    #$81            ; compare with 1
   BCC    LAB_E334        ; branch if FAC1 < 1

   LDA    #    LDY    #>LAB_E2DD        ; pointer to (pi/2) low byte
   JSR    LAB_D850        ; perform subtraction, FAC1 from (AY)
LAB_E334
   PLA                ; restore FAC1 sign
   BPL    LAB_E33A        ; exit if was +ve

   JMP    LAB_DFB4        ; else do - FAC1 and return

LAB_E33A
   RTS


;***********************************************************************************;
;
; series for ATN(n)

LAB_E33B
   .byte    $0B                ; series counter
   .byte    $76,$B3,$83,$BD,$D3    ;-6.84793912e-04
   .byte    $79,$1E,$F4,$A6,$F5    ; 4.85094216e-03
   .byte    $7B,$83,$FC,$B0,$10    ;-0.0161117015
   .byte    $7C,$0C,$1F,$67,$CA    ; 0.034209638
   .byte    $7C,$DE,$53,$CB,$C1    ;-0.054279133
   .byte    $7D,$14,$64,$70,$4C    ; 0.0724571965
   .byte    $7D,$B7,$EA,$51,$7A    ;-0.0898019185
   .byte    $7D,$63,$30,$88,$7E    ; 0.110932413
   .byte    $7E,$92,$44,$99,$3A    ;-0.142839808
   .byte    $7E,$4C,$CC,$91,$C7    ; 0.19999912
   .byte    $7F,$AA,$AA,$AA,$13    ;-0.333333316
   .byte    $81,$00,$00,$00,$00    ; 1.000000000


;***********************************************************************************;
;
; BASIC cold start entry point

LAB_E378
   JSR    LAB_E45B        ; initialise BASIC vector table
   JSR    LAB_E3A4        ; initialise BASIC RAM locations
   JSR    LAB_E404        ; print start up message and initialise memory pointers
   LDX    #$FB            ; value for start stack
   TXS                ; set stack pointer
   JMP    LAB_C474        ; do "READY." warm start


;***********************************************************************************;
;
; character get subroutine for zero page

; the target address for the LDA LAB_EA60 becomes the BASIC execute pointer once the
; block is copied to it's destination, any non zero page address will do at assembly
; time, to assemble a three byte instruction.

; page 0 initialisation table from LAB_0073
; increment and scan memory

LAB_E387
   INC    LAB_7A        ; increment BASIC execute pointer low byte
   BNE    LAB_E38D        ; branch if no carry
                   ; else
   INC    LAB_7B        ; increment BASIC execute pointer high byte

; page 0 initialisation table from LAB_0079
; scan memory

LAB_E38D
   LDA    LAB_EA60        ; get byte to scan, address set by call routine
   CMP    #':'            ; compare with ":"
   BCS    LAB_E39E        ; exit if>=

; page 0 initialisation table from LAB_0080
; clear Cb if numeric

   CMP    #' '            ; compare with " "
   BEQ    LAB_E387        ; if " " go do next

   SEC                ; set carry for SBC
   SBC    #'0'            ; subtract "0"
   SEC                ; set carry for SBC
   SBC    #$D0            ; subtract -"0"
                   ; clear carry if byte = "0"-"9"
LAB_E39E
   RTS


;***********************************************************************************;
;
; spare bytes, not referenced

;LAB_E39F
   .byte    $80,$4F,$C7,$52,$58
                   ; 0.811635157


;***********************************************************************************;
;
; initialise BASIC RAM locations

LAB_E3A4
   LDA    #$4C            ; opcode for JMP
   STA    LAB_54        ; save for functions vector jump
   STA    LAB_00        ; save for USR() vector jump
                   ; set USR() vector to illegal quantity error
   LDA    #    LDY    #>LAB_D248        ; set USR() vector high byte
   STA    LAB_01        ; save USR() vector low byte
   STY    LAB_02        ; save USR() vector high byte
   LDA    #    LDY    #>LAB_D391        ; set fixed to float vector high byte
   STA    LAB_05        ; save fixed to float vector low byte
   STY    LAB_06        ; save fixed to float vector high byte
   LDA    #    LDY    #>LAB_D1AA        ; set float to fixed vector high byte
   STA    LAB_03        ; save float to fixed vector low byte
   STY    LAB_04        ; save float to fixed vector high byte

; copy block from LAB_E387 to LAB_0074

   LDX    #$1C            ; set byte count
LAB_E3C4
   LDA    LAB_E387,X        ; get byte from table
   STA    LAB_0073,X        ; save byte in page zero
   DEX                ; decrement count
   BPL    LAB_E3C4        ; loop if not all done

   LDA    #$03            ; set step size, collecting descriptors
   STA    LAB_53        ; save garbage collection step size
   LDA    #$00            ; clear A
   STA    LAB_68        ; clear FAC1 overflow byte
   STA    LAB_13        ; clear current I/O channel, flag default
   STA    LAB_18        ; clear current descriptor stack item pointer high byte
   LDX    #$01            ; set X
   STX    LAB_01FD        ; set chain link pointer low byte
   STX    LAB_01FC        ; set chain link pointer high byte
   LDX    #LAB_19        ; initial value for descriptor stack
   STX    LAB_16        ; set descriptor stack pointer
   SEC                ; set Cb = 1 to read the bottom of memory
   JSR    LAB_FF9C        ; read/set the bottom of memory
   STX    LAB_2B        ; save start of memory low byte
   STY    LAB_2C        ; save start of memory high byte
   SEC                ; set Cb = 1 to read the top of memory
   JSR    LAB_FF99        ; read/set the top of memory
   STX    LAB_37        ; save end of memory low byte
   STY    LAB_38        ; save end of memory high byte
   STX    LAB_33        ; set bottom of string space low byte
   STY    LAB_34        ; set bottom of string space high byte
   LDY    #$00            ; clear index
   TYA                ; clear A
   STA    (LAB_2B),Y        ; clear first byte of memory
   INC    LAB_2B        ; increment start of memory low byte
   BNE    LAB_E403        ; branch if no rollover

   INC    LAB_2C        ; increment start of memory high byte
LAB_E403
   RTS


;***********************************************************************************;
;
; print start up message and initialise memory pointers

LAB_E404
   LDA    LAB_2B        ; get start of memory low byte
   LDY    LAB_2C        ; get start of memory high byte
   JSR    LAB_C408        ; check available memory, do out of memory error if no room
   LDA    #    LDY    #>LAB_E436        ; set "**** CBM BASIC V2 ****" pointer high byte
   JSR    LAB_CB1E        ; print null terminated string
   LDA    LAB_37        ; get end of memory low byte
   SEC                ; set carry for subtract
   SBC    LAB_2B        ; subtract start of memory low byte
   TAX                ; copy result to X
   LDA    LAB_38        ; get end of memory high byte
   SBC    LAB_2C        ; subtract start of memory high byte
   JSR    LAB_DDCD        ; print XA as unsigned integer
   LDA    #    LDY    #>LAB_E429        ; set " BYTES FREE" pointer high byte
   JSR    LAB_CB1E        ; print null terminated string
   JMP    LAB_C644        ; do NEW, CLEAR, RESTORE and return


;***********************************************************************************;
;
LAB_E429
   .byte    " BYTES FREE",$0D,$00
LAB_E436
   .byte    $93,"**** CBM BASIC V2 ****",$0D,$00


;***********************************************************************************;
;
; BASIC vectors, these are copied to RAM from LAB_0300 onwards

LAB_E44F
   .word    LAB_C43A        ; error message                LAB_0300
   .word    LAB_C483        ; BASIC warm start            LAB_0302
   .word    LAB_C57C        ; crunch BASIC tokens            LAB_0304
   .word    LAB_C71A        ; uncrunch BASIC tokens            LAB_0306
   .word    LAB_C7E4        ; start new BASIC code            LAB_0308
   .word    LAB_CE86        ; get arithmetic element        LAB_030A


;***********************************************************************************;
;
; initialise BASIC vectors

LAB_E45B
   LDX    #$0B            ; set byte count
LAB_E45D
   LDA    LAB_E44F,X        ; get byte from table
   STA    LAB_0300,X        ; save byte to RAM
   DEX                ; decrement index
   BPL    LAB_E45D        ; loop if more to do

   RTS


;***********************************************************************************;
;
; BASIC warm start entry point

LAB_E467
   JSR    LAB_FFCC        ; close input and output channels
   LDA    #$00            ; clear A
   STA    LAB_13        ; set current I/O channel, flag default
   JSR    LAB_C67A        ; flush BASIC stack and clear continue pointer
   CLI                ; enable interrupts
   JMP    LAB_C474        ; do warm start


;***********************************************************************************;
;
; checksum byte, not referenced

;LAB_E475
   .byte    $E8            ; [PAL]
;    .byte    $41            ; [NTSC]


;***********************************************************************************;
;
; rebuild BASIC line chaining and do RESTORE

LAB_E476
   JSR    LAB_C533        ; rebuild BASIC line chaining
   JMP    LAB_C677        ; do RESTORE, clear stack and return


;***********************************************************************************;
;
; spare bytes, not referenced

;LAB_E47C
   .byte    $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
   .byte    $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
   .byte    $FF,$FF,$FF,$FF


;***********************************************************************************;
;
; set serial data out high

LAB_E4A0
   LDA    LAB_912C        ; get VIA 2 PCR
   AND    #$DF            ; set CB2 low, serial data out high
   STA    LAB_912C        ; set VIA 2 PCR
   RTS


;***********************************************************************************;
;
; set serial data out low

LAB_E4A9
   LDA    LAB_912C        ; get VIA 2 PCR
   ORA    #$20            ; set CB2 high, serial data out low
   STA    LAB_912C        ; set VIA 2 PCR
   RTS


;***********************************************************************************;
;
; get serial clock status

LAB_E4B2
   LDA    LAB_911F        ; get VIA 1 DRA, no handshake
   CMP    LAB_911F        ; compare with self
   BNE    LAB_E4B2        ; loop if changing

   LSR                ; shift serial clock to Cb
   RTS


;***********************************************************************************;
;
; get seconday address and print "Searching..."

LAB_E4BC
   LDX    LAB_B9        ; get secondary address
   JMP    LAB_F647        ; print "Searching..." and return


;***********************************************************************************;
;
; set LOAD address if secondary address = 0

LAB_E4C1
   TXA                ; copy secondary address
   BNE    LAB_E4CC        ; load location not set in LOAD call, so
                   ; continue with load
   LDA    LAB_C3        ; get load address low byte
   STA    LAB_AE        ; save program start address low byte
   LDA    LAB_C4        ; get load address high byte
   STA    LAB_AF        ; save program start address high byte
LAB_E4CC
   JMP    LAB_F66A        ; display "LOADING" or "VERIFYING" and return


;***********************************************************************************;
;
; patch for CLOSE

LAB_E4CF
   JSR    LAB_F8E3        ; initiate tape write
   BCC    LAB_E4D7        ; branch if no error

   PLA                ; else dump stacked exit code
   LDA    #$00            ; clear exit code
LAB_E4D7
   JMP    LAB_F39E        ; go do I/O close


;***********************************************************************************;
;
; spare bytes, not referenced

;LAB_E4DA
   .byte    $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
   .byte    $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
   .byte    $FF,$FF,$FF,$FF,$FF,$FF


;***********************************************************************************;
;
; return base address of I/O devices

; this routine will set XY to the address of the memory section where the memory
; mapped I/O devices are located. This address can then be used with an offset to
; access the memory mapped I/O devices in the computer.

LAB_E500
   LDX    #    LDY    #>LAB_9110        ; get I/O base address high byte
   RTS


;***********************************************************************************;
;
; return X,Y organization of screen

; this routine returns the x,y organisation of the screen in X,Y

LAB_E505
   LDX    #$16            ; get screen X, 22 columns
   LDY    #$17            ; get screen Y, 23 rows
   RTS


;***********************************************************************************;
;
; read/set X,Y cursor position, Cb = 1 to read, Cb = 0 to set

; this routine, when called with the carry flag set, loads the current position of
; the cursor on the screen into the X and Y registers. X is the column number of
; the cursor location and Y is the row number of the cursor. A call with the carry
; bit clear moves the cursor to the position determined by the X and Y registers.

LAB_E50A
   BCS    LAB_E513        ; if read cursor skip the set cursor

   STX    LAB_D6        ; save cursor row
   STY    LAB_D3        ; save cursor column
   JSR    LAB_E587        ; set screen pointers for cursor row, column
LAB_E513
   LDX    LAB_D6        ; get cursor row
   LDY    LAB_D3        ; get cursor column
   RTS


;***********************************************************************************;
;
; initialise hardware

LAB_E518
   JSR    LAB_E5BB        ; set default devices and initialise Vic chip
   LDA    LAB_0288        ; get screen memory page
   AND    #$FD            ; mask xxxx xx0x, all but va9
   ASL                ; << 1 xxxx x0x0
   ASL                ; << 2 xxxx 0x00
   ORA    #$80            ; set 1xxx 0x00
   STA    LAB_9005        ; set screen and character memory location
   LDA    LAB_0288        ; get screen memory page
   AND    #$02            ; mask bit 9
   BEQ    LAB_E536        ; if zero just go normalise screen

                   ; else set va9 in vic chip
   LDA    #$80            ; set b7
   ORA    LAB_9002        ; OR in as video address 9
   STA    LAB_9002        ; save new va9

                   ; now normalise screen
LAB_E536
   LDA    #$00            ; clear A
   STA    LAB_0291        ; clear shift mode switch
   STA    LAB_CF        ; clear cursor blink phase
   LDA    #    STA    LAB_028F        ; set keyboard decode logic pointer low byte
   LDA    #>LAB_EBDC        ; get keyboard decode logic pointer high byte
   STA    LAB_0290        ; set keyboard decode logic pointer high byte
   LDA    #$0A            ; 10d
   STA    LAB_0289        ; set maximum size of keyboard buffer
   STA    LAB_028C        ; set repeat delay counter
   LDA    #$06            ; colour blue
   STA    LAB_0286        ; set current colour code
   LDA    #$04            ; speed 4
   STA    LAB_028B        ; set repeat speed counter
   LDA    #$0C            ; cursor flash timing
   STA    LAB_CD        ; set cursor timing countdown
   STA    LAB_CC        ; set cursor enable, $00 = flash cursor

; clear screen

LAB_E55F
   LDA    LAB_0288        ; get screen memory page
   ORA    #$80            ; set high bit, flag every line is logical line start
   TAY                ; copy to Y
   LDA    #$00            ; clear line start low byte
   TAX                ; clear index
LAB_E568
   STY    LAB_D9,X        ; save start of line X pointer high byte
   CLC                ; clear carry for add
   ADC    #$16            ; add line length to low byte
   BCC    LAB_E570        ; if no rollover skip the high byte increment

   INY                ; else increment high byte
LAB_E570
   INX                ; increment line index
   CPX    #$18            ; compare with number of lines + 1
   BNE    LAB_E568        ; loop if not all done

   LDA    #$FF            ; end of table marker ??
   STA    LAB_D9,X        ; mark end of table
   LDX    #$16            ; set line count, 23 lines to do, 0 to 22
LAB_E57B
   JSR    LAB_EA8D        ; clear screen line X
   DEX                ; decrement count
   BPL    LAB_E57B        ; loop if more to do

; home cursor

LAB_E581
   LDY    #$00            ; clear Y
   STY    LAB_D3        ; clear cursor column
   STY    LAB_D6        ; clear cursor row

; set screen pointers for cursor row, column

LAB_E587
   LDX    LAB_D6        ; get cursor row
   LDA    LAB_D3        ; get cursor column
LAB_E58B
   LDY    LAB_D9,X        ; get start of line X pointer high byte
   BMI    LAB_E597        ; continue if logical line start

   CLC                ; else clear carry for add
   ADC    #$16            ; add one line length
   STA    LAB_D3        ; save cursor column
   DEX                ; decrement cursor row
   BPL    LAB_E58B        ; loop, branch always

LAB_E597
   LDA    LAB_D9,X        ; get start of line X pointer high byte
   AND    #$03            ; mask 0000 00xx, line memory page
   ORA    LAB_0288        ; OR with screen memory page
   STA    LAB_D2        ; set current screen line pointer high byte
   LDA    LAB_EDFD,X        ; get start of line low byte from ROM table
   STA    LAB_D1        ; set current screen line pointer low byte
   LDA    #$15            ; set line length
   INX                ; increment cursor row
LAB_E5A8
   LDY    LAB_D9,X        ; get start of line X pointer high byte
   BMI    LAB_E5B2        ; exit if logical line start

   CLC                ; else clear carry for add
   ADC    #$16            ; add one line length to current line length
   INX                ; increment cursor row
   BPL    LAB_E5A8        ; loop, branch always

LAB_E5B2
   STA    LAB_D5        ; save current screen line length
   RTS


;***********************************************************************************;
;
; set default devices, initialise Vic chip and home cursor
;
; unreferenced code

;LAB_E5B5
   JSR    LAB_E5BB        ; set default devices and initialise Vic chip
   JMP    LAB_E581        ; home cursor and return


;***********************************************************************************;
;
; set default devices and initialise Vic chip

LAB_E5BB
   LDA    #$03            ; set screen
   STA    LAB_9A        ; set output device number
   LDA    #$00            ; set keyboard
   STA    LAB_99        ; set input device number

; initialise Vic chip

LAB_E5C3
   LDX    #$10            ; set byte count
LAB_E5C5
   LDA    LAB_EDE4-1,X    ; get byte from setup table
   STA    LAB_9000-1,X    ; save byte to Vic chip
   DEX                ; decrement count/index
   BNE    LAB_E5C5        ; loop if more to do

   RTS


;***********************************************************************************;
;
; input from keyboard buffer

LAB_E5CF
   LDY    LAB_0277        ; get current character from buffer
   LDX    #$00            ; clear index
LAB_E5D4
   LDA    LAB_0277+1,X    ; get next character,X from buffer
   STA    LAB_0277,X        ; save as current character,X in buffer
   INX                ; increment index
   CPX    LAB_C6        ; compare with keyboard buffer index
   BNE    LAB_E5D4        ; loop if more to do

   DEC    LAB_C6        ; decrement keyboard buffer index
   TYA                ; copy key to A
   CLI                ; enable interrupts
   CLC                ; flag got byte
   RTS


;***********************************************************************************;
;
; write character and wait for key

LAB_E5E5
   JSR    LAB_E742        ; output character

; wait for key from keyboard

LAB_E5E8
   LDA    LAB_C6        ; get keyboard buffer index
   STA    LAB_CC        ; cursor enable, $00 = flash cursor, $xx = no flash
   STA    LAB_0292        ; screen scrolling flag, $00 = scroll, $xx = no scroll
                   ; this disables both the cursor flash and the screen scroll
                   ; while there are characters in the keyboard buffer
   BEQ    LAB_E5E8        ; loop if buffer empty

   SEI                ; disable interrupts
   LDA    LAB_CF        ; get cursor blink phase
   BEQ    LAB_E602        ; branch if cursor phase

                   ; else character phase
   LDA    LAB_CE        ; get character under cursor
   LDX    LAB_0287        ; get colour under cursor
   LDY    #$00            ; clear Y
   STY    LAB_CF        ; clear cursor blink phase
   JSR    LAB_EAA1        ; print character A and colour X
LAB_E602
   JSR    LAB_E5CF        ; input from keyboard buffer
   CMP    #$83            ; compare with [SHIFT][RUN]
   BNE    LAB_E619        ; branch if not [SHIFT][RUN]

                   ; keys are [SHIFT][RUN] so put "LOAD",$0D,"RUN",$0D into
                   ; the buffer
   LDX    #$09            ; set byte count
   SEI                ; disable interrupts
   STX    LAB_C6        ; set keyboard buffer index
LAB_E60E
   LDA    LAB_EDF4-1,X    ; get byte from auto load/run table
   STA    LAB_0277-1,X    ; save to keyboard buffer
   DEX                ; decrement count/index
   BNE    LAB_E60E        ; loop while more to do

   BEQ    LAB_E5E8        ; loop for next key, branch always

                   ; was not [SHIFT][RUN]
LAB_E619
   CMP    #$0D            ; compare with [CR]
   BNE    LAB_E5E5        ; if not [CR] print character and get next key

                   ; was [CR]
   LDY    LAB_D5        ; get current screen line length
   STY    LAB_D0        ; input from keyboard or screen, $xx = screen,
                   ; $00 = keyboard
LAB_E621
   LDA    (LAB_D1),Y        ; get character from current screen line
   CMP    #' '            ; compare with [SPACE]
   BNE    LAB_E62A        ; branch if not [SPACE]

   DEY                ; else eliminate the space, decrement end of input line
   BNE    LAB_E621        ; loop, branch always

LAB_E62A
   INY                ; increment past last non space character on line
   STY    LAB_C8        ; save input [EOL] pointer
   LDY    #$00            ; clear A
   STY    LAB_0292        ; clear screen scrolling flag, $00 = scroll, $xx = no scroll
   STY    LAB_D3        ; clear cursor column
   STY    LAB_D4        ; clear cursor quote flag, $xx = quote, $00 = no quote
   LDA    LAB_C9        ; get input cursor row
   BMI    LAB_E657        ;.

   LDX    LAB_D6        ; get cursor row
   JSR    LAB_E719        ; find and set pointers for start of logical line
   CPX    LAB_C9        ; compare with input cursor row
   BNE    LAB_E657        ;.

   BNE    LAB_E657        ;.?? what's this? just to make sure or something

   LDA    LAB_CA        ; get input cursor column
   STA    LAB_D3        ; save cursor column
   CMP    LAB_C8        ; compare with input [EOL] pointer
   BCC    LAB_E657        ; branch if less, cursor is in line

   BCS    LAB_E691        ; else cursor is beyond the line end, branch always


;***********************************************************************************;
;
; input from screen or keyboard

LAB_E64F
   TYA                ; copy Y
   PHA                ; save Y
   TXA                ; copy X
   PHA                ; save X
   LDA    LAB_D0        ; input from keyboard or screen, $xx = screen,
                   ; $00 = keyboard
   BEQ    LAB_E5E8        ; if keyboard go wait for key

LAB_E657
   LDY    LAB_D3        ; get cursor column
   LDA    (LAB_D1),Y        ; get character from the current screen line
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ; just a few wasted cycles.
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   STA    LAB_D7        ; save temporary last character
   AND    #$3F            ; mask key bits
   ASL    LAB_D7        ; << temporary last character
   BIT    LAB_D7        ; test it
   BPL    LAB_E67E        ; branch if not [NO KEY]

   ORA    #$80            ;.
LAB_E67E
   BCC    LAB_E684        ;.

   LDX    LAB_D4        ; get cursor quote flag, $xx = quote, $00 = no quote
   BNE    LAB_E688        ; branch if in quote mode

LAB_E684
   BVS    LAB_E688        ;.

   ORA    #$40            ;.
LAB_E688
   INC    LAB_D3        ; increment cursor column
   JSR    LAB_E6B8        ; if open quote toggle cursor quote flag
   CPY    LAB_C8        ; compare with input [EOL] pointer
   BNE    LAB_E6A8        ; branch if not at line end

LAB_E691
   LDA    #$00            ;.
   STA    LAB_D0        ; clear input from keyboard or screen, $xx = screen,
                   ; $00 = keyboard
   LDA    #$0D            ; set character [CR]
   LDX    LAB_99        ; get input device number
   CPX    #$03            ; compare with screen
   BEQ    LAB_E6A3        ; branch if screen

   LDX    LAB_9A        ; get output device number
   CPX    #$03            ; compare with screen
   BEQ    LAB_E6A6        ; branch if screen

LAB_E6A3
   JSR    LAB_E742        ; output character
LAB_E6A6
   LDA    #$0D            ; set character [CR]
LAB_E6A8
   STA    LAB_D7        ; save character
   PLA                ; pull X
   TAX                ; restore X
   PLA                ; pull Y
   TAY                ; restore Y
   LDA    LAB_D7        ; restore character
   CMP    #$DE            ;.
   BNE    LAB_E6B6        ;.

   LDA    #$FF            ;.
LAB_E6B6
   CLC                ; flag ok
   RTS


;***********************************************************************************;
;
; if open quote toggle cursor quote flag

LAB_E6B8
   CMP    #$22            ; comapre byte with "
   BNE    LAB_E6C4        ; exit if not "

   LDA    LAB_D4        ; get cursor quote flag, $xx = quote, $00 = no quote
   EOR    #$01            ; toggle it
   STA    LAB_D4        ; save cursor quote flag
   LDA    #$22            ; restore the "
LAB_E6C4
   RTS


;***********************************************************************************;
;
; insert uppercase/graphic character

LAB_E6C5
   ORA    #$40            ; change to uppercase/graphic
LAB_E6C7
   LDX    LAB_C7        ; get reverse flag
   BEQ    LAB_E6CD        ; branch if not reverse

                   ; else ..
; insert reversed character

LAB_E6CB
   ORA    #$80            ; reverse character
LAB_E6CD
   LDX    LAB_D8        ; get insert count
   BEQ    LAB_E6D3        ; branch if none

   DEC    LAB_D8        ; else decrement insert count
LAB_E6D3
   LDX    LAB_0286        ; get current colour code
   JSR    LAB_EAA1        ; print character A and colour X
   JSR    LAB_E6EA        ; advance cursor

; restore registers, set quote flag and exit

LAB_E6DC
   PLA                ; pull Y
   TAY                ; restore Y
   LDA    LAB_D8        ; get insert count
   BEQ    LAB_E6E4        ; skip quote flag clear if inserts to do

   LSR    LAB_D4        ; clear cursor quote flag, $xx = quote, $00 = no quote
LAB_E6E4
   PLA                ; pull X
   TAX                ; restore X
   PLA                ; restore A
   CLC                ;.
   CLI                ; enable interrupts
   RTS


;***********************************************************************************;
;
; advance cursor

LAB_E6EA
   JSR    LAB_E8FA        ; test for line increment
   INC    LAB_D3        ; increment cursor column
   LDA    LAB_D5        ; get current screen line length
   CMP    LAB_D3        ; compare with cursor column
   BCS    LAB_E72C        ; exit if line length >= cursor column

   CMP    #$57            ; compare with max length
   BEQ    LAB_E723        ; if at max clear column, back cursor up and do newline

   LDA    LAB_0292        ; get autoscroll flag
   BEQ    LAB_E701        ; branch if autoscroll on

   JMP    LAB_E9F0        ;.else open space on screen

LAB_E701
   LDX    LAB_D6        ; get cursor row
   CPX    #$17            ; compare with max + 1
   BCC    LAB_E70E        ; if less than max + 1 go add this row to the current
                   ; logical line

   JSR    LAB_E975        ; else scroll screen
   DEC    LAB_D6        ; decrement cursor row
   LDX    LAB_D6        ; get cursor row

; add this row to the current logical line

LAB_E70E
   ASL    LAB_D9,X        ; shift start of line X pointer high byte
   LSR    LAB_D9,X        ; shift start of line X pointer high byte back,
                   ; clear b7, start of logical line
   JMP    LAB_ED5B        ; make next screen line start of logical line, increment
                   ; line length and set pointers

; add one line length and set pointers for start of line

LAB_E715
   ADC    #$16            ; add one line length
   STA    LAB_D5        ; save current screen line length

; find and set pointers for start of logical line

LAB_E719
   LDA    LAB_D9,X        ; get start of line X pointer high byte
   BMI    LAB_E720        ; exit loop if start of logical line

   DEX                ; else back up one line
   BNE    LAB_E719        ; loop if not on first line

LAB_E720
   JMP    LAB_EA7E        ; set start of line X and return

; clear cursor column, back cursor up one line and do newline

LAB_E723
   DEC    LAB_D6        ; decrement cursor row. if the cursor was incremented past
                   ; the last line then this decrement and the scroll will
                   ; leave the cursor one line above the botom of the screen
   JSR    LAB_E8C3        ; do newline
   LDA    #$00            ; clear A
   STA    LAB_D3        ; clear cursor column
LAB_E72C
   RTS

; back onto previous line if possible

LAB_E72D
   LDX    LAB_D6        ; get cursor row
   BNE    LAB_E737        ; branch if not top row

   STX    LAB_D3        ; clear cursor column
   PLA                ; dump return address low byte
   PLA                ; dump return address high byte
   BNE    LAB_E6DC        ; restore registers, set quote flag and exit, branch always

LAB_E737
   DEX                ; decrement cursor row
   STX    LAB_D6        ; save cursor row
   JSR    LAB_E587        ; set screen pointers for cursor row, column
   LDY    LAB_D5        ; get current screen line length
   STY    LAB_D3        ; save as cursor column
   RTS


;***********************************************************************************;
;
;## output character to screen

LAB_E742
   PHA                ; save character
   STA    LAB_D7        ; save temporary last character
   TXA                ; copy X
   PHA                ; save X
   TYA                ; copy Y
   PHA                ; save Y
   LDA    #$00            ; clear A
   STA    LAB_D0        ; clear input from keyboard or screen, $xx = screen,
                   ; $00 = keyboard
   LDY    LAB_D3        ; get cursor column
   LDA    LAB_D7        ; restore last character
   BPL    LAB_E756        ; branch if unshifted

   JMP    LAB_E800        ; do shifted characters and return

LAB_E756
   CMP    #$0D            ; compare with [CR]
   BNE    LAB_E75D        ; branch if not [CR]

   JMP    LAB_E8D8        ; else output [CR] and return

LAB_E75D
   CMP    #' '            ; compare with [SPACE]
   BCC    LAB_E771        ; branch if < [SPACE]

   CMP    #$60            ;.
   BCC    LAB_E769        ; branch if $20 to $5F

                   ; character is $60 or greater
   AND    #$DF            ;.
   BNE    LAB_E76B        ;.

LAB_E769
   AND    #$3F            ;.
LAB_E76B
   JSR    LAB_E6B8        ; if open quote toggle cursor direct/programmed flag
   JMP    LAB_E6C7        ;.

                   ; character was < [SPACE] so is a control character
                   ; of some sort
LAB_E771
   LDX    LAB_D8        ; get insert count
   BEQ    LAB_E778        ; branch if no characters to insert

   JMP    LAB_E6CB        ; insert reversed character

LAB_E778
   CMP    #$14            ; compare with [INSERT]/[DELETE]
   BNE    LAB_E7AA        ; branch if not [INSERT]/[DELETE]

   TYA                ;.
   BNE    LAB_E785        ;.

   JSR    LAB_E72D        ; back onto previous line if possible
   JMP    LAB_E79F        ;.

LAB_E785
   JSR    LAB_E8E8        ; test for line decrement

                   ; now close up the line
   DEY                ; decrement index to previous character
   STY    LAB_D3        ; save cursor column
   JSR    LAB_EAB2        ; calculate pointer to colour RAM
LAB_E78E
   INY                ; increment index to next character
   LDA    (LAB_D1),Y        ; get character from current screen line
   DEY                ; decrement index to previous character
   STA    (LAB_D1),Y        ; save character to current screen line
   INY                ; increment index to next character
   LDA    (LAB_F3),Y        ; get colour RAM byte
   DEY                ; decrement index to previous character
   STA    (LAB_F3),Y        ; save colour RAM byte
   INY                ; increment index to next character
   CPY    LAB_D5        ; compare with current screen line length
   BNE    LAB_E78E        ; loop if not there yet

LAB_E79F
   LDA    #' '            ; set [SPACE]
   STA    (LAB_D1),Y        ; clear last character on current screen line
   LDA    LAB_0286        ; get current colour code
   STA    (LAB_F3),Y        ; save to colour RAM
   BPL    LAB_E7F7        ; branch always

LAB_E7AA
   LDX    LAB_D4        ; get cursor quote flag, $xx = quote, $00 = no quote
   BEQ    LAB_E7B1        ; branch if not quote mode

   JMP    LAB_E6CB        ; insert reversed character

LAB_E7B1
   CMP    #$12            ; compare with [RVS ON]
   BNE    LAB_E7B7        ; branch if not [RVS ON]

   STA    LAB_C7        ; set reverse flag
LAB_E7B7
   CMP    #$13            ; compare with [CLR HOME]
   BNE    LAB_E7BE        ; branch if not [CLR HOME]

   JSR    LAB_E581        ; home cursor
LAB_E7BE
   CMP    #$1D            ; compare with [CURSOR RIGHT]
   BNE    LAB_E7D9        ; branch if not [CURSOR RIGHT]

   INY                ; increment cursor column
   JSR    LAB_E8FA        ; test for line increment
   STY    LAB_D3        ; save cursor column
   DEY                ; decrement cursor column
   CPY    LAB_D5        ; compare cursor column with current screen line length
   BCC    LAB_E7D6        ; exit if less

                   ; else the cursor column is >= the current screen line
                   ; length so back onto the current line and do a newline
   DEC    LAB_D6        ; decrement cursor row
   JSR    LAB_E8C3        ; do newline
   LDY    #$00            ; clear cursor column
LAB_E7D4
   STY    LAB_D3        ; save cursor column
LAB_E7D6
   JMP    LAB_E6DC        ; restore registers, set quote flag and exit

LAB_E7D9
   CMP    #$11            ; compare with [CURSOR DOWN]
   BNE    LAB_E7FA        ; branch if not [CURSOR DOWN]

   CLC                ; clear carry for add
   TYA                ; copy cursor column
   ADC    #$16            ; add one line
   TAY                ; copy back to A
   INC    LAB_D6        ; increment cursor row
   CMP    LAB_D5        ; compare cursor column with current screen line length
   BCC    LAB_E7D4        ; save cursor column and exit if less

   BEQ    LAB_E7D4        ; save cursor column and exit if equal

                   ; else the cursor has moved beyond the end of this line
                   ; so back it up until it's on the start of the logical line
   DEC    LAB_D6        ; decrement cursor row
LAB_E7EC
   SBC    #$16            ; subtract one line
   BCC    LAB_E7F4        ; exit loop if on previous line

   STA    LAB_D3        ; else save cursor column
   BNE    LAB_E7EC        ; loop if not at start of line

LAB_E7F4
   JSR    LAB_E8C3        ; do newline
LAB_E7F7
   JMP    LAB_E6DC        ; restore registers, set quote flag and exit

LAB_E7FA
   JSR    LAB_E912        ; set the colour from the character in A
   JMP    LAB_ED21        ;.

LAB_E800
   NOP                ; just a few wasted cycles
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   AND    #$7F            ; mask 0xxx xxxx, clear b7
   CMP    #$7F            ; was it $FF before the mask
   BNE    LAB_E81D        ; branch if not

   LDA    #$5E            ; else make it $5E
LAB_E81D
   NOP                ; just a few wasted cycles
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   CMP    #' '            ; compare with [SPACE]
   BCC    LAB_E82A        ; branch if < [SPACE]

   JMP    LAB_E6C5        ; insert uppercase/graphic character and return

                   ; character was $80 to $9F and is now $00 to $1F
LAB_E82A
   CMP    #$0D            ; compare with [CR]
   BNE    LAB_E831        ; branch if not [CR]

   JMP    LAB_E8D8        ; else output [CR] and return

                   ; was not [CR]
LAB_E831
   LDX    LAB_D4        ; get cursor quote flag, $xx = quote, $00 = no quote
   BNE    LAB_E874        ; branch if quote mode

   CMP    #$14            ; compare with [INSERT DELETE]
   BNE    LAB_E870        ; branch if not [INSERT DELETE]

   LDY    LAB_D5        ; get current screen line length
   LDA    (LAB_D1),Y        ; get character from current screen line
   CMP    #' '            ; compare with [SPACE]
   BNE    LAB_E845        ; branch if not [SPACE]

   CPY    LAB_D3        ; compare current column with cursor column
   BNE    LAB_E84C        ; if not cursor column go open up space on line

LAB_E845
   CPY    #$57            ; compare current column with max line length
   BEQ    LAB_E86D        ; exit if at line end

   JSR    LAB_E9EE        ; else open space on screen
                   ; now open up space on the line to insert a character
LAB_E84C
   LDY    LAB_D5        ; get current screen line length
   JSR    LAB_EAB2        ; calculate pointer to colour RAM
LAB_E851
   DEY                ; decrement index to previous character
   LDA    (LAB_D1),Y        ; get character from current screen line
   INY                ; increment index to next character
   STA    (LAB_D1),Y        ; save character to current screen line
   DEY                ; decrement index to previous character
   LDA    (LAB_F3),Y        ; get current screen line colour RAM byte
   INY                ; increment index to next character
   STA    (LAB_F3),Y        ; save current screen line colour RAM byte
   DEY                ; decrement index to previous character
   CPY    LAB_D3        ; compare with cursor column
   BNE    LAB_E851        ; loop if not there yet

   LDA    #' '            ; set [SPACE]
   STA    (LAB_D1),Y        ; clear character at cursor position on current screen line
   LDA    LAB_0286        ; get current colour code
   STA    (LAB_F3),Y        ; save to cursor position on current screen line colour RAM
   INC    LAB_D8        ; increment insert count
LAB_E86D
   JMP    LAB_E6DC        ; restore registers, set quote flag and exit

LAB_E870
   LDX    LAB_D8        ; get insert count
   BEQ    LAB_E879        ; branch if no insert space

LAB_E874
   ORA    #$40            ; change to uppercase/graphic
   JMP    LAB_E6CB        ; insert reversed character

LAB_E879
   CMP    #$11            ; compare with [CURSOR UP]
   BNE    LAB_E893        ; branch if not [CURSOR UP]

   LDX    LAB_D6        ; get cursor row
   BEQ    LAB_E8B8        ; branch if on top line

   DEC    LAB_D6        ; decrement cursor row
   LDA    LAB_D3        ; get cursor column
   SEC                ; set carry for subtract
   SBC    #$16            ; subtract one line length
   BCC    LAB_E88E        ; branch if stepped back to previous line

   STA    LAB_D3        ; else save cursor column ..
   BPL    LAB_E8B8        ; .. and exit, branch always

LAB_E88E
   JSR    LAB_E587        ; set screen pointers for cursor row, column ..
   BNE    LAB_E8B8        ; .. and exit, branch always

LAB_E893
   CMP    #$12            ; compare with [RVS OFF]
   BNE    LAB_E89B        ; branch if not [RVS OFF]

   LDA    #$00            ; clear A
   STA    LAB_C7        ; clear reverse flag
LAB_E89B
   CMP    #$1D            ; compare with [CURSOR LEFT]
   BNE    LAB_E8B1        ; branch if not [CURSOR LEFT]

   TYA                ; copy cursor column
   BEQ    LAB_E8AB        ; branch if at start of line

   JSR    LAB_E8E8        ; test for line decrement
   DEY                ; decrement cursor column
   STY    LAB_D3        ; save cursor column
   JMP    LAB_E6DC        ; restore registers, set quote flag and exit

LAB_E8AB
   JSR    LAB_E72D        ; back onto previous line if possible
   JMP    LAB_E6DC        ; restore registers, set quote flag and exit

LAB_E8B1
   CMP    #$13            ; compare with [CLR]
   BNE    LAB_E8BB        ; branch if not [CLR]

   JSR    LAB_E55F        ; clear screen
LAB_E8B8
   JMP    LAB_E6DC        ; restore registers, set quote flag and exit

LAB_E8BB
   ORA    #$80            ; restore b7, colour can only be black, cyan, magenta
                   ; or yellow
   JSR    LAB_E912        ; set the colour from the character in A
   JMP    LAB_ED30        ;.


;***********************************************************************************;
;
; do newline

LAB_E8C3
   LSR    LAB_C9        ; shift >> input cursor row
   LDX    LAB_D6        ; get cursor row
LAB_E8C7
   INX                ; increment row
   CPX    #$17            ; compare with last row + 1
   BNE    LAB_E8CF        ; branch if not last row + 1

   JSR    LAB_E975        ; else scroll screen
LAB_E8CF
   LDA    LAB_D9,X        ; get start of line X pointer high byte
   BPL    LAB_E8C7        ; loop if not start of logical line

   STX    LAB_D6        ; else save cursor row
   JMP    LAB_E587        ; set screen pointers for cursor row, column and return


;***********************************************************************************;
;
; output [CR]

LAB_E8D8
   LDX    #$00            ; clear X
   STX    LAB_D8        ; clear insert count
   STX    LAB_C7        ; clear reverse flag
   STX    LAB_D4        ; clear cursor quote flag, $xx = quote, $00 = no quote
   STX    LAB_D3        ; clear cursor column
   JSR    LAB_E8C3        ; do newline
   JMP    LAB_E6DC        ; restore registers, set quote flag and exit


;***********************************************************************************;
;
; test for line decrement

LAB_E8E8
   LDX    #$04            ; set count
   LDA    #$00            ; set column
LAB_E8EC
   CMP    LAB_D3        ; compare with cursor column
   BEQ    LAB_E8F7        ; branch if at start of line

   CLC                ; else clear carry for add
   ADC    #$16            ; increment to next line
   DEX                ; decrement loop count
   BNE    LAB_E8EC        ; loop if more to test

   RTS

LAB_E8F7
   DEC    LAB_D6        ; else decrement cursor row
   RTS


;***********************************************************************************;
;
; test for line increment. if at end of line, but not at end of last line, increment the
; cursor row

LAB_E8FA
   LDX    #$04            ; set count
   LDA    #$15            ; set column
LAB_E8FE
   CMP    LAB_D3        ; compare with cursor column
   BEQ    LAB_E909        ; if at end of line test and possibly increment cursor row

   CLC                ; else clear carry for add
   ADC    #$16            ; increment to next line
   DEX                ; decrement loop count
   BNE    LAB_E8FE        ; loop if more to test

   RTS

                   ; cursor is at end of line
LAB_E909
   LDX    LAB_D6        ; get cursor row
   CPX    #$17            ; compare with end of screen
   BEQ    LAB_E911        ; exit if end of screen

   INC    LAB_D6        ; else increment cursor row
LAB_E911
   RTS


;***********************************************************************************;
;
; set colour code. enter with the colour character in A. if A does not contain a
; colour character this routine exits without changing the colour

LAB_E912
   LDX    #LAB_E928-LAB_E921
                   ; set colour code count
LAB_E914
   CMP    LAB_E921,X        ; compare the character with the table code
   BEQ    LAB_E91D        ; if a match go save the colour and exit

   DEX                ; else decrement the index
   BPL    LAB_E914        ; loop if more to do

   RTS

LAB_E91D
   STX    LAB_0286        ; set current colour code
   RTS


;***********************************************************************************;
;
; ASCII colour code table
                   ; CHR$()    colour
LAB_E921                ; ------    ------
   .byte    $90            ; 144    black
   .byte    $05            ; 5    white
   .byte    $1C            ; 28    red
   .byte    $9F            ; 159    cyan
   .byte    $9C            ; 156    magenta
   .byte    $1E            ; 30    green
   .byte    $1F            ; 31    blue
LAB_E928
   .byte    $9E            ; 158    yellow


;***********************************************************************************;
;
; code conversion, these don't seem to be used anywhere

;LAB_E929
   .byte    $EF,$A1,$DF,$A6,$E1,$B1,$E2,$B2,$E3,$B3,$E4,$B4,$E5,$B5,$E6,$B6
   .byte    $E7,$B7,$E8,$B8,$E9,$B9,$FA,$BA,$FB,$BB,$FC,$BC,$EC,$BD,$FE,$BE
   .byte    $84,$BF,$F7,$C0,$F8,$DB,$F9,$DD,$EA,$DE,$5E,$E0,$5B,$E1,$5D,$E2
   .byte    $40,$B0,$61,$B1,$78,$DB,$79,$DD,$66,$B6,$77,$C0,$70,$F0,$71,$F1
   .byte    $72,$F2,$73,$F3,$74,$F4,$75,$F5,$76,$F6,$7D,$FD


;***********************************************************************************;
;
; scroll screen

LAB_E975
   LDA    LAB_AC        ; copy tape buffer start pointer
   PHA                ; save it
   LDA    LAB_AD        ; copy tape buffer start pointer
   PHA                ; save it
   LDA    LAB_AE        ; copy tape buffer end pointer
   PHA                ; save it
   LDA    LAB_AF        ; copy tape buffer end pointer
   PHA                ; save it
LAB_E981
   LDX    #$FF            ; set to -1 for pre increment loop
   DEC    LAB_D6        ; decrement cursor row
   DEC    LAB_C9        ; decrement input cursor row
   DEC    LAB_F2        ; decrement screen row marker
LAB_E989
   INX                ; increment line number
   JSR    LAB_EA7E        ; set start of line X
   CPX    #$16            ; compare with last line
   BCS    LAB_E99D        ; branch if >= $16

   LDA    LAB_EDFD+1,X    ; get start of next line pointer low byte
   STA    LAB_AC        ; save next line pointer low byte
   LDA    LAB_D9+1,X        ; get start of next line pointer high byte
   JSR    LAB_EA56        ; shift screen line up
   BMI    LAB_E989        ; loop, branch always

LAB_E99D
   JSR    LAB_EA8D        ; clear screen line X

                   ; now shift up the start of logical line bits
   LDX    #$00            ; clear index
LAB_E9A2
   LDA    LAB_D9,X        ; get start of line X pointer high byte
   AND    #$7F            ; clear line X start of logical line bit
   LDY    LAB_D9+1,X        ; get start of next line pointer high byte
   BPL    LAB_E9AC        ; branch if next line not start of line

   ORA    #$80            ; set line X start of logical line bit
LAB_E9AC
   STA    LAB_D9,X        ; set start of line X pointer high byte
   INX                ; increment line number
   CPX    #$16            ; compare with last line
   BNE    LAB_E9A2        ; loop if not last line

   LDA    LAB_D9+$16        ; get start of last line pointer high byte
   ORA    #$80            ; mark as start of logical line
   STA    LAB_D9+$16        ; set start of last line pointer high byte
   LDA    LAB_D9        ; get start of first line pointer high byte
   BPL    LAB_E981        ; if not start of logical line loop back and
                   ; scroll the screen up another line

   INC    LAB_D6        ; increment cursor row
   INC    LAB_F2        ; increment screen row marker
   LDA    #$FB            ; set keyboard column c2
   STA    LAB_9120        ; set VIA 2 DRB, keyboard column
   LDA    LAB_9121        ; get VIA 2 DRA, keyboard row
   CMP    #$FE            ; compare with row r0 active, [CTL]
   PHP                ; save status
   LDA    #$F7            ; set keyboard column c3
   STA    LAB_9120        ; set VIA 2 DRB, keyboard column
   PLP                ; restore status
   BNE    LAB_E9DF        ; skip delay if ??

                   ; first time round the inner loop X will be $16
   LDY    #$00            ; clear delay outer loop count, do this 256 times
LAB_E9D6
   NOP                ; waste cycles
   DEX                ; decrement inner loop count
   BNE    LAB_E9D6        ; loop if not all done

   DEY                ; decrement outer loop count
   BNE    LAB_E9D6        ; loop if not all done

   STY    LAB_C6        ; clear keyboard buffer index
LAB_E9DF
   LDX    LAB_D6        ; get cursor row
   PLA                ; pull tape buffer end pointer
   STA    LAB_AF        ; restore it
   PLA                ; pull tape buffer end pointer
   STA    LAB_AE        ; restore it
   PLA                ; pull tape buffer pointer
   STA    LAB_AD        ; restore it
   PLA                ; pull tape buffer pointer
   STA    LAB_AC        ; restore it
   RTS


;***********************************************************************************;
;
; open space on screen

LAB_E9EE
   LDX    LAB_D6        ; get cursor row
LAB_E9F0
   INX                ; increment row
   LDA    LAB_D9,X        ; get start of line X pointer high byte
   BPL    LAB_E9F0        ; branch if not start of logical line

   STX    LAB_F2        ; set screen row marker
   CPX    #$16            ; compare with last line
   BEQ    LAB_EA08        ; branch if = last line

   BCC    LAB_EA08        ; branch if < last line

                   ; else was > last line
   JSR    LAB_E975        ; else scroll screen
   LDX    LAB_F2        ; get screen row marker
   DEX                ; decrement screen row marker
   DEC    LAB_D6        ; decrement cursor row
   JMP    LAB_E70E        ; add this row to the current logical line and return

LAB_EA08
   LDA    LAB_AC        ; copy tape buffer pointer
   PHA                ; save it
   LDA    LAB_AD        ; copy tape buffer pointer
   PHA                ; save it
   LDA    LAB_AE        ; copy tape buffer end pointer
   PHA                ; save it
   LDA    LAB_AF        ; copy tape buffer end pointer
   PHA                ; save it
   LDX    #$17            ; set to end line + 1 for predecrement loop
LAB_EA16
   DEX                ; decrement line number
   JSR    LAB_EA7E        ; set start of line X
   CPX    LAB_F2        ; compare with screen row marker
   BCC    LAB_EA2C        ; branch if < screen row marker

   BEQ    LAB_EA2C        ; branch if = screen row marker

   LDA    LAB_EDFD-1,X    ; else get start of previous line low byte from ROM table
   STA    LAB_AC        ; save previous line pointer low byte
   LDA    LAB_D9-1,X        ; get start of previous line pointer high byte
   JSR    LAB_EA56        ; shift screen line down
   BMI    LAB_EA16        ; loop, branch always

LAB_EA2C
   JSR    LAB_EA8D        ; clear screen line X
   LDX    #$15            ;.
LAB_EA31
   CPX    LAB_F2        ;.compare with screen row marker
   BCC    LAB_EA44        ;.

   LDA    LAB_D9+1,X        ;.
   AND    #$7F            ;.
   LDY    LAB_D9,X        ; get start of line X pointer high byte
   BPL    LAB_EA3F        ;.

   ORA    #$80            ;.
LAB_EA3F
   STA    LAB_D9+1,X        ;.
   DEX                ;.
   BNE    LAB_EA31        ;.

LAB_EA44
   LDX    LAB_F2        ;.get screen row marker
   JSR    LAB_E70E        ; add this row to the current logical line
   PLA                ; pull tape buffer end pointer
   STA    LAB_AF        ; restore it
   PLA                ; pull tape buffer end pointer
   STA    LAB_AE        ; restore it
   PLA                ; pull tape buffer pointer
   STA    LAB_AD        ; restore it
   PLA                ; pull tape buffer pointer
   STA    LAB_AC        ; restore it
   RTS


;***********************************************************************************;
;
; shift screen line up/down

LAB_EA56
   AND    #$03            ; mask 0000 00xx, line memory page
   ORA    LAB_0288        ; OR with screen memory page
   STA    LAB_AD        ; save next/previous line pointer high byte
   JSR    LAB_EA6E        ; calculate pointers to screen lines colour RAM
LAB_EA60
   LDY    #$15            ; set column count
LAB_EA62
   LDA    (LAB_AC),Y        ; get character from next/previous screen line
   STA    (LAB_D1),Y        ; save character to current screen line
   LDA    (LAB_AE),Y        ; get colour from next/previous screen line colour RAM
   STA    (LAB_F3),Y        ; save colour to current screen line colour RAM
   DEY                ; decrement column index/count
   BPL    LAB_EA62        ; loop if more to do

   RTS


;***********************************************************************************;
;
; calculate pointers to screen lines colour RAM

LAB_EA6E
   JSR    LAB_EAB2        ; calculate pointer to current screen line colour RAM
   LDA    LAB_AC        ; get next screen line pointer low byte
   STA    LAB_AE        ; save next screen line colour RAM pointer low byte
   LDA    LAB_AD        ; get next screen line pointer high byte
   AND    #$03            ; mask 0000 00xx, line memory page
   ORA    #$94            ; set 1001 01xx, colour memory page
   STA    LAB_AF        ; save next screen line colour RAM pointer high byte
   RTS


;***********************************************************************************;
;
; set start of line X

LAB_EA7E
   LDA    LAB_EDFD,X        ; get start of line low byte from ROM table
   STA    LAB_D1        ; set current screen line pointer low byte
   LDA    LAB_D9,X        ; get start of line high byte from RAM table
   AND    #$03            ; mask 0000 00xx, line memory page
   ORA    LAB_0288        ; OR with screen memory page
   STA    LAB_D2        ; set current screen line pointer high byte
   RTS


;***********************************************************************************;
;
; clear screen line X

LAB_EA8D
   LDY    #$15            ; set number of columns to clear
   JSR    LAB_EA7E        ; set start of line X
   JSR    LAB_EAB2        ; calculate pointer to colour RAM
LAB_EA95
   LDA    #' '            ; set [SPACE]
   STA    (LAB_D1),Y        ; clear character in current screen line
   LDA    #$01            ; set colour, blue on white
   STA    (LAB_F3),Y        ; set colour RAM in current screen line
   DEY                ; decrement index
   BPL    LAB_EA95        ; loop if more to do

   RTS


;***********************************************************************************;
;
; print character A and colour X to screen

LAB_EAA1
   TAY                ; copy character
   LDA    #$02            ; set count to $02, usually $14 ??
   STA    LAB_CD        ; set cursor countdown
   JSR    LAB_EAB2        ; calculate pointer to colour RAM
   TYA                ; get character back

; save character and colour to screen @ cursor

LAB_EAAA
   LDY    LAB_D3        ; get cursor column
   STA    (LAB_D1),Y        ; save character from current screen line
   TXA                ; copy colour to A
   STA    (LAB_F3),Y        ; save to colour RAM
   RTS


;***********************************************************************************;
;
; calculate pointer to colour RAM

LAB_EAB2
   LDA    LAB_D1        ; get current screen line pointer low byte
   STA    LAB_F3        ; save pointer to colour RAM low byte
   LDA    LAB_D2        ; get current screen line pointer high byte
   AND    #$03            ; mask 0000 00xx, line memory page
   ORA    #$94            ; set 1001 01xx, colour memory page
   STA    LAB_F4        ; save pointer to colour RAM high byte
   RTS


;***********************************************************************************;
;
; update the clock, flash the cursor, control the cassette and scan the keyboard

; IRQ handler

LAB_EABF
   JSR    LAB_FFEA        ; increment real time clock
   LDA    LAB_CC        ; get cursor enable
   BNE    LAB_EAEF        ; branch if not flash cursor

   DEC    LAB_CD        ; else decrement cursor timing countdown
   BNE    LAB_EAEF        ; branch if not done

   LDA    #$14            ; set count
   STA    LAB_CD        ; save cursor timing countdown
   LDY    LAB_D3        ; get cursor column
   LSR    LAB_CF        ; shift b0 cursor blink phase into carry
   LDX    LAB_0287        ; get colour under cursor
   LDA    (LAB_D1),Y        ; get character from current screen line
   BCS    LAB_EAEA        ; branch if cursor phase b0 was 1

   INC    LAB_CF        ; set cursor blink phase to 1
   STA    LAB_CE        ; save character under cursor
   JSR    LAB_EAB2        ; calculate pointer to colour RAM
   LDA    (LAB_F3),Y        ; get colour RAM byte
   STA    LAB_0287        ; save colour under cursor
   LDX    LAB_0286        ; get current colour code
   LDA    LAB_CE        ; get character under cursor
LAB_EAEA
   EOR    #$80            ; toggle b7 of character under cursor
   JSR    LAB_EAAA        ; save character and colour to screen @ cursor
LAB_EAEF
   LDA    LAB_911F        ; get VIA 1 DRA, no handshake
   AND    #$40            ; mask cassette switch sense
   BEQ    LAB_EB01        ; branch if cassette sense low

                   ; cassette sense was high so turn off motor and clear
                   ; the interlock
   LDY    #$00            ; clear Y
   STY    LAB_C0        ; clear the tape motor interlock
   LDA    LAB_911C        ; get VIA 1 PCR
   ORA    #$02            ; set CA2 high, turn off motor
   BNE    LAB_EB0A        ; branch always

                   ; cassette sense was low so turn on motor, perhaps
LAB_EB01
   LDA    LAB_C0        ; get tape motor interlock
   BNE    LAB_EB12        ; if cassette interlock <> 0 don't turn on motor

   LDA    LAB_911C        ; get VIA 1 PCR
   AND    #$FD            ; set CA2 low, turn on motor
LAB_EB0A
   BIT    LAB_911E        ; test VIA 1 IER
   BVS    LAB_EB12        ; if T1 interrupt enabled don't change motor state

   STA    LAB_911C        ; set VIA 1 PCR, set CA2 high/low
LAB_EB12
   JSR    LAB_EB1E        ; scan keyboard
   BIT    LAB_9124        ; test VIA 2 T1C_l, clear the timer interrupt flag
   PLA                ; pull Y
   TAY                ; restore Y
   PLA                ; pull X
   TAX                ; restore X
   PLA                ; restore A
   RTI


;***********************************************************************************;
;
; scan keyboard performs the following ..
;
; 1)    check if key pressed, if not then exit the routine
;
; 2)    init I/O ports of VIA 2 for keyboard scan and set pointers to decode table 1.
;    clear the character counter
;
; 3)    set one line of port B low and test for a closed key on port A by shifting the
;    byte read from the port. if the carry is clear then a key is closed so save the
;    count which is incremented on each shift. check for shift/stop/cbm keys and
;    flag if closed
;
; 4)    repeat step 3 for the whole matrix
;
; 5)    evaluate the SHIFT/CTRL/C= keys, this may change the decode table selected
;
; 6)    use the key count saved in step 3 as an index into the table selected in step 5
;
; 7)    check for key repeat operation
;
; 8)    save the decoded key to the buffer if first press or repeat

; scan keyboard

; this routine will scan the keyboard and check for pressed keys. It is the same
; routine called by the interrupt handler. If a key is down, its ASCII value is
; placed in the keyboard queue.

LAB_EB1E
   LDA    #$00            ; clear A
   STA    LAB_028D        ; clear keyboard shift/control/c= flag
   LDY    #$40            ; set no key
   STY    LAB_CB        ; save which key
   STA    LAB_9120        ; clear VIA 2 DRB, keyboard column
   LDX    LAB_9121        ; get VIA 2 DRA, keyboard row
   CPX    #$FF            ; compare with all bits set
   BEQ    LAB_EB8F        ; if no key pressed clear current key and exit (does
                   ; further BEQ to LAB_EBBA)

   LDA    #$FE            ; set column 0 low
   STA    LAB_9120        ; set VIA 2 DRB, keyboard column
   LDY    #$00            ; clear key count
   LDA    #    STA    LAB_F5        ; set keyboard pointer low byte
   LDA    #>LAB_EC5E        ; get decode table high byte
   STA    LAB_F6        ; set keyboard pointer high byte
LAB_EB40
   LDX    #$08            ; set row count
   LDA    LAB_9121        ; get VIA 2 DRA, keyboard row
   CMP    LAB_9121        ; compare with itself
   BNE    LAB_EB40        ; loop if changing

LAB_EB4A
   LSR                ; shift row to Cb
   BCS    LAB_EB63        ; if no key closed on this row go do next row

   PHA                ; save row
   LDA    (LAB_F5),Y        ; get character from decode table
   CMP    #$05            ; compare with $05, there is no $05 key but the control
                   ; keys are all less than $05
   BCS    LAB_EB60        ; if not shift/control/c=/stop go save key count

                   ; else was shift/control/c=/stop key
   CMP    #$03            ; compare with $03, stop
   BEQ    LAB_EB60        ; if stop go save key count and continue

                   ; character is $01 - shift, $02 - c= or $04 - control
   ORA    LAB_028D        ; OR keyboard shift/control/c= flag
   STA    LAB_028D        ; save keyboard shift/control/c= flag
   BPL    LAB_EB62        ; skip save key, branch always

LAB_EB60
   STY    LAB_CB        ; save key count
LAB_EB62
   PLA                ; restore row
LAB_EB63
   INY                ; increment key count
   CPY    #$41            ; compare with max+1
   BCS    LAB_EB71        ; exit loop if >= max+1

                   ; else still in matrix
   DEX                ; decrement row count
   BNE    LAB_EB4A        ; loop if more rows to do

   SEC                ; set carry for keyboard column shift
   ROL    LAB_9120        ; shift VIA 2 DRB, keyboard column
   BNE    LAB_EB40        ; loop for next column, branch always

LAB_EB71
   JMP    (LAB_028F)        ; evaluate the SHIFT/CTRL/C= keys, LAB_EBDC

; key decoding continues here after the SHIFT/CTRL/C= keys are evaluated

LAB_EB74
   LDY    LAB_CB        ; get saved key count
   LDA    (LAB_F5),Y        ; get character from decode table
   TAX                ; copy character to X
   CPY    LAB_C5        ; compare key count with last key count
   BEQ    LAB_EB84        ; if this key = current key, key held, go test repeat

   LDY    #$10            ; set repeat delay count
   STY    LAB_028C        ; save repeat delay count
   BNE    LAB_EBBA        ; go save key to buffer and exit, branch always

LAB_EB84
   AND    #$7F            ; clear b7
   BIT    LAB_028A        ; test key repeat
   BMI    LAB_EBA1        ; branch if repeat all

   BVS    LAB_EBD6        ; branch if repeat none

   CMP    #$7F            ; compare with end marker
LAB_EB8F
   BEQ    LAB_EBBA        ; if $00/end marker go save key to buffer and exit

   CMP    #$14            ; compare with [INSERT]/[DELETE]
   BEQ    LAB_EBA1        ; if [INSERT]/[DELETE] go test for repeat

   CMP    #' '            ; compare with [SPACE]
   BEQ    LAB_EBA1        ; if [SPACE] go test for repeat

   CMP    #$1D            ; compare with [CURSOR RIGHT]
   BEQ    LAB_EBA1        ; if [CURSOR RIGHT] go test for repeat

   CMP    #$11            ; compare with [CURSOR DOWN]
   BNE    LAB_EBD6        ; if not [CURSOR DOWN] just exit

                   ; was one of the cursor movement keys, insert/delete
                   ; key or the space bar so always do repeat tests
LAB_EBA1
   LDY    LAB_028C        ; get repeat delay counter
   BEQ    LAB_EBAB        ; branch if delay expired

   DEC    LAB_028C        ; else decrement repeat delay counter
   BNE    LAB_EBD6        ; branch if delay not expired

                   ; repeat delay counter has expired
LAB_EBAB
   DEC    LAB_028B        ; decrement repeat speed counter
   BNE    LAB_EBD6        ; branch if repeat speed count not expired

   LDY    #$04            ; set for 4/60ths of a second
   STY    LAB_028B        ; set repeat speed counter
   LDY    LAB_C6        ; get keyboard buffer index
   DEY                ; decrement it
   BPL    LAB_EBD6        ; if the buffer isn't empty just exit

                   ; else repeat the key immediately

; possibly save the key to the keyboard buffer. if there was no key pressed or the key
; was not found during the scan (possibly due to key bounce) then X will be $FF here

LAB_EBBA
   LDY    LAB_CB        ; get the key count
   STY    LAB_C5        ; save as the current key count
   LDY    LAB_028D        ; get keyboard shift/control/c= flag
   STY    LAB_028E        ; save as last keyboard shift pattern
   CPX    #$FF            ; compare character with table end marker or no key
   BEQ    LAB_EBD6        ; if table end marker or no key just exit

   TXA                ; copy character to A
   LDX    LAB_C6        ; get keyboard buffer index
   CPX    LAB_0289        ; compare with keyboard buffer size
   BCS    LAB_EBD6        ; if buffer full just exit

   STA    LAB_0277,X        ; save character to keyboard buffer
   INX                ; increment index
   STX    LAB_C6        ; save keyboard buffer index
LAB_EBD6
   LDA    #$F7            ; enable column 3 for stop key
   STA    LAB_9120        ; set VIA 2 DRB, keyboard column
   RTS

; evaluate SHIFT/CTRL/C= keys
;
; 0    $00    EC5E
; 1    $02    EC9F
; 2    $04    ECE0
; 3    ..    ....
; 4    $06    EDA3
; 5    $06    EDA3
; 6    $06    EDA3
; 7    $06    EDA3

LAB_EBDC
   LDA    LAB_028D        ; get keyboard shift/control/c= flag
   CMP    #$03            ; compare with [SHIFT][C=]
   BNE    LAB_EC0F        ; branch if not [SHIFT][C=]

   CMP    LAB_028E        ; compare with last
   BEQ    LAB_EBD6        ; exit if still the same

   LDA    LAB_0291        ; get shift mode switch $00 = enabled, $80 = locked
   BMI    LAB_EC43        ; if locked continue keyboard decode

   NOP                ; just a few wasted cycles
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;

                   ; toggle text mode
   LDA    LAB_9005        ; get start of character memory, ROM
   EOR    #$02            ; toggle $8000,$8800
   STA    LAB_9005        ; set start of character memory, ROM
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   JMP    LAB_EC43        ; continue keyboard decode

                   ; was not [SHIFT][C=] but could be any other combination
LAB_EC0F
   ASL                ; << 1
   CMP    #$08            ; compare with [CTRL]
   BCC    LAB_EC18        ; branch if not [CTRL] pressed

   LDA    #$06            ; else [CTRL] was pressed so make index = $06
   NOP                ;
   NOP                ;
LAB_EC18
   NOP                ; just a few wasted cycles
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   NOP                ;
   TAX                ; copy index to X
   LDA    LAB_EC46,X        ; get decode table pointer low byte
   STA    LAB_F5        ; save decode table pointer low byte
   LDA    LAB_EC46+1,X    ; get decode table pointer high byte
   STA    LAB_F6        ; save decode table pointer high byte
LAB_EC43
   JMP    LAB_EB74        ; continue keyboard decode


;***********************************************************************************;
;
; keyboard decode table pointers

LAB_EC46
   .word    LAB_EC5E        ; unshifted
   .word    LAB_EC9F        ; shifted
   .word    LAB_ECE0        ; commodore
   .word    LAB_EDA3        ; control
   .word    LAB_EC5E        ; unshifted
   .word    LAB_EC9F        ; shifted
   .word    LAB_ED69        ; shfited
   .word    LAB_EDA3        ; control
   .word    LAB_ED21        ; graphics/text control
   .word    LAB_ED69        ; shifted
   .word    LAB_ED69        ; shifted
   .word    LAB_EDA3        ; control

; keyboard decode table - unshifted

LAB_EC5E
   .byte    $31,$33,$35,$37,$39,$2B,$5C,$14
   .byte    $5F,$57,$52,$59,$49,$50,$2A,$0D
   .byte    $04,$41,$44,$47,$4A,$4C,$3B,$1D
   .byte    $03,$01,$58,$56,$4E,$2C,$2F,$11
   .byte    $20,$5A,$43,$42,$4D,$2E,$01,$85
   .byte    $02,$53,$46,$48,$4B,$3A,$3D,$86
   .byte    $51,$45,$54,$55,$4F,$40,$5E,$87
   .byte    $32,$34,$36,$38,$30,$2D,$13,$88
   .byte    $FF

; keyboard decode table - shifted

LAB_EC9F
   .byte    $21,$23,$25,$27,$29,$DB,$A9,$94
   .byte    $5F,$D7,$D2,$D9,$C9,$D0,$C0,$8D
   .byte    $04,$C1,$C4,$C7,$CA,$CC,$5D,$9D
   .byte    $83,$01,$D8,$D6,$CE,$3C,$3F,$91
   .byte    $A0,$DA,$C3,$C2,$CD,$3E,$01,$89
   .byte    $02,$D3,$C6,$C8,$CB,$5B,$3D,$8A
   .byte    $D1,$C5,$D4,$D5,$CF,$BA,$DE,$8B
   .byte    $22,$24,$26,$28,$30,$DD,$93,$8C
   .byte    $FF

; keyboard decode table - commodore

LAB_ECE0
   .byte    $21,$23,$25,$27,$29,$A6,$A8,$94
   .byte    $5F,$B3,$B2,$B7,$A2,$AF,$DF,$8D
   .byte    $04,$B0,$AC,$A5,$B5,$B6,$5D,$9D
   .byte    $83,$01,$BD,$BE,$AA,$3C,$3F,$91
   .byte    $A0,$AD,$BC,$BF,$A7,$3E,$01,$89
   .byte    $02,$AE,$BB,$B4,$A1,$5B,$3D,$8A
   .byte    $AB,$B1,$A3,$B8,$B9,$A4,$DE,$8B
   .byte    $22,$24,$26,$28,$30,$DC,$93,$8C
   .byte    $FF


;***********************************************************************************;
;
;## graphics/text control

LAB_ED21
   CMP    #$0E            ; compare with [SWITCH TO LOWER CASE]
   BNE    LAB_ED30        ; branch if not [SWITCH TO LOWER CASE]

   LDA    #$02            ; set for $8800, lower case characters
   ORA    LAB_9005        ; OR with start of character memory, ROM
   STA    LAB_9005        ; save start of character memory, ROM
   JMP    LAB_E6DC        ; restore registers, set quote flag and exit

LAB_ED30
   CMP    #$8E            ; compare with [SWITCH TO UPPER CASE]
   BNE    LAB_ED3F        ; branch if not [SWITCH TO UPPER CASE]

   LDA    #$FD            ; set for $8000, upper case characters
   AND    LAB_9005        ; AND with start of character memory, ROM
   STA    LAB_9005        ; save start of character memory, ROM

LAB_ED3C
   JMP    LAB_E6DC        ; restore registers, set quote flag and exit

LAB_ED3F
   CMP    #$08            ; compare with disable [SHIFT][C=]
   BNE    LAB_ED4D        ; branch if not disable [SHIFT][C=]

   LDA    #$80            ; set to lock shift mode switch
   ORA    LAB_0291        ; OR with shift mode switch, $00 = enabled, $80 = locked
   STA    LAB_0291        ; save shift mode switch
   BMI    LAB_ED3C        ; branch always

LAB_ED4D
   CMP    #$09            ; compare with enable [SHIFT][C=]
   BNE    LAB_ED3C        ; exit if not enable [SHIFT][C=]

   LDA    #$7F            ; set to unlock shift mode switch
   AND    LAB_0291        ; AND with shift mode switch, $00 = enabled, $80 = locked
   STA    LAB_0291        ; save shift mode switch
   BPL    LAB_ED3C        ; branch always

; make next screen line start of logical line, increment line length and set pointers

LAB_ED5B
   INX                ; increment screen row
   LDA    LAB_D9,X        ; get start of line X pointer high byte
   ORA    #$80            ; mark as start of logical line
   STA    LAB_D9,X        ; set start of line X pointer high byte
   DEX                ; restore screen row
   LDA    LAB_D5        ; get current screen line length
   CLC                ; clear carry for add
   JMP    LAB_E715        ; add one line length, set pointers for start of line and
                   ; return


;***********************************************************************************;
;
; keyboard decode table - shifted

LAB_ED69
   .byte    $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
   .byte    $FF,$04,$FF,$FF,$FF,$FF,$FF,$E2
   .byte    $9D,$83,$01,$FF,$FF,$FF,$FF,$FF
   .byte    $91,$A0,$FF,$FF,$FF,$FF,$EE,$01
   .byte    $89,$02,$FF,$FF,$FF,$FF,$E1,$FD
   .byte    $8A,$FF,$FF,$FF,$FF,$FF,$B0,$E0
   .byte    $8B,$F2,$F4,$F6,$FF,$F0,$ED,$93
   .byte    $8C,$FF

; keyboard decode table - control

LAB_EDA3
   .byte    $90,$1C,$9C,$1F,$12,$FF,$FF,$FF
   .byte    $06,$FF,$12,$FF,$FF,$FF,$FF,$FF
   .byte    $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
   .byte    $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
   .byte    $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
   .byte    $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
   .byte    $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
   .byte    $05,$9F,$1E,$9E,$92,$FF,$FF,$FF
   .byte    $FF


;***********************************************************************************;
;
; initial values for VIC registers

LAB_EDE4
   .byte    $0C            ; interlace and horizontal center [PAL]
;    .byte    $05            ; interlace and horizontal center [NTSC]
                   ; bit    function
                   ; ---    --------
                   ; 7    interlace / non interlace
                   ; 6-0    horizontal origin
   .byte    $26            ; vertical origin [PAL]
;    .byte    $19            ; vertical origin [NTSC]
   .byte    $16            ; video address and colums, $9400 for colour RAM
                   ; bit    function
                   ; ---    --------
                   ; 7    video address va9
                   ; 6-0    number of columns
   .byte    $2E            ; rows and character size
                   ; bit    function
                   ; ---    --------
                   ; 7    b9 raster line
                   ; 6-1    number of rows
                   ; 0    8x16 / 8x8 characters
   .byte    $00            ; raster line
   .byte    $C0            ; video memory addresses, RAM $1000, ROM $8000
                   ; bit    function
                   ; ---    --------
                   ; 7    must be 1
                   ; 6-4    video memory address va12-va10
                   ; 3-0    character memory start address

                   ; 0000 ROM    $8000    set 1 - we use this
                   ; 0001 "    $8400
                   ; 0010 "    $8800 set 2
                   ; 0011 "    $8C00
                   ; 1100 RAM    $1000
                   ; 1101 "    $1400
                   ; 1110 "    $1800
                   ; 1111 "    $1C00

   .byte    $00            ; light pen horizontal position
   .byte    $00            ; light pen vertical position

   .byte    $00            ; paddle X
   .byte    $00            ; paddle Y
   .byte    $00            ; oscillator 1 frequency
   .byte    $00            ; oscillator 2 frequency
   .byte    $00            ; oscillator 3 frequency
   .byte    $00            ; noise source frequency
   .byte    $00            ; aux colour and volume
                   ; bit    function
                   ; ---    --------
                   ; 7-4    auxiliary colour information
                   ; 3-0    volume
   .byte    $1B            ; screen and border colour
                   ; bit    function
                   ; ---    --------
                   ; 7-4    background colour
                   ; 3    inverted or normal mode
                   ; 2-0    border colour


;***********************************************************************************;
;
; keyboard buffer for auto load/run

LAB_EDF4
   .byte    "LOAD",$0D,"RUN",$0D


;***********************************************************************************;
;
; low byte screen line addresses

LAB_EDFD
   .byte    $00,$16,$2C,$42
   .byte    $58,$6E,$84,$9A
   .byte    $B0,$C6,$DC,$F2
   .byte    $08,$1E,$34,$4A
   .byte    $60,$76,$8C,$A2
   .byte    $B8,$CE,$E4


;***********************************************************************************;
;
; command a serial bus device to TALK

; to use this routine the accumulator must first be loaded with a device number
; between 4 and 30. When called this routine converts this device number to a talk
; address. Then this data is transmitted as a command on the Serial bus.

LAB_EE14
   ORA    #$40            ; OR with the TALK command
   .byte    $2C            ; makes next line BIT LAB_2009


;***********************************************************************************;
;
; command devices on the serial bus to LISTEN

; this routine will command a device on the serial bus to receive data. The
; accumulator must be loaded with a device number between 4 and 31 before calling
; this routine. LISTEN convert this to a listen address then transmit this data as
; a command on the serial bus. The specified device will then go into listen mode
; and be ready to accept information.

LAB_EE17
   ORA    #$20            ; OR with the LISTEN command
   JSR    LAB_F160        ; check RS232 bus idle


;***********************************************************************************;
;
; send control character

LAB_EE1C
   PHA                ; save device address
   BIT    LAB_94        ; test deferred character flag
   BPL    LAB_EE2B        ; branch if no defered character

   SEC                ; flag EOI
   ROR    LAB_A3        ; rotate into EOI flag byte
   JSR    LAB_EE49        ; Tx byte on serial bus
   LSR    LAB_94        ; clear deferred character flag
   LSR    LAB_A3        ; clear EOI flag
LAB_EE2B
   PLA                ; restore device address
   STA    LAB_95        ; save as serial defered character
   JSR    LAB_E4A0        ; set serial data out high
   CMP    #$3F            ; compare read byte with $3F
   BNE    LAB_EE38        ; branch if not $3F, this branch will always be taken as
                   ; after VIA 2's PCR is read it is ANDed with $DF, so the
                   ; result can never be $3F

   JSR    LAB_EF84        ; set serial clock high
LAB_EE38
   LDA    LAB_911F        ; get VIA 1 DRA, no handshake
   ORA    #$80            ; set serial ATN low
   STA    LAB_911F        ; set VIA 1 DRA, no handshake


;***********************************************************************************;
;
; if the code drops through to here the serial clock is low and the serial data has been
; released so the following code will have no effect apart from delaying the first byte
; by 1ms

;## set clk/data, wait and Tx byte on serial bus

LAB_EE40
   JSR    LAB_EF8D        ; set serial clock low
   JSR    LAB_E4A0        ; set serial data out high
   JSR    LAB_EF96        ; 1ms delay


;***********************************************************************************;
;
; Tx byte on serial bus

LAB_EE49
   SEI                ; disable interrupts
   JSR    LAB_E4A0        ; set serial data out high
   JSR    LAB_E4B2        ; get serial clock status
   LSR                ; shift serial data to Cb
   BCS    LAB_EEB4        ; if data high do device not present

   JSR    LAB_EF84        ; set serial clock high
   BIT    LAB_A3        ; test EOI flag
   BPL    LAB_EE66        ; branch if not EOI

; I think this is the EOI sequence so the serial clock has been released and the serial
; data is being held low by the peripherals. first up wait for the serial data to rise

LAB_EE5A
   JSR    LAB_E4B2        ; get serial clock status
   LSR                ; shift serial data to Cb
   BCC    LAB_EE5A        ; loop if data low

; now the data is high, EOI is signalled by waiting for at least 200us without pulling
; the serial clock line low again. the listener should respond by pulling the serial
; data line low

LAB_EE60
   JSR    LAB_E4B2        ; get serial clock status
   LSR                ; shift serial data to Cb
   BCS    LAB_EE60        ; loop if data high

; the serial data has gone low ending the EOI sequence, now just wait for the serial
; data line to go high again or, if this isn't an EOI sequence, just wait for the serial
; data to go high the first time

LAB_EE66
   JSR    LAB_E4B2        ; get serial clock status
   LSR                ; shift serial data to Cb
   BCC    LAB_EE66        ; loop if data low

; serial data is high now pull the clock low, preferably within 60us

   JSR    LAB_EF8D        ; set serial clock low

; now the Vic has to send the eight bits, LSB first. first it sets the serial data line
; to reflect the bit in the byte, then it sets the serial clock to high. The serial
; clock is left high for 26 cycles, 23us on a PAL Vic, before it is again pulled low
; and the serial data is allowed high again

   LDA    #$08            ; eight bits to do
   STA    LAB_A5        ; set serial bus bit count
LAB_EE73
   LDA    LAB_911F        ; get VIA 1 DRA, no handshake
   CMP    LAB_911F        ; compare with self
   BNE    LAB_EE73        ; loop if changing

   LSR                ; serial clock to carry
   LSR                ; serial data to carry
   BCC    LAB_EEB7        ; if data low do timeout on serial bus

   ROR    LAB_95        ; rotate transmit byte
   BCS    LAB_EE88        ; branch if bit = 1

   JSR    LAB_E4A9        ; else set serial data out low
   BNE    LAB_EE8B        ; branch always

LAB_EE88
   JSR    LAB_E4A0        ; set serial data out high
LAB_EE8B
   JSR    LAB_EF84        ; set serial clock high
   NOP                ; waste ..
   NOP                ; .. a ..
   NOP                ; .. cycle ..
   NOP                ; .. or two
   LDA    LAB_912C        ; get VIA 2 PCR
   AND    #$DF            ; set CB2 low, serial data out high
   ORA    #$02            ; set CA2 high, serial clock out low
   STA    LAB_912C        ; save VIA 2 PCR
   DEC    LAB_A5        ; decrement serial bus bit count
   BNE    LAB_EE73        ; loop if not all done

; now all eight bits have been sent it's up to the peripheral to signal the byte was
; received by pulling the serial data low. this should be done within one milisecond

   LDA    #$04            ; wait for up to about 1ms
   STA    LAB_9129        ; set VIA 2 T2C_h
LAB_EEA5
   LDA    LAB_912D        ; get VIA 2 IFR
   AND    #$20            ; mask T2 interrupt
   BNE    LAB_EEB7        ; if T2 interrupt do timeout on serial bus

   JSR    LAB_E4B2        ; get serial clock status
   LSR                ; shift serial data to Cb
   BCS    LAB_EEA5        ; if data high go wait some more

   CLI                ; enable interrupts
   RTS


;***********************************************************************************;
;
; device not present

LAB_EEB4
   LDA    #$80            ; error $80, device not present
   .byte    $2C            ; makes next line BIT LAB_03A9


;***********************************************************************************;
;
; timeout on serial bus

LAB_EEB7
   LDA    #$03            ; error $03, write timeout
LAB_EEB9
   JSR    LAB_FE6A        ; OR into serial status byte
   CLI                ; enable interrupts
   CLC                ; clear for branch
   BCC    LAB_EF09        ; ATN high, delay, clock high then data high, branch always


;***********************************************************************************;
;
; send secondary address after LISTEN

; this routine is used to send a secondary address to an I/O device after a call to
; the LISTEN routine is made and the device commanded to LISTEN. The routine cannot
; be used to send a secondary address after a call to the TALK routine.

; A secondary address is usually used to give set-up information to a device before
; I/O operations begin.

; When a secondary address is to be sent to a device on the serial bus the address
; must first be ORed with $60.

LAB_EEC0
   STA    LAB_95        ; save defered byte
   JSR    LAB_EE40        ; set clk/data, wait and Tx byte on serial bus

; set serial ATN high

LAB_EEC5
   LDA    LAB_911F        ; get VIA 1 DRA, no handshake
   AND    #$7F            ; set serial ATN high
   STA    LAB_911F        ; set VIA 1 DRA, no handshake
   RTS


;***********************************************************************************;
;
; send secondary address after TALK

; this routine transmits a secondary address on the serial bus for a TALK device.
; This routine must be called with a number between 4 and 31 in the accumulator.
; The routine will send this number as a secondary address command over the serial
; bus. This routine can only be called after a call to the TALK routine. It will
; not work after a LISTEN.

LAB_EECE
   STA    LAB_95        ; save the secondary address byte to transmit
   JSR    LAB_EE40        ; set clk/data, wait and Tx byte on serial bus


;***********************************************************************************;
;
; wait for bus end after send

LAB_EED3
   SEI                ; disable interrupts
   JSR    LAB_E4A9        ; set serial data out low
   JSR    LAB_EEC5        ; set serial ATN high
   JSR    LAB_EF84        ; set serial clock high
LAB_EEDD
   JSR    LAB_E4B2        ; get serial clock status
   BCS    LAB_EEDD        ; branch if clock high

   CLI                ; enable interrupts
   RTS


;***********************************************************************************;
;
; output a byte to the serial bus

; this routine is used to send information to devices on the serial bus. A call to
; this routine will put a data byte onto the serial bus using full handshaking.
; Before this routine is called the LISTEN routine, LAB_FFB1, must be used to
; command a device on the serial bus to get ready to receive data.

; the accumulator is loaded with a byte to output as data on the serial bus. A
; device must be listening or the status word will return a timeout. This routine
; always buffers one character. So when a call to the UNLISTEN routine, LAB_FFAE,
; is made to end the data transmission, the buffered character is sent with EOI
; set. Then the UNLISTEN command is sent to the device.

LAB_EEE4
   BIT    LAB_94        ; test deferred character flag
   BMI    LAB_EEED        ; branch if defered character

   SEC                ; set carry
   ROR    LAB_94        ; shift into deferred character flag
   BNE    LAB_EEF2        ; save byte and exit, branch always

LAB_EEED
   PHA                ; save byte
   JSR    LAB_EE49        ; Tx byte on serial bus
   PLA                ; restore byte
LAB_EEF2
   STA    LAB_95        ; save defered byte
   CLC                ; flag ok
   RTS


;***********************************************************************************;
;
; command the serial bus to UNTALK

; this routine will transmit an UNTALK command on the serial bus. All devices
; previously set to TALK will stop sending data when this command is received.

LAB_EEF6
   JSR    LAB_EF8D        ; set serial clock low
   LDA    LAB_911F        ; get VIA 1 DRA, no handshake
   ORA    #$80            ; set serial ATN low
   STA    LAB_911F        ; set VIA 1 DRA, no handshake

   LDA    #$5F            ; set the UNTALK command
   .byte    $2C            ; makes next line BIT LAB_3FA9


;***********************************************************************************;
;
; command the serial bus to UNLISTEN

; this routine commands all devices on the serial bus to stop receiving data from
; the computer. Calling this routine results in an UNLISTEN command being transmitted
; on the serial bus. Only devices previously commanded to listen will be affected.

; This routine is normally used after the computer is finished sending data to
; external devices. Sending the UNLISTEN will command the listening devices to get
; off the serial bus so it can be used for other purposes.

LAB_EF04
   LDA    #$3F            ; set the UNLISTEN command
   JSR    LAB_EE1C        ; send control character

; ATN high, delay, clock high then data high

LAB_EF09
   JSR    LAB_EEC5        ; set serial ATN high

; 1ms delay, clock high then data high

LAB_EF0C
   TXA                ; save device number
   LDX    #$0B            ; short delay
LAB_EF0F
   DEX                ; decrement count
   BNE    LAB_EF0F        ; loop if not all done

   TAX                ; restore device number
   JSR    LAB_EF84        ; set serial clock high
   JMP    LAB_E4A0        ; set serial data out high and return


;***********************************************************************************;
;
; input a byte from the serial bus

; this routine reads a byte of data from the serial bus using full handshaking. the
; data is returned in the accumulator. before using this routine the TALK routine,
; LAB_FFB4, must have been called first to command the device on the serial bus to
; send data on the bus. if the input device needs a secondary command it must be sent
; by using the TKSA routine, LAB_FF96, before calling this routine.

; errors are returned in the status word which can be read by calling the READST
; routine, LAB_FFB7.

LAB_EF19
   SEI                ; disable interrupts
   LDA    #$00            ; clear A
   STA    LAB_A5        ; clear serial bus bit count
   JSR    LAB_EF84        ; set serial clock high
LAB_EF21
   JSR    LAB_E4B2        ; get serial clock status
   BCC    LAB_EF21        ; loop while clock low

   JSR    LAB_E4A0        ; set serial data out high
LAB_EF29
   LDA    #$01            ; set timeout count high byte
   STA    LAB_9129        ; set VIA 2 T2C_h
LAB_EF2E
   LDA    LAB_912D        ; get VIA 2 IFR
   AND    #$20            ; mask T2 interrupt
   BNE    LAB_EF3C        ; branch if T2 interrupt

   JSR    LAB_E4B2        ; get serial clock status
   BCS    LAB_EF2E        ; loop if clock high

   BCC    LAB_EF54        ; else go se 8 bits to do, branch always

                   ; T2 timed out
LAB_EF3C
   LDA    LAB_A5        ; get serial bus bit count
   BEQ    LAB_EF45        ; if not already EOI then go flag EOI

   LDA    #$02            ; error $02, read timeour
   JMP    LAB_EEB9        ; set serial status and exit

LAB_EF45
   JSR    LAB_E4A9        ; set serial data out low
   JSR    LAB_EF0C        ; 1ms delay, clock high then data high
   LDA    #$40            ; set EOI
   JSR    LAB_FE6A        ; OR into serial status byte
   INC    LAB_A5        ; increment serial bus bit count, do error on next timeout
   BNE    LAB_EF29        ; go try again

LAB_EF54
   LDA    #$08            ; 8 bits to do
   STA    LAB_A5        ; set serial bus bit count
LAB_EF58
   LDA    LAB_911F        ; get VIA 1 DRA, no handshake
   CMP    LAB_911F        ; compare with self
   BNE    LAB_EF58        ; loop if changing

   LSR                ; serial clock into carry
   BCC    LAB_EF58        ; loop while serial clock low

   LSR                ; serial data into carry
   ROR    LAB_A4        ; shift data bit into receive byte
LAB_EF66
   LDA    LAB_911F        ; get VIA 1 DRA, no handshake
   CMP    LAB_911F        ; compare with self
   BNE    LAB_EF66        ; loop if changing

   LSR                ; serial clock into carry
   BCS    LAB_EF66        ; loop while serial clock high

   DEC    LAB_A5        ; decrement serial bus bit count
   BNE    LAB_EF58        ; loop if not all done

   JSR    LAB_E4A9        ; set serial data out low
   LDA    LAB_90        ; get serial status byte
   BEQ    LAB_EF7F        ; branch if no error

   JSR    LAB_EF0C        ; 1ms delay, clock high then data high
LAB_EF7F
   LDA    LAB_A4        ; get receive byte
   CLI                ; enable interrupts
   CLC
   RTS


;***********************************************************************************;
;
; set serial clock high

LAB_EF84
   LDA    LAB_912C        ; get VIA 2 PCR
   AND    #$FD            ; set CA2 low, serial clock out high
   STA    LAB_912C        ; set VIA 2 PCR
   RTS


;***********************************************************************************;
;
; set serial clock low

LAB_EF8D
   LDA    LAB_912C        ; get VIA 2 PCR
   ORA    #$02            ; set CA2 high, serial clock out low
   STA    LAB_912C        ; set VIA 2 PCR
   RTS


;***********************************************************************************;
;
; 1ms delay

LAB_EF96
   LDA    #$04            ; set for 1024 cycles
   STA    LAB_9129        ; set VIA 2 T2C_h
LAB_EF9B
   LDA    LAB_912D        ; get VIA 2 IFR
   AND    #$20            ; mask T2 interrupt
   BEQ    LAB_EF9B        ; loop until T2 interrupt

   RTS


;***********************************************************************************;
;
; RS232 Tx NMI routine

LAB_EFA3
   LDA    LAB_B4        ; get RS232 bit count
   BEQ    LAB_EFEE        ; if zero go setup next RS232 Tx byte and return

   BMI    LAB_EFE8        ; if -ve go do stop bit(s)

                   ; else bit count is non zero and +ve
   LSR    LAB_B6        ; shift RS232 output byte buffer
   LDX    #$00            ; set $00 for bit = 0
   BCC    LAB_EFB0        ; branch if bit was 0

   DEX                ; set $FF for bit = 1
LAB_EFB0
   TXA                ; copy bit to A
   EOR    LAB_BD        ; EOR with RS232 parity byte
   STA    LAB_BD        ; save RS232 parity byte
   DEC    LAB_B4        ; decrement RS232 bit count
   BEQ    LAB_EFBF        ; if RS232 bit count now zero go do parity bit

; save bit and exit

LAB_EFB9
   TXA                ; copy bit to A
   AND    #$20            ; mask for CB2 control bit
   STA    LAB_B5        ; save RS232 next bit to send
   RTS

; do RS232 parity bit, enters with RS232 bit count = 0

LAB_EFBF
   LDA    #$20            ; mask 00x0 0000, parity enable bit
   BIT    LAB_0294        ; test pseudo 6551 command register
   BEQ    LAB_EFDA        ; branch if parity disabled

   BMI    LAB_EFE4        ; branch if fixed mark or space parity

   BVS    LAB_EFDE        ; branch if even parity

                   ; else odd parity
   LDA    LAB_BD        ; get RS232 parity byte
   BNE    LAB_EFCF        ; if parity not zero leave parity bit = 0

LAB_EFCE
   DEX                ; make parity bit = 1
LAB_EFCF
   DEC    LAB_B4        ; decrement RS232 bit count, 1 stop bit
   LDA    LAB_0293        ; get pseudo 6551 control register
   BPL    LAB_EFB9        ; if 1 stop bit save parity bit and exit

                   ; else two stop bits ..
   DEC    LAB_B4        ; decrement RS232 bit count, 2 stop bits
   BNE    LAB_EFB9        ; save bit and exit, branch always

                   ; parity is disabled so the parity bit becomes the first,
                   ; and possibly only, stop bit. to do this increment the bit
                   ; count which effectively decrements the stop bit count.
LAB_EFDA
   INC    LAB_B4        ; increment RS232 bit count, = -1 stop bit
   BNE    LAB_EFCE        ; set stop bit = 1 and exit

                   ; do even parity
LAB_EFDE
   LDA    LAB_BD        ; get RS232 parity byte
   BEQ    LAB_EFCF        ; if parity zero leave parity bit = 0

   BNE    LAB_EFCE        ; else make parity bit = 1, branch always

                   ; fixed mark or space parity
LAB_EFE4
   BVS    LAB_EFCF        ; if fixed space parity leave parity bit = 0

   BVC    LAB_EFCE        ; else fixed mark parity make parity bit = 1, branch always

; decrement stop bit count, set stop bit = 1 and exit. $FF is one stop bit, $FE is two
; stop bits

LAB_EFE8
   INC    LAB_B4        ; decrement RS232 bit count
   LDX    #$FF            ; set stop bit = 1
   BNE    LAB_EFB9        ; save stop bit and exit, branch always

; setup next RS232 Tx byte

LAB_EFEE
   LDA    LAB_0294        ; get 6551 pseudo command register
   LSR                ; handshake bit inot Cb
   BCC    LAB_EFFB        ; branch if 3 line interface

   BIT    LAB_9120        ; test VIA 2 DRB, this is wrong, the adress should be
                   ; LAB_9110 which is VIA 1 which is where the DSR and
                   ; CTS inputs really are ##

   BPL    LAB_F016        ; if DSR = 0 set DSR signal not present and exit

   BVC    LAB_F019        ; if CTS = 0 set CTS signal not present and exit

                   ; was 3 line interface
LAB_EFFB
   LDA    #$00            ; clear A
   STA    LAB_BD        ; clear RS232 parity byte
   STA    LAB_B5        ; clear RS232 next bit to send
   LDX    LAB_0298        ; get number of bits to be sent/received
   STX    LAB_B4        ; set RS232 bit count
   LDY    LAB_029D        ; get index to Tx buffer start
   CPY    LAB_029E        ; compare with index to Tx buffer end
   BEQ    LAB_F021        ; if all done go disable T1 interrupt and return

   LDA    (LAB_F9),Y        ; else get byte from buffer
   STA    LAB_B6        ; save to RS232 output byte buffer
   INC    LAB_029D        ; increment index to Tx buffer start
   RTS


;***********************************************************************************;
;
;## exit or quit
; set DSR signal not present

LAB_F016
   LDA    #$40            ; set DSR signal not present
   .byte    $2C            ; makes next line BIT LAB_10A9

; set CTS signal not present

LAB_F019
   LDA    #$10            ; set CTS signal not present
   ORA    LAB_0297        ; OR with RS232 status register
   STA    LAB_0297        ; save RS232 status register

; disable T1 interrupt

LAB_F021
   LDA    #$40            ; disable T1 interrupt
   STA    LAB_911E        ; set VIA 1 IER
   RTS


;***********************************************************************************;
;
; compute bit count

LAB_F027
   LDX    #$09            ; set bit count to 9, 8 data + 1 stop bit
   LDA    #$20            ; mask for 8/7 data bits
   BIT    LAB_0293        ; test pseudo 6551 control register
   BEQ    LAB_F031        ; branch if 8 bits

   DEX                ; else decrement count for 7 data bits
LAB_F031
   BVC    LAB_F035        ; branch if 7 bits

   DEX                ; else decrement count ..
   DEX                ; .. for 5 data bits
LAB_F035
   RTS


;***********************************************************************************;
;
; RS232 Rx NMI

LAB_F036
   LDX    LAB_A9        ; get start bit check flag
   BNE    LAB_F068        ; branch if no start bit received

   DEC    LAB_A8        ; decrement receiver bit count in
   BEQ    LAB_F06F        ;.

   BMI    LAB_F04D        ;.

   LDA    LAB_A7        ; get receiver input bit temporary storage
   EOR    LAB_AB        ;.
   STA    LAB_AB        ;.
   LSR    LAB_A7        ; shift receiver input bit temporary storage
   ROR    LAB_AA        ;.
LAB_F04A
   RTS

LAB_F04B
   DEC    LAB_A8        ; decrement receiver bit count in
LAB_F04D
   LDA    LAB_A7        ; get receiver input bit temporary storage
   BEQ    LAB_F0B3        ;.

   LDA    LAB_0293        ; get pseudo 6551 control register
   ASL                ;.
   LDA    #$01            ;.
   ADC    LAB_A8        ; add receiver bit count in
   BNE    LAB_F04A        ;.


;***********************************************************************************;
;
;## setup to Rx

LAB_F05B
   LDA    #$90            ; enable CB1 interrupt
   STA    LAB_911E        ; set VIA 1 IER
   STA    LAB_A9        ; set start bit check flag, set no start bit received
   LDA    #$20            ; disable T2 interrupt
   STA    LAB_911E        ; set VIA 1 IER
   RTS


;***********************************************************************************;
;
; no RS232 start bit received

LAB_F068
   LDA    LAB_A7        ; get receiver input bit temporary storage
   BNE    LAB_F05B        ;.

   STA    LAB_A9        ; set start bit check flag, set start bit received
   RTS


;***********************************************************************************;
;
; ??

LAB_F06F
   LDY    LAB_029B        ; get index to Rx buffer end
   INY                ; increment index
   CPY    LAB_029C        ; compare with index to Rx buffer start
   BEQ    LAB_F0A2        ; if buffer full go do Rx overrun error

   STY    LAB_029B        ; save index to Rx buffer end
   DEY                ; decrement index
   LDA    LAB_AA        ; get assembled byte
   LDX    LAB_0298        ; get bit count
LAB_F081
   CPX    #$09            ; compare with byte + stop
   BEQ    LAB_F089        ; branch if all nine bits received

   LSR                ; else shift byte
   INX                ; increment bit count
   BNE    LAB_F081        ; loop, branch always

LAB_F089
   STA    (LAB_F7),Y        ; save received byte to Rx buffer
   LDA    #$20            ; mask 00x0 0000, parity enable bit
   BIT    LAB_0294        ; test pseudo 6551 command register
   BEQ    LAB_F04B        ; branch if parity disabled

   BMI    LAB_F04A        ; branch if mark or space parity

   LDA    LAB_A7        ; get receiver input bit temporary storage
   EOR    LAB_AB        ;.
   BEQ    LAB_F09D        ;.

   BVS    LAB_F04A        ;.

   .byte    $2C            ; makes next line BIT LAB_AB50
LAB_F09D
   BVC    LAB_F04A        ;.

   LDA    #$01            ; set Rx parity error
   .byte    $2C            ; makes next line BIT LAB_04A9

LAB_F0A2
   LDA    #$04            ; set Rx overrun error
   .byte    $2C            ; makes next line BIT LAB_80A9

LAB_F0A5
   LDA    #$80            ; Rx break error
   .byte    $2C            ; makes next line BIT LAB_02A9

LAB_F0A8
   LDA    #$02            ; Rx frame error
   ORA    LAB_0297        ; OR with RS232 status byte
   STA    LAB_0297        ; save RS232 status byte
   JMP    LAB_F05B        ;.

LAB_F0B3
   LDA    LAB_AA        ;.
   BNE    LAB_F0A8        ; if ?? do frame error

   BEQ    LAB_F0A5        ; else do break error, branch always


;***********************************************************************************;
;
; do illegal device number

LAB_F0B9
   JMP    LAB_F796        ; do illegal device number and return


;***********************************************************************************;
;
; open RS232 channel for output

LAB_F0BC
   STA    LAB_9A        ; save output device number
   LDA    LAB_0294        ; get pseudo 6551 command register
   LSR                ; shift handshake bit to carry
   BCC    LAB_F0EB        ; branch if 3 line interface

   LDA    #$02            ; mask for RTS out
   BIT    LAB_9110        ; test VIA 1 DRB
   BPL    LAB_F0E8        ; if DSR = 0 set DSR not present and exit

   BNE    LAB_F0EB        ; if RTS = 1 just exit

LAB_F0CD
   LDA    LAB_911E        ; get VIA 1 IER
   AND    #$30            ; mask 00xx 0000, T2 and CB1 interrupts
   BNE    LAB_F0CD        ; loop while either enabled

LAB_F0D4
   BIT    LAB_9110        ; test VIA 1 DRB
   BVS    LAB_F0D4        ; loop while CTS high

   LDA    LAB_9110        ; get VIA 1 DRB
   ORA    #$02            ; set RTS high
   STA    LAB_9110        ; save VIA 1 DRB
LAB_F0E1
   BIT    LAB_9110        ; test VIA 1 DRB
   BVS    LAB_F0EB        ; exit if CTS high

   BMI    LAB_F0E1        ; loop while DSR high

LAB_F0E8
   JSR    LAB_F016        ; set DSR signal not present
LAB_F0EB
   CLC                ; flag ok
   RTS


;***********************************************************************************;
;
; send byte to RS232 buffer

LAB_F0ED
   LDY    LAB_029E        ; get index to Tx buffer end
   INY                ; + 1
   CPY    LAB_029D        ; compare with index to Tx buffer start
   BEQ    LAB_F0ED        ; loop while buffer full

   STY    LAB_029E        ; set index to Tx buffer end
   DEY                ; index to available buffer byte
   STA    (LAB_F9),Y        ; save byte to buffer
   BIT    LAB_911E        ; test VIA 1 IER
   BVC    LAB_F102        ; branch if T1 not enabled

   RTS

LAB_F102
   LDA    LAB_0299        ; get baud rate bit time low byte
   STA    LAB_9114        ; set VIA 1 T1C_l
   LDA    LAB_029A        ; get baud rate bit time high byte
   STA    LAB_9115        ; set VIA 1 T1C_h
   LDA    #$C0            ; enable T1 interrupt
   STA    LAB_911E        ; set VIA 1 IER
   JMP    LAB_EFEE        ; setup next RS232 Tx byte and return


;***********************************************************************************;
;
; input from RS232 buffer

LAB_F116
   STA    LAB_99        ; save input device number
   LDA    LAB_0294        ; get pseudo 6551 command register
   LSR                ;.
   BCC    LAB_F146        ; branch if 3 line interface

   AND    #$08            ; mask duplex bit, pseudo 6551 command is >> 1
   BEQ    LAB_F146        ; branch if full duplex

   LDA    #$02            ;.
   BIT    LAB_9110        ; test VIA 1 DRB
   BPL    LAB_F0E8        ;.

   BEQ    LAB_F144        ;.

LAB_F12B
   BIT    LAB_911E        ; test VIA 1 IER
   BVS    LAB_F12B        ; loop while T1 interrupt enabled

   LDA    LAB_9110        ; get VIA 1 DRB
   AND    #$FD            ; mask xxxx xx0x, clear RTS out
   STA    LAB_9110        ; save VIA 1 DRB
LAB_F138
   LDA    LAB_9110        ; get VIA 1 DRB
   AND    #$04            ; mask xxxx x1xx, DTR
   BEQ    LAB_F138        ; loop while DTR low

LAB_F13F
   LDA    #$90            ; enable CB1 interrupt
   STA    LAB_911E        ; set VIA 1 IER
LAB_F144
   CLC                ;.
   RTS

LAB_F146
   LDA    LAB_911E        ; get VIA 1 IER
   AND    #$30            ; mask 0xx0 0000, T1 and T2 interrupts
   BEQ    LAB_F13F        ; if both interrupts disabled go enable CB1
                   ; interrupt and exit

   CLC                ;.
   RTS


;***********************************************************************************;
;
; get byte from RS232 buffer

LAB_F14F
   LDY    LAB_029C        ; get index to Rx buffer start
   CPY    LAB_029B        ; compare with index to Rx buffer end
   BEQ    LAB_F15D        ; return null if buffer empty

   LDA    (LAB_F7),Y        ; get byte from Rx buffer
   INC    LAB_029C        ; increment index to Rx buffer start
   RTS

LAB_F15D
   LDA    #$00            ; return null
   RTS


;***********************************************************************************;
;
; check RS232 bus idle

LAB_F160
   PHA                ; save A
   LDA    LAB_911E        ; get VIA 1 IER
   BEQ    LAB_F172        ; branch if no interrupts enabled. this branch will
                   ; never be taken as b7 of IER always reads as 1
                   ; according to the 6522 data sheet
LAB_F166
   LDA    LAB_911E        ; get VIA 1 IER
   AND    #$60            ; mask 0xx0 0000, T1 and T2 interrupts
   BNE    LAB_F166        ; loop if T1 or T2 active

   LDA    #$10            ; disable CB1 interrupt
   STA    LAB_911E        ; set VIA 1 IER
LAB_F172
   PLA                ; restore A
   RTS


;***********************************************************************************;
;
; kernel I/O messages

LAB_F174
   .byte    $0D,"I/O ERROR ",'#'+$80
LAB_F180
   .byte    $0D,"SEARCHING",' '+$80
LAB_F18B
   .byte    "FOR",' '+$80
LAB_F18F
   .byte    $0D,"PRESS PLAY ON TAP",'E'+$80
LAB_F1A2
   .byte    "PRESS RECORD & PLAY ON TAP",'E'+$80
LAB_F1BD
   .byte    $0D,"LOADIN",'G'+$80
LAB_F1C5
   .byte    $0D,"SAVING",' '+$80
LAB_F1CD
   .byte    $0D,"VERIFYIN",'G'+$80
LAB_F1D7
   .byte    $0D,"FOUND",' '+$80
LAB_F1DE
   .byte    $0D,"OK",$0D+$80


;***********************************************************************************;
;
; display control I/O message if in direct mode

LAB_F1E2
   BIT    LAB_9D        ; test message mode flag
   BPL    LAB_F1F3        ; exit if control messages off

; display kernel I/O message

LAB_F1E6
   LDA    LAB_F174,Y        ; get byte from message table
   PHP                ; save status
   AND    #$7F            ; clear b7
   JSR    LAB_FFD2        ; output character to channel
   INY                ; increment index
   PLP                ; restore status
   BPL    LAB_F1E6        ; loop if not end of message

LAB_F1F3
   CLC                ;.
   RTS


;***********************************************************************************;
;
; get a character from the input device

; in practice this routine operates identically to the CHRIN routine, LAB_FFCF,
; for all devices except for the keyboard. If the keyboard is the current input
; device this routine will get one character from the keyboard buffer. It depends
; on the IRQ routine to read the keyboard and put characters into the buffer.

; If the keyboard buffer is empty the value returned in the accumulator will be zero

LAB_F1F5
   LDA    LAB_99        ; get input device number
   BNE    LAB_F201        ; branch if not keyboard

                   ; input device was keyboard
   LDA    LAB_C6        ; get keyboard buffer length
   BEQ    LAB_F26A        ; if buffer empty go flag no byte and return

   SEI                ; disable interrupts
   JMP    LAB_E5CF        ; input from keyboard buffer and return

                   ; input device was not keyboard
LAB_F201
   CMP    #$02            ; compare device with RS232 device
   BNE    LAB_F21D        ; branch if not RS232 device

                   ; input device is RS232 device
LAB_F205
   STY    LAB_97        ; save Y
   JSR    LAB_F14F        ; get byte from RS232 buffer
   LDY    LAB_97        ; restore Y
   CLC                ; flag no error
   RTS


;***********************************************************************************;
;
; input character from channel

; this routine will get a byte of data from the channel already set up as the input
; channel by the CHKIN routine, LAB_FFC6.

; If CHKIN, LAB_FFC6, has not been used to define another input channel the data is
; expected to be from the keyboard. the data byte is returned in the accumulator. the
; channel remains open after the call.

; input from the keyboard is handled in a special way. first, the cursor is turned on
; and it will blink until a carriage return is typed on the keyboard. all characters
; on the logical line, up to 88 characters, will be stored in the BASIC input buffer.
; then the characters can be returned one at a time by calling this routine once for
; each character. when the carriage return is returned the entire line has been
; processed. the next time this routine is called the whole process begins again.

LAB_F20E
   LDA    LAB_99        ; get input device number
   BNE    LAB_F21D        ; if it's not the keyboard continue

                   ; the input device is the keyboard
   LDA    LAB_D3        ; get cursor column
   STA    LAB_CA        ; set input cursor column
   LDA    LAB_D6        ; get cursor row
   STA    LAB_C9        ; set input cursor row
   JMP    LAB_E64F        ; go get input from the keyboard

; the input device was not the keyboard

LAB_F21D
   CMP    #$03            ; compare device number with screen
   BNE    LAB_F22A        ; if it's not the screen continue

                   ; the input device is the screen
   STA    LAB_D0        ; input from keyboard or screen, $xx = screen,
                   ; $00 = keyboard
   LDA    LAB_D5        ; get current screen line length
   STA    LAB_C8        ; save input [EOL] pointer
   JMP    LAB_E64F        ; go get input from the screen

; the input device was not the screen

LAB_F22A
   BCS    LAB_F264        ; if input device is the serial bus go handle it

; the input device is < the screen do must be the RS232 or tape device

   CMP    #$02            ; compare device with RS232 device
   BEQ    LAB_F26F        ; if it's the RS232 device go handle it

; else there's only the tape device left ..

   STX    LAB_97        ; save X
   JSR    LAB_F250        ; get byte from tape
   BCS    LAB_F24D        ; exit if error

   PHA                ; save byte
   JSR    LAB_F250        ; get next byte from tape
   BCS    LAB_F24A        ; exit if error

   BNE    LAB_F244        ; branch if end reached

   LDA    #$40            ; set [EOF] bit
   JSR    LAB_FE6A        ; OR into serial status byte
LAB_F244
   DEC    LAB_A6        ; decrement tape buffer index
   LDX    LAB_97        ; restore X
   PLA                ; restore saved byte
   RTS

; error exit from input character

LAB_F24A
   TAX                ; copy error byte ??
   PLA                ; dump saved byte
   TXA                ; restore error byte ??
LAB_F24D
   LDX    LAB_97        ; restore X
   RTS


;***********************************************************************************;
;
; get byte from tape

LAB_F250
   JSR    LAB_F88A        ; bump tape pointer
   BNE    LAB_F260        ; if not end get next byte and exit

   JSR    LAB_F8C0        ; initiate tape read
   BCS    LAB_F26B        ; exit if error flagged

   LDA    #$00            ; clear A
   STA    LAB_A6        ; clear tape buffer index
   BEQ    LAB_F250        ; loop, branch always

LAB_F260
   LDA    (LAB_B2),Y        ; get next byte from buffer
   CLC                ; flag no error
   RTS


;***********************************************************************************;
;
; the input device was the serial bus

LAB_F264
   LDA    LAB_90        ; get serial status byte
   BEQ    LAB_F26C        ; if no errors flagged go input byte and return

   LDA    #$0D            ; else return [EOL]
LAB_F26A
   CLC                ; flag no error
LAB_F26B
   RTS

LAB_F26C
   JMP    LAB_EF19        ; input a byte from the serial bus and return

                   ; input device was RS232 device
LAB_F26F
   JSR    LAB_F205        ; get byte from RS232 device
   BCS    LAB_F279        ; branch if error, this doesn't get taken as the last
                   ; instruction in the get byte from RS232 device routine
                   ; is CLC
   CMP    #$00            ; compare with null
   BEQ    LAB_F26F        ; loop if null

   CLC                ; flag no error
LAB_F279
   RTS


;***********************************************************************************;
;
; output a character to channel

; this routine will output a character to an already opened channel. Use the OPEN
; routine, LAB_FFC0, and the CHKOUT routine, LAB_FFC9, to set up the output channel
; before calling this routine. If these calls are omitted, data will be sent to the
; default output device, device 3, the screen. The data byte to be output is loaded
; into the accumulator, and this routine is called. The data is then sent to the
; specified output device. The channel is left open after the call.

; NOTE: Care must be taken when using routine to send data to a serial device since
; data will be sent to all open output channels on the bus. Unless this is desired,
; all open output channels on the serial bus other than the actually intended
; destination channel must be closed by a call to the KERNAL close channel routine.

LAB_F27A
   PHA                ; save the character to send
   LDA    LAB_9A        ; get output device number
   CMP    #$03            ; compare device number with screen
   BNE    LAB_F285        ; if output device not screen continue

; the output device is the screen

   PLA                ; restore character to send
   JMP    LAB_E742        ; output character and return

; the output device was not the screen

LAB_F285
   BCC    LAB_F28B        ; if output device < screen continue

; the output device was > screen so it is a serial bus device

   PLA                ; restore character to send
   JMP    LAB_EEE4        ; output a byte to the serial bus and return

; the output device is < screen

LAB_F28B
   CMP    #$02            ; compare the device with RS232 device
   BEQ    LAB_F2B9        ; if output device is RS232 device go handle it

; else the output device is the cassette

   PLA                ; restore the character to send


;***********************************************************************************;
;
; output a character to the cassette

LAB_F290
   STA    LAB_9E        ; save character to character buffer
   PHA                ; save A
   TXA                ; copy X
   PHA                ; save X
   TYA                ; copy Y
   PHA                ; save Y
   JSR    LAB_F88A        ; bump tape pointer
   BNE    LAB_F2AA        ; if not end save next byte and exit

   JSR    LAB_F8E3        ; initiate tape write
   BCS    LAB_F2AF        ; exit if error

   LDA    #$02            ; set data block type ??
   LDY    #$00            ; clear index
   STA    (LAB_B2),Y        ; save type to buffer ??
   INY                ; increment index
   STY    LAB_A6        ; save tape buffer index
LAB_F2AA
   LDA    LAB_9E        ; restore character from character buffer
   STA    (LAB_B2),Y        ; save to buffer
   CLC                ; flag no error
LAB_F2AF
   PLA                ; pull Y
   TAY                ; restore Y
   PLA                ; pull X
   TAX                ; restore X
   PLA                ; restore A
   BCC    LAB_F2B8        ; exit if no error

   LDA    #$00            ; else clear A
LAB_F2B8
   RTS


;***********************************************************************************;
;
; the output device is RS232 device

LAB_F2B9
   PLA                ; restore character to send
   STX    LAB_97        ; save X
   STY    LAB_9E        ; save Y
   JSR    LAB_F0ED        ; send byte to RS232 buffer
   LDX    LAB_97        ; restore Y
   LDY    LAB_9E        ; restore X
   CLC                ; flag ok
   RTS


;***********************************************************************************;
;
; open a channel for input

; any logical file that has already been opened by the OPEN routine, LAB_FFC0, can be
; defined as an input channel by this routine. the device on the channel must be an
; input device or an error will occur and the routine will abort.

; if you are getting data from anywhere other than the keyboard, this routine must be
; called before using either the CHRIN routine, LAB_FFCF, or the GETIN routine,
; LAB_FFE4. if you are getting data from the keyboard and no other input channels are
; open then the calls to this routine and to the OPEN routine, LAB_FFC0, are not needed.

; when used with a device on the serial bus this routine will automatically send the
; listen address specified by the OPEN routine, LAB_FFC0, and any secondary address.

; possible errors are:
;
;    3 : file not open
;    5 : device not present
;    6 : file is not an input file

LAB_F2C7
   JSR    LAB_F3CF        ; find file
   BEQ    LAB_F2CF        ; branch if file opened

   JMP    LAB_F784        ; do file not open error and return

LAB_F2CF
   JSR    LAB_F3DF        ; set file details from table,X
   LDA    LAB_BA        ; get device number
   BEQ    LAB_F2EC        ; if device was keyboard save device #, flag ok and exit

   CMP    #$03            ; compare device number with screen
   BEQ    LAB_F2EC        ; if device was screen save device #, flag ok and exit

   BCS    LAB_F2F0        ; branch if serial bus device

   CMP    #$02            ; compare device with RS232 device
   BNE    LAB_F2E3        ; branch if not RS 232 device

   JMP    LAB_F116        ; else get input from RS232 buffer and return

LAB_F2E3
   LDX    LAB_B9        ; get secondary address
   CPX    #$60            ;.
   BEQ    LAB_F2EC        ;.

   JMP    LAB_F78D        ; do not input file error and return

LAB_F2EC
   STA    LAB_99        ; save input device number
   CLC                ; flag ok
   RTS

                   ; device was serial bus device
LAB_F2F0
   TAX                ; copy device number to X
   JSR    LAB_EE14        ; command a serial bus device to TALK
   LDA    LAB_B9        ; get secondary address
   BPL    LAB_F2FE        ;.

   JSR    LAB_EED3        ; wait for bus end after send
   JMP    LAB_F301        ;.

LAB_F2FE
   JSR    LAB_EECE        ; send secondary address after TALK
LAB_F301
   TXA                ; copy device back to A
   BIT    LAB_90        ; test serial status byte
   BPL    LAB_F2EC        ; if device present save device number and exit

   JMP    LAB_F78A        ; do device not present error and return


;***********************************************************************************;
;
; open a channel for output

; any logical file that has already been opened by the OPEN routine, LAB_FFC0, can be
; defined as an output channel by this routine the device on the channel must be an
; output device or an error will occur and the routine will abort.

; if you are sending data to anywhere other than the screen this routine must be
; called before using the CHROUT routine, LAB_FFD2. if you are sending data to the
; screen and no other output channels are open then the calls to this routine and to
; the OPEN routine, LAB_FFC0, are not needed.

; when used with a device on the serial bus this routine will automatically send the
; listen address specified by the OPEN routine, LAB_FFC0, and any secondary address.

; possible errors are:
;
;    3 : file not open
;    5 : device not present
;    7 : file is not an output file

LAB_F309
   JSR    LAB_F3CF        ; find file
   BEQ    LAB_F311        ; branch if file found

   JMP    LAB_F784        ; do file not open error and return

LAB_F311
   JSR    LAB_F3DF        ; set file details from table,X
   LDA    LAB_BA        ; get device number
   BNE    LAB_F31B        ; branch if device is not keyboard

LAB_F318
   JMP    LAB_F790        ; do not output file error and return

LAB_F31B
   CMP    #$03            ; compare device number with screen
   BEQ    LAB_F32E        ; if screen save output device number and exit

   BCS    LAB_F332        ; branch if > screen, serial bus device

   CMP    #$02            ; compare device with RS232 device
   BNE    LAB_F328        ; branch if not RS232 device, must be tape

   JMP    LAB_F0BC        ; open RS232 channel for output

                   ; open tape channel for output
LAB_F328
   LDX    LAB_B9        ; get secondary address
   CPX    #$60            ;.
   BEQ    LAB_F318        ; if ?? do not output file error and return

LAB_F32E
   STA    LAB_9A        ; save output device number
   CLC                ; flag ok
   RTS

LAB_F332
   TAX                ; copy device number
   JSR    LAB_EE17        ; command devices on the serial bus to LISTEN
   LDA    LAB_B9        ; get secondary address
   BPL    LAB_F33F        ; branch if address to send

   JSR    LAB_EEC5        ; else set serial ATN high
   BNE    LAB_F342        ; branch always

LAB_F33F
   JSR    LAB_EEC0        ; send secondary address after LISTEN
LAB_F342
   TXA                ; copy device number back to A
   BIT    LAB_90        ; test serial status byte
   BPL    LAB_F32E        ; if device present save output device number and exit

   JMP    LAB_F78A        ; else do device not present error and return


;***********************************************************************************;
;
; close a specified logical file

; this routine is used to close a logical file after all I/O operations have been
; completed on that file. This routine is called after the accumulator is loaded
; with the logical file number to be closed, the same number used when the file was
; opened using the OPEN routine.

LAB_F34A
   JSR    LAB_F3D4        ; find file A
   BEQ    LAB_F351        ; if the file is found go close it

   CLC                ; else thr file was closed so just flag ok
   RTS

; found the file so close it

LAB_F351
   JSR    LAB_F3DF        ; set file details from table,X
   TXA                ; copy file index to A
   PHA                ; save file index
   LDA    LAB_BA        ; get device number
   BEQ    LAB_F3B1        ; if $00, keyboard, restore index and close file

   CMP    #$03            ; compare device number with screen
   BEQ    LAB_F3B1        ; if screen restore index and close file

   BCS    LAB_F3AE        ; if > screen go do serial bus device close

   CMP    #$02            ; compare device with RS232 device
   BNE    LAB_F38D        ; branch if not RS232 device

                   ; else close RS232 device
   PLA                ; restore file index
   JSR    LAB_F3B2        ; close file index X
   LDA    #$7D            ; disable T1, T2, CB1, CB2, SR and CA2
   STA    LAB_911E        ; set VIA 1 IER
   LDA    #$06            ; set DTR and RTS high
   STA    LAB_9110        ; set VIA 1 DRB
   LDA    #$EE            ; CB2 high, CB1 -ve edge, CA2 high, CA1 -ve edge
   STA    LAB_911C        ; set VIA 1 PCR
   JSR    LAB_FE75        ; read the top of memory
   LDA    LAB_F8        ; get RS232 input buffer pointer high byte
   BEQ    LAB_F37F        ; branch if no RS232 input buffer

   INY                ; else reclaim RS232 input buffer memory
LAB_F37F
   LDA    LAB_FA        ; get RS232 output buffer pointer high byte
   BEQ    LAB_F384        ; branch if no RS232 output buffer

   INY                ; else reclaim RS232 output buffer memory
LAB_F384
   LDA    #$00            ; clear A
   STA    LAB_F8        ; clear RS232 input buffer pointer high byte
   STA    LAB_FA        ; clear RS232 output buffer pointer high byte
   JMP    LAB_F53C        ; go set top of memory and exit

LAB_F38D
   LDA    LAB_B9        ; get secondary address
   AND    #$0F            ;.
   BEQ    LAB_F3B1        ; if ?? restore index and close file

   JSR    LAB_F84D        ; get tape buffer start pointer in XY
   LDA    #$00            ; character $00
   JSR    LAB_F290        ; output character to cassette
   JMP    LAB_E4CF        ; go do CLOSE tail

LAB_F39E
   BCS    LAB_F3CE        ; just exit if error

   LDA    LAB_B9        ; get secondary address
   CMP    #$62            ;.
   BNE    LAB_F3B1        ; if not ?? restore index and close file

   LDA    #$05            ; set logical end of the tape
   JSR    LAB_F7E7        ; write tape header
   JMP    LAB_F3B1        ; restore index and close file


;***********************************************************************************;
;
; do serial bus device file close

LAB_F3AE
   JSR    LAB_F6DA        ; close serial bus device
LAB_F3B1
   PLA                ; restore file index


;***********************************************************************************;
;
; close file index X

LAB_F3B2
   TAX                ; copy index to file to close
   DEC    LAB_98        ; decrement open file count
   CPX    LAB_98        ; compare index with open file count
   BEQ    LAB_F3CD        ; exit if equal, last entry was closing file

                   ; else entry was not last in list so copy last table entry
                   ; file details over the details of the closing one
   LDY    LAB_98        ; get open file count as index
   LDA    LAB_0259,Y        ; get last+1 logical file number from logical file table
   STA    LAB_0259,X        ; save logical file number over closed file
   LDA    LAB_0263,Y        ; get last+1 device number from device number table
   STA    LAB_0263,X        ; save device number over closed file
   LDA    LAB_026D,Y        ; get last+1 secondary address from secondary address table
   STA    LAB_026D,X        ; save secondary address over closed file
LAB_F3CD
   CLC                ;.
LAB_F3CE
   RTS


;***********************************************************************************;
;
; find file

LAB_F3CF
   LDA    #$00            ; clear A
   STA    LAB_90        ; clear serial status byte
   TXA                ; copy logical file number to A

; find file A

LAB_F3D4
   LDX    LAB_98        ; get open file count
LAB_F3D6
   DEX                ; decrememnt count to give index
   BMI    LAB_F3EE        ; exit if no files

   CMP    LAB_0259,X        ; compare logical file number with table logical file number
   BNE    LAB_F3D6        ; loop if no match

   RTS


;***********************************************************************************;
;
; set file details from table,X

LAB_F3DF
   LDA    LAB_0259,X        ; get logical file from logical file table
   STA    LAB_B8        ; set logical file
   LDA    LAB_0263,X        ; get device number from device number table
   STA    LAB_BA        ; set device number
   LDA    LAB_026D,X        ; get secondary address from secondary address table
   STA    LAB_B9        ; set secondary address
LAB_F3EE
   RTS


;***********************************************************************************;
;
; close all channels and files

; this routine closes all open files. When this routine is called, the pointers into
; the open file table are reset, closing all files. Also the routine automatically
; resets the I/O channels.

LAB_F3EF
   LDA    #$00            ; clear A
   STA    LAB_98        ; clear open file count


;***********************************************************************************;
;
; close input and output channels

; this routine is called to clear all open channels and restore the I/O channels to
; their original default values. It is usually called after opening other I/O
; channels and using them for input/output operations. The default input device is
; 0, the keyboard. The default output device is 3, the screen.

; If one of the channels to be closed is to the serial port, an UNTALK signal is sent
; first to clear the input channel or an UNLISTEN is sent to clear the output channel.
; By not calling this routine and leaving listener(s) active on the serial bus,
; several devices can receive the same data from the VIC at the same time. One way to
; take advantage of this would be to command the printer to TALK and the disk to
; LISTEN. This would allow direct printing of a disk file.

LAB_F3F3
   LDX    #$03            ; set X to screen
   CPX    LAB_9A        ; compare output device number with screen
   BCS    LAB_F3FC        ; branch if >= screen

                   ; else was serial bus
   JSR    LAB_EF04        ; command the serial bus to UNLISTEN
LAB_F3FC
   CPX    LAB_99        ; compare input device number with screen
   BCS    LAB_F403        ; branch if >= screen

                   ; else was serial bus
   JSR    LAB_EEF6        ; command the serial bus to UNTALK
LAB_F403
   STX    LAB_9A        ; set output device number to screen
   LDA    #$00            ; set for keyboard
   STA    LAB_99        ; set input device number to keyboard
   RTS


;***********************************************************************************;
;
; open a logical file

; this routine is used to open a logical file. Once the logical file is set up it
; can be used for input/output operations. Most of the I/O KERNAL routines call on
; this routine to create the logical files to operate on. No arguments need to be
; set up to use this routine, but both the SETLFS, LAB_FFBA, and SETNAM, LAB_FFBD,
; KERNAL routines must be called before using this routine.

LAB_F40A
   LDX    LAB_B8        ; get logical file number
   BNE    LAB_F411        ; branch if there is a file

   JMP    LAB_F78D        ; else do not input file error and return

LAB_F411
   JSR    LAB_F3CF        ; find file
   BNE    LAB_F419        ; branch if file not found

   JMP    LAB_F781        ; else do file already open error and return

LAB_F419
   LDX    LAB_98        ; get open file count
   CPX    #$0A            ; compare with max
   BCC    LAB_F422        ; branch if less

   JMP    LAB_F77E        ; else do too many files error and return

LAB_F422
   INC    LAB_98        ; increment open file count
   LDA    LAB_B8        ; get logical file number
   STA    LAB_0259,X        ; save to logical file table
   LDA    LAB_B9        ; get secondary address
   ORA    #$60            ; OR with the OPEN CHANNEL command
   STA    LAB_B9        ; set secondary address
   STA    LAB_026D,X        ; save to secondary address table
   LDA    LAB_BA        ; get device number
   STA    LAB_0263,X        ; save to device number table
   BEQ    LAB_F493        ; do ok exit if keyboard

   CMP    #$03            ; compare device number with screen
   BEQ    LAB_F493        ; do ok exit if screen

   BCC    LAB_F444        ; branch if < screen, tape or RS232

                   ; else is serial bus device
   JSR    LAB_F495        ; send secondary address and filename
   BCC    LAB_F493        ; do ok exit

LAB_F444
   CMP    #$02            ; compare device with RS232 device
   BNE    LAB_F44B        ; branch if not RS232 device, must be tape

   JMP    LAB_F4C7        ; go open RS232 device and return

LAB_F44B
   JSR    LAB_F84D        ; get tape buffer start pointer in XY
   BCS    LAB_F453        ; branch if >= $0200

   JMP    LAB_F796        ; do illegal device number and return

LAB_F453
   LDA    LAB_B9        ; get secondary address
   AND    #$0F            ;.
   BNE    LAB_F478        ;.

   JSR    LAB_F894        ; wait for PLAY
   BCS    LAB_F494        ; exit if STOP was pressed

   JSR    LAB_F647        ; print "Searching..."
   LDA    LAB_B7        ; get file name length
   BEQ    LAB_F46F        ; if null file name just go find header

   JSR    LAB_F867        ; find specific tape header
   BCC    LAB_F482        ; branch if no error

   BEQ    LAB_F494        ; exit if ??

LAB_F46C
   JMP    LAB_F787        ; do file not found error and return

LAB_F46F
   JSR    LAB_F7AF        ; find tape header, exit with header in buffer
   BEQ    LAB_F494        ; exit if end of tape found

   BCC    LAB_F482        ;.

   BCS    LAB_F46C        ;.

LAB_F478
   JSR    LAB_F8B7        ; wait for PLAY/RECORD
   BCS    LAB_F494        ; exit if STOP was pressed

   LDA    #$04            ; set data file header
   JSR    LAB_F7E7        ; write tape header
LAB_F482
   LDA    #$BF            ;.
   LDY    LAB_B9        ; get secondary address
   CPY    #$60            ;.
   BEQ    LAB_F491        ;.

   LDY    #$00            ; clear index
   LDA    #$02            ;.
   STA    (LAB_B2),Y        ;.save to tape buffer
   TYA                ;.clear A
LAB_F491
   STA    LAB_A6        ;.save tape buffer index
LAB_F493
   CLC                ; flag ok
LAB_F494
   RTS


;***********************************************************************************;
;
; send secondary address and filename

LAB_F495
   LDA    LAB_B9        ; get secondary address
   BMI    LAB_F4C5        ; ok exit if -ve

   LDY    LAB_B7        ; get file name length
   BEQ    LAB_F4C5        ; ok exit if null

   LDA    LAB_BA        ; get device number
   JSR    LAB_EE17        ; command devices on the serial bus to LISTEN
   LDA    LAB_B9        ; get the secondary address
   ORA    #$F0            ; OR with the OPEN command
   JSR    LAB_EEC0        ; send secondary address after LISTEN
   LDA    LAB_90        ; get serial status byte
   BPL    LAB_F4B2        ; branch if device present

   PLA                ; else dump calling address low byte
   PLA                ; dump calling address high byte
   JMP    LAB_F78A        ; do device not present error and return

LAB_F4B2
   LDA    LAB_B7        ; get file name length
   BEQ    LAB_F4C2        ; branch if null name

   LDY    #$00            ; clear index
LAB_F4B8
   LDA    (LAB_BB),Y        ; get file name byte
   JSR    LAB_EEE4        ; output a byte to the serial bus
   INY                ; increment index
   CPY    LAB_B7        ; compare with file name length
   BNE    LAB_F4B8        ; loop if not all done

LAB_F4C2
   JSR    LAB_EF04        ; command the serial bus to UNLISTEN
LAB_F4C5
   CLC                ; flag ok
   RTS


;***********************************************************************************;
;
; open RS232

LAB_F4C7
   LDA    #$06            ; IIII IOOI, DTR and RTS only as outputs
   STA    LAB_9112        ; set VIA 1 DDRB
   STA    LAB_9110        ; set VIA 1 DRB, DTR and RTS high
   LDA    #$EE            ; CB2 high, CB1 -ve edge, CA2 high, CA1 -ve edge
   STA    LAB_911C        ; set VIA 1 PCR
   LDY    #$00            ; clear index
   STY    LAB_0297        ; clear RS232 status byte
LAB_F4D9
   CPY    LAB_B7        ; compare with file name length
   BEQ    LAB_F4E7        ; exit loop if done

   LDA    (LAB_BB),Y        ; get file name byte
   STA    LAB_0293,Y        ; copy to 6551 register set
   INY                ; increment index
   CPY    #$04            ; compare with $04
   BNE    LAB_F4D9        ; loop if not to 4 yet

LAB_F4E7
   JSR    LAB_F027        ; compute bit count
   STX    LAB_0298        ; save bit count
   LDA    LAB_0293        ; get pseudo 6551 control register
   AND    #$0F            ; mask 0000 xxxx, baud rate
   BNE    LAB_F4F4        ; branch nowhere. perhaps there was going to be some
                   ; error trapping for unimplemented baud rates but
                   ; this was ever done
LAB_F4F4
   ASL                ; * 2
   TAX                ; copy to index
   LDA    LAB_FF5C-2,X    ; get timer constant low byte
   ASL                ; * 2
   TAY                ; copy to Y
   LDA    LAB_FF5C-1,X    ; get timer constant high byte
   ROL                ; * 2
   PHA                ; save it
   TYA                ; get timer constant low byte back
   ADC    #$C8            ; + $C8, carry cleared by previous ROL
   STA    LAB_0299        ; save bit cell time low byte
   PLA                ; restore high byte
   ADC    #$00            ; add carry
   STA    LAB_029A        ; save bit cell time high byte
   LDA    LAB_0294        ; get pseudo 6551 command register
   LSR                ; shift b0 into Cb
   BCC    LAB_F51B        ; branch if 3 line interface

   LDA    LAB_9120        ; get VIA 2 DRB, this is wrong, the adress should be
                   ; LAB_9110 which is VIA 1 which is where the DSR input
                   ; really is
   ASL                ; shift DSR into Cb
   BCS    LAB_F51B        ; branch if DSR = 1

   JMP    LAB_F016        ; set DSR signal not present and return

LAB_F51B
   LDA    LAB_029B        ; get index to Rx buffer end
   STA    LAB_029C        ; set index to Rx buffer start, clear Rx buffer
   LDA    LAB_029E        ; get index to Tx buffer end
   STA    LAB_029D        ; set index to Tx buffer start, clear Tx buffer
   JSR    LAB_FE75        ; read the top of memory
   LDA    LAB_F8        ; get Rx buffer pointer high byte
   BNE    LAB_F533        ; branch if buffer already set

   DEY                ; decrement top of memory high byte, 256 byte buffer
   STY    LAB_F8        ; set Rx buffer pointer high byte
   STX    LAB_F7        ; set Rx buffer pointer low byte
LAB_F533
   LDA    LAB_FA        ; get Tx buffer pointer high byte
   BNE    LAB_F53C        ; branch if buffer already set

   DEY                ; decrement Rx buffer pointer high byte, 256 byte buffer
   STY    LAB_FA        ; set Tx buffer pointer high byte
   STX    LAB_F9        ; set Tx buffer pointer low byte
LAB_F53C
   SEC                ;.
   LDA    #$F0            ;.
   JMP    LAB_FE7B        ; set the top of memory and return


;***********************************************************************************;
;
; load RAM from a device

; this routine will load data bytes from any input device directly into the memory
; of the computer. It can also be used for a verify operation comparing data from a
; device with the data already in memory, leaving the data stored in RAM unchanged.

; The accumulator must be set to 0 for a load operation or 1 for a verify. If the
; input device was OPENed with a secondary address of 0 the header information from
; device will be ignored. In this case XY must contain the starting address for the
; load. If the device was addressed with a secondary address of 1 or 2 the data will
; load into memory starting at the location specified by the header. This routine
; returns the address of the highest RAM location which was loaded.

; Before this routine can be called, the SETLFS, LAB_FFBA, and SETNAM, LAB_FFBD,
; routines must be called.

LAB_F542
   STX    LAB_C3        ; set kernal setup pointer low byte
   STY    LAB_C4        ; set kernal setup pointer high byte
   JMP    (LAB_0330)        ; do LOAD vector, usually points to LAB_F549


;***********************************************************************************;
;
; load

LAB_F549
   STA    LAB_93        ; save load/verify flag
   LDA    #$00            ; clear A
   STA    LAB_90        ; clear serial status byte
   LDA    LAB_BA        ; get device number
   BNE    LAB_F556        ; branch if not keyboard

                   ; can't load form keyboard so ..
LAB_F553
   JMP    LAB_F796        ; do illegal device number and return

LAB_F556
   CMP    #$03            ; compare device number with screen
   BEQ    LAB_F553        ; if screen go do illegal device number and return

   BCC    LAB_F5CA        ; branch if less than screen

                   ; else is serial bus device
   LDY    LAB_B7        ; get file name length
   BNE    LAB_F563        ; branch if not null name

   JMP    LAB_F793        ; else do missing file name error and return

LAB_F563
   JSR    LAB_E4BC        ; get seconday address and print "Searching..."
   LDA    #$60            ;.
   STA    LAB_B9        ; save the secondary address
   JSR    LAB_F495        ; send secondary address and filename
   LDA    LAB_BA        ; get device number
   JSR    LAB_EE14        ; command a serial bus device to TALK
   LDA    LAB_B9        ; get secondary address
   JSR    LAB_EECE        ; send secondary address after TALK
   JSR    LAB_EF19        ; input a byte from the serial bus
   STA    LAB_AE        ; save program start address low byte
   LDA    LAB_90        ; get serial status byte
   LSR                ; shift time out read ..
   LSR                ; .. into carry bit
   BCS    LAB_F5C7        ; if timed out go do file not found error and return

   JSR    LAB_EF19        ; input a byte from the serial bus
   STA    LAB_AF        ; save program start address high byte
   JSR    LAB_E4C1        ; set LOAD address if secondary address = 0
LAB_F58A
   LDA    #$FD            ; mask xxxx xx0x, clear time out read bit
   AND    LAB_90        ; mask serial status byte
   STA    LAB_90        ; set serial status byte
   JSR    LAB_FFE1        ; scan stop key, return Zb = 1 = [STOP]
   BNE    LAB_F598        ; branch if not [STOP]

   JMP    LAB_F6CB        ; else close the serial bus device and flag stop

LAB_F598
   JSR    LAB_EF19        ; input a byte from the serial bus
   TAX                ; copy byte
   LDA    LAB_90        ; get serial status byte
   LSR                ; shift time out read ..
   LSR                ; .. into carry bit
   BCS    LAB_F58A        ; if timed out go ??

   TXA                ; copy received byte back
   LDY    LAB_93        ; get load/verify flag
   BEQ    LAB_F5B3        ; branch if load

                   ; else is verify
   LDY    #$00            ; clear index
   CMP    (LAB_AE),Y        ; compare byte with previously loaded byte
   BEQ    LAB_F5B5        ; branch if match

   LDA    #$10            ; flag read error
   JSR    LAB_FE6A        ; OR into serial status byte
   .byte    $2C            ; makes next line BIT LAB_AE91
LAB_F5B3
   STA    (LAB_AE),Y        ; save byte to memory
LAB_F5B5
   INC    LAB_AE        ; increment save pointer low byte
   BNE    LAB_F5BB        ; if no rollover skip the high byte increment

   INC    LAB_AF        ; else increment save pointer high byte
LAB_F5BB
   BIT    LAB_90        ; test serial status byte
   BVC    LAB_F58A        ; loop if not end of file

   JSR    LAB_EEF6        ; command the serial bus to UNTALK
   JSR    LAB_F6DA        ; close serial bus device
   BCC    LAB_F641        ; if ?? go flag ok and exit

LAB_F5C7
   JMP    LAB_F787        ; do file not found error and return

LAB_F5CA
   CMP    #$02            ; compare device with RS232 device
   BNE    LAB_F5D1        ; if not RS232 device continue

   JMP    LAB_F0B9        ; else do illegal device number and return

LAB_F5D1
   JSR    LAB_F84D        ; get tape buffer start pointer in XY
   BCS    LAB_F5D9        ; branch if >= $0200

   JMP    LAB_F796        ; do illegal device number and return

LAB_F5D9
   JSR    LAB_F894        ; wait for PLAY
   BCS    LAB_F646        ; exit if STOP was pressed

   JSR    LAB_F647        ; print "Searching..."
LAB_F5E1
   LDA    LAB_B7        ; get file name length
   BEQ    LAB_F5EE
   JSR    LAB_F867        ; find specific tape header
   BCC    LAB_F5F5        ; if no error continue

   BEQ    LAB_F646        ; exit if ??

   BCS    LAB_F5C7        ;., branch always

LAB_F5EE
   JSR    LAB_F7AF        ; find tape header, exit with header in buffer
   BEQ    LAB_F646        ; exit if ??

   BCS    LAB_F5C7        ;.

LAB_F5F5
   LDA    LAB_90        ; get serial status byte
   AND    #$10            ; mask 000x 0000, read error
   SEC                ; flag fail
   BNE    LAB_F646        ; if read error just exit

   CPX    #$01            ;.
   BEQ    LAB_F611        ;.

   CPX    #$03            ;.
   BNE    LAB_F5E1        ;.

LAB_F604
   LDY    #$01            ;.
   LDA    (LAB_B2),Y        ;.
   STA    LAB_C3        ;.
   INY                ;.
   LDA    (LAB_B2),Y        ;.
   STA    LAB_C4        ;.
   BCS    LAB_F615        ;.

LAB_F611
   LDA    LAB_B9        ; get secondary address
   BNE    LAB_F604        ;.

LAB_F615
   LDY    #$03            ;.
   LDA    (LAB_B2),Y        ;.
   LDY    #$01            ;.
   SBC    (LAB_B2),Y        ;.
   TAX                ;.
   LDY    #$04            ;.
   LDA    (LAB_B2),Y        ;.
   LDY    #$02            ;.
   SBC    (LAB_B2),Y        ;.
   TAY                ;.
   CLC                ;.
   TXA                ;.
   ADC    LAB_C3        ;.
   STA    LAB_AE        ;.
   TYA                ;.
   ADC    LAB_C4        ;.
   STA    LAB_AF        ;.
   LDA    LAB_C3        ;.
   STA    LAB_C1        ; set I/O start addresses low byte
   LDA    LAB_C4        ;.
   STA    LAB_C2        ; set I/O start addresses high byte
   JSR    LAB_F66A        ; display "LOADING" or "VERIFYING"
   JSR    LAB_F8C9        ; do the tape read
   .byte    $24            ; makes next line BIT LAB_18, keep the error flag in Cb
LAB_F641
   CLC                ; flag ok
   LDX    LAB_AE        ; get the LOAD end pointer low byte
   LDY    LAB_AF        ; get the LOAD end pointer high byte
LAB_F646
   RTS


;***********************************************************************************;
;
; print "searching"

LAB_F647
   LDA    LAB_9D        ; get message mode flag
   BPL    LAB_F669        ; exit if control messages off

   LDY    #LAB_F180-LAB_F174
                   ; index to "SEARCHING "
   JSR    LAB_F1E6        ; display kernel I/O message
   LDA    LAB_B7        ; get file name length
   BEQ    LAB_F669        ; exit if null name

   LDY    #LAB_F18B-LAB_F174
                   ; else index to "FOR "
   JSR    LAB_F1E6        ; display kernel I/O message

; print file name

LAB_F659
   LDY    LAB_B7        ; get file name length
   BEQ    LAB_F669        ; exit if null file name

   LDY    #$00            ; clear index
LAB_F65F
   LDA    (LAB_BB),Y        ; get file name byte
   JSR    LAB_FFD2        ; output character to channel
   INY                ; increment index
   CPY    LAB_B7        ; compare with file name length
   BNE    LAB_F65F        ; loop if more to do

LAB_F669
   RTS

; display "LOADING" or "VERIFYING"

LAB_F66A
   LDY    #LAB_F1BD-LAB_F174
                   ; point to "LOADING"
   LDA    LAB_93        ; get load/verify flag
   BEQ    LAB_F672        ; branch if load

   LDY    #LAB_F1CD-LAB_F174
                   ; point to "VERIFYING"
LAB_F672
   JMP    LAB_F1E2        ; display kernel I/O message if in direct mode and return


;***********************************************************************************;
;
; save RAM to device, A = index to start address, XY = end address low/high

; this routine saves a section of memory. Memory is saved from an indirect address
; on page 0 specified by A, to the address stored in XY, to a logical file. The
; SETLFS, LAB_FFBA, and SETNAM, LAB_FFBD, routines must be used before calling this
; routine. However, a file name is not required to SAVE to device 1, the cassette.
; Any attempt to save to other devices without using a file name results in an error.

; NOTE: device 0, the keyboard, and device 3, the screen, cannot be SAVEd to. If
; the attempt is made, an error will occur, and the SAVE stopped.

LAB_F675
   STX    LAB_AE        ; save end address low byte
   STY    LAB_AF        ; save end address high byte
   TAX                ; copy index to start pointer
   LDA    LAB_00,X        ; get start address low byte
   STA    LAB_C1        ; set I/O start addresses low byte
   LDA    LAB_01,X        ; get start address high byte
   STA    LAB_C2        ; set I/O start addresses high byte
   JMP    (LAB_0332)        ; go save, usually points to LAB_F685


;***********************************************************************************;
;
; save

LAB_F685
   LDA    LAB_BA        ; get device number
   BNE    LAB_F68C        ; branch if not keyboard

                   ; else ..
LAB_F689
   JMP    LAB_F796        ; do illegal device number and return

LAB_F68C
   CMP    #$03            ; compare device number with screen
   BEQ    LAB_F689        ; if screen do illegal device number and return

   BCC    LAB_F6F1        ; branch if < screen

                   ; is greater than screen so is serial bus
   LDA    #$61            ; set secondary address to $01
                   ; when a secondary address is to be sent to a device on
                   ; the serial bus the address must first be ORed with $60
   STA    LAB_B9        ; save secondary address
   LDY    LAB_B7        ; get file name length
   BNE    LAB_F69D        ; branch if filename not null

   JMP    LAB_F793        ; else do missing file name error and return

LAB_F69D
   JSR    LAB_F495        ; send secondary address and filename
   JSR    LAB_F728        ; print saving [file name]
   LDA    LAB_BA        ; get device number
   JSR    LAB_EE17        ; command devices on the serial bus to LISTEN
   LDA    LAB_B9        ; get secondary address
   JSR    LAB_EEC0        ; send secondary address after LISTEN
   LDY    #$00            ; clear index
   JSR    LAB_FBD2        ; copy I/O start address to buffer address
   LDA    LAB_AC        ; get buffer address low byte
   JSR    LAB_EEE4        ; output a byte to the serial bus
   LDA    LAB_AD        ; get buffer address high byte
   JSR    LAB_EEE4        ; output a byte to the serial bus
LAB_F6BC
   JSR    LAB_FD11        ; check read/write pointer, return Cb = 1 if pointer >= end
   BCS    LAB_F6D7        ; go do UNLISTEN if at end

   LDA    (LAB_AC),Y        ; get byte from buffer
   JSR    LAB_EEE4        ; output a byte to the serial bus
   JSR    LAB_FFE1        ; scan stop key
   BNE    LAB_F6D2        ; if stop not pressed go increment pointer and loop for next

                   ; else ..

; close the serial bus device and flag stop

LAB_F6CB
   JSR    LAB_F6DA        ; close serial bus device
   LDA    #$00            ;.
   SEC                ; flag stop
   RTS

LAB_F6D2
   JSR    LAB_FD1B        ; increment read/write pointer
   BNE    LAB_F6BC        ; loop, branch always


;***********************************************************************************;
;
; command serial bus to UNLISTEN then close channel

LAB_F6D7
   JSR    LAB_EF04        ; command the serial bus to UNLISTEN

; close the serial bus device

LAB_F6DA
   BIT    LAB_B9        ; test the secondary address
   BMI    LAB_F6EF        ; if already closed just exit

   LDA    LAB_BA        ; get the device number
   JSR    LAB_EE17        ; command devices on the serial bus to LISTEN
   LDA    LAB_B9        ; get secondary address
   AND    #$EF            ; mask the channel number
   ORA    #$E0            ; OR with the CLOSE command
   JSR    LAB_EEC0        ; send secondary address after LISTEN
   JSR    LAB_EF04        ; command the serial bus to UNLISTEN
LAB_F6EF
   CLC                ; flag ok
   RTS

;
; save program file to tape

LAB_F6F1
   CMP    #$02            ; compare device with RS232 device
   BNE    LAB_F6F8        ; branch if not RS232 device

   JMP    LAB_F0B9        ; else do illegal device number and return

LAB_F6F8
   JSR    LAB_F84D        ; get tape buffer start pointer in XY
   BCC    LAB_F689        ; if < $0200 do illegal device number and return

   JSR    LAB_F8B7        ; wait for PLAY/RECORD
   BCS    LAB_F727        ; exit if STOP was pressed

   JSR    LAB_F728        ; print saving [file name]
   LDX    #$03            ; set header for a non relocatable program file
   LDA    LAB_B9        ; get secondary address
   AND    #$01            ; mask non relocatable bit
   BNE    LAB_F70F        ; branch if non relocatable program

   LDX    #$01            ; else set header for a relocatable program file
LAB_F70F
   TXA                ; copy header type to A
   JSR    LAB_F7E7        ; write tape header
   BCS    LAB_F727        ; exit if error

   JSR    LAB_F8E6        ; do tape write, 20 cycle count
   BCS    LAB_F727        ; exit if error

   LDA    LAB_B9        ; get secondary address
   AND    #$02            ; mask end of tape flag
   BEQ    LAB_F726        ; branch if not end of tape

   LDA    #$05            ; else set logical end of the tape
   JSR    LAB_F7E7        ; write tape header
   .byte    $24            ; makes next line BIT LAB_18 so Cb is not changed
LAB_F726
   CLC                ; flag ok
LAB_F727
   RTS


;***********************************************************************************;
;
; print saving [file name]

LAB_F728
   LDA    LAB_9D        ; get message mode flag
   BPL    LAB_F727        ; exit if control messages off

   LDY    #LAB_F1C5-LAB_F174
                   ; index to "SAVING "
   JSR    LAB_F1E6        ; display kernel I/O message
   JMP    LAB_F659        ; print file name and return


;***********************************************************************************;
;
; increment real time clock

; this routine updates the system clock. Normally this routine is called by the
; normal KERNAL interrupt routine every 1/60th of a second. If the user program
; processes its own interrupts this routine must be called to update the time. Also,
; the STOP key routine must be called if the stop key is to remain functional.

LAB_F734
   LDX    #$00            ; clear X
   INC    LAB_A2        ; increment jiffy low byte
   BNE    LAB_F740        ; if no rollover skip the mid byte increment

   INC    LAB_A1        ; increment jiffy mid byte
   BNE    LAB_F740        ; if no rollover skip the high byte increment

   INC    LAB_A0        ; increment jiffy high byte

                   ; now subtract a days worth of jiffies from current count
                   ; and remember only the Cb result
LAB_F740
   SEC                ; set carry for subtract
   LDA    LAB_A2        ; get jiffy clock low byte
   SBC    #$01            ; subtract $4F1A01 low byte
   LDA    LAB_A1        ; get jiffy clock mid byte
   SBC    #$1A            ; subtract $4F1A01 mid byte
   LDA    LAB_A0        ; get jiffy clock high byte
   SBC    #$4F            ; subtract $4F1A01 high byte
   BCC    LAB_F755        ; branch if less than $4F1A01 jiffies

                   ; else ..
   STX    LAB_A0        ; clear jiffies high byte
   STX    LAB_A1        ; clear jiffies mid byte
   STX    LAB_A2        ; clear jiffies low byte
                   ; this is wrong, there are $4F1A00 jiffies in a day so
                   ; the reset to zero should occur when the value reaches
                   ; $4F1A00 and not $4F1A01. this would give an extra jiffy
                   ; every day and a possible TI value of 24:00:00
LAB_F755
   LDA    LAB_912F        ; get VIA 2 DRA, keyboard row, no handshake
   CMP    LAB_912F        ; compare with self
   BNE    LAB_F755        ; loop if changing

   STA    LAB_91        ; save VIA 2 DRA, keyboard row
   RTS


;***********************************************************************************;
;
; read the real time clock

; this routine returns the time, in jiffies, in AXY. The accumulator contains the
; most significant byte.

LAB_F760
   SEI                ; disable interrupts
   LDA    LAB_A2        ; get jiffy clock low byte
   LDX    LAB_A1        ; get jiffy clock mid byte
   LDY    LAB_A0        ; get jiffy clock high byte


;***********************************************************************************;
;
; set the real time clock

; the system clock is maintained by an interrupt routine that updates the clock
; every 1/60th of a second. The clock is three bytes long which gives the capability
; to count from zero up to 5,184,000 jiffies - 24 hours plus one jiffy. At that point
; the clock resets to zero. Before calling this routine to set the clock the new time,
; in jiffies, should be in YXA, the accumulator containing the most significant byte.

LAB_F767
   SEI                ; disable interrupts
   STA    LAB_A2        ; save jiffy clock low byte
   STX    LAB_A1        ; save jiffy clock mid byte
   STY    LAB_A0        ; save jiffy clock high byte
   CLI                ; enable interrupts
   RTS


;***********************************************************************************;
;
; scan stop key, return Zb = 1 = [STOP]

; if the STOP key on the keyboard is pressed when this routine is called the Z flag
; will be set. All other flags remain unchanged. If the STOP key is not pressed then
; the accumulator will contain a byte representing the last row of the keyboard scan.

; The user can also check for certain other keys this way.

LAB_F770
   LDA    LAB_91        ; get keyboard row
   CMP    #$FE            ; compare with r0 down
   BNE    LAB_F77D        ; branch if not just r0

   PHP                ; save status
   JSR    LAB_FFCC        ; close input and output channels
   STA    LAB_C6        ; save keyboard buffer length
   PLP                ; restore status
LAB_F77D
   RTS


;***********************************************************************************;
;
; file error messages

LAB_F77E
   LDA    #$01            ; too many files
   .byte    $2C            ; makes next line BIT LAB_02A9
LAB_F781
   LDA    #$02            ; file already open
   .byte    $2C            ; makes next line BIT LAB_03A9
LAB_F784
   LDA    #$03            ; file not open
   .byte    $2C            ; makes next line BIT LAB_04A9
LAB_F787
   LDA    #$04            ; file not found
   .byte    $2C            ; makes next line BIT LAB_05A9
LAB_F78A
   LDA    #$05            ; device not present
   .byte    $2C            ; makes next line BIT LAB_06A9
LAB_F78D
   LDA    #$06            ; not input file
   .byte    $2C            ; makes next line BIT LAB_07A9
LAB_F790
   LDA    #$07            ; not output file
   .byte    $2C            ; makes next line BIT LAB_08A9
LAB_F793
   LDA    #$08            ; missing file name
   .byte    $2C            ; makes next line BIT LAB_09A9
LAB_F796
   LDA    #$09            ; illegal device number

   PHA                ; save error #
   JSR    LAB_FFCC        ; close input and output channels
   LDY    #LAB_F174-LAB_F174
                   ; index to "I/O ERROR #"
   BIT    LAB_9D        ; test message mode flag
   BVC    LAB_F7AC        ; exit if kernal messages off

   JSR    LAB_F1E6        ; display kernel I/O message
   PLA                ; restore error #
   PHA                ; copy error #
   ORA    #'0'            ; convert to ASCII
   JSR    LAB_FFD2        ; output character to channel
LAB_F7AC
   PLA                ; pull error number
   SEC                ; flag error
   RTS


;***********************************************************************************;
;
; find tape header, exit with header in buffer

LAB_F7AF
   LDA    LAB_93        ; get load/verify flag
   PHA                ; save load/verify flag
   JSR    LAB_F8C0        ; initiate tape read
   PLA                ; restore load/verify flag
   STA    LAB_93        ; save load/verify flag
   BCS    LAB_F7E6        ; exit if error

   LDY    #$00            ; clear index
   LDA    (LAB_B2),Y        ; read first byte from tape buffer
   CMP    #$05            ; compare with logical end of the tape
   BEQ    LAB_F7E6        ; exit if end of the tape

   CMP    #$01            ; compare with header for a relocatable program file
   BEQ    LAB_F7CE        ; branch if program file header

   CMP    #$03            ; compare with header for a non relocatable program file
   BEQ    LAB_F7CE        ; branch if program file header

   CMP    #$04            ; compare with data file header
   BNE    LAB_F7AF        ; if data file loop to find tape header

                   ; was program file header
LAB_F7CE
   TAX                ; copy header type
   BIT    LAB_9D        ; get message mode flag
   BPL    LAB_F7E4        ; exit if control messages off

   LDY    #LAB_F1D7-LAB_F174
                   ; index to "FOUND "
   JSR    LAB_F1E6        ; display kernel I/O message
   LDY    #$05            ; index to tape filename
LAB_F7DA
   LDA    (LAB_B2),Y        ; get byte from tape buffer
   JSR    LAB_FFD2        ; output character to channel
   INY                ; increment index
   CPY    #$15            ; compare with end+1
   BNE    LAB_F7DA        ; loop if more to do

LAB_F7E4
   CLC                ; flag no error
   DEY                ; decrement index
LAB_F7E6
   RTS


;***********************************************************************************;
;
; write tape header

LAB_F7E7
   STA    LAB_9E        ; save header type
   JSR    LAB_F84D        ; get tape buffer start pointer in XY
   BCC    LAB_F84C        ; exit if < $0200

   LDA    LAB_C2        ; get I/O start address high byte
   PHA                ; save it
   LDA    LAB_C1        ; get I/O start address low byte
   PHA                ; save it
   LDA    LAB_AF        ; get tape end address high byte
   PHA                ; save it
   LDA    LAB_AE        ; get tape end address low byte
   PHA                ; save it

   LDY    #$BF            ; index to header end
   LDA    #' '            ; clear byte, [SPACE]
LAB_F7FE
   STA    (LAB_B2),Y        ; clear header byte
   DEY                ; decrement index
   BNE    LAB_F7FE        ; loop if more to do

   LDA    LAB_9E        ; get header type back
   STA    (LAB_B2),Y        ; write to header
   INY                ; increment index
   LDA    LAB_C1        ; get I/O start address low byte
   STA    (LAB_B2),Y        ; write to header
   INY                ; increment index
   LDA    LAB_C2        ; get I/O start address high byte
   STA    (LAB_B2),Y        ; write to header
   INY                ; increment index
   LDA    LAB_AE        ; get tape end address low byte
   STA    (LAB_B2),Y        ; write to header
   INY                ; increment index
   LDA    LAB_AF        ; get tape end address high byte
   STA    (LAB_B2),Y        ; write to header
   INY                ; increment index
   STY    LAB_9F        ; save index
   LDY    #$00            ; clear Y
   STY    LAB_9E        ; clear name index
LAB_F822
   LDY    LAB_9E        ; get name index
   CPY    LAB_B7        ; compare with file name length
   BEQ    LAB_F834        ; exit loop if all done

   LDA    (LAB_BB),Y        ; get file name byte
   LDY    LAB_9F        ; get buffer index
   STA    (LAB_B2),Y        ; save file name byte to buffer
   INC    LAB_9E        ; increment file name index
   INC    LAB_9F        ; increment tape buffer index
   BNE    LAB_F822        ; loop, branch always

LAB_F834
   JSR    LAB_F854        ; set tape buffer start and end pointers
   LDA    #$69            ; set write lead cycle count
   STA    LAB_AB        ; save write lead cycle count
   JSR    LAB_F8EA        ; do tape write, no cycle count set
   TAY                ;.
   PLA                ; pull tape end address low byte
   STA    LAB_AE        ; restore it
   PLA                ; pull tape end address high byte
   STA    LAB_AF        ; restore it
   PLA                ; pull I/O start addresses low byte
   STA    LAB_C1        ; restore it
   PLA                ; pull I/O start addresses high byte
   STA    LAB_C2        ; restore it
   TYA                ;.
LAB_F84C
   RTS


;***********************************************************************************;
;
; get tape buffer start pointer

LAB_F84D
   LDX    LAB_B2        ; get tape buffer start pointer low byte
   LDY    LAB_B3        ; get tape buffer start pointer high byte
   CPY    #$02            ; compare high byte with $02xx
   RTS


;***********************************************************************************;
;
; set tape buffer start and end pointers

LAB_F854
   JSR    LAB_F84D        ; get tape buffer start pointer in XY
   TXA                ; copy tape buffer start pointer low byte
   STA    LAB_C1        ; save as I/O address pointer low byte
   CLC                ; clear carry for add
   ADC    #$C0            ; add buffer length low byte
   STA    LAB_AE        ; save tape buffer end pointer low byte
   TYA                ; copy tape buffer start pointer high byte
   STA    LAB_C2        ; save as I/O address pointer high byte
   ADC    #$00            ; add buffer length high byte
   STA    LAB_AF        ; save tape buffer end pointer high byte
   RTS


;***********************************************************************************;
;
; find specific tape header

LAB_F867
   JSR    LAB_F7AF        ; find tape header, exit with header in buffer
   BCS    LAB_F889        ; just exit if error

   LDY    #$05            ; index to name
   STY    LAB_9F        ; save as tape buffer index
   LDY    #$00            ; clear Y
   STY    LAB_9E        ; save as name buffer index
LAB_F874
   CPY    LAB_B7        ; compare with file name length
   BEQ    LAB_F888        ; ok exit if match

   LDA    (LAB_BB),Y        ; get file name byte
   LDY    LAB_9F        ; get index to tape buffer
   CMP    (LAB_B2),Y        ; compare with tape header name byte
   BNE    LAB_F867        ; if no match go get next header

   INC    LAB_9E        ; else increment name buffer index
   INC    LAB_9F        ; increment tape buffer index
   LDY    LAB_9E        ; get name buffer index
   BNE    LAB_F874        ; loop, branch always

LAB_F888
   CLC                ; flag ok
LAB_F889
   RTS


;***********************************************************************************;
;
; bump tape pointer

LAB_F88A
   JSR    LAB_F84D        ; get tape buffer start pointer in XY
   INC    LAB_A6        ; increment tape buffer index
   LDY    LAB_A6        ; get tape buffer index
   CPY    #$C0            ; compare with buffer length
   RTS


;***********************************************************************************;
;
; wait for PLAY

LAB_F894
   JSR    LAB_F8AB        ; return cassette sense in Zb
   BEQ    LAB_F8B5        ; exit if switch closed

                   ; cassette switch was open
   LDY    #LAB_F18F-LAB_F174
                   ; index to "PRESS PLAY ON TAPE"
LAB_F89B
   JSR    LAB_F1E6        ; display kernel I/O message
LAB_F89E
   JSR    LAB_F94B        ; scan stop key and flag abort if pressed
                   ; note if STOP was pressed the return is to the
                   ; routine that called this one and not here
   JSR    LAB_F8AB        ; return cassette sense in Zb
   BNE    LAB_F89E        ; loop if cassette switch open

   LDY    #LAB_F1DE-LAB_F174
                   ; index to "OK"
   JMP    LAB_F1E6        ; display kernel I/O message and return


;***********************************************************************************;
;
; return cassette sense in Zb

LAB_F8AB
   LDA    #$40            ; mask for cassette switch
   BIT    LAB_911F        ; test VIA 1 DRA, no handshake
   BNE    LAB_F8B5        ; branch if cassette sense high

   BIT    LAB_911F        ; test VIA 1 DRA again
LAB_F8B5
   CLC
   RTS


;***********************************************************************************;
;
; wait for PLAY/RECORD

LAB_F8B7
   JSR    LAB_F8AB        ; return cassette sense in Zb
   BEQ    LAB_F8B5        ; exit if switch closed

                   ; cassette switch was open
   LDY    #LAB_F1A2-LAB_F174
                   ; index to "PRESS RECORD & PLAY ON TAPE"
   BNE    LAB_F89B        ; display message and wait for switch, branch always


;***********************************************************************************;
;
; initiate tape read

LAB_F8C0
   LDA    #$00            ; clear A
   STA    LAB_90        ; clear serial status byte
   STA    LAB_93        ; clear the load/verify flag
   JSR    LAB_F854        ; set tape buffer start and end pointers
LAB_F8C9
   JSR    LAB_F894        ; wait for PLAY
   BCS    LAB_F8ED        ; exit if STOP was pressed, uses further BCS at target
                   ; address to reach final target at LAB_F957

   SEI                ; disable interrupts
   LDA    #$00            ; clear A
   STA    LAB_AA        ;.
   STA    LAB_B4        ;.
   STA    LAB_B0        ; clear tape timing constant min byte
   STA    LAB_9E        ; clear tape pass 1 error log/char buffer
   STA    LAB_9F        ; clear tape pass 2 error log corrected
   STA    LAB_9C        ; clear byte received flag
   LDA    #$82            ; enable CA1 interrupt
   LDX    #$0E            ; set index for tape read vector
   BNE    LAB_F8F4        ; go do tape read/write, branch always


;***********************************************************************************;
;
; initiate tape write

LAB_F8E3
   JSR    LAB_F854        ; set tape buffer start and end pointers

; do tape write, 20 cycle count

LAB_F8E6
   LDA    #$14            ; set write lead cycle count
   STA    LAB_AB        ; save write lead cycle count

; do tape write, no cycle count set

LAB_F8EA
   JSR    LAB_F8B7        ; wait for PLAY/RECORD
LAB_F8ED
   BCS    LAB_F957        ; if STOPped clear save IRQ address and exit

   SEI                ; disable interrupts
   LDA    #$A0            ; enable VIA 2 T2 interrupt
   LDX    #$08            ; set index for tape write tape leader vector


;***********************************************************************************;
;
; tape read/write

LAB_F8F4
   LDY    #$7F            ; disable all interrupts
   STY    LAB_912E        ; set VIA 2 IER, disable interrupts
   STA    LAB_912E        ; set VIA 2 IER, enable interrupts according to A
   JSR    LAB_F160        ; check RS232 bus idle
   LDA    LAB_0314        ; get IRQ vector low byte
   STA    LAB_029F        ; save IRQ vector low byte
   LDA    LAB_0315        ; get IRQ vector high byte
   STA    LAB_02A0        ; save IRQ vector high byte
   JSR    LAB_FCFB        ; set tape vector
   LDA    #$02            ; set copies count. the first copy is the load copy, the
                   ; second copy is the verify copy
   STA    LAB_BE        ; save copies count
   JSR    LAB_FBDB        ; new tape byte setup
   LDA    LAB_911C        ; get VIA 1 PCR
   AND    #$FD            ; CA2 low, turn on tape motor
   ORA    #$0C            ; manual output mode
   STA    LAB_911C        ; set VIA 1 PCR
   STA    LAB_C0        ; set tape motor interlock

                   ; 326656 cycle delay, allow tape motor speed to stabilise
   LDX    #$FF            ; outer loop count
LAB_F923
   LDY    #$FF            ; inner loop count
LAB_F925
   DEY                ; decrement inner loop count
   BNE    LAB_F925        ; loop if more to do

   DEX                ; decrement outer loop count
   BNE    LAB_F923        ; loop if more to do

   STA    LAB_9129        ; set VIA 2 T2C_h
   CLI                ; enable tape interrupts
LAB_F92F
   LDA    LAB_02A0        ; get saved IRQ high byte
   CMP    LAB_0315        ; compare with the current IRQ high byte
   CLC                ; flag ok
   BEQ    LAB_F957        ; if tape write done go clear saved IRQ address and exit

   JSR    LAB_F94B        ; scan stop key and flag abort if pressed
                   ; note if STOP was pressed the return is to the
                   ; routine that called this one and not here
   LDA    LAB_912D        ; get VIA 2 IFR
   AND    #$40            ; mask T1 interrupt
   BEQ    LAB_F92F        ; loop if not T1 interrupt

                   ; else increment jiffy clock
   LDA    LAB_9114        ; get VIA 1 T1C_l, clear T1 flag
   JSR    LAB_F734        ; increment the real time clock
   JMP    LAB_F92F        ; loop


;***********************************************************************************;
;
; scan stop key and flag abort if pressed

LAB_F94B
   JSR    LAB_FFE1        ; scan stop key
   CLC                ; flag no stop
   BNE    LAB_F95C        ; exit if no stop

   JSR    LAB_FCCF        ; restore everything for STOP
   SEC                ; flag stopped
   PLA                ; dump return address low byte
   PLA                ; dump return address high byte


;***********************************************************************************;
;
; clear saved IRQ address

LAB_F957
   LDA    #$00            ; clear A
   STA    LAB_02A0        ; clear saved IRQ address high byte
LAB_F95C
   RTS


;***********************************************************************************;
;
;## set timing

LAB_F95D
   STX    LAB_B1        ; save tape timing constant max byte
   LDA    LAB_B0        ; get tape timing constant min byte
   ASL                ; *2
   ASL                ; *4
   CLC                ; clear carry for add
   ADC    LAB_B0        ; add tape timing constant min byte *5
   CLC                ; clear carry for add
   ADC    LAB_B1        ; add tape timing constant max byte
   STA    LAB_B1        ; save tape timing constant max byte
   LDA    #$00            ;.
   BIT    LAB_B0        ; test tape timing constant min byte
   BMI    LAB_F972        ; branch if b7 set

   ROL                ; else shift carry into ??
LAB_F972
   ASL    LAB_B1        ; shift tape timing constant max byte
   ROL                ;.
   ASL    LAB_B1        ; shift tape timing constant max byte
   ROL                ;.
   TAX                ;.
LAB_F979
   LDA    LAB_9128        ; get VIA 2 T2C_l
   CMP    #$15            ;.compare with ??
   BCC    LAB_F979        ; loop if less

   ADC    LAB_B1        ; add tape timing constant max byte
   STA    LAB_9124        ; set VIA 2 T1C_l
   TXA                ;.
   ADC    LAB_9129        ; add VIA 2 T2C_h
   STA    LAB_9125        ; set VIA 2 T1C_h
   CLI                ; enable interrupts
   RTS


;***********************************************************************************;
;
;;    On Commodore computers, the streams consist of four kinds of symbols
;;    that denote different kinds of low-to-high-to-low transitions on the
;;    read or write signals of the Commodore cassette interface.
;;
;;    A    A break in the communications, or a pulse with very long cycle
;;        time.
;;
;;    B    A short pulse, whose cycle time typically ranges from 296 to 424
;;        microseconds, depending on the computer model.
;;
;;    C    A medium-length pulse, whose cycle time typically ranges from
;;        440 to 576 microseconds, depending on the computer model.
;;
;;    D    A long pulse, whose cycle time typically ranges from 600 to 744
;;        microseconds, depending on the computer model.
;;
;; The actual interpretation of the serial data takes a little more work to
;; explain. The typical ROM tape loader (and the turbo loaders) will
;; initialize a timer with a specified value and start it counting down. If
;; either the tape data changes or the timer runs out, an IRQ will occur. The
;; loader will determine which condition caused the IRQ. If the tape data
;; changed before the timer ran out, we have a short pulse, or a "0" bit. If
;; the timer ran out first, we have a long pulse, or a "1" bit. Doing this
;; continuously and we decode the entire file.

; read tape bits, IRQ routine

; read T2C which has been counting down from $FFFF. subtract this from $FFFF

LAB_F98E
   LDX    LAB_9129        ; get VIA 2 T2C_h
   LDY    #$FF            ;.set $FF
   TYA                ;.A = $FF
   SBC    LAB_9128        ; subtract VIA 2 T2C_l
   CPX    LAB_9129        ; compare VIA 2 T2C_h with previous
   BNE    LAB_F98E        ; loop if timer low byte rolled over

   STX    LAB_B1        ; save tape timing constant max byte
   TAX                ;.copy $FF - T2C_l
   STY    LAB_9128        ; set VIA 2 T2C_l to $FF
   STY    LAB_9129        ; set VIA 2 T2C_h to $FF
   TYA                ;.$FF
   SBC    LAB_B1        ; subtract tape timing constant max byte
                   ; A = $FF - T2C_h
   STX    LAB_B1        ; save tape timing constant max byte
                   ; LAB_B1 = $FF - T2C_l
   LSR                ;.A = $FF - T2C_h >> 1
   ROR    LAB_B1        ; shift tape timing constant max byte
                   ; LAB_B1 = $FF - T2C_l >> 1
   LSR                ;.A = $FF - T2C_h >> 1
   ROR    LAB_B1        ; shift tape timing constant max byte
                   ; LAB_B1 = $FF - T2C_l >> 1
   LDA    LAB_B0        ; get tape timing constant min byte
   CLC                ; clear carry for add
   ADC    #$3C            ;.
   BIT    LAB_9121        ; test VIA 2 DRA, keyboard row
   CMP    LAB_B1        ; compare with tape timing constant max byte
                   ; compare with ($FFFF - T2C) >> 2
   BCS    LAB_FA06        ;.branch if min + $3C >= ($FFFF - T2C) >> 2

                   ;.min + $3C < ($FFFF - T2C) >> 2
   LDX    LAB_9C        ;.get byte received flag
   BEQ    LAB_F9C3        ;.branch if not byte received

   JMP    LAB_FAAD        ;.store tape character

LAB_F9C3
   LDX    LAB_A3        ;.get EOI flag byte
   BMI    LAB_F9E2        ;.

   LDX    #$00            ;.
   ADC    #$30            ;.
   ADC    LAB_B0        ; add tape timing constant min byte
   CMP    LAB_B1        ; compare with tape timing constant max byte
   BCS    LAB_F9ED        ;.

   INX                ;.
   ADC    #$26            ;.
   ADC    LAB_B0        ; add tape timing constant min byte
   CMP    LAB_B1        ; compare with tape timing constant max byte
   BCS    LAB_F9F1        ;.

   ADC    #$2C            ;.
   ADC    LAB_B0        ; add tape timing constant min byte
   CMP    LAB_B1        ; compare with tape timing constant max byte
   BCC    LAB_F9E5        ;.

LAB_F9E2
   JMP    LAB_FA60        ;.

LAB_F9E5
   LDA    LAB_B4        ; get bit count
   BEQ    LAB_FA06        ; branch if zero

   STA    LAB_A8        ; save receiver bit count in
   BNE    LAB_FA06        ; branch always

LAB_F9ED
   INC    LAB_A9        ; increment ?? start bit check flag
   BCS    LAB_F9F3        ;.

LAB_F9F1
   DEC    LAB_A9        ; decrement ?? start bit check flag
LAB_F9F3
   SEC                ;.
   SBC    #$13            ;.
   SBC    LAB_B1        ; subtract tape timing constant max byte
   ADC    LAB_92        ; add timing constant for tape
   STA    LAB_92        ; save timing constant for tape
   LDA    LAB_A4        ;.get tape bit cycle phase
   EOR    #$01            ;.
   STA    LAB_A4        ;.save tape bit cycle phase
   BEQ    LAB_FA25        ;.

   STX    LAB_D7        ;.
LAB_FA06
   LDA    LAB_B4        ; get bit count
   BEQ    LAB_FA22        ; exit if zero

   BIT    LAB_912D        ; test get 2 IFR
   BVC    LAB_FA22        ; exit if no T1 interrupt

   LDA    #$00            ;.
   STA    LAB_A4        ; clear tape bit cycle phase
   LDA    LAB_A3        ;.get EOI flag byte
   BPL    LAB_FA47        ;.

   BMI    LAB_F9E2        ;.

LAB_FA19
   LDX    #$A6            ; set timimg max byte
   JSR    LAB_F95D        ; set timing
   LDA    LAB_9B        ;.
   BNE    LAB_F9E5        ;.
LAB_FA22
   JMP    LAB_FF56        ; restore registers and exit interrupt

LAB_FA25
   LDA    LAB_92        ; get timing constant for tape
   BEQ    LAB_FA30        ;.

   BMI    LAB_FA2E        ;.

   DEC    LAB_B0        ; decrement tape timing constant min byte
   .byte    $2C            ; makes next line BIT LAB_B0E6
LAB_FA2E
   INC    LAB_B0        ; increment tape timing constant min byte
LAB_FA30
   LDA    #$00            ;.
   STA    LAB_92        ; clear timing constant for tape
   CPX    LAB_D7        ;.
   BNE    LAB_FA47        ;.

   TXA                ;.
   BNE    LAB_F9E5        ;.

   LDA    LAB_A9        ; get start bit check flag
   BMI    LAB_FA06        ;.

   CMP    #$10            ;.
   BCC    LAB_FA06        ;.

   STA    LAB_96        ;.save cassette block synchronization number
   BCS    LAB_FA06        ;.

LAB_FA47
   TXA
   EOR    LAB_9B        ;.
   STA    LAB_9B        ;.
   LDA    LAB_B4        ;.
   BEQ    LAB_FA22        ;.

   DEC    LAB_A3        ;.decrement EOI flag byte
   BMI    LAB_FA19        ;.

   LSR    LAB_D7        ;.
   ROR    LAB_BF        ;.parity count
   LDX    #$DA            ; set timimg max byte
   JSR    LAB_F95D        ; set timing
   JMP    LAB_FF56        ; restore registers and exit interrupt

LAB_FA60
   LDA    LAB_96        ;.get cassette block synchronization number
   BEQ    LAB_FA68        ;.

   LDA    LAB_B4        ;.
   BEQ    LAB_FA6C        ;.

LAB_FA68
   LDA    LAB_A3        ;.get EOI flag byte
   BPL    LAB_F9F1        ;.

LAB_FA6C
   LSR    LAB_B1        ; shift tape timing constant max byte
   LDA    #$93            ;.
   SEC                ;.
   SBC    LAB_B1        ; subtract tape timing constant max byte
   ADC    LAB_B0        ; add tape timing constant min byte
   ASL                ;.
   TAX                ; copy timimg high byte
   JSR    LAB_F95D        ; set timing
   INC    LAB_9C        ;.
   LDA    LAB_B4        ;.
   BNE    LAB_FA91        ;.

   LDA    LAB_96        ;.get cassette block synchronization number
   BEQ    LAB_FAAA        ;.

   STA    LAB_A8        ; save receiver bit count in
   LDA    #$00            ;.
   STA    LAB_96        ;.clear cassette block synchronization number
   LDA    #$C0            ; enable T1 interrupt
   STA    LAB_912E        ; set VIA 2 IER
   STA    LAB_B4        ;.
LAB_FA91
   LDA    LAB_96        ;.get cassette block synchronization number
   STA    LAB_B5        ;.
   BEQ    LAB_FAA0        ;.

   LDA    #$00            ;.
   STA    LAB_B4        ;.
   LDA    #$40            ; disable T1 interrupt
   STA    LAB_912E        ; set VIA 2 IER
LAB_FAA0
   LDA    LAB_BF        ;.parity count
   STA    LAB_BD        ;.save RS232 parity byte
   LDA    LAB_A8        ; get receiver bit count in
   ORA    LAB_A9        ; OR with start bit check flag
   STA    LAB_B6        ;.
LAB_FAAA
   JMP    LAB_FF56        ; restore registers and exit interrupt


;***********************************************************************************;
;
;## store character

LAB_FAAD
   JSR    LAB_FBDB        ; new tape byte setup
   STA    LAB_9C        ; clear byte received flag
   LDX    #$DA            ; set timimg max byte
   JSR    LAB_F95D        ; set timing
   LDA    LAB_BE        ;.get copies count
   BEQ    LAB_FABD        ;.

   STA    LAB_A7        ; save receiver input bit temporary storage
LAB_FABD
   LDA    #$0F            ;.
   BIT    LAB_AA        ;.
   BPL    LAB_FADA        ;.

   LDA    LAB_B5        ;.
   BNE    LAB_FAD3        ;.

   LDX    LAB_BE        ;.get copies count
   DEX                ;.
   BNE    LAB_FAD7        ; if ?? restore registers and exit interrupt

   LDA    #$08            ; set short block
   JSR    LAB_FE6A        ; OR into serial status byte
   BNE    LAB_FAD7        ; restore registers and exit interrupt, branch always

LAB_FAD3
   LDA    #$00            ;.
   STA    LAB_AA        ;.
LAB_FAD7
   JMP    LAB_FF56        ; restore registers and exit interrupt

LAB_FADA
   BVS    LAB_FB0D        ;.

   BNE    LAB_FAF6        ;.

   LDA    LAB_B5        ;.
   BNE    LAB_FAD7        ;.

   LDA    LAB_B6        ;.
   BNE    LAB_FAD7        ;.

   LDA    LAB_A7        ; get receiver input bit temporary storage
   LSR                ;.
   LDA    LAB_BD        ;.get RS232 parity byte
   BMI    LAB_FAF0        ;.

   BCC    LAB_FB07        ;.

   CLC                ;.
LAB_FAF0
   BCS    LAB_FB07        ;.

   AND    #$0F            ;.
   STA    LAB_AA        ;.
LAB_FAF6
   DEC    LAB_AA        ;.
   BNE    LAB_FAD7        ;.

   LDA    #$40            ;.
   STA    LAB_AA        ;.
   JSR    LAB_FBD2        ; copy I/O start address to buffer address
   LDA    #$00            ;.
   STA    LAB_AB        ;.
   BEQ    LAB_FAD7        ;., branch always


;***********************************************************************************;
;
;## reset pointer

LAB_FB07
   LDA    #$80            ;.
   STA    LAB_AA        ;.
   BNE    LAB_FAD7        ; restore registers and exit interrupt, branch always

LAB_FB0D
   LDA    LAB_B5        ;.
   BEQ    LAB_FB1B        ;.

   LDA    #$04            ;.
   JSR    LAB_FE6A        ; OR into serial status byte
   LDA    #$00            ;.
   JMP    LAB_FB97        ;.

LAB_FB1B
   JSR    LAB_FD11        ; check read/write pointer, return Cb = 1 if pointer >= end
   BCC    LAB_FB23        ;.

   JMP    LAB_FB95        ;.

LAB_FB23
   LDX    LAB_A7        ; get receiver input bit temporary storage
   DEX                ;.
   BEQ    LAB_FB55        ;.

   LDA    LAB_93        ; get load/verify flag
   BEQ    LAB_FB38        ; branch if load

   LDY    #$00            ; clear index
   LDA    LAB_BD        ;.get RS232 parity byte
   CMP    (LAB_AC),Y        ;.
   BEQ    LAB_FB38        ;.

   LDA    #$01            ;.
   STA    LAB_B6        ;.
LAB_FB38
   LDA    LAB_B6        ;.
   BEQ    LAB_FB87        ;.

   LDX    #$3D            ;.
   CPX    LAB_9E        ;.
   BCC    LAB_FB80        ;.

   LDX    LAB_9E        ;.
   LDA    LAB_AD        ;.
   STA    LAB_0100+1,X    ;.
   LDA    LAB_AC        ;.
   STA    LAB_0100,X        ;.
   INX                ;.
   INX                ;.
   STX    LAB_9E        ;.
   JMP    LAB_FB87        ;.

LAB_FB55
   LDX    LAB_9F        ;.
   CPX    LAB_9E        ;.
   BEQ    LAB_FB90        ;.

   LDA    LAB_AC        ;.
   CMP    LAB_0100,X        ;.
   BNE    LAB_FB90        ;.

   LDA    LAB_AD        ;.
   CMP    LAB_0100+1,X    ;.
   BNE    LAB_FB90        ;.

   INC    LAB_9F        ;.
   INC    LAB_9F        ;.
   LDA    LAB_93        ; get load/verify flag
   BEQ    LAB_FB7C        ; branch if load

   LDA    LAB_BD        ;.get RS232 parity byte
   LDY    #$00            ;.
   CMP    (LAB_AC),Y        ;.
   BEQ    LAB_FB90        ;.

   INY                ;.
   STY    LAB_B6        ;.
LAB_FB7C
   LDA    LAB_B6        ;.
   BEQ    LAB_FB87        ;.

LAB_FB80
   LDA    #$10            ;.
   JSR    LAB_FE6A        ; OR into serial status byte
   BNE    LAB_FB90        ;.

LAB_FB87
   LDA    LAB_93        ; get load/verify flag
   BNE    LAB_FB90        ; branch if verify

   TAY                ;.
   LDA    LAB_BD        ;.get RS232 parity byte
   STA    (LAB_AC),Y        ;.
LAB_FB90
   JSR    LAB_FD1B        ; increment read/write pointer
   BNE    LAB_FBCF        ; restore registers and exit interrupt, branch always

LAB_FB95
   LDA    #$80            ;.
LAB_FB97
   STA    LAB_AA        ;.
   LDX    LAB_BE        ;.get copies count
   DEX                ;.
   BMI    LAB_FBA0        ;.

   STX    LAB_BE        ;.save copies count
LAB_FBA0
   DEC    LAB_A7        ; decrement receiver input bit temporary storage
   BEQ    LAB_FBAC        ;.

   LDA    LAB_9E        ;.
   BNE    LAB_FBCF        ; if ?? restore registers and exit interrupt

   STA    LAB_BE        ;.save copies count
   BEQ    LAB_FBCF        ; restore registers and exit interrupt, branch always

LAB_FBAC
   JSR    LAB_FCCF        ; restore everything for STOP
   JSR    LAB_FBD2        ; copy I/O start address to buffer address
   LDY    #$00            ; clear index
   STY    LAB_AB        ; clear checksum
LAB_FBB6
   LDA    (LAB_AC),Y        ; get byte from buffer
   EOR    LAB_AB        ; XOR with checksum
   STA    LAB_AB        ; save new checksum
   JSR    LAB_FD1B        ; increment read/write pointer
   JSR    LAB_FD11        ; check read/write pointer, return Cb = 1 if pointer >= end
   BCC    LAB_FBB6        ; loop if not at end

   LDA    LAB_AB        ; get computed checksum
   EOR    LAB_BD        ; compare with stored checksum ??
   BEQ    LAB_FBCF        ; if checksum ok restore registers and exit interrupt

   LDA    #$20            ; else set checksum error
   JSR    LAB_FE6A        ; OR into serial status byte
LAB_FBCF
   JMP    LAB_FF56        ; restore registers and exit interrupt


;***********************************************************************************;
;
; copy I/O start address to buffer address

LAB_FBD2
   LDA    LAB_C2        ; get I/O start address high byte
   STA    LAB_AD        ; set buffer address high byte
   LDA    LAB_C1        ; get I/O start address low byte
   STA    LAB_AC        ; set buffer address low byte
   RTS


;***********************************************************************************;
;
; new tape byte setup

LAB_FBDB
   LDA    #$08            ; eight bits to do
   STA    LAB_A3        ; set bit count
   LDA    #$00            ; clear A
   STA    LAB_A4        ; clear tape bit cycle phase
   STA    LAB_A8        ; clear start bit first cycle done flag
   STA    LAB_9B        ; clear byte parity
   STA    LAB_A9        ; clear start bit check flag, set no start bit yet
   RTS


;***********************************************************************************;
;
; send lsb from tape write byte to tape

; this routine tests the least significant bit in the tape write byte and sets VIA 2 T2
; depending on the state of the bit. if the bit is a 1 a time of $00B0 cycles is set, if
; the bot is a 0 a time of $0060 cycles is set. note that this routine does not shift the
; bits of the tape write byte but uses a copy of that byte, the byte itself is shifted
; elsewhere

LAB_FBEA
   LDA    LAB_BD        ; get tape write byte
   LSR                ; shift lsb into Cb
   LDA    #$60            ; set time constant low byte for bit = 0
   BCC    LAB_FBF3        ; branch if bit was 0

; set time constant for bit = 1 and toggle tape

LAB_FBF1
   LDA    #$B0            ; set time constant low byte for bit = 1

; write time constant and toggle tape

LAB_FBF3
   LDX    #$00            ; set time constant high byte

; write time constant and toggle tape

LAB_FBF5
   STA    LAB_9128        ; set VIA 2 T2C_l
   STX    LAB_9129        ; set VIA 2 T2C_h
   LDA    LAB_9120        ; get VIA 2 DRB, keyboard column
   EOR    #$08            ; toggle tape out bit
   STA    LAB_9120        ; set VIA 2 DRB
   AND    #$08            ; mask tape out bit
   RTS


;***********************************************************************************;
;
; flag block done and exit interrupt

LAB_FC06
   SEC                ; set carry flag
   ROR    LAB_AD        ; set buffer address high byte negative, flag all sync,
                   ; data and checksum bytes written
   BMI    LAB_FC47        ; restore registers and exit interrupt, branch always


;***********************************************************************************;
;
; tape write, IRQ routine.

; this is the routine that writes the bits to the tape. it is called each time VIA 2 T2
; times out and checks if the start bit is done, if so checks if the data bits are done,
; if so it checks if the byte is done, if so it checks if the synchronisation bytes are
; done, if so it checks if the data bytes are done, if so it checks if the checksum byte
; is done, if so it checks if both the load and verify copies have been done, if so it
; stops the tape

LAB_FC0B
   LDA    LAB_A8        ; get start bit first cycle done flag
   BNE    LAB_FC21        ; if first cycle done go do rest of byte

; each byte sent starts with two half cycles of $0110 ststem clocks and the whole block
; ends with two more such half cycles

   LDA    #$10            ; set first start cycle time constant low byte
   LDX    #$01            ; set first start cycle time constant high byte
   JSR    LAB_FBF5        ; write time constant and toggle tape
   BNE    LAB_FC47        ; if first half cycle go restore registers and exit
                   ; interrupt

   INC    LAB_A8        ; set start bit first start cycle done flag
   LDA    LAB_AD        ; get buffer address high byte
   BPL    LAB_FC47        ; if block not complete go restore registers and exit
                   ; interrupt. the end of a block is indicated by the tape
                   ; buffer high byte b7 being set to 1

   JMP    LAB_FC95        ; else do tape routine, block complete exit

; continue tape byte write. the first start cycle, both half cycles of it, is complete
; so the routine drops straight through to here

LAB_FC21
   LDA    LAB_A9        ; get start bit check flag
   BNE    LAB_FC2E        ; if the start bit is complete go send the byte bits

; after the two half cycles of $0110 ststem clocks the start bit is completed with two
; half cycles of $00B0 system clocks. this is the same as the first part of a 1 bit

   JSR    LAB_FBF1        ; set time constant for bit = 1 and toggle tape
   BNE    LAB_FC47        ; if first half cycle go restore registers and exit
                   ; interrupt

   INC    LAB_A9        ; set start bit check flag
   BNE    LAB_FC47        ; restore registers and exit interrupt, branch always

; continue tape byte write. the start bit, both cycles of it, is complete so the routine
; drops straight through to here. now the cycle pairs for each bit, and the parity bit,
; are sent

LAB_FC2E
   JSR    LAB_FBEA        ; send lsb from tape write byte to tape
   BNE    LAB_FC47        ; if first half cycle go restore registers and exit
                   ; interrupt

                   ; else two half cycles have been done
   LDA    LAB_A4        ; get tape bit cycle phase
   EOR    #$01            ; toggle b0
   STA    LAB_A4        ; save tape bit cycle phase
   BEQ    LAB_FC4A        ; if bit cycle phase complete go setup for next bit

; each bit is written as two full cycles. a 1 is sent as a full cycle of $0160 system
; clocks then a full cycle of $00C0 system clocks. a 0 is sent as a full cycle of $00C0
; system clocks then a full cycle of $0160 system clocks. to do this each bit from the
; write byte is inverted during the second bit cycle phase. as the bit is inverted it
; is also added to the, one bit, parity count for this byte

   LDA    LAB_BD        ; get tape write byte
   EOR    #$01            ; invert bit being sent
   STA    LAB_BD        ; save tape write byte
   AND    #$01            ; mask b0
   EOR    LAB_9B        ; EOR with tape write byte parity bit
   STA    LAB_9B        ; save tape write byte parity bit
LAB_FC47
   JMP    LAB_FF56        ; restore registers and exit interrupt

; the bit cycle phase is complete so shift out the just written bit and test for byte
; end

LAB_FC4A
   LSR    LAB_BD        ; shift bit out of tape write byte
   DEC    LAB_A3        ; decrement tape write bit count
   LDA    LAB_A3        ; get tape write bit count
   BEQ    LAB_FC8C        ; if all the data bits have been written go setup for
                   ; sending the parity bit next and exit the interrupt

   BPL    LAB_FC47        ; if all the data bits are not yet sent just restore the
                   ; registers and exit the interrupt

; do next tape byte

; the byte is complete. the start bit, data bits and parity bit have been written to
; the tape so setup for the next byte

LAB_FC54
   JSR    LAB_FBDB        ; new tape byte setup
   CLI                ; enable interrupts
   LDA    LAB_A5        ; get cassette synchronization character count
   BEQ    LAB_FC6E        ; if synchronisation characters done go do block data

; at the start of each block sent to tape there are a number of synchronisation bytes
; that count down to the actual data. the commodore tape system saves two copies of all
; the tape data, the first is loaded and is indicated by the synchronisation bytes
; having b7 set, and the second copy is indicated by the synchronisation bytes having b7
; clear. the sequence goes $09, $08, ..... $02, $01, data bytes

   LDX    #$00            ; clear X
   STX    LAB_D7        ; clear checksum byte
   DEC    LAB_A5        ; decrement cassette synchronization byte count
   LDX    LAB_BE        ; get cassette copies count
   CPX    #$02            ; compare with load block indicator
   BNE    LAB_FC6A        ; branch if not the load block

   ORA    #$80            ; this is the load block so make the synchronisation count
                   ; go $89, $88, ..... $82, $81
LAB_FC6A
   STA    LAB_BD        ; save the synchronisation byte as the tape write byte
   BNE    LAB_FC47        ; restore registers and exit interrupt, branch always

; the synchronization bytes have been done so now check and do the actual block data

LAB_FC6E
   JSR    LAB_FD11        ; check read/write pointer, return Cb = 1 if pointer >= end
   BCC    LAB_FC7D        ; if not all done yet go get the byte to send

   BNE    LAB_FC06        ; if pointer > end go flag block done and exit interrupt

                   ; else the block is complete, it only remains to write the
                   ; checksum byte to the tape so setup for that
   INC    LAB_AD        ; increment buffer pointer high byte, this means the block
                   ; done branch will always be taken next time without having
                   ; to worry about the low byte wrapping to zero
   LDA    LAB_D7        ; get checksum byte
   STA    LAB_BD        ; save checksum as tape write byte
   BCS    LAB_FC47        ; restore registers and exit interrupt, branch always

; the block isn't finished so get the next byte to write to tape

LAB_FC7D
   LDY    #$00            ; clear index
   LDA    (LAB_AC),Y        ; get byte from buffer
   STA    LAB_BD        ; save as tape write byte
   EOR    LAB_D7        ; XOR with checksum byte
   STA    LAB_D7        ; save new checksum byte
   JSR    LAB_FD1B        ; increment read/write pointer
   BNE    LAB_FC47        ; restore registers and exit interrupt, branch always

; set parity as next bit and exit interrupt

LAB_FC8C
   LDA    LAB_9B        ; get parity bit
   EOR    #$01            ; toggle it
   STA    LAB_BD        ; save as tape write byte
LAB_FC92
   JMP    LAB_FF56        ; restore registers and exit interrupt

; tape routine, block complete exit

LAB_FC95
   DEC    LAB_BE        ; decrement copies remaining to read/write
   BNE    LAB_FC9C        ; branch if more to do

   JSR    LAB_FD08        ; else stop cassette motor
LAB_FC9C
   LDA    #$50            ; set tape write leader count
   STA    LAB_A7        ; save tape write leader count
   LDX    #$08            ; set index for write tape leader vector
   SEI                ; disable interrupts
   JSR    LAB_FCFB        ; set tape vector
   BNE    LAB_FC92        ; restore registers and exit interrupt, branch always


;***********************************************************************************;
;
; write tape leader IRQ routine

LAB_FCA8
   LDA    #$78            ; set time constant low byte for bit = leader
   JSR    LAB_FBF3        ; write time constant and toggle tape
   BNE    LAB_FC92        ; if tape bit high restore registers and exit interrupt

   DEC    LAB_A7        ; decrement cycle count
   BNE    LAB_FC92        ; if not all done restore registers and exit interrupt

   JSR    LAB_FBDB        ; new tape byte setup
   DEC    LAB_AB        ; decrement cassette leader count
   BPL    LAB_FC92        ; if not all done restore registers and exit interrupt

   LDX    #$0A            ; set index for tape write vector
   JSR    LAB_FCFB        ; set tape vector
   CLI                ; enable interrupts
   INC    LAB_AB        ; clear cassette leader counter, was $FF
   LDA    LAB_BE        ; get cassette block count
   BEQ    LAB_FCF6        ; if all done restore everything for STOP and exit interrupt

   JSR    LAB_FBD2        ; copy I/O start address to buffer address
   LDX    #$09            ; set nine synchronisation bytes
   STX    LAB_A5        ; save cassette synchronization byte count
   BNE    LAB_FC54        ; go do next tape byte, branch always


;***********************************************************************************;
;
; restore everything for STOP

LAB_FCCF
   PHP                ; save status
   SEI                ; disable interrupts
   JSR    LAB_FD08        ; stop cassette motor
   LDA    #$7F            ; disable all interrupts
   STA    LAB_912E        ; set VIA 2 IER
   LDA    #$F7            ; set keyboard column 3 active
   STA    LAB_9120        ; set VIA 2 DRB, keyboard column
   LDA    #$40            ; set T1 free run, T2 clock �2,
                   ; SR disabled, latches disabled
   STA    LAB_912B        ; set VIA 2 ACR
   JSR    LAB_FE39        ; set 60Hz and enable timer
   LDA    LAB_02A0        ; get saved IRQ vector high byte
   BEQ    LAB_FCF4        ; branch if null

   STA    LAB_0315        ; restore IRQ vector high byte
   LDA    LAB_029F        ; get saved IRQ vector low byte
   STA    LAB_0314        ; restore IRQ vector low byte
LAB_FCF4
   PLP                ; restore status
   RTS


;***********************************************************************************;
;
; reset vector

LAB_FCF6
   JSR    LAB_FCCF        ; restore everything for STOP
   BEQ    LAB_FC92        ; restore registers and exit interrupt, branch always


;***********************************************************************************;
;
; set tape vector

LAB_FCFB
   LDA    LAB_FDF1-8,X    ; get tape IRQ vector low byte
   STA    LAB_0314        ; set IRQ vector low byte
   LDA    LAB_FDF1-7,X    ; get tape IRQ vector high byte
   STA    LAB_0315        ; set IRQ vector high byte
   RTS


;***********************************************************************************;
;
; stop cassette motor

LAB_FD08
   LDA    LAB_911C        ; get VIA 1 PCR
   ORA    #$0E            ; set CA2 high, cassette motor off
   STA    LAB_911C        ; set VIA 1 PCR
   RTS


;***********************************************************************************;
;
; check read/write pointer
; return Cb = 1 if pointer >= end

LAB_FD11
   SEC                ; set carry for subtract
   LDA    LAB_AC        ; get buffer address low byte
   SBC    LAB_AE        ; subtract buffer end low byte
   LDA    LAB_AD        ; get buffer address high byte
   SBC    LAB_AF        ; subtract buffer end high byte
   RTS


;***********************************************************************************;
;
; increment read/write pointer

LAB_FD1B
   INC    LAB_AC        ; increment buffer address low byte
   BNE    LAB_FD21        ; if no overflow skip the high byte increment

   INC    LAB_AD        ; increment buffer address high byte
LAB_FD21
   RTS


;***********************************************************************************;
;
; RESET, hardware reset starts here

LAB_FD22
   LDX    #$FF            ; set X for stack
   SEI                ; disable interrupts
   TXS                ; clear stack
   CLD                ; clear decimal mode
   JSR    LAB_FD3F        ; scan for autostart ROM at $A000
   BNE    LAB_FD2F        ; if not there continue Vic startup

   JMP    (LAB_A000)        ; call ROM start code

LAB_FD2F
   JSR    LAB_FD8D        ; initialise and test RAM
   JSR    LAB_FD52        ; restore default I/O vectors
   JSR    LAB_FDF9        ; initialize I/O registers
   JSR    LAB_E518        ; initialise hardware
   CLI                ; enable interrupts
   JMP    (LAB_C000)        ; execute BASIC


;***********************************************************************************;
;
; scan for autostart ROM at $A000, returns Zb=1 if ROM found

LAB_FD3F
   LDX    #$05            ; five characters to test
LAB_FD41
   LDA    LAB_FD4D-1,X    ; get test character
   CMP    LAB_A004-1,X    ; compare wiith byte in ROM space
   BNE    LAB_FD4C        ; exit if no match

   DEX                ; decrement index
   BNE    LAB_FD41        ; loop if not all done

LAB_FD4C
   RTS


;***********************************************************************************;
;
; autostart ROM signature

LAB_FD4D
   .byte    "A0",$C3,$C2,$CD    ; A0CBM


;***********************************************************************************;
;
; restore default I/O vectors

; This routine restores the default values of all system vectors used in KERNAL and
; BASIC routines and interrupts. The KERNAL VECTOR routine is used to read and alter
; individual system vectors.

LAB_FD52
   LDX    #    LDY    #>LAB_FD6D        ; pointer to vector table high byte
   CLC                ; flag set vectors


;***********************************************************************************;
;
; set/read vectored I/O from (XY), Cb = 1 to read, Cb = 0 to set

; this routine manages all system vector jump addresses stored in RAM. calling this
; routine with the accumulator carry bit set will store the current contents of the
; RAM vectors in a list pointed to by the X and Y registers.

; When this routine is called with the carry bit clear, the user list pointed to by
; the X and Y registers is transferred to the system RAM vectors.

; NOTE: This routine requires caution in its use. The best way to use it is to first
; read the entire vector contents into the user area, alter the desired vectors, and
; then copy the contents back to the system vectors.

LAB_FD57
   STX    LAB_C3        ; save pointer low byte
   STY    LAB_C4        ; save pointer high byte
   LDY    #$1F            ; set byte count
LAB_FD5D
   LDA    LAB_0314,Y        ; read vector byte from vectors
   BCS    LAB_FD64        ; if read vectors skip the read from XY

   LDA    (LAB_C3),Y        ; read vector byte from (XY)
LAB_FD64
   STA    (LAB_C3),Y        ; save byte to (XY)
   STA    LAB_0314,Y        ; save byte to vector
   DEY                ; decrement index
   BPL    LAB_FD5D        ; loop if more to do

   RTS

;; The above code works but it tries to write to the ROM. while this is usually harmless
;; systems that use flash ROM may suffer. Here is a version that makes the extra write
;; to RAM instead but is otherwise identical in function. ##
;
;; set/read vectored I/O from (XY), Cb = 1 to read, Cb = 0 to set
;
;LAB_FD57
;    STX    LAB_C3        ; save pointer low byte
;    STY    LAB_C4        ; save pointer high byte
;    LDY    #$1F            ; set byte count
;LAB_FD5D
;    LDA    (LAB_C3),Y        ; read vector byte from (XY)
;    BCC    LAB_FD66        ; if set vectors skip the read from XY
;
;    LDA    LAB_0314,Y        ; else read vector byte from vectors
;    STA    (LAB_C3),Y        ; save byte to (XY)
;LAB_FD66
;    STA    LAB_0314,Y        ; save byte to vector
;    DEY                ; decrement index
;    BPL    LAB_FD5D        ; loop if more to do
;
;    RTS


;***********************************************************************************;
;
; kernal vectors

LAB_FD6D
   .word    LAB_EABF        ; LAB_0314    IRQ vector
   .word    LAB_FED2        ; LAB_0316    BRK vector
   .word    LAB_FEAD        ; LAB_0318    NMI vector
   .word    LAB_F40A        ; LAB_031A    open a logical file
   .word    LAB_F34A        ; LAB_031C    close a specified logical file
   .word    LAB_F2C7        ; LAB_031E    open channel for input
   .word    LAB_F309        ; LAB_0320    open channel for output
   .word    LAB_F3F3        ; LAB_0322    close input and output channels
   .word    LAB_F20E        ; LAB_0324    input character from channel
   .word    LAB_F27A        ; LAB_0326    output character to channel
   .word    LAB_F770        ; LAB_0328    scan stop key
   .word    LAB_F1F5        ; LAB_032A    get character from keyboard queue
   .word    LAB_F3EF        ; LAB_032C    close all channels and files
   .word    LAB_FED2        ; LAB_032E    user function

; Vector to user defined command, currently points to BRK.

; This appears to be a holdover from PET days, when the built-in machine language monitor
; would jump through the LAB_032E vector when it encountered a command that it did not
; understand, allowing the user to add new commands to the monitor.

; Although this vector is initialized to point to the routine called by STOP/RESTORE and
; the BRK interrupt, and is updated by the kernal vector routine at $FD57, it no longer
; has any function.

   .word    LAB_F549        ; LAB_0330    load
   .word    LAB_F685        ; LAB_0332    save


;***********************************************************************************;
;
; initialise and test RAM, the RAM from $000 to $03FF is never tested and is just assumed
; to work. first a search is done from $0401 for the start of memory and this is saved, if
; this start is at or beyond $1100 then the routine dead ends. once the start of memory is
; found the routine looks for the end of memory, if this end is before $2000 the routine
; again dead ends. lastly, if the end of memory is at $2000 then the screen is set to
; $1E00, but if the memory extends to or beyond $2100 then the screen is moved to $1000

LAB_FD8D
   LDA    #$00            ; clear A
   TAX                ; clear index
LAB_FD90
   STA    LAB_00,X        ; clear page 0
   STA    LAB_0200,X        ; clear page 2
   STA    LAB_0300,X        ; clear page 3
   INX                ; increment index
   BNE    LAB_FD90        ; loop if more to do

   LDX    #    LDY    #>LAB_033C        ; set cassette buffer pointer high byte
   STX    LAB_B2        ; save tape buffer start pointer low byte
   STY    LAB_B3        ; save tape buffer start pointer high byte

   STA    LAB_C1        ; clear RAM test pointer low byte
   STA    LAB_97        ; clear looking for end flag
   STA    LAB_0281        ; clear OS start of memory low byte

   TAY                ; clear Y
   LDA    #$04            ; set RAM test pointer high byte
   STA    LAB_C2        ; save RAM test pointer high byte
LAB_FDAF
   INC    LAB_C1        ; increment RAM test pointer low byte
   BNE    LAB_FDB5        ; if no rollover skip the high byte increment

   INC    LAB_C2        ; increment RAM test pointer high byte
LAB_FDB5
   JSR    LAB_FE91        ; test RAM byte, return Cb=0 if failed
   LDA    LAB_97        ; test looking for end flag
   BEQ    LAB_FDDE        ; branch if not looking for end

                   ; else now looking for the end of memory
   BCS    LAB_FDAF        ; loop if byte test passed

   LDY    LAB_C2        ; get test address high byte
   LDX    LAB_C1        ; get test address low byte
   CPY    #$20            ; compare with $2000, RAM should always end at or after
                   ; $2000 even with no expansion memory as the built in RAM
                   ; ends at $1FFF. therefore the following test should
                   ; never branch
   BCC    LAB_FDEB        ; if end address < $2000 go do dead end loop

   CPY    #$21            ; compare with $2100
   BCS    LAB_FDD2        ; branch if >= $2100

                   ; else memory ended before $2100
   LDY    #$1E            ; set screen memory page to $1E00
   STY    LAB_0288        ; save screen memory page
LAB_FDCF
   JMP    LAB_FE7B        ; set the top of memory and return

                   ; memory ends beyond $2100
LAB_FDD2
   LDA    #$12            ; set OS start of memory high byte
   STA    LAB_0282        ; save OS start of memory high byte
   LDA    #$10            ; set screen memory page to $1000
   STA    LAB_0288        ; save screen memory page
   BNE    LAB_FDCF        ; set the top of memory and return, branch always

LAB_FDDE
   BCC    LAB_FDAF        ; loop if byte test failed, not found start yet

                   ; else found start of RAM
   LDA    LAB_C2        ; get test address high byte
   STA    LAB_0282        ; save OS start of memory high byte
   STA    LAB_97        ; set looking for end flag
   CMP    #$11            ; compare start with $1100, RAM should always start before
                   ; $1100 even with no expansion memory as the built in RAM
                   ; starts at $1000. therefore the following test should
                   ; always branch
   BCC    LAB_FDAF        ; go find end of RAM, branch always

                   ; if the code drops through here then the RAM has failed
                   ; and there is not much else to be done
LAB_FDEB
   JSR    LAB_E5C3        ; initialise Vic chip
   JMP    LAB_FDEB        ; loop forever


;***********************************************************************************;
;
; tape IRQ vectors

LAB_FDF1
   .word    LAB_FCA8        ; $08    write tape leader IRQ routine
   .word    LAB_FC0B        ; $0A    tape write IRQ routine
   .word    LAB_EABF        ; $0C    normal IRQ vector
   .word    LAB_F98E        ; $0E    read tape bits IRQ routine


;***********************************************************************************;
;
; initialize I/O registers

LAB_FDF9
   LDA    #$7F            ; disable all interrupts
   STA    LAB_911E        ; on VIA 1 IER ..
   STA    LAB_912E        ; .. and VIA 2 IER

   LDA    #$40            ; set T1 free run, T2 clock �2,
                   ; SR disabled, latches disabled
   STA    LAB_912B        ; set VIA 2 ACR

   LDA    #$40            ; set T1 free run, T2 clock �2,
                   ; SR disabled, latches disabled
   STA    LAB_911B        ; set VIA 1 ACR

   LDA    #$FE            ; CB2 high, RS232 Tx
                   ; CB1 +ve edge,
                   ; CA2 high, tape motor off
                   ; CA1 -ve edge
   STA    LAB_911C        ; set VIA 1 PCR

   LDA    #$DE            ; CB2 low, serial data out high
                   ; CB1 +ve edge,
                   ; CA2 high, serial clock out low
                   ; CA1 -ve edge
   STA    LAB_912C        ; set VIA 2 PCR

   LDX    #$00            ; all inputs, RS232 interface or parallel user port
   STX    LAB_9112        ; set VIA 1 DDRB

   LDX    #$FF            ; all outputs, keyboard column
   STX    LAB_9122        ; set VIA 2 DDRB

   LDX    #$00            ; all inputs, keyboard row
   STX    LAB_9123        ; set VIA 2 DDRA

   LDX    #$80            ; OIII IIII, ATN out, light pen, joystick, serial data
                   ; in, serial clk in
   STX    LAB_9113        ; set VIA 1 DDRA

   LDX    #$00            ; ATN out low, set ATN high
   STX    LAB_911F        ; set VIA 1 DRA, no handshake

   JSR    LAB_EF84        ; set serial clock high
   LDA    #$82            ; enable CA1 interrupt, [RESTORE] key
   STA    LAB_911E        ; set VIA 1 IER
   JSR    LAB_EF8D        ; set serial clock low


;***********************************************************************************;
;
; set 60Hz and enable timer

LAB_FE39
   LDA    #$C0            ; enable T1 interrupt
   STA    LAB_912E        ; set VIA 2 IER
   LDA    #$26            ; set timer constant low byte [PAL]
;    LDA    #$89            ; set timer constant low byte [NTSC]
   STA    LAB_9124        ; set VIA 2 T1C_l
   LDA    #$48            ; set timer constant high byte [PAL]
;    LDA    #$42            ; set timer constant high byte [NTSC]
   STA    LAB_9125        ; set VIA 2 T1C_h
   RTS


;***********************************************************************************;
;
; set filename

; this routine is used to set up the file name for the OPEN, SAVE, or LOAD routines.
; The accumulator must be loaded with the length of the file and XY with the pointer
; to file name, X being the low byte. The address can be any valid memory address in
; the system where a string of characters for the file name is stored. If no file
; name desired the accumulator must be set to 0, representing a zero file length,
; in that case XY may be set to any memory address.

LAB_FE49
   STA    LAB_B7        ; set file name length
   STX    LAB_BB        ; set file name pointer low byte
   STY    LAB_BC        ; set file name pointer high byte
   RTS


;***********************************************************************************;
;
; set logical file, first and second addresses

; this routine will set the logical file number, device address, and secondary
; address, command number, for other KERNAL routines.

; the logical file number is used by the system as a key to the file table created
; by the OPEN file routine. Device addresses can range from 0 to 30. The following
; codes are used by the computer to stand for the following CBM devices:

; ADDRESS    DEVICE
; =======    ======
; 0        Keyboard
; 1        Cassette #1
; 2        RS-232C device
; 3        CRT display
; 4        Serial bus printer
; 8        CBM Serial bus disk drive

; device numbers of four or greater automatically refer to devices on the serial
; bus.

; a command to the device is sent as a secondary address on the serial bus after
; the device number is sent during the serial attention handshaking sequence. If
; no secondary address is to be sent Y should be set to $FF.

LAB_FE50
   STA    LAB_B8        ; set logical file
   STX    LAB_BA        ; set device number
   STY    LAB_B9        ; set secondary address or command
   RTS


;***********************************************************************************;
;
; read I/O status word

; this routine returns the current status of the I/O device in the accumulator. The
; routine is usually called after new communication to an I/O device. The routine
; will give information about device status, or errors that have occurred during the
; I/O operation.

LAB_FE57
   LDA    LAB_BA        ; get device number
   CMP    #$02            ; compare device with RS232 device
   BNE    LAB_FE68        ; branch if not RS232 device

                   ; get RS232 device status
   LDA    LAB_0297        ; read RS232 status word

   LDA    #$00            ; clear A
   STA    LAB_0297        ; clear RS232 status

; the above code is wrong. the RS232 status is in A but A is cleared and that is used
; to clear the RS232 status byte. so whatever the status the result is always $00 and
; the status byte is always cleared. A solution is to use X to clear the status after
; it is read instead of the above like this ..
;
;    LDX    #$00            ; clear X
;    STX    LAB_0297        ; clear RS232 status ##
   RTS


;***********************************************************************************;
;
; control kernal messages

; this routine controls the printing of error and control messages by the KERNAL.
; Either print error messages or print control messages can be selected by setting
; the accumulator when the routine is called.

; FILE NOT FOUND is an example of an error message. PRESS PLAY ON CASSETTE is an
; example of a control message.

; bits 6 and 7 of this value determine where the message will come from. If bit 7
; is set one of the error messages from the KERNAL will be printed. If bit 6 is set
; a control message will be printed.

LAB_FE66
   STA    LAB_9D        ; set message mode flag
LAB_FE68
   LDA    LAB_90        ; read serial status byte

; OR into serial status byte

LAB_FE6A
   ORA    LAB_90        ; OR with serial status byte
   STA    LAB_90        ; save serial status byte
   RTS


;***********************************************************************************;
;
; set timeout on serial bus

; this routine sets the timeout flag for the serial bus. When the timeout flag is
; set, the computer will wait for a device on the serial port for 64 milliseconds.
; If the device does not respond to the computer's DAV signal within that time the
; computer will recognize an error condition and leave the handshake sequence. When
; this routine is called and the accumulator contains a 0 in bit 7, timeouts are
; enabled. A 1 in bit 7 will disable the timeouts.

; NOTE: The the timeout feature is used to communicate that a disk file is not found
; on an attempt to OPEN a file.

LAB_FE6F
   STA    LAB_0285        ; save serial bus timeout flag
   RTS


;***********************************************************************************;
;
; read/set the top of memory, Cb = 1 to read, Cb = 0 to set

; this routine is used to read and set the top of RAM. When this routine is called
; with the carry bit set the pointer to the top of RAM will be loaded into XY. When
; this routine is called with the carry bit clear XY will be saved as the top of
; memory pointer changing the top of memory.

LAB_FE73
   BCC    LAB_FE7B        ; if Cb clear go set the top of memory

; read the top of memory

LAB_FE75
   LDX    LAB_0283        ; get memory top low byte
   LDY    LAB_0284        ; get memory top high byte

; set the top of memory

LAB_FE7B
   STX    LAB_0283        ; set memory top low byte
   STY    LAB_0284        ; set memory top high byte
   RTS


;***********************************************************************************;
;
; read/set the bottom of memory, Cb = 1 to read, Cb = 0 to set

; this routine is used to read and set the bottom of RAM. When this routine is
; called with the carry bit set the pointer to the bottom of RAM will be loaded
; into XY. When this routine is called with the carry bit clear XY will be saved as
; the bottom of memory pointer changing the bottom of memory.

LAB_FE82
   BCC    LAB_FE8A        ; if Cb clear go set the bottom of memory

; read the bottom of memory

   LDX    LAB_0281        ; read OS start of memory low byte
   LDY    LAB_0282        ; read OS start of memory high byte

; set the bottom of memory

LAB_FE8A
   STX    LAB_0281        ; set OS start of memory low byte
   STY    LAB_0282        ; set OS start of memory high byte
   RTS


;***********************************************************************************;
;
; non-destructive test RAM byte, return Cb=0 if failed

LAB_FE91
   LDA    (LAB_C1),Y        ; get existing RAM byte
   TAX                ; copy to X
   LDA    #$55            ; set first test byte
   STA    (LAB_C1),Y        ; save to RAM
   CMP    (LAB_C1),Y        ; compare with saved
   BNE    LAB_FEA4        ; branch if fail

   ROR                ; make byte $AA, carry is set here
   STA    (LAB_C1),Y        ; save to RAM
   CMP    (LAB_C1),Y        ; compare with saved
   BNE    LAB_FEA4        ; branch if fail
   .byte    $A9            ; makes next line LDA #$18

LAB_FEA4
   CLC                ; flag test failed
   TXA                ; get original byte back
   STA    (LAB_C1),Y        ; restore original byte
   RTS


;***********************************************************************************;
;
; NMI vector

LAB_FEA9
   SEI                ; disable interrupts
   JMP    (LAB_0318)        ; do NMI vector


;***********************************************************************************;
;
; NMI handler

LAB_FEAD
   PHA                ; save A
   TXA                ; copy X
   PHA                ; save X
   TYA                ; copy Y
   PHA                ; save Y
   LDA    LAB_911D        ; get VIA 1 IFR
   BPL    LAB_FEFF        ; if no interrupt restore registers and exit

   AND    LAB_911E        ; AND with VIA 1 IER
   TAX                ; copy to X
   AND    #$02            ; mask [RESTORE] key
   BEQ    LAB_FEDE        ; branch if not [RESTORE] key

                   ; else was [RESTORE] key ..
   JSR    LAB_FD3F        ; scan for autostart ROM at $A000
   BNE    LAB_FEC7        ; branch if no autostart ROM

   JMP    (LAB_A002)        ; else do autostart ROM break entry

LAB_FEC7
   BIT    LAB_9111        ; test VIA 1 DRA
   JSR    LAB_F734        ; increment the real time clock
   JSR    LAB_FFE1        ; scan stop key
   BNE    LAB_FEFF        ; if not [STOP] restore registers and exit interrupt


;***********************************************************************************;
;
; BRK handler

LAB_FED2
   JSR    LAB_FD52        ; restore default I/O vectors
   JSR    LAB_FDF9        ; initialize I/O registers
   JSR    LAB_E518        ; initialise hardware
   JMP    (LAB_C002)        ; do BASIC break entry


;***********************************************************************************;
;
; RS232 NMI routine

LAB_FEDE
   LDA    LAB_911E        ; get VIA 1 IER
   ORA    #$80            ; set enable bit, this bit should be set according to the
                   ; Rockwell 6522 datasheet but clear acording to the MOS
                   ; datasheet. best to assume it's not in the state required
                   ; and set it so
   PHA                ; save to re-enable interrupts
   LDA    #$7F            ; disable all interrupts
   STA    LAB_911E        ; set VIA 1 IER
   TXA                ; get active interrupts back
   AND    #$40            ; mask T1 interrupt
   BEQ    LAB_FF02        ; branch if not T1 interrupt

                   ; was VIA 1 T1 interrupt
   LDA    #$CE            ; CB2 low, CB1 -ve edge, CA2 high, CA1 -ve edge
   ORA    LAB_B5        ; OR RS232 next bit to send, sets CB2 high if set
   STA    LAB_911C        ; set VIA 1 PCR
   LDA    LAB_9114        ; get VIA 1 T1C_l
   PLA                ; restore interrupt enable byte to rstore previously
                   ; enabled interrupts
   STA    LAB_911E        ; set VIA 1 IER
   JSR    LAB_EFA3        ; RS232 Tx NMI routine
LAB_FEFF
   JMP    LAB_FF56        ; restore registers and exit interrupt

                   ; was not VIA 1 T1 interrupt
LAB_FF02
   TXA                ; get active interrupts back
   AND    #$20            ; mask T2 interrupt
   BEQ    LAB_FF2C        ; branch if not T2 interrupt

                   ; was VIA 1 T2 interrupt
   LDA    LAB_9110        ; get VIA 1 DRB
   AND    #$01            ; mask RS232 data in
   STA    LAB_A7        ; save receiver input bit temp storage
   LDA    LAB_9118        ; get VIA 1 T2C_l
   SBC    #$16            ;.
   ADC    LAB_0299        ; add baud rate bit time low byte
   STA    LAB_9118        ; set VIA 1 T2C_l
   LDA    LAB_9119        ; get VIA 1 T2C_h
   ADC    LAB_029A        ; add baud rate bit time high byte
   STA    LAB_9119        ; set VIA 1 T2C_h
   PLA                ; restore interrupt enable byte to restore previously
                   ; enabled interrupts
   STA    LAB_911E        ; set VIA 1 IER, restore interrupts
   JSR    LAB_F036        ; RS232 Rx
   JMP    LAB_FF56        ; restore registers and exit interrupt

                   ; was not VIA 1 T2 interrupt
LAB_FF2C
   TXA                ; get active interrupts back
   AND    #$10            ; mask CB1 interrupt, Rx data bit transition
   BEQ    LAB_FF56        ; if no bit restore registers and exit interrupt

   LDA    LAB_0293        ; get pseudo 6551 control register
   AND    #$0F            ; clear non baud bits
   BNE    LAB_FF38        ; short delay. was this to be a branch to code to implement
                   ; the user baud rate ??
LAB_FF38
   ASL                ; *2, 2 bytes per baud count
   TAX                ; copy to index
   LDA    LAB_FF5C-2,X    ; get baud count low byte
   STA    LAB_9118        ; set VIA 1 T2C_l
   LDA    LAB_FF5C-1,X    ; get baud count high byte
   STA    LAB_9119        ; set VIA 1 T2C_h
   LDA    LAB_9110        ; read VIA 1 DRB, clear interrupt flag
   PLA                ; restore interrupt enable byte to rstore previously
                   ; enabled interrupts
   ORA    #$20            ; enable T2 interrupt
   AND    #$EF            ; disable CB1 interrupt
   STA    LAB_911E        ; set VIA 1 IER
   LDX    LAB_0298        ; get number of bits to be sent/received
   STX    LAB_A8        ; save receiver bit count in


;***********************************************************************************;
;
; restore the registers and exit the interrupt
;
; if you write your own interrupt code you should either return from the interrupt
; using code that ends up here ot code that replicates this code.

LAB_FF56
   PLA                ; pull Y
   TAY                ; restore Y
   PLA                ; pull X
   TAX                ; restore X
   PLA                ; restore A
   RTI


;***********************************************************************************;
;
; baud rate word is calculated from ..
;
; (system clock / baud rate) / 2 - 100
;
;        system clock
;        ------------
; PAL        1108404 Hz
; NTSC    1022727 Hz

; baud rate tables for PAL Vic 20

LAB_FF5C
   .word    $2AE6            ; 50 baud
   .word    $1C78            ; 75 baud
   .word    $1349            ; 110 baud
   .word    $0FB1            ; 134.5 baud
   .word    $0E0A            ; 150 baud
   .word    $06D3            ; 300 baud
   .word    $0338            ; 600 baud
   .word    $016A            ; 1200 baud
   .word    $00D0            ; 1800 baud
   .word    $0083            ; 2400 baud
   .word    $0036            ; 3600 baud

; baud rate tables for NTSC Vic 20

;    .word    $2792            ; 50 baud
;    .word    $1A40            ; 75 baud
;    .word    $11C6            ; 110 baud
;    .word    $0E74            ; 134.5 baud
;    .word    $0CEE            ; 150 baud
;    .word    $0645            ; 300 baud
;    .word    $02F1            ; 600 baud
;    .word    $0146            ; 1200 baud
;    .word    $00B8            ; 1800 baud
;    .word    $0071            ; 2400 baud
;    .word    $002A            ; 3600 baud


;***********************************************************************************;
;
; IRQ vector

LAB_FF72
   PHA                ; save A
   TXA                ; copy X
   PHA                ; save X
   TYA                ; copy Y
   PHA                ; save Y
   TSX                ; copy stack pointer
   LDA    LAB_0100+4,X    ; get the stacked status register
   AND    #$10            ; mask the BRK flag bit
   BEQ    LAB_FF82        ; if not BRK go do the hardware IRQ vector

   JMP    (LAB_0316)        ; else do the BRK vector (iBRK)

LAB_FF82
   JMP    (LAB_0314)        ; do IRQ vector (iIRQ)


;***********************************************************************************;
;
; spare bytes, not referenced

;LAB_FF85
   .byte    $FF,$FF,$FF,$FF,$FF


;***********************************************************************************;
;
; restore default I/O vectors

; This routine restores the default values of all system vectors used in KERNAL and
; BASIC routines and interrupts. The KERNAL VECTOR routine is used to read and alter
; individual system vectors.


;LAB_FF8A
   JMP    LAB_FD52        ; restore default I/O vectors


;***********************************************************************************;
;
; read/set vectored I/O

; this routine manages all system vector jump addresses stored in RAM. calling this
; routine with the accumulator carry bit set will store the current contents of the
; RAM vectors in a list pointed to by the X and Y registers.

; When this routine is called with the carry bit clear, the user list pointed to by
; the X and Y registers is transferred to the system RAM vectors.

; NOTE: This routine requires caution in its use. The best way to use it is to first
; read the entire vector contents into the user area, alter the desired vectors, and
; then copy the contents back to the system vectors.

;LAB_FF8D
   JMP    LAB_FD57        ; set/read vectored I/O from (XY)


;***********************************************************************************;
;
; control kernal messages

; this routine controls the printing of error and control messages by the KERNAL.
; Either print error messages or print control messages can be selected by setting
; the accumulator when the routine is called.

; FILE NOT FOUND is an example of an error message. PRESS PLAY ON CASSETTE is an
; example of a control message.

; bits 6 and 7 of this value determine where the message will come from. If bit 7
; is set one of the error messages from the KERNAL will be printed. If bit 6 is set
; a control message will be printed.

LAB_FF90
   JMP    LAB_FE66        ; control kernal messages


;***********************************************************************************;
;
; send secondary address after LISTEN

; this routine is used to send a secondary address to an I/O device after a call to
; the LISTEN routine is made and the device commanded to LISTEN. The routine cannot
; be used to send a secondary address after a call to the TALK routine.

; A secondary address is usually used to give set-up information to a device before
; I/O operations begin.

; When a secondary address is to be sent to a device on the serial bus the address
; must first be ORed with $60.

;LAB_FF93
   JMP    LAB_EEC0        ; send secondary address after LISTEN


;***********************************************************************************;
;
; send secondary address after TALK

; this routine transmits a secondary address on the serial bus for a TALK device.
; This routine must be called with a number between 4 and 31 in the accumulator.
; The routine will send this number as a secondary address command over the serial
; bus. This routine can only be called after a call to the TALK routine. It will
; not work after a LISTEN.

;LAB_FF96
   JMP    LAB_EECE        ; send secondary address after TALK


;***********************************************************************************;
;
; read/set the top of memory

; this routine is used to read and set the top of RAM. When this routine is called
; with the carry bit set the pointer to the top of RAM will be loaded into XY. When
; this routine is called with the carry bit clear XY will be saved as the top of
; memory pointer changing the top of memory.

LAB_FF99
   JMP    LAB_FE73        ; read/set the top of memory


;***********************************************************************************;
;
; read/set the bottom of memory

; this routine is used to read and set the bottom of RAM. When this routine is
; called with the carry bit set the pointer to the bottom of RAM will be loaded
; into XY. When this routine is called with the carry bit clear XY will be saved as
; the bottom of memory pointer changing the bottom of memory.

LAB_FF9C
   JMP    LAB_FE82        ; read/set the bottom of memory


;***********************************************************************************;
;
; scan the keyboard

; this routine will scan the keyboard and check for pressed keys. It is the same
; routine called by the interrupt handler. If a key is down, its ASCII value is
; placed in the keyboard queue.

;LAB_FF9F
   JMP    LAB_EB1E        ; scan keyboard


;***********************************************************************************;
;
; set timeout on serial bus

; this routine sets the timeout flag for the serial bus. When the timeout flag is
; set, the computer will wait for a device on the serial port for 64 milliseconds.
; If the device does not respond to the computer's DAV signal within that time the
; computer will recognize an error condition and leave the handshake sequence. When
; this routine is called and the accumulator contains a 0 in bit 7, timeouts are
; enabled. A 1 in bit 7 will disable the timeouts.

; NOTE: The the timeout feature is used to communicate that a disk file is not found
; on an attempt to OPEN a file.

;LAB_FFA2
   JMP    LAB_FE6F        ; set timeout on serial bus


;************************************************************************************
;
; input a byte from the serial bus

; this routine reads a byte of data from the serial bus using full handshaking. the
; data is returned in the accumulator. before using this routine the TALK routine,
; LAB_FFB4, must have been called first to command the device on the serial bus to
; send data on the bus. if the input device needs a secondary command it must be sent
; by using the TKSA routine, LAB_FF96, before calling this routine.

; errors are returned in the status word which can be read by calling the READST
; routine, LAB_FFB7.

;LAB_FFA5
   JMP    LAB_EF19        ; input byte from serial bus


;************************************************************************************
;
; output a byte to the serial bus

; this routine is used to send information to devices on the serial bus. A call to
; this routine will put a data byte onto the serial bus using full handshaking.
; Before this routine is called the LISTEN routine, LAB_FFB1, must be used to
; command a device on the serial bus to get ready to receive data.

; the accumulator is loaded with a byte to output as data on the serial bus. A
; device must be listening or the status word will return a timeout. This routine
; always buffers one character. So when a call to the UNLISTEN routine, LAB_FFAE,
; is made to end the data transmission, the buffered character is sent with EOI
; set. Then the UNLISTEN command is sent to the device.

;LAB_FFA8
   JMP    LAB_EEE4        ; output a byte to the serial bus


;***********************************************************************************;
;
; command the serial bus to UNTALK

; this routine will transmit an UNTALK command on the serial bus. All devices
; previously set to TALK will stop sending data when this command is received.

;LAB_FFAB
   JMP    LAB_EEF6        ; command the serial bus to UNTALK


;***********************************************************************************;
;
; command the serial bus to UNLISTEN

; this routine commands all devices on the serial bus to stop receiving data from
; the computer. Calling this routine results in an UNLISTEN command being transmitted
; on the serial bus. Only devices previously commanded to listen will be affected.

; This routine is normally used after the computer is finished sending data to
; external devices. Sending the UNLISTEN will command the listening devices to get
; off the serial bus so it can be used for other purposes.

;LAB_FFAE
   JMP    LAB_EF04        ; command the serial bus to UNLISTEN


;***********************************************************************************;
;
; command devices on the serial bus to LISTEN

; this routine will command a device on the serial bus to receive data. The
; accumulator must be loaded with a device number between 4 and 31 before calling
; this routine. LISTEN convert this to a listen address then transmit this data as
; a command on the serial bus. The specified device will then go into listen mode
; and be ready to accept information.

;LAB_FFB1
   JMP    LAB_EE17        ; command devices on the serial bus to LISTEN


;***********************************************************************************;
;
; command a serial bus device to TALK

; to use this routine the accumulator must first be loaded with a device number
; between 4 and 30. When called this routine converts this device number to a talk
; address. Then this data is transmitted as a command on the Serial bus.

;LAB_FFB4
   JMP    LAB_EE14        ; command serial bus device to TALK


;***********************************************************************************;
;
; read I/O status word

; this routine returns the current status of the I/O device in the accumulator. The
; routine is usually called after new communication to an I/O device. The routine
; will give information about device status, or errors that have occurred during the
; I/O operation.

LAB_FFB7
   JMP    LAB_FE57        ; read I/O status word


;***********************************************************************************;
;
; set logical, first and second addresses

; this routine will set the logical file number, device address, and secondary
; address, command number, for other KERNAL routines.

; the logical file number is used by the system as a key to the file table created
; by the OPEN file routine. Device addresses can range from 0 to 30. The following
; codes are used by the computer to stand for the following CBM devices:

; ADDRESS    DEVICE
; =======    ======
; 0        Keyboard
; 1        Cassette #1
; 2        RS-232C device
; 3        CRT display
; 4        Serial bus printer
; 8        CBM Serial bus disk drive

; device numbers of four or greater automatically refer to devices on the serial
; bus.

; a command to the device is sent as a secondary address on the serial bus after
; the device number is sent during the serial attention handshaking sequence. If
; no secondary address is to be sent Y should be set to $FF.

LAB_FFBA
   JMP    LAB_FE50        ; set logical, first and second addresses


;***********************************************************************************;
;
; set the filename

; this routine is used to set up the file name for the OPEN, SAVE, or LOAD routines.
; The accumulator must be loaded with the length of the file and XY with the pointer
; to file name, X being th low byte. The address can be any valid memory address in
; the system where a string of characters for the file name is stored. If no file
; name desired the accumulator must be set to 0, representing a zero file length,
; in that case XY may be set to any memory address.

LAB_FFBD
   JMP    LAB_FE49        ; set filename


;***********************************************************************************;
;
; open a logical file

; this routine is used to open a logical file. Once the logical file is set up it
; can be used for input/output operations. Most of the I/O KERNAL routines call on
; this routine to create the logical files to operate on. No arguments need to be
; set up to use this routine, but both the SETLFS, LAB_FFBA, and SETNAM, LAB_FFBD,
; KERNAL routines must be called before using this routine.

LAB_FFC0
   JMP    (LAB_031A)        ; do open file vector


;***********************************************************************************;
;
; close a specified logical file

; this routine is used to close a logical file after all I/O operations have been
; completed on that file. This routine is called after the accumulator is loaded
; with the logical file number to be closed, the same number used when the file was
; opened using the OPEN routine.

LAB_FFC3
   JMP    (LAB_031C)        ; do close file vector


;************************************************************************************
;
; open a channel for input

; any logical file that has already been opened by the OPEN routine, LAB_FFC0, can be
; defined as an input channel by this routine. the device on the channel must be an
; input device or an error will occur and the routine will abort.

; if you are getting data from anywhere other than the keyboard, this routine must be
; called before using either the CHRIN routine, LAB_FFCF, or the GETIN routine,
; LAB_FFE4. if you are getting data from the keyboard and no other input channels are
; open then the calls to this routine and to the OPEN routine, LAB_FFC0, are not needed.

; when used with a device on the serial bus this routine will automatically send the
; listen address specified by the OPEN routine, LAB_FFC0, and any secondary address.

; possible errors are:
;
;    3 : file not open
;    5 : device not present
;    6 : file is not an input file

LAB_FFC6
   JMP    (LAB_031E)        ; do open for input vector


;************************************************************************************
;
; open a channel for output

; any logical file that has already been opened by the OPEN routine, LAB_FFC0, can be
; defined as an output channel by this routine the device on the channel must be an
; output device or an error will occur and the routine will abort.

; if you are sending data to anywhere other than the screen this routine must be
; called before using the CHROUT routine, LAB_FFD2. if you are sending data to the
; screen and no other output channels are open then the calls to this routine and to
; the OPEN routine, LAB_FFC0, are not needed.

; when used with a device on the serial bus this routine will automatically send the
; listen address specified by the OPEN routine, LAB_FFC0, and any secondary address.

; possible errors are:
;
;    3 : file not open
;    5 : device not present
;    7 : file is not an output file

LAB_FFC9
   JMP    (LAB_0320)        ; do open for output vector


;************************************************************************************
;
; close input and output channels

; this routine is called to clear all open channels and restore the I/O channels to
; their original default values. It is usually called after opening other I/O
; channels and using them for input/output operations. The default input device is
; 0, the keyboard. The default output device is 3, the screen.

; If one of the channels to be closed is to the serial port, an UNTALK signal is sent
; first to clear the input channel or an UNLISTEN is sent to clear the output channel.
; By not calling this routine and leaving listener(s) active on the serial bus,
; several devices can receive the same data from the VIC at the same time. One way to
; take advantage of this would be to command the printer to TALK and the disk to
; LISTEN. This would allow direct printing of a disk file.

LAB_FFCC
   JMP    (LAB_0322)        ; do close vector


;************************************************************************************
;
; input character from channel

; this routine will get a byte of data from the channel already set up as the input
; channel by the CHKIN routine, LAB_FFC6.

; If CHKIN, LAB_FFC6, has not been used to define another input channel the data is
; expected to be from the keyboard. the data byte is returned in the accumulator. the
; channel remains open after the call.

; input from the keyboard is handled in a special way. first, the cursor is turned on
; and it will blink until a carriage return is typed on the keyboard. all characters
; on the logical line, up to 88 characters, will be stored in the BASIC input buffer.
; then the characters can be returned one at a time by calling this routine once for
; each character. when the carriage return is returned the entire line has been
; processed. the next time this routine is called the whole process begins again.

LAB_FFCF
   JMP    (LAB_0324)        ; do input vector


;************************************************************************************
;
; output a character to channel

; this routine will output a character to an already opened channel. Use the OPEN
; routine, LAB_FFC0, and the CHKOUT routine, LAB_FFC9, to set up the output channel
; before calling this routine. If these calls are omitted, data will be sent to the
; default output device, device 3, the screen. The data byte to be output is loaded
; into the accumulator, and this routine is called. The data is then sent to the
; specified output device. The channel is left open after the call.

; NOTE: Care must be taken when using routine to send data to a serial device since
; data will be sent to all open output channels on the bus. Unless this is desired,
; all open output channels on the serial bus other than the actually intended
; destination channel must be closed by a call to the KERNAL close channel routine.

LAB_FFD2
   JMP    (LAB_0326)        ; do output vector


;***********************************************************************************;
;
; load RAM from a device

; this routine will load data bytes from any input device directly into the memory
; of the computer. It can also be used for a verify operation comparing data from a
; device with the data already in memory, leaving the data stored in RAM unchanged.

; The accumulator must be set to 0 for a load operation or 1 for a verify. If the
; input device was OPENed with a secondary address of 0 the header information from
; device will be ignored. In this case XY must contain the starting address for the
; load. If the device was addressed with a secondary address of 1 or 2 the data will
; load into memory starting at the location specified by the header. This routine
; returns the address of the highest RAM location which was loaded.

; Before this routine can be called, the SETLFS, LAB_FFBA, and SETNAM, LAB_FFBD,
; routines must be called.

LAB_FFD5
   JMP    LAB_F542        ; load RAM from a device


;***********************************************************************************;
;
; save RAM to a device

; this routine saves a section of memory. Memory is saved from an indirect address
; on page 0 specified by A, to the address stored in XY, to a logical file. The
; SETLFS, LAB_FFBA, and SETNAM, LAB_FFBD, routines must be used before calling this
; routine. However, a file name is not required to SAVE to device 1, the cassette.
; Any attempt to save to other devices without using a file name results in an error.

; NOTE: device 0, the keyboard, and device 3, the screen, cannot be SAVEd to. If
; the attempt is made, an error will occur, and the SAVE stopped.

LAB_FFD8
   JMP    LAB_F675        ; save RAM to device


;***********************************************************************************;
;
; set the real time clock

; the system clock is maintained by an interrupt routine that updates the clock
; every 1/60th of a second. The clock is three bytes long which gives the capability
; to count from zero up to 5,184,000 jiffies - 24 hours plus one jiffy. At that point
; the clock resets to zero. Before calling this routine to set the clock the new time,
; in jiffies, should be in YXA, the accumulator containing the most significant byte.

LAB_FFDB
   JMP    LAB_F767        ; set real time clock


;***********************************************************************************;
;
; read the real time clock

; this routine returns the time, in jiffies, in AXY. The accumulator contains the
; most significant byte.

LAB_FFDE
   JMP    LAB_F760        ; read real time clock


;***********************************************************************************;
;
; scan the stop key

; if the STOP key on the keyboard is pressed when this routine is called the Z flag
; will be set. All other flags remain unchanged. If the STOP key is not pressed then
; the accumulator will contain a byte representing the last row of the keyboard scan.

; The user can also check for certain other keys this way.

LAB_FFE1
   JMP    (LAB_0328)        ; do stop key vector


;***********************************************************************************;
;
; get a character from an input device

; in practice this routine operates identically to the CHRIN routine, LAB_FFCF,
; for all devices except for the keyboard. If the keyboard is the current input
; device this routine will get one character from the keyboard buffer. It depends
; on the IRQ routine to read the keyboard and put characters into the buffer.

; If the keyboard buffer is empty the value returned in the accumulator will be zero

LAB_FFE4
   JMP    (LAB_032A)        ; do get vector


;***********************************************************************************;
;
; close all channels and files

; this routine closes all open files. When this routine is called, the pointers into
; the open file table are reset, closing all files. Also the routine automatically
; resets the I/O channels.

LAB_FFE7
   JMP    (LAB_032C)        ; do close all vector


;***********************************************************************************;
;
; increment the real time clock

; this routine updates the system clock. Normally this routine is called by the
; normal KERNAL interrupt routine every 1/60th of a second. If the user program
; processes its own interrupts this routine must be called to update the time. Also,
; the STOP key routine must be called if the stop key is to remain functional.

LAB_FFEA
   JMP    LAB_F734        ; increment real time clock


;***********************************************************************************;
;
; return X,Y organization of screen

; this routine returns the x,y organisation of the screen in X,Y

;LAB_FFED
   JMP    LAB_E505        ; return X,Y organization of screen


;***********************************************************************************;
;
; read/set X,Y cursor position

; this routine, when called with the carry flag set, loads the current position of
; the cursor on the screen into the X and Y registers. X is the column number of
; the cursor location and Y is the row number of the cursor. A call with the carry
; bit clear moves the cursor to the position determined by the X and Y registers.

LAB_FFF0
   JMP    LAB_E50A        ; read/set X,Y cursor position


;***********************************************************************************;
;
; return the base address of the I/O devices

; this routine will set XY to the address of the memory section where the memory
; mapped I/O devices are located. This address can then be used with an offset to
; access the memory mapped I/O devices in the computer.

LAB_FFF3
   JMP    LAB_E500        ; return base address of I/O devices


;***********************************************************************************;
;
; spare bytes, not referenced

   .byte    $FF,$FF,$FF,$FF


;***********************************************************************************;
;
; hardware vectors

   .word    LAB_FEA9        ; NMI vector
   .word    LAB_FD22        ; RESET vector
   .word    LAB_FF72        ; IRQ vector

   .END


;***********************************************************************************;
;***********************************************************************************;