ca65 V2.17 - Git 582aa41 Main file : BASIC.ca65 Current file: BASIC.ca65 000000r 1 ; 000000r 1 ; Acorn System/Atom BASIC 000000r 1 ; 000000r 1 ; Produced from an original System BASIC EPROM purchased in 1982 000000r 1 ; and an Atom purchased in the early 80's, 000000r 1 ; disassembled during 1982 and recently transferred to CA65 format. 000000r 1 ; 000000r 1 ; (Chris Oddy November 2018) 000000r 1 ; 000000r 1 .setcpu "6502" 000000r 1 .listbytes unlimited 000000r 1 ; 000000r 1 ; This source code can create either a System or Atom variant of BASIC 000000r 1 ; 000000r 1 .define ATOM 0 ; set to 1 for the Atom variant 000000r 1 .define SYSTEM 1 ; set to 1 for the System variant 000000r 1 ; 000000r 1 ; check valid options selected 000000r 1 .if (ATOM=0 .and SYSTEM=0) .or (ATOM<>0 .and SYSTEM<>0) 000000r 1 .error "Invalid variant options selected" 000000r 1 .endif 000000r 1 ; 000000r 1 ; ****** Zero Page Workspace ****** 000000r 1 ; 000000r 1 err_no := $00 ; error number (1 byte) 000000r 1 baslin := $01 ; BASIC linenumber (2 bytes) 000000r 1 index := $03 ; index to text pointer (1 byte) 000000r 1 accptr := $04 ; accumulator stack pointer (1 byte) 000000r 1 txtptr := $05 ; text area pointer (2 bytes) 000000r 1 count := $07 ; PRINT position counter (1 byte) 000000r 1 random := $08 ; random number (5 bytes) 000000r 1 TOP := $0D ; TOP of text area (2 bytes) 000000r 1 prbase := $0F ; PRINT number base 000000r 1 ; - decimal: bit7=1, hex: bit7=0 (1 byte) 000000r 1 handle := $0F ; file handle (1 byte) 000000r 1 admode := $0F ; 000000r 1 errptr := $10 ; pointer to error text (2 bytes) 000000r 1 txtpag := $12 ; bottom of text area page (1 byte) 000000r 1 BOTTOM := $12 ; 000000r 1 do_cnt := $13 ; DO loop counter/stack pointer (1 byte) 000000r 1 goscnt := $14 ; GOSUB counter/stack pointer (1 byte) 000000r 1 forcnt := $15 ; FOR loop counter/stack pointer (1 byte) 000000r 1 000000r 1 acc1 := $16 ; 1st byte of accumulator stack (15 levels) 000000r 1 frespc := $23 ; 000000r 1 acc2 := $25 ; 2nd byte of accumulator stack (15 levels) 000000r 1 acc3 := $34 ; 3rd byte of accumulator stack (15 levels) 000000r 1 acc4 := $43 ; 4th byte of accumulator stack (15 levels) 000000r 1 000000r 1 bwork := $52 ; BASIC workspace area 000000r 1 X0L := $52 ; 000000r 1 X0M := $53 ; 000000r 1 Y0L := $54 ; 000000r 1 Y0M := $55 ; 000000r 1 xdir := $56 ; 000000r 1 pltcnt := $57 ; 000000r 1 X1L := $5A ; 000000r 1 X1M := $5B ; 000000r 1 Y1L := $5C ; 000000r 1 Y1M := $5D ; 000000r 1 pixadr := $5F ; 000000r 1 y_pos := $61 ; 000000r 1 adrmod := $64 ; 000000r 1 opcode := $66 ; 000000r 1 opernd := $67 ; 000000r 1 mnemon := $69 ; 000000r 1 ; 000000r 1 ; *** Floating Point Workspace *** ($70 to $7F ?) 000000r 1 ; 000000r 1 ; *** Unused Workspace *** ($80 to $AF ?) 000000r 1 ; 000000r 1 ; *** COS Workspace *** ($B0 to $FF ?) 000000r 1 ; 000000r 1 buffer := $0100 ; input buffer (64 bytes) 000000r 1 strbuf := $0140 ; string buffer (64 bytes) 000000r 1 ; 000000r 1 ; *** Stack *** ($0180 to $01FF) 000000r 1 ; 000000r 1 stack := $01FF ; top of processor stack 000000r 1 ; 000000r 1 BRKVEC := $0202 ; vector to BRK service routine 000000r 1 WRCVEC := $0208 ; vector to 'Write Character' service routine (OSWRCH) 000000r 1 BPTVEC := $0216 ; vector to 'Byte PUT to open file' service routine (OSBPUT) 000000r 1 ; 000000r 1 ; Free ($021C to $023F ?) 000000r 1 ; 000000r 1 ; *** BASIC Workspace *** ($0240 to $03FF) 000000r 1 ; 000000r 1 forvar := $0240 ; FOR loop variable stack (15 levels) 000000r 1 .if ATOM=1 000000r 1 stepa := $024B ; FOR loop STEP parameter stack (15 levels) 000000r 1 stepb := $0256 ; 000000r 1 stepc := $0261 ; 000000r 1 stepd := $026C ; 000000r 1 fortoa := $0277 ; FOR loop TO parameter stack (15 levels) 000000r 1 fortob := $0282 ; 000000r 1 fortoc := $028D ; 000000r 1 fortod := $0298 ; 000000r 1 forskl := $02A3 ; LSB of FOR loop return address stack (15 levels) 000000r 1 forskm := $02AE ; MSB of FOR loop return address stack (15 levels) 000000r 1 dostkl := $02B9 ; LSB of DO loop return address stack (15 levels) 000000r 1 dostkm := $02C4 ; MSB of DO loop return address stack (15 levels) 000000r 1 gostkl := $02CF ; LSB of GOSUB return address stack (15 levels) 000000r 1 gostkm := $02DD ; MSB of GOSUB return address stack (15 levels) 000000r 1 .endif 000000r 1 .if SYSTEM=1 000000r 1 stepa := $024F ; FOR loop STEP parameter stack (15 levels) 000000r 1 stepb := $025E ; 000000r 1 stepc := $026D ; 000000r 1 stepd := $027C ; 000000r 1 fortoa := $028B ; FOR loop TO parameter stack (15 levels) 000000r 1 fortob := $029A ; 000000r 1 fortoc := $02A9 ; 000000r 1 fortod := $02B8 ; 000000r 1 forskl := $02C7 ; LSB of FOR loop return address stack (15 levels) 000000r 1 forskm := $02D6 ; MSB of FOR loop return address stack (15 levels) 000000r 1 dostkl := $02E5 ; LSB of DO loop return address stack (15 levels) 000000r 1 dostkm := $02F4 ; MSB of DO loop return address stack (15 levels) 000000r 1 gostkl := $0303 ; LSB of GOSUB return address stack (15 levels) 000000r 1 gostkm := $0312 ; MSB of GOSUB return address stack (15 levels) 000000r 1 .endif 000000r 1 000000r 1 pwidth := $0321 ; PRINT field width, variable @ (1 byte) 000000r 1 intega := $0322 ; 1st byte (LSB) of 4 byte integer variables 000000r 1 integb := $033D ; 2nd byte of 4 byte integer variables 000000r 1 integc := $0358 ; 3rd byte of 4 byte integer variables 000000r 1 integd := $0373 ; 4th byte (MSB) of 4 byte integer variables 000000r 1 label := $038D ; label storage a to z (26 words) 000000r 1 000000r 1 arrayl := $02EB ; arrays ? 000000r 1 arraym := $0306 ; 000000r 1 000000r 1 ; 000000r 1 old_xl := $03C1 ; 000000r 1 old_xm := $03C2 ; 000000r 1 old_yl := $03C3 ; 000000r 1 old_ym := $03C4 ; 000000r 1 ; 000000r 1 ploter := $03FE ; plotter routine address 000000r 1 ; 000000r 1 ; ****** Hardware Addresses ****** 000000r 1 ; 000000r 1 ; *** 200.000 6502 CPU Board *** 000000r 1 ; 000000r 1 ; 8154 Interface located at $0E20 (IC2) 000000r 1 IC2 := $0E20 000000r 1 IC2B := $0E21 ; 8154 Port B Data Register (keyboard) 000000r 1 ; 000000r 1 ; *** Atom 8255 PIA (IC25) *** 000000r 1 ; 000000r 1 IC25A := $B000 ; bits 0-3: keyboard row (output) 000000r 1 ; bits 4-7: graphics mode (output) 000000r 1 IC25B := $B001 ; bits 0-5: keyboard column (input) 000000r 1 ; bit 6: CTRL key (input, active low) 000000r 1 ; bit 7: SHIFT keys (input, active low) 000000r 1 IC25C := $B002 ; bit 0: cassette interface output 000000r 1 ; bit 1: 2.4kHz enable (output) 000000r 1 ; bit 2: loudspeaker output 000000r 1 ; bit 3: not used 000000r 1 ; bit 4: cassette interface 2.4kHz input 000000r 1 ; bit 5: cassette interface input 000000r 1 ; bit 6: REPT key (input, active low) 000000r 1 ; bit 7: 60 Hz sync (low during flyback) 000000r 1 IC25CL := $B003 ; control register, normally $8A: mode 0 000000r 1 ; outputs: port A, port C lower; inputs: port B, port C upper 000000r 1 ; 000000r 1 .if ATOM=1 000000r 1 KEYBRD := IC25B ; Atom keyboard on IC25 000000r 1 .endif 000000r 1 ; 000000r 1 .if SYSTEM=1 000000r 1 KEYBRD := IC2B ; System Keyboard on IC2 000000r 1 .endif 000000r 1 ; 000000r 1 ; BASIC Text Space 000000r 1 ; 000000r 1 .if SYSTEM=1 000000r 1 txtspc := $3000 000000r 1 .endif 000000r 1 .if ATOM=1 000000r 1 txtspc := $2900 000000r 1 .endif 000000r 1 ; 000000r 1 screen := $8000 ; Screen RAM base address 000000r 1 screna := $8000 ; 000000r 1 screnb := $8100 ; 000000r 1 scrmd1 := $8200 ; Graphics Mode 1 000000r 1 scrmd2 := $8400 ; Graphics Mode 2 000000r 1 scrmd3 := $8600 ; Graphics Mode 3 000000r 1 scrmd4 := $8C00 ; Graphics Mode 4 000000r 1 ; 000000r 1 ; Floating Point or ONLIBASIC Extension ROMs 000000r 1 ; 000000r 1 EXTROM := $D000 000000r 1 ; 000000r 1 ; OS Calls 000000r 1 ; 000000r 1 OUTSTR := $F7D1 ; Output a String of Characters 000000r 1 OSSHUT := $FFCB ; Closes a file whose file handle is in Y, a value of zero 000000r 1 ; will close all open files. 000000r 1 OSFIND := $FFCE ; Opens a file returning a file handle in the accumulator. 000000r 1 ; X points to the following data in zeropage: 000000r 1 ; filename terminated by CR. 000000r 1 ; The file handle will be zero if the file does not exist. 000000r 1 ; If carry is set the file must exist and is opened for 000000r 1 ; reading and writing. If carry is clear the file need not 000000r 1 ; exist. The sequential file pointer is set to 0. 000000r 1 OSBPUT := $FFD1 ; Byte PUT to open file - outputs the byte in the accumulator 000000r 1 ; to a sequential file. In systems other than COS the 000000r 1 ; sequential byte pointer will be incremented. 000000r 1 OSBGET := $FFD4 ; Byte GET from open file - returns the next byte from a 000000r 1 ; sequential read file in the accumulator 000000r 1 ; In systems other than COS the sequential byte pointer will 000000r 1 ; be incremented. 000000r 1 OSSTAR := $FFD7 ; SeT ARguments - sets the value of a files sequential pointer. 000000r 1 ; X points to the zeropage location containing the value, 000000r 1 ; Y contains the file handle. 000000r 1 OSRDAR := $FFDA ; ReaD ARguments - returns the value of a files arguments. 000000r 1 ; X points to the zeropage location where the result is to be 000000r 1 ; placed, Y contains the file handle, A specifies the argument 000000r 1 ; - 0:sequential pointer, 1: length, 2:file region. 000000r 1 OSSAVE := $FFDD ; Save an area of memory to a specified file. 000000r 1 ; X points to the following data in zeropage: 000000r 1 ; filename terminated by CR, address where data is reloaded, 000000r 1 ; execute address, start address in memory, end address+1. 000000r 1 ; If insufficient space for the file then a BRK will occur. 000000r 1 ; In interrupt/DMA systems a wait for completion will occur if 000000r 1 ; carry was set on entry. 000000r 1 OSLOAD := $FFE0 ; Load a file into a specified area of memory. 000000r 1 ; X points to the following data in zeropage: 000000r 1 ; filename terminated by CR, address of destination, 000000r 1 ; a byte which if bit 7=0 causes load address to be used. 000000r 1 ; If the file cannot be found then a BRK will occur. 000000r 1 ; In interrupt/DMA systems a wait for completion will occur if 000000r 1 ; carry was set on entry. 000000r 1 OSRDCH := $FFE3 ; REad CHaracter - fetches a byte from the input channel. 000000r 1 OSECHO := $FFE6 ; Fetches byte with OSRDCH and sends to output channel using 000000r 1 ; OSWRCH (if CR is read then a LF and CR are sent to OSWRCH). 000000r 1 OSASCI := $FFE9 ; ASCIi write - sends byte in A to output channel using OSWRCH. 000000r 1 ; A CR is sent using OSCRLF i.e. will be preceded by a linefeed. 000000r 1 OSCRLF := $FFED ; Sends a LF($0A) and a CR($0D) to output channel using OSWRCH. 000000r 1 OSWRCR := $FFF2 ; WRite CR - sends carriage return ($0D) down output channel. 000000r 1 OSWRCH := $FFF4 ; WRite CHaracter - sends the byte in A down the output channel. 000000r 1 OSCLI := $FFF7 ; Command Line Interpreter - interprets a string of characters 000000r 1 ; at $0100 terminated by a CR, errors are met with a BRK. 000000r 1 ; 000000r 1 ; ASCII Control Codes 000000r 1 ; 000000r 1 CR := $0D ; Carriage Return 000000r 1 CAN := $18 ; CANcel 000000r 1 ESC := $1B ; ESCape 000000r 1 SPACE := ' ' ; space 000000r 1 DEL := $7F ; DELete 000000r 1 ; 000000r 1 .org $C000 ; Start address of System/Atom BASIC 00C000 1 ; 00C000 1 ; Tables 1 to 16 are used by PARSE1 to find 00C000 1 ; keywords, as a match is found further table 00C000 1 ; Index1 provides a link to further characters 00C000 1 ; (if any) and MSB's of routine address, LSB is 00C000 1 ; in the second part of Index 1. 00C000 1 ; 00C000 1 Table1: ; Table 1 - Comparisons: 1st characters 00C000 1 3C T1LT: .byte "<" ; '<' 1st char of '<>' INEQUA($C76D), 00C001 1 ; '<=' ILTEQU($C764), 00C001 1 ; '<' ILT($C774) 00C001 1 3D T1EQ: .byte "=" ; '=' IEQUAL($C75B) 00C002 1 3E T1GT: .byte ">" ; '>' 1st char of '>=' IGTEQU($C77B) 00C003 1 FE .byte $FE ; $FE: end of Table1, return no match 00C004 1 ; 00C004 1 Table2: ; Table 2 - Unary Operators: 1st characters 00C004 1 2D T2MI: .byte "-" ; '-' UMINUS($C8C1) 00C005 1 2B T2PL: .byte "+" ; '+' UPLUS($C8DC) 00C006 1 C8 T2a: .byte >UPLUS ; end of Table2, no match go to UPLUS($C8DC) 00C007 1 ; 00C007 1 Table3: ; Table 3 - Functions: 1st characters 00C007 1 23 T3PD: .byte "#" ; '#' HCONST($C90A) 00C008 1 28 T3OB: .byte "(" ; '(' IL_PAR($C944) 00C009 1 21 T3PG: .byte "!" ; '!' F_QEEK($C95F) 00C00A 1 3F T3QM: .byte "?" ; '?' F_PEEK($C94C) 00C00B 1 52 T3R: .byte "R" ; 'R' 1st char of 'RND'($C986) 00C00C 1 54 T3T: .byte "T" ; 'T' 1st char of 'TOP'($C973) 00C00D 1 4C T3L: .byte "L" ; 'L' 1st char of 'LEN'($C9BD) 00C00E 1 43 T3C: .byte "C" ; 'C' 1st char of 'COUNT'($C97A),'CH'($C9D2) 00C00F 1 41 T3A: .byte "A" ; 'A' 1st char of 'ABS'($C902) 00C010 1 50 T3P: .byte "P" ; 'P' 1st char of 'PTR'($CF29) 00C011 1 45 T3E: .byte "E" ; 'E' 1st char of 'EXT'($CF28) 00C012 1 47 T3G: .byte "G" ; 'G' 1st char of 'GET'($CF66) 00C013 1 42 T3B: .byte "B" ; 'B' 1st char of 'BGET'($CF5B) 00C014 1 46 T3F: .byte "F" ; 'F' 1st char of 'FIN'($CFA6),'FOUT'($CFA7) 00C015 1 .if ATOM=1 00C015 1 T3a: .byte >RDARAY ; end of Table3, no match go to RDARAY 00C015 1 .endif 00C015 1 .if SYSTEM=1 00C015 1 CA T3a: .byte >NOFUNC ; end of Table3, no match go to NOFUNC($CA24) 00C016 1 .endif 00C016 1 ; 00C016 1 Table4: ; Table 4 - Loops: 1st characters followed by MSB 00C016 1 ; of routine address 00C016 1 54 .byte "T" ; 'T' 1st char of 'TO' 00C017 1 FF T4FF: .byte $FF ; $FF 00C018 1 4F T4O: .byte "O" ; 'O' remainder of 'TO'($CB81) 00C019 1 CB T4a: .byte >TO ; TO($CB81) 00C01A 1 ; 00C01A 1 Table5: ; Table 5 - STEP: followed by MSB of routine address 00C01A 1 53 .byte "S" ; 'S' 1st char of 'STEP'($CBA2) 00C01B 1 CB T5a: .byte >STEP ; STEP($CBA2) 00C01C 1 54 45 50 T5TEP: .byte "TEP" ; 'TEP' remainder of 'STEP' 00C01F 1 CB .byte >STEP ; STEP($CBA2) 00C020 1 ; 00C020 1 Table6: ; Table 6 - THEN: followed by MSB of routine address 00C020 1 54 C3 .byte "T",>THEN ; 'T' 1st char of 'THEN'($C31B) 00C022 1 48 45 4E T6HEN: .byte "HEN" ; 'HEN' remainder of 'THEN' 00C025 1 C3 .byte >THEN ; THEN($C31B) 00C026 1 ; 00C026 1 Table7: ; Table 7 - STRING: 1st characters followed by MSB 00C026 1 ; of routine address 00C026 1 22 .byte '"' ; '"' STRLIT($CEBF) 00C027 1 24 .byte "$" ; '$' STRVAR($CEB6) 00C028 1 CE T7a: .byte >STRVAR ; >STRVAR($CEB6) 00C029 1 CE T7b: .byte >STRLIT ; >STRLIT($CEBF) 00C02A 1 CC T7c: .byte >INPSTR ; >INPSTR($CCB6) 00C02B 1 ; 00C02B 1 Table8: ; Table 8 - INPUT: 1st characters 00C02B 1 24 .byte "$" ; '$' INPSTR($CCB6) 00C02C 1 ; 00C02C 1 Table9: ; Table 9 - INPINT: 1st characters followed by MSB 00C02C 1 ; of routine address 00C02C 1 2C .byte "," ; ',' INPUT($CC81) 00C02D 1 C5 .byte >ENDCNT ; end of table, no match go to ENDCNT($C558) 00C02E 1 ; 00C02E 1 Table10: ; Table 10 - PRINT: 1st characters 00C02E 1 24 .byte "$" ; '$' PSTROP($C390) 00C02F 1 26 .byte "&" ; '&' PR_HEX($C335) 00C030 1 3B .byte ";" ; ';' PR_END($C54A) 00C031 1 0D .byte CR ; 'CR' PR_END($C54A) 00C032 1 2C .byte "," ; ',' PRINT($C334) 00C033 1 C3 .byte >PR_INT ; >PR_INT($C33F) 00C034 1 C5 T10a: .byte >PR_END ; >PR_END($C54A) 00C035 1 C2 T10b: .byte >RTN ; >RTN($C278) 00C036 1 3E C7 T10GT: .byte ">",>INEQUA ; '>' 2nd char of '<>' 00C038 1 3D C7 T10EQ1: .byte "=",>ILTEQU ; '=' 2nd char of '<=' 00C03A 1 C7 T10c: .byte >ILT ; >ILT($C774) 00C03B 1 C7 T10d: .byte >IEQUAL ; >IEQUAL($C75B) 00C03C 1 3D C7 T10EQ2: .byte "=",>IGTEQU ; '=' 2nd char of '>=' 00C03E 1 C7 T10e: .byte >IGT ; >IGT($C782) 00C03F 1 C8 T10f: .byte >UMINUS ; >UMINUS($C8C1) 00C040 1 52 C7 T10R: .byte "R",>LOR ; 'R' 1st char of LOR($C722) 00C042 1 C7 T10g: .byte >STRCMP ; >STRCMP($C731) 00C043 1 ; 00C043 1 Table11: ; Table 11 - Logical Relationships: 2nd 00C043 1 ; character(s) followed by MSB of routine address 00C043 1 4F .byte "O" ; 'O' 1st char of 'OR' 00C044 1 41 .byte "A" ; 'A' 1st char of 'AND' 00C045 1 FE T11end: .byte $FE ; $FE: end of table, return no match 00C046 1 ; 00C046 1 Table12: ; Table 12 - String or Integer followed by MSB of 00C046 1 ; routine address 00C046 1 24 C7 .byte "$",>INTCMP ; '$' INTCMP($C753) 00C048 1 ; 00C048 1 48 C9 T12H: .byte "H",>CH ; 'H' remainder of 'CH' CH($C9D2) 00C04A 1 45 4E C9 T12fN: .byte "EN",>LEN ; 'EN' remainder of 'LEN'($C9BD) 00C04D 1 4E 44 C7 T12ND1: .byte "ND",>LAND ; 'ND' remainder of 'LAND'($C714) 00C050 1 C9 T12a: .byte >HCONST ; >HCONST($C90A) 00C051 1 C9 T12b: .byte >IL_PAR ; >IL_PAR($C944) 00C052 1 C9 T12c: .byte >F_QEEK ; >F_QEEK($C94C) 00C053 1 C9 T12d: .byte >F_PEEK ; >F_PEEK($C94C) 00C054 1 4E 44 C9 T12ND2: .byte "ND",>RND ; 'ND' remainder of 'RND'($C986) 00C057 1 4F 50 C9 T12OP: .byte "OP",>TOPv ; 'OP' remainder of 'TOP'($C973) 00C05A 1 4F 55 4E 54 T12OUN: .byte "OUNT",>COUNT ; 'OUNT' remainder of 'COUNT'($C97A) 00C05E 1 C9 00C05F 1 42 53 C9 T12fS: .byte "BS",>ABS ; 'BS' remainder of 'ABS($C902) 00C062 1 54 52 CF T12TR: .byte "TR",>F_PTR ; 'TR' remainder of 'PTR' F_PTR($CF29) 00C065 1 58 54 CF T12XT: .byte "XT",>EXT ; 'XT' remainder of 'EXT'($CF28) 00C068 1 45 54 CF T12fT: .byte "ET",>GET ; 'ET remainder of 'GET'($CF66) 00C06B 1 47 45 54 CF T12GET: .byte "GET",>BGET ; 'GET' remainder of 'BGET'($CF5B) 00C06F 1 49 4E CF T12IN: .byte "IN",>FIN ; 'IN' remainder of 'FIN'($CFA6) 00C072 1 4F 55 54 CF T12OUT: .byte "OUT",>FOUT ; 'OUT' remainder of 'FOUT'($CFA7) 00C076 1 C3 T12e: .byte >PSTROP ; >PSTROP($C390) 00C077 1 C3 T12f: .byte >PR_HEX ; >PR_HEX($C335) 00C078 1 52 49 4E 54 T12RIN: .byte "RINT" ; 'RINT' remainder of 'PRINT' 00C07C 1 C3 T12g: .byte >PRINT ; >PRINT($C334) 00C07D 1 ; 00C07D 1 Table13: ; Table 13 - Non-executable Basic Commands: 1st 00C07D 1 ; characters 00C07D 1 4E .byte "N" ; 'N' 1st char of 'NEW' 00C07E 1 4C .byte "L" ; 'L' 1st char of 'LIST','LOAD' 00C07F 1 ; 00C07F 1 Table14: ; Table 14 - Executable Basic Statements: 1st 00C07F 1 ; characters 00C07F 1 55 .byte "U" ; 'U' 1st char of 'UNTIL' 00C080 1 4E .byte "N" ; 'N' 1st char of 'NEXT' 00C081 1 49 .byte "I" ; 'I' 1st char of 'IF','INPUT' 00C082 1 47 .byte "G" ; 'G' 1st char of 'GOTO','GOSUB' 00C083 1 52 .byte "R" ; 'R' 1st char of 'RETURN','REM','RUN' 00C084 1 46 .byte "F" ; 'F' 1st char of 'FOR' 00C085 1 21 .byte "!" ; '!' (pling) 00C086 1 3F .byte "?" ; '?' 00C087 1 24 .byte "$" ; '$' 00C088 1 50 .byte "P" ; 'P' 1st char of 'PRINT','PTR','PUT' 00C089 1 44 .byte "D" ; 'D' 1st char of 'DO' 00C08A 1 4C .byte "L" ; 'L' 1st char of 'LET','LINK' 00C08B 1 53 .byte "S" ; 'S' 1st char of 'SGET','SPUT','SHUT','SAVE' 00C08C 1 42 .byte "B" ; 'B' 1st char of 'BPUT' 00C08D 1 2A .byte "*" ; '*' OS Call 00C08E 1 45 .byte "E" ; 'E' 1st char of 'END' 00C08F 1 .if ATOM=1 00C08F 1 T14a: .byte >WRARAY ; >WRARAY($B84B) 00C08F 1 .endif 00C08F 1 .if SYSTEM=1 00C08F 1 C5 T14a: .byte >NOSTAT ; >NOSTAT($C550) 00C090 1 .endif 00C090 1 41 56 45 CF T14bVE: .byte "AVE",>SAVE ; 'AVE' remainder of 'SAVE' SAVE($CF0A) 00C094 1 45 57 C2 T14EW: .byte "EW",>NEW ; 'EW' remainder of 'NEW' NEW($C2AD) 00C097 1 4F CC T14O: .byte "O",>DO ; 'O' remainder of 'DO'($CCF0) 00C099 1 45 54 C3 T14ET: .byte "ET",>LET ; 'ET remainder of 'LET'($C325) 00C09C 1 49 4E 4B C3 T14INK: .byte "INK",>LINK ; 'INK' remainder of 'LINK'($C3B2) 00C0A0 1 49 53 54 CA T14IST: .byte "IST",>LIST ; 'IST remainder of 'LIST'($CA51) 00C0A4 1 4F 41 44 CE T14OAD: .byte "OAD",>LOAD ; 'OAD'' remainder of 'LOAD'($CEED) 00C0A8 1 4E 54 49 4C T14NTI: .byte "NTIL",>UNTIL ; 'NTIL' remainder of 'UNTIL'($CCD2) 00C0AC 1 CC 00C0AD 1 45 58 54 CA T14EXT: .byte "EXT",>NEXT ; 'EXT' remainder of 'NEXT'($CACD) 00C0B1 1 46 C5 T14F: .byte "F",>IF ; 'F' remainder of 'IF'($C566) 00C0B3 1 4E 50 55 54 T14NPU: .byte "NPUT" ; 'NPUT' remainder of 'INPUT'($CC81) 00C0B7 1 CC T14b: .byte >INPUT ; >INPUT($CC81) 00C0B8 1 4F 53 55 42 T14OSU: .byte "OSUB",>GOSUB ; 'OSUB' remainder of 'GOSUB'($CBD2) 00C0BC 1 CB 00C0BD 1 4F 54 4F CC T14OTO: .byte "OTO",>GOTO ; 'OTO' remainder of 'GOTO'($CC05) 00C0C1 1 45 54 55 52 T14ETU: .byte "ETURN",>RETURN ; 'ETURN' remainder of 'RETURN'($CBEC) 00C0C5 1 4E CB 00C0C7 1 45 4D C5 T14EM: .byte "EM",>REM ; 'EM' remainder of 'REM'($C575) 00C0CA 1 .if ATOM=1 00C0CA 1 T14UN: .byte "UN",>NEWRUN ; 'UN' remainder of 'RUN' (NEWRUN $B941) 00C0CA 1 .endif 00C0CA 1 .if SYSTEM=1 00C0CA 1 55 4E CE T14UN: .byte "UN",>RUN ; 'UN' remainder of 'RUN'($CE83) 00C0CD 1 .endif 00C0CD 1 4F 52 CB T14OR: .byte "OR",>FOR ; 'OR' remainder of 'FOR'($CB57) 00C0D0 1 4E 44 CD T14ND: .byte "ND",>END ; 'ND' remainder of 'END'($CD98) 00C0D3 1 47 45 54 CF T14GET: .byte "GET",>SGET ; 'GET' remainder of 'SGET'($CFE3) 00C0D7 1 50 55 54 CF T14PU1: .byte "PUT",>SPUT ; 'PUT' remainder of 'SPUT' SPUT($CFC5) 00C0DB 1 48 55 54 CF T14HUT: .byte "HUT",>SHUT ; 'HUT' remainder of 'SHUT'($CFB6) 00C0DF 1 50 55 54 CF T14PU2: .byte "PUT",>BPUT ; 'PUT' remainder of 'BPUT' BPUT($CF8F) 00C0E3 1 54 52 CF T14TR: .byte "TR",>PTR ; 'TR' remainder of 'PTR'($CF47) 00C0E6 1 55 54 CF T14UT: .byte "UT",>PUT ; 'UT' remainder of 'PUT'($CF95) 00C0E9 1 C3 T14c: .byte >F_QOKE ; >F_QOKE($C3EE) 00C0EA 1 C4 T14d: .byte >F_POKE ; >F_POKE($C406) 00C0EB 1 CD T14e: .byte >STREQU ; >STREQU($CD5C) 00C0EC 1 C4 T14f: .byte >OSCOM ; >OSCOM($C40F) 00C0ED 1 ; 00C0ED 1 Table15: ; Table 15 - Comma 00C0ED 1 2C .byte "," ; ',' 00C0EE 1 FE .byte $FE ; end of Table15, no match return 00C0EF 1 ; 00C0EF 1 Index1: ; Index 1 00C0EF 1 36 .byte ' 00C0F0 1 3B .byte ' to Table 10 '=' 00C0F2 1 C0 .byte $C0 ; 00C0F3 1 ; 00C0F3 1 3F .byte UMINUS 00C0F4 1 06 .byte UPLUS 00C0F5 1 DC .byte HCONST 00C0F7 1 51 .byte IL_PAR 00C0F8 1 52 .byte F_QEEK 00C0F9 1 53 .byte F_PEEK 00C0FA 1 54 .byte RDARAY to NOFUNC to STEP to THEN to THEN to STRLIT 00C116 1 28 .byte STRVAR 00C117 1 B6 .byte ENDCNT to PSTROP 00C11E 1 77 .byte PR_HEX 00C11F 1 34 .byte PR_END 00C120 1 34 .byte PR_END 00C121 1 7C .byte PRINT 00C122 1 3F .byte PR_INT to PR_END to RTN to ' to Table 10 INEQU to IGTEQU to IGT to UMINUS to LOR to STRCMP to INTCMP to CH to LEN to LAND to HCONST to IL_PAR to F_QEEK to F_PEEK to TOPv to TOPv 00C149 1 48 .byte COUNT to ABS to PTR to EXT to GET to BGET to FIN to FOUT to PSTROP to PR_HEX to PRINT to WRARAY to NOSTAT to >NOSTAT 00C17F 1 .endif 00C17F 1 8F .byte SAVE to NEW to DO to LET to LINK to LIST to LOAD to UNTIL to EXT to IF to INPUT to INPUT 00C1A7 1 8F .byte GOSUB to GOTO to RETURN to REM to NEWRUN to RUN to FOR to END to SGET to SPUT to SHUT to BPUT to PTR to PUT to F_QOKE to STREQU to OSCOM to ISUB 00C213 1 C7 .byte >IADD 00C214 1 C7 .byte >IOR 00C215 1 C7 .byte >IEOR 00C216 1 C7 .byte >IEOR 00C217 1 C8 .byte >IMULT 00C218 1 C8 .byte >IDIV 00C219 1 C8 .byte >IMOD 00C21A 1 C8 .byte >O_QEEK 00C21B 1 C8 .byte >O_PEEK 00C21C 1 C8 .byte >IAND 00C21D 1 C8 .byte >IAND 00C21E 1 C2 .byte >RTN 00C21F 1 C2 .byte >RTN 00C220 1 C2 .byte >RTN 00C221 1 C2 .byte >RTN 00C222 1 C3 .byte >F_QOKE 00C223 1 C4 .byte >F_POKE 00C224 1 CD .byte >STREQU 00C225 1 CD .byte >STREQU 00C226 1 C3 .byte >LETEQU 00C227 1 CD .byte >O_QOKE 00C228 1 CD .byte >O_POKE 00C229 1 CD .byte >O_POKE 00C22A 1 C3 .byte >PRCRLF 00C22B 1 C3 .byte >PR_STR 00C22C 1 ; 00C22C 1 ; Get File Handle and Parse Comma 00C22C 1 20 3E CF HDLCOM: jsr GETHDL ; get file handle 00C22F 1 84 0F sty handle ; and save it, then 00C231 1 00C231 1 ; Parse Comma 00C231 1 A2 ED PARCOM: ldx #txtspc 00C2B4 1 85 12 sta txtpag ; set-up pointer to bottom page of text space, usually 00C2B6 1 ; page $3 i.e. $3000 00C2B6 1 A9 0D BASIC2: lda #CR 00C2B8 1 A4 12 ldy txtpag ; set-up TOP to point at bottom of text area 00C2BA 1 84 0E sty TOP+1 00C2BC 1 A0 00 ldy #$00 00C2BE 1 84 0D sty TOP 00C2C0 1 91 0D sta (TOP),y ; and initialise text space to CR,$FF 00C2C2 1 A9 FF lda #$FF 00C2C4 1 C8 iny 00C2C5 1 91 0D sta (TOP),y 00C2C7 1 C8 iny ; and increment TOP to free space 00C2C8 1 84 0D sty TOP 00C2CA 1 .if ATOM=1 00C2CA 1 lda #08 ; set PRINT field width to 8 00C2CA 1 .endif 00C2CA 1 .if SYSTEM=1 00C2CA 1 A9 05 lda #05 ; set PRINT field width to 5 00C2CC 1 .endif 00C2CC 1 8D 21 03 sta pwidth 00C2CF 1 A9 3E nxtcom: lda #'>' ; BASIC prompt 00C2D1 1 D8 cld 00C2D2 1 20 0F CD jsr BUFFIN ; read line of input from input channel 00C2D5 1 A2 01 ldx #$01 ; set-up text pointer 00C2D7 1 86 06 stx txtptr+1 00C2D9 1 CA dex 00C2DA 1 86 05 stx txtptr 00C2DC 1 86 01 stx baslin ; set BASIC linenumber to 0000 00C2DE 1 86 02 stx baslin+1 00C2E0 1 A9 D8 lda #ERROR 00C2E7 1 8D 03 02 sta BRKVEC+1 00C2EA 1 A9 E7 lda #errtxt 00C2F0 1 85 11 sta errptr+1 00C2F2 1 A2 FF interp: ldx #$FF ; reset processor stack 00C2F4 1 9A txs 00C2F5 1 A9 00 lda #$00 00C2F7 1 85 04 sta accptr ; reset accumulator stack pointer 00C2F9 1 85 03 sta index ; reset text pointer index 00C2FB 1 85 15 sta forcnt ; reset FOR loop counter 00C2FD 1 85 13 sta do_cnt ; reset DO loop counter 00C2FF 1 85 14 sta goscnt ; reset GOSUB counter 00C301 1 A2 34 ldx #$34 ; 26 x 2 00C303 1 9D 8C 03 clrlab: sta label-1,x ; clear label address 00C306 1 CA dex 00C307 1 D0 FA bne clrlab ; all 26 00C309 1 20 34 C4 jsr TST_IV ; was an expression entered ? 00C30C 1 B0 21 bcs evalet ; yes - evaluate it 00C30E 1 20 6A C4 jsr ICONST ; does input start with a decimal linenumber 00C311 1 90 03 bcc bascom ; no - try commands 00C313 1 4C C9 CD jmp NEWTXT ; yes - go to amend text 00C316 1 A2 7D bascom: ldx #Z, not a variable 00C445 1 E9 3F sbc #'?' 00C447 1 90 1B bcc tstrtn ; branch if 0P.",'"' 00C9EB 1 50 2E 27 22 00C9EF 1 45 72 72 6F 00C9F3 1 72 22 3F 30 00C9F7 1 3B 49 46 21 00C9FB 1 31 26 23 46 00C9FF 1 46 46 46 3C 00CA03 1 3E 30 50 2E 00CA07 1 22 00CA08 1 20 61 74 20 .byte " at line ",'"',"!1&#FFFF",CR 00CA0C 1 6C 69 6E 65 00CA10 1 20 22 21 31 00CA14 1 26 23 46 46 00CA18 1 46 46 0D 00CA1B 1 .endif 00CA1B 1 00CA1B 1 00 00 50 2E err_29: .byte $00,$00,"P.';E.",CR 00CA1F 1 27 3B 45 2E 00CA23 1 0D 00CA24 1 00CA24 1 ; No Function Found 00CA24 1 20 24 C4 NOFUNC: jsr TSTEXT ; test for Extension ROM 00CA27 1 90 F2 bcc err_29 ; Error 29 ' Unknown or missing function' 00CA29 1 6C 04 D0 jmp (EXTROM+4) ; call Extension ROM 00CA2C 1 00CA2C 1 ; Set Variable Expression 00CA2C 1 20 8B C7 SET_V: jsr IEVALU 00CA2F 1 A6 04 mova_i: ldx accptr ; move accumulator contents to 00CA31 1 CA dex ; integer variable 00CA32 1 CA dex 00CA33 1 86 04 stx accptr 00CA35 1 B4 16 ldy acc1,x 00CA37 1 B5 17 lda acc1+1,x 00CA39 1 99 21 03 sta intega-1,y 00CA3C 1 B5 26 lda acc2+1,x 00CA3E 1 99 3C 03 sta integb-1,y 00CA41 1 B5 35 lda acc3+1,x 00CA43 1 99 57 03 sta integc-1,y 00CA46 1 B5 44 lda acc4+1,x 00CA48 1 99 72 03 sta integd-1,y 00CA4B 1 60 rts 00CA4C 1 00CA4C 1 ; Write Character To Output Channel 00CA4C 1 E6 07 WRCH: inc count ; increment PRINT counter 00CA4E 1 6C 08 02 jmp (WRCVEC) ; and jump to OSWRCH 00CA51 1 ; (for some reason indirectly via its vector) 00CA51 1 00CA51 1 ; LIST Command 00CA51 1 LIST: 00CA51 1 .if SYSTEM=1 00CA51 1 A9 05 lda #$05 00CA53 1 8D 21 03 sta pwidth ; set field width to 5 00CA56 1 .endif 00CA56 1 A9 00 lda #$00 00CA58 1 20 7C C9 jsr byte_a ; accumulator 0 = 0 (lowest linenumber) 00CA5B 1 A9 FF lda #$FF 00CA5D 1 20 7C C9 jsr byte_a ; accumulator 1 = $FF 00CA60 1 85 04 sta accptr ; accumulator stack pointer = 0 00CA62 1 A0 7F ldy #$7F 00CA64 1 84 26 sty acc2+1 ; accumulator 1 = $7FFF (highest linenumber) 00CA66 1 20 65 C4 jsr LSTPAR ; extract first parameter 00CA69 1 90 4D bcc npara1 ; if carry clear - no parameter 00CA6B 1 20 31 C2 jsr PARCOM ; check for delimiter comma 00CA6E 1 B0 53 bcs npara2 ; carry set if none present 00CA70 1 20 65 C4 jsr LSTPAR ; extract second parameter 00CA73 1 A2 01 dolist: ldx #$01 00CA75 1 86 04 stx accptr ; accumulator stack pointer = 1 00CA77 1 20 E4 C4 jsr ENDTST ; check for end of command 00CA7A 1 20 2E C6 jsr FNDLNS ; search for line from start of text 00CA7D 1 90 2B bcc linfnd ; line found ? - list from it 00CA7F 1 88 dey 00CA80 1 B0 1C bcs noline ; line not found - list from next line 00CA82 1 lislin: 00CA82 1 .if ATOM=1 00CA82 1 lda #$05 00CA82 1 sta $0321 00CA82 1 jsr PR_ACC ; output linenumber 00CA82 1 lda #$08 00CA82 1 sta $0321 ; and a space 00CA82 1 .endif 00CA82 1 .if SYSTEM=1 00CA82 1 20 89 C5 jsr PR_ACC ; output linenumber 00CA85 1 A9 20 lda #SPACE 00CA87 1 20 4C CA jsr WRCH ; and a space 00CA8A 1 .endif 00CA8A 1 A4 03 ldy index ; retrieve text pointer index 00CA8C 1 B1 58 outlin: lda (bwork+6),y ; output line of text 00CA8E 1 C9 0D cmp #CR 00CA90 1 F0 06 beq linend ; until CR found 00CA92 1 20 4C CA jsr WRCH 00CA95 1 C8 iny 00CA96 1 D0 F4 bne outlin 00CA98 1 20 54 CD linend: jsr CRLF ; output CRLF at end of line 00CA9B 1 20 A1 CE jsr ADDYW6 ; add Y to pointer 00CA9E 1 B1 58 noline: lda (bwork+6),y ; set linenumber of next line 00CAA0 1 85 25 sta acc2 00CAA2 1 C8 iny 00CAA3 1 B1 58 lda (bwork+6),y 00CAA5 1 85 16 sta acc1 00CAA7 1 C8 iny 00CAA8 1 84 03 sty index ; save pointer index 00CAAA 1 A5 16 linfnd: lda acc1 ; subtract final linenumber from present 00CAAC 1 18 clc 00CAAD 1 E5 17 sbc acc1+1 00CAAF 1 A5 25 lda acc2 00CAB1 1 E5 26 sbc acc2+1 00CAB3 1 90 CD bcc lislin ; continue if more lines to go, otherwise 00CAB5 1 4C CF C2 jmp nxtcom ; return to immediate mode 00CAB8 1 20 31 C2 npara1: jsr PARCOM ; no 1st parameter parse delimiter comma 00CABB 1 E6 04 inc accptr ; increment accumulator stack pointer 00CABD 1 20 65 C4 jsr LSTPAR ; and extract second parameter (if any) 00CAC0 1 4C 73 CA jmp dolist ; proceed to LIST 00CAC3 1 A5 16 npara2: lda acc1 ; only 1 parameter given 00CAC5 1 A4 25 ldy acc2 ; i.e. list one line 00CAC7 1 85 17 sta acc1+1 ; set to and from linenumber to that line 00CAC9 1 84 26 sty acc2+1 00CACB 1 B0 A6 bcs dolist ; proceed to LIST line 00CACD 1 00CACD 1 ; NEXT statement 00CACD 1 20 34 C4 NEXT: jsr TST_IV ; was an expression entered ? 00CAD0 1 A4 15 ldy forcnt ; load FOR loop counter 00CAD2 1 F0 10 beq err230 ; have there been any FORs ? - Error 230 'Next without matching FOR' 00CAD4 1 90 0F bcc dostep ; if no variable specified carry on 00CAD6 1 C6 04 dec accptr 00CAD8 1 B5 15 lda forcnt,x ; load specified variable 00CADA 1 D9 3F 02 tst_v: cmp forvar-1,y ; compare with FOR variable 00CADD 1 F0 06 beq dostep ; if a match do NEXT 00CADF 1 88 dey 00CAE0 1 84 15 sty forcnt 00CAE2 1 D0 F6 bne tst_v ; try previous loop for match 00CAE4 1 00 err230: brk ; Error 230 'NEXT without matching FOR' 00CAE5 1 BE 3F 02 dostep: ldx forvar-1,y ; load loop variable 00CAE8 1 18 clc 00CAE9 1 BD 21 03 lda intega-1,x ; add STEP to variable 00CAEC 1 79 4E 02 adc stepa-1,y ; also put result in bwork 00CAEF 1 9D 21 03 sta intega-1,x 00CAF2 1 85 52 sta bwork 00CAF4 1 BD 3C 03 lda integb-1,x 00CAF7 1 79 5D 02 adc stepb-1,y 00CAFA 1 9D 3C 03 sta integb-1,x 00CAFD 1 85 53 sta bwork+1 00CAFF 1 BD 57 03 lda integc-1,x 00CB02 1 79 6C 02 adc stepc-1,y 00CB05 1 9D 57 03 sta integc-1,x 00CB08 1 85 54 sta bwork+2 00CB0A 1 BD 72 03 lda integd-1,x 00CB0D 1 79 7B 02 adc stepd-1,y 00CB10 1 9D 72 03 sta integd-1,x 00CB13 1 AA tax 00CB14 1 A5 52 lda bwork ; check if past TO parameter 00CB16 1 38 sec ; by subtracting TO from bwork 00CB17 1 F9 8A 02 sbc fortoa-1,y 00CB1A 1 85 52 sta bwork 00CB1C 1 A5 53 lda bwork+1 00CB1E 1 F9 99 02 sbc fortob-1,y 00CB21 1 85 53 sta bwork+1 00CB23 1 A5 54 lda bwork+2 00CB25 1 F9 A8 02 sbc fortoc-1,y 00CB28 1 85 54 sta bwork+2 00CB2A 1 8A txa 00CB2B 1 F9 B7 02 sbc fortod-1,y 00CB2E 1 05 52 ora bwork 00CB30 1 05 53 ora bwork+1 00CB32 1 05 54 ora bwork+2 00CB34 1 F0 0F beq loop ; variable = TO ? 00CB36 1 8A txa 00CB37 1 59 7B 02 eor stepd-1,y ; check is past TO parameter 00CB3A 1 59 B7 02 eor fortod-1,y 00CB3D 1 10 04 bpl testto 00CB3F 1 B0 04 bcs loop 00CB41 1 90 0F bcc endlop 00CB43 1 B0 0D testto: bcs endlop 00CB45 1 B9 C6 02 loop: lda forskl-1,y ; if not keep looping 00CB48 1 85 05 sta txtptr ; load address after FOR TO statement 00CB4A 1 B9 D5 02 lda forskm-1,y ; as text pointer 00CB4D 1 85 06 sta txtptr+1 00CB4F 1 4C FF CB jmp rstcon ; reset pointer index and continue execution 00CB52 1 C6 15 endlop: dec forcnt ; end of loop - decrement FOR counter 00CB54 1 4C 58 C5 jmp ENDCNT ; and continue execution 00CB57 1 00CB57 1 ; FOR Statement 00CB57 1 20 34 C4 FOR: jsr TST_IV ; was an expression entered ? 00CB5A 1 90 11 bcc ERR111+1 ; Error 111 'Missing variable in FOR' 00CB5C 1 20 79 C2 jsr PAREQU ; check for equals 00CB5F 1 20 2C CA jsr SET_V ; set FOR variable to following expression 00CB62 1 98 tya ; put variable in A 00CB63 1 A4 15 ldy forcnt 00CB65 1 .if ATOM=1 00CB65 1 cpy #$0B ; check number of FOR loops 00CB65 1 .endif 00CB65 1 .if SYSTEM=1 00CB65 1 C0 0F cpy #$0F ; check number of FOR loops 00CB67 1 .endif 00CB67 1 B0 04 bcs ERR111+1 ; Error 111 'Too many FOR statements' 00CB69 1 99 40 02 sta forvar,y ; save FOR variable 00CB6C 1 A9 00 ERR111: lda #$00 00CB6E 1 99 7C 02 sta stepd,y ; set STEP to 1 as default 00CB71 1 99 6D 02 sta stepc,y 00CB74 1 99 5E 02 sta stepb,y 00CB77 1 A9 01 lda #$01 00CB79 1 99 4F 02 sta stepa,y 00CB7C 1 A2 16 ldx #BASIC1 00CF1F 1 85 57 sta bwork+5 00CF21 1 18 clc ; do not wait for completion 00CF22 1 20 DD FF jsr OSSAVE ; do save 00CF25 1 4C 5B C5 jmp cont_x ; and continue execution 00CF28 1 00CF28 1 ; EXT Function 00CF28 1 38 EXT: sec 00CF29 1 ; PTR Function 00CF29 1 A9 00 F_PTR: lda #$00 00CF2B 1 2A rol a ; rotate carry flag into A to get 0 or 1 00CF2C 1 48 pha 00CF2D 1 20 3E CF jsr GETHDL ; get file handle 00CF30 1 A2 52 ldx #bwork ; point X at result location 00CF32 1 68 pla 00CF33 1 20 DA FF jsr OSRDAR ; get specified argument 00CF36 1 A0 52 ldy #bwork ; point Y at result 00CF38 1 20 9F C9 jsr MOVY_A ; and move to accumulator 00CF3B 1 95 42 sta acc4-1,x 00CF3D 1 60 rts 00CF3E 1 00CF3E 1 ; Get File Handle 00CF3E 1 20 BC C8 GETHDL: jsr GETINT ; get integer 00CF41 1 B4 15 SETHDL: ldy acc1-1,x ; put in Y for DOS routines 00CF43 1 CA dex ; decrement and save accumulator 00CF44 1 86 04 stx accptr ; stack pointer 00CF46 1 60 rts ; and return 00CF47 1 00CF47 1 ; PTR Statement 00CF47 1 20 BC C8 PTR: jsr GETINT ; get integer 00CF4A 1 20 DE C4 jsr EQUEXP 00CF4D 1 20 CB C3 jsr MOVA_W ; get file pointer into bwork 00CF50 1 20 41 CF jsr SETHDL ; get file handle 00CF53 1 A2 52 ldx #bwork ; point X at file pointer 00CF55 1 20 D7 FF jsr OSSTAR ; set file pointer 00CF58 1 4C 5B C5 jmp cont_x ; and continue execution 00CF5B 1 00CF5B 1 ; BGET Function 00CF5B 1 20 3E CF BGET: jsr GETHDL ; get file handle 00CF5E 1 84 52 sty bwork ; set-up file handle 00CF60 1 20 D4 FF jsr OSBGET ; get byte from file 00CF63 1 4C 7C C9 jmp byte_a ; and continue execution 00CF66 1 00CF66 1 ; GET Function 00CF66 1 20 5B CF GET: jsr BGET ; use BGET for first byte 00CF69 1 A4 52 ldy bwork 00CF6B 1 20 D4 FF jsr OSBGET ; then get remaining 3 bytes 00CF6E 1 95 24 sta acc2-1,x 00CF70 1 20 D4 FF jsr OSBGET 00CF73 1 95 33 sta acc3-1,x 00CF75 1 20 D4 FF jsr OSBGET 00CF78 1 95 42 sta acc4-1,x 00CF7A 1 60 rts 00CF7B 1 00CF7B 1 ; Do PUT 00CF7B 1 20 BC C8 DO_PUT: jsr GETINT ; get value to PUT 00CF7E 1 20 31 C2 jsr PARCOM ; check for delimiter ',' 00CF81 1 20 E1 C4 jsr EXPEND ; and final parameter 00CF84 1 20 CB C3 jsr MOVA_W 00CF87 1 20 41 CF jsr SETHDL ; get file handle 00CF8A 1 A5 52 lda bwork 00CF8C 1 6C 16 02 jmp (BPTVEC) ; and send byte 00CF8F 1 00CF8F 1 ; BPUT Statement 00CF8F 1 20 7B CF BPUT: jsr DO_PUT ; PUT byte 00CF92 1 4C 5B C5 putrtn: jmp cont_x ; and continue execution 00CF95 1 00CF95 1 ; PUT Statement 00CF95 1 20 7B CF PUT: jsr DO_PUT ; use BPUT for first byte 00CF98 1 A2 01 ldx #$01 00CF9A 1 B5 52 put_4: lda bwork,x 00CF9C 1 20 D1 FF jsr OSBPUT ; then send 3 remaining bytes 00CF9F 1 E8 inx 00CFA0 1 E0 04 cpx #$04 00CFA2 1 90 F6 bcc put_4 00CFA4 1 B0 EC bcs putrtn ; and return 00CFA6 1 00CFA6 1 ; FIN Function 00CFA6 1 38 FIN: sec 00CFA7 1 ; FOUT Function 00CFA7 1 08 FOUT: php 00CFA8 1 20 B1 CE jsr STRING ; get filename 00CFAB 1 A2 52 ldx #bwork ; point X at I/O table 00CFAD 1 28 plp ; retrieve exist flag 00CFAE 1 20 CE FF jsr OSFIND ; find file 00CFB1 1 A6 04 ldx accptr ; retrieve accumulator stack pointer 00CFB3 1 4C 7C C9 jmp byte_a ; return handle, in A, in accumulator 00CFB6 1 00CFB6 1 ; SHUT Statement 00CFB6 1 20 BC C8 SHUT: jsr GETINT ; get file handle 00CFB9 1 20 E4 C4 jsr ENDTST ; test for end of statement 00CFBC 1 20 41 CF jsr SETHDL ; set file handle 00CFBF 1 20 CB FF jsr OSSHUT ; shut file 00CFC2 1 4C 5B C5 s_cont: jmp cont_x ; and continue 00CFC5 1 00CFC5 1 ; SPUT Statement 00CFC5 1 20 2C C2 SPUT: jsr HDLCOM ; get file handle 00CFC8 1 20 B1 CE jsr STRING ; and string to PUT 00CFCB 1 20 E4 C4 jsr ENDTST ; test for end of statement 00CFCE 1 88 dey ; Y=0 00CFCF 1 B1 52 putstr: lda (bwork),y ; read string 00CFD1 1 84 55 sty bwork+3 ; save string pointer 00CFD3 1 A4 0F ldy handle ; retrieve file handle 00CFD5 1 48 pha 00CFD6 1 20 D1 FF jsr OSBPUT ; send character 00CFD9 1 68 pla 00CFDA 1 C9 0D cmp #CR ; was it end of string, CR ? 00CFDC 1 F0 E4 beq s_cont ; yes - continue next statement 00CFDE 1 A4 55 ldy bwork+3 ; no - retrieve string pointer 00CFE0 1 C8 iny 00CFE1 1 D0 EC bne putstr ; and get next character 00CFE3 1 00CFE3 1 ; SGET Statement 00CFE3 1 20 2C C2 SGET: jsr HDLCOM ; get file handle 00CFE6 1 20 E1 C4 jsr EXPEND ; and string address 00CFE9 1 20 CB C3 jsr MOVA_W ; move address to bwork 00CFEC 1 A0 00 ldy #$00 00CFEE 1 84 55 getstr: sty bwork+3 00CFF0 1 A4 0F ldy handle ; retrieve file handle 00CFF2 1 20 D4 FF jsr OSBGET ; read character 00CFF5 1 A4 55 ldy bwork+3 ; save file handle 00CFF7 1 91 52 sta (bwork),y ; save character 00CFF9 1 C8 iny 00CFFA 1 C9 0D cmp #CR ; end of string, CR ? 00CFFC 1 D0 F0 bne getstr ; no - get next character 00CFFE 1 F0 C2 beq s_cont ; yes - continue next statement 00D000 1 00D000 1 .if ATOM=1 00D000 1 .org $F000 ; Start address of Atom OS ROM 00D000 1 ; 00D000 1 EXTRA: .byte "PLOT",>PLOT,DRAW,MOVE,CLEAR,DIM,ASSEM,OLD,WAIT,NOSTAT, 00D000 1 ; Draw a line in white to absolute position , 00D000 1 DRAW: ldx #$05 ; DRAW is the same as PLOT 5 (k=5) 00D000 1 bne savmod ; branch always 00D000 1 00D000 1 ; MOVE Statement 00D000 1 ; syntax: 00D000 1 ; Move to absolute postion , 00D000 1 MOVE: ldx #$0C ; MOVE is the same as PLOT 12 (k=12) 00D000 1 savmod: stx acc1 ; 00D000 1 inc accptr 00D000 1 bne doplot ; branch always 00D000 1 00D000 1 ; PLOT Statement 00D000 1 ; syntax: 00D000 1 ; Depending on the value of PLOT will move or draw a line or point: 00D000 1 ; k=0: move relative to last position 00D000 1 ; k=1: draw line in white relative to last position 00D000 1 ; k=2: invert line relative to last position 00D000 1 ; k=3: draw line in black relative to last position 00D000 1 ; k=4: move to absolute position 00D000 1 ; k=5: draw white line to absolute position 00D000 1 ; k=6: invert line to absolute position 00D000 1 ; k=7: draw black line to absolute position 00D000 1 ; k=8: move relative to last position 00D000 1 ; k=9: plot white point relative to last position 00D000 1 ; k=10: invert point relative to last position 00D000 1 ; k=11: plot black point relative to last position 00D000 1 ; k=12: move relative to last position 00D000 1 ; k=13: plot white point at absolute position 00D000 1 ; k=14: invert white point at absolute position 00D000 1 ; k=15: plot black point at absolute position 00D000 1 PLOT: jsr GETINT ; get (integer constant, variable or expression) 00D000 1 jsr PARCOM ; parse seperating comma 00D000 1 00D000 1 doplot: jsr GETINT ; get (integer constant, variable or expression) 00D000 1 jsr PARCOM ; parse seperating comma 00D000 1 jsr GETINT ; get (integer constant, variable or expression) 00D000 1 jsr ENDTST ; test for end of statement 00D000 1 lda $15,x ; get LSB of 3rd parameter 00D000 1 sta Y1L ; and store at Y1L 00D000 1 lda $24,x ; get MSB of 3rd parameter 00D000 1 sta Y1M ; and store at Y1M 00D000 1 00D000 1 lda $14,x ; get LSB of 2nd parameter 00D000 1 sta X1L ; and store at X1L 00D000 1 lda $23,x ; get MSB of 2nd parameter 00D000 1 sta X1M ; and store at X1M 00D000 1 00D000 1 ldx #$00 ; reset accumulator stack pointer 00D000 1 stx accptr 00D000 1 ldx #$03 ; retrieve old X and Y coordinates 00D000 1 ld_old: lda old_xl,x ; Y0 and X0 00D000 1 sta X0L,x 00D000 1 dex 00D000 1 bpl ld_old 00D000 1 lda $16 ; get 00D000 1 and #$04 ; absolute or relative position ? 00D000 1 bne abs ; branch if absolute 00D000 1 ldx #$02 ; yes - new X and Y relative coordinates 00D000 1 addrel: clc ; to old coordinates 00D000 1 lda X1L,x 00D000 1 adc X0L,x 00D000 1 sta X1L,x 00D000 1 lda X1M,x 00D000 1 adc X0M,x 00D000 1 sta X1M,x 00D000 1 dex 00D000 1 dex 00D000 1 bpl addrel ; both X and Y coordinates 00D000 1 abs: ldx #$03 ; save new X,Y coordinates for PLOT 00D000 1 wr_old: lda X1L,x 00D000 1 sta old_xl,x 00D000 1 dex 00D000 1 bpl wr_old 00D000 1 lda acc1 ; test PLOTing mode 00D000 1 and #$03 00D000 1 beq endplt ; if MOVE mode - finished 00D000 1 sta bwork+$C 00D000 1 lda acc1 00D000 1 and #$08 00D000 1 beq DODRAW ; if DRAW branch to do DRAW 00D000 1 jsr DOPLOT ; alter single pixel only and 00D000 1 endplt: jmp cont_x ; continue execution 00D000 1 00D000 1 ; Draw Line 00D000 1 DODRAW: ldx #$02 00D000 1 nxtdif: sec ; calculate X and Y differences 00D000 1 lda X1L,x 00D000 1 sbc X0L,x 00D000 1 ldy X0L,x 00D000 1 sty X1L,x 00D000 1 sta X0L,x 00D000 1 ldy X0M,x 00D000 1 lda X1M,x 00D000 1 sbc X0M,x 00D000 1 sty X1M,x 00D000 1 sta X0M,x 00D000 1 sta xdir,x ; save PLOT direction 00D000 1 bpl posdif 00D000 1 lda #$00 ; if direction negative, negate 00D000 1 sec ; to get magnitude of difference 00D000 1 sbc X0L,x 00D000 1 sta X0L,x 00D000 1 lda #$00 00D000 1 sbc X0M,x 00D000 1 sta X0M,x 00D000 1 posdif: dex 00D000 1 dex 00D000 1 bpl nxtdif ; do for both X and Y 00D000 1 lda Y0L ; which direction has largest change ? 00D000 1 cmp X0L 00D000 1 lda Y0M 00D000 1 sbc X0M 00D000 1 bcc x_gt_y 00D000 1 lda #$00 ; Y greater than X 00D000 1 sbc Y0L ; set up plot counter 00D000 1 sta pltcnt 00D000 1 lda #$00 00D000 1 sbc Y0M 00D000 1 sec 00D000 1 ror a 00D000 1 sta pltcnt+2 00D000 1 ror pltcnt 00D000 1 nxplta: jsr DOPLOT ; plot next point 00D000 1 lda Y1L ; compare present Y with final value 00D000 1 cmp old_yl 00D000 1 bne add_y 00D000 1 lda Y1M 00D000 1 cmp old_ym 00D000 1 bne add_y 00D000 1 drwend: jmp cont_x ; if end - continue execution 00D000 1 add_y: jsr INYDEY ; increment/decrement Y coordinate 00D000 1 lda pltcnt+2 ; test MSB of counter 00D000 1 bmi nxplta ; do we need to change X ? 00D000 1 jsr INXDEX ; yes 00D000 1 jmp nxplta ; then plot next point 00D000 1 x_gt_y: lda X0M ; X greater than Y 00D000 1 lsr a ; set-up plot counter 00D000 1 sta pltcnt+2 00D000 1 lda X0L 00D000 1 ror a 00D000 1 sta pltcnt 00D000 1 nxpltb: jsr DOPLOT ; plot next point 00D000 1 lda X1L ; compare present X with final value 00D000 1 cmp old_xl 00D000 1 bne add_x 00D000 1 lda X1M 00D000 1 cmp old_xm 00D000 1 beq drwend ; if end - branch to continue execution 00D000 1 add_x: jsr INXDEX ; increment/decrement X coordinate 00D000 1 lda pltcnt+2 ; test MSB of counter 00D000 1 bpl nxpltb ; do we need to change Y ? 00D000 1 jsr INYDEY ; yes 00D000 1 jmp nxpltb ; then plot next point 00D000 1 00D000 1 ; Alter X Coordinate 00D000 1 INXDEX: sec 00D000 1 lda pltcnt ; subtract magnitude of Y from counter 00D000 1 sbc Y0L 00D000 1 sta pltcnt 00D000 1 lda pltcnt+2 00D000 1 sbc Y0M 00D000 1 sta pltcnt+2 00D000 1 ldx #$00 ; point at X coordinate 00D000 1 beq tstdir 00D000 1 00D000 1 ; Alter Y Coordinate 00D000 1 INYDEY: clc 00D000 1 lda pltcnt ; add magnitude of X to counter 00D000 1 adc X0L 00D000 1 sta pltcnt 00D000 1 lda pltcnt+2 00D000 1 adc X0M 00D000 1 sta pltcnt+2 00D000 1 ldx #$02 ; point at Y 00D000 1 tstdir: lda xdir,x ; which direction are we plotting in ? 00D000 1 bpl incord 00D000 1 lda X1L,x ; down - decrement coordinate 00D000 1 bne ndecrd 00D000 1 dec X1M,x 00D000 1 ndecrd: dec X1L,x 00D000 1 incrtn: rts 00D000 1 incord: inc X1L,x ; up - increment coordinate 00D000 1 bne incrtn 00D000 1 inc X1M,x 00D000 1 rts 00D000 1 00D000 1 DOPLOT: jmp (ploter) ; ?? 00D000 1 00D000 1 ; CLEAR Statement 00D000 1 CLEAR: jsr GETI_W ; get argument into work 00D000 1 err129a:ldy #$00 00D000 1 lda X0L 00D000 1 beq clear0 ; CLEAR 0 is special case 00D000 1 cmp #$05 00D000 1 bcc clr_ok ; if argument greater than 4 set to 4 00D000 1 lda #$04 00D000 1 clr_ok: ldx #>screna 00D000 1 stx Y0L ; point work+1 at start of screen RAM 00D000 1 sty X0M 00D000 1 sta X0L ; save graphics mode 00D000 1 tax 00D000 1 lda SCRTOP-1,x ; read address of top of new screen 00D000 1 ldx BOTTOM ; does it clash with text area ? 00D000 1 bpl notext 00D000 1 cmp BOTTOM 00D000 1 bcs err129a+1 ; Error 129 'Protected RAM in graphics mode' 00D000 1 notext: tax ; move MSB of top to X 00D000 1 tya ; A=0, all pixels off 00D000 1 do_clr: sta (X0M),y ; clear screen 00D000 1 dey 00D000 1 bne do_clr 00D000 1 inc Y0L ; increment MSB pointer 00D000 1 cpx Y0L ; compare with top of screen 00D000 1 bne do_clr 00D000 1 setplt: ldy X0L ; set-up PLOT routine address 00D000 1 lda PLOT_M,y 00D000 1 sta ploter+1 00D000 1 lda PLOT_L,y 00D000 1 sta ploter 00D000 1 lda MODE,y 00D000 1 sta IC25A ; load CRTC with control byte (set graphics mode ??) 00D000 1 jmp ENDCNT ; test end of statement, continue execution 00D000 1 clear0: lda #$40 ; CLEAR 0 - fill screen with graphic spaces 00D000 1 c0_fil: sta screna,y 00D000 1 sta screnb,y 00D000 1 dey 00D000 1 bne c0_fil 00D000 1 beq setplt ; and set-up PLOT address and CRTC 00D000 1 00D000 1 SCRTOP: .byte $84,$86,$8C,$98 ; MSB of Screen TOP Addresses 00D000 1 00D000 1 PLOT_L: .byte PLOT_0,>PLOT_1,>PLOT_2,>PLOT_3,>PLOT_4 ; MSB of PLOT Routines 00D000 1 00D000 1 MODE: .byte $00,$30,$70,$B0,$F0 ; control bytes for CRTC 00D000 1 00D000 1 ; Plotter Graphics Mode 0 00D000 1 PLOT_0: lda X1M 00D000 1 ora Y1M 00D000 1 bne p0_rtn ; return if off screen 00D000 1 lda X1L ; check range of X (0-63) 00D000 1 cmp #$40 00D000 1 bcs p0_rtn ; return if too large 00D000 1 lsr a ; divide by 2 for column 00D000 1 sta pixadr 00D000 1 lda #$2F ; negate Y coordinate 00D000 1 sec 00D000 1 sbc Y1L 00D000 1 cmp #$30 ; and check range (0-47) 00D000 1 bcs p0_rtn ; return if too large 00D000 1 ldx #$FF 00D000 1 sec 00D000 1 div_y3: inx ; divide Y coordinate by 3 00D000 1 sbc #$03 00D000 1 bcs div_y3 00D000 1 adc #$03 00D000 1 sta y_pos ; save pixel Y position within character 00D000 1 txa 00D000 1 asl a ; multiply character row by 32 00D000 1 asl a 00D000 1 asl a 00D000 1 asl a 00D000 1 asl a 00D000 1 ora pixadr ; OR in column 00D000 1 sta pixadr ; to give LSB of address 00D000 1 lda #$80 ; add screen base address 00D000 1 adc #$00 ; and carry 00D000 1 sta pixadr+1 ; to give MSB of address 00D000 1 lda X1L ; work out pixel position within character 00D000 1 lsr a 00D000 1 lda y_pos 00D000 1 rol a 00D000 1 tay 00D000 1 lda PIXEL+2,y ; load pixel bit 00D000 1 ALTPIX: ldy #$00 00D000 1 ldx bwork+$C ; test 'colour' - set, reset or invert 00D000 1 dex 00D000 1 beq set 00D000 1 dex 00D000 1 beq invert 00D000 1 eor #$FF ; reset - invert bit pattern 00D000 1 and (pixadr),y ; and AND with screen 00D000 1 sta (pixadr),y 00D000 1 rts 00D000 1 invert: eor (pixadr),y ; invert - EOR bit pattern with screen 00D000 1 sta (pixadr),y 00D000 1 rts 00D000 1 set: ora (pixadr),y ; set - OR bit pattern with screen 00D000 1 sta (pixadr),y 00D000 1 p0_rtn: rts 00D000 1 00D000 1 ; Plotter Graphics Mode 1 00D000 1 PLOT_1: lda X1M 00D000 1 ora Y1M 00D000 1 bne p0_rtn ; return if off screen 00D000 1 lda X1L ; check range of X (0-127) 00D000 1 bmi p0_rtn 00D000 1 lsr A ; divide by 8 - calculate column 00D000 1 lsr A 00D000 1 lsr A 00D000 1 sta pixadr 00D000 1 lda #$3F ; negate Y coordinate 00D000 1 sec 00D000 1 sbc Y1L 00D000 1 cmp #$40 ; and check range (0-63) 00D000 1 bcc shft4y ; continue with plotting 00D000 1 rts 00D000 1 00D000 1 ; Plotter Graphics Mode 2 00D000 1 PLOT_2: lda X1M 00D000 1 ora Y1M 00D000 1 bne p0_rtn ; if off screen return 00D000 1 lda X1L 00D000 1 bmi p0_rtn ; check range of X (0-127) 00D000 1 lsr a ; divide by 8 - calculate column 00D000 1 lsr a 00D000 1 lsr a 00D000 1 sta pixadr 00D000 1 lda #$5F ; negate Y coordinate 00D000 1 sec 00D000 1 sbc Y1L 00D000 1 cmp #$60 ; and check range (0-95) 00D000 1 bcc shft4y ; continue with plotting 00D000 1 p2_rtn: rts 00D000 1 00D000 1 ; Plotter Graphics Mode 3 00D000 1 PLOT_3: lda X1M 00D000 1 ora Y1M 00D000 1 bne p0_rtn ; return if off screen 00D000 1 lda X1L 00D000 1 bmi p0_rtn ; check range of X (0-127) 00D000 1 lsr a ; divide by 8 - calculate column 00D000 1 lsr a 00D000 1 lsr a 00D000 1 sta pixadr 00D000 1 lda #$BF ; negate Y coordinate 00D000 1 sec 00D000 1 sbc Y1L 00D000 1 cmp #$C0 00D000 1 bcs p0_rtn ; and check range (0-191) 00D000 1 shft4y: ldy #$00 ; clear MSB of pixel address 00D000 1 sty pixadr+1 00D000 1 shfy5y: asl a ; shift 4 bits of Y into MSB 00D000 1 rol pixadr+1 00D000 1 asl a 00D000 1 rol pixadr+1 00D000 1 asl a 00D000 1 rol pixadr+1 00D000 1 asl a 00D000 1 rol pixadr+1 00D000 1 adc pixadr ; add column to remaining bite of Y 00D000 1 sta pixadr 00D000 1 lda pixadr+1 00D000 1 adc #$80 ; NOT