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