Fully Commented Commodore 64 ROM Disassembly (English)

revision 2aa642c

 CBMBASIC and KERNAL

 The comments have been taken from
    The almost completely commented C64 ROM disassembly. V1.01 Lee Davison 2012

 The ROM is the 901227-03 version ($FF80 = 3).

 Converted and formatted by Michael Steil <mist64@mac.com>

 Corrections (typos, formatting, content) welcome at:
 https://github.com/mist64/c64rom


start of the BASIC ROM

.:A000 94 E3                    BASIC cold start entry point
.:A002 7B E3                    BASIC warm start entry point

.:A004 43 42 4D 42 41 53 49 43  '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
.:A00C 30 A8                    perform END     $80
.:A00E 41 A7                    perform FOR     $81
.:A010 1D AD                    perform NEXT    $82
.:A012 F7 A8                    perform DATA    $83
.:A014 A4 AB                    perform INPUT#  $84
.:A016 BE AB                    perform INPUT   $85
.:A018 80 B0                    perform DIM     $86
.:A01A 05 AC                    perform READ    $87
.:A01C A4 A9                    perform LET     $88
.:A01E 9F A8                    perform GOTO    $89
.:A020 70 A8                    perform RUN     $8A
.:A022 27 A9                    perform IF      $8B
.:A024 1C A8                    perform RESTORE $8C
.:A026 82 A8                    perform GOSUB   $8D
.:A028 D1 A8                    perform RETURN  $8E
.:A02A 3A A9                    perform REM     $8F
.:A02C 2E A8                    perform STOP    $90
.:A02E 4A A9                    perform ON      $91
.:A030 2C B8                    perform WAIT    $92
.:A032 67 E1                    perform LOAD    $93
.:A034 55 E1                    perform SAVE    $94
.:A036 64 E1                    perform VERIFY  $95
.:A038 B2 B3                    perform DEF     $96
.:A03A 23 B8                    perform POKE    $97
.:A03C 7F AA                    perform PRINT#  $98
.:A03E 9F AA                    perform PRINT   $99
.:A040 56 A8                    perform CONT    $9A
.:A042 9B A6                    perform LIST    $9B
.:A044 5D A6                    perform CLR     $9C
.:A046 85 AA                    perform CMD     $9D
.:A048 29 E1                    perform SYS     $9E
.:A04A BD E1                    perform OPEN    $9F
.:A04C C6 E1                    perform CLOSE   $A0
.:A04E 7A AB                    perform GET     $A1
.:A050 41 A6                    perform NEW     $A2

action addresses for functions

.:A052 39 BC                    perform SGN     $B4
.:A054 CC BC                    perform INT     $B5
.:A056 58 BC                    perform ABS     $B6
.:A058 10 03                    perform USR     $B7
.:A05A 7D B3                    perform FRE     $B8
.:A05C 9E B3                    perform POS     $B9
.:A05E 71 BF                    perform SQR     $BA
.:A060 97 E0                    perform RND     $BB
.:A062 EA B9                    perform LOG     $BC
.:A064 ED BF                    perform EXP     $BD
.:A066 64 E2                    perform COS     $BE
.:A068 6B E2                    perform SIN     $BF
.:A06A B4 E2                    perform TAN     $C0
.:A06C 0E E3                    perform ATN     $C1
.:A06E 0D B8                    perform PEEK    $C2
.:A070 7C B7                    perform LEN     $C3
.:A072 65 B4                    perform STR$    $C4
.:A074 AD B7                    perform VAL     $C5
.:A076 8B B7                    perform ASC     $C6
.:A078 EC B6                    perform CHR$    $C7
.:A07A 00 B7                    perform LEFT$   $C8
.:A07C 2C B7                    perform RIGHT$  $C9
.:A07E 37 B7                    perform MID$    $CA

precedence byte and action addresses for operators

                                like the primary 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
.:A080 79 69 B8                 +
.:A083 79 52 B8                 -
.:A086 7B 2A BA                 *
.:A089 7B 11 BB                 /
.:A08C 7F 7A BF                 ^
.:A08F 50 E8 AF                 AND
.:A092 46 E5 AF                 OR
.:A095 7D B3 BF                 >
.:A098 5A D3 AE                 =
.:A09B 64 15 B0                 <

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
.:A09E 45 4E                    end
.:A0A0 C4 46 4F D2 4E 45 58 D4  for next
.:A0A8 44 41 54 C1 49 4E 50 55  data input#
.:A0B0 54 A3 49 4E 50 55 D4 44  input dim
.:A0B8 49 CD 52 45 41 C4 4C 45  read let
.:A0C0 D4 47 4F 54 CF 52 55 CE  goto run
.:A0C8 49 C6 52 45 53 54 4F 52  if restore
.:A0D0 C5 47 4F 53 55 C2 52 45  gosub return
.:A0D8 54 55 52 CE 52 45 CD 53  rem stop
.:A0E0 54 4F D0 4F CE 57 41 49  on wait
.:A0E8 D4 4C 4F 41 C4 53 41 56  load save
.:A0F0 C5 56 45 52 49 46 D9 44  verify def
.:A0F8 45 C6 50 4F 4B C5 50 52  poke print#
.:A100 49 4E 54 A3 50 52 49 4E  print
.:A108 D4 43 4F 4E D4 4C 49 53  cont list
.:A110 D4 43 4C D2 43 4D C4 53  clr cmd sys
.:A118 59 D3 4F 50 45 CE 43 4C  open close
.:A120 4F 53 C5 47 45 D4 4E 45  get new

                                next are the secondary command keywords, these can not start a statement
.:A128 D7 54 41 42 A8 54 CF 46  tab( to
.:A130 CE 53 50 43 A8 54 48 45  spc( then
.:A138 CE 4E 4F D4 53 54 45 D0  not stop
                                next are the operators
.:A140 AB AD AA AF DE 41 4E C4  + - * / ' and
.:A148 4F D2 BE BD BC           or <=>
.:A14D                53 47 CE  sgn

                                and finally the functions
.:A150 49 4E D4 41 42 D3 55 53  int abs usr
.:A158 D2 46 52 C5 50 4F D3 53  fre pos sqr
.:A160 51 D2 52 4E C4 4C 4F C7  rnd log
.:A168 45 58 D0 43 4F D3 53 49  exp cos sin
.:A170 CE 54 41 CE 41 54 CE 50  tan atn peek
.:A178 45 45 CB 4C 45 CE 53 54  len str$
.:A180 52 A4 56 41 CC 41 53 C3  val asc
.:A188 43 48 52 A4 4C 45 46 54  chr$ left$
.:A190 A4 52 49 47 48 54 A4 4D  right$ mid$

                                lastly is GO, this is an add on so that GO TO, as well as GOTO, will work
.:A198 49 44 A4 47 CF           go
.:A19F 00                       end marker

BASIC error messages

.:A1A0 54 4F                    1 too many files
.:A1A0 4F 20 4D 41 4E 59 20 46
.:A1A8 49 4C 45 D3 46 49 4C 45  2 file open
.:A1B0 20 4F 50 45 CE 46 49 4C  3 file not open
.:A1B8 45 20 4E 4F 54 20 4F 50
.:A1C0 45 CE 46 49 4C 45 20 4E  4 file not found
.:A1C8 4F 54 20 46 4F 55 4E C4  5 device not present
.:A1D0 44 45 56 49 43 45 20 4E
.:A1D8 4F 54 20 50 52 45 53 45
.:A1E0 4E D4 4E 4F 54 20 49 4E  6 not input file
.:A1E8 50 55 54 20 46 49 4C C5
.:A1F0 4E 4F 54 20 4F 55 54 50  7 not output file
.:A1F8 55 54 20 46 49 4C C5 4D
.:A200 49 53 53 49 4E 47 20 46  8 missing filename
.:A208 49 4C 45 20 4E 41 4D C5
.:A210 49 4C 4C 45 47 41 4C 20  9 illegal device number
.:A218 44 45 56 49 43 45 20 4E
.:A220 55 4D 42 45 D2 4E 45 58  10 next without for
.:A228 54 20 57 49 54 48 4F 55
.:A230 54 20 46 4F D2 53 59 4E  11 syntax
.:A238 54 41 D8 52 45 54 55 52  12 return without gosub
.:A240 4E 20 57 49 54 48 4F 55
.:A248 54 20 47 4F 53 55 C2 4F  13 out of data
.:A250 55 54 20 4F 46 20 44 41
.:A258 54 C1 49 4C 4C 45 47 41  14 illegal quantity
.:A260 4C 20 51 55 41 4E 54 49
.:A268 54 D9 4F 56 45 52 46 4C  15 overflow
.:A270 4F D7 4F 55 54 20 4F 46  16 out of memory
.:A278 20 4D 45 4D 4F 52 D9 55  17 undef'd statement
.:A280 4E 44 45 46 27 44 20 53
.:A288 54 41 54 45 4D 45 4E D4
.:A290 42 41 44 20 53 55 42 53  18 bad subscript
.:A298 43 52 49 50 D4 52 45 44  19 redim'd array
.:A2A0 49 4D 27 44 20 41 52 52
.:A2A8 41 D9 44 49 56 49 53 49  20 division by zero
.:A2B0 4F 4E 20 42 59 20 5A 45
.:A2B8 52 CF 49 4C 4C 45 47 41  21 illegal direct
.:A2C0 4C 20 44 49 52 45 43 D4
.:A2C8 54 59 50 45 20 4D 49 53  22 type mismatch
.:A2D0 4D 41 54 43 C8 53 54 52  23 string too long
.:A2D8 49 4E 47 20 54 4F 4F 20
.:A2E0 4C 4F 4E C7 46 49 4C 45  24 file data
.:A2E8 20 44 41 54 C1 46 4F 52  25 formula too complex
.:A2F0 4D 55 4C 41 20 54 4F 4F
.:A2F8 20 43 4F 4D 50 4C 45 D8
.:A300 43 41 4E 27 54 20 43 4F  26 can't continue
.:A308 4E 54 49 4E 55 C5 55 4E  27 undef'd function
.:A310 44 45 46 27 44 20 46 55
.:A318 4E 43 54 49 4F CE 56 45  28 verify
.:A320 52 49 46 D9 4C 4F 41 C4  29 load

error message pointer table

.:A328 9E A1 AC A1 B5 A1 C2 A1
.:A330 D0 A1 E2 A1 F0 A1 FF A1
.:A338 10 A2 25 A2 35 A2 3B A2
.:A340 4F A2 5A A2 6A A2 72 A2
.:A348 7F A2 90 A2 9D A2 AA A2
.:A350 BA A2 C8 A2 D5 A2 E4 A2
.:A358 ED A2 00 A3 0E A3 1E A3
.:A360 24 A3 83 A3

BASIC messages

.:A364 0D 4F 4B 0D              OK
.:A368 00 20 20 45 52 52 4F 52  ERROR
.:A370 00 20 49 4E 20 00 0D 0A  IN
.:A378 52 45 41 44 59 2E 0D 0A  READY.
.:A380 00 0D 0A 42 52 45 41 4B  BREAK
.:A388 00

spare byte, not referenced

.:A389 A0                       unused

search the stack for FOR or GOSUB activity

                                return Zb=1 if FOR variable found
.,A38A BA       TSX             copy stack pointer
.,A38B E8       INX             +1 pass return address
.,A38C E8       INX             +2 pass return address
.,A38D E8       INX             +3 pass calling routine return address
.,A38E E8       INX             +4 pass calling routine return address
.,A38F BD 01 01 LDA $0101,X     get the token byte from the stack
.,A392 C9 81    CMP #$81        is it the FOR token
.,A394 D0 21    BNE $A3B7       if not FOR token just exit
                                it was the FOR token
.,A396 A5 4A    LDA $4A         get FOR/NEXT variable pointer high byte
.,A398 D0 0A    BNE $A3A4       branch if not null
.,A39A BD 02 01 LDA $0102,X     get FOR variable pointer low byte
.,A39D 85 49    STA $49         save FOR/NEXT variable pointer low byte
.,A39F BD 03 01 LDA $0103,X     get FOR variable pointer high byte
.,A3A2 85 4A    STA $4A         save FOR/NEXT variable pointer high byte
.,A3A4 DD 03 01 CMP $0103,X     compare variable pointer with stacked variable pointer
                                high byte
.,A3A7 D0 07    BNE $A3B0       branch if no match
.,A3A9 A5 49    LDA $49         get FOR/NEXT variable pointer low byte
.,A3AB DD 02 01 CMP $0102,X     compare variable pointer with stacked variable pointer
                                low byte
.,A3AE F0 07    BEQ $A3B7       exit if match found
.,A3B0 8A       TXA             copy index
.,A3B1 18       CLC             clear carry for add
.,A3B2 69 12    ADC #$12        add FOR stack use size
.,A3B4 AA       TAX             copy back to index
.,A3B5 D0 D8    BNE $A38F       loop if not at start of stack
.,A3B7 60       RTS

open up a space in the memory, set the end of arrays

.,A3B8 20 08 A4 JSR $A408       check available memory, do out of memory error if no room
.,A3BB 85 31    STA $31         set end of arrays low byte
.,A3BD 84 32    STY $32         set end of arrays high byte
                                open up a space in the memory, don't set the array end
.,A3BF 38       SEC             set carry for subtract
.,A3C0 A5 5A    LDA $5A         get block end low byte
.,A3C2 E5 5F    SBC $5F         subtract block start low byte
.,A3C4 85 22    STA $22         save MOD(block length/$100) byte
.,A3C6 A8       TAY             copy MOD(block length/$100) byte to Y
.,A3C7 A5 5B    LDA $5B         get block end high byte
.,A3C9 E5 60    SBC $60         subtract block start high byte
.,A3CB AA       TAX             copy block length high byte to X
.,A3CC E8       INX             +1 to allow for count=0 exit
.,A3CD 98       TYA             copy block length low byte to A
.,A3CE F0 23    BEQ $A3F3       branch if length low byte=0
                                block is (X-1)*256+Y bytes, do the Y bytes first
.,A3D0 A5 5A    LDA $5A         get block end low byte
.,A3D2 38       SEC             set carry for subtract
.,A3D3 E5 22    SBC $22         subtract MOD(block length/$100) byte
.,A3D5 85 5A    STA $5A         save corrected old block end low byte
.,A3D7 B0 03    BCS $A3DC       branch if no underflow
.,A3D9 C6 5B    DEC $5B         else decrement block end high byte
.,A3DB 38       SEC             set carry for subtract
.,A3DC A5 58    LDA $58         get destination end low byte
.,A3DE E5 22    SBC $22         subtract MOD(block length/$100) byte
.,A3E0 85 58    STA $58         save modified new block end low byte
.,A3E2 B0 08    BCS $A3EC       branch if no underflow
.,A3E4 C6 59    DEC $59         else decrement block end high byte
.,A3E6 90 04    BCC $A3EC       branch always
.,A3E8 B1 5A    LDA ($5A),Y     get byte from source
.,A3EA 91 58    STA ($58),Y     copy byte to destination
.,A3EC 88       DEY             decrement index
.,A3ED D0 F9    BNE $A3E8       loop until Y=0
                                now do Y=0 indexed byte
.,A3EF B1 5A    LDA ($5A),Y     get byte from source
.,A3F1 91 58    STA ($58),Y     save byte to destination
.,A3F3 C6 5B    DEC $5B         decrement source pointer high byte
.,A3F5 C6 59    DEC $59         decrement destination pointer high byte
.,A3F7 CA       DEX             decrement block count
.,A3F8 D0 F2    BNE $A3EC       loop until count = $0
.,A3FA 60       RTS

check room on stack for A bytes

                                if stack too deep do out of memory error
.,A3FB 0A       ASL             *2
.,A3FC 69 3E    ADC #$3E        need at least $3E bytes free
.,A3FE B0 35    BCS $A435       if overflow go do out of memory error then warm start
.,A400 85 22    STA $22         save result in temp byte
.,A402 BA       TSX             copy stack
.,A403 E4 22    CPX $22         compare new limit with stack
.,A405 90 2E    BCC $A435       if stack < limit do out of memory error then warm start
.,A407 60       RTS

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

.,A408 C4 34    CPY $34         compare with bottom of string space high byte
.,A40A 90 28    BCC $A434       if less then exit (is ok)
.,A40C D0 04    BNE $A412       skip next test if greater (tested <)
                                high byte was =, now do low byte
.,A40E C5 33    CMP $33         compare with bottom of string space low byte
.,A410 90 22    BCC $A434       if less then exit (is ok)
                                address is > string storage ptr (oops!)
.,A412 48       PHA             push address low byte
.,A413 A2 09    LDX #$09        set index to save $57 to $60 inclusive
.,A415 98       TYA             copy address high byte (to push on stack)
                                save misc numeric work area
.,A416 48       PHA             push byte
.,A417 B5 57    LDA $57,X       get byte from $57 to $60
.,A419 CA       DEX             decrement index
.,A41A 10 FA    BPL $A416       loop until all done
.,A41C 20 26 B5 JSR $B526       do garbage collection routine
                                restore misc numeric work area
.,A41F A2 F7    LDX #$F7        set index to restore bytes
.,A421 68       PLA             pop byte
.,A422 95 61    STA $61,X       save byte to $57 to $60
.,A424 E8       INX             increment index
.,A425 30 FA    BMI $A421       loop while -ve
.,A427 68       PLA             pop address high byte
.,A428 A8       TAY             copy back to Y
.,A429 68       PLA             pop address low byte
.,A42A C4 34    CPY $34         compare with bottom of string space high byte
.,A42C 90 06    BCC $A434       if less then exit (is ok)
.,A42E D0 05    BNE $A435       if greater do out of memory error then warm start
                                high byte was =, now do low byte
.,A430 C5 33    CMP $33         compare with bottom of string space low byte
.,A432 B0 01    BCS $A435       if >= do out of memory error then warm start
                                ok exit, carry clear
.,A434 60       RTS

do out of memory error then warm start

.,A435 A2 10    LDX #$10        error code $10, out of memory error
                                do error #X then warm start
.,A437 6C 00 03 JMP ($0300)     do error message

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

.,A43A 8A       TXA             copy error number
.,A43B 0A       ASL             *2
.,A43C AA       TAX             copy to index
.,A43D BD 26 A3 LDA $A326,X     get error message pointer low byte
.,A440 85 22    STA $22         save it
.,A442 BD 27 A3 LDA $A327,X     get error message pointer high byte
.,A445 85 23    STA $23         save it
.,A447 20 CC FF JSR $FFCC       close input and output channels
.,A44A A9 00    LDA #$00        clear A
.,A44C 85 13    STA $13         clear current I/O channel, flag default
.,A44E 20 D7 AA JSR $AAD7       print CR/LF
.,A451 20 45 AB JSR $AB45       print "?"
.,A454 A0 00    LDY #$00        clear index
.,A456 B1 22    LDA ($22),Y     get byte from message
.,A458 48       PHA             save status
.,A459 29 7F    AND #$7F        mask 0xxx xxxx, clear b7
.,A45B 20 47 AB JSR $AB47       output character
.,A45E C8       INY             increment index
.,A45F 68       PLA             restore status
.,A460 10 F4    BPL $A456       loop if character was not end marker
.,A462 20 7A A6 JSR $A67A       flush BASIC stack and clear continue pointer
.,A465 A9 69    LDA #$69        set " ERROR" pointer low byte
.,A467 A0 A3    LDY #$A3        set " ERROR" pointer high byte

print string and do warm start, break entry

.,A469 20 1E AB JSR $AB1E       print null terminated string
.,A46C A4 3A    LDY $3A         get current line number high byte
.,A46E C8       INY             increment it
.,A46F F0 03    BEQ $A474       branch if was in immediate mode
.,A471 20 C2 BD JSR $BDC2       do " IN " line number message

do warm start

.,A474 A9 76    LDA #$76        set "READY." pointer low byte
.,A476 A0 A3    LDY #$A3        set "READY." pointer high byte
.,A478 20 1E AB JSR $AB1E       print null terminated string
.,A47B A9 80    LDA #$80        set for control messages only
.,A47D 20 90 FF JSR $FF90       control kernal messages
.,A480 6C 02 03 JMP ($0302)     do BASIC warm start

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

.,A483 20 60 A5 JSR $A560       call for BASIC input
.,A486 86 7A    STX $7A         save BASIC execute pointer low byte
.,A488 84 7B    STY $7B         save BASIC execute pointer high byte
.,A48A 20 73 00 JSR $0073       increment and scan memory
.,A48D AA       TAX             copy byte to set flags
.,A48E F0 F0    BEQ $A480       loop if no input
                                got to interpret the input line now ....
.,A490 A2 FF    LDX #$FF        current line high byte to -1, indicates immediate mode
.,A492 86 3A    STX $3A         set current line number high byte
.,A494 90 06    BCC $A49C       if numeric character go handle new BASIC line
                                no line number .. immediate mode
.,A496 20 79 A5 JSR $A579       crunch keywords into BASIC tokens
.,A499 4C E1 A7 JMP $A7E1       go scan and interpret code

handle new BASIC line

.,A49C 20 6B A9 JSR $A96B       get fixed-point number into temporary integer
.,A49F 20 79 A5 JSR $A579       crunch keywords into BASIC tokens
.,A4A2 84 0B    STY $0B         save index pointer to end of crunched line
.,A4A4 20 13 A6 JSR $A613       search BASIC for temporary integer line number
.,A4A7 90 44    BCC $A4ED       if not found skip the line delete
                                line # already exists so delete it
.,A4A9 A0 01    LDY #$01        set index to next line pointer high byte
.,A4AB B1 5F    LDA ($5F),Y     get next line pointer high byte
.,A4AD 85 23    STA $23         save it
.,A4AF A5 2D    LDA $2D         get start of variables low byte
.,A4B1 85 22    STA $22         save it
.,A4B3 A5 60    LDA $60         get found line pointer high byte
.,A4B5 85 25    STA $25         save it
.,A4B7 A5 5F    LDA $5F         get found line pointer low byte
.,A4B9 88       DEY             decrement index
.,A4BA F1 5F    SBC ($5F),Y     subtract next line pointer low byte
.,A4BC 18       CLC             clear carry for add
.,A4BD 65 2D    ADC $2D         add start of variables low byte
.,A4BF 85 2D    STA $2D         set start of variables low byte
.,A4C1 85 24    STA $24         save destination pointer low byte
.,A4C3 A5 2E    LDA $2E         get start of variables high byte
.,A4C5 69 FF    ADC #$FF        -1 + carry
.,A4C7 85 2E    STA $2E         set start of variables high byte
.,A4C9 E5 60    SBC $60         subtract found line pointer high byte
.,A4CB AA       TAX             copy to block count
.,A4CC 38       SEC             set carry for subtract
.,A4CD A5 5F    LDA $5F         get found line pointer low byte
.,A4CF E5 2D    SBC $2D         subtract start of variables low byte
.,A4D1 A8       TAY             copy to bytes in first block count
.,A4D2 B0 03    BCS $A4D7       branch if no underflow
.,A4D4 E8       INX             increment block count, correct for = 0 loop exit
.,A4D5 C6 25    DEC $25         decrement destination high byte
.,A4D7 18       CLC             clear carry for add
.,A4D8 65 22    ADC $22         add source pointer low byte
.,A4DA 90 03    BCC $A4DF       branch if no overflow
.,A4DC C6 23    DEC $23         else decrement source pointer high byte
.,A4DE 18       CLC             clear carry
                                close up memory to delete old line
.,A4DF B1 22    LDA ($22),Y     get byte from source
.,A4E1 91 24    STA ($24),Y     copy to destination
.,A4E3 C8       INY             increment index
.,A4E4 D0 F9    BNE $A4DF       while <> 0 do this block
.,A4E6 E6 23    INC $23         increment source pointer high byte
.,A4E8 E6 25    INC $25         increment destination pointer high byte
.,A4EA CA       DEX             decrement block count
.,A4EB D0 F2    BNE $A4DF       loop until all done
                                got new line in buffer and no existing same #
.,A4ED 20 59 A6 JSR $A659       reset execution to start, clear variables, flush stack
                                and return
.,A4F0 20 33 A5 JSR $A533       rebuild BASIC line chaining
.,A4F3 AD 00 02 LDA $0200       get first byte from buffer
.,A4F6 F0 88    BEQ $A480       if no line go do BASIC warm start
                                else insert line into memory
.,A4F8 18       CLC             clear carry for add
.,A4F9 A5 2D    LDA $2D         get start of variables low byte
.,A4FB 85 5A    STA $5A         save as source end pointer low byte
.,A4FD 65 0B    ADC $0B         add index pointer to end of crunched line
.,A4FF 85 58    STA $58         save as destination end pointer low byte
.,A501 A4 2E    LDY $2E         get start of variables high byte
.,A503 84 5B    STY $5B         save as source end pointer high byte
.,A505 90 01    BCC $A508       branch if no carry to high byte
.,A507 C8       INY             else increment high byte
.,A508 84 59    STY $59         save as destination end pointer high byte
.,A50A 20 B8 A3 JSR $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.
.,A50D A5 14    LDA $14         get line number low byte
.,A50F A4 15    LDY $15         get line number high byte
.,A511 8D FE 01 STA $01FE       save line number low byte before crunched line
.,A514 8C FF 01 STY $01FF       save line number high byte before crunched line
.,A517 A5 31    LDA $31         get end of arrays low byte
.,A519 A4 32    LDY $32         get end of arrays high byte
.,A51B 85 2D    STA $2D         set start of variables low byte
.,A51D 84 2E    STY $2E         set start of variables high byte
.,A51F A4 0B    LDY $0B         get index to end of crunched line
.,A521 88       DEY             -1
.,A522 B9 FC 01 LDA $01FC,Y     get byte from crunched line
.,A525 91 5F    STA ($5F),Y     save byte to memory
.,A527 88       DEY             decrement index
.,A528 10 F8    BPL $A522       loop while more to do
                                reset execution, clear variables, flush stack, rebuild BASIC chain and do warm start
.,A52A 20 59 A6 JSR $A659       reset execution to start, clear variables and flush stack
.,A52D 20 33 A5 JSR $A533       rebuild BASIC line chaining
.,A530 4C 80 A4 JMP $A480       go do BASIC warm start

rebuild BASIC line chaining

.,A533 A5 2B    LDA $2B         get start of memory low byte
.,A535 A4 2C    LDY $2C         get start of memory high byte
.,A537 85 22    STA $22         set line start pointer low byte
.,A539 84 23    STY $23         set line start pointer high byte
.,A53B 18       CLC             clear carry for add
.,A53C A0 01    LDY #$01        set index to pointer to next line high byte
.,A53E B1 22    LDA ($22),Y     get pointer to next line high byte
.,A540 F0 1D    BEQ $A55F       exit if null, [EOT]
.,A542 A0 04    LDY #$04        point to first code byte of line
                                there is always 1 byte + [EOL] as null entries are deleted
.,A544 C8       INY             next code byte
.,A545 B1 22    LDA ($22),Y     get byte
.,A547 D0 FB    BNE $A544       loop if not [EOL]
.,A549 C8       INY             point to byte past [EOL], start of next line
.,A54A 98       TYA             copy it
.,A54B 65 22    ADC $22         add line start pointer low byte
.,A54D AA       TAX             copy to X
.,A54E A0 00    LDY #$00        clear index, point to this line's next line pointer
.,A550 91 22    STA ($22),Y     set next line pointer low byte
.,A552 A5 23    LDA $23         get line start pointer high byte
.,A554 69 00    ADC #$00        add any overflow
.,A556 C8       INY             increment index to high byte
.,A557 91 22    STA ($22),Y     set next line pointer high byte
.,A559 86 22    STX $22         set line start pointer low byte
.,A55B 85 23    STA $23         set line start pointer high byte
.,A55D 90 DD    BCC $A53C       go do next line, branch always
.,A55F 60       RTS
                                call for BASIC input
.,A560 A2 00    LDX #$00        set channel $00, keyboard
.,A562 20 12 E1 JSR $E112       input character from channel with error check
.,A565 C9 0D    CMP #$0D        compare with [CR]
.,A567 F0 0D    BEQ $A576       if [CR] set XY to $200 - 1, print [CR] and exit
                                character was not [CR]
.,A569 9D 00 02 STA $0200,X     save character to buffer
.,A56C E8       INX             increment buffer index
.,A56D E0 59    CPX #$59        compare with max+1
.,A56F 90 F1    BCC $A562       branch if < max+1
.,A571 A2 17    LDX #$17        error $17, string too long error
.,A573 4C 37 A4 JMP $A437       do error #X then warm start
.,A576 4C CA AA JMP $AACA       set XY to $200 - 1 and print [CR]

crunch BASIC tokens vector

.,A579 6C 04 03 JMP ($0304)     do crunch BASIC tokens

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

.,A57C A6 7A    LDX $7A         get BASIC execute pointer low byte
.,A57E A0 04    LDY #$04        set save index
.,A580 84 0F    STY $0F         clear open quote/DATA flag
.,A582 BD 00 02 LDA $0200,X     get a byte from the input buffer
.,A585 10 07    BPL $A58E       if b7 clear go do crunching
.,A587 C9 FF    CMP #$FF        compare with the token for PI, this toke is input
                                directly from the keyboard as the PI character
.,A589 F0 3E    BEQ $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
.,A58B E8       INX             increment read index
.,A58C D0 F4    BNE $A582       loop if more to do, branch always
.,A58E C9 20    CMP #$20        compare with [SPACE]
.,A590 F0 37    BEQ $A5C9       if [SPACE] save byte then continue crunching
.,A592 85 08    STA $08         save buffer byte as search character
.,A594 C9 22    CMP #$22        compare with quote character
.,A596 F0 56    BEQ $A5EE       if quote go copy quoted string
.,A598 24 0F    BIT $0F         get open quote/DATA token flag
.,A59A 70 2D    BVS $A5C9       branch if b6 of Oquote set, was DATA
                                go save byte then continue crunching
.,A59C C9 3F    CMP #$3F        compare with "?" character
.,A59E D0 04    BNE $A5A4       if not "?" continue crunching
.,A5A0 A9 99    LDA #$99        else the keyword token is $99, PRINT
.,A5A2 D0 25    BNE $A5C9       go save byte then continue crunching, branch always
.,A5A4 C9 30    CMP #$30        compare with "0"
.,A5A6 90 04    BCC $A5AC       branch if <, continue crunching
.,A5A8 C9 3C    CMP #$3C        compare with "<"
.,A5AA 90 1D    BCC $A5C9       if <, 0123456789:; go save byte then continue crunching
                                gets here with next character not numeric, ";" or ":"
.,A5AC 84 71    STY $71         copy save index
.,A5AE A0 00    LDY #$00        clear table pointer
.,A5B0 84 0B    STY $0B         clear word index
.,A5B2 88       DEYadjust for pre increment loop
.,A5B3 86 7A    STX $7A         save BASIC execute pointer low byte, buffer index
.,A5B5 CA       DEX             adjust for pre increment loop
.,A5B6 C8       INY             next table byte
.,A5B7 E8       INX             next buffer byte
.,A5B8 BD 00 02 LDA $0200,X     get byte from input buffer
.,A5BB 38       SEC             set carry for subtract
.,A5BC F9 9E A0 SBC $A09E,Y     subtract table byte
.,A5BF F0 F5    BEQ $A5B6       go compare next if match
.,A5C1 C9 80    CMP #$80        was it end marker match ?
.,A5C3 D0 30    BNE $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
.,A5C5 05 0B    ORA $0B         OR with word index, +$80 in A makes token
.,A5C7 A4 71    LDY $71         restore save index
                                save byte then continue crunching
.,A5C9 E8       INXincrement buffer read index
.,A5CA C8       INY             increment save index
.,A5CB 99 FB 01 STA $01FB,Y     save byte to output
.,A5CE B9 FB 01 LDA $01FB,Y     get byte from output, set flags
.,A5D1 F0 36    BEQ $A609       branch if was null [EOL]
                                A holds the token here
.,A5D3 38       SEC             set carry for subtract
.,A5D4 E9 3A    SBC #$3A        subtract ":"
.,A5D6 F0 04    BEQ $A5DC       branch if it was (is now $00)
                                A now holds token-':'
.,A5D8 C9 49    CMP #$49        compare with the token for DATA-':'
.,A5DA D0 02    BNE $A5DE       if not DATA go try REM
                                token was : or DATA
.,A5DC 85 0F    STA $0F         save the token-$3A
.,A5DE 38       SEC             set carry for subtract
.,A5DF E9 55    SBC #$55        subtract the token for REM-':'
.,A5E1 D0 9F    BNE $A582       if wasn't REM crunch next bit of line
.,A5E3 85 08    STA $08         else was REM so set search for [EOL]
                                loop for "..." etc.
.,A5E5 BD 00 02 LDA $0200,X     get byte from input buffer
.,A5E8 F0 DF    BEQ $A5C9       if null [EOL] save byte then continue crunching
.,A5EA C5 08    CMP $08         compare with stored character
.,A5EC F0 DB    BEQ $A5C9       if match save byte then continue crunching
.,A5EE C8       INY             increment save index
.,A5EF 99 FB 01 STA $01FB,Y     save byte to output
.,A5F2 E8       INX             increment buffer index
.,A5F3 D0 F0    BNE $A5E5       loop while <> 0, should never reach 0
                                not found keyword this go
.,A5F5 A6 7A    LDX $7A         restore BASIC execute pointer low byte
.,A5F7 E6 0B    INC $0B         increment word index (next word)
                                now find end of this word in the table
.,A5F9 C8       INY             increment table index
.,A5FA B9 9D A0 LDA $A09D,Y     get table byte
.,A5FD 10 FA    BPL $A5F9       loop if not end of word yet
.,A5FF B9 9E A0 LDA $A09E,Y     get byte from keyword table
.,A602 D0 B4    BNE $A5B8       go test next word if not zero byte, end of table
                                reached end of table with no match
.,A604 BD 00 02 LDA $0200,X     restore byte from input buffer
.,A607 10 BE    BPL $A5C7       branch always, all unmatched bytes in the buffer are
                                $00 to $7F, go save byte in output and continue crunching
                                reached [EOL]
.,A609 99 FD 01 STA $01FD,Y     save [EOL]
.,A60C C6 7B    DEC $7B         decrement BASIC execute pointer high byte
.,A60E A9 FF    LDA #$FF        point to start of buffer-1
.,A610 85 7A    STA $7A         set BASIC execute pointer low byte
.,A612 60       RTS

search BASIC for temporary integer line number

.,A613 A5 2B    LDA $2B         get start of memory low byte
.,A615 A6 2C    LDX $2C         get start of memory high byte

search Basic for temp integer line number from AX

                                returns carry set if found
.,A617 A0 01    LDY #$01        set index to next line pointer high byte
.,A619 85 5F    STA $5F         save low byte as current
.,A61B 86 60    STX $60         save high byte as current
.,A61D B1 5F    LDA ($5F),Y     get next line pointer high byte from address
.,A61F F0 1F    BEQ $A640       pointer was zero so done, exit
.,A621 C8       INY             increment index ...
.,A622 C8       INY             ... to line # high byte
.,A623 A5 15    LDA $15         get temporary integer high byte
.,A625 D1 5F    CMP ($5F),Y     compare with line # high byte
.,A627 90 18    BCC $A641       exit if temp < this line, target line passed
.,A629 F0 03    BEQ $A62E       go check low byte if =
.,A62B 88       DEY             else decrement index
.,A62C D0 09    BNE $A637       branch always
.,A62E A5 14    LDA $14         get temporary integer low byte
.,A630 88       DEY             decrement index to line # low byte
.,A631 D1 5F    CMP ($5F),Y     compare with line # low byte
.,A633 90 0C    BCC $A641       exit if temp < this line, target line passed
.,A635 F0 0A    BEQ $A641       exit if temp = (found line#)
                                not quite there yet
.,A637 88       DEY             decrement index to next line pointer high byte
.,A638 B1 5F    LDA ($5F),Y     get next line pointer high byte
.,A63A AA       TAX             copy to X
.,A63B 88       DEY             decrement index to next line pointer low byte
.,A63C B1 5F    LDA ($5F),Y     get next line pointer low byte
.,A63E B0 D7    BCS $A617       go search for line # in temporary integer
                                from AX, carry always set
.,A640 18       CLC             clear found flag
.,A641 60       RTS

perform NEW

.,A642 D0 FD    BNE $A641       exit if following byte to allow syntax error
.,A644 A9 00    LDA #$00        clear A
.,A646 A8       TAY             clear index
.,A647 91 2B    STA ($2B),Y     clear pointer to next line low byte
.,A649 C8       INY             increment index
.,A64A 91 2B    STA ($2B),Y     clear pointer to next line high byte, erase program
.,A64C A5 2B    LDA $2B         get start of memory low byte
.,A64E 18       CLC             clear carry for add
.,A64F 69 02    ADC #$02        add null program length
.,A651 85 2D    STA $2D         set start of variables low byte
.,A653 A5 2C    LDA $2C         get start of memory high byte
.,A655 69 00    ADC #$00        add carry
.,A657 85 2E    STA $2E         set start of variables high byte

reset execute pointer and do CLR

.,A659 20 8E A6 JSR $A68E       set BASIC execute pointer to start of memory - 1
.,A65C A9 00    LDA #$00        set Zb for CLR entry

perform CLR

.,A65E D0 2D    BNE $A68D       exit if following byte to allow syntax error
.,A660 20 E7 FF JSR $FFE7       close all channels and files
.,A663 A5 37    LDA $37         get end of memory low byte
.,A665 A4 38    LDY $38         get end of memory high byte
.,A667 85 33    STA $33         set bottom of string space low byte, clear strings
.,A669 84 34    STY $34         set bottom of string space high byte
.,A66B A5 2D    LDA $2D         get start of variables low byte
.,A66D A4 2E    LDY $2E         get start of variables high byte
.,A66F 85 2F    STA $2F         set end of variables low byte, clear variables
.,A671 84 30    STY $30         set end of variables high byte
.,A673 85 31    STA $31         set end of arrays low byte, clear arrays
.,A675 84 32    STY $32         set end of arrays high byte

do RESTORE and clear stack

.,A677 20 1D A8 JSR $A81D       perform RESTORE

flush BASIC stack and clear the continue pointer

.,A67A A2 19    LDX #$19        get the descriptor stack start
.,A67C 86 16    STX $16         set the descriptor stack pointer
.,A67E 68       PLA             pull the return address low byte
.,A67F A8       TAY             copy it
.,A680 68       PLA             pull the return address high byte
.,A681 A2 FA    LDX #$FA        set the cleared stack pointer
.,A683 9A       TXS             set the stack
.,A684 48       PHA             push the return address high byte
.,A685 98       TYA             restore the return address low byte
.,A686 48       PHA             push the return address low byte
.,A687 A9 00    LDA #$00        clear A
.,A689 85 3E    STA $3E         clear the continue pointer high byte
.,A68B 85 10    STA $10         clear the subscript/FNX flag
.,A68D 60       RTS

set BASIC execute pointer to start of memory - 1

.,A68E 18       CLC             clear carry for add
.,A68F A5 2B    LDA $2B         get start of memory low byte
.,A691 69 FF    ADC #$FF        add -1 low byte
.,A693 85 7A    STA $7A         set BASIC execute pointer low byte
.,A695 A5 2C    LDA $2C         get start of memory high byte
.,A697 69 FF    ADC #$FF        add -1 high byte
.,A699 85 7B    STA $7B         save BASIC execute pointer high byte
.,A69B 60       RTS

perform LIST

.,A69C 90 06    BCC $A6A4       branch if next character not token (LIST n...)
.,A69E F0 04    BEQ $A6A4       branch if next character [NULL] (LIST)
.,A6A0 C9 AB    CMP #$AB        compare with token for -
.,A6A2 D0 E9    BNE $A68D       exit if not - (LIST -m)
                                LIST [[n][-m]]
                                this bit sets the n , if present, as the start and end
.,A6A4 20 6B A9 JSR $A96B       get fixed-point number into temporary integer
.,A6A7 20 13 A6 JSR $A613       search BASIC for temporary integer line number
.,A6AA 20 79 00 JSR $0079       scan memory
.,A6AD F0 0C    BEQ $A6BB       branch if no more chrs
                                this bit checks the - is present
.,A6AF C9 AB    CMP #$AB        compare with token for -
.,A6B1 D0 8E    BNE $A641       return if not "-" (will be SN error)
                                LIST [n]-m
                                the - was there so set m as the end value
.,A6B3 20 73 00 JSR $0073       increment and scan memory
.,A6B6 20 6B A9 JSR $A96B       get fixed-point number into temporary integer
.,A6B9 D0 86    BNE $A641       exit if not ok
.,A6BB 68       PLA             dump return address low byte, exit via warm start
.,A6BC 68       PLA             dump return address high byte
.,A6BD A5 14    LDA $14         get temporary integer low byte
.,A6BF 05 15    ORA $15         OR temporary integer high byte
.,A6C1 D0 06    BNE $A6C9       branch if start set
.,A6C3 A9 FF    LDA #$FF        set for -1
.,A6C5 85 14    STA $14         set temporary integer low byte
.,A6C7 85 15    STA $15         set temporary integer high byte
.,A6C9 A0 01    LDY #$01        set index for line
.,A6CB 84 0F    STY $0F         clear open quote flag
.,A6CD B1 5F    LDA ($5F),Y     get next line pointer high byte
.,A6CF F0 43    BEQ $A714       if null all done so exit
.,A6D1 20 2C A8 JSR $A82C       do CRTL-C check vector
.,A6D4 20 D7 AA JSR $AAD7       print CR/LF
.,A6D7 C8       INY             increment index for line
.,A6D8 B1 5F    LDA ($5F),Y     get line number low byte
.,A6DA AA       TAX             copy to X
.,A6DB C8       INY             increment index
.,A6DC B1 5F    LDA ($5F),Y     get line number high byte
.,A6DE C5 15    CMP $15         compare with temporary integer high byte
.,A6E0 D0 04    BNE $A6E6       branch if no high byte match
.,A6E2 E4 14    CPX $14         compare with temporary integer low byte
.,A6E4 F0 02    BEQ $A6E8       branch if = last line to do, < will pass next branch
                                else
.,A6E6 B0 2C    BCS $A714       if greater all done so exit
.,A6E8 84 49    STY $49         save index for line
.,A6EA 20 CD BD JSR $BDCD       print XA as unsigned integer
.,A6ED A9 20    LDA #$20        space is the next character
.,A6EF A4 49    LDY $49         get index for line
.,A6F1 29 7F    AND #$7F        mask top out bit of character
.,A6F3 20 47 AB JSR $AB47       go print the character
.,A6F6 C9 22    CMP #$22        was it " character
.,A6F8 D0 06    BNE $A700       if not skip the quote handle
                                we are either entering or leaving a pair of quotes
.,A6FA A5 0F    LDA $0F         get open quote flag
.,A6FC 49 FF    EOR #$FF        toggle it
.,A6FE 85 0F    STA $0F         save it back
.,A700 C8       INY             increment index
.,A701 F0 11    BEQ $A714       line too long so just bail out and do a warm start
.,A703 B1 5F    LDA ($5F),Y     get next byte
.,A705 D0 10    BNE $A717       if not [EOL] (go print character)
                                was [EOL]
.,A707 A8       TAY             else clear index
.,A708 B1 5F    LDA ($5F),Y     get next line pointer low byte
.,A70A AA       TAX             copy to X
.,A70B C8       INY             increment index
.,A70C B1 5F    LDA ($5F),Y     get next line pointer high byte
.,A70E 86 5F    STX $5F         set pointer to line low byte
.,A710 85 60    STA $60         set pointer to line high byte
.,A712 D0 B5    BNE $A6C9       go do next line if not [EOT]
                                else ...
.,A714 4C 86 E3 JMP $E386       do warm start
.,A717 6C 06 03 JMP ($0306)     do uncrunch BASIC tokens

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

.,A71A 10 D7    BPL $A6F3       just go print it if not token byte
                                else was token byte so uncrunch it
.,A71C C9 FF    CMP #$FF        compare with the token for PI. in this case the token
                                is the same as the PI character so it just needs printing
.,A71E F0 D3    BEQ $A6F3       just print it if so
.,A720 24 0F    BIT $0F         test the open quote flag
.,A722 30 CF    BMI $A6F3       just go print character if open quote set
.,A724 38       SEC             else set carry for subtract
.,A725 E9 7F    SBC #$7F        reduce token range to 1 to whatever
.,A727 AA       TAX             copy token # to X
.,A728 84 49    STY $49         save index for line
.,A72A A0 FF    LDY #$FF        start from -1, adjust for pre increment
.,A72C CA       DEX             decrement token #
.,A72D F0 08    BEQ $A737       if now found go do printing
.,A72F C8       INY             else increment index
.,A730 B9 9E A0 LDA $A09E,Y     get byte from keyword table
.,A733 10 FA    BPL $A72F       loop until keyword end marker
.,A735 30 F5    BMI $A72C       go test if this is required keyword, branch always
                                found keyword, it's the next one
.,A737 C8       INY             increment keyword table index
.,A738 B9 9E A0 LDA $A09E,Y     get byte from table
.,A73B 30 B2    BMI $A6EF       go restore index, mask byte and print if
                                byte was end marker
.,A73D 20 47 AB JSR $AB47       else go print the character
.,A740 D0 F5    BNE $A737       go get next character, branch always

perform FOR

.,A742 A9 80    LDA #$80        set FNX
.,A744 85 10    STA $10         set subscript/FNX flag
.,A746 20 A5 A9 JSR $A9A5       perform LET
.,A749 20 8A A3 JSR $A38A       search the stack for FOR or GOSUB activity
.,A74C D0 05    BNE $A753       branch if FOR, this variable, not found
                                FOR, this variable, was found so first we dump the old one
.,A74E 8A       TXA             copy index
.,A74F 69 0F    ADC #$0F        add FOR structure size-2
.,A751 AA       TAX             copy to index
.,A752 9A       TXS             set stack (dump FOR structure (-2 bytes))
.,A753 68       PLA             pull return address
.,A754 68       PLA             pull return address
.,A755 A9 09    LDA #$09        we need 18d bytes !
.,A757 20 FB A3 JSR $A3FB       check room on stack for 2*A bytes
.,A75A 20 06 A9 JSR $A906       scan for next BASIC statement ([:] or [EOL])
.,A75D 18       CLC             clear carry for add
.,A75E 98       TYA             copy index to A
.,A75F 65 7A    ADC $7A         add BASIC execute pointer low byte
.,A761 48       PHA             push onto stack
.,A762 A5 7B    LDA $7B         get BASIC execute pointer high byte
.,A764 69 00    ADC #$00        add carry
.,A766 48       PHA             push onto stack
.,A767 A5 3A    LDA $3A         get current line number high byte
.,A769 48       PHA             push onto stack
.,A76A A5 39    LDA $39         get current line number low byte
.,A76C 48       PHA             push onto stack
.,A76D A9 A4    LDA #$A4        set "TO" token
.,A76F 20 FF AE JSR $AEFF       scan for CHR$(A), else do syntax error then warm start
.,A772 20 8D AD JSR $AD8D       check if source is numeric, else do type mismatch
.,A775 20 8A AD JSR $AD8A       evaluate expression and check is numeric, else do
                                type mismatch
.,A778 A5 66    LDA $66         get FAC1 sign (b7)
.,A77A 09 7F    ORA #$7F        set all non sign bits
.,A77C 25 62    AND $62         and FAC1 mantissa 1
.,A77E 85 62    STA $62         save FAC1 mantissa 1
.,A780 A9 8B    LDA #$8B        set return address low byte
.,A782 A0 A7    LDY #$A7        set return address high byte
.,A784 85 22    STA $22         save return address low byte
.,A786 84 23    STY $23         save return address high byte
.,A788 4C 43 AE JMP $AE43       round FAC1 and put on stack, returns to next instruction
.,A78B A9 BC    LDA #$BC        set 1 pointer low address, default step size
.,A78D A0 B9    LDY #$B9        set 1 pointer high address
.,A78F 20 A2 BB JSR $BBA2       unpack memory (AY) into FAC1
.,A792 20 79 00 JSR $0079       scan memory
.,A795 C9 A9    CMP #$A9        compare with STEP token
.,A797 D0 06    BNE $A79F       if not "STEP" continue
                                was step so ....
.,A799 20 73 00 JSR $0073       increment and scan memory
.,A79C 20 8A AD JSR $AD8A       evaluate expression and check is numeric, else do
                                type mismatch
.,A79F 20 2B BC JSR $BC2B       get FAC1 sign, return A = $FF -ve, A = $01 +ve
.,A7A2 20 38 AE JSR $AE38       push sign, round FAC1 and put on stack
.,A7A5 A5 4A    LDA $4A         get FOR/NEXT variable pointer high byte
.,A7A7 48       PHA             push on stack
.,A7A8 A5 49    LDA $49         get FOR/NEXT variable pointer low byte
.,A7AA 48       PHA             push on stack
.,A7AB A9 81    LDA #$81        get FOR token
.,A7AD 48       PHA             push on stack

interpreter inner loop

.,A7AE 20 2C A8 JSR $A82C       do CRTL-C check vector
.,A7B1 A5 7A    LDA $7A         get the BASIC execute pointer low byte
.,A7B3 A4 7B    LDY $7B         get the BASIC execute pointer high byte
.,A7B5 C0 02    CPY #$02        compare the high byte with $02xx
.,A7B7 EA       NOP             unused byte
.,A7B8 F0 04    BEQ $A7BE       if immediate mode skip the continue pointer save
.,A7BA 85 3D    STA $3D         save the continue pointer low byte
.,A7BC 84 3E    STY $3E         save the continue pointer high byte
.,A7BE A0 00    LDY #$00        clear the index
.,A7C0 B1 7A    LDA ($7A),Y     get a BASIC byte
.,A7C2 D0 43    BNE $A807       if not [EOL] go test for ":"
.,A7C4 A0 02    LDY #$02        else set the index
.,A7C6 B1 7A    LDA ($7A),Y     get next line pointer high byte
.,A7C8 18       CLC             clear carry for no "BREAK" message
.,A7C9 D0 03    BNE $A7CE       branch if not end of program
.,A7CB 4C 4B A8 JMP $A84B       else go to immediate mode,was immediate or [EOT] marker
.,A7CE C8       INY             increment index
.,A7CF B1 7A    LDA ($7A),Y     get line number low byte
.,A7D1 85 39    STA $39         save current line number low byte
.,A7D3 C8       INY             increment index
.,A7D4 B1 7A    LDA ($7A),Y     get line # high byte
.,A7D6 85 3A    STA $3A         save current line number high byte
.,A7D8 98       TYA             A now = 4
.,A7D9 65 7A    ADC $7A         add BASIC execute pointer low byte, now points to code
.,A7DB 85 7A    STA $7A         save BASIC execute pointer low byte
.,A7DD 90 02    BCC $A7E1       branch if no overflow
.,A7DF E6 7B    INC $7B         else increment BASIC execute pointer high byte
.,A7E1 6C 08 03 JMP ($0308)     do start new BASIC code

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

.,A7E4 20 73 00 JSR $0073       increment and scan memory
.,A7E7 20 ED A7 JSR $A7ED       go interpret BASIC code from BASIC execute pointer
.,A7EA 4C AE A7 JMP $A7AE       loop

go interpret BASIC code from BASIC execute pointer

.,A7ED F0 3C    BEQ $A82B       if the first byte is null just exit
.,A7EF E9 80    SBC #$80        normalise the token
.,A7F1 90 11    BCC $A804       if wasn't token go do LET
.,A7F3 C9 23    CMP #$23        compare with token for TAB(-$80
.,A7F5 B0 17    BCS $A80E       branch if >= TAB(
.,A7F7 0A       ASL             *2 bytes per vector
.,A7F8 A8       TAY             copy to index
.,A7F9 B9 0D A0 LDA $A00D,Y     get vector high byte
.,A7FC 48       PHA             push on stack
.,A7FD B9 0C A0 LDA $A00C,Y     get vector low byte
.,A800 48       PHA             push on stack
.,A801 4C 73 00 JMP $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
.,A804 4C A5 A9 JMP $A9A5       perform LET
                                was not [EOL]
.,A807 C9 3A    CMP #$3A        comapre with ":"
.,A809 F0 D6    BEQ $A7E1       if ":" go execute new code
                                else ...
.,A80B 4C 08 AF JMP $AF08       do syntax error then warm start
                                token was >= TAB(
.,A80E C9 4B    CMP #$4B        compare with the token for GO
.,A810 D0 F9    BNE $A80B       if not "GO" do syntax error then warm start
                                else was "GO"
.,A812 20 73 00 JSR $0073       increment and scan memory
.,A815 A9 A4    LDA #$A4        set "TO" token
.,A817 20 FF AE JSR $AEFF       scan for CHR$(A), else do syntax error then warm start
.,A81A 4C A0 A8 JMP $A8A0       perform GOTO

perform RESTORE

.,A81D 38       SEC             set carry for subtract
.,A81E A5 2B    LDA $2B         get start of memory low byte
.,A820 E9 01    SBC #$01        -1
.,A822 A4 2C    LDY $2C         get start of memory high byte
.,A824 B0 01    BCS $A827branch if no rollunder
.,A826 88       DEY             else decrement high byte
.,A827 85 41    STA $41         set DATA pointer low byte
.,A829 84 42    STY $42         set DATA pointer high byte
.,A82B 60       RTS

do CRTL-C check vector

.,A82C 20 E1 FF JSR $FFE1       scan stop key

perform STOP

.,A82F B0 01    BCS $A832       if carry set do BREAK instead of just END

perform END

.,A831 18       CLC             clear carry
.,A832 D0 3C    BNE $A870       return if wasn't CTRL-C
.,A834 A5 7A    LDA $7A         get BASIC execute pointer low byte
.,A836 A4 7B    LDY $7B         get BASIC execute pointer high byte
.,A838 A6 3A    LDX $3A         get current line number high byte
.,A83A E8       INX             increment it
.,A83B F0 0C    BEQ $A849       branch if was immediate mode
.,A83D 85 3D    STA $3D         save continue pointer low byte
.,A83F 84 3E    STY $3E         save continue pointer high byte
.,A841 A5 39    LDA $39         get current line number low byte
.,A843 A4 3A    LDY $3A         get current line number high byte
.,A845 85 3B    STA $3B         save break line number low byte
.,A847 84 3C    STY $3C         save break line number high byte
.,A849 68       PLA             dump return address low byte
.,A84A 68       PLA             dump return address high byte
.,A84B A9 81    LDA #$81        set [CR][LF]"BREAK" pointer low byte
.,A84D A0 A3    LDY #$A3        set [CR][LF]"BREAK" pointer high byte
.,A84F 90 03    BCC $A854       if was program end skip the print string
.,A851 4C 69 A4 JMP $A469       print string and do warm start
.,A854 4C 86 E3 JMP $E386       do warm start

perform CONT

.,A857 D0 17    BNE $A870       exit if following byte to allow syntax error
.,A859 A2 1A    LDX #$1A        error code $1A, can't continue error
.,A85B A4 3E    LDY $3E         get continue pointer high byte
.,A85D D0 03    BNE $A862       go do continue if we can
.,A85F 4C 37 A4 JMP $A437       else do error #X then warm start
                                we can continue so ...
.,A862 A5 3D    LDA $3D         get continue pointer low byte
.,A864 85 7A    STA $7A         save BASIC execute pointer low byte
.,A866 84 7B    STY $7B         save BASIC execute pointer high byte
.,A868 A5 3B    LDA $3B         get break line low byte
.,A86A A4 3C    LDY $3C         get break line high byte
.,A86C 85 39    STA $39         set current line number low byte
.,A86E 84 3A    STY $3A         set current line number high byte
.,A870 60       RTS

perform RUN

.,A871 08       PHP             save status
.,A872 A9 00    LDA #$00        no control or kernal messages
.,A874 20 90 FF JSR $FF90       control kernal messages
.,A877 28       PLP             restore status
.,A878 D0 03    BNE $A87D       branch if RUN n
.,A87A 4C 59 A6 JMP $A659       reset execution to start, clear variables, flush stack
                                and return
.,A87D 20 60 A6 JSR $A660       go do "CLEAR"
.,A880 4C 97 A8 JMP $A897       get n and do GOTO n

perform GOSUB

.,A883 A9 03    LDA #$03        need 6 bytes for GOSUB
.,A885 20 FB A3 JSR $A3FB       check room on stack for 2*A bytes
.,A888 A5 7B    LDA $7B         get BASIC execute pointer high byte
.,A88A 48       PHA             save it
.,A88B A5 7A    LDA $7A         get BASIC execute pointer low byte
.,A88D 48       PHA             save it
.,A88E A5 3A    LDA $3A         get current line number high byte
.,A890 48       PHA             save it
.,A891 A5 39    LDA $39         get current line number low byte
.,A893 48       PHA             save it
.,A894 A9 8D    LDA #$8D        token for GOSUB
.,A896 48       PHA             save it
.,A897 20 79 00 JSR $0079       scan memory
.,A89A 20 A0 A8 JSR $A8A0       perform GOTO
.,A89D 4C AE A7 JMP $A7AE       go do interpreter inner loop

perform GOTO

.,A8A0 20 6B A9 JSR $A96B       get fixed-point number into temporary integer
.,A8A3 20 09 A9 JSR $A909       scan for next BASIC line
.,A8A6 38       SEC             set carry for subtract
.,A8A7 A5 39    LDA $39         get current line number low byte
.,A8A9 E5 14    SBC $14         subtract temporary integer low byte
.,A8AB A5 3A    LDA $3A         get current line number high byte
.,A8AD E5 15    SBC $15         subtract temporary integer high byte
.,A8AF B0 0B    BCS $A8BC       if current line number >= temporary integer, go search
                                from the start of memory
.,A8B1 98       TYA             else copy line index to A
.,A8B2 38       SEC             set carry (+1)
.,A8B3 65 7A    ADC $7A         add BASIC execute pointer low byte
.,A8B5 A6 7B    LDX $7B         get BASIC execute pointer high byte
.,A8B7 90 07    BCC $A8C0       branch if no overflow to high byte
.,A8B9 E8       INX             increment high byte
.,A8BA B0 04    BCS $A8C0       branch always (can never be carry)

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

.,A8BC A5 2B    LDA $2B         get start of memory low byte
.,A8BE A6 2C    LDX $2Cget start of memory high byte

search for line # in temporary integer from (AX)

.,A8C0 20 17 A6 JSR $A617       search Basic for temp integer line number from AX
.,A8C3 90 1E    BCC $A8E3       if carry clear go do unsdefined statement error
                                carry all ready set for subtract
.,A8C5 A5 5F    LDA $5F         get pointer low byte
.,A8C7 E9 01    SBC #$01        -1
.,A8C9 85 7A    STA $7A         save BASIC execute pointer low byte
.,A8CB A5 60    LDA $60         get pointer high byte
.,A8CD E9 00    SBC #$00        subtract carry
.,A8CF 85 7B    STA $7B         save BASIC execute pointer high byte
.,A8D1 60       RTS

perform RETURN

.,A8D2 D0 FD    BNE $A8D1       exit if following token to allow syntax error
.,A8D4 A9 FF    LDA #$FF        set byte so no match possible
.,A8D6 85 4A    STA $4A         save FOR/NEXT variable pointer high byte
.,A8D8 20 8A A3 JSR $A38A       search the stack for FOR or GOSUB activity,
                                get token off stack
.,A8DB 9A       TXScorrect the stack
.,A8DC C9 8D    CMP #$8D        compare with GOSUB token
.,A8DE F0 0B    BEQ $A8EB       if matching GOSUB go continue RETURN
.,A8E0 A2 0C    LDX #$0C        else error code $04, return without gosub error
.:A8E2 2C       .BYTE $2C       makes next line BIT $11A2
.,A8E3 A2 11    LDX #$02        error code $11, undefined statement error
.,A8E5 4C 37 A4 JMP $A437       do error #X then warm start
.,A8E8 4C 08 AF JMP $AF08       do syntax error then warm start
                                was matching GOSUB token
.,A8EB 68       PLA             dump token byte
.,A8EC 68       PLA             pull return line low byte
.,A8ED 85 39    STA $39         save current line number low byte
.,A8EF 68       PLA             pull return line high byte
.,A8F0 85 3A    STA $3A         save current line number high byte
.,A8F2 68       PLA             pull return address low byte
.,A8F3 85 7A    STA $7A         save BASIC execute pointer low byte
.,A8F5 68       PLA             pull return address high byte
.,A8F6 85 7B    STA $7B         save BASIC execute pointer high byte

perform DATA

.,A8F8 20 06 A9 JSR $A906       scan for next BASIC statement ([:] or [EOL])

add Y to the BASIC execute pointer

.,A8FB 98       TYA             copy index to A
.,A8FC 18       CLC             clear carry for add
.,A8FD 65 7A    ADC $7A         add BASIC execute pointer low byte
.,A8FF 85 7A    STA $7A         save BASIC execute pointer low byte
.,A901 90 02    BCC $A905       skip increment if no carry
.,A903 E6 7B    INC $7B         else increment BASIC execute pointer high byte
.,A905 60       RTS

scan for next BASIC statement ([:] or [EOL])

                                returns Y as index to [:] or [EOL]
.,A906 A2 3A    LDX #$3A        set look for character = ":"
.:A908 2C       .BYTE $2C       makes next line BIT $00A2

scan for next BASIC line

                                returns Y as index to [EOL]
.,A909 A2 00    LDX #$00        set alternate search character = [EOL]
.,A90B 86 07    STX $07         store alternate search character
.,A90D A0 00    LDY #$00        set search character = [EOL]
.,A90F 84 08    STY $08         save the search character
.,A911 A5 08    LDA $08         get search character
.,A913 A6 07    LDX $07         get alternate search character
.,A915 85 07    STA $07         make search character = alternate search character
.,A917 86 08    STX $08         make alternate search character = search character
.,A919 B1 7A    LDA ($7A),Y     get BASIC byte
.,A91B F0 E8    BEQ $A905       exit if null [EOL]
.,A91D C5 08    CMP $08         compare with search character
.,A91F F0 E4    BEQ $A905       exit if found
.,A921 C8       INY             else increment index
.,A922 C9 22    CMP #$22        compare current character with open quote
.,A924 D0 F3    BNE $A919       if found go swap search character for alternate search
                                character
.,A926 F0 E9    BEQ $A911       loop for next character, branch always

perform IF

.,A928 20 9E AD JSR $AD9E       evaluate expression
.,A92B 20 79 00 JSR $0079       scan memory
.,A92E C9 89    CMP #$89        compare with "GOTO" token
.,A930 F0 05    BEQ $A937       if it was  the token for GOTO go do IF ... GOTO
                                wasn't IF ... GOTO so must be IF ... THEN
.,A932 A9 A7    LDA #$A7        set "THEN" token
.,A934 20 FF AE JSR $AEFF       scan for CHR$(A), else do syntax error then warm start
.,A937 A5 61    LDA $61         get FAC1 exponent
.,A939 D0 05    BNE $A940       if result was non zero continue execution
                                else REM rest of line

perform REM

.,A93B 20 09 A9 JSR $A909       scan for next BASIC line
.,A93E F0 BB    BEQ $A8FB       add Y to the BASIC execute pointer and return, branch
                                always
                                result was non zero so do rest of line
.,A940 20 79 00 JSR $0079       scan memory
.,A943 B0 03    BCS $A948       branch if not numeric character, is variable or keyword
.,A945 4C A0 A8 JMP $A8A0       else perform GOTO n
                                is variable or keyword
.,A948 4C ED A7 JMP $A7ED       interpret BASIC code from BASIC execute pointer

perform ON

.,A94B 20 9E B7 JSR $B79E       get byte parameter
.,A94E 48       PHA             push next character
.,A94F C9 8D    CMP #$8D        compare with GOSUB token
.,A951 F0 04    BEQ $A957       if GOSUB go see if it should be executed
.,A953 C9 89    CMP #$89        compare with GOTO token
.,A955 D0 91    BNE $A8E8       if not GOTO do syntax error then warm start
                                next character was GOTO or GOSUB, see if it should be executed
.,A957 C6 65    DEC $65         decrement the byte value
.,A959 D0 04    BNE $A95F       if not zero go see if another line number exists
.,A95B 68       PLA             pull keyword token
.,A95C 4C EF A7 JMP $A7EF       go execute it
.,A95F 20 73 00 JSR $0073       increment and scan memory
.,A962 20 6B A9 JSR $A96B       get fixed-point number into temporary integer
                                skip this n
.,A965 C9 2C    CMP #$2C        compare next character with ","
.,A967 F0 EE    BEQ $A957       loop if ","
.,A969 68       PLA             else pull keyword token, ran out of options
.,A96A 60       RTS

get fixed-point number into temporary integer

.,A96B A2 00    LDX #$00        clear X
.,A96D 86 14    STX $14         clear temporary integer low byte
.,A96F 86 15    STX $15         clear temporary integer high byte
.,A971 B0 F7    BCS $A96A       return if carry set, end of scan, character was not 0-9
.,A973 E9 2F    SBC #$2F        subtract $30, $2F+carry, from byte
.,A975 85 07    STA $07         store #
.,A977 A5 15    LDA $15         get temporary integer high byte
.,A979 85 22    STA $22         save it for now
.,A97B C9 19    CMP #$19        compare with $19
.,A97D B0 D4    BCS $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 $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
                                $A955 skipping the second compare
.,A97F A5 14    LDA $14         get temporary integer low byte
.,A981 0A       ASL             *2 low byte
.,A982 26 22    ROL $22         *2 high byte
.,A984 0A       ASL             *2 low byte
.,A985 26 22    ROL $22         *2 high byte (*4)
.,A987 65 14    ADC $14         + low byte (*5)
.,A989 85 14    STA $14         save it
.,A98B A5 22    LDA $22         get high byte temp
.,A98D 65 15    ADC $15         + high byte (*5)
.,A98F 85 15    STA $15         save it
.,A991 06 14    ASL $14         *2 low byte (*10d)
.,A993 26 15    ROL $15         *2 high byte (*10d)
.,A995 A5 14    LDA $14         get low byte
.,A997 65 07    ADC $07         add #
.,A999 85 14    STA $14         save low byte
.,A99B 90 02    BCC $A99F       branch if no overflow to high byte
.,A99D E6 15    INC $15         else increment high byte
.,A99F 20 73 00 JSR $0073       increment and scan memory
.,A9A2 4C 71 A9 JMP $A971       loop for next character

perform LET

.,A9A5 20 8B B0 JSR $B08B       get variable address
.,A9A8 85 49    STA $49         save variable address low byte
.,A9AA 84 4A    STY $4A         save variable address high byte
.,A9AC A9 B2    LDA #$B2        $B2 is "=" token
.,A9AE 20 FF AE JSR $AEFF       scan for CHR$(A), else do syntax error then warm start
.,A9B1 A5 0E    LDA $0E         get data type flag, $80 = integer, $00 = float
.,A9B3 48       PHA             push data type flag
.,A9B4 A5 0D    LDA $0D         get data type flag, $FF = string, $00 = numeric
.,A9B6 48       PHA             push data type flag
.,A9B7 20 9E AD JSR $AD9E       evaluate expression
.,A9BA 68       PLA             pop data type flag
.,A9BB 2A       ROL             string bit into carry
.,A9BC 20 90 AD JSR $AD90       do type match check
.,A9BF D0 18    BNE $A9D9       branch if string
.,A9C1 68       PLA             pop integer/float data type flag
                                assign value to numeric variable
.,A9C2 10 12    BPL $A9D6       branch if float
                                expression is numeric integer
.,A9C4 20 1B BC JSR $BC1B       round FAC1
.,A9C7 20 BF B1 JSR $B1BF       evaluate integer expression, no sign check
.,A9CA A0 00    LDY #$00        clear index
.,A9CC A5 64    LDA $64         get FAC1 mantissa 3
.,A9CE 91 49    STA ($49),Y     save as integer variable low byte
.,A9D0 C8       INY             increment index
.,A9D1 A5 65    LDA $65         get FAC1 mantissa 4
.,A9D3 91 49    STA ($49),Y     save as integer variable high byte
.,A9D5 60       RTS
.,A9D6 4C D0 BB JMP $BBD0       pack FAC1 into variable pointer and return
                                assign value to numeric variable
.,A9D9 68       PLA             dump integer/float data type flag
.,A9DA A4 4A    LDY $4A         get variable pointer high byte
.,A9DC C0 BF    CPY #$BF        was it TI$ pointer
.,A9DE D0 4C    BNE $AA2C       branch if not
                                else it's TI$ = 
.,A9E0 20 A6 B6 JSR $B6A6       pop string off descriptor stack, or from top of string
                                space returns with A = length, X = pointer low byte,
                                Y = pointer high byte
.,A9E3 C9 06    CMP #$06        compare length with 6
.,A9E5 D0 3D    BNE $AA24       if length not 6 do illegal quantity error then warm start
.,A9E7 A0 00    LDY #$00        clear index
.,A9E9 84 61    STY $61         clear FAC1 exponent
.,A9EB 84 66    STY $66         clear FAC1 sign (b7)
.,A9ED 84 71    STY $71         save index
.,A9EF 20 1D AA JSR $AA1D       check and evaluate numeric digit
.,A9F2 20 E2 BA JSR $BAE2       multiply FAC1 by 10
.,A9F5 E6 71    INC $71         increment index
.,A9F7 A4 71    LDY $71         restore index
.,A9F9 20 1D AA JSR $AA1D       check and evaluate numeric digit
.,A9FC 20 0C BC JSR $BC0C       round and copy FAC1 to FAC2
.,A9FF AA       TAX             copy FAC1 exponent
.,AA00 F0 05    BEQ $AA07       branch if FAC1 zero
.,AA02 E8       INX             increment index, * 2
.,AA03 8A       TXA             copy back to A
.,AA04 20 ED BA JSR $BAED       FAC1 = (FAC1 + (FAC2 * 2)) * 2 = FAC1 * 6
.,AA07 A4 71    LDY $71         get index
.,AA09 C8       INY             increment index
.,AA0A C0 06    CPY #$06        compare index with 6
.,AA0C D0 DF    BNE $A9ED       loop if not 6
.,AA0E 20 E2 BA JSR $BAE2       multiply FAC1 by 10
.,AA11 20 9B BC JSR $BC9B       convert FAC1 floating to fixed
.,AA14 A6 64    LDX $64         get FAC1 mantissa 3
.,AA16 A4 63    LDY $63         get FAC1 mantissa 2
.,AA18 A5 65    LDA $65         get FAC1 mantissa 4
.,AA1A 4C DB FF JMP $FFDB       set real time clock and return

check and evaluate numeric digit

.,AA1D B1 22    LDA ($22),Y     get byte from string
.,AA1F 20 80 00 JSR $0080       clear Cb if numeric. this call should be to $84
                                as the code from $80 first comapres the byte with
                                [SPACE] and does a BASIC increment and get if it is
.,AA22 90 03    BCC $AA27       branch if numeric
.,AA24 4C 48 B2 JMP $B248       do illegal quantity error then warm start
.,AA27 E9 2F    SBC #$2F        subtract $2F + carry to convert ASCII to binary
.,AA29 4C 7E BD JMP $BD7E       evaluate new ASCII digit and return

assign value to numeric variable, but not TI$

.,AA2C A0 02    LDY #$02        index to string pointer high byte
.,AA2E B1 64    LDA ($64),Y     get string pointer high byte
.,AA30 C5 34    CMP $34         compare with bottom of string space high byte
.,AA32 90 17    BCC $AA4B       branch if string pointer high byte is less than bottom
                                of string space high byte
.,AA34 D0 07    BNE $AA3D       branch if string pointer high byte is greater than
                                bottom of string space high byte
                                else high bytes were equal
.,AA36 88       DEY             decrement index to string pointer low byte
.,AA37 B1 64    LDA ($64),Y     get string pointer low byte
.,AA39 C5 33    CMP $33         compare with bottom of string space low byte
.,AA3B 90 0E    BCC $AA4B       branch if string pointer low byte is less than bottom
                                of string space low byte
.,AA3D A4 65    LDY $65         get descriptor pointer high byte
.,AA3F C4 2E    CPY $2E         compare with start of variables high byte
.,AA41 90 08    BCC $AA4B       branch if less, is on string stack
.,AA43 D0 0D    BNE $AA52       if greater make space and copy string
                                else high bytes were equal
.,AA45 A5 64    LDA $64         get descriptor pointer low byte
.,AA47 C5 2D    CMP $2D         compare with start of variables low byte
.,AA49 B0 07    BCS $AA52       if greater or equal make space and copy string
.,AA4B A5 64    LDA $64         get descriptor pointer low byte
.,AA4D A4 65    LDY $65         get descriptor pointer high byte
.,AA4F 4C 68 AA JMP $AA68       go copy descriptor to variable
.,AA52 A0 00    LDY #$00        clear index
.,AA54 B1 64    LDA ($64),Y     get string length
.,AA56 20 75 B4 JSR $B475       copy descriptor pointer and make string space A bytes long
.,AA59 A5 50    LDA $50         copy old descriptor pointer low byte
.,AA5B A4 51    LDY $51         copy old descriptor pointer high byte
.,AA5D 85 6F    STA $6F         save old descriptor pointer low byte
.,AA5F 84 70    STY $70         save old descriptor pointer high byte
.,AA61 20 7A B6 JSR $B67A       copy string from descriptor to utility pointer
.,AA64 A9 61    LDA #$61        get descriptor pointer low byte
.,AA66 A0 00    LDY #$00        get descriptor pointer high byte
.,AA68 85 50    STA $50         save descriptor pointer low byte
.,AA6A 84 51    STY $51         save descriptor pointer high byte
.,AA6C 20 DB B6 JSR $B6DB       clean descriptor stack, YA = pointer
.,AA6F A0 00    LDY #$00        clear index
.,AA71 B1 50    LDA ($50),Y     get string length from new descriptor
.,AA73 91 49    STA ($49),Y     copy string length to variable
.,AA75 C8       INY             increment index
.,AA76 B1 50    LDA ($50),Y     get string pointer low byte from new descriptor
.,AA78 91 49    STA ($49),Y     copy string pointer low byte to variable
.,AA7A C8       INY             increment index
.,AA7B B1 50    LDA ($50),Y     get string pointer high byte from new descriptor
.,AA7D 91 49    STA ($49),Y     copy string pointer high byte to variable
.,AA7F 60       RTS

perform PRINT#

.,AA80 20 86 AA JSR $AA86       perform CMD
.,AA83 4C B5 AB JMP $ABB5       close input and output channels and return

perform CMD

.,AA86 20 9E B7 JSR $B79E       get byte parameter
.,AA89 F0 05    BEQ $AA90       branch if following byte is ":" or [EOT]
.,AA8B A9 2C    LDA #$2C        set ","
.,AA8D 20 FF AE JSR $AEFF       scan for CHR$(A), else do syntax error then warm start
.,AA90 08       PHP             save status
.,AA91 86 13    STX $13         set current I/O channel
.,AA93 20 18 E1 JSR $E118       open channel for output with error check
.,AA96 28       PLP             restore status
.,AA97 4C A0 AA JMP $AAA0       perform PRINT
.,AA9A 20 21 AB JSR $AB21       print string from utility pointer
.,AA9D 20 79 00 JSR $0079       scan memory

perform PRINT

.,AAA0 F0 35    BEQ $AAD7       if nothing following just print CR/LF
.,AAA2 F0 43    BEQ $AAE7       exit if nothing following, end of PRINT branch
.,AAA4 C9 A3    CMP #$A3        compare with token for TAB(
.,AAA6 F0 50    BEQ $AAF8       if TAB( go handle it
.,AAA8 C9 A6    CMP #$A6        compare with token for SPC(
.,AAAA 18       CLC             flag SPC(
.,AAAB F0 4B    BEQ $AAF8       if SPC( go handle it
.,AAAD C9 2C    CMP #$2C        compare with ","
.,AAAF F0 37    BEQ $AAE8       if "," go skip to the next TAB position
.,AAB1 C9 3B    CMP #$3B        compare with ";"
.,AAB3 F0 5E    BEQ $AB13       if ";" go continue the print loop
.,AAB5 20 9E AD JSR $AD9E       evaluate expression
.,AAB8 24 0D    BIT $0D         test data type flag, $FF = string, $00 = numeric
.,AABA 30 DE    BMI $AA9A       if string go print string, scan memory and continue PRINT
.,AABC 20 DD BD JSR $BDDD       convert FAC1 to ASCII string result in (AY)
.,AABF 20 87 B4 JSR $B487       print " terminated string to utility pointer
.,AAC2 20 21 AB JSR $AB21       print string from utility pointer
.,AAC5 20 3B AB JSR $AB3B       print [SPACE] or [CURSOR RIGHT]
.,AAC8 D0 D3    BNE $AA9D       go scan memory and continue PRINT, branch always

set XY to $0200 - 1 and print [CR]

.,AACA A9 00    LDA #$00        clear A
.,AACC 9D 00 02 STA $0200,X     clear first byte of input buffer
.,AACF A2 FF    LDX #$FF        $0200 - 1 low byte
.,AAD1 A0 01    LDY #$01        $0200 - 1 high byte
.,AAD3 A5 13    LDA $13         get current I/O channel
.,AAD5 D0 10    BNE $AAE7       exit if not default channel

print CR/LF

.,AAD7 A9 0D    LDA #$0D        set [CR]
.,AAD9 20 47 AB JSR $AB47       print the character
.,AADC 24 13    BIT $13         test current I/O channel
.,AADE 10 05    BPL $AAE5       if ?? toggle A, EOR #$FF and return
.,AAE0 A9 0A    LDA #$0A        set [LF]
.,AAE2 20 47 AB JSR $AB47       print the character
                                toggle A
.,AAE5 49 FF    EOR #$FF        invert A
.,AAE7 60       RTS
                                was ","
.,AAE8 38       SEC             set Cb for read cursor position
.,AAE9 20 F0 FF JSR $FFF0       read/set X,Y cursor position
.,AAEC 98       TYA             copy cursor Y
.,AAED 38       SEC             set carry for subtract
.,AAEE E9 0A    SBC #$0A        subtract one TAB length
.,AAF0 B0 FC    BCS $AAEE       loop if result was +ve
.,AAF2 49 FF    EOR #$FF        complement it
.,AAF4 69 01    ADC #$01        +1, twos complement
.,AAF6 D0 16    BNE $AB0E       always print A spaces, result is never $00
.,AAF8 08       PHP             save TAB( or SPC( status
.,AAF9 38       SEC             set Cb for read cursor position
.,AAFA 20 F0 FF JSR $FFF0       read/set X,Y cursor position
.,AAFD 84 09    STY $09         save current cursor position
.,AAFF 20 9B B7 JSR $B79B       scan and get byte parameter
.,AB02 C9 29    CMP #$29        compare with ")"
.,AB04 D0 59    BNE $AB5F       if not ")" do syntax error
.,AB06 28       PLP             restore TAB( or SPC( status
.,AB07 90 06    BCC $AB0F       branch if was SPC(
                                else was TAB(
.,AB09 8A       TXA             copy TAB() byte to A
.,AB0A E5 09    SBC $09         subtract current cursor position
.,AB0C 90 05    BCC $AB13       go loop for next if already past requited position
.,AB0E AA       TAX             copy [SPACE] count to X
.,AB0F E8       INX             increment count
.,AB10 CA       DEX             decrement count
.,AB11 D0 06    BNE $AB19       branch if count was not zero
                                was ";" or [SPACES] printed
.,AB13 20 73 00 JSR $0073       increment and scan memory
.,AB16 4C A2 AA JMP $AAA2       continue print loop
.,AB19 20 3B AB JSR $AB3B       print [SPACE] or [CURSOR RIGHT]
.,AB1C D0 F2    BNE $AB10       loop, branch always

print null terminated string

.,AB1E 20 87 B4 JSR $B487       print " terminated string to utility pointer

print string from utility pointer

.,AB21 20 A6 B6 JSR $B6A6       pop string off descriptor stack, or from top of string
                                space returns with A = length, X = pointer low byte,
                                Y = pointer high byte
.,AB24 AA       TAX             copy length
.,AB25 A0 00    LDY #$00        clear index
.,AB27 E8       INX             increment length, for pre decrement loop
.,AB28 CA       DEX             decrement length
.,AB29 F0 BC    BEQ $AAE7       exit if done
.,AB2B B1 22    LDA ($22),Y     get byte from string
.,AB2D 20 47 AB JSR $AB47       print the character
.,AB30 C8       INY             increment index
.,AB31 C9 0D    CMP #$0D        compare byte with [CR]
.,AB33 D0 F3    BNE $AB28       loop if not [CR]
.,AB35 20 E5 AA JSR $AAE5       toggle A, EOR #$FF. what is the point of this ??
.,AB38 4C 28 AB JMP $AB28       loop

print [SPACE] or [CURSOR RIGHT]

.,AB3B A5 13    LDA $13         get current I/O channel
.,AB3D F0 03    BEQ $AB42       if default channel go output [CURSOR RIGHT]
.,AB3F A9 20    LDA #$20        else output [SPACE]
.:AB41 2C       .BYTE $2C       makes next line BIT $1DA9
.,AB42 A9 1D    LDA #$1D        set [CURSOR RIGHT]
.:AB44 2C       .BYTE $2C       makes next line BIT $3FA9

print "?"

.,AB45 A9 3F    LDA #$3F        set "?"

print character

.,AB47 20 0C E1 JSR $E10C       output character to channel with error check
.,AB4A 29 FF    AND #$FF        set the flags on A
.,AB4C 60       RTS

bad input routine

.,AB4D A5 11    LDA $11         get INPUT mode flag, $00 = INPUT, $40 = GET, $98 = READ
.,AB4F F0 11    BEQ $AB62       branch if INPUT
.,AB51 30 04    BMI $AB57       branch if READ
                                else was GET
.,AB53 A0 FF    LDY #$FF        set current line high byte to -1, indicate immediate mode
.,AB55 D0 04    BNE $AB5B       branch always
.,AB57 A5 3F    LDA $3F         get current DATA line number low byte
.,AB59 A4 40    LDY $40         get current DATA line number high byte
.,AB5B 85 39    STA $39         set current line number low byte
.,AB5D 84 3A    STY $3A         set current line number high byte
.,AB5F 4C 08 AF JMP $AF08       do syntax error then warm start
                                was INPUT
.,AB62 A5 13    LDA $13         get current I/O channel
.,AB64 F0 05    BEQ $AB6B       branch if default channel
.,AB66 A2 18    LDX #$18        else error $18, file data error
.,AB68 4C 37 A4 JMP $A437       do error #X then warm start
.,AB6B A9 0C    LDA #$0C        set "?REDO FROM START" pointer low byte
.,AB6D A0 AD    LDY #$AD        set "?REDO FROM START" pointer high byte
.,AB6F 20 1E AB JSR $AB1E       print null terminated string
.,AB72 A5 3D    LDA $3D         get continue pointer low byte
.,AB74 A4 3E    LDY $3E         get continue pointer high byte
.,AB76 85 7A    STA $7A         save BASIC execute pointer low byte
.,AB78 84 7B    STY $7B         save BASIC execute pointer high byte
.,AB7A 60       RTS

perform GET

.,AB7B 20 A6 B3 JSR $B3A6       check not Direct, back here if ok
.,AB7E C9 23    CMP #$23        compare with "#"
.,AB80 D0 10    BNE $AB92       branch if not GET#
.,AB82 20 73 00 JSR $0073       increment and scan memory
.,AB85 20 9E B7 JSR $B79E       get byte parameter
.,AB88 A9 2C    LDA #$2C        set ","
.,AB8A 20 FF AE JSR $AEFF       scan for CHR$(A), else do syntax error then warm start
.,AB8D 86 13    STX $13         set current I/O channel
.,AB8F 20 1E E1 JSR $E11E       open channel for input with error check
.,AB92 A2 01    LDX #$01        set pointer low byte
.,AB94 A0 02    LDY #$02        set pointer high byte
.,AB96 A9 00    LDA #$00        clear A
.,AB98 8D 01 02 STA $0201       ensure null terminator
.,AB9B A9 40    LDA #$40        input mode = GET
.,AB9D 20 0F AC JSR $AC0F       perform the GET part of READ
.,ABA0 A6 13    LDX $13         get current I/O channel
.,ABA2 D0 13    BNE $ABB7       if not default channel go do channel close and return
.,ABA4 60       RTS

perform INPUT#

.,ABA5 20 9E B7 JSR $B79E       get byte parameter
.,ABA8 A9 2C    LDA #$2C        set ","
.,ABAA 20 FF AE JSR $AEFF       scan for CHR$(A), else do syntax error then warm start
.,ABAD 86 13    STX $13         set current I/O channel
.,ABAF 20 1E E1 JSR $E11E       open channel for input with error check
.,ABB2 20 CE AB JSR $ABCE       perform INPUT with no prompt string

close input and output channels

.,ABB5 A5 13    LDA $13         get current I/O channel
.,ABB7 20 CC FF JSR $FFCC       close input and output channels
.,ABBA A2 00    LDX #$00        clear X
.,ABBC 86 13    STX $13         clear current I/O channel, flag default
.,ABBE 60       RTS

perform INPUT

.,ABBF C9 22    CMP #$22        compare next byte with open quote
.,ABC1 D0 0B    BNE $ABCE       if no prompt string just do INPUT
.,ABC3 20 BD AE JSR $AEBD       print "..." string
.,ABC6 A9 3B    LDA #$3B        load A with ";"
.,ABC8 20 FF AE JSR $AEFF       scan for CHR$(A), else do syntax error then warm start
.,ABCB 20 21 AB JSR $AB21       print string from utility pointer
                                done with prompt, now get data
.,ABCE 20 A6 B3 JSR $B3A6       check not Direct, back here if ok
.,ABD1 A9 2C    LDA #$2C        set ","
.,ABD3 8D FF 01 STA $01FF       save to start of buffer - 1
.,ABD6 20 F9 AB JSR $ABF9       print "? " and get BASIC input
.,ABD9 A5 13    LDA $13         get current I/O channel
.,ABDB F0 0D    BEQ $ABEA       branch if default I/O channel
.,ABDD 20 B7 FF JSR $FFB7       read I/O status word
.,ABE0 29 02    AND #$02        mask no DSR/timeout
.,ABE2 F0 06    BEQ $ABEA       branch if not error
.,ABE4 20 B5 AB JSR $ABB5       close input and output channels
.,ABE7 4C F8 A8 JMP $A8F8       perform DATA
.,ABEA AD 00 02 LDA $0200       get first byte in input buffer
.,ABED D0 1E    BNE $AC0D       branch if not null
                                else ..
.,ABEF A5 13    LDA $13         get current I/O channel
.,ABF1 D0 E3    BNE $ABD6       if not default channel go get BASIC input
.,ABF3 20 06 A9 JSR $A906       scan for next BASIC statement ([:] or [EOL])
.,ABF6 4C FB A8 JMP $A8FB       add Y to the BASIC execute pointer and return

print "? " and get BASIC input

.,ABF9 A5 13    LDA $13         get current I/O channel
.,ABFB D0 06    BNE $AC03       skip "?" prompt if not default channel
.,ABFD 20 45 AB JSR $AB45       print "?"
.,AC00 20 3B AB JSR $AB3B       print [SPACE] or [CURSOR RIGHT]
.,AC03 4C 60 A5 JMP $A560       call for BASIC input and return

perform READ

.,AC06 A6 41    LDX $41         get DATA pointer low byte
.,AC08 A4 42    LDY $42         get DATA pointer high byte
.,AC0A A9 98    LDA #$98        set input mode = READ
.:AC0C 2C       .BYTE $2C       makes next line BIT $00A9
.,AC0D A9 00    LDA #$00        set input mode = INPUT

perform GET

.,AC0F 85 11    STA $11         set input mode flag, $00 = INPUT, $40 = GET, $98 = READ
.,AC11 86 43    STX $43         save READ pointer low byte
.,AC13 84 44    STY $44         save READ pointer high byte
                                READ, GET or INPUT next variable from list
.,AC15 20 8B B0 JSR $B08B       get variable address
.,AC18 85 49    STA $49         save address low byte
.,AC1A 84 4A    STY $4A         save address high byte
.,AC1C A5 7A    LDA $7A         get BASIC execute pointer low byte
.,AC1E A4 7B    LDY $7B         get BASIC execute pointer high byte
.,AC20 85 4B    STA $4B         save BASIC execute pointer low byte
.,AC22 84 4C    STY $4C         save BASIC execute pointer high byte
.,AC24 A6 43    LDX $43         get READ pointer low byte
.,AC26 A4 44    LDY $44         get READ pointer high byte
.,AC28 86 7A    STX $7A         save as BASIC execute pointer low byte
.,AC2A 84 7B    STY $7B         save as BASIC execute pointer high byte
.,AC2C 20 79 00 JSR $0079       scan memory
.,AC2F D0 20    BNE $AC51       branch if not null
                                pointer was to null entry
.,AC31 24 11    BIT $11         test input mode flag, $00 = INPUT, $40 = GET, $98 = READ
.,AC33 50 0C    BVC $AC41       branch if not GET
                                else was GET
.,AC35 20 24 E1 JSR $E124       get character from input device with error check
.,AC38 8D 00 02 STA $0200       save to buffer
.,AC3B A2 FF    LDX #$FF        set pointer low byte
.,AC3D A0 01    LDY #$01        set pointer high byte
.,AC3F D0 0C    BNE $AC4D       go interpret single character
.,AC41 30 75    BMI $ACB8       branch if READ
                                else was INPUT
.,AC43 A5 13    LDA $13         get current I/O channel
.,AC45 D0 03    BNE $AC4A       skip "?" prompt if not default channel
.,AC47 20 45 AB JSR $AB45       print "?"
.,AC4A 20 F9 AB JSR $ABF9       print "? " and get BASIC input
.,AC4D 86 7A    STX $7A         save BASIC execute pointer low byte
.,AC4F 84 7B    STY $7B         save BASIC execute pointer high byte
.,AC51 20 73 00 JSR $0073       increment and scan memory, execute pointer now points to
                                start of next data or null terminator
.,AC54 24 0D    BIT $0D         test data type flag, $FF = string, $00 = numeric
.,AC56 10 31    BPL $AC89       branch if numeric
                                type is string
.,AC58 24 11    BIT $11         test INPUT mode flag, $00 = INPUT, $40 = GET, $98 = READ
.,AC5A 50 09    BVC $AC65       branch if not GET
                                else do string GET
.,AC5C E8       INX             clear X ??
.,AC5D 86 7A    STX $7A         save BASIC execute pointer low byte
.,AC5F A9 00    LDA #$00        clear A
.,AC61 85 07    STA $07         clear search character
.,AC63 F0 0C    BEQ $AC71       branch always
                                is string INPUT or string READ
.,AC65 85 07    STA $07         save search character
.,AC67 C9 22    CMP #$22        compare with "
.,AC69 F0 07    BEQ $AC72       branch if quote
                                string is not in quotes so ":", "," or $00 are the
                                termination characters
.,AC6B A9 3A    LDA #$3A        set ":"
.,AC6D 85 07    STA $07         set search character
.,AC6F A9 2C    LDA #$2C        set ","
.,AC71 18       CLC             clear carry for add
.,AC72 85 08    STA $08         set scan quotes flag
.,AC74 A5 7A    LDA $7A         get BASIC execute pointer low byte
.,AC76 A4 7B    LDY $7B         get BASIC execute pointer high byte
.,AC78 69 00    ADC #$00        add to pointer low byte. this add increments the pointer
                                if the mode is INPUT or READ and the data is a "..."
                                string
.,AC7A 90 01    BCC $AC7D       branch if no rollover
.,AC7C C8       INY             else increment pointer high byte
.,AC7D 20 8D B4 JSR $B48D       print string to utility pointer
.,AC80 20 E2 B7 JSR $B7E2       restore BASIC execute pointer from temp
.,AC83 20 DA A9 JSR $A9DA       perform string LET
.,AC86 4C 91 AC JMP $AC91       continue processing command
                                GET, INPUT or READ is numeric
.,AC89 20 F3 BC JSR $BCF3       get FAC1 from string
.,AC8C A5 0E    LDA $0E         get data type flag, $80 = integer, $00 = float
.,AC8E 20 C2 A9 JSR $A9C2       assign value to numeric variable
.,AC91 20 79 00 JSR $0079       scan memory
.,AC94 F0 07    BEQ $AC9D       branch if ":" or [EOL]
.,AC96 C9 2C    CMP #$2C        comparte with ","
.,AC98 F0 03    BEQ $AC9D       branch if ","
.,AC9A 4C 4D AB JMP $AB4D       else go do bad input routine
                                string terminated with ":", "," or $00
.,AC9D A5 7A    LDA $7A         get BASIC execute pointer low byte
.,AC9F A4 7B    LDY $7B         get BASIC execute pointer high byte
.,ACA1 85 43    STA $43         save READ pointer low byte
.,ACA3 84 44    STY $44         save READ pointer high byte
.,ACA5 A5 4B    LDA $4B         get saved BASIC execute pointer low byte
.,ACA7 A4 4C    LDY $4C         get saved BASIC execute pointer high byte
.,ACA9 85 7A    STA $7A         restore BASIC execute pointer low byte
.,ACAB 84 7B    STY $7B         restore BASIC execute pointer high byte
.,ACAD 20 79 00 JSR $0079       scan memory
.,ACB0 F0 2D    BEQ $ACDF       branch if ":" or [EOL]
.,ACB2 20 FD AE JSR $AEFD       scan for ",", else do syntax error then warm start
.,ACB5 4C 15 AC JMP $AC15       go READ or INPUT next variable from list
                                was READ
.,ACB8 20 06 A9 JSR $A906       scan for next BASIC statement ([:] or [EOL])
.,ACBB C8       INY             increment index to next byte
.,ACBC AA       TAX             copy byte to X
.,ACBD D0 12    BNE $ACD1       branch if ":"
.,ACBF A2 0D    LDX #$0D        else set error $0D, out of data error
.,ACC1 C8       INY             increment index to next line pointer high byte
.,ACC2 B1 7A    LDA ($7A),Y     get next line pointer high byte
.,ACC4 F0 6C    BEQ $AD32       branch if program end, eventually does error X
.,ACC6 C8       INY             increment index
.,ACC7 B1 7A    LDA ($7A),Y     get next line # low byte
.,ACC9 85 3F    STA $3F         save current DATA line low byte
.,ACCB C8       INY             increment index
.,ACCC B1 7A    LDA ($7A),Y     get next line # high byte
.,ACCE C8       INY             increment index
.,ACCF 85 40    STA $40         save current DATA line high byte
.,ACD1 20 FB A8 JSR $A8FB       add Y to the BASIC execute pointer
.,ACD4 20 79 00 JSR $0079       scan memory
.,ACD7 AA       TAX             copy the byte
.,ACD8 E0 83    CPX #$83        compare it with token for DATA
.,ACDA D0 DC    BNE $ACB8       loop if not DATA
.,ACDC 4C 51 AC JMP $AC51       continue evaluating READ
.,ACDF A5 43    LDA $43         get READ pointer low byte
.,ACE1 A4 44    LDY $44         get READ pointer high byte
.,ACE3 A6 11    LDX $11         get INPUT mode flag, $00 = INPUT, $40 = GET, $98 = READ
.,ACE5 10 03    BPL $ACEA       branch if INPUT or GET
.,ACE7 4C 27 A8 JMP $A827       else set data pointer and exit
.,ACEA A0 00    LDY #$00        clear index
.,ACEC B1 43    LDA ($43),Y     get READ byte
.,ACEE F0 0B    BEQ $ACFB       exit if [EOL]
.,ACF0 A5 13    LDA $13         get current I/O channel
.,ACF2 D0 07    BNE $ACFB       exit if not default channel
.,ACF4 A9 FC    LDA #$FC        set "?EXTRA IGNORED" pointer low byte
.,ACF6 A0 AC    LDY #$AC        set "?EXTRA IGNORED" pointer high byte
.,ACF8 4C 1E AB JMP $AB1E       print null terminated string
.,ACFB 60       RTS

input error messages

.:ACFC 3F 45 58 54 52 41 20 49  '?extra ignored'
.:AD04 47 4E 4F 52 45 44 0D 00
.:AD0C 3F 52 45 44 4F 20 46 52  '?redo from start'
.:AD14 4F 4D 20 53 54 41 52 54
.:AD1C 0D 00

perform NEXT

.,AD1E D0 04    BNE $AD24       branch if NEXT variable
.,AD20 A0 00    LDY #$00        else clear Y
.,AD22 F0 03    BEQ $AD27       branch always
                                NEXT variable
.,AD24 20 8B B0 JSR $B08B       get variable address
.,AD27 85 49    STA $49         save FOR/NEXT variable pointer low byte
.,AD29 84 4A    STY $4A         save FOR/NEXT variable pointer high byte
                                (high byte cleared if no variable defined)
.,AD2B 20 8A A3 JSR $A38A       search the stack for FOR or GOSUB activity
.,AD2E F0 05    BEQ $AD35       branch if FOR, this variable, found
.,AD30 A2 0A    LDX #$0A        else set error $0A, next without for error
.,AD32 4C 37 A4 JMP $A437       do error #X then warm start
                                found this FOR variable
.,AD35 9A       TXS             update stack pointer
.,AD36 8A       TXA             copy stack pointer
.,AD37 18       CLC             clear carry for add
.,AD38 69 04    ADC #$04        point to STEP value
.,AD3A 48       PHA             save it
.,AD3B 69 06    ADC #$06        point to TO value
.,AD3D 85 24    STA $24         save pointer to TO variable for compare
.,AD3F 68       PLA             restore pointer to STEP value
.,AD40 A0 01    LDY #$01        point to stack page
.,AD42 20 A2 BB JSR $BBA2       unpack memory (AY) into FAC1
.,AD45 BA       TSX             get stack pointer back
.,AD46 BD 09 01 LDA $0109,X     get step sign
.,AD49 85 66    STA $66         save FAC1 sign (b7)
.,AD4B A5 49    LDA $49         get FOR/NEXT variable pointer low byte
.,AD4D A4 4A    LDY $4A         get FOR/NEXT variable pointer high byte
.,AD4F 20 67 B8 JSR $B867       add FOR variable to FAC1
.,AD52 20 D0 BB JSR $BBD0       pack FAC1 into FOR variable
.,AD55 A0 01    LDY #$01        point to stack page
.,AD57 20 5D BC JSR $BC5D       compare FAC1 with TO value
.,AD5A BA       TSX             get stack pointer back
.,AD5B 38       SEC             set carry for subtract
.,AD5C FD 09 01 SBC $0109,X     subtract step sign
.,AD5F F0 17    BEQ $AD78       branch if =, loop complete
                                loop back and do it all again
.,AD61 BD 0F 01 LDA $010F,X     get FOR line low byte
.,AD64 85 39    STA $39         save current line number low byte
.,AD66 BD 10 01 LDA $0110,X     get FOR line high byte
.,AD69 85 3A    STA $3A         save current line number high byte
.,AD6B BD 12 01 LDA $0112,X     get BASIC execute pointer low byte
.,AD6E 85 7A    STA $7A         save BASIC execute pointer low byte
.,AD70 BD 11 01 LDA $0111,X     get BASIC execute pointer high byte
.,AD73 85 7B    STA $7B         save BASIC execute pointer high byte
.,AD75 4C AE A7 JMP $A7AE       go do interpreter inner loop
                                NEXT loop comlete
.,AD78 8A       TXA             stack copy to A
.,AD79 69 11    ADC #$11        add $12, $11 + carry, to dump FOR structure
.,AD7B AA       TAX             copy back to index
.,AD7C 9A       TXS             copy to stack pointer
.,AD7D 20 79 00 JSR $0079       scan memory
.,AD80 C9 2C    CMP #$2C        compare with ","
.,AD82 D0 F1    BNE $AD75       if not "," go do interpreter inner loop
                                was "," so another NEXT variable to do
.,AD84 20 73 00 JSR $0073       increment and scan memory
.,AD87 20 24 AD JSR $AD24       do NEXT variable

evaluate expression and check type mismatch

.,AD8A 20 9E AD JSR $AD9E       evaluate expression
                                check if source and destination are numeric
.,AD8D 18       CLC
.:AD8E 24       .BYTE $24       makes next line BIT $38
                                check if source and destination are string
.,AD8F 38       SEC             destination is string
                                type match check, set C for string, clear C for numeric
.,AD90 24 0D    BIT $0D         test data type flag, $FF = string, $00 = numeric
.,AD92 30 03    BMI $AD97       branch if string
.,AD94 B0 03    BCS $AD99       if destiantion is numeric do type missmatch error
.,AD96 60       RTS
.,AD97 B0 FD    BCS $AD96       exit if destination is string
                                do type missmatch error
.,AD99 A2 16    LDX #$16        error code $16, type missmatch error
.,AD9B 4C 37 A4 JMP $A437       do error #X then warm start

evaluate expression

.,AD9E A6 7A    LDX $7A         get BASIC execute pointer low byte
.,ADA0 D0 02    BNE $ADA4       skip next if not zero
.,ADA2 C6 7B    DEC $7B         else decrement BASIC execute pointer high byte
.,ADA4 C6 7A    DEC $7A         decrement BASIC execute pointer low byte
.,ADA6 A2 00    LDX #$00        set null precedence, flag done
.:ADA8 24       .BYTE $24       makes next line BIT $48
.,ADA9 48       PHA             push compare evaluation byte if branch to here
.,ADAA 8A       TXA             copy precedence byte
.,ADAB 48       PHA             push precedence byte
.,ADAC A9 01    LDA #$01        2 bytes
.,ADAE 20 FB A3 JSR $A3FB       check room on stack for A*2 bytes
.,ADB1 20 83 AE JSR $AE83       get value from line
.,ADB4 A9 00    LDA #$00        clear A
.,ADB6 85 4D    STA $4D         clear comparrison evaluation flag
.,ADB8 20 79 00 JSR $0079       scan memory
.,ADBB 38       SEC             set carry for subtract
.,ADBC E9 B1    SBC #$B1        subtract the token for ">"
.,ADBE 90 17    BCC $ADD7       branch if < ">"
.,ADC0 C9 03    CMP #$03        compare with ">" to +3
.,ADC2 B0 13    BCS $ADD7       branch if >= 3
                                was token for ">" "=" or "<"
.,ADC4 C9 01    CMP #$01compare with token for =
.,ADC6 2A       ROL             *2, b0 = carry (=1 if token was = or <)
.,ADC7 49 01    EOR #$01        toggle b0
.,ADC9 45 4D    EOR $4D         EOR with comparrison evaluation flag
.,ADCB C5 4D    CMP $4D         compare with comparrison evaluation flag
.,ADCD 90 61    BCC $AE30       if < saved flag do syntax error then warm start
.,ADCF 85 4D    STA $4D         save new comparrison evaluation flag
.,ADD1 20 73 00 JSR $0073       increment and scan memory
.,ADD4 4C BB AD JMP $ADBB       go do next character
.,ADD7 A6 4D    LDX $4D         get comparrison evaluation flag
.,ADD9 D0 2C    BNE $AE07       branch if compare function
.,ADDB B0 7B    BCS $AE58       go do functions
                                else was < TK_GT so is operator or lower
.,ADDD 69 07    ADC #$07        add # of operators (+, -, *, /, ^, AND or OR)
.,ADDF 90 77    BCC $AE58       branch if < + operator
                                carry was set so token was +, -, *, /, ^, AND or OR
.,ADE1 65 0D    ADC $0D         add data type flag, $FF = string, $00 = numeric
.,ADE3 D0 03    BNE $ADE8       branch if not string or not + token
                                will only be $00 if type is string and token was +
.,ADE5 4C 3D B6 JMP $B63D       add strings, string 1 is in the descriptor, string 2
                                is in line, and return
.,ADE8 69 FF    ADC #$FF        -1 (corrects for carry add)
.,ADEA 85 22    STA $22         save it
.,ADEC 0A       ASL             *2
.,ADED 65 22    ADC $22         *3
.,ADEF A8       TAY             copy to index
.,ADF0 68       PLA             pull previous precedence
.,ADF1 D9 80 A0 CMP $A080,Y     compare with precedence byte
.,ADF4 B0 67    BCS $AE5D       branch if A >=
.,ADF6 20 8D AD JSR $AD8D       check if source is numeric, else do type mismatch
.,ADF9 48       PHA             save precedence
.,ADFA 20 20 AE JSR $AE20       get vector, execute function then continue evaluation
.,ADFD 68       PLArestore precedence
.,ADFE A4 4B    LDY $4B         get precedence stacked flag
.,AE00 10 17    BPL $AE19       branch if stacked values
.,AE02 AA       TAX             copy precedence, set flags
.,AE03 F0 56    BEQ $AE5B       exit if done
.,AE05 D0 5F    BNE $AE66       else pop FAC2 and return, branch always
.,AE07 46 0D    LSR $0D         clear data type flag, $FF = string, $00 = numeric
.,AE09 8A       TXA             copy compare function flag
.,AE0A 2A       ROL             <<1, shift data type flag into b0, 1 = string, 0 = num
.,AE0B A6 7A    LDX $7A         get BASIC execute pointer low byte
.,AE0D D0 02    BNE $AE11       branch if no underflow
.,AE0F C6 7B    DEC $7B         else decrement BASIC execute pointer high byte
.,AE11 C6 7A    DEC $7A         decrement BASIC execute pointer low byte
.,AE13 A0 1B    LDY #$1B
                                set offset to = operator precedence entry
.,AE15 85 4D    STA $4D         save new comparrison evaluation flag
.,AE17 D0 D7    BNE $ADF0       branch always
.,AE19 D9 80 A0 CMP $A080,Y     compare with stacked function precedence
.,AE1C B0 48    BCS $AE66       if A >=, pop FAC2 and return
.,AE1E 90 D9    BCC $ADF9       else go stack this one and continue, branch always

get vector, execute function then continue evaluation

.,AE20 B9 82 A0 LDA $A082,Y     get function vector high byte
.,AE23 48       PHA             onto stack
.,AE24 B9 81 A0 LDA $A081,Y     get function vector low byte
.,AE27 48       PHA             onto stack
                                now push sign, round FAC1 and put on stack
.,AE28 20 33 AE JSR $AE33       function will return here, then the next RTS will call
                                the function
.,AE2B A5 4D    LDA $4D         get comparrison evaluation flag
.,AE2D 4C A9 AD JMP $ADA9       continue evaluating expression
.,AE30 4C 08 AF JMP $AF08       do syntax error then warm start
.,AE33 A5 66    LDA $66         get FAC1 sign (b7)
.,AE35 BE 80 A0 LDX $A080,Y     get precedence byte

push sign, round FAC1 and put on stack

.,AE38 A8       TAY             copy sign
.,AE39 68       PLA             get return address low byte
.,AE3A 85 22    STA $22         save it
.,AE3C E6 22    INC $22         increment it as return-1 is pushed
                                note, no check is made on the high byte so if the calling
                                routine ever assembles to a page edge then this all goes
                                horribly wrong!
.,AE3E 68       PLA             get return address high byte
.,AE3F 85 23    STA $23         save it
.,AE41 98       TYA             restore sign
.,AE42 48       PHA             push sign

round FAC1 and put on stack

.,AE43 20 1B BC JSR $BC1B       round FAC1
.,AE46 A5 65    LDA $65         get FAC1 mantissa 4
.,AE48 48       PHA             save it
.,AE49 A5 64    LDA $64         get FAC1 mantissa 3
.,AE4B 48       PHA             save it
.,AE4C A5 63    LDA $63         get FAC1 mantissa 2
.,AE4E 48       PHA             save it
.,AE4F A5 62    LDA $62         get FAC1 mantissa 1
.,AE51 48       PHA             save it
.,AE52 A5 61    LDA $61         get FAC1 exponent
.,AE54 48       PHA             save it
.,AE55 6C 22 00 JMP ($0022)     return, sort of

do functions

.,AE58 A0 FF    LDY #$FF        flag function
.,AE5A 68       PLA             pull precedence byte
.,AE5B F0 23    BEQ $AE80       exit if done
.,AE5D C9 64    CMP #$64        compare previous precedence with $64
.,AE5F F0 03    BEQ $AE64       branch if was $64 (< function)
.,AE61 20 8D AD JSR $AD8D       check if source is numeric, else do type mismatch
.,AE64 84 4B    STY $4B         save precedence stacked flag
                                pop FAC2 and return
.,AE66 68       PLA             pop byte
.,AE67 4A       LSR             shift out comparison evaluation lowest bit
.,AE68 85 12    STA $12         save the comparison evaluation flag
.,AE6A 68       PLA             pop exponent
.,AE6B 85 69    STA $69         save FAC2 exponent
.,AE6D 68       PLA             pop mantissa 1
.,AE6E 85 6A    STA $6A         save FAC2 mantissa 1
.,AE70 68       PLA             pop mantissa 2
.,AE71 85 6B    STA $6B         save FAC2 mantissa 2
.,AE73 68       PLA             pop mantissa 3
.,AE74 85 6C    STA $6C         save FAC2 mantissa 3
.,AE76 68       PLA             pop mantissa 4
.,AE77 85 6D    STA $6D         save FAC2 mantissa 4
.,AE79 68       PLA             pop sign
.,AE7A 85 6E    STA $6E         save FAC2 sign (b7)
.,AE7C 45 66    EOR $66         EOR FAC1 sign (b7)
.,AE7E 85 6F    STA $6F         save sign compare (FAC1 EOR FAC2)
.,AE80 A5 61    LDA $61         get FAC1 exponent
.,AE82 60       RTS

get value from line

.,AE83 6C 0A 03 JMP ($030A)     get arithmetic element

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

.,AE86 A9 00    LDA #$00        clear byte
.,AE88 85 0D    STA $0D         clear data type flag, $FF = string, $00 = numeric
.,AE8A 20 73 00 JSR $0073       increment and scan memory
.,AE8D B0 03    BCS $AE92       branch if not numeric character
                                else numeric string found (e.g. 123)
.,AE8F 4C F3 BC JMP $BCF3       get FAC1 from string and return
                                get value from line .. continued
                                wasn't a number so ...
.,AE92 20 13 B1 JSR $B113       check byte, return Cb = 0 if<"A" or >"Z"
.,AE95 90 03    BCC $AE9A       branch if not variable name
.,AE97 4C 28 AF JMP $AF28       variable name set-up and return
.,AE9A C9 FF    CMP #$FF        compare with token for PI
.,AE9C D0 0F    BNE $AEAD       branch if not PI
.,AE9E A9 A8    LDA #$A8        get PI pointer low byte
.,AEA0 A0 AE    LDY #$AE        get PI pointer high byte
.,AEA2 20 A2 BB JSR $BBA2       unpack memory (AY) into FAC1
.,AEA5 4C 73 00 JMP $0073       increment and scan memory and return

PI as floating number

.:AEA8 82 49 0F DA A1           3.141592653

get value from line .. continued

                                wasn't variable name so ...
.,AEAD C9 2E    CMP #$2E        compare with "."
.,AEAF F0 DE    BEQ $AE8F       if so get FAC1 from string and return, e.g. was .123
                                wasn't .123 so ...
.,AEB1 C9 AB    CMP #$AB        compare with token for -
.,AEB3 F0 58    BEQ $AF0D       branch if - token, do set-up for functions
                                wasn't -123 so ...
.,AEB5 C9 AA    CMP #$AA        compare with token for +
.,AEB7 F0 D1    BEQ $AE8A       branch if + token, +1 = 1 so ignore leading +
                                it wasn't any sort of number so ...
.,AEB9 C9 22    CMP #$22        compare with "
.,AEBB D0 0F    BNE $AECC       branch if not open quote
                                was open quote so get the enclosed string

print "..." string to string utility area

.,AEBD A5 7A    LDA $7A         get BASIC execute pointer low byte
.,AEBF A4 7B    LDY $7B         get BASIC execute pointer high byte
.,AEC1 69 00    ADC #$00        add carry to low byte
.,AEC3 90 01    BCC $AEC6       branch if no overflow
.,AEC5 C8       INY             increment high byte
.,AEC6 20 87 B4 JSR $B487       print " terminated string to utility pointer
.,AEC9 4C E2 B7 JMP $B7E2       restore BASIC execute pointer from temp and return
                                get value from line .. continued
                                wasn't a string so ...
.,AECC C9 A8    CMP #$A8        compare with token for NOT
.,AECE D0 13    BNE $AEE3       branch if not token for NOT
                                was NOT token
.,AED0 A0 18    LDY #$18        offset to NOT function
.,AED2 D0 3B    BNE $AF0F       do set-up for function then execute, branch always
                                do = compare
.,AED4 20 BF B1 JSR $B1BF       evaluate integer expression, no sign check
.,AED7 A5 65    LDA $65         get FAC1 mantissa 4
.,AED9 49 FF    EOR #$FF        invert it
.,AEDB A8       TAY             copy it
.,AEDC A5 64    LDA $64         get FAC1 mantissa 3
.,AEDE 49 FF    EOR #$FF        invert it
.,AEE0 4C 91 B3 JMP $B391       convert fixed integer AY to float FAC1 and return
                                get value from line .. continued
                                wasn't a string or NOT so ...
.,AEE3 C9 A5    CMP #$A5        compare with token for FN
.,AEE5 D0 03    BNE $AEEA       branch if not token for FN
.,AEE7 4C F4 B3 JMP $B3F4       else go evaluate FNx
                                get value from line .. continued
                                wasn't a string, NOT or FN so ...
.,AEEA C9 B4    CMP #$B4        compare with token for SGN
.,AEEC 90 03    BCC $AEF1       if less than SGN token evaluate expression in parentheses
                                else was a function token
.,AEEE 4C A7 AF JMP $AFA7       go set up function references, branch always
                                get value from line .. continued
                                if here it can only be something in brackets so ....
                                evaluate expression within parentheses
.,AEF1 20 FA AE JSR $AEFA       scan for "(", else do syntax error then warm start
.,AEF4 20 9E AD JSR $AD9E       evaluate expression
                                all the 'scan for' routines return the character after the sought character
                                scan for ")", else do syntax error then warm start
.,AEF7 A9 29    LDA #$29        load A with ")"
.:AEF9 2C       .BYTE $2C       makes next line BIT $28A9
                                scan for "(", else do syntax error then warm start
.,AEFA A9 28    LDA #$28        load A with "("
.:AEFC 2C       .BYTE $2C       makes next line BIT $2CA9
                                scan for ",", else do syntax error then warm start
.,AEFD A9 2C    LDA #$2C        load A with ","
                                scan for CHR$(A), else do syntax error then warm start
.,AEFF A0 00    LDY #$00        clear index
.,AF01 D1 7A    CMP ($7A),Y     compare with BASIC byte
.,AF03 D0 03    BNE $AF08       if not expected byte do syntax error then warm start
.,AF05 4C 73 00 JMP $0073       else increment and scan memory and return
                                syntax error then warm start
.,AF08 A2 0B    LDX #$0B        error code $0B, syntax error
.,AF0A 4C 37 A4 JMP $A437       do error #X then warm start
.,AF0D A0 15    LDY #$15        set offset from base to > operator
.,AF0F 68       PLA             dump return address low byte
.,AF10 68       PLA             dump return address high byte
.,AF11 4C FA AD JMP $ADFA       execute function then continue evaluation

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

.,AF14 38       SEC             set carry for subtract
.,AF15 A5 64    LDA $64         get variable address low byte
.,AF17 E9 00    SBC #$00        subtract $A000 low byte
.,AF19 A5 65    LDA $65         get variable address high byte
.,AF1B E9 A0    SBC #$A0        subtract $A000 high byte
.,AF1D 90 08    BCC $AF27       exit if address < $A000
.,AF1F A9 A2    LDA #$A2        get end of BASIC marker low byte
.,AF21 E5 64    SBC $64         subtract variable address low byte
.,AF23 A9 E3    LDA #$E3        get end of BASIC marker high byte
.,AF25 E5 65    SBC $65         subtract variable address high byte
.,AF27 60       RTS

variable name set-up

.,AF28 20 8B B0 JSR $B08B       get variable address
.,AF2B 85 64    STA $64         save variable pointer low byte
.,AF2D 84 65    STY $65         save variable pointer high byte
.,AF2F A6 45    LDX $45         get current variable name first character
.,AF31 A4 46    LDY $46         get current variable name second character
.,AF33 A5 0D    LDA $0D         get data type flag, $FF = string, $00 = numeric
.,AF35 F0 26    BEQ $AF5D       branch if numeric
                                variable is string
.,AF37 A9 00    LDA #$00        else clear A
.,AF39 85 70    STA $70         clear FAC1 rounding byte
.,AF3B 20 14 AF JSR $AF14       check address range
.,AF3E 90 1C    BCC $AF5C       exit if not in BASIC ROM
.,AF40 E0 54    CPX #$54        compare variable name first character with "T"
.,AF42 D0 18    BNE $AF5C       exit if not "T"
.,AF44 C0 C9    CPY #$C9        compare variable name second character with "I$"
.,AF46 D0 14    BNE $AF5C       exit if not "I$"
                                variable name was "TI$"
.,AF48 20 84 AF JSR $AF84       read real time clock into FAC1 mantissa, 0HML
.,AF4B 84 5E    STY $5E         clear exponent count adjust
.,AF4D 88       DEY             Y = $FF
.,AF4E 84 71    STY $71         set output string index, -1 to allow for pre increment
.,AF50 A0 06    LDY #$06        HH:MM:SS is six digits
.,AF52 84 5D    STY $5D         set number of characters before the decimal point
.,AF54 A0 24    LDY #$24
                                index to jiffy conversion table
.,AF56 20 68 BE JSR $BE68       convert jiffy count to string
.,AF59 4C 6F B4 JMP $B46F       exit via STR$() code tail
.,AF5C 60       RTS
                                variable name set-up, variable is numeric
.,AF5D 24 0E    BIT $0E         test data type flag, $80 = integer, $00 = float
.,AF5F 10 0D    BPL $AF6E       branch if float
.,AF61 A0 00    LDY #$00        clear index
.,AF63 B1 64    LDA ($64),Y     get integer variable low byte
.,AF65 AA       TAX             copy to X
.,AF66 C8       INY             increment index
.,AF67 B1 64    LDA ($64),Y     get integer variable high byte
.,AF69 A8       TAY             copy to Y
.,AF6A 8A       TXA             copy loa byte to A
.,AF6B 4C 91 B3 JMP $B391       convert fixed integer AY to float FAC1 and return
                                variable name set-up, variable is float
.,AF6E 20 14 AF JSR $AF14       check address range
.,AF71 90 2D    BCC $AFA0       if not in BASIC ROM get pointer and unpack into FAC1
.,AF73 E0 54    CPX #$54        compare variable name first character with "T"
.,AF75 D0 1B    BNE $AF92       branch if not "T"
.,AF77 C0 49    CPY #$49        compare variable name second character with "I"
.,AF79 D0 25    BNE $AFA0       branch if not "I"
                                variable name was "TI"
.,AF7B 20 84 AF JSR $AF84       read real time clock into FAC1 mantissa, 0HML
.,AF7E 98       TYA             clear A
.,AF7F A2 A0    LDX #$A0        set exponent to 32 bit value
.,AF81 4C 4F BC JMP $BC4F       set exponent = X and normalise FAC1

read real time clock into FAC1 mantissa, 0HML

.,AF84 20 DE FF JSR $FFDE       read real time clock
.,AF87 86 64    STX $64         save jiffy clock mid byte as  FAC1 mantissa 3
.,AF89 84 63    STY $63         save jiffy clock high byte as  FAC1 mantissa 2
.,AF8B 85 65    STA $65         save jiffy clock low byte as  FAC1 mantissa 4
.,AF8D A0 00    LDY #$00        clear Y
.,AF8F 84 62    STY $62         clear FAC1 mantissa 1
.,AF91 60       RTS
                                variable name set-up, variable is float and not "Tx"
.,AF92 E0 53    CPX #$53        compare variable name first character with "S"
.,AF94 D0 0A    BNE $AFA0       if not "S" go do normal floating variable
.,AF96 C0 54    CPY #$54        compare variable name second character with "
.,AF98 D0 06    BNE $AFA0       if not "T" go do normal floating variable
                                variable name was "ST"
.,AF9A 20 B7 FF JSR $FFB7       read I/O status word
.,AF9D 4C 3C BC JMP $BC3C       save A as integer byte and return
                                variable is float
.,AFA0 A5 64    LDA $64         get variable pointer low byte
.,AFA2 A4 65    LDY $65         get variable pointer high byte
.,AFA4 4C A2 BB JMP $BBA2       unpack memory (AY) into FAC1

get value from line continued

                                only functions left so ..
                                set up function references
.,AFA7 0A       ASL             *2 (2 bytes per function address)
.,AFA8 48       PHA             save function offset
.,AFA9 AA       TAX             copy function offset
.,AFAA 20 73 00 JSR $0073       increment and scan memory
.,AFAD E0 8F    CPX #$8F        compare function offset to CHR$ token offset+1
.,AFAF 90 20    BCC $AFD1       branch if < LEFT$ (can not be =)
                                get value from line .. continued
                                was LEFT$, RIGHT$ or MID$ so..
.,AFB1 20 FA AE JSR $AEFA       scan for "(", else do syntax error then warm start
.,AFB4 20 9E AD JSR $AD9E       evaluate, should be string, expression
.,AFB7 20 FD AE JSR $AEFD       scan for ",", else do syntax error then warm start
.,AFBA 20 8F AD JSR $AD8F       check if source is string, else do type mismatch
.,AFBD 68       PLA             restore function offset
.,AFBE AA       TAX             copy it
.,AFBF A5 65    LDA $65         get descriptor pointer high byte
.,AFC1 48       PHA             push string pointer high byte
.,AFC2 A5 64    LDA $64         get descriptor pointer low byte
.,AFC4 48       PHA             push string pointer low byte
.,AFC5 8A       TXA             restore function offset
.,AFC6 48       PHA             save function offset
.,AFC7 20 9E B7 JSR $B79E       get byte parameter
.,AFCA 68       PLA             restore function offset
.,AFCB A8       TAY             copy function offset
.,AFCC 8A       TXA             copy byte parameter to A
.,AFCD 48       PHA             push byte parameter
.,AFCE 4C D6 AF JMP $AFD6       go call function
                                get value from line .. continued
                                was SGN() to CHR$() so..
.,AFD1 20 F1 AE JSR $AEF1       evaluate expression within parentheses
.,AFD4 68       PLA             restore function offset
.,AFD5 A8       TAY             copy to index
.,AFD6 B9 EA 9F LDA $9FEA,Y     get function jump vector low byte
.,AFD9 85 55    STA $55         save functions jump vector low byte
.,AFDB B9 EB 9F LDA $9FEB,Y     get function jump vector high byte
.,AFDE 85 56    STA $56         save functions jump vector high byte
.,AFE0 20 54 00 JSR $0054       do function call
.,AFE3 4C 8D AD JMP $AD8D       check if source is numeric and RTS, else do type mismatch
                                string functions avoid this by dumping the return address

perform OR

                                this works because NOT(NOT(x) AND NOT(y)) = x OR y
.,AFE6 A0 FF    LDY #$FF        set Y for OR
.:AFE8 2C       .BYTE $2C       makes next line BIT $00A0

perform AND

.,AFE9 A0 00    LDY #$00        clear Y for AND
.,AFEB 84 0B    STY $0B         set AND/OR invert value
.,AFED 20 BF B1 JSR $B1BF       evaluate integer expression, no sign check
.,AFF0 A5 64    LDA $64         get FAC1 mantissa 3
.,AFF2 45 0B    EOR $0B         EOR low byte
.,AFF4 85 07    STA $07         save it
.,AFF6 A5 65    LDA $65         get FAC1 mantissa 4
.,AFF8 45 0B    EOR $0B         EOR high byte
.,AFFA 85 08    STA $08         save it
.,AFFC 20 FC BB JSR $BBFC       copy FAC2 to FAC1, get 2nd value in expression
.,AFFF 20 BF B1 JSR $B1BF       evaluate integer expression, no sign check
.,B002 A5 65    LDA $65         get FAC1 mantissa 4
.,B004 45 0B    EOR $0B         EOR high byte
.,B006 25 08    AND $08         AND with expression 1 high byte
.,B008 45 0B    EOR $0B         EOR result high byte
.,B00A A8       TAY             save in Y
.,B00B A5 64    LDA $64         get FAC1 mantissa 3
.,B00D 45 0B    EOR $0B         EOR low byte
.,B00F 25 07    AND $07         AND with expression 1 low byte
.,B011 45 0B    EOR $0B         EOR result low byte
.,B013 4C 91 B3 JMP $B391       convert fixed integer AY to float FAC1 and return

perform comparisons

                                do < compare
.,B016 20 90 AD JSR $AD90       type match check, set C for string
.,B019 B0 13    BCS $B02E       branch if string
                                do numeric < compare
.,B01B A5 6E    LDA $6E         get FAC2 sign (b7)
.,B01D 09 7F    ORA #$7F        set all non sign bits
.,B01F 25 6A    AND $6A         and FAC2 mantissa 1 (AND in sign bit)
.,B021 85 6A    STA $6A         save FAC2 mantissa 1
.,B023 A9 69    LDA #$69        set pointer low byte to FAC2
.,B025 A0 00    LDY #$00        set pointer high byte to FAC2
.,B027 20 5B BC JSR $BC5B       compare FAC1 with (AY)
.,B02A AA       TAXcopy the result
.,B02B 4C 61 B0 JMP $B061       go evaluate result
                                do string < compare
.,B02E A9 00    LDA #$00        clear byte
.,B030 85 0D    STA $0D         clear data type flag, $FF = string, $00 = numeric
.,B032 C6 4D    DEC $4D         clear < bit in comparrison evaluation flag
.,B034 20 A6 B6 JSR $B6A6       pop string off descriptor stack, or from top of string
                                space returns with A = length, X = pointer low byte,
                                Y = pointer high byte
.,B037 85 61    STA $61         save length
.,B039 86 62    STX $62         save string pointer low byte
.,B03B 84 63    STY $63         save string pointer high byte
.,B03D A5 6C    LDA $6C         get descriptor pointer low byte
.,B03F A4 6D    LDY $6D         get descriptor pointer high byte
.,B041 20 AA B6 JSR $B6AA       pop (YA) descriptor off stack or from top of string space
                                returns with A = length, X = pointer low byte,
                                Y = pointer high byte
.,B044 86 6C    STX $6C         save string pointer low byte
.,B046 84 6D    STY $6D         save string pointer high byte
.,B048 AA       TAX             copy length
.,B049 38       SEC             set carry for subtract
.,B04A E5 61    SBC $61         subtract string 1 length
.,B04C F0 08    BEQ $B056       branch if str 1 length = string 2 length
.,B04E A9 01    LDA #$01        set str 1 length > string 2 length
.,B050 90 04    BCC $B056       branch if so
.,B052 A6 61    LDX $61         get string 1 length
.,B054 A9 FF    LDA #$FF        set str 1 length < string 2 length
.,B056 85 66    STA $66         save length compare
.,B058 A0 FF    LDY #$FF        set index
.,B05A E8       INX             adjust for loop
.,B05B C8       INY             increment index
.,B05C CA       DEX             decrement count
.,B05D D0 07    BNE $B066       branch if still bytes to do
.,B05F A6 66    LDX $66         get length compare back
.,B061 30 0F    BMI $B072       branch if str 1 < str 2
.,B063 18       CLC             flag str 1 <= str 2
.,B064 90 0C    BCC $B072       go evaluate result
.,B066 B1 6C    LDA ($6C),Y     get string 2 byte
.,B068 D1 62    CMP ($62),Y     compare with string 1 byte
.,B06A F0 EF    BEQ $B05B       loop if bytes =
.,B06C A2 FF    LDX #$FF        set str 1 < string 2
.,B06E B0 02    BCS $B072       branch if so
.,B070 A2 01    LDX #$01        set str 1 > string 2
.,B072 E8       INX             x = 0, 1 or 2
.,B073 8A       TXA             copy to A
.,B074 2A       ROL             * 2 (1, 2 or 4)
.,B075 25 12    AND $12         AND with the comparison evaluation flag
.,B077 F0 02    BEQ $B07B       branch if 0 (compare is false)
.,B079 A9 FF    LDA #$FFelse set result true
.,B07B 4C 3C BC JMP $BC3C       save A as integer byte and return
.,B07E 20 FD AE JSR $AEFD       scan for ",", else do syntax error then warm start

perform DIM

.,B081 AA       TAX             copy "DIM" flag to X
.,B082 20 90 B0 JSR $B090       search for variable
.,B085 20 79 00 JSR $0079       scan memory
.,B088 D0 F4    BNE $B07E       scan for "," and loop if not null
.,B08A 60       RTS

search for variable

.,B08B A2 00    LDX #$00        set DIM flag = $00
.,B08D 20 79 00 JSR $0079       scan memory, 1st character
.,B090 86 0C    STX $0C         save DIM flag
.,B092 85 45    STA $45         save 1st character
.,B094 20 79 00 JSR $0079       scan memory
.,B097 20 13 B1 JSR $B113       check byte, return Cb = 0 if<"A" or >"Z"
.,B09A B0 03    BCS $B09F       branch if ok
.,B09C 4C 08 AF JMP $AF08       else syntax error then warm start
                                was variable name so ...
.,B09F A2 00    LDX #$00        clear 2nd character temp
.,B0A1 86 0D    STX $0D         clear data type flag, $FF = string, $00 = numeric
.,B0A3 86 0E    STX $0E         clear data type flag, $80 = integer, $00 = float
.,B0A5 20 73 00 JSR $0073       increment and scan memory, 2nd character
.,B0A8 90 05    BCC $B0AF       if character = "0"-"9" (ok) go save 2nd character
                                2nd character wasn't "0" to "9" so ...
.,B0AA 20 13 B1 JSR $B113       check byte, return Cb = 0 if<"A" or >"Z"
.,B0AD 90 0B    BCC $B0BA       branch if <"A" or >"Z" (go check if string)
.,B0AF AA       TAX             copy 2nd character
                                ignore further (valid) characters in the variable name
.,B0B0 20 73 00 JSR $0073       increment and scan memory, 3rd character
.,B0B3 90 FB    BCC $B0B0       loop if character = "0"-"9" (ignore)
.,B0B5 20 13 B1 JSR $B113       check byte, return Cb = 0 if<"A" or >"Z"
.,B0B8 B0 F6    BCS $B0B0       loop if character = "A"-"Z" (ignore)
                                check if string variable
.,B0BA C9 24    CMP #$24        compare with "$"
.,B0BC D0 06    BNE $B0C4       branch if not string
                                type is string
.,B0BE A9 FF    LDA #$FF        set data type = string
.,B0C0 85 0D    STA $0D         set data type flag, $FF = string, $00 = numeric
.,B0C2 D0 10    BNE $B0D4       branch always
.,B0C4 C9 25    CMP #$25        compare with "%"
.,B0C6 D0 13    BNE $B0DB       branch if not integer
.,B0C8 A5 10    LDA $10         get subscript/FNX flag
.,B0CA D0 D0    BNE $B09C       if ?? do syntax error then warm start
.,B0CC A9 80    LDA #$80        set integer type
.,B0CE 85 0E    STA $0E         set data type = integer
.,B0D0 05 45    ORA $45         OR current variable name first byte
.,B0D2 85 45    STA $45         save current variable name first byte
.,B0D4 8A       TXA             get 2nd character back
.,B0D5 09 80    ORA #$80        set top bit, indicate string or integer variable
.,B0D7 AA       TAX             copy back to 2nd character temp
.,B0D8 20 73 00 JSR $0073       increment and scan memory
.,B0DB 86 46    STX $46         save 2nd character
.,B0DD 38       SEC             set carry for subtract
.,B0DE 05 10    ORA $10         or with subscript/FNX flag - or FN name
.,B0E0 E9 28    SBC #$28        subtract "("
.,B0E2 D0 03    BNE $B0E7       branch if not "("
.,B0E4 4C D1 B1 JMP $B1D1       go find, or make, array
                                either find or create variable
                                variable name wasn't xx(.... so look for plain variable
.,B0E7 A0 00    LDY #$00        clear A
.,B0E9 84 10    STY $10         clear subscript/FNX flag
.,B0EB A5 2D    LDA $2D         get start of variables low byte
.,B0ED A6 2E    LDX $2E         get start of variables high byte
.,B0EF 86 60    STX $60         save search address high byte
.,B0F1 85 5F    STA $5F         save search address low byte
.,B0F3 E4 30    CPX $30         compare with end of variables high byte
.,B0F5 D0 04    BNE $B0FB       skip next compare if <>
                                high addresses were = so compare low addresses
.,B0F7 C5 2F    CMP $2F         compare low address with end of variables low byte
.,B0F9 F0 22    BEQ $B11D       if not found go make new variable
.,B0FB A5 45    LDA $45         get 1st character of variable to find
.,B0FD D1 5F    CMP ($5F),Y     compare with variable name 1st character
.,B0FF D0 08    BNE $B109       branch if no match
                                1st characters match so compare 2nd character
.,B101 A5 46    LDA $46         get 2nd character of variable to find
.,B103 C8       INY             index to point to variable name 2nd character
.,B104 D1 5F    CMP ($5F),Y     compare with variable name 2nd character
.,B106 F0 7D    BEQ $B185       branch if match (found variable)
.,B108 88       DEY             else decrement index (now = $00)
.,B109 18       CLC             clear carry for add
.,B10A A5 5F    LDA $5F         get search address low byte
.,B10C 69 07    ADC #$07        +7, offset to next variable name
.,B10E 90 E1    BCC $B0F1       loop if no overflow to high byte
.,B110 E8       INX             else increment high byte
.,B111 D0 DC    BNE $B0EF       loop always, RAM doesn't extend to $FFFF
                                check byte, return Cb = 0 if<"A" or >"Z"
.,B113 C9 41    CMP #$41        compare with "A"
.,B115 90 05    BCC $B11C       exit if less
                                carry is set
.,B117 E9 5B    SBC #$5B        subtract "Z"+1
.,B119 38       SEC             set carry
.,B11A E9 A5    SBC #$A5        subtract $A5 (restore byte)
                                carry clear if byte > $5A
.,B11C 60       RTS
                                reached end of variable memory without match
                                ... so create new variable
.,B11D 68       PLApop return address low byte
.,B11E 48       PHA             push return address low byte
.,B11F C9 2A    CMP #$2A        compare with expected calling routine return low byte
.,B121 D0 05    BNE $B128       if not get variable go create new variable
                                this will only drop through if the call was from $AF28 and is only called
                                from there if it is searching for a variable from the right hand side of a LET a=b
                                statement, it prevents the creation of variables not assigned a value.
                                value returned by this is either numeric zero, exponent byte is $00, or null string,
                                descriptor length byte is $00. in fact a pointer to any $00 byte would have done.
                                else return dummy null value
.,B123 A9 13    LDA #$13        set result pointer low byte
.,B125 A0 BF    LDY #$BF        set result pointer high byte
.,B127 60       RTS
                                create new numeric variable
.,B128 A5 45    LDA $45         get variable name first character
.,B12A A4 46    LDY $46         get variable name second character
.,B12C C9 54    CMP #$54        compare first character with "T"
.,B12E D0 0B    BNE $B13B       branch if not "T"
.,B130 C0 C9    CPY #$C9        compare second character with "I$"
.,B132 F0 EF    BEQ $B123       if "I$" return null value
.,B134 C0 49    CPY #$49        compare second character with "I"
.,B136 D0 03    BNE $B13B       branch if not "I"
                                if name is "TI" do syntax error
.,B138 4C 08 AF JMP $AF08       do syntax error then warm start
.,B13B C9 53    CMP #$53        compare first character with "S"
.,B13D D0 04    BNE $B143       branch if not "S"
.,B13F C0 54    CPY #$54        compare second character with "T"
.,B141 F0 F5    BEQ $B138       if name is "ST" do syntax error
.,B143 A5 2F    LDA $2F         get end of variables low byte
.,B145 A4 30    LDY $30         get end of variables high byte
.,B147 85 5F    STA $5F         save old block start low byte
.,B149 84 60    STY $60         save old block start high byte
.,B14B A5 31    LDA $31         get end of arrays low byte
.,B14D A4 32    LDY $32         get end of arrays high byte
.,B14F 85 5A    STA $5A         save old block end low byte
.,B151 84 5B    STY $5B         save old block end high byte
.,B153 18       CLC             clear carry for add
.,B154 69 07    ADC #$07        +7, space for one variable
.,B156 90 01    BCC $B159       branch if no overflow to high byte
.,B158 C8       INY             else increment high byte
.,B159 85 58    STA $58         set new block end low byte
.,B15B 84 59    STY $59         set new block end high byte
.,B15D 20 B8 A3 JSR $A3B8       open up space in memory
.,B160 A5 58    LDA $58         get new start low byte
.,B162 A4 59    LDY $59         get new start high byte (-$100)
.,B164 C8       INY             correct high byte
.,B165 85 2F    STA $2F         set end of variables low byte
.,B167 84 30    STY $30         set end of variables high byte
.,B169 A0 00    LDY #$00        clear index
.,B16B A5 45    LDA $45         get variable name 1st character
.,B16D 91 5F    STA ($5F),Y     save variable name 1st character
.,B16F C8       INY             increment index
.,B170 A5 46    LDA $46         get variable name 2nd character
.,B172 91 5F    STA ($5F),Y     save variable name 2nd character
.,B174 A9 00    LDA #$00        clear A
.,B176 C8       INY             increment index
.,B177 91 5F    STA ($5F),Y     initialise variable byte
.,B179 C8       INY             increment index
.,B17A 91 5F    STA ($5F),Y     initialise variable byte
.,B17C C8       INY             increment index
.,B17D 91 5F    STA ($5F),Y     initialise variable byte
.,B17F C8       INY             increment index
.,B180 91 5F    STA ($5F),Y     initialise variable byte
.,B182 C8       INY             increment index
.,B183 91 5F    STA ($5F),Y     initialise variable byte
                                found a match for variable
.,B185 A5 5F    LDA $5F         get variable address low byte
.,B187 18       CLC             clear carry for add
.,B188 69 02    ADC #$02        +2, offset past variable name bytes
.,B18A A4 60    LDY $60         get variable address high byte
.,B18C 90 01    BCC $B18F       branch if no overflow from add
.,B18E C8       INYelse increment high byte
.,B18F 85 47    STA $47         save current variable pointer low byte
.,B191 84 48    STY $48         save current variable pointer high byte
.,B193 60       RTS
                                set-up array pointer to first element in array
.,B194 A5 0B    LDA $0B         get # of dimensions (1, 2 or 3)
.,B196 0A       ASL             *2 (also clears the carry !)
.,B197 69 05    ADC #$05        +5 (result is 7, 9 or 11 here)
.,B199 65 5F    ADC $5F         add array start pointer low byte
.,B19B A4 60    LDY $60         get array pointer high byte
.,B19D 90 01    BCC $B1A0       branch if no overflow
.,B19F C8       INY             else increment high byte
.,B1A0 85 58    STA $58         save array data pointer low byte
.,B1A2 84 59    STY $59         save array data pointer high byte
.,B1A4 60       RTS

-32768 as floating value

.:B1A5 90 80 00 00 00           -32768

convert float to fixed

.,B1AA 20 BF B1 JSR $B1BF       evaluate integer expression, no sign check
.,B1AD A5 64    LDA $64         get result low byte
.,B1AF A4 65    LDY $65         get result high byte
.,B1B1 60       RTS

evaluate integer expression

.,B1B2 20 73 00 JSR $0073       increment and scan memory
.,B1B5 20 9E AD JSR $AD9E       evaluate expression
                                evaluate integer expression, sign check
.,B1B8 20 8D AD JSR $AD8D       check if source is numeric, else do type mismatch
.,B1BB A5 66    LDA $66         get FAC1 sign (b7)
.,B1BD 30 0D    BMI $B1CC       do illegal quantity error if -ve
                                evaluate integer expression, no sign check
.,B1BF A5 61    LDA $61         get FAC1 exponent
.,B1C1 C9 90    CMP #$90        compare with exponent = 2^16 (n>2^15)
.,B1C3 90 09    BCC $B1CE       if n<2^16 go convert FAC1 floating to fixed and return
.,B1C5 A9 A5    LDA #$A5        set pointer low byte to -32768
.,B1C7 A0 B1    LDY #$B1        set pointer high byte to -32768
.,B1C9 20 5B BC JSR $BC5B       compare FAC1 with (AY)
.,B1CC D0 7A    BNE $B248       if <> do illegal quantity error then warm start
.,B1CE 4C 9B BC JMP $BC9B       convert FAC1 floating to fixed and return

find or make array

                                an array is stored as follows

                                array name             two bytes with the following patterns for different types
                                                       1st char    2nd char
                                                          b7          b7       type             element size
                                                       --------    --------    -----            ------------
                                                          0           0        floating point   5
                                                          0           1        string           3
                                                          1           1        integer          2
                                offset to next array   word
                                dimension count        byte
                                1st dimension size     word, this is the number of elements including 0
                                2nd dimension size     word, only here if the array has a second dimension
                                2nd dimension size     word, only here if the array has a third dimension
                                                       note: the dimension size word is in high byte low byte
                                                       format, not like most 6502 words
                                then for each element the required number of bytes given as the element size above
.,B1D1 A5 0C    LDA $0C         get DIM flag
.,B1D3 05 0E    ORA $0E         OR with data type flag
.,B1D5 48       PHA             push it
.,B1D6 A5 0D    LDA $0D         get data type flag, $FF = string, $00 = numeric
.,B1D8 48       PHA             push it
.,B1D9 A0 00    LDY #$00        clear dimensions count
                                now get the array dimension(s) and stack it (them) before the data type and DIM flag
.,B1DB 98       TYA             copy dimensions count
.,B1DC 48       PHA             save it
.,B1DD A5 46    LDA $46         get array name 2nd byte
.,B1DF 48       PHA             save it
.,B1E0 A5 45    LDA $45         get array name 1st byte
.,B1E2 48       PHA             save it
.,B1E3 20 B2 B1 JSR $B1B2       evaluate integer expression
.,B1E6 68       PLA             pull array name 1st byte
.,B1E7 85 45    STA $45         restore array name 1st byte
.,B1E9 68       PLA             pull array name 2nd byte
.,B1EA 85 46    STA $46         restore array name 2nd byte
.,B1EC 68       PLA             pull dimensions count
.,B1ED A8       TAY             restore it
.,B1EE BA       TSX             copy stack pointer
.,B1EF BD 02 01 LDA $0102,X     get DIM flag
.,B1F2 48       PHA             push it
.,B1F3 BD 01 01 LDA $0101,X     get data type flag
.,B1F6 48       PHA             push it
.,B1F7 A5 64    LDA $64         get this dimension size high byte
.,B1F9 9D 02 01 STA $0102,X     stack before flag bytes
.,B1FC A5 65    LDA $65         get this dimension size low byte
.,B1FE 9D 01 01 STA $0101,X     stack before flag bytes
.,B201 C8       INY             increment dimensions count
.,B202 20 79 00 JSR $0079       scan memory
.,B205 C9 2C    CMP #$2C        compare with ","
.,B207 F0 D2    BEQ $B1DB       if found go do next dimension
.,B209 84 0B    STY $0B         store dimensions count
.,B20B 20 F7 AE JSR $AEF7       scan for ")", else do syntax error then warm start
.,B20E 68       PLA             pull data type flag
.,B20F 85 0D    STA $0D         restore data type flag, $FF = string, $00 = numeric
.,B211 68       PLA             pull data type flag
.,B212 85 0E    STA $0E         restore data type flag, $80 = integer, $00 = float
.,B214 29 7F    AND #$7F        mask dim flag
.,B216 85 0C    STA $0C         restore DIM flag
.,B218 A6 2F    LDX $2F         set end of variables low byte
                                (array memory start low byte)
.,B21A A5 30    LDA $30         set end of variables high byte
                                (array memory start high byte)
                                now check to see if we are at the end of array memory, we would be if there were
                                no arrays.
.,B21C 86 5F    STX $5F         save as array start pointer low byte
.,B21E 85 60    STA $60         save as array start pointer high byte
.,B220 C5 32    CMP $32         compare with end of arrays high byte
.,B222 D0 04    BNE $B228       branch if not reached array memory end
.,B224 E4 31    CPX $31         else compare with end of arrays low byte
.,B226 F0 39    BEQ $B261       go build array if not found
                                search for array
.,B228 A0 00    LDY #$00        clear index
.,B22A B1 5F    LDA ($5F),Y     get array name first byte
.,B22C C8       INY             increment index to second name byte
.,B22D C5 45    CMP $45         compare with this array name first byte
.,B22F D0 06    BNE $B237       branch if no match
.,B231 A5 46    LDA $46         else get this array name second byte
.,B233 D1 5F    CMP ($5F),Y     compare with array name second byte
.,B235 F0 16    BEQ $B24D       array found so branch
                                no match
.,B237 C8       INY             increment index
.,B238 B1 5F    LDA ($5F),Y     get array size low byte
.,B23A 18       CLC             clear carry for add
.,B23B 65 5F    ADC $5F         add array start pointer low byte
.,B23D AA       TAX             copy low byte to X
.,B23E C8       INY             increment index
.,B23F B1 5F    LDA ($5F),Y     get array size high byte
.,B241 65 60    ADC $60         add array memory pointer high byte
.,B243 90 D7    BCC $B21C       if no overflow go check next array

do bad subscript error

.,B245 A2 12    LDX #$12        error $12, bad subscript error
.:B247 2C       .BYTE $2C       makes next line BIT $0EA2

do illegal quantity error

.,B248 A2 0E    LDX #$0E        error $0E, illegal quantity error
.,B24A 4C 37 A4 JMP $A437       do error #X then warm start

found the array

.,B24D A2 13    LDX #$13        set error $13, double dimension error
.,B24F A5 0C    LDA $0C         get DIM flag
.,B251 D0 F7    BNE $B24A       if we are trying to dimension it do error #X then warm
                                start
                                found the array and we're not dimensioning it so we must find an element in it
.,B253 20 94 B1 JSR $B194       set-up array pointer to first element in array
.,B256 A5 0B    LDA $0B         get dimensions count
.,B258 A0 04    LDY #$04        set index to array's # of dimensions
.,B25A D1 5F    CMP ($5F),Y     compare with no of dimensions
.,B25C D0 E7    BNE $B245       if wrong do bad subscript error
.,B25E 4C EA B2 JMP $B2EA       found array so go get element
                                array not found, so build it
.,B261 20 94 B1 JSR $B194       set-up array pointer to first element in array
.,B264 20 08 A4 JSR $A408       check available memory, do out of memory error if no room
.,B267 A0 00    LDY #$00        clear Y
.,B269 84 72    STY $72         clear array data size high byte
.,B26B A2 05    LDX #$05        set default element size
.,B26D A5 45    LDA $45         get variable name 1st byte
.,B26F 91 5F    STA ($5F),Y     save array name 1st byte
.,B271 10 01    BPL $B274       branch if not string or floating point array
.,B273 CA       DEX             decrement element size, $04
.,B274 C8       INY             increment index
.,B275 A5 46    LDA $46         get variable name 2nd byte
.,B277 91 5F    STA ($5F),Y     save array name 2nd byte
.,B279 10 02    BPL $B27D       branch if not integer or string
.,B27B CA       DEX             decrement element size, $03
.,B27C CA       DEX             decrement element size, $02
.,B27D 86 71    STX $71         save element size
.,B27F A5 0B    LDA $0B         get dimensions count
.,B281 C8       INY             increment index ..
.,B282 C8       INY             .. to array  ..
.,B283 C8       INY             .. dimension count
.,B284 91 5F    STA ($5F),Y     save array dimension count
.,B286 A2 0B    LDX #$0B        set default dimension size low byte
.,B288 A9 00    LDA #$00        set default dimension size high byte
.,B28A 24 0C    BIT $0C         test DIM flag
.,B28C 50 08    BVC $B296       branch if default to be used
.,B28E 68       PLA             pull dimension size low byte
.,B28F 18       CLC             clear carry for add
.,B290 69 01    ADC #$01        add 1, allow for zeroeth element
.,B292 AA       TAX             copy low byte to X
.,B293 68       PLA             pull dimension size high byte
.,B294 69 00    ADC #$00        add carry to high byte
.,B296 C8       INY             incement index to dimension size high byte
.,B297 91 5F    STA ($5F),Y     save dimension size high byte
.,B299 C8       INY             incement index to dimension size low byte
.,B29A 8A       TXA             copy dimension size low byte
.,B29B 91 5F    STA ($5F),Y     save dimension size low byte
.,B29D 20 4C B3 JSR $B34C       compute array size
.,B2A0 86 71    STX $71         save result low byte
.,B2A2 85 72    STA $72         save result high byte
.,B2A4 A4 22    LDY $22         restore index
.,B2A6 C6 0B    DEC $0B         decrement dimensions count
.,B2A8 D0 DC    BNE $B286       loop if not all done
.,B2AA 65 59    ADC $59         add array data pointer high byte
.,B2AC B0 5D    BCS $B30B       if overflow do out of memory error then warm start
.,B2AE 85 59    STA $59         save array data pointer high byte
.,B2B0 A8       TAY             copy array data pointer high byte
.,B2B1 8A       TXA             copy array size low byte
.,B2B2 65 58    ADC $58         add array data pointer low byte
.,B2B4 90 03    BCC $B2B9       branch if no rollover
.,B2B6 C8       INY             else increment next array pointer high byte
.,B2B7 F0 52    BEQ $B30B       if rolled over do out of memory error then warm start
.,B2B9 20 08 A4 JSR $A408       check available memory, do out of memory error if no room
.,B2BC 85 31    STA $31         set end of arrays low byte
.,B2BE 84 32    STY $32         set end of arrays high byte
                                now the aray is created we need to zero all the elements in it
.,B2C0 A9 00    LDA #$00        clear A for array clear
.,B2C2 E6 72    INC $72increment array size high byte, now block count
.,B2C4 A4 71    LDY $71         get array size low byte, now index to block
.,B2C6 F0 05    BEQ $B2CD       branch if $00
.,B2C8 88       DEY             decrement index, do 0 to n-1
.,B2C9 91 58    STA ($58),Y     clear array element byte
.,B2CB D0 FB    BNE $B2C8       loop until this block done
.,B2CD C6 59    DEC $59decrement array pointer high byte
.,B2CF C6 72    DEC $72decrement block count high byte
.,B2D1 D0 F5    BNE $B2C8loop until all blocks done
.,B2D3 E6 59    INC $59correct for last loop
.,B2D5 38       SEC             set carry for subtract
.,B2D6 A5 31    LDA $31         get end of arrays low byte
.,B2D8 E5 5F    SBC $5F         subtract array start low byte
.,B2DA A0 02    LDY #$02        index to array size low byte
.,B2DC 91 5F    STA ($5F),Y     save array size low byte
.,B2DE A5 32    LDA $32         get end of arrays high byte
.,B2E0 C8       INY             index to array size high byte
.,B2E1 E5 60    SBC $60         subtract array start high byte
.,B2E3 91 5F    STA ($5F),Y     save array size high byte
.,B2E5 A5 0C    LDA $0C         get default DIM flag
.,B2E7 D0 62    BNE $B34B       exit if this was a DIM command
                                else, find element
.,B2E9 C8       INY             set index to # of dimensions, the dimension indeces
                                are on the stack and will be removed as the position
                                of the array element is calculated
.,B2EA B1 5F    LDA ($5F),Y     get array's dimension count
.,B2EC 85 0B    STA $0B         save it
.,B2EE A9 00    LDA #$00        clear byte
.,B2F0 85 71    STA $71         clear array data pointer low byte
.,B2F2 85 72    STA $72         save array data pointer high byte
.,B2F4 C8       INY             increment index, point to array bound high byte
.,B2F5 68       PLA             pull array index low byte
.,B2F6 AA       TAX             copy to X
.,B2F7 85 64    STA $64         save index low byte to FAC1 mantissa 3
.,B2F9 68       PLA             pull array index high byte
.,B2FA 85 65    STA $65         save index high byte to FAC1 mantissa 4
.,B2FC D1 5F    CMP ($5F),Y     compare with array bound high byte
.,B2FE 90 0E    BCC $B30E       branch if within bounds
.,B300 D0 06    BNE $B308       if outside bounds do bad subscript error
                                else high byte was = so test low bytes
.,B302 C8       INY             index to array bound low byte
.,B303 8A       TXA             get array index low byte
.,B304 D1 5F    CMP ($5F),Y     compare with array bound low byte
.,B306 90 07    BCC $B30F       branch if within bounds
.,B308 4C 45 B2 JMP $B245       do bad subscript error
.,B30B 4C 35 A4 JMP $A435       do out of memory error then warm start
.,B30E C8       INY             index to array bound low byte
.,B30F A5 72    LDA $72         get array data pointer high byte
.,B311 05 71    ORA $71         OR with array data pointer low byte
.,B313 18       CLC             clear carry for either add, carry always clear here ??
.,B314 F0 0A    BEQ $B320       branch if array data pointer = null, skip multiply
.,B316 20 4C B3 JSR $B34C       compute array size
.,B319 8A       TXA             get result low byte
.,B31A 65 64    ADC $64add index low byte from FAC1 mantissa 3
.,B31C AA       TAX             save result low byte
.,B31D 98       TYAget result high byte
.,B31E A4 22    LDY $22         restore index
.,B320 65 65    ADC $65add index high byte from FAC1 mantissa 4
.,B322 86 71    STX $71save array data pointer low byte
.,B324 C6 0B    DEC $0B         decrement dimensions count
.,B326 D0 CA    BNE $B2F2       loop if dimensions still to do
.,B328 85 72    STA $72save array data pointer high byte
.,B32A A2 05    LDX #$05        set default element size
.,B32C A5 45    LDA $45         get variable name 1st byte
.,B32E 10 01    BPL $B331       branch if not string or floating point array
.,B330 CA       DEX             decrement element size, $04
.,B331 A5 46    LDA $46         get variable name 2nd byte
.,B333 10 02    BPL $B337       branch if not integer or string
.,B335 CA       DEX             decrement element size, $03
.,B336 CA       DEX             decrement element size, $02
.,B337 86 28    STX $28         save dimension size low byte
.,B339 A9 00    LDA #$00        clear dimension size high byte
.,B33B 20 55 B3 JSR $B355       compute array size
.,B33E 8A       TXA             copy array size low byte
.,B33F 65 58    ADC $58         add array data start pointer low byte
.,B341 85 47    STA $47         save as current variable pointer low byte
.,B343 98       TYA             copy array size high byte
.,B344 65 59    ADC $59         add array data start pointer high byte
.,B346 85 48    STA $48         save as current variable pointer high byte
.,B348 A8       TAY             copy high byte to Y
.,B349 A5 47    LDA $47         get current variable pointer low byte
                                pointer to element is now in AY
.,B34B 60       RTS
                                compute array size, result in XY
.,B34C 84 22    STY $22         save index
.,B34E B1 5F    LDA ($5F),Y     get dimension size low byte
.,B350 85 28    STA $28         save dimension size low byte
.,B352 88       DEY             decrement index
.,B353 B1 5F    LDA ($5F),Y     get dimension size high byte
.,B355 85 29    STA $29         save dimension size high byte
.,B357 A9 10    LDA #$10        count = $10 (16 bit multiply)
.,B359 85 5D    STA $5D         save bit count
.,B35B A2 00    LDX #$00        clear result low byte
.,B35D A0 00    LDY #$00        clear result high byte
.,B35F 8A       TXA             get result low byte
.,B360 0A       ASL             *2
.,B361 AA       TAX             save result low byte
.,B362 98       TYA             get result high byte
.,B363 2A       ROL             *2
.,B364 A8       TAY             save result high byte
.,B365 B0 A4    BCS $B30B       if overflow go do "Out of memory" error
.,B367 06 71    ASL $71         shift element size low byte
.,B369 26 72    ROL $72         shift element size high byte
.,B36B 90 0B    BCC $B378       skip add if no carry
.,B36D 18       CLC             else clear carry for add
.,B36E 8A       TXA             get result low byte
.,B36F 65 28    ADC $28         add dimension size low byte
.,B371 AA       TAX             save result low byte
.,B372 98       TYA             get result high byte
.,B373 65 29    ADC $29         add dimension size high byte
.,B375 A8       TAY             save result high byte
.,B376 B0 93    BCS $B30B       if overflow go do "Out of memory" error
.,B378 C6 5D    DEC $5D         decrement bit count
.,B37A D0 E3    BNE $B35F       loop until all done
.,B37C 60       RTS
                                perform FRE()
.,B37D A5 0D    LDA $0D         get data type flag, $FF = string, $00 = numeric
.,B37F F0 03    BEQ $B384       branch if numeric
.,B381 20 A6 B6 JSR $B6A6       pop string off descriptor stack, or from top of string
                                space returns with A = length, X=$71=pointer low byte,
                                Y=$72=pointer high byte
                                FRE(n) was numeric so do this
.,B384 20 26 B5 JSR $B526       go do garbage collection
.,B387 38       SEC             set carry for subtract
.,B388 A5 33    LDA $33         get bottom of string space low byte
.,B38A E5 31    SBC $31         subtract end of arrays low byte
.,B38C A8       TAY             copy result to Y
.,B38D A5 34    LDA $34         get bottom of string space high byte
.,B38F E5 32    SBC $32         subtract end of arrays high byte

convert fixed integer AY to float FAC1

.,B391 A2 00    LDX #$00        set type = numeric
.,B393 86 0D    STX $0D         clear data type flag, $FF = string, $00 = numeric
.,B395 85 62    STA $62         save FAC1 mantissa 1
.,B397 84 63    STY $63         save FAC1 mantissa 2
.,B399 A2 90    LDX #$90        set exponent=2^16 (integer)
.,B39B 4C 44 BC JMP $BC44       set exp = X, clear FAC1 3 and 4, normalise and return

perform POS()

.,B39E 38       SEC             set Cb for read cursor position
.,B39F 20 F0 FF JSR $FFF0       read/set X,Y cursor position
.,B3A2 A9 00    LDA #$00        clear high byte
.,B3A4 F0 EB    BEQ $B391       convert fixed integer AY to float FAC1, branch always
                                check not Direct, used by DEF and INPUT
.,B3A6 A6 3A    LDX $3A         get current line number high byte
.,B3A8 E8       INX             increment it
.,B3A9 D0 A0    BNE $B34B       return if not direct mode
                                else do illegal direct error
.,B3AB A2 15    LDX #$15        error $15, illegal direct error
.:B3AD 2C       .BYTE $2C       makes next line BIT $1BA2
.,B3AE A2 1B    LDX #$1B        error $1B, undefined function error
.,B3B0 4C 37 A4 JMP $A437       do error #X then warm start

perform DEF

.,B3B3 20 E1 B3 JSR $B3E1       check FNx syntax
.,B3B6 20 A6 B3 JSR $B3A6       check not direct, back here if ok
.,B3B9 20 FA AE JSR $AEFA       scan for "(", else do syntax error then warm start
.,B3BC A9 80    LDA #$80        set flag for FNx
.,B3BE 85 10    STA $10         save subscript/FNx flag
.,B3C0 20 8B B0 JSR $B08B       get variable address
.,B3C3 20 8D AD JSR $AD8D       check if source is numeric, else do type mismatch
.,B3C6 20 F7 AE JSR $AEF7       scan for ")", else do syntax error then warm start
.,B3C9 A9 B2    LDA #$B2        get = token
.,B3CB 20 FF AE JSR $AEFF       scan for CHR$(A), else do syntax error then warm start
.,B3CE 48       PHA             push next character
.,B3CF A5 48    LDA $48         get current variable pointer high byte
.,B3D1 48       PHA             push it
.,B3D2 A5 47    LDA $47         get current variable pointer low byte
.,B3D4 48       PHA             push it
.,B3D5 A5 7B    LDA $7B         get BASIC execute pointer high byte
.,B3D7 48       PHA             push it
.,B3D8 A5 7A    LDA $7A         get BASIC execute pointer low byte
.,B3DA 48       PHA             push it
.,B3DB 20 F8 A8 JSR $A8F8       perform DATA
.,B3DE 4C 4F B4 JMP $B44F       put execute pointer and variable pointer into function
                                and return

check FNx syntax

.,B3E1 A9 A5    LDA #$A5        set FN token
.,B3E3 20 FF AE JSR $AEFF       scan for CHR$(A), else do syntax error then warm start
.,B3E6 09 80    ORA #$80        set FN flag bit
.,B3E8 85 10    STA $10         save FN name
.,B3EA 20 92 B0 JSR $B092       search for FN variable
.,B3ED 85 4E    STA $4E         save function pointer low byte
.,B3EF 84 4F    STY $4F         save function pointer high byte
.,B3F1 4C 8D AD JMP $AD8D       check if source is numeric and return, else do type
                                mismatch

Evaluate FNx

.,B3F4 20 E1 B3 JSR $B3E1       check FNx syntax
.,B3F7 A5 4F    LDA $4F         get function pointer high byte
.,B3F9 48       PHA             push it
.,B3FA A5 4E    LDA $4E         get function pointer low byte
.,B3FC 48       PHA             push it
.,B3FD 20 F1 AE JSR $AEF1       evaluate expression within parentheses
.,B400 20 8D AD JSR $AD8D       check if source is numeric, else do type mismatch
.,B403 68       PLA             pop function pointer low byte
.,B404 85 4E    STA $4E         restore it
.,B406 68       PLA             pop function pointer high byte
.,B407 85 4F    STA $4F         restore it
.,B409 A0 02    LDY #$02        index to variable pointer high byte
.,B40B B1 4E    LDA ($4E),Y     get variable address low byte
.,B40D 85 47    STA $47         save current variable pointer low byte
.,B40F AA       TAX             copy address low byte
.,B410 C8       INY             index to variable address high byte
.,B411 B1 4E    LDA ($4E),Y     get variable pointer high byte
.,B413 F0 99    BEQ $B3AE       branch if high byte zero
.,B415 85 48    STA $48         save current variable pointer high byte
.,B417 C8       INY             index to mantissa 3
                                now stack the function variable value before use
.,B418 B1 47    LDA ($47),Y     get byte from variable
.,B41A 48       PHA             stack it
.,B41B 88       DEY             decrement index
.,B41C 10 FA    BPL $B418       loop until variable stacked
.,B41E A4 48    LDY $48get current variable pointer high byte
.,B420 20 D4 BB JSR $BBD4       pack FAC1 into (XY)
.,B423 A5 7B    LDA $7B         get BASIC execute pointer high byte
.,B425 48       PHA             push it
.,B426 A5 7A    LDA $7A         get BASIC execute pointer low byte
.,B428 48       PHA             push it
.,B429 B1 4E    LDA ($4E),Y     get function execute pointer low byte
.,B42B 85 7A    STA $7A         save BASIC execute pointer low byte
.,B42D C8       INY             index to high byte
.,B42E B1 4E    LDA ($4E),Y     get function execute pointer high byte
.,B430 85 7B    STA $7B         save BASIC execute pointer high byte
.,B432 A5 48    LDA $48         get current variable pointer high byte
.,B434 48       PHA             push it
.,B435 A5 47    LDA $47         get current variable pointer low byte
.,B437 48       PHA             push it
.,B438 20 8A AD JSR $AD8A       evaluate expression and check is numeric, else do
                                type mismatch
.,B43B 68       PLA             pull variable address low byte
.,B43C 85 4E    STA $4E         save variable address low byte
.,B43E 68       PLA             pull variable address high byte
.,B43F 85 4F    STA $4F         save variable address high byte
.,B441 20 79 00 JSR $0079       scan memory
.,B444 F0 03    BEQ $B449       branch if null (should be [EOL] marker)
.,B446 4C 08 AF JMP $AF08       else syntax error then warm start

restore BASIC execute pointer and function variable from stack

.,B449 68       PLA             pull BASIC execute pointer low byte
.,B44A 85 7A    STA $7A         save BASIC execute pointer low byte
.,B44C 68       PLA             pull BASIC execute pointer high byte
.,B44D 85 7B    STA $7B         save BASIC execute pointer high byte
                                put execute pointer and variable pointer into function
.,B44F A0 00    LDY #$00        clear index
.,B451 68       PLA             pull BASIC execute pointer low byte
.,B452 91 4E    STA ($4E),Y     save to function
.,B454 68       PLA             pull BASIC execute pointer high byte
.,B455 C8       INY             increment index
.,B456 91 4E    STA ($4E),Y     save to function
.,B458 68       PLA             pull current variable address low byte
.,B459 C8       INY             increment index
.,B45A 91 4E    STA ($4E),Y     save to function
.,B45C 68       PLA             pull current variable address high byte
.,B45D C8       INY             increment index
.,B45E 91 4E    STA ($4E),Y     save to function
.,B460 68       PLA             pull ??
.,B461 C8       INY             increment index
.,B462 91 4E    STA ($4E),Y     save to function
.,B464 60       RTS

perform STR$()

.,B465 20 8D AD JSR $AD8D       check if source is numeric, else do type mismatch
.,B468 A0 00    LDY #$00        set string index
.,B46A 20 DF BD JSR $BDDF       convert FAC1 to string
.,B46D 68       PLA             dump return address (skip type check)
.,B46E 68       PLA             dump return address (skip type check)
.,B46F A9 FF    LDA #$FF        set result string low pointer
.,B471 A0 00    LDY #$00        set result string high pointer
.,B473 F0 12    BEQ $B487print null terminated string to utility pointer

do string vector

                                copy descriptor pointer and make string space A bytes long
.,B475 A6 64    LDX $64         get descriptor pointer low byte
.,B477 A4 65    LDY $65         get descriptor pointer high byte
.,B479 86 50    STX $50         save descriptor pointer low byte
.,B47B 84 51    STY $51         save descriptor pointer high byte

make string space A bytes long

.,B47D 20 F4 B4 JSR $B4F4       make space in string memory for string A long
.,B480 86 62    STX $62         save string pointer low byte
.,B482 84 63    STY $63         save string pointer high byte
.,B484 85 61    STA $61         save length
.,B486 60       RTS

scan, set up string

                                print " terminated string to utility pointer
.,B487 A2 22    LDX #$22        set terminator to "
.,B489 86 07    STX $07         set search character, terminator 1
.,B48B 86 08    STX $08         set terminator 2
                                print search or alternate terminated string to utility pointer
                                source is AY
.,B48D 85 6F    STA $6F         store string start low byte
.,B48F 84 70    STY $70         store string start high byte
.,B491 85 62    STA $62         save string pointer low byte
.,B493 84 63    STY $63         save string pointer high byte
.,B495 A0 FF    LDY #$FF        set length to -1
.,B497 C8       INY             increment length
.,B498 B1 6F    LDA ($6F),Y     get byte from string
.,B49A F0 0C    BEQ $B4A8       exit loop if null byte [EOS]
.,B49C C5 07    CMP $07         compare with search character, terminator 1
.,B49E F0 04    BEQ $B4A4       branch if terminator
.,B4A0 C5 08    CMP $08         compare with terminator 2
.,B4A2 D0 F3    BNE $B497       loop if not terminator 2
.,B4A4 C9 22    CMP #$22        compare with "
.,B4A6 F0 01    BEQ $B4A9       branch if " (carry set if = !)
.,B4A8 18       CLC             clear carry for add (only if [EOL] terminated string)
.,B4A9 84 61    STY $61         save length in FAC1 exponent
.,B4AB 98       TYA             copy length to A
.,B4AC 65 6F    ADC $6F         add string start low byte
.,B4AE 85 71    STA $71         save string end low byte
.,B4B0 A6 70    LDX $70         get string start high byte
.,B4B2 90 01    BCC $B4B5       branch if no low byte overflow
.,B4B4 E8       INX             else increment high byte
.,B4B5 86 72    STX $72         save string end high byte
.,B4B7 A5 70    LDA $70         get string start high byte
.,B4B9 F0 04    BEQ $B4BF       branch if in utility area
.,B4BB C9 02    CMP #$02        compare with input buffer memory high byte
.,B4BD D0 0B    BNE $B4CA       branch if not in input buffer memory
                                string in input buffer or utility area, move to string
                                memory
.,B4BF 98       TYA             copy length to A
.,B4C0 20 75 B4 JSR $B475       copy descriptor pointer and make string space A bytes long
.,B4C3 A6 6F    LDX $6F         get string start low byte
.,B4C5 A4 70    LDY $70         get string start high byte
.,B4C7 20 88 B6 JSR $B688       store string A bytes long from XY to utility pointer
                                check for space on descriptor stack then ...
                                put string address and length on descriptor stack and update stack pointers
.,B4CA A6 16    LDX $16         get the descriptor stack pointer
.,B4CC E0 22    CPX #$22        compare it with the maximum + 1
.,B4CE D0 05    BNE $B4D5       if there is space on the string stack continue
                                else do string too complex error
.,B4D0 A2 19    LDX #$19        error $19, string too complex error
.,B4D2 4C 37 A4 JMP $A437       do error #X then warm start
                                put string address and length on descriptor stack and update stack pointers
.,B4D5 A5 61    LDA $61         get the string length
.,B4D7 95 00    STA $00,X       put it on the string stack
.,B4D9 A5 62    LDA $62         get the string pointer low byte
.,B4DB 95 01    STA $01,X       put it on the string stack
.,B4DD A5 63    LDA $63         get the string pointer high byte
.,B4DF 95 02    STA $02,X       put it on the string stack
.,B4E1 A0 00    LDY #$00        clear Y
.,B4E3 86 64    STX $64         save the string descriptor pointer low byte
.,B4E5 84 65    STY $65         save the string descriptor pointer high byte, always $00
.,B4E7 84 70    STY $70         clear FAC1 rounding byte
.,B4E9 88       DEY             Y = $FF
.,B4EA 84 0D    STY $0D         save the data type flag, $FF = string
.,B4EC 86 17    STX $17         save the current descriptor stack item pointer low byte
.,B4EE E8       INX             update the stack pointer
.,B4EF E8       INX             update the stack pointer
.,B4F0 E8       INX             update the stack pointer
.,B4F1 86 16    STX $16         save the new descriptor stack pointer
.,B4F3 60       RTS

make space in string memory for string A long

                                return X = pointer low byte, Y = pointer high byte
.,B4F4 46 0F    LSR $0F         clear garbage collected flag (b7)
                                make space for string A long
.,B4F6 48       PHA             save string length
.,B4F7 49 FF    EOR #$FF        complement it
.,B4F9 38       SEC             set carry for subtract, two's complement add
.,B4FA 65 33    ADC $33         add bottom of string space low byte, subtract length
.,B4FC A4 34    LDY $34         get bottom of string space high byte
.,B4FE B0 01    BCS $B501       skip decrement if no underflow
.,B500 88       DEY             decrement bottom of string space high byte
.,B501 C4 32    CPY $32         compare with end of arrays high byte
.,B503 90 11    BCC $B516       do out of memory error if less
.,B505 D0 04    BNE $B50B       if not = skip next test
.,B507 C5 31    CMP $31         compare with end of arrays low byte
.,B509 90 0B    BCC $B516       do out of memory error if less
.,B50B 85 33    STA $33         save bottom of string space low byte
.,B50D 84 34    STY $34         save bottom of string space high byte
.,B50F 85 35    STA $35         save string utility ptr low byte
.,B511 84 36    STY $36         save string utility ptr high byte
.,B513 AA       TAX             copy low byte to X
.,B514 68       PLA             get string length back
.,B515 60       RTS
.,B516 A2 10    LDX #$10        error code $10, out of memory error
.,B518 A5 0F    LDA $0F         get garbage collected flag
.,B51A 30 B6    BMI $B4D2       if set then do error code X
.,B51C 20 26 B5 JSR $B526       else go do garbage collection
.,B51F A9 80    LDA #$80        flag for garbage collected
.,B521 85 0F    STA $0F         set garbage collected flag
.,B523 68       PLA             pull length
.,B524 D0 D0    BNE $B4F6       go try again (loop always, length should never be = $00)

garbage collection routine

.,B526 A6 37    LDX $37         get end of memory low byte
.,B528 A5 38    LDA $38         get end of memory high byte
                                re-run routine from last ending
.,B52A 86 33    STX $33         set bottom of string space low byte
.,B52C 85 34    STA $34         set bottom of string space high byte
.,B52E A0 00    LDY #$00        clear index
.,B530 84 4F    STY $4F         clear working pointer high byte
.,B532 84 4E    STY $4E         clear working pointer low byte
.,B534 A5 31    LDA $31         get end of arrays low byte
.,B536 A6 32    LDX $32         get end of arrays high byte
.,B538 85 5F    STA $5F         save as highest uncollected string pointer low byte
.,B53A 86 60    STX $60         save as highest uncollected string pointer high byte
.,B53C A9 19    LDA #$19        set descriptor stack pointer
.,B53E A2 00    LDX #$00        clear X
.,B540 85 22    STA $22         save descriptor stack pointer low byte
.,B542 86 23    STX $23         save descriptor stack pointer high byte ($00)
.,B544 C5 16    CMP $16         compare with descriptor stack pointer
.,B546 F0 05    BEQ $B54D       branch if =
.,B548 20 C7 B5 JSR $B5C7       check string salvageability
.,B54B F0 F7    BEQ $B544       loop always
                                done stacked strings, now do string variables
.,B54D A9 07    LDA #$07        set step size = $07, collecting variables
.,B54F 85 53    STA $53         save garbage collection step size
.,B551 A5 2D    LDA $2D         get start of variables low byte
.,B553 A6 2E    LDX $2E         get start of variables high byte
.,B555 85 22    STA $22         save as pointer low byte
.,B557 86 23    STX $23         save as pointer high byte
.,B559 E4 30    CPX $30         compare end of variables high byte,
                                start of arrays high byte
.,B55B D0 04    BNE $B561       branch if no high byte match
.,B55D C5 2F    CMP $2F         else compare end of variables low byte,
                                start of arrays low byte
.,B55F F0 05    BEQ $B566       branch if = variable memory end
.,B561 20 BD B5 JSR $B5BD       check variable salvageability
.,B564 F0 F3    BEQ $B559       loop always
                                done string variables, now do string arrays
.,B566 85 58    STA $58         save start of arrays low byte as working pointer
.,B568 86 59    STX $59         save start of arrays high byte as working pointer
.,B56A A9 03    LDA #$03        set step size, collecting descriptors
.,B56C 85 53    STA $53         save step size
.,B56E A5 58    LDA $58         get pointer low byte
.,B570 A6 59    LDX $59         get pointer high byte
.,B572 E4 32    CPX $32         compare with end of arrays high byte
.,B574 D0 07    BNE $B57D       branch if not at end
.,B576 C5 31    CMP $31         else compare with end of arrays low byte
.,B578 D0 03    BNE $B57D       branch if not at end
.,B57A 4C 06 B6 JMP $B606       collect string, tidy up and exit if at end ??
.,B57D 85 22    STA $22         save pointer low byte
.,B57F 86 23    STX $23         save pointer high byte
.,B581 A0 00    LDY #$00        set index
.,B583 B1 22    LDA ($22),Y     get array name first byte
.,B585 AA       TAX             copy it
.,B586 C8       INY             increment index
.,B587 B1 22    LDA ($22),Y     get array name second byte
.,B589 08       PHP             push the flags
.,B58A C8       INY             increment index
.,B58B B1 22    LDA ($22),Y     get array size low byte
.,B58D 65 58    ADC $58         add start of this array low byte
.,B58F 85 58    STA $58         save start of next array low byte
.,B591 C8       INY             increment index
.,B592 B1 22    LDA ($22),Y     get array size high byte
.,B594 65 59    ADC $59         add start of this array high byte
.,B596 85 59    STA $59         save start of next array high byte
.,B598 28       PLP             restore the flags
.,B599 10 D3    BPL $B56E       skip if not string array
                                was possibly string array so ...
.,B59B 8A       TXA             get name first byte back
.,B59C 30 D0    BMI $B56E       skip if not string array
.,B59E C8       INY             increment index
.,B59F B1 22    LDA ($22),Y     get # of dimensions
.,B5A1 A0 00    LDY #$00        clear index
.,B5A3 0A       ASL             *2
.,B5A4 69 05    ADC #$05        +5 (array header size)
.,B5A6 65 22    ADC $22         add pointer low byte
.,B5A8 85 22    STA $22         save pointer low byte
.,B5AA 90 02    BCC $B5AE       branch if no rollover
.,B5AC E6 23    INC $23         else increment pointer hgih byte
.,B5AE A6 23    LDX $23         get pointer high byte
.,B5B0 E4 59    CPX $59         compare pointer high byte with end of this array high byte
.,B5B2 D0 04    BNE $B5B8       branch if not there yet
.,B5B4 C5 58    CMP $58         compare pointer low byte with end of this array low byte
.,B5B6 F0 BA    BEQ $B572       if at end of this array go check next array
.,B5B8 20 C7 B5 JSR $B5C7       check string salvageability
.,B5BB F0 F3    BEQ $B5B0       loop
                                check variable salvageability
.,B5BD B1 22    LDA ($22),Y     get variable name first byte
.,B5BF 30 35    BMI $B5F6       add step and exit if not string
.,B5C1 C8       INY             increment index
.,B5C2 B1 22    LDA ($22),Y     get variable name second byte
.,B5C4 10 30    BPL $B5F6       add step and exit if not string
.,B5C6 C8       INY             increment index
                                check string salvageability
.,B5C7 B1 22    LDA ($22),Y     get string length
.,B5C9 F0 2B    BEQ $B5F6       add step and exit if null string
.,B5CB C8       INY             increment index
.,B5CC B1 22    LDA ($22),Y     get string pointer low byte
.,B5CE AA       TAX             copy to X
.,B5CF C8       INY             increment index
.,B5D0 B1 22    LDA ($22),Y     get string pointer high byte
.,B5D2 C5 34    CMP $34         compare string pointer high byte with bottom of string
                                space high byte
.,B5D4 90 06    BCC $B5DC       if bottom of string space greater go test against highest
                                uncollected string
.,B5D6 D0 1E    BNE $B5F6       if bottom of string space less string has been collected
                                so go update pointers, step to next and return
                                high bytes were equal so test low bytes
.,B5D8 E4 33    CPX $33         compare string pointer low byte with bottom of string
                                space low byte
.,B5DA B0 1A    BCS $B5F6       if bottom of string space less string has been collected
                                so go update pointers, step to next and return
                                else test string against highest uncollected string so far
.,B5DC C5 60    CMP $60         compare string pointer high byte with highest uncollected
                                string high byte
.,B5DE 90 16    BCC $B5F6       if highest uncollected string is greater then go update
                                pointers, step to next and return
.,B5E0 D0 04    BNE $B5E6       if highest uncollected string is less then go set this
                                string as highest uncollected so far
                                high bytes were equal so test low bytes
.,B5E2 E4 5F    CPX $5F         compare string pointer low byte with highest uncollected
                                string low byte
.,B5E4 90 10    BCC $B5F6       if highest uncollected string is greater then go update
                                pointers, step to next and return
                                else set current string as highest uncollected string
.,B5E6 86 5F    STX $5F         save string pointer low byte as highest uncollected string
                                low byte
.,B5E8 85 60    STA $60         save string pointer high byte as highest uncollected
                                string high byte
.,B5EA A5 22    LDA $22         get descriptor pointer low byte
.,B5EC A6 23    LDX $23         get descriptor pointer high byte
.,B5EE 85 4E    STA $4E         save working pointer high byte
.,B5F0 86 4F    STX $4F         save working pointer low byte
.,B5F2 A5 53    LDA $53         get step size
.,B5F4 85 55    STA $55         copy step size
.,B5F6 A5 53    LDA $53         get step size
.,B5F8 18       CLC             clear carry for add
.,B5F9 65 22    ADC $22         add pointer low byte
.,B5FB 85 22    STA $22         save pointer low byte
.,B5FD 90 02    BCC $B601       branch if no rollover
.,B5FF E6 23    INC $23         else increment pointer high byte
.,B601 A6 23    LDX $23         get pointer high byte
.,B603 A0 00    LDY #$00        flag not moved
.,B605 60       RTS
                                collect string
.,B606 A5 4F    LDA $4F         get working pointer low byte
.,B608 05 4E    ORA $4E         OR working pointer high byte
.,B60A F0 F5    BEQ $B601       exit if nothing to collect
.,B60C A5 55    LDA $55         get copied step size
.,B60E 29 04    AND #$04        mask step size, $04 for variables, $00 for array or stack
.,B610 4A       LSR             >> 1
.,B611 A8       TAY             copy to index
.,B612 85 55    STA $55         save offset to descriptor start
.,B614 B1 4E    LDA ($4E),Y     get string length low byte
.,B616 65 5F    ADC $5F         add string start low byte
.,B618 85 5A    STA $5A         set block end low byte
.,B61A A5 60    LDA $60         get string start high byte
.,B61C 69 00    ADC #$00        add carry
.,B61E 85 5B    STA $5B         set block end high byte
.,B620 A5 33    LDA $33         get bottom of string space low byte
.,B622 A6 34    LDX $34         get bottom of string space high byte
.,B624 85 58    STA $58         save destination end low byte
.,B626 86 59    STX $59         save destination end high byte
.,B628 20 BF A3 JSR $A3BF       open up space in memory, don't set array end. this
                                copies the string from where it is to the end of the
                                uncollected string memory
.,B62B A4 55    LDY $55         restore offset to descriptor start
.,B62D C8       INY             increment index to string pointer low byte
.,B62E A5 58    LDA $58         get new string pointer low byte
.,B630 91 4E    STA ($4E),Y     save new string pointer low byte
.,B632 AA       TAX             copy string pointer low byte
.,B633 E6 59    INC $59         increment new string pointer high byte
.,B635 A5 59    LDA $59         get new string pointer high byte
.,B637 C8       INY             increment index to string pointer high byte
.,B638 91 4E    STA ($4E),Y     save new string pointer high byte
.,B63A 4C 2A B5 JMP $B52A       re-run routine from last ending, XA holds new bottom
                                of string memory pointer

concatenate

                                add strings, the first string is in the descriptor, the second string is in line
.,B63D A5 65    LDA $65         get descriptor pointer high byte
.,B63F 48       PHA             put on stack
.,B640 A5 64    LDA $64         get descriptor pointer low byte
.,B642 48       PHA             put on stack
.,B643 20 83 AE JSR $AE83       get value from line
.,B646 20 8F AD JSR $AD8F       check if source is string, else do type mismatch
.,B649 68       PLA             get descriptor pointer low byte back
.,B64A 85 6F    STA $6F         set pointer low byte
.,B64C 68       PLA             get descriptor pointer high byte back
.,B64D 85 70    STA $70         set pointer high byte
.,B64F A0 00    LDY #$00        clear index
.,B651 B1 6F    LDA ($6F),Y     get length of first string from descriptor
.,B653 18       CLC             clear carry for add
.,B654 71 64    ADC ($64),Y     add length of second string
.,B656 90 05    BCC $B65D       branch if no overflow
.,B658 A2 17    LDX #$17        else error $17, string too long error
.,B65A 4C 37 A4 JMP $A437       do error #X then warm start
.,B65D 20 75 B4 JSR $B475       copy descriptor pointer and make string space A bytes long
.,B660 20 7A B6 JSR $B67A       copy string from descriptor to utility pointer
.,B663 A5 50    LDA $50         get descriptor pointer low byte
.,B665 A4 51    LDY $51         get descriptor pointer high byte
.,B667 20 AA B6 JSR $B6AA       pop (YA) descriptor off stack or from top of string space
                                returns with A = length, X = pointer low byte,
                                Y = pointer high byte
.,B66A 20 8C B6 JSR $B68C       store string from pointer to utility pointer
.,B66D A5 6F    LDA $6F         get descriptor pointer low byte
.,B66F A4 70    LDY $70         get descriptor pointer high byte
.,B671 20 AA B6 JSR $B6AA       pop (YA) descriptor off stack or from top of string space
                                returns with A = length, X = pointer low byte,
                                Y = pointer high byte
.,B674 20 CA B4 JSR $B4CA       check space on descriptor stack then put string address
                                and length on descriptor stack and update stack pointers
.,B677 4C B8 AD JMP $ADB8       continue evaluation

copy string from descriptor to utility pointer

.,B67A A0 00    LDY #$00        clear index
.,B67C B1 6F    LDA ($6F),Y     get string length
.,B67E 48       PHA             save it
.,B67F C8       INY             increment index
.,B680 B1 6F    LDA ($6F),Y     get string pointer low byte
.,B682 AA       TAX             copy to X
.,B683 C8       INY             increment index
.,B684 B1 6F    LDA ($6F),Y     get string pointer high byte
.,B686 A8       TAY             copy to Y
.,B687 68       PLA             get length back
.,B688 86 22    STX $22         save string pointer low byte
.,B68A 84 23    STY $23         save string pointer high byte
                                store string from pointer to utility pointer
.,B68C A8       TAY             copy length as index
.,B68D F0 0A    BEQ $B699       branch if null string
.,B68F 48       PHA             save length
.,B690 88       DEY             decrement length/index
.,B691 B1 22    LDA ($22),Y     get byte from string
.,B693 91 35    STA ($35),Y     save byte to destination
.,B695 98       TYA             copy length/index
.,B696 D0 F8    BNE $B690       loop if not all done yet
.,B698 68       PLA             restore length
.,B699 18       CLC             clear carry for add
.,B69A 65 35    ADC $35         add string utility ptr low byte
.,B69C 85 35    STA $35         save string utility ptr low byte
.,B69E 90 02    BCC $B6A2       branch if no rollover
.,B6A0 E6 36    INC $36         increment string utility ptr high byte
.,B6A2 60       RTS

evaluate string

.,B6A3 20 8F AD JSR $AD8F       check if source is string, else do type mismatch
                                pop string off descriptor stack, or from top of string space
                                returns with A = length, X = pointer low byte, Y = pointer high byte
.,B6A6 A5 64    LDA $64         get descriptor pointer low byte
.,B6A8 A4 65    LDY $65         get descriptor pointer high byte
                                pop (YA) descriptor off stack or from top of string space
                                returns with A = length, X = pointer low byte, Y = pointer high byte
.,B6AA 85 22    STA $22         save string pointer low byte
.,B6AC 84 23    STY $23         save string pointer high byte
.,B6AE 20 DB B6 JSR $B6DB       clean descriptor stack, YA = pointer
.,B6B1 08       PHP             save status flags
.,B6B2 A0 00    LDY #$00        clear index
.,B6B4 B1 22    LDA ($22),Y     get length from string descriptor
.,B6B6 48       PHA             put on stack
.,B6B7 C8       INY             increment index
.,B6B8 B1 22    LDA ($22),Y     get string pointer low byte from descriptor
.,B6BA AA       TAX             copy to X
.,B6BB C8       INY             increment index
.,B6BC B1 22    LDA ($22),Y     get string pointer high byte from descriptor
.,B6BE A8       TAY             copy to Y
.,B6BF 68       PLA             get string length back
.,B6C0 28       PLP             restore status
.,B6C1 D0 13    BNE $B6D6       branch if pointer <> last_sl,last_sh
.,B6C3 C4 34    CPY $34         compare with bottom of string space high byte
.,B6C5 D0 0F    BNE $B6D6       branch if <>
.,B6C7 E4 33    CPX $33         else compare with bottom of string space low byte
.,B6C9 D0 0B    BNE $B6D6       branch if <>
.,B6CB 48       PHA             save string length
.,B6CC 18       CLC             clear carry for add
.,B6CD 65 33    ADC $33         add bottom of string space low byte
.,B6CF 85 33    STA $33         set bottom of string space low byte
.,B6D1 90 02    BCC $B6D5       skip increment if no overflow
.,B6D3 E6 34    INC $34         increment bottom of string space high byte
.,B6D5 68       PLA             restore string length
.,B6D6 86 22    STX $22         save string pointer low byte
.,B6D8 84 23    STY $23         save string pointer high byte
.,B6DA 60       RTS
                                clean descriptor stack, YA = pointer
                                checks if AY is on the descriptor stack, if so does a stack discard
.,B6DB C4 18    CPY $18         compare high byte with current descriptor stack item
                                pointer high byte
.,B6DD D0 0C    BNE $B6EB       exit if <>
.,B6DF C5 17    CMP $17         compare low byte with current descriptor stack item
                                pointer low byte
.,B6E1 D0 08    BNE $B6EB       exit if <>
.,B6E3 85 16    STA $16         set descriptor stack pointer
.,B6E5 E9 03    SBC #$03        update last string pointer low byte
.,B6E7 85 17    STA $17         save current descriptor stack item pointer low byte
.,B6E9 A0 00    LDY #$00        clear high byte
.,B6EB 60       RTS

perform CHR$()

.,B6EC 20 A1 B7 JSR $B7A1       evaluate byte expression, result in X
.,B6EF 8A       TXA             copy to A
.,B6F0 48       PHA             save character
.,B6F1 A9 01    LDA #$01        string is single byte
.,B6F3 20 7D B4 JSR $B47D       make string space A bytes long
.,B6F6 68       PLA             get character back
.,B6F7 A0 00    LDY #$00        clear index
.,B6F9 91 62    STA ($62),Y     save byte in string - byte IS string!
.,B6FB 68       PLA             dump return address (skip type check)
.,B6FC 68       PLA             dump return address (skip type check)
.,B6FD 4C CA B4 JMP $B4CA       check space on descriptor stack then put string address
                                and length on descriptor stack and update stack pointers

perform LEFT$()

.,B700 20 61 B7 JSR $B761       pull string data and byte parameter from stack
                                return pointer in descriptor, byte in A (and X), Y=0
.,B703 D1 50    CMP ($50),Y     compare byte parameter with string length
.,B705 98       TYA             clear A
.,B706 90 04    BCC $B70C       branch if string length > byte parameter
.,B708 B1 50    LDA ($50),Y     else make parameter = length
.,B70A AA       TAX             copy to byte parameter copy
.,B70B 98       TYA             clear string start offset
.,B70C 48       PHA             save string start offset
.,B70D 8A       TXA             copy byte parameter (or string length if <)
.,B70E 48       PHA             save string length
.,B70F 20 7D B4 JSR $B47D       make string space A bytes long
.,B712 A5 50    LDA $50         get descriptor pointer low byte
.,B714 A4 51    LDY $51         get descriptor pointer high byte
.,B716 20 AA B6 JSR $B6AA       pop (YA) descriptor off stack or from top of string space
                                returns with A = length, X = pointer low byte,
                                Y = pointer high byte
.,B719 68       PLA             get string length back
.,B71A A8       TAY             copy length to Y
.,B71B 68       PLA             get string start offset back
.,B71C 18       CLC             clear carry for add
.,B71D 65 22    ADC $22         add start offset to string start pointer low byte
.,B71F 85 22    STA $22         save string start pointer low byte
.,B721 90 02    BCC $B725       branch if no overflow
.,B723 E6 23    INC $23         else increment string start pointer high byte
.,B725 98       TYA             copy length to A
.,B726 20 8C B6 JSR $B68C       store string from pointer to utility pointer
.,B729 4C CA B4 JMP $B4CA       check space on descriptor stack then put string address
                                and length on descriptor stack and update stack pointers

perform RIGHT$()

.,B72C 20 61 B7 JSR $B761       pull string data and byte parameter from stack
                                return pointer in descriptor, byte in A (and X), Y=0
.,B72F 18       CLC             clear carry for add-1
.,B730 F1 50    SBC ($50),Y     subtract string length
.,B732 49 FF    EOR #$FF        invert it (A=LEN(expression$)-l)
.,B734 4C 06 B7 JMP $B706       go do rest of LEFT$()

perform MID$()

.,B737 A9 FF    LDA #$FF        set default length = 255
.,B739 85 65    STA $65         save default length
.,B73B 20 79 00 JSR $0079       scan memory
.,B73E C9 29    CMP #$29        compare with ")"
.,B740 F0 06    BEQ $B748       branch if = ")" (skip second byte get)
.,B742 20 FD AE JSR $AEFD       scan for ",", else do syntax error then warm start
.,B745 20 9E B7 JSR $B79E       get byte parameter
.,B748 20 61 B7 JSR $B761       pull string data and byte parameter from stack
                                return pointer in descriptor, byte in A (and X), Y=0
.,B74B F0 4B    BEQ $B798       if null do illegal quantity error then warm start
.,B74D CA       DEX             decrement start index
.,B74E 8A       TXA             copy to A
.,B74F 48       PHA             save string start offset
.,B750 18       CLC             clear carry for sub-1
.,B751 A2 00    LDX #$00        clear output string length
.,B753 F1 50    SBC ($50),Y     subtract string length
.,B755 B0 B6    BCS $B70D       if start>string length go do null string
.,B757 49 FF    EOR #$FF        complement -length
.,B759 C5 65    CMP $65         compare byte parameter
.,B75B 90 B1    BCC $B70E       if length>remaining string go do RIGHT$
.,B75D A5 65    LDA $65         get length byte
.,B75F B0 AD    BCS $B70E       go do string copy, branch always

pull string data and byte parameter from stack

                                return pointer in descriptor, byte in A (and X), Y=0
.,B761 20 F7 AE JSR $AEF7       scan for ")", else do syntax error then warm start
.,B764 68       PLA             pull return address low byte
.,B765 A8       TAY             save return address low byte
.,B766 68       PLA             pull return address high byte
.,B767 85 55    STA $55         save return address high byte
.,B769 68       PLA             dump call to function vector low byte
.,B76A 68       PLA             dump call to function vector high byte
.,B76B 68       PLA             pull byte parameter
.,B76C AA       TAX             copy byte parameter to X
.,B76D 68       PLA             pull string pointer low byte
.,B76E 85 50    STA $50         save it
.,B770 68       PLA             pull string pointer high byte
.,B771 85 51    STA $51         save it
.,B773 A5 55    LDA $55         get return address high byte
.,B775 48       PHA             back on stack
.,B776 98       TYA             get return address low byte
.,B777 48       PHA             back on stack
.,B778 A0 00    LDY #$00        clear index
.,B77A 8A       TXA             copy byte parameter
.,B77B 60       RTS

perform LEN()

.,B77C 20 82 B7 JSR $B782       evaluate string, get length in A (and Y)
.,B77F 4C A2 B3 JMP $B3A2       convert Y to byte in FAC1 and return

evaluate string, get length in Y

.,B782 20 A3 B6 JSR $B6A3       evaluate string
.,B785 A2 00    LDX #$00        set data type = numeric
.,B787 86 0D    STX $0D         clear data type flag, $FF = string, $00 = numeric
.,B789 A8       TAY             copy length to Y
.,B78A 60       RTS

perform ASC()

.,B78B 20 82 B7 JSR $B782       evaluate string, get length in A (and Y)
.,B78E F0 08    BEQ $B798       if null do illegal quantity error then warm start
.,B790 A0 00    LDY #$00        set index to first character
.,B792 B1 22    LDA ($22),Y     get byte
.,B794 A8       TAY             copy to Y
.,B795 4C A2 B3 JMP $B3A2       convert Y to byte in FAC1 and return

do illegal quantity error then warm start

.,B798 4C 48 B2 JMP $B248       do illegal quantity error then warm start

scan and get byte parameter

.,B79B 20 73 00 JSR $0073       increment and scan memory

get byte parameter

.,B79E 20 8A AD JSR $AD8A       evaluate expression and check is numeric, else do
                                type mismatch

evaluate byte expression, result in X

.,B7A1 20 B8 B1 JSR $B1B8       evaluate integer expression, sign check
.,B7A4 A6 64    LDX $64         get FAC1 mantissa 3
.,B7A6 D0 F0    BNE $B798       if not null do illegal quantity error then warm start
.,B7A8 A6 65    LDX $65         get FAC1 mantissa 4
.,B7AA 4C 79 00 JMP $0079       scan memory and return

perform VAL()

.,B7AD 20 82 B7 JSR $B782       evaluate string, get length in A (and Y)
.,B7B0 D0 03    BNE $B7B5       branch if not null string
                                string was null so set result = $00
.,B7B2 4C F7 B8 JMP $B8F7       clear FAC1 exponent and sign and return
.,B7B5 A6 7A    LDX $7A         get BASIC execute pointer low byte
.,B7B7 A4 7B    LDY $7B         get BASIC execute pointer high byte
.,B7B9 86 71    STX $71         save BASIC execute pointer low byte
.,B7BB 84 72    STY $72         save BASIC execute pointer high byte
.,B7BD A6 22    LDX $22         get string pointer low byte
.,B7BF 86 7A    STX $7A         save BASIC execute pointer low byte
.,B7C1 18       CLC             clear carry for add
.,B7C2 65 22    ADC $22         add string length
.,B7C4 85 24    STA $24         save string end low byte
.,B7C6 A6 23    LDX $23         get string pointer high byte
.,B7C8 86 7B    STX $7B         save BASIC execute pointer high byte
.,B7CA 90 01    BCC $B7CD       branch if no high byte increment
.,B7CC E8       INX             increment string end high byte
.,B7CD 86 25    STX $25         save string end high byte
.,B7CF A0 00    LDY #$00        set index to $00
.,B7D1 B1 24    LDA ($24),Y     get string end byte
.,B7D3 48       PHA             push it
.,B7D4 98       TYA             clear A
.,B7D5 91 24    STA ($24),Y     terminate string with $00
.,B7D7 20 79 00 JSR $0079       scan memory
.,B7DA 20 F3 BC JSR $BCF3       get FAC1 from string
.,B7DD 68       PLA             restore string end byte
.,B7DE A0 00    LDY #$00        clear index
.,B7E0 91 24    STA ($24),Y     put string end byte back

restore BASIC execute pointer from temp

.,B7E2 A6 71    LDX $71         get BASIC execute pointer low byte back
.,B7E4 A4 72    LDY $72         get BASIC execute pointer high byte back
.,B7E6 86 7A    STX $7A         save BASIC execute pointer low byte
.,B7E8 84 7B    STY $7B         save BASIC execute pointer high byte
.,B7EA 60       RTS

get parameters for POKE/WAIT

.,B7EB 20 8A AD JSR $AD8A       evaluate expression and check is numeric, else do
                                type mismatch
.,B7EE 20 F7 B7 JSR $B7F7       convert FAC_1 to integer in temporary integer
.,B7F1 20 FD AE JSR $AEFD       scan for ",", else do syntax error then warm start
.,B7F4 4C 9E B7 JMP $B79E       get byte parameter and return

convert FAC_1 to integer in temporary integer

.,B7F7 A5 66    LDA $66         get FAC1 sign
.,B7F9 30 9D    BMI $B798       if -ve do illegal quantity error then warm start
.,B7FB A5 61    LDA $61         get FAC1 exponent
.,B7FD C9 91    CMP #$91        compare with exponent = 2^16
.,B7FF B0 97    BCS $B798       if >= do illegal quantity error then warm start
.,B801 20 9B BC JSR $BC9B       convert FAC1 floating to fixed
.,B804 A5 64    LDA $64         get FAC1 mantissa 3
.,B806 A4 65    LDY $65         get FAC1 mantissa 4
.,B808 84 14    STY $14         save temporary integer low byte
.,B80A 85 15    STA $15         save temporary integer high byte
.,B80C 60       RTS

perform PEEK()

.,B80D A5 15    LDA $15         get line number high byte
.,B80F 48       PHA             save line number high byte
.,B810 A5 14    LDA $14         get line number low byte
.,B812 48       PHA             save line number low byte
.,B813 20 F7 B7 JSR $B7F7       convert FAC_1 to integer in temporary integer
.,B816 A0 00    LDY #$00        clear index
.,B818 B1 14    LDA ($14),Y     read byte
.,B81A A8       TAY             copy byte to A
.,B81B 68       PLA             pull byte
.,B81C 85 14    STA $14         restore line number low byte
.,B81E 68       PLA             pull byte
.,B81F 85 15    STA $15         restore line number high byte
.,B821 4C A2 B3 JMP $B3A2       convert Y to byte in FAC_1 and return

perform POKE

.,B824 20 EB B7 JSR $B7EB       get parameters for POKE/WAIT
.,B827 8A       TXA             copy byte to A
.,B828 A0 00    LDY #$00        clear index
.,B82A 91 14    STA ($14),Y     write byte
.,B82C 60       RTS

perform WAIT

.,B82D 20 EB B7 JSR $B7EB       get parameters for POKE/WAIT
.,B830 86 49    STX $49         save byte
.,B832 A2 00    LDX #$00        clear mask
.,B834 20 79 00 JSR $0079       scan memory
.,B837 F0 03    BEQ $B83C       skip if no third argument
.,B839 20 F1 B7 JSR $B7F1       scan for "," and get byte, else syntax error then
                                warm start
.,B83C 86 4A    STX $4A         save EOR argument
.,B83E A0 00    LDY #$00        clear index
.,B840 B1 14    LDA ($14),Y     get byte via temporary integer (address)
.,B842 45 4A    EOR $4A         EOR with second argument       (mask)
.,B844 25 49    AND $49         AND with first argument        (byte)
.,B846 F0 F8    BEQ $B840       loop if result is zero
.,B848 60       RTS

add 0.5 to FAC1 (round FAC1)

.,B849 A9 11    LDA #$11        set 0.5 pointer low byte
.,B84B A0 BF    LDY #$BF        set 0.5 pointer high byte
.,B84D 4C 67 B8 JMP $B867       add (AY) to FAC1

perform subtraction, FAC1 from (AY)

.,B850 20 8C BA JSR $BA8C       unpack memory (AY) into FAC2

perform subtraction, FAC1 from FAC2

.,B853 A5 66    LDA $66         get FAC1 sign (b7)
.,B855 49 FF    EOR #$FF        complement it
.,B857 85 66    STA $66         save FAC1 sign (b7)
.,B859 45 6E    EOR $6E         EOR with FAC2 sign (b7)
.,B85B 85 6F    STA $6F         save sign compare (FAC1 EOR FAC2)
.,B85D A5 61    LDA $61         get FAC1 exponent
.,B85F 4C 6A B8 JMP $B86A       add FAC2 to FAC1 and return
.,B862 20 99 B9 JSR $B999       shift FACX A times right (>8 shifts)
.,B865 90 3C    BCC $B8A3       go subtract mantissas

add (AY) to FAC1

.,B867 20 8C BA JSR $BA8C       unpack memory (AY) into FAC2

add FAC2 to FAC1

.,B86A D0 03    BNE $B86F       branch if FAC1 is not zero
.,B86C 4C FC BB JMP $BBFC       FAC1 was zero so copy FAC2 to FAC1 and return
                                FAC1 is non zero
.,B86F A6 70    LDX $70         get FAC1 rounding byte
.,B871 86 56    STX $56         save as FAC2 rounding byte
.,B873 A2 69    LDX #$69        set index to FAC2 exponent address
.,B875 A5 69    LDA $69         get FAC2 exponent
.,B877 A8       TAY             copy exponent
.,B878 F0 CE    BEQ $B848       exit if zero
.,B87A 38       SEC             set carry for subtract
.,B87B E5 61    SBC $61         subtract FAC1 exponent
.,B87D F0 24    BEQ $B8A3       if equal go add mantissas
.,B87F 90 12    BCC $B893       if FAC2 < FAC1 then go shift FAC2 right
                                else FAC2 > FAC1
.,B881 84 61    STY $61         save FAC1 exponent
.,B883 A4 6E    LDY $6E         get FAC2 sign (b7)
.,B885 84 66    STY $66         save FAC1 sign (b7)
.,B887 49 FF    EOR #$FF        complement A
.,B889 69 00    ADC #$00        +1, twos complement, carry is set
.,B88B A0 00    LDY #$00        clear Y
.,B88D 84 56    STY $56         clear FAC2 rounding byte
.,B88F A2 61    LDX #$61        set index to FAC1 exponent address
.,B891 D0 04    BNE $B897       branch always
                                FAC2 < FAC1
.,B893 A0 00    LDY #$00        clear Y
.,B895 84 70    STY $70         clear FAC1 rounding byte
.,B897 C9 F9    CMP #$F9        compare exponent diff with $F9
.,B899 30 C7    BMI $B862       branch if range $79-$F8
.,B89B A8       TAY             copy exponent difference to Y
.,B89C A5 70    LDA $70         get FAC1 rounding byte
.,B89E 56 01    LSR $01,X       shift FAC? mantissa 1
.,B8A0 20 B0 B9 JSR $B9B0       shift FACX Y times right
                                exponents are equal now do mantissa subtract
.,B8A3 24 6F    BIT $6F         test sign compare (FAC1 EOR FAC2)
.,B8A5 10 57    BPL $B8FE       if = add FAC2 mantissa to FAC1 mantissa and return
.,B8A7 A0 61    LDY #$61        set the Y index to FAC1 exponent address
.,B8A9 E0 69    CPX #$69        compare X to FAC2 exponent address
.,B8AB F0 02    BEQ $B8AF       if = continue, Y = FAC1, X = FAC2
.,B8AD A0 69    LDY #$69        else set the Y index to FAC2 exponent address
                                subtract the smaller from the bigger (take the sign of
                                the bigger)
.,B8AF 38       SEC             set carry for subtract
.,B8B0 49 FF    EOR #$FF        ones complement A
.,B8B2 65 56    ADC $56         add FAC2 rounding byte
.,B8B4 85 70    STA $70         save FAC1 rounding byte
.,B8B6 B9 04 00 LDA $0004,Y     get FACY mantissa 4
.,B8B9 F5 04    SBC $04,X       subtract FACX mantissa 4
.,B8BB 85 65    STA $65         save FAC1 mantissa 4
.,B8BD B9 03 00 LDA $0003,Y     get FACY mantissa 3
.,B8C0 F5 03    SBC $03,X       subtract FACX mantissa 3
.,B8C2 85 64    STA $64         save FAC1 mantissa 3
.,B8C4 B9 02 00 LDA $0002,Y     get FACY mantissa 2
.,B8C7 F5 02    SBC $02,X       subtract FACX mantissa 2
.,B8C9 85 63    STA $63         save FAC1 mantissa 2
.,B8CB B9 01 00 LDA $0001,Y     get FACY mantissa 1
.,B8CE F5 01    SBC $01,X       subtract FACX mantissa 1
.,B8D0 85 62    STA $62         save FAC1 mantissa 1

do ABS and normalise FAC1

.,B8D2 B0 03    BCS $B8D7       branch if number is +ve
.,B8D4 20 47 B9 JSR $B947       negate FAC1

normalise FAC1

.,B8D7 A0 00    LDY #$00        clear Y
.,B8D9 98       TYA             clear A
.,B8DA 18       CLC             clear carry for add
.,B8DB A6 62    LDX $62         get FAC1 mantissa 1
.,B8DD D0 4A    BNE $B929       if not zero normalise FAC1
.,B8DF A6 63    LDX $63         get FAC1 mantissa 2
.,B8E1 86 62    STX $62         save FAC1 mantissa 1
.,B8E3 A6 64    LDX $64         get FAC1 mantissa 3
.,B8E5 86 63    STX $63         save FAC1 mantissa 2
.,B8E7 A6 65    LDX $65         get FAC1 mantissa 4
.,B8E9 86 64    STX $64         save FAC1 mantissa 3
.,B8EB A6 70    LDX $70         get FAC1 rounding byte
.,B8ED 86 65    STX $65         save FAC1 mantissa 4
.,B8EF 84 70    STY $70         clear FAC1 rounding byte
.,B8F1 69 08    ADC #$08        add x to exponent offset
.,B8F3 C9 20    CMP #$20        compare with $20, max offset, all bits would be = 0
.,B8F5 D0 E4    BNE $B8DB       loop if not max

clear FAC1 exponent and sign

.,B8F7 A9 00    LDA #$00        clear A
.,B8F9 85 61    STA $61         set FAC1 exponent

save FAC1 sign

.,B8FB 85 66    STA $66         save FAC1 sign (b7)
.,B8FD 60       RTS

add FAC2 mantissa to FAC1 mantissa

.,B8FE 65 56    ADC $56         add FAC2 rounding byte
.,B900 85 70    STA $70         save FAC1 rounding byte
.,B902 A5 65    LDA $65         get FAC1 mantissa 4
.,B904 65 6D    ADC $6D         add FAC2 mantissa 4
.,B906 85 65    STA $65         save FAC1 mantissa 4
.,B908 A5 64    LDA $64         get FAC1 mantissa 3
.,B90A 65 6C    ADC $6C         add FAC2 mantissa 3
.,B90C 85 64    STA $64         save FAC1 mantissa 3
.,B90E A5 63    LDA $63         get FAC1 mantissa 2
.,B910 65 6B    ADC $6B         add FAC2 mantissa 2
.,B912 85 63    STA $63         save FAC1 mantissa 2
.,B914 A5 62    LDA $62         get FAC1 mantissa 1
.,B916 65 6A    ADC $6A         add FAC2 mantissa 1
.,B918 85 62    STA $62         save FAC1 mantissa 1
.,B91A 4C 36 B9 JMP $B936       test and normalise FAC1 for C=0/1
.,B91D 69 01    ADC #$01        add 1 to exponent offset
.,B91F 06 70    ASL $70         shift FAC1 rounding byte
.,B921 26 65    ROL $65         shift FAC1 mantissa 4
.,B923 26 64    ROL $64         shift FAC1 mantissa 3
.,B925 26 63    ROL $63         shift FAC1 mantissa 2
.,B927 26 62    ROL $62         shift FAC1 mantissa 1
                                normalise FAC1
.,B929 10 F2    BPL $B91D       loop if not normalised
.,B92B 38       SEC             set carry for subtract
.,B92C E5 61    SBC $61         subtract FAC1 exponent
.,B92E B0 C7    BCS $B8F7       branch if underflow (set result = $0)
.,B930 49 FF    EOR #$FF        complement exponent
.,B932 69 01    ADC #$01        +1 (twos complement)
.,B934 85 61    STA $61         save FAC1 exponent
                                test and normalise FAC1 for C=0/1
.,B936 90 0E    BCC $B946       exit if no overflow
                                normalise FAC1 for C=1
.,B938 E6 61    INC $61         increment FAC1 exponent
.,B93A F0 42    BEQ $B97E       if zero do overflow error then warm start
.,B93C 66 62    ROR $62         shift FAC1 mantissa 1
.,B93E 66 63    ROR $63         shift FAC1 mantissa 2
.,B940 66 64    ROR $64         shift FAC1 mantissa 3
.,B942 66 65    ROR $65         shift FAC1 mantissa 4
.,B944 66 70    ROR $70         shift FAC1 rounding byte
.,B946 60       RTS

negate FAC1

.,B947 A5 66    LDA $66         get FAC1 sign (b7)
.,B949 49 FF    EOR #$FF        complement it
.,B94B 85 66    STA $66         save FAC1 sign (b7)
                                twos complement FAC1 mantissa
.,B94D A5 62    LDA $62         get FAC1 mantissa 1
.,B94F 49 FF    EOR #$FF        complement it
.,B951 85 62    STA $62         save FAC1 mantissa 1
.,B953 A5 63    LDA $63         get FAC1 mantissa 2
.,B955 49 FF    EOR #$FF        complement it
.,B957 85 63    STA $63         save FAC1 mantissa 2
.,B959 A5 64    LDA $64         get FAC1 mantissa 3
.,B95B 49 FF    EOR #$FF        complement it
.,B95D 85 64    STA $64         save FAC1 mantissa 3
.,B95F A5 65    LDA $65         get FAC1 mantissa 4
.,B961 49 FF    EOR #$FF        complement it
.,B963 85 65    STA $65         save FAC1 mantissa 4
.,B965 A5 70    LDA $70         get FAC1 rounding byte
.,B967 49 FF    EOR #$FF        complement it
.,B969 85 70    STA $70         save FAC1 rounding byte
.,B96B E6 70    INC $70         increment FAC1 rounding byte
.,B96D D0 0E    BNE $B97D       exit if no overflow
                                increment FAC1 mantissa
.,B96F E6 65    INC $65         increment FAC1 mantissa 4
.,B971 D0 0A    BNE $B97D       finished if no rollover
.,B973 E6 64    INC $64         increment FAC1 mantissa 3
.,B975 D0 06    BNE $B97D       finished if no rollover
.,B977 E6 63    INC $63         increment FAC1 mantissa 2
.,B979 D0 02    BNE $B97D       finished if no rollover
.,B97B E6 62    INC $62         increment FAC1 mantissa 1
.,B97D 60       RTS

do overflow error then warm start

.,B97E A2 0F    LDX #$0F        error $0F, overflow error
.,B980 4C 37 A4 JMP $A437       do error #X then warm start

shift FCAtemp << A+8 times

.,B983 A2 25    LDX #$25        set the offset to FACtemp
.,B985 B4 04    LDY $04,X       get FACX mantissa 4
.,B987 84 70    STY $70         save as FAC1 rounding byte
.,B989 B4 03    LDY $03,X       get FACX mantissa 3
.,B98B 94 04    STY $04,X       save FACX mantissa 4
.,B98D B4 02    LDY $02,X       get FACX mantissa 2
.,B98F 94 03    STY $03,X       save FACX mantissa 3
.,B991 B4 01    LDY $01,X       get FACX mantissa 1
.,B993 94 02    STY $02,X       save FACX mantissa 2
.,B995 A4 68    LDY $68         get FAC1 overflow byte
.,B997 94 01    STY $01,X       save FACX mantissa 1
                                shift FACX -A times right (> 8 shifts)
.,B999 69 08    ADC #$08        add 8 to shift count
.,B99B 30 E8    BMI $B985       go do 8 shift if still -ve
.,B99D F0 E6    BEQ $B985       go do 8 shift if zero
.,B99F E9 08    SBC #$08        else subtract 8 again
.,B9A1 A8       TAY             save count to Y
.,B9A2 A5 70    LDA $70         get FAC1 rounding byte
.,B9A4 B0 14    BCS $B9BA
.,B9A6 16 01    ASL $01,X       shift FACX mantissa 1
.,B9A8 90 02    BCC $B9AC       branch if +ve
.,B9AA F6 01    INC $01,X       this sets b7 eventually
.,B9AC 76 01    ROR $01,X       shift FACX mantissa 1 (correct for ASL)
.,B9AE 76 01    ROR $01,X       shift FACX mantissa 1 (put carry in b7)
                                shift FACX Y times right
.,B9B0 76 02    ROR $02,X       shift FACX mantissa 2
.,B9B2 76 03    ROR $03,X       shift FACX mantissa 3
.,B9B4 76 04    ROR $04,X       shift FACX mantissa 4
.,B9B6 6A       ROR             shift FACX rounding byte
.,B9B7 C8       INY             increment exponent diff
.,B9B8 D0 EC    BNE $B9A6       branch if range adjust not complete
.,B9BA 18       CLC             just clear it
.,B9BB 60       RTS

constants and series for LOG(n)

.:B9BC 81 00 00 00 00           1
.:B9C1 03                       series counter
.:B9C2 7F 5E 56 CB 79            .434255942
.:B9C7 80 13 9B 0B 64            .576584541
.:B9CC 80 76 38 93 16            .961800759
.:B9D1 82 38 AA 3B 20           2.88539007
.:B9D5 80 35 04 F3 34            .707106781 = 1/SQR(2)
.:B9DB 81 35 04 F3 34           1.41421356 = SQR(2)
.:B9E0 80 80 00 00 00           -.5
.:B9E5 80 31 72 17 F8            .693147181  =  LOG(2)

perform LOG()

.,B9EA 20 2B BC JSR $BC2B       test sign and zero
.,B9ED F0 02    BEQ $B9F1       if zero do illegal quantity error then warm start
.,B9EF 10 03    BPL $B9F4       skip error if +ve
.,B9F1 4C 48 B2 JMP $B248       do illegal quantity error then warm start
.,B9F4 A5 61    LDA $61         get FAC1 exponent
.,B9F6 E9 7F    SBC #$7F        normalise it
.,B9F8 48       PHA             save it
.,B9F9 A9 80    LDA #$80        set exponent to zero
.,B9FB 85 61    STA $61         save FAC1 exponent
.,B9FD A9 D6    LDA #$D6        pointer to 1/root 2 low byte
.,B9FF A0 B9    LDY #$B9        pointer to 1/root 2 high byte
.,BA01 20 67 B8 JSR $B867       add (AY) to FAC1 (1/root2)
.,BA04 A9 DB    LDA #$DB        pointer to root 2 low byte
.,BA06 A0 B9    LDY #$B9        pointer to root 2 high byte
.,BA08 20 0F BB JSR $BB0F       convert AY and do (AY)/FAC1 (root2/(x+(1/root2)))
.,BA0B A9 BC    LDA #$BC        pointer to 1 low byte
.,BA0D A0 B9    LDY #$B9        pointer to 1 high byte
.,BA0F 20 50 B8 JSR $B850       subtract FAC1 ((root2/(x+(1/root2)))-1) from (AY)
.,BA12 A9 C1    LDA #$C1        pointer to series for LOG(n) low byte
.,BA14 A0 B9    LDY #$B9        pointer to series for LOG(n) high byte
.,BA16 20 43 E0 JSR $E043       ^2 then series evaluation
.,BA19 A9 E0    LDA #$E0        pointer to -0.5 low byte
.,BA1B A0 B9    LDY #$B9        pointer to -0.5 high byte
.,BA1D 20 67 B8 JSR $B867       add (AY) to FAC1
.,BA20 68       PLA             restore FAC1 exponent
.,BA21 20 7E BD JSR $BD7E       evaluate new ASCII digit
.,BA24 A9 E5    LDA #$E5        pointer to LOG(2) low byte
.,BA26 A0 B9    LDY #$B9        pointer to LOG(2) high byte

do convert AY, FCA1*(AY)

.,BA28 20 8C BA JSR $BA8C       unpack memory (AY) into FAC2
.,BA2B D0 03    BNE $BA30       multiply FAC1 by FAC2 ??
.,BA2D 4C 8B BA JMP $BA8B       exit if zero
.,BA30 20 B7 BA JSR $BAB7       test and adjust accumulators
.,BA33 A9 00    LDA #$00        clear A
.,BA35 85 26    STA $26         clear temp mantissa 1
.,BA37 85 27    STA $27         clear temp mantissa 2
.,BA39 85 28    STA $28         clear temp mantissa 3
.,BA3B 85 29    STA $29         clear temp mantissa 4
.,BA3D A5 70    LDA $70         get FAC1 rounding byte
.,BA3F 20 59 BA JSR $BA59       go do shift/add FAC2
.,BA42 A5 65    LDA $65         get FAC1 mantissa 4
.,BA44 20 59 BA JSR $BA59       go do shift/add FAC2
.,BA47 A5 64    LDA $64         get FAC1 mantissa 3
.,BA49 20 59 BA JSR $BA59       go do shift/add FAC2
.,BA4C A5 63    LDA $63         get FAC1 mantissa 2
.,BA4E 20 59 BA JSR $BA59       go do shift/add FAC2
.,BA51 A5 62    LDA $62         get FAC1 mantissa 1
.,BA53 20 5E BA JSR $BA5E       go do shift/add FAC2
.,BA56 4C 8F BB JMP $BB8F       copy temp to FAC1, normalise and return
.,BA59 D0 03    BNE $BA5E       branch if byte <> zero
.,BA5B 4C 83 B9 JMP $B983       shift FCAtemp << A+8 times
                                else do shift and add
.,BA5E 4A       LSR             shift byte
.,BA5F 09 80    ORA #$80        set top bit (mark for 8 times)
.,BA61 A8       TAY             copy result
.,BA62 90 19    BCC $BA7D       skip next if bit was zero
.,BA64 18       CLC             clear carry for add
.,BA65 A5 29    LDA $29         get temp mantissa 4
.,BA67 65 6D    ADC $6D         add FAC2 mantissa 4
.,BA69 85 29    STA $29         save temp mantissa 4
.,BA6B A5 28    LDA $28         get temp mantissa 3
.,BA6D 65 6C    ADC $6C         add FAC2 mantissa 3
.,BA6F 85 28    STA $28         save temp mantissa 3
.,BA71 A5 27    LDA $27         get temp mantissa 2
.,BA73 65 6B    ADC $6B         add FAC2 mantissa 2
.,BA75 85 27    STA $27         save temp mantissa 2
.,BA77 A5 26    LDA $26         get temp mantissa 1
.,BA79 65 6A    ADC $6A         add FAC2 mantissa 1
.,BA7B 85 26    STA $26         save temp mantissa 1
.,BA7D 66 26    ROR $26         shift temp mantissa 1
.,BA7F 66 27    ROR $27         shift temp mantissa 2
.,BA81 66 28    ROR $28         shift temp mantissa 3
.,BA83 66 29    ROR $29         shift temp mantissa 4
.,BA85 66 70    ROR $70         shift temp rounding byte
.,BA87 98       TYA             get byte back
.,BA88 4A       LSR             shift byte
.,BA89 D0 D6    BNE $BA61       loop if all bits not done
.,BA8B 60       RTS

unpack memory (AY) into FAC2

.,BA8C 85 22    STA $22         save pointer low byte
.,BA8E 84 23    STY $23         save pointer high byte
.,BA90 A0 04    LDY #$04        5 bytes to get (0-4)
.,BA92 B1 22    LDA ($22),Y     get mantissa 4
.,BA94 85 6D    STA $6D         save FAC2 mantissa 4
.,BA96 88       DEY             decrement index
.,BA97 B1 22    LDA ($22),Y     get mantissa 3
.,BA99 85 6C    STA $6C         save FAC2 mantissa 3
.,BA9B 88       DEY             decrement index
.,BA9C B1 22    LDA ($22),Y     get mantissa 2
.,BA9E 85 6B    STA $6B         save FAC2 mantissa 2
.,BAA0 88       DEY             decrement index
.,BAA1 B1 22    LDA ($22),Y     get mantissa 1 + sign
.,BAA3 85 6E    STA $6E         save FAC2 sign (b7)
.,BAA5 45 66    EOR $66         EOR with FAC1 sign (b7)
.,BAA7 85 6F    STA $6F         save sign compare (FAC1 EOR FAC2)
.,BAA9 A5 6E    LDA $6E         recover FAC2 sign (b7)
.,BAAB 09 80    ORA #$80        set 1xxx xxx (set normal bit)
.,BAAD 85 6A    STA $6A         save FAC2 mantissa 1
.,BAAF 88       DEY             decrement index
.,BAB0 B1 22    LDA ($22),Y     get exponent byte
.,BAB2 85 69    STA $69         save FAC2 exponent
.,BAB4 A5 61    LDA $61         get FAC1 exponent
.,BAB6 60       RTS

test and adjust accumulators

.,BAB7 A5 69    LDA $69         get FAC2 exponent
.,BAB9 F0 1F    BEQ $BADA       branch if FAC2 = $00 (handle underflow)
.,BABB 18       CLC             clear carry for add
.,BABC 65 61    ADC $61         add FAC1 exponent
.,BABE 90 04    BCC $BAC4       branch if sum of exponents < $0100
.,BAC0 30 1D    BMI $BADF       do overflow error
.,BAC2 18       CLC             clear carry for the add
.:BAC3 2C       .BYTE $2C       makes next line BIT $1410
.,BAC4 10 14    BPL $BADA       if +ve go handle underflow
.,BAC6 69 80    ADC #$80        adjust exponent
.,BAC8 85 61    STA $61         save FAC1 exponent
.,BACA D0 03    BNE $BACF       branch if not zero
.,BACC 4C FB B8 JMP $B8FB       save FAC1 sign and return
.,BACF A5 6F    LDA $6F         get sign compare (FAC1 EOR FAC2)
.,BAD1 85 66    STA $66         save FAC1 sign (b7)
.,BAD3 60       RTS
                                handle overflow and underflow
.,BAD4 A5 66    LDA $66         get FAC1 sign (b7)
.,BAD6 49 FF    EOR #$FF        complement it
.,BAD8 30 05    BMI $BADF       do overflow error
                                handle underflow
.,BADA 68       PLA             pop return address low byte
.,BADB 68       PLA             pop return address high byte
.,BADC 4C F7 B8 JMP $B8F7       clear FAC1 exponent and sign and return
.,BADF 4C 7E B9 JMP $B97E       do overflow error then warm start

multiply FAC1 by 10

.,BAE2 20 0C BC JSR $BC0C       round and copy FAC1 to FAC2
.,BAE5 AA       TAX             copy exponent (set the flags)
.,BAE6 F0 10    BEQ $BAF8       exit if zero
.,BAE8 18       CLC             clear carry for add
.,BAE9 69 02    ADC #$02        add two to exponent (*4)
.,BAEB B0 F2    BCS $BADF       do overflow error if > $FF
                                FAC1 = (FAC1 + FAC2) * 2
.,BAED A2 00    LDX #$00        clear byte
.,BAEF 86 6F    STX $6F         clear sign compare (FAC1 EOR FAC2)
.,BAF1 20 77 B8 JSR $B877       add FAC2 to FAC1 (*5)
.,BAF4 E6 61    INC $61         increment FAC1 exponent (*10)
.,BAF6 F0 E7    BEQ $BADF       if exponent now zero go do overflow error
.,BAF8 60       RTS

10 as a floating value

.:BAF9 84 20 00 00 00           10

divide FAC1 by 10

.,BAFE 20 0C BC JSR $BC0C       round and copy FAC1 to FAC2
.,BB01 A9 F9    LDA #$F9        set 10 pointer low byte
.,BB03 A0 BA    LDY #$BA        set 10 pointer high byte
.,BB05 A2 00    LDX #$00        clear sign

divide by (AY) (X=sign)

.,BB07 86 6F    STX $6F         save sign compare (FAC1 EOR FAC2)
.,BB09 20 A2 BB JSR $BBA2       unpack memory (AY) into FAC1
.,BB0C 4C 12 BB JMP $BB12       do FAC2/FAC1
                                Perform divide-by

convert AY and do (AY)/FAC1

.,BB0F 20 8C BA JSR $BA8C       unpack memory (AY) into FAC2
.,BB12 F0 76    BEQ $BB8A       if zero go do /0 error
.,BB14 20 1B BC JSR $BC1B       round FAC1
.,BB17 A9 00    LDA #$00        clear A
.,BB19 38       SEC             set carry for subtract
.,BB1A E5 61    SBC $61         subtract FAC1 exponent (2s complement)
.,BB1C 85 61    STA $61         save FAC1 exponent
.,BB1E 20 B7 BA JSR $BAB7       test and adjust accumulators
.,BB21 E6 61    INC $61         increment FAC1 exponent
.,BB23 F0 BA    BEQ $BADF       if zero do overflow error
.,BB25 A2 FC    LDX #$FC        set index to FAC temp
.,BB27 A9 01    LDA #$01        set byte
.,BB29 A4 6A    LDY $6A         get FAC2 mantissa 1
.,BB2B C4 62    CPY $62         compare FAC1 mantissa 1
.,BB2D D0 10    BNE $BB3F       branch if <>
.,BB2F A4 6B    LDY $6B         get FAC2 mantissa 2
.,BB31 C4 63    CPY $63         compare FAC1 mantissa 2
.,BB33 D0 0A    BNE $BB3F       branch if <>
.,BB35 A4 6C    LDY $6C         get FAC2 mantissa 3
.,BB37 C4 64    CPY $64         compare FAC1 mantissa 3
.,BB39 D0 04    BNE $BB3F       branch if <>
.,BB3B A4 6D    LDY $6D         get FAC2 mantissa 4
.,BB3D C4 65    CPY $65         compare FAC1 mantissa 4
.,BB3F 08       PHP             save FAC2-FAC1 compare status
.,BB40 2A       ROL             shift byte
.,BB41 90 09    BCC $BB4C       skip next if no carry
.,BB43 E8       INX             increment index to FAC temp
.,BB44 95 29    STA $29,X
.,BB46 F0 32    BEQ $BB7A
.,BB48 10 34    BPL $BB7E
.,BB4A A9 01    LDA #$01
.,BB4C 28       PLP             restore FAC2-FAC1 compare status
.,BB4D B0 0E    BCS $BB5D       if FAC2 >= FAC1 then do subtract
                                FAC2 = FAC2*2
.,BB4F 06 6D    ASL $6D         shift FAC2 mantissa 4
.,BB51 26 6C    ROL $6C         shift FAC2 mantissa 3
.,BB53 26 6B    ROL $6B         shift FAC2 mantissa 2
.,BB55 26 6A    ROL $6A         shift FAC2 mantissa 1
.,BB57 B0 E6    BCS $BB3F       loop with no compare
.,BB59 30 CE    BMI $BB29       loop with compare
.,BB5B 10 E2    BPL $BB3F       loop with no compare, branch always
.,BB5D A8       TAY             save FAC2-FAC1 compare status
.,BB5E A5 6D    LDA $6D         get FAC2 mantissa 4
.,BB60 E5 65    SBC $65         subtract FAC1 mantissa 4
.,BB62 85 6D    STA $6D         save FAC2 mantissa 4
.,BB64 A5 6C    LDA $6C         get FAC2 mantissa 3
.,BB66 E5 64    SBC $64         subtract FAC1 mantissa 3
.,BB68 85 6C    STA $6C         save FAC2 mantissa 3
.,BB6A A5 6B    LDA $6B         get FAC2 mantissa 2
.,BB6C E5 63    SBC $63         subtract FAC1 mantissa 2
.,BB6E 85 6B    STA $6B         save FAC2 mantissa 2
.,BB70 A5 6A    LDA $6A         get FAC2 mantissa 1
.,BB72 E5 62    SBC $62         subtract FAC1 mantissa 1
.,BB74 85 6A    STA $6A         save FAC2 mantissa 1
.,BB76 98       TYA             restore FAC2-FAC1 compare status
.,BB77 4C 4F BB JMP $BB4F
.,BB7A A9 40    LDA #$40
.,BB7C D0 CE    BNE $BB4C       branch always
                                do A<<6, save as FAC1 rounding byte, normalise and return
.,BB7E 0A       ASL
.,BB7F 0A       ASL
.,BB80 0A       ASL
.,BB81 0A       ASL
.,BB82 0A       ASL
.,BB83 0A       ASL
.,BB84 85 70    STA $70         save FAC1 rounding byte
.,BB86 28       PLP             dump FAC2-FAC1 compare status
.,BB87 4C 8F BB JMP $BB8F       copy temp to FAC1, normalise and return
                                do "Divide by zero" error
.,BB8A A2 14    LDX #$14        error $14, divide by zero error
.,BB8C 4C 37 A4 JMP $A437       do error #X then warm start
.,BB8F A5 26    LDA $26         get temp mantissa 1
.,BB91 85 62    STA $62         save FAC1 mantissa 1
.,BB93 A5 27    LDA $27         get temp mantissa 2
.,BB95 85 63    STA $63         save FAC1 mantissa 2
.,BB97 A5 28    LDA $28         get temp mantissa 3
.,BB99 85 64    STA $64         save FAC1 mantissa 3
.,BB9B A5 29    LDA $29         get temp mantissa 4
.,BB9D 85 65    STA $65         save FAC1 mantissa 4
.,BB9F 4C D7 B8 JMP $B8D7       normalise FAC1 and return

unpack memory (AY) into FAC1

.,BBA2 85 22    STA $22         save pointer low byte
.,BBA4 84 23    STY $23         save pointer high byte
.,BBA6 A0 04    LDY #$04        5 bytes to do
.,BBA8 B1 22    LDA ($22),Y     get fifth byte
.,BBAA 85 65    STA $65         save FAC1 mantissa 4
.,BBAC 88       DEY             decrement index
.,BBAD B1 22    LDA ($22),Y     get fourth byte
.,BBAF 85 64    STA $64         save FAC1 mantissa 3
.,BBB1 88       DEY             decrement index
.,BBB2 B1 22    LDA ($22),Y     get third byte
.,BBB4 85 63    STA $63         save FAC1 mantissa 2
.,BBB6 88       DEY             decrement index
.,BBB7 B1 22    LDA ($22),Y     get second byte
.,BBB9 85 66    STA $66         save FAC1 sign (b7)
.,BBBB 09 80    ORA #$80        set 1xxx xxxx (add normal bit)
.,BBBD 85 62    STA $62         save FAC1 mantissa 1
.,BBBF 88       DEY             decrement index
.,BBC0 B1 22    LDA ($22),Y     get first byte (exponent)
.,BBC2 85 61    STA $61         save FAC1 exponent
.,BBC4 84 70    STY $70         clear FAC1 rounding byte
.,BBC6 60       RTS

pack FAC1 into $5C

.,BBC7 A2 5C    LDX #$5C        set pointer low byte
.:BBC9 2C       .BYTE $2C       makes next line BIT $57A2

pack FAC1 into $57

.,BBCA A2 57    LDX #$57        set pointer low byte
.,BBCC A0 00    LDY #$00        set pointer high byte
.,BBCE F0 04    BEQ $BBD4       pack FAC1 into (XY) and return, branch always

pack FAC1 into variable pointer

.,BBD0 A6 49    LDX $49         get destination pointer low byte
.,BBD2 A4 4A    LDY $4A         get destination pointer high byte

pack FAC1 into (XY)

.,BBD4 20 1B BC JSR $BC1B       round FAC1
.,BBD7 86 22    STX $22         save pointer low byte
.,BBD9 84 23    STY $23         save pointer high byte
.,BBDB A0 04    LDY #$04        set index
.,BBDD A5 65    LDA $65         get FAC1 mantissa 4
.,BBDF 91 22    STA ($22),Y     store in destination
.,BBE1 88       DEY             decrement index
.,BBE2 A5 64    LDA $64         get FAC1 mantissa 3
.,BBE4 91 22    STA ($22),Y     store in destination
.,BBE6 88       DEY             decrement index
.,BBE7 A5 63    LDA $63         get FAC1 mantissa 2
.,BBE9 91 22    STA ($22),Y     store in destination
.,BBEB 88       DEY             decrement index
.,BBEC A5 66    LDA $66         get FAC1 sign (b7)
.,BBEE 09 7F    ORA #$7F        set bits x111 1111
.,BBF0 25 62    AND $62         AND in FAC1 mantissa 1
.,BBF2 91 22    STA ($22),Y     store in destination
.,BBF4 88       DEY             decrement index
.,BBF5 A5 61    LDA $61         get FAC1 exponent
.,BBF7 91 22    STA ($22),Y     store in destination
.,BBF9 84 70    STY $70         clear FAC1 rounding byte
.,BBFB 60       RTS

copy FAC2 to FAC1

.,BBFC A5 6E    LDA $6E         get FAC2 sign (b7)
                                save FAC1 sign and copy ABS(FAC2) to FAC1
.,BBFE 85 66    STA $66         save FAC1 sign (b7)
.,BC00 A2 05    LDX #$05        5 bytes to copy
.,BC02 B5 68    LDA $68,X       get byte from FAC2,X
.,BC04 95 60    STA $60,X       save byte at FAC1,X
.,BC06 CA       DEX             decrement count
.,BC07 D0 F9    BNE $BC02       loop if not all done
.,BC09 86 70    STX $70         clear FAC1 rounding byte
.,BC0B 60       RTS

round and copy FAC1 to FAC2

.,BC0C 20 1B BC JSR $BC1B       round FAC1
                                copy FAC1 to FAC2
.,BC0F A2 06    LDX #$06        6 bytes to copy
.,BC11 B5 60    LDA $60,X       get byte from FAC1,X
.,BC13 95 68    STA $68,X       save byte at FAC2,X
.,BC15 CA       DEX             decrement count
.,BC16 D0 F9    BNE $BC11       loop if not all done
.,BC18 86 70    STX $70         clear FAC1 rounding byte
.,BC1A 60       RTS

round FAC1

.,BC1B A5 61    LDA $61         get FAC1 exponent
.,BC1D F0 FB    BEQ $BC1A       exit if zero
.,BC1F 06 70    ASL $70         shift FAC1 rounding byte
.,BC21 90 F7    BCC $BC1A       exit if no overflow
                                round FAC1 (no check)
.,BC23 20 6F B9 JSR $B96F       increment FAC1 mantissa
.,BC26 D0 F2    BNE $BC1A       branch if no overflow
.,BC28 4C 38 B9 JMP $B938       nornalise FAC1 for C=1 and return

get FAC1 sign

                                return A = $FF, Cb = 1/-ve A = $01, Cb = 0/+ve, A = $00, Cb = ?/0
.,BC2B A5 61    LDA $61         get FAC1 exponent
.,BC2D F0 09    BEQ $BC38       exit if zero (allready correct SGN(0)=0)

return A = $FF, Cb = 1/-ve A = $01, Cb = 0/+ve

                                no = 0 check
.,BC2F A5 66    LDA $66         else get FAC1 sign (b7)

return A = $FF, Cb = 1/-ve A = $01, Cb = 0/+ve

                                no = 0 check, sign in A
.,BC31 2A       ROL             move sign bit to carry
.,BC32 A9 FF    LDA #$FF        set byte for -ve result
.,BC34 B0 02    BCS $BC38       return if sign was set (-ve)
.,BC36 A9 01    LDA #$01        else set byte for +ve result
.,BC38 60       RTS

perform SGN()

.,BC39 20 2B BC JSR $BC2B       get FAC1 sign, return A = $FF -ve, A = $01 +ve

save A as integer byte

.,BC3C 85 62    STA $62         save FAC1 mantissa 1
.,BC3E A9 00    LDA #$00        clear A
.,BC40 85 63    STA $63         clear FAC1 mantissa 2
.,BC42 A2 88    LDX #$88        set exponent
                                set exponent = X, clear FAC1 3 and 4 and normalise
.,BC44 A5 62    LDA $62         get FAC1 mantissa 1
.,BC46 49 FF    EOR #$FF        complement it
.,BC48 2A       ROL             sign bit into carry
                                set exponent = X, clear mantissa 4 and 3 and normalise FAC1
.,BC49 A9 00    LDA #$00        clear A
.,BC4B 85 65    STA $65         clear FAC1 mantissa 4
.,BC4D 85 64    STA $64         clear FAC1 mantissa 3
                                set exponent = X and normalise FAC1
.,BC4F 86 61    STX $61         set FAC1 exponent
.,BC51 85 70    STA $70         clear FAC1 rounding byte
.,BC53 85 66    STA $66         clear FAC1 sign (b7)
.,BC55 4C D2 B8 JMP $B8D2       do ABS and normalise FAC1

perform ABS()

.,BC58 46 66    LSR $66         clear FAC1 sign, put zero in b7
.,BC5A 60       RTS

compare FAC1 with (AY)

                                returns A=$00 if FAC1 = (AY)
                                returns A=$01 if FAC1 > (AY)
                                returns A=$FF if FAC1 < (AY)
.,BC5B 85 24    STA $24         save pointer low byte
.,BC5D 84 25    STY $25         save pointer high byte
.,BC5F A0 00    LDY #$00        clear index
.,BC61 B1 24    LDA ($24),Y     get exponent
.,BC63 C8       INY             increment index
.,BC64 AA       TAX             copy (AY) exponent to X
.,BC65 F0 C4    BEQ $BC2B       branch if (AY) exponent=0 and get FAC1 sign
                                A = $FF, Cb = 1/-ve A = $01, Cb = 0/+ve
.,BC67 B1 24    LDA ($24),Y     get (AY) mantissa 1, with sign
.,BC69 45 66    EOR $66         EOR FAC1 sign (b7)
.,BC6B 30 C2    BMI $BC2F       if signs <> do return A = $FF, Cb = 1/-ve
                                A = $01, Cb = 0/+ve and return
.,BC6D E4 61    CPX $61         compare (AY) exponent with FAC1 exponent
.,BC6F D0 21    BNE $BC92       branch if different
.,BC71 B1 24    LDA ($24),Y     get (AY) mantissa 1, with sign
.,BC73 09 80    ORA #$80        normalise top bit
.,BC75 C5 62    CMP $62         compare with FAC1 mantissa 1
.,BC77 D0 19    BNE $BC92       branch if different
.,BC79 C8       INY             increment index
.,BC7A B1 24    LDA ($24),Y     get mantissa 2
.,BC7C C5 63    CMP $63         compare with FAC1 mantissa 2
.,BC7E D0 12    BNE $BC92       branch if different
.,BC80 C8       INY             increment index
.,BC81 B1 24    LDA ($24),Y     get mantissa 3
.,BC83 C5 64    CMP $64         compare with FAC1 mantissa 3
.,BC85 D0 0B    BNE $BC92       branch if different
.,BC87 C8       INY             increment index
.,BC88 A9 7F    LDA #$7F        set for 1/2 value rounding byte
.,BC8A C5 70    CMP $70         compare with FAC1 rounding byte (set carry)
.,BC8C B1 24    LDA ($24),Y     get mantissa 4
.,BC8E E5 65    SBC $65         subtract FAC1 mantissa 4
.,BC90 F0 28    BEQ $BCBA       exit if mantissa 4 equal
                                gets here if number <> FAC1
.,BC92 A5 66    LDA $66         get FAC1 sign (b7)
.,BC94 90 02    BCC $BC98       branch if FAC1 > (AY)
.,BC96 49 FF    EOR #$FF        else toggle FAC1 sign
.,BC98 4C 31 BC JMP $BC31       return A = $FF, Cb = 1/-ve A = $01, Cb = 0/+ve

convert FAC1 floating to fixed

.,BC9B A5 61    LDA $61         get FAC1 exponent
.,BC9D F0 4A    BEQ $BCE9       if zero go clear FAC1 and return
.,BC9F 38       SEC             set carry for subtract
.,BCA0 E9 A0    SBC #$A0        subtract maximum integer range exponent
.,BCA2 24 66    BIT $66         test FAC1 sign (b7)
.,BCA4 10 09    BPL $BCAF       branch if FAC1 +ve
                                FAC1 was -ve
.,BCA6 AA       TAX             copy subtracted exponent
.,BCA7 A9 FF    LDA #$FF        overflow for -ve number
.,BCA9 85 68    STA $68         set FAC1 overflow byte
.,BCAB 20 4D B9 JSR $B94D       twos complement FAC1 mantissa
.,BCAE 8A       TXA             restore subtracted exponent
.,BCAF A2 61    LDX #$61        set index to FAC1
.,BCB1 C9 F9    CMP #$F9        compare exponent result
.,BCB3 10 06    BPL $BCBB       if < 8 shifts shift FAC1 A times right and return
.,BCB5 20 99 B9 JSR $B999       shift FAC1 A times right (> 8 shifts)
.,BCB8 84 68    STY $68         clear FAC1 overflow byte
.,BCBA 60       RTS

shift FAC1 A times right

.,BCBB A8       TAY             copy shift count
.,BCBC A5 66    LDA $66         get FAC1 sign (b7)
.,BCBE 29 80    AND #$80        mask sign bit only (x000 0000)
.,BCC0 46 62    LSR $62         shift FAC1 mantissa 1
.,BCC2 05 62    ORA $62         OR sign in b7 FAC1 mantissa 1
.,BCC4 85 62    STA $62         save FAC1 mantissa 1
.,BCC6 20 B0 B9 JSR $B9B0       shift FAC1 Y times right
.,BCC9 84 68    STY $68         clear FAC1 overflow byte
.,BCCB 60       RTS

perform INT()

.,BCCC A5 61    LDA $61         get FAC1 exponent
.,BCCE C9 A0    CMP #$A0        compare with max int
.,BCD0 B0 20    BCS $BCF2       exit if >= (allready int, too big for fractional part!)
.,BCD2 20 9B BC JSR $BC9B       convert FAC1 floating to fixed
.,BCD5 84 70    STY $70         save FAC1 rounding byte
.,BCD7 A5 66    LDA $66         get FAC1 sign (b7)
.,BCD9 84 66    STY $66         save FAC1 sign (b7)
.,BCDB 49 80    EOR #$80        toggle FAC1 sign
.,BCDD 2A       ROL             shift into carry
.,BCDE A9 A0    LDA #$A0        set new exponent
.,BCE0 85 61    STA $61         save FAC1 exponent
.,BCE2 A5 65    LDA $65         get FAC1 mantissa 4
.,BCE4 85 07    STA $07         save FAC1 mantissa 4 for power function
.,BCE6 4C D2 B8 JMP $B8D2       do ABS and normalise FAC1

clear FAC1 and return

.,BCE9 85 62    STA $62         clear FAC1 mantissa 1
.,BCEB 85 63    STA $63         clear FAC1 mantissa 2
.,BCED 85 64    STA $64         clear FAC1 mantissa 3
.,BCEF 85 65    STA $65         clear FAC1 mantissa 4
.,BCF1 A8       TAY             clear Y
.,BCF2 60       RTS

get FAC1 from string

.,BCF3 A0 00    LDY #$00        clear Y
.,BCF5 A2 0A    LDX #$0A        set index
.,BCF7 94 5D    STY $5D,X       clear byte
.,BCF9 CA       DEX             decrement index
.,BCFA 10 FB    BPL $BCF7       loop until numexp to negnum (and FAC1) = $00
.,BCFC 90 0F    BCC $BD0D       branch if first character is numeric
.,BCFE C9 2D    CMP #$2D        else compare with "-"
.,BD00 D0 04    BNE $BD06       branch if not "-"
.,BD02 86 67    STX $67         set flag for -ve n (negnum = $FF)
.,BD04 F0 04    BEQ $BD0A       branch always
.,BD06 C9 2B    CMP #$2B        else compare with "+"
.,BD08 D0 05    BNE $BD0F       branch if not "+"
.,BD0A 20 73 00 JSR $0073       increment and scan memory
.,BD0D 90 5B    BCC $BD6A       branch if numeric character
.,BD0F C9 2E    CMP #$2E        else compare with "."
.,BD11 F0 2E    BEQ $BD41       branch if "."
.,BD13 C9 45    CMP #$45        else compare with "E"
.,BD15 D0 30    BNE $BD47       branch if not "E"
                                was "E" so evaluate exponential part
.,BD17 20 73 00 JSR $0073       increment and scan memory
.,BD1A 90 17    BCC $BD33       branch if numeric character
.,BD1C C9 AB    CMP #$AB        else compare with token for -
.,BD1E F0 0E    BEQ $BD2E       branch if token for -
.,BD20 C9 2D    CMP #$2D        else compare with "-"
.,BD22 F0 0A    BEQ $BD2E       branch if "-"
.,BD24 C9 AA    CMP #$AA        else compare with token for +
.,BD26 F0 08    BEQ $BD30       branch if token for +
.,BD28 C9 2B    CMP #$2B        else compare with "+"
.,BD2A F0 04    BEQ $BD30       branch if "+"
.,BD2C D0 07    BNE $BD35       branch always
.,BD2E 66 60    ROR $60         set exponent -ve flag (C, which=1, into b7)
.,BD30 20 73 00 JSR $0073       increment and scan memory
.,BD33 90 5C    BCC $BD91       branch if numeric character
.,BD35 24 60    BIT $60         test exponent -ve flag
.,BD37 10 0E    BPL $BD47       if +ve go evaluate exponent
                                else do exponent = -exponent
.,BD39 A9 00    LDA #$00        clear result
.,BD3B 38       SEC             set carry for subtract
.,BD3C E5 5E    SBC $5E         subtract exponent byte
.,BD3E 4C 49 BD JMP $BD49       go evaluate exponent
.,BD41 66 5F    ROR $5F         set decimal point flag
.,BD43 24 5F    BIT $5F         test decimal point flag
.,BD45 50 C3    BVC $BD0A       branch if only one decimal point so far
                                evaluate exponent
.,BD47 A5 5E    LDA $5E         get exponent count byte
.,BD49 38       SEC             set carry for subtract
.,BD4A E5 5D    SBC $5D         subtract numerator exponent
.,BD4C 85 5E    STA $5E         save exponent count byte
.,BD4E F0 12    BEQ $BD62       branch if no adjustment
.,BD50 10 09    BPL $BD5B       else if +ve go do FAC1*10^expcnt
                                else go do FAC1/10^(0-expcnt)
.,BD52 20 FE BA JSR $BAFE       divide FAC1 by 10
.,BD55 E6 5E    INC $5E         increment exponent count byte
.,BD57 D0 F9    BNE $BD52       loop until all done
.,BD59 F0 07    BEQ $BD62       branch always
.,BD5B 20 E2 BA JSR $BAE2       multiply FAC1 by 10
.,BD5E C6 5E    DEC $5E         decrement exponent count byte
.,BD60 D0 F9    BNE $BD5B       loop until all done
.,BD62 A5 67    LDA $67         get -ve flag
.,BD64 30 01    BMI $BD67       if -ve do - FAC1 and return
.,BD66 60       RTS

do - FAC1 and return

.,BD67 4C B4 BF JMP $BFB4       do - FAC1
                                do unsigned FAC1*10+number
.,BD6A 48       PHA             save character
.,BD6B 24 5F    BIT $5F         test decimal point flag
.,BD6D 10 02    BPL $BD71       skip exponent increment if not set
.,BD6F E6 5D    INC $5D         else increment number exponent
.,BD71 20 E2 BA JSR $BAE2       multiply FAC1 by 10
.,BD74 68       PLA             restore character
.,BD75 38       SEC             set carry for subtract
.,BD76 E9 30    SBC #$30        convert to binary
.,BD78 20 7E BD JSR $BD7E       evaluate new ASCII digit
.,BD7B 4C 0A BD JMP $BD0A       go do next character
                                evaluate new ASCII digit
                                multiply FAC1 by 10 then (ABS) add in new digit
.,BD7E 48       PHA             save digit
.,BD7F 20 0C BC JSR $BC0C       round and copy FAC1 to FAC2
.,BD82 68       PLA             restore digit
.,BD83 20 3C BC JSR $BC3C       save A as integer byte
.,BD86 A5 6E    LDA $6E         get FAC2 sign (b7)
.,BD88 45 66    EOR $66         toggle with FAC1 sign (b7)
.,BD8A 85 6F    STA $6F         save sign compare (FAC1 EOR FAC2)
.,BD8C A6 61    LDX $61         get FAC1 exponent
.,BD8E 4C 6A B8 JMP $B86A       add FAC2 to FAC1 and return
                                evaluate next character of exponential part of number
.,BD91 A5 5E    LDA $5E         get exponent count byte
.,BD93 C9 0A    CMP #$0A        compare with 10 decimal
.,BD95 90 09    BCC $BDA0       branch if less
.,BD97 A9 64    LDA #$64        make all -ve exponents = -100 decimal (causes underflow)
.,BD99 24 60    BIT $60         test exponent -ve flag
.,BD9B 30 11    BMI $BDAE       branch if -ve
.,BD9D 4C 7E B9 JMP $B97E       else do overflow error then warm start
.,BDA0 0A       ASL             *2
.,BDA1 0A       ASL             *4
.,BDA2 18       CLC             clear carry for add
.,BDA3 65 5E    ADC $5E         *5
.,BDA5 0A       ASL             *10
.,BDA6 18       CLC             clear carry for add
.,BDA7 A0 00    LDY #$00        set index
.,BDA9 71 7A    ADC ($7A),Y     add character (will be $30 too much!)
.,BDAB 38       SEC             set carry for subtract
.,BDAC E9 30    SBC #$30        convert character to binary
.,BDAE 85 5E    STA $5E         save exponent count byte
.,BDB0 4C 30 BD JMP $BD30       go get next character

limits for scientific mode

.:BDB3 9B 3E BC 1F FD           99999999.90625, maximum value with at least one decimal
.:BDB8 9E 6E 6B 27 FD           999999999.25, maximum value before scientific notation
.:BDBD 9E 6E 6B 28 00           1000000000

do " IN " line number message

.,BDC2 A9 71    LDA #$71        set " IN " pointer low byte
.,BDC4 A0 A3    LDY #$A3        set " IN " pointer high byte
.,BDC6 20 DA BD JSR $BDDA       print null terminated string
.,BDC9 A5 3A    LDA $3A         get the current line number high byte
.,BDCB A6 39    LDX $39         get the current line number low byte

print XA as unsigned integer

.,BDCD 85 62    STA $62         save high byte as FAC1 mantissa1
.,BDCF 86 63    STX $63         save low byte as FAC1 mantissa2
.,BDD1 A2 90    LDX #$90        set exponent to 16d bits
.,BDD3 38       SEC             set integer is +ve flag
.,BDD4 20 49 BC JSR $BC49       set exponent = X, clear mantissa 4 and 3 and normalise
                                FAC1
.,BDD7 20 DF BD JSR $BDDF       convert FAC1 to string
.,BDDA 4C 1E AB JMP $AB1E       print null terminated string

convert FAC1 to ASCII string result in (AY)

.,BDDD A0 01    LDY #$01        set index = 1
.,BDDF A9 20    LDA #$20        character = " " (assume +ve)
.,BDE1 24 66    BIT $66         test FAC1 sign (b7)
.,BDE3 10 02    BPL $BDE7       branch if +ve
.,BDE5 A9 2D    LDA #$2D        else character = "-"
.,BDE7 99 FF 00 STA $00FF,Y     save leading character (" " or "-")
.,BDEA 85 66    STA $66         save FAC1 sign (b7)
.,BDEC 84 71    STY $71         save index
.,BDEE C8       INY             increment index
.,BDEF A9 30    LDA #$30        set character = "0"
.,BDF1 A6 61    LDX $61         get FAC1 exponent
.,BDF3 D0 03    BNE $BDF8       branch if FAC1<>0
                                exponent was $00 so FAC1 is 0
.,BDF5 4C 04 BF JMP $BF04       save last character, [EOT] and exit
                                FAC1 is some non zero value
.,BDF8 A9 00    LDA #$00        clear (number exponent count)
.,BDFA E0 80    CPX #$80        compare FAC1 exponent with $80 (<1.00000)
.,BDFC F0 02    BEQ $BE00       branch if 0.5 <= FAC1 < 1.0
.,BDFE B0 09    BCS $BE09       branch if FAC1=>1
.,BE00 A9 BD    LDA #$BD        set 1000000000 pointer low byte
.,BE02 A0 BD    LDY #$BD        set 1000000000 pointer high byte
.,BE04 20 28 BA JSR $BA28       do convert AY, FCA1*(AY)
.,BE07 A9 F7    LDA #$F7        set number exponent count
.,BE09 85 5D    STA $5D         save number exponent count
.,BE0B A9 B8    LDA #$B8        set 999999999.25 pointer low byte (max before sci note)
.,BE0D A0 BD    LDY #$BD        set 999999999.25 pointer high byte
.,BE0F 20 5B BC JSR $BC5B       compare FAC1 with (AY)
.,BE12 F0 1E    BEQ $BE32       exit if FAC1 = (AY)
.,BE14 10 12    BPL $BE28       go do /10 if FAC1 > (AY)
                                FAC1 < (AY)
.,BE16 A9 B3    LDA #$B3        set 99999999.90625 pointer low byte
.,BE18 A0 BD    LDY #$BD        set 99999999.90625 pointer high byte
.,BE1A 20 5B BC JSR $BC5B       compare FAC1 with (AY)
.,BE1D F0 02    BEQ $BE21       branch if FAC1 = (AY) (allow decimal places)
.,BE1F 10 0E    BPL $BE2F       branch if FAC1 > (AY) (no decimal places)
                                FAC1 <= (AY)
.,BE21 20 E2 BA JSR $BAE2       multiply FAC1 by 10
.,BE24 C6 5D    DEC $5D         decrement number exponent count
.,BE26 D0 EE    BNE $BE16       go test again, branch always
.,BE28 20 FE BA JSR $BAFE       divide FAC1 by 10
.,BE2B E6 5D    INC $5D         increment number exponent count
.,BE2D D0 DC    BNE $BE0B       go test again, branch always
                                now we have just the digits to do
.,BE2F 20 49 B8 JSR $B849       add 0.5 to FAC1 (round FAC1)
.,BE32 20 9B BC JSR $BC9B       convert FAC1 floating to fixed
.,BE35 A2 01    LDX #$01        set default digits before dp = 1
.,BE37 A5 5D    LDA $5D         get number exponent count
.,BE39 18       CLC             clear carry for add
.,BE3A 69 0A    ADC #$0A        up to 9 digits before point
.,BE3C 30 09    BMI $BE47       if -ve then 1 digit before dp
.,BE3E C9 0B    CMP #$0B        A>=$0B if n>=1E9
.,BE40 B0 06    BCS $BE48       branch if >= $0B
                                carry is clear
.,BE42 69 FF    ADC #$FF        take 1 from digit count
.,BE44 AA       TAX             copy to X
.,BE45 A9 02    LDA #$02        set exponent adjust
.,BE47 38       SEC             set carry for subtract
.,BE48 E9 02    SBC #$02        -2
.,BE4A 85 5E    STA $5E         save exponent adjust
.,BE4C 86 5D    STX $5D         save digits before dp count
.,BE4E 8A       TXA             copy to A
.,BE4F F0 02    BEQ $BE53       branch if no digits before dp
.,BE51 10 13    BPL $BE66       branch if digits before dp
.,BE53 A4 71    LDY $71         get output string index
.,BE55 A9 2E    LDA #$2E        character "."
.,BE57 C8       INY             increment index
.,BE58 99 FF 00 STA $00FF,Y     save to output string
.,BE5B 8A       TXA
.,BE5C F0 06    BEQ $BE64
.,BE5E A9 30    LDA #$30        character "0"
.,BE60 C8       INY             increment index
.,BE61 99 FF 00 STA $00FF,Y     save to output string
.,BE64 84 71    STY $71         save output string index
.,BE66 A0 00    LDY #$00        clear index (point to 100,000)
.,BE68 A2 80    LDX #$80
.,BE6A A5 65    LDA $65         get FAC1 mantissa 4
.,BE6C 18       CLC             clear carry for add
.,BE6D 79 19 BF ADC $BF19,Y     add byte 4, least significant
.,BE70 85 65    STA $65         save FAC1 mantissa4
.,BE72 A5 64    LDA $64         get FAC1 mantissa 3
.,BE74 79 18 BF ADC $BF18,Y     add byte 3
.,BE77 85 64    STA $64         save FAC1 mantissa3
.,BE79 A5 63    LDA $63         get FAC1 mantissa 2
.,BE7B 79 17 BF ADC $BF17,Y     add byte 2
.,BE7E 85 63    STA $63         save FAC1 mantissa2
.,BE80 A5 62    LDA $62         get FAC1 mantissa 1
.,BE82 79 16 BF ADC $BF16,Y     add byte 1, most significant
.,BE85 85 62    STA $62         save FAC1 mantissa1
.,BE87 E8       INX             increment the digit, set the sign on the test sense bit
.,BE88 B0 04    BCS $BE8E       if the carry is set go test if the result was positive
                                else the result needs to be negative
.,BE8A 10 DE    BPL $BE6A       not -ve so try again
.,BE8C 30 02    BMI $BE90       else done so return the digit
.,BE8E 30 DA    BMI $BE6A       not +ve so try again
                                else done so return the digit
.,BE90 8A       TXA             copy the digit
.,BE91 90 04    BCC $BE97       if Cb=0 just use it
.,BE93 49 FF    EOR #$FF        else make the 2's complement ..
.,BE95 69 0A    ADC #$0A        .. and subtract it from 10
.,BE97 69 2F    ADC #$2F        add "0"-1 to result
.,BE99 C8       INY             increment ..
.,BE9A C8       INY             .. index to..
.,BE9B C8       INY             .. next less ..
.,BE9C C8       INY             .. power of ten
.,BE9D 84 47    STY $47         save current variable pointer low byte
.,BE9F A4 71    LDY $71         get output string index
.,BEA1 C8       INY             increment output string index
.,BEA2 AA       TAX             copy character to X
.,BEA3 29 7F    AND #$7F        mask out top bit
.,BEA5 99 FF 00 STA $00FF,Y     save to output string
.,BEA8 C6 5D    DEC $5D         decrement # of characters before the dp
.,BEAA D0 06    BNE $BEB2       branch if still characters to do
                                else output the point
.,BEAC A9 2E    LDA #$2E        character "."
.,BEAE C8       INY             increment output string index
.,BEAF 99 FF 00 STA $00FF,Y     save to output string
.,BEB2 84 71    STY $71         save output string index
.,BEB4 A4 47    LDY $47         get current variable pointer low byte
.,BEB6 8A       TXA             get character back
.,BEB7 49 FF    EOR #$FF        toggle the test sense bit
.,BEB9 29 80    AND #$80        clear the digit
.,BEBB AA       TAX             copy it to the new digit
.,BEBC C0 24    CPY #$24
                                compare the table index with the max for decimal numbers
.,BEBE F0 04    BEQ $BEC4       if at the max exit the digit loop
.,BEC0 C0 3C    CPY #$3C
                                compare the table index with the max for time
.,BEC2 D0 A6    BNE $BE6A       loop if not at the max
                                now remove trailing zeroes
.,BEC4 A4 71    LDY $71         restore the output string index
.,BEC6 B9 FF 00 LDA $00FF,Y     get character from output string
.,BEC9 88       DEY             decrement output string index
.,BECA C9 30    CMP #$30        compare with "0"
.,BECC F0 F8    BEQ $BEC6       loop until non "0" character found
.,BECE C9 2E    CMP #$2E        compare with "."
.,BED0 F0 01    BEQ $BED3       branch if was dp
                                restore last character
.,BED2 C8       INY             increment output string index
.,BED3 A9 2B    LDA #$2B        character "+"
.,BED5 A6 5E    LDX $5E         get exponent count
.,BED7 F0 2E    BEQ $BF07       if zero go set null terminator and exit
                                exponent isn't zero so write exponent
.,BED9 10 08    BPL $BEE3       branch if exponent count +ve
.,BEDB A9 00    LDA #$00        clear A
.,BEDD 38       SEC             set carry for subtract
.,BEDE E5 5E    SBC $5E         subtract exponent count adjust (convert -ve to +ve)
.,BEE0 AA       TAX             copy exponent count to X
.,BEE1 A9 2D    LDA #$2D        character "-"
.,BEE3 99 01 01 STA $0101,Y     save to output string
.,BEE6 A9 45    LDA #$45        character "E"
.,BEE8 99 00 01 STA $0100,Y     save exponent sign to output string
.,BEEB 8A       TXA             get exponent count back
.,BEEC A2 2F    LDX #$2F        one less than "0" character
.,BEEE 38       SEC             set carry for subtract
.,BEEF E8       INX             increment 10's character
.,BEF0 E9 0A    SBC #$0A        subtract 10 from exponent count
.,BEF2 B0 FB    BCS $BEEF       loop while still >= 0
.,BEF4 69 3A    ADC #$3A        add character ":" ($30+$0A, result is 10 less that value)
.,BEF6 99 03 01 STA $0103,Y     save to output string
.,BEF9 8A       TXA             copy 10's character
.,BEFA 99 02 01 STA $0102,Y     save to output string
.,BEFD A9 00    LDA #$00        set null terminator
.,BEFF 99 04 01 STA $0104,Y     save to output string
.,BF02 F0 08    BEQ $BF0C       go set string pointer (AY) and exit, branch always
                                save last character, [EOT] and exit
.,BF04 99 FF 00 STA $00FF,Y     save last character to output string
                                set null terminator and exit
.,BF07 A9 00    LDA #$00        set null terminator
.,BF09 99 00 01 STA $0100,Y     save after last character
                                set string pointer (AY) and exit
.,BF0C A9 00    LDA #$00        set result string pointer low byte
.,BF0E A0 01    LDY #$01        set result string pointer high byte
.,BF10 60       RTS

constants

.:BF11 80 00                    0.5, first two bytes
.:BF13 00 00 00                 null return for undefined variables
.:BF16 FA 0A 1F 00              -100 000 000
.:BF1A 00 98 96 80               +10 000 000
.:BF1E FF F0 BD C0                -1 000 000
.:BF22 00 01 86 A0                  +100 000
.:BF26 FF FF D8 F0                   -10 000
.:BF2A 00 00 03 E8                    +1 000
.:BF2E FF FF FF 9C                     - 100
.:BF32 00 00 00 0A                       +10
.:BF36 FF FF FF FF                        -1

jiffy counts

.:BF3A FF DF 0A 80              -2160000    10s hours
.:BF3E 00 03 4B C0               +216000        hours
.:BF42 FF FF 73 60                -36000    10s mins
.:BF46 00 00 0E 10                 +3600        mins
.:BF4A FF FF FD A8                  -600    10s secs
.:BF4E 00 00 00 3C                   +60        secs

not referenced

.:BF52 EC                       checksum byte

spare bytes, not referenced

.:BF53 AA AA AA AA AA
.:BF58 AA AA AA AA AA AA AA AA
.:BF60 AA AA AA AA AA AA AA AA
.:BF68 AA AA AA AA AA AA AA AA
.:BF70 AA

perform SQR()

.,BF71 20 0C BC JSR $BC0C       round and copy FAC1 to FAC2
.,BF74 A9 11    LDA #$11        set 0.5 pointer low address
.,BF76 A0 BF    LDY #$BF        set 0.5 pointer high address
.,BF78 20 A2 BB JSR $BBA2       unpack memory (AY) into FAC1

perform power function

.,BF7B F0 70    BEQ $BFED       perform EXP()
.,BF7D A5 69    LDA $69         get FAC2 exponent
.,BF7F D0 03    BNE $BF84       branch if FAC2<>0
.,BF81 4C F9 B8 JMP $B8F9       clear FAC1 exponent and sign and return
.,BF84 A2 4E    LDX #$4E        set destination pointer low byte
.,BF86 A0 00    LDY #$00        set destination pointer high byte
.,BF88 20 D4 BB JSR $BBD4       pack FAC1 into (XY)
.,BF8B A5 6E    LDA $6E         get FAC2 sign (b7)
.,BF8D 10 0F    BPL $BF9E       branch if FAC2>0
                                else FAC2 is -ve and can only be raised to an
                                integer power which gives an x + j0 result
.,BF8F 20 CC BC JSR $BCCC       perform INT()
.,BF92 A9 4E    LDA #$4E        set source pointer low byte
.,BF94 A0 00    LDY #$00        set source pointer high byte
.,BF96 20 5B BC JSR $BC5B       compare FAC1 with (AY)
.,BF99 D0 03    BNE $BF9E       branch if FAC1 <> (AY) to allow Function Call error
                                this will leave FAC1 -ve and cause a Function Call
                                error when LOG() is called
.,BF9B 98       TYA             clear sign b7
.,BF9C A4 07    LDY $07         get FAC1 mantissa 4 from INT() function as sign in
                                Y for possible later negation, b0 only needed
.,BF9E 20 FE BB JSR $BBFE       save FAC1 sign and copy ABS(FAC2) to FAC1
.,BFA1 98       TYA             copy sign back ..
.,BFA2 48       PHA             .. and save it
.,BFA3 20 EA B9 JSR $B9EA       perform LOG()
.,BFA6 A9 4E    LDA #$4E        set pointer low byte
.,BFA8 A0 00    LDY #$00        set pointer high byte
.,BFAA 20 28 BA JSR $BA28       do convert AY, FCA1*(AY)
.,BFAD 20 ED BF JSR $BFED       perform EXP()
.,BFB0 68       PLA             pull sign from stack
.,BFB1 4A       LSR             b0 is to be tested
.,BFB2 90 0A    BCC $BFBE       if no bit then exit
                                do - FAC1
.,BFB4 A5 61    LDA $61         get FAC1 exponent
.,BFB6 F0 06    BEQ $BFBE       exit if FAC1_e = $00
.,BFB8 A5 66    LDA $66         get FAC1 sign (b7)
.,BFBA 49 FF    EOR #$FF        complement it
.,BFBC 85 66    STA $66         save FAC1 sign (b7)
.,BFBE 60       RTS

exp(n) constant and series

.:BFBF 81 38 AA 3B 29           1.44269504 = 1/LOG(2)
.:BFC4 07                       series count
.:BFC5 71 34 58 3E 56           2.14987637E-5
.:BFCA 74 16 7E B3 1B           1.43523140E-4
.:BFCF 77 2F EE E3 85           1.34226348E-3
.:BFD4 7A 1D 84 1C 2A           9.61401701E-3
.:BFD9 7C 63 59 58 0A           5.55051269E-2
.:BFDE 7E 75 FD E7 C6           2.40226385E-1
.:BFE3 80 31 72 18 10           6.93147186E-1
.:BFE8 81 00 00 00 00           1.00000000

perform EXP()

.,BFED A9 BF    LDA #$BF        set 1.443 pointer low byte
.,BFEF A0 BF    LDY #$BF        set 1.443 pointer high byte
.,BFF1 20 28 BA JSR $BA28       do convert AY, FCA1*(AY)
.,BFF4 A5 70    LDA $70         get FAC1 rounding byte
.,BFF6 69 50    ADC #$50        +$50/$100
.,BFF8 90 03    BCC $BFFD       skip rounding if no carry
.,BFFA 20 23 BC JSR $BC23       round FAC1 (no check)
.,BFFD 4C 00 E0 JMP $E000       continue EXP()

start of the kernal ROM

                                EXP() continued
.,E000 85 56    STA $56         save FAC2 rounding byte
.,E002 20 0F BC JSR $BC0F       copy FAC1 to FAC2
.,E005 A5 61    LDA $61         get FAC1 exponent
.,E007 C9 88    CMP #$88        compare with EXP limit (256d)
.,E009 90 03    BCC $E00E       branch if less
.,E00B 20 D4 BA JSR $BAD4       handle overflow and underflow
.,E00E 20 CC BC JSR $BCCC       perform INT()
.,E011 A5 07    LDA $07         get mantissa 4 from INT()
.,E013 18       CLC             clear carry for add
.,E014 69 81    ADC #$81        normalise +1
.,E016 F0 F3    BEQ $E00B       if $00 result has overflowed so go handle it
.,E018 38       SEC             set carry for subtract
.,E019 E9 01    SBC #$01        exponent now correct
.,E01B 48       PHA             save FAC2 exponent
                                swap FAC1 and FAC2
.,E01C A2 05    LDX #$05        4 bytes to do
.,E01E B5 69    LDA $69,X       get FAC2,X
.,E020 B4 61    LDY $61,X       get FAC1,X
.,E022 95 61    STA $61,X       save FAC1,X
.,E024 94 69    STY $69,X       save FAC2,X
.,E026 CA       DEX             decrement count/index
.,E027 10 F5    BPL $E01E       loop if not all done
.,E029 A5 56    LDA $56         get FAC2 rounding byte
.,E02B 85 70    STA $70         save as FAC1 rounding byte
.,E02D 20 53 B8 JSR $B853       perform subtraction, FAC2 from FAC1
.,E030 20 B4 BF JSR $BFB4       do - FAC1
.,E033 A9 C4    LDA #$C4        set counter pointer low byte
.,E035 A0 BF    LDY #$BF        set counter pointer high byte
.,E037 20 59 E0 JSR $E059       go do series evaluation
.,E03A A9 00    LDA #$00        clear A
.,E03C 85 6F    STA $6F         clear sign compare (FAC1 EOR FAC2)
.,E03E 68       PLA             get saved FAC2 exponent
.,E03F 20 B9 BA JSR $BAB9       test and adjust accumulators
.,E042 60       RTS
                                ^2 then series evaluation
.,E043 85 71    STA $71         save count pointer low byte
.,E045 84 72    STY $72         save count pointer high byte
.,E047 20 CA BB JSR $BBCA       pack FAC1 into $57
.,E04A A9 57    LDA #$57        set pointer low byte (Y already $00)
.,E04C 20 28 BA JSR $BA28       do convert AY, FCA1*(AY)
.,E04F 20 5D E0 JSR $E05D       go do series evaluation
.,E052 A9 57    LDA #$57        pointer to original # low byte
.,E054 A0 00    LDY #$00        pointer to original # high byte
.,E056 4C 28 BA JMP $BA28       do convert AY, FCA1*(AY)
                                do series evaluation
.,E059 85 71    STA $71         save count pointer low byte
.,E05B 84 72    STY $72         save count pointer high byte
                                do series evaluation
.,E05D 20 C7 BB JSR $BBC7       pack FAC1 into $5C
.,E060 B1 71    LDA ($71),Y     get constants count
.,E062 85 67    STA $67         save constants count
.,E064 A4 71    LDY $71         get count pointer low byte
.,E066 C8       INY             increment it (now constants pointer)
.,E067 98       TYA             copy it
.,E068 D0 02    BNE $E06C       skip next if no overflow
.,E06A E6 72    INC $72         else increment high byte
.,E06C 85 71    STA $71         save low byte
.,E06E A4 72    LDY $72         get high byte
.,E070 20 28 BA JSR $BA28       do convert AY, FCA1*(AY)
.,E073 A5 71    LDA $71         get constants pointer low byte
.,E075 A4 72    LDY $72         get constants pointer high byte
.,E077 18       CLC             clear carry for add
.,E078 69 05    ADC #$05        +5 to low pointer (5 bytes per constant)
.,E07A 90 01    BCC $E07D       skip next if no overflow
.,E07C C8       INY             increment high byte
.,E07D 85 71    STA $71         save pointer low byte
.,E07F 84 72    STY $72         save pointer high byte
.,E081 20 67 B8 JSR $B867       add (AY) to FAC1
.,E084 A9 5C    LDA #$5C        set pointer low byte to partial
.,E086 A0 00    LDY #$00        set pointer high byte to partial
.,E088 C6 67    DEC $67         decrement constants count
.,E08A D0 E4    BNE $E070       loop until all done
.,E08C 60       RTS

RND values

.:E08D 98 35 44 7A 00           11879546            multiplier
.:E092 68 28 B1 46 00           3.927677739E-8      offset

perform RND()

.,E097 20 2B BC JSR $BC2B       get FAC1 sign
                                return A = $FF -ve, A = $01 +ve
.,E09A 30 37    BMI $E0D3       if n<0 copy byte swapped FAC1 into RND() seed
.,E09C D0 20    BNE $E0BE       if n>0 get next number in RND() sequence
                                else n=0 so get the RND() number from VIA 1 timers
.,E09E 20 F3 FF JSR $FFF3       return base address of I/O devices
.,E0A1 86 22    STX $22         save pointer low byte
.,E0A3 84 23    STY $23         save pointer high byte
.,E0A5 A0 04    LDY #$04        set index to T1 low byte
.,E0A7 B1 22    LDA ($22),Y     get T1 low byte
.,E0A9 85 62    STA $62         save FAC1 mantissa 1
.,E0AB C8       INY             increment index
.,E0AC B1 22    LDA ($22),Y     get T1 high byte
.,E0AE 85 64    STA $64         save FAC1 mantissa 3
.,E0B0 A0 08    LDY #$08        set index to T2 low byte
.,E0B2 B1 22    LDA ($22),Y     get T2 low byte
.,E0B4 85 63    STA $63         save FAC1 mantissa 2
.,E0B6 C8       INY             increment index
.,E0B7 B1 22    LDA ($22),Y     get T2 high byte
.,E0B9 85 65    STA $65         save FAC1 mantissa 4
.,E0BB 4C E3 E0 JMP $E0E3       set exponent and exit
.,E0BE A9 8B    LDA #$8B        set seed pointer low address
.,E0C0 A0 00    LDY #$00        set seed pointer high address
.,E0C2 20 A2 BB JSR $BBA2       unpack memory (AY) into FAC1
.,E0C5 A9 8D    LDA #$8D        set 11879546 pointer low byte
.,E0C7 A0 E0    LDY #$E0        set 11879546 pointer high byte
.,E0C9 20 28 BA JSR $BA28       do convert AY, FCA1*(AY)
.,E0CC A9 92    LDA #$92        set 3.927677739E-8 pointer low byte
.,E0CE A0 E0    LDY #$E0        set 3.927677739E-8 pointer high byte
.,E0D0 20 67 B8 JSR $B867       add (AY) to FAC1
.,E0D3 A6 65    LDX $65         get FAC1 mantissa 4
.,E0D5 A5 62    LDA $62         get FAC1 mantissa 1
.,E0D7 85 65    STA $65         save FAC1 mantissa 4
.,E0D9 86 62    STX $62         save FAC1 mantissa 1
.,E0DB A6 63    LDX $63         get FAC1 mantissa 2
.,E0DD A5 64    LDA $64         get FAC1 mantissa 3
.,E0DF 85 63    STA $63         save FAC1 mantissa 2
.,E0E1 86 64    STX $64         save FAC1 mantissa 3
.,E0E3 A9 00    LDA #$00        clear byte
.,E0E5 85 66    STA $66         clear FAC1 sign (always +ve)
.,E0E7 A5 61    LDA $61         get FAC1 exponent
.,E0E9 85 70    STA $70         save FAC1 rounding byte
.,E0EB A9 80    LDA #$80        set exponent = $80
.,E0ED 85 61    STA $61         save FAC1 exponent
.,E0EF 20 D7 B8 JSR $B8D7       normalise FAC1
.,E0F2 A2 8B    LDX #$8B        set seed pointer low address
.,E0F4 A0 00    LDY #$00        set seed pointer high address

pack FAC1 into (XY)

.,E0F6 4C D4 BB JMP $BBD4       pack FAC1 into (XY)

handle BASIC I/O error

.,E0F9 C9 F0    CMP #$F0        compare error with $F0
.,E0FB D0 07    BNE $E104       branch if not $F0
.,E0FD 84 38    STY $38         set end of memory high byte
.,E0FF 86 37    STX $37         set end of memory low byte
.,E101 4C 63 A6 JMP $A663       clear from start to end and return
                                error was not $F0
.,E104 AA       TAX             copy error #
.,E105 D0 02    BNE $E109       branch if not $00
.,E107 A2 1E    LDX #$1E        else error $1E, break error
.,E109 4C 37 A4 JMP $A437       do error #X then warm start

output character to channel with error check

.,E10C 20 D2 FF JSR $FFD2       output character to channel
.,E10F B0 E8    BCS $E0F9       if error go handle BASIC I/O error
.,E111 60       RTS

input character from channel with error check

.,E112 20 CF FF JSR $FFCF       input character from channel
.,E115 B0 E2    BCS $E0F9       if error go handle BASIC I/O error
.,E117 60       RTS

open channel for output with error check

.,E118 20 AD E4 JSR $E4AD       open channel for output
.,E11B B0 DC    BCS $E0F9       if error go handle BASIC I/O error
.,E11D 60       RTS

open channel for input with error check

.,E11E 20 C6 FF JSR $FFC6       open channel for input
.,E121 B0 D6    BCS $E0F9       if error go handle BASIC I/O error
.,E123 60       RTS

get character from input device with error check

.,E124 20 E4 FF JSR $FFE4       get character from input device
.,E127 B0 D0    BCS $E0F9       if error go handle BASIC I/O error
.,E129 60       RTS

perform SYS

.,E12A 20 8A AD JSR $AD8A       evaluate expression and check is numeric, else do
                                type mismatch
.,E12D 20 F7 B7 JSR $B7F7       convert FAC_1 to integer in temporary integer
.,E130 A9 E1    LDA #$E1        get return address high byte
.,E132 48       PHA             push as return address
.,E133 A9 46    LDA #$46        get return address low byte
.,E135 48       PHA             push as return address
.,E136 AD 0F 03 LDA $030F       get saved status register
.,E139 48       PHA             put on stack
.,E13A AD 0C 03 LDA $030C       get saved A
.,E13D AE 0D 03 LDX $030D       get saved X
.,E140 AC 0E 03 LDY $030E       get saved Y
.,E143 28       PLP             pull processor status
.,E144 6C 14 00 JMP ($0014)     call SYS address
                                tail end of SYS code
.,E147 08       PHP             save status
.,E148 8D 0C 03 STA $030C       save returned A
.,E14B 8E 0D 03 STX $030D       save returned X
.,E14E 8C 0E 03 STY $030E       save returned Y
.,E151 68       PLA             restore saved status
.,E152 8D 0F 03 STA $030F       save status
.,E155 60       RTS

perform SAVE

.,E156 20 D4 E1 JSR $E1D4       get parameters for LOAD/SAVE
.,E159 A6 2D    LDX $2D         get start of variables low byte
.,E15B A4 2E    LDY $2E         get start of variables high byte
.,E15D A9 2B    LDA #$2B        index to start of program memory
.,E15F 20 D8 FF JSR $FFD8       save RAM to device, A = index to start address, XY = end
                                address low/high
.,E162 B0 95    BCS $E0F9       if error go handle BASIC I/O error
.,E164 60       RTS

perform VERIFY

.,E165 A9 01    LDA #$01        flag verify
.:E167 2C       .BYTE $2C       makes next line BIT $00A9

perform LOAD

.,E168 A9 00    LDA #$00        flag load
.,E16A 85 0A    STA $0A         set load/verify flag
.,E16C 20 D4 E1 JSR $E1D4       get parameters for LOAD/SAVE
.,E16F A5 0A    LDA $0A         get load/verify flag
.,E171 A6 2B    LDX $2B         get start of memory low byte
.,E173 A4 2C    LDY $2C         get start of memory high byte
.,E175 20 D5 FF JSR $FFD5       load RAM from a device
.,E178 B0 57    BCS $E1D1       if error go handle BASIC I/O error
.,E17A A5 0A    LDA $0A         get load/verify flag
.,E17C F0 17    BEQ $E195       branch if load
.,E17E A2 1C    LDX #$1C        error $1C, verify error
.,E180 20 B7 FF JSR $FFB7       read I/O status word
.,E183 29 10    AND #$10        mask for tape read error
.,E185 D0 17    BNE $E19E       branch if no read error
.,E187 A5 7A    LDA $7A         get the BASIC execute pointer low byte
                                is this correct ?? won't this mean the "OK" prompt
                                when doing a load from within a program ?
.,E189 C9 02    CMP #$02
.,E18B F0 07    BEQ $E194       if ?? skip "OK" prompt
.,E18D A9 64    LDA #$64        set "OK" pointer low byte
.,E18F A0 A3    LDY #$A3        set "OK" pointer high byte
.,E191 4C 1E AB JMP $AB1E       print null terminated string
.,E194 60       RTS

do READY return to BASIC

.,E195 20 B7 FF JSR $FFB7       read I/O status word
.,E198 29 BF    AND #$BF        mask x0xx xxxx, clear read error
.,E19A F0 05    BEQ $E1A1       branch if no errors
.,E19C A2 1D    LDX #$1D        error $1D, load error
.,E19E 4C 37 A4 JMP $A437       do error #X then warm start
.,E1A1 A5 7B    LDA $7B         get BASIC execute pointer high byte
.,E1A3 C9 02    CMP #$02        compare with $02xx
.,E1A5 D0 0E    BNE $E1B5       branch if not immediate mode
.,E1A7 86 2D    STX $2D         set start of variables low byte
.,E1A9 84 2E    STY $2E         set start of variables high byte
.,E1AB A9 76    LDA #$76        set "READY." pointer low byte
.,E1AD A0 A3    LDY #$A3        set "READY." pointer high byte
.,E1AF 20 1E AB JSR $AB1E       print null terminated string
.,E1B2 4C 2A A5 JMP $A52A       reset execution, clear variables, flush stack,
                                rebuild BASIC chain and do warm start
.,E1B5 20 8E A6 JSR $A68E       set BASIC execute pointer to start of memory - 1
.,E1B8 20 33 A5 JSR $A533       rebuild BASIC line chaining
.,E1BB 4C 77 A6 JMP $A677       rebuild BASIC line chaining, do RESTORE and return

perform OPEN

.,E1BE 20 19 E2 JSR $E219       get parameters for OPEN/CLOSE
.,E1C1 20 C0 FF JSR $FFC0       open a logical file
.,E1C4 B0 0B    BCS $E1D1       branch if error
.,E1C6 60       RTS

perform CLOSE

.,E1C7 20 19 E2 JSR $E219       get parameters for OPEN/CLOSE
.,E1CA A5 49    LDA $49         get logical file number
.,E1CC 20 C3 FF JSR $FFC3       close a specified logical file
.,E1CF 90 C3    BCC $E194       exit if no error
.,E1D1 4C F9 E0 JMP $E0F9       go handle BASIC I/O error

get parameters for LOAD/SAVE

.,E1D4 A9 00    LDA #$00        clear file name length
.,E1D6 20 BD FF JSR $FFBD       clear the filename
.,E1D9 A2 01    LDX #$01        set default device number, cassette
.,E1DB A0 00    LDY #$00        set default command
.,E1DD 20 BA FF JSR $FFBA       set logical, first and second addresses
.,E1E0 20 06 E2 JSR $E206       exit function if [EOT] or ":"
.,E1E3 20 57 E2 JSR $E257       set filename
.,E1E6 20 06 E2 JSR $E206       exit function if [EOT] or ":"
.,E1E9 20 00 E2 JSR $E200       scan and get byte, else do syntax error then warm start
.,E1EC A0 00    LDY #$00        clear command
.,E1EE 86 49    STX $49         save device number
.,E1F0 20 BA FF JSR $FFBA       set logical, first and second addresses
.,E1F3 20 06 E2 JSR $E206       exit function if [EOT] or ":"
.,E1F6 20 00 E2 JSR $E200       scan and get byte, else do syntax error then warm start
.,E1F9 8A       TXA             copy command to A
.,E1FA A8       TAY             copy command to Y
.,E1FB A6 49    LDX $49         get device number back
.,E1FD 4C BA FF JMP $FFBA       set logical, first and second addresses and return

scan and get byte, else do syntax error then warm start

.,E200 20 0E E2 JSR $E20E       scan for ",byte", else do syntax error then warm start
.,E203 4C 9E B7 JMP $B79E       get byte parameter and return
                                exit function if [EOT] or ":"
.,E206 20 79 00 JSR $0079       scan memory
.,E209 D0 02    BNE $E20D       branch if not [EOL] or ":"
.,E20B 68       PLA             dump return address low byte
.,E20C 68       PLA             dump return address high byte
.,E20D 60       RTS

scan for ",valid byte", else do syntax error then warm start

.,E20E 20 FD AE JSR $AEFD       scan for ",", else do syntax error then warm start

scan for valid byte, not [EOL] or ":", else do syntax error then warm start

.,E211 20 79 00 JSR $0079       scan memory
.,E214 D0 F7    BNE $E20D       exit if following byte
.,E216 4C 08 AF JMP $AF08       else do syntax error then warm start

get parameters for OPEN/CLOSE

.,E219 A9 00    LDA #$00        clear the filename length
.,E21B 20 BD FF JSR $FFBD       clear the filename
.,E21E 20 11 E2 JSR $E211       scan for valid byte, else do syntax error then warm start
.,E221 20 9E B7 JSR $B79E       get byte parameter, logical file number
.,E224 86 49    STX $49         save logical file number
.,E226 8A       TXA             copy logical file number to A
.,E227 A2 01    LDX #$01        set default device number, cassette
.,E229 A0 00    LDY #$00        set default command
.,E22B 20 BA FF JSR $FFBA       set logical, first and second addresses
.,E22E 20 06 E2 JSR $E206       exit function if [EOT] or ":"
.,E231 20 00 E2 JSR $E200       scan and get byte, else do syntax error then warm start
.,E234 86 4A    STX $4A         save device number
.,E236 A0 00    LDY #$00        clear command
.,E238 A5 49    LDA $49         get logical file number
.,E23A E0 03    CPX #$03        compare device number with screen
.,E23C 90 01    BCC $E23F       branch if less than screen
.,E23E 88       DEY             else decrement command
.,E23F 20 BA FF JSR $FFBA       set logical, first and second addresses
.,E242 20 06 E2 JSR $E206       exit function if [EOT] or ":"
.,E245 20 00 E2 JSR $E200       scan and get byte, else do syntax error then warm start
.,E248 8A       TXA             copy command to A
.,E249 A8       TAY             copy command to Y
.,E24A A6 4A    LDX $4A         get device number
.,E24C A5 49    LDA $49         get logical file number
.,E24E 20 BA FF JSR $FFBA       set logical, first and second addresses
.,E251 20 06 E2 JSR $E206       exit function if [EOT] or ":"
.,E254 20 0E E2 JSR $E20E       scan for ",byte", else do syntax error then warm start

set filename

.,E257 20 9E AD JSR $AD9E       evaluate expression
.,E25A 20 A3 B6 JSR $B6A3       evaluate string
.,E25D A6 22    LDX $22         get string pointer low byte
.,E25F A4 23    LDY $23         get string pointer high byte
.,E261 4C BD FF JMP $FFBD       set the filename and return

perform COS()

.,E264 A9 E0    LDA #$E0        set pi/2 pointer low byte
.,E266 A0 E2    LDY #$E2        set pi/2 pointer high byte
.,E268 20 67 B8 JSR $B867       add (AY) to FAC1

perform SIN()

.,E26B 20 0C BC JSR $BC0C       round and copy FAC1 to FAC2
.,E26E A9 E5    LDA #$E5        set 2*pi pointer low byte
.,E270 A0 E2    LDY #$E2        set 2*pi pointer high byte
.,E272 A6 6E    LDX $6E         get FAC2 sign (b7)
.,E274 20 07 BB JSR $BB07       divide by (AY) (X=sign)
.,E277 20 0C BC JSR $BC0C       round and copy FAC1 to FAC2
.,E27A 20 CC BC JSR $BCCC       perform INT()
.,E27D A9 00    LDA #$00        clear byte
.,E27F 85 6F    STA $6F         clear sign compare (FAC1 EOR FAC2)
.,E281 20 53 B8 JSR $B853       perform subtraction, FAC2 from FAC1
.,E284 A9 EA    LDA #$EA        set 0.25 pointer low byte
.,E286 A0 E2    LDY #$E2        set 0.25 pointer high byte
.,E288 20 50 B8 JSR $B850       perform subtraction, FAC1 from (AY)
.,E28B A5 66    LDA $66         get FAC1 sign (b7)
.,E28D 48       PHA             save FAC1 sign
.,E28E 10 0D    BPL $E29D       branch if +ve
                                FAC1 sign was -ve
.,E290 20 49 B8 JSR $B849       add 0.5 to FAC1 (round FAC1)
.,E293 A5 66    LDA $66         get FAC1 sign (b7)
.,E295 30 09    BMI $E2A0       branch if -ve
.,E297 A5 12    LDA $12         get the comparison evaluation flag
.,E299 49 FF    EOR #$FF        toggle flag
.,E29B 85 12    STA $12         save the comparison evaluation flag
.,E29D 20 B4 BF JSR $BFB4       do - FAC1
.,E2A0 A9 EA    LDA #$EA        set 0.25 pointer low byte
.,E2A2 A0 E2    LDY #$E2        set 0.25 pointer high byte
.,E2A4 20 67 B8 JSR $B867       add (AY) to FAC1
.,E2A7 68       PLA             restore FAC1 sign
.,E2A8 10 03    BPL $E2AD       branch if was +ve
                                else correct FAC1
.,E2AA 20 B4 BF JSR $BFB4       do - FAC1
.,E2AD A9 EF    LDA #$EF        set pointer low byte to counter
.,E2AF A0 E2    LDY #$E2        set pointer high byte to counter
.,E2B1 4C 43 E0 JMP $E043       ^2 then series evaluation and return

perform TAN()

.,E2B4 20 CA BB JSR $BBCA       pack FAC1 into $57
.,E2B7 A9 00    LDA #$00        clear A
.,E2B9 85 12    STA $12         clear the comparison evaluation flag
.,E2BB 20 6B E2 JSR $E26B       perform SIN()
.,E2BE A2 4E    LDX #$4E        set sin(n) pointer low byte
.,E2C0 A0 00    LDY #$00        set sin(n) pointer high byte
.,E2C2 20 F6 E0 JSR $E0F6       pack FAC1 into (XY)
.,E2C5 A9 57    LDA #$57        set n pointer low byte
.,E2C7 A0 00    LDY #$00        set n pointer high byte
.,E2C9 20 A2 BB JSR $BBA2       unpack memory (AY) into FAC1
.,E2CC A9 00    LDA #$00        clear byte
.,E2CE 85 66    STA $66         clear FAC1 sign (b7)
.,E2D0 A5 12    LDA $12         get the comparison evaluation flag
.,E2D2 20 DC E2 JSR $E2DC       save flag and go do series evaluation
.,E2D5 A9 4E    LDA #$4E        set sin(n) pointer low byte
.,E2D7 A0 00    LDY #$00        set sin(n) pointer high byte
.,E2D9 4C 0F BB JMP $BB0F       convert AY and do (AY)/FAC1

save comparison flag and do series evaluation

.,E2DC 48       PHA             save comparison flag
.,E2DD 4C 9D E2 JMP $E29D       add 0.25, ^2 then series evaluation

constants and series for SIN/COS(n)

.:E2E0 81 49 0F DA A2           1.570796371, pi/2, as floating number
.:E2E5 83 49 0F DA A2           6.28319, 2*pi, as floating number
.:E2EA 7F 00 00 00 00           0.25
.:E2EF 05                       series counter
.:E2F0 84 E6 1A 2D 1B           -14.3813907
.:E2F5 86 28 07 FB F8            42.0077971
.:E2FA 87 99 68 89 01           -76.7041703
.:E2FF 87 23 35 DF E1            81.6052237
.:E304 86 A5 5D E7 28           -41.3147021
.:E309 83 49 0F DA A2             6.28318531   2*pi

perform ATN()

.,E30E A5 66    LDA $66         get FAC1 sign (b7)
.,E310 48       PHA             save sign
.,E311 10 03    BPL $E316       branch if +ve
.,E313 20 B4 BF JSR $BFB4       else do - FAC1
.,E316 A5 61    LDA $61         get FAC1 exponent
.,E318 48       PHA             push exponent
.,E319 C9 81    CMP #$81        compare with 1
.,E31B 90 07    BCC $E324       branch if FAC1 < 1
.,E31D A9 BC    LDA #$BC        pointer to 1 low byte
.,E31F A0 B9    LDY #$B9        pointer to 1 high byte
.,E321 20 0F BB JSR $BB0F       convert AY and do (AY)/FAC1
.,E324 A9 3E    LDA #$3E        pointer to series low byte
.,E326 A0 E3    LDY #$E3        pointer to series high byte
.,E328 20 43 E0 JSR $E043       ^2 then series evaluation
.,E32B 68       PLA             restore old FAC1 exponent
.,E32C C9 81    CMP #$81        compare with 1
.,E32E 90 07    BCC $E337       branch if FAC1 < 1
.,E330 A9 E0    LDA #$E0        pointer to (pi/2) low byte
.,E332 A0 E2    LDY #$E2        pointer to (pi/2) low byte
.,E334 20 50 B8 JSR $B850       perform subtraction, FAC1 from (AY)
.,E337 68       PLA             restore FAC1 sign
.,E338 10 03    BPL $E33D       exit if was +ve
.,E33A 4C B4 BF JMP $BFB4       else do - FAC1 and return
.,E33D 60       RTS

series for ATN(n)

.:E33E 0B                       series counter
.:E33F 76 B3 83 BD D3           -6.84793912E-04
.:E344 79 1E F4 A6 F5            4.85094216E-03
.:E349 7B 83 FC B0 10            -.0161117015
.:E34E 7C 0C 1F 67 CA             .034209638
.:E353 7C DE 53 CB C1            -.054279133
.:E358 7D 14 64 70 4C             .0724571965
.:E35D 7D B7 EA 51 7A            -.0898019185
.:E362 7D 63 30 88 7E             .110932413
.:E367 7E 92 44 99 3A            -.142839808
.:E36C 7E 4C CC 91 C7             .19999912
.:E371 7F AA AA AA 13            -.333333316
.:E376 81 00 00 00 00            1

BASIC warm start entry point

.,E37B 20 CC FF JSR $FFCC       close input and output channels
.,E37E A9 00    LDA #$00        clear A
.,E380 85 13    STA $13         set current I/O channel, flag default
.,E382 20 7A A6 JSR $A67A       flush BASIC stack and clear continue pointer
.,E385 58       CLI             enable the interrupts
.,E386 A2 80    LDX #$80        set -ve error, just do warm start
.,E388 6C 00 03 JMP ($0300)     go handle error message, normally $E38B
.,E38B 8A       TXA             copy the error number
.,E38C 30 03    BMI $E391       if -ve go do warm start
.,E38E 4C 3A A4 JMP $A43A       else do error #X then warm start
.,E391 4C 74 A4 JMP $A474       do warm start

BASIC cold start entry point

.,E394 20 53 E4 JSR $E453       initialise the BASIC vector table
.,E397 20 BF E3 JSR $E3BF       initialise the BASIC RAM locations
.,E39A 20 22 E4 JSR $E422       print the start up message and initialise the memory
                                pointers
                                not ok ??
.,E39D A2 FB    LDX #$FB        value for start stack
.,E39F 9A       TXS             set stack pointer
.,E3A0 D0 E4    BNE $E386       do "READY." warm start, branch always

character get subroutine for zero page

                                the target address for the LDA $EA60 becomes the BASIC execute pointer once the
                                block is copied to its destination, any non zero page address will do at assembly
                                time, to assemble a three byte instruction. $EA60 is RTS, NOP.
                                page 0 initialisation table from $0073
                                increment and scan memory
.,E3A2 E6 7A    INC $7A         increment BASIC execute pointer low byte
.,E3A4 D0 02    BNE $E3A8       branch if no carry
                                else
.,E3A6 E6 7B    INC $7B         increment BASIC execute pointer high byte
                                page 0 initialisation table from $0079
                                scan memory
.,E3A8 AD 60 EA LDA $EA60       get byte to scan, address set by call routine
.,E3AB C9 3A    CMP #$3A        compare with ":"
.,E3AD B0 0A    BCS $E3B9       exit if>=
                                page 0 initialisation table from $0080
                                clear Cb if numeric
.,E3AF C9 20    CMP #$20        compare with " "
.,E3B1 F0 EF    BEQ $E3A2       if " " go do next
.,E3B3 38       SEC             set carry for SBC
.,E3B4 E9 30    SBC #$30        subtract "0"
.,E3B6 38       SEC             set carry for SBC
.,E3B7 E9 D0    SBC #$D0        subtract -"0"
                                clear carry if byte = "0"-"9"
.,E3B9 60       RTS

spare bytes, not referenced

.:E3BA 80 4F C7 52 58           0.811635157

initialise BASIC RAM locations

.,E3BF A9 4C    LDA #$4C        opcode for JMP
.,E3C1 85 54    STA $54         save for functions vector jump
.,E3C3 8D 10 03 STA $0310       save for USR() vector jump
                                set USR() vector to illegal quantity error
.,E3C6 A9 48    LDA #$48        set USR() vector low byte
.,E3C8 A0 B2    LDY #$B2        set USR() vector high byte
.,E3CA 8D 11 03 STA $0311       save USR() vector low byte
.,E3CD 8C 12 03 STY $0312       save USR() vector high byte
.,E3D0 A9 91    LDA #$91        set fixed to float vector low byte
.,E3D2 A0 B3    LDY #$B3        set fixed to float vector high byte
.,E3D4 85 05    STA $05         save fixed to float vector low byte
.,E3D6 84 06    STY $06         save fixed to float vector high byte
.,E3D8 A9 AA    LDA #$AA        set float to fixed vector low byte
.,E3DA A0 B1    LDY #$B1        set float to fixed vector high byte
.,E3DC 85 03    STA $03         save float to fixed vector low byte
.,E3DE 84 04    STY $04         save float to fixed vector high byte
                                copy the character get subroutine from $E3A2 to $0074
.,E3E0 A2 1C    LDX #$1C        set the byte count
.,E3E2 BD A2 E3 LDA $E3A2,X     get a byte from the table
.,E3E5 95 73    STA $73,X       save the byte in page zero
.,E3E7 CA       DEX             decrement the count
.,E3E8 10 F8    BPL $E3E2       loop if not all done
                                clear descriptors, strings, program area and mamory pointers
.,E3EA A9 03    LDA #$03        set the step size, collecting descriptors
.,E3EC 85 53    STA $53         save the garbage collection step size
.,E3EE A9 00    LDA #$00        clear A
.,E3F0 85 68    STA $68         clear FAC1 overflow byte
.,E3F2 85 13    STA $13         clear the current I/O channel, flag default
.,E3F4 85 18    STA $18         clear the current descriptor stack item pointer high byte
.,E3F6 A2 01    LDX #$01        set X
.,E3F8 8E FD 01 STX $01FD       set the chain link pointer low byte
.,E3FB 8E FC 01 STX $01FC       set the chain link pointer high byte
.,E3FE A2 19    LDX #$19        initial the value for descriptor stack
.,E400 86 16    STX $16         set descriptor stack pointer
.,E402 38       SEC             set Cb = 1 to read the bottom of memory
.,E403 20 9C FF JSR $FF9C       read/set the bottom of memory
.,E406 86 2B    STX $2B         save the start of memory low byte
.,E408 84 2C    STY $2C         save the start of memory high byte
.,E40A 38       SEC             set Cb = 1 to read the top of memory
.,E40B 20 99 FF JSR $FF99       read/set the top of memory
.,E40E 86 37    STX $37         save the end of memory low byte
.,E410 84 38    STY $38         save the end of memory high byte
.,E412 86 33    STX $33         set the bottom of string space low byte
.,E414 84 34    STY $34         set the bottom of string space high byte
.,E416 A0 00    LDY #$00        clear the index
.,E418 98       TYA             clear the A
.,E419 91 2B    STA ($2B),Y     clear the the first byte of memory
.,E41B E6 2B    INC $2B         increment the start of memory low byte
.,E41D D0 02    BNE $E421       if no rollover skip the high byte increment
.,E41F E6 2C    INC $2C         increment start of memory high byte
.,E421 60       RTS

print the start up message and initialise the memory pointers

.,E422 A5 2B    LDA $2B         get the start of memory low byte
.,E424 A4 2C    LDY $2C         get the start of memory high byte
.,E426 20 08 A4 JSR $A408       check available memory, do out of memory error if no room
.,E429 A9 73    LDA #$73        set "**** COMMODORE 64 BASIC V2 ****" pointer low byte
.,E42B A0 E4    LDY #$E4        set "**** COMMODORE 64 BASIC V2 ****" pointer high byte
.,E42D 20 1E AB JSR $AB1E       print a null terminated string
.,E430 A5 37    LDA $37         get the end of memory low byte
.,E432 38       SEC             set carry for subtract
.,E433 E5 2B    SBC $2B         subtract the start of memory low byte
.,E435 AA       TAX             copy the result to X
.,E436 A5 38    LDA $38         get the end of memory high byte
.,E438 E5 2C    SBC $2C         subtract the start of memory high byte
.,E43A 20 CD BD JSR $BDCD       print XA as unsigned integer
.,E43D A9 60    LDA #$60        set " BYTES FREE" pointer low byte
.,E43F A0 E4    LDY #$E4        set " BYTES FREE" pointer high byte
.,E441 20 1E AB JSR $AB1E       print a null terminated string
.,E444 4C 44 A6 JMP $A644       do NEW, CLEAR, RESTORE and return

BASIC vectors, these are copied to RAM from $0300 onwards

.:E447 8B E3                    error message          $0300
.:E449 83 A4                    BASIC warm start       $0302
.:E44B 7C A5                    crunch BASIC tokens    $0304
.:E44D 1A A7                    uncrunch BASIC tokens  $0306
.:E44F E4 A7                    start new BASIC code   $0308
.:E451 86 AE                    get arithmetic element $030A

initialise the BASIC vectors

.,E453 A2 0B    LDX #$0B        set byte count
.,E455 BD 47 E4 LDA $E447,X     get byte from table
.,E458 9D 00 03 STA $0300,X     save byte to RAM
.,E45B CA       DEX             decrement index
.,E45C 10 F7    BPL $E455       loop if more to do
.,E45E 60       RTS

BASIC startup messages

.:E45F 00 20 42 41 53 49 43 20  basic bytes free
.:E467 42 59 54 45 53 20 46 52
.:E46F 45 45 0D 00 93 0D 20 20
.:E473 93 0D 20 20 20 20 2A 2A  (clr) **** commodore 64 basic v2 ****
.:E47B 2A 2A 20 43 4F 4D 4D 4F  (cr) (cr) 64k ram system
.:E483 44 4F 52 45 20 36 34 20
.:E48B 42 41 53 49 43 20 56 32
.:E493 20 2A 2A 2A 2A 0D 0D 20
.:E49B 36 34 4B 20 52 41 4D 20
.:E4A3 53 59 53 54 45 4D 20 20
.:E4AB 00

unused

.:E4AC 5C

open channel for output

.,E4AD 48       PHA             save the flag byte
.,E4AE 20 C9 FF JSR $FFC9       open channel for output
.,E4B1 AA       TAX             copy the returned flag byte
.,E4B2 68       PLA             restore the alling flag byte
.,E4B3 90 01    BCC $E4B6       if there is no error skip copying the error flag
.,E4B5 8A       TXA             else copy the error flag
.,E4B6 60       RTS

unused bytes

.:E4B7 AA AA AA AA AA AA AA AA
.:E4BF AA AA AA AA AA AA AA AA
.:E4C7 AA AA AA AA AA AA AA AA
.:E4CF AA AA AA AA AA

flag the RS232 start bit and set the parity

.,E4D3 85 A9    STA $A9         save the start bit check flag, set start bit received
.,E4D5 A9 01    LDA #$01        set the initial parity state
.,E4D7 85 AB    STA $AB         save the receiver parity bit
.,E4D9 60       RTS

save the current colour to the colour RAM

.,E4DA AD 21 D0 LDA $D021       get the current colour code
.,E4DD 91 F3    STA ($F3),Y     save it to the colour RAM
.,E4DF 60       RTS

wait ~8.5 seconds for any key from the STOP key column

.,E4E0 69 02    ADC #$02        set the number of jiffies to wait
.,E4E2 A4 91    LDY $91         read the stop key column
.,E4E4 C8       INY             test for $FF, no keys pressed
.,E4E5 D0 04    BNE $E4EB       if any keys were pressed just exit
.,E4E7 C5 A1    CMP $A1         compare the wait time with the jiffy clock mid byte
.,E4E9 D0 F7    BNE $E4E2       if not there yet go wait some more
.,E4EB 60       RTS

baud rate tables for PAL C64

                                baud rate word is calculated from ..

                                (system clock / baud rate) / 2 - 100

                                    system clock
                                    ------------
                                PAL       985248 Hz
                                NTSC     1022727 Hz
.:E4EC 19 26                      50   baud   985300
.:E4EE 44 19                      75   baud   985200
.:E4F0 1A 11                     110   baud   985160
.:E4F2 E8 0D                     134.5 baud   984540
.:E4F4 70 0C                     150   baud   985200
.:E4F6 06 06                     300   baud   985200
.:E4F8 D1 02                     600   baud   985200
.:E4FA 37 01                    1200   baud   986400
.:E4FC AE 00                    1800   baud   986400
.:E4FE 69 00                    2400   baud   984000

return the base address of the I/O devices

.,E500 A2 00    LDX #$00        get the I/O base address low byte
.,E502 A0 DC    LDY #$DC        get the I/O base address high byte
.,E504 60       RTS

return the x,y organization of the screen

.,E505 A2 28    LDX #$28        get the x size
.,E507 A0 19    LDY #$19        get the y size
.,E509 60       RTS

read/set the x,y cursor position

.,E50A B0 07    BCS $E513       if read cursor go do read
.,E50C 86 D6    STX $D6         save the cursor row
.,E50E 84 D3    STY $D3         save the cursor column
.,E510 20 6C E5 JSR $E56C       set the screen pointers for the cursor row, column
.,E513 A6 D6    LDX $D6         get the cursor row
.,E515 A4 D3    LDY $D3         get the cursor column
.,E517 60       RTS

initialise the screen and keyboard

.,E518 20 A0 E5 JSR $E5A0       initialise the vic chip
.,E51B A9 00    LDA #$00        clear A
.,E51D 8D 91 02 STA $0291       clear the shift mode switch
.,E520 85 CF    STA $CF         clear the cursor blink phase
.,E522 A9 48    LDA #$48        get the keyboard decode logic pointer low byte
.,E524 8D 8F 02 STA $028F       save the keyboard decode logic pointer low byte
.,E527 A9 EB    LDA #$EB        get the keyboard decode logic pointer high byte
.,E529 8D 90 02 STA $0290       save the keyboard decode logic pointer high byte
.,E52C A9 0A    LDA #$0A        set the maximum size of the keyboard buffer
.,E52E 8D 89 02 STA $0289       save the maximum size of the keyboard buffer
.,E531 8D 8C 02 STA $028C       save the repeat delay counter
.,E534 A9 0E    LDA #$0E        set light blue
.,E536 8D 86 02 STA $0286       save the current colour code
.,E539 A9 04    LDA #$04        speed 4
.,E53B 8D 8B 02 STA $028B       save the repeat speed counter
.,E53E A9 0C    LDA #$0C        set the cursor flash timing
.,E540 85 CD    STA $CD         save the cursor timing countdown
.,E542 85 CC    STA $CC         save the cursor enable, $00 = flash cursor

clear the screen

.,E544 AD 88 02 LDA $0288       get the screen memory page
.,E547 09 80    ORA #$80        set the high bit, flag every line is a logical line start
.,E549 A8       TAY             copy to Y
.,E54A A9 00    LDA #$00        clear the line start low byte
.,E54C AA       TAX             clear the index
.,E54D 94 D9    STY $D9,X       save the start of line X pointer high byte
.,E54F 18       CLC             clear carry for add
.,E550 69 28    ADC #$28        add the line length to the low byte
.,E552 90 01    BCC $E555       if no rollover skip the high byte increment
.,E554 C8       INY             else increment the high byte
.,E555 E8       INX             increment the line index
.,E556 E0 1A    CPX #$1A        compare it with the number of lines + 1
.,E558 D0 F3    BNE $E54D       loop if not all done
.,E55A A9 FF    LDA #$FF        set the end of table marker
.,E55C 95 D9    STA $D9,X       mark the end of the table
.,E55E A2 18    LDX #$18        set the line count, 25 lines to do, 0 to 24
.,E560 20 FF E9 JSR $E9FF       clear screen line X
.,E563 CA       DEX             decrement the count
.,E564 10 FA    BPL $E560       loop if more to do

home the cursor

.,E566 A0 00    LDY #$00        clear Y
.,E568 84 D3    STY $D3         clear the cursor column
.,E56A 84 D6    STY $D6         clear the cursor row

set screen pointers for cursor row, column

.,E56C A6 D6    LDX $D6         get the cursor row
.,E56E A5 D3    LDA $D3         get the cursor column
.,E570 B4 D9    LDY $D9,X       get start of line X pointer high byte
.,E572 30 08    BMI $E57C       if it is the logical line start continue
.,E574 18       CLC             else clear carry for add
.,E575 69 28    ADC #$28        add one line length
.,E577 85 D3    STA $D3         save the cursor column
.,E579 CA       DEX             decrement the cursor row
.,E57A 10 F4    BPL $E570       loop, branch always
.,E57C 20 F0 E9 JSR $E9F0       fetch a screen address
.,E57F A9 27    LDA #$27        set the line length
.,E581 E8       INX             increment the cursor row
.,E582 B4 D9    LDY $D9,X       get the start of line X pointer high byte
.,E584 30 06    BMI $E58C       if logical line start exit
.,E586 18       CLC             else clear carry for add
.,E587 69 28    ADC #$28        add one line length to the current line length
.,E589 E8       INX             increment the cursor row
.,E58A 10 F6    BPL $E582       loop, branch always
.,E58C 85 D5    STA $D5         save current screen line length
.,E58E 4C 24 EA JMP $EA24       calculate the pointer to colour RAM and return
.,E591 E4 C9    CPX $C9         compare it with the input cursor row
.,E593 F0 03    BEQ $E598       if there just exit
.,E595 4C ED E6 JMP $E6ED       else go ??
.,E598 60       RTS

orphan bytes ??

.,E599 EA       NOP             huh
.,E59A 20 A0 E5 JSR $E5A0       initialise the vic chip
.,E59D 4C 66 E5 JMP $E566       home the cursor and return

initialise the vic chip

.,E5A0 A9 03    LDA #$03        set the screen as the output device
.,E5A2 85 9A    STA $9A         save the output device number
.,E5A4 A9 00    LDA #$00        set the keyboard as the input device
.,E5A6 85 99    STA $99         save the input device number
.,E5A8 A2 2F    LDX #$2F        set the count/index
.,E5AA BD B8 EC LDA $ECB8,X     get a vic ii chip initialisation value
.,E5AD 9D FF CF STA $CFFF,X     save it to the vic ii chip
.,E5B0 CA       DEX             decrement the count/index
.,E5B1 D0 F7    BNE $E5AA       loop if more to do
.,E5B3 60       RTS

input from the keyboard buffer

.,E5B4 AC 77 02 LDY $0277       get the current character from the buffer
.,E5B7 A2 00    LDX #$00        clear the index
.,E5B9 BD 78 02 LDA $0278,X     get the next character,X from the buffer
.,E5BC 9D 77 02 STA $0277,X     save it as the current character,X in the buffer
.,E5BF E8       INX             increment the index
.,E5C0 E4 C6    CPX $C6         compare it with the keyboard buffer index
.,E5C2 D0 F5    BNE $E5B9       loop if more to do
.,E5C4 C6 C6    DEC $C6         decrement keyboard buffer index
.,E5C6 98       TYA             copy the key to A
.,E5C7 58       CLI             enable the interrupts
.,E5C8 18       CLC             flag got byte
.,E5C9 60       RTS

write character and wait for key

.,E5CA 20 16 E7 JSR $E716       output character

wait for a key from the keyboard

.,E5CD A5 C6    LDA $C6         get the keyboard buffer index
.,E5CF 85 CC    STA $CC         cursor enable, $00 = flash cursor, $xx = no flash
.,E5D1 8D 92 02 STA $0292       screen scrolling flag, $00 = scroll, $xx = no scroll
                                this disables both the cursor flash and the screen scroll
                                while there are characters in the keyboard buffer
.,E5D4 F0 F7    BEQ $E5CD       loop if the buffer is empty
.,E5D6 78       SEI             disable the interrupts
.,E5D7 A5 CF    LDA $CF         get the cursor blink phase
.,E5D9 F0 0C    BEQ $E5E7       if cursor phase skip the overwrite
                                else it is the character phase
.,E5DB A5 CE    LDA $CE         get the character under the cursor
.,E5DD AE 87 02 LDX $0287       get the colour under the cursor
.,E5E0 A0 00    LDY #$00        clear Y
.,E5E2 84 CF    STY $CF         clear the cursor blink phase
.,E5E4 20 13 EA JSR $EA13       print character A and colour X
.,E5E7 20 B4 E5 JSR $E5B4       input from the keyboard buffer
.,E5EA C9 83    CMP #$83        compare with [SHIFT][RUN]
.,E5EC D0 10    BNE $E5FE       if not [SHIFT][RUN] skip the buffer fill
                                keys are [SHIFT][RUN] so put "LOAD",$0D,"RUN",$0D into
                                the buffer
.,E5EE A2 09    LDX #$09        set the byte count
.,E5F0 78       SEI             disable the interrupts
.,E5F1 86 C6    STX $C6         set the keyboard buffer index
.,E5F3 BD E6 EC LDA $ECE6,X     get byte from the auto load/run table
.,E5F6 9D 76 02 STA $0276,X     save it to the keyboard buffer
.,E5F9 CA       DEX             decrement the count/index
.,E5FA D0 F7    BNE $E5F3       loop while more to do
.,E5FC F0 CF    BEQ $E5CD       loop for the next key, branch always
                                was not [SHIFT][RUN]
.,E5FE C9 0D    CMP #$0D        compare the key with [CR]
.,E600 D0 C8    BNE $E5CA       if not [CR] print the character and get the next key
                                else it was [CR]
.,E602 A4 D5    LDY $D5         get the current screen line length
.,E604 84 D0    STY $D0         input from keyboard or screen, $xx = screen,
                                $00 = keyboard
.,E606 B1 D1    LDA ($D1),Y     get the character from the current screen line
.,E608 C9 20    CMP #$20        compare it with [SPACE]
.,E60A D0 03    BNE $E60F       if not [SPACE] continue
.,E60C 88       DEY             else eliminate the space, decrement end of input line
.,E60D D0 F7    BNE $E606       loop, branch always
.,E60F C8       INY             increment past the last non space character on line
.,E610 84 C8    STY $C8         save the input [EOL] pointer
.,E612 A0 00    LDY #$00        clear A
.,E614 8C 92 02 STY $0292       clear the screen scrolling flag, $00 = scroll
.,E617 84 D3    STY $D3         clear the cursor column
.,E619 84 D4    STY $D4         clear the cursor quote flag, $xx = quote, $00 = no quote
.,E61B A5 C9    LDA $C9         get the input cursor row
.,E61D 30 1B    BMI $E63A
.,E61F A6 D6    LDX $D6         get the cursor row
.,E621 20 ED E6 JSR $E6ED       find and set the pointers for the start of logical line
.,E624 E4 C9    CPX $C9         compare with input cursor row
.,E626 D0 12    BNE $E63A
.,E628 A5 CA    LDA $CA         get the input cursor column
.,E62A 85 D3    STA $D3         save the cursor column
.,E62C C5 C8    CMP $C8         compare the cursor column with input [EOL] pointer
.,E62E 90 0A    BCC $E63A       if less, cursor is in line, go ??
.,E630 B0 2B    BCS $E65D       else the cursor is beyond the line end, branch always

input from screen or keyboard

.,E632 98       TYA             copy Y
.,E633 48       PHA             save Y
.,E634 8A       TXA             copy X
.,E635 48       PHA             save X
.,E636 A5 D0    LDA $D0         input from keyboard or screen, $xx = screen,
                                $00 = keyboard
.,E638 F0 93    BEQ $E5CD       if keyboard go wait for key
.,E63A A4 D3    LDY $D3         get the cursor column
.,E63C B1 D1    LDA ($D1),Y     get character from the current screen line
.,E63E 85 D7    STA $D7         save temporary last character
.,E640 29 3F    AND #$3F        mask key bits
.,E642 06 D7    ASL $D7         << temporary last character
.,E644 24 D7    BIT $D7         test it
.,E646 10 02    BPL $E64A       branch if not [NO KEY]
.,E648 09 80    ORA #$80
.,E64A 90 04    BCC $E650
.,E64C A6 D4    LDX $D4         get the cursor quote flag, $xx = quote, $00 = no quote
.,E64E D0 04    BNE $E654       if in quote mode go ??
.,E650 70 02    BVS $E654
.,E652 09 40    ORA #$40
.,E654 E6 D3    INC $D3         increment the cursor column
.,E656 20 84 E6 JSR $E684       if open quote toggle the cursor quote flag
.,E659 C4 C8    CPY $C8         compare ?? with input [EOL] pointer
.,E65B D0 17    BNE $E674       if not at line end go ??
.,E65D A9 00    LDA #$00        clear A
.,E65F 85 D0    STA $D0         clear input from keyboard or screen, $xx = screen,
                                $00 = keyboard
.,E661 A9 0D    LDA #$0D        set character [CR]
.,E663 A6 99    LDX $99         get the input device number
.,E665 E0 03    CPX #$03        compare the input device with the screen
.,E667 F0 06    BEQ $E66F       if screen go ??
.,E669 A6 9A    LDX $9A         get the output device number
.,E66B E0 03    CPX #$03        compare the output device with the screen
.,E66D F0 03    BEQ $E672       if screen go ??
.,E66F 20 16 E7 JSR $E716       output the character
.,E672 A9 0D    LDA #$0D        set character [CR]
.,E674 85 D7    STA $D7         save character
.,E676 68       PLA             pull X
.,E677 AA       TAX             restore X
.,E678 68       PLA             pull Y
.,E679 A8       TAY             restore Y
.,E67A A5 D7    LDA $D7         restore character
.,E67C C9 DE    CMP #$DE
.,E67E D0 02    BNE $E682
.,E680 A9 FF    LDA #$FF
.,E682 18       CLC             flag ok
.,E683 60       RTS

if open quote toggle cursor quote flag

.,E684 C9 22    CMP #$22        comapre byte with "
.,E686 D0 08    BNE $E690       exit if not "
.,E688 A5 D4    LDA $D4         get cursor quote flag, $xx = quote, $00 = no quote
.,E68A 49 01    EOR #$01        toggle it
.,E68C 85 D4    STA $D4         save cursor quote flag
.,E68E A9 22    LDA #$22        restore the "
.,E690 60       RTS

insert uppercase/graphic character

.,E691 09 40    ORA #$40        change to uppercase/graphic
.,E693 A6 C7    LDX $C7         get the reverse flag
.,E695 F0 02    BEQ $E699       branch if not reverse
                                else ..
                                insert reversed character
.,E697 09 80    ORA #$80        reverse character
.,E699 A6 D8    LDX $D8         get the insert count
.,E69B F0 02    BEQ $E69F       branch if none
.,E69D C6 D8    DEC $D8         else decrement the insert count
.,E69F AE 86 02 LDX $0286       get the current colour code
.,E6A2 20 13 EA JSR $EA13       print character A and colour X
.,E6A5 20 B6 E6 JSR $E6B6       advance the cursor
                                restore the registers, set the quote flag and exit
.,E6A8 68       PLA             pull Y
.,E6A9 A8       TAY             restore Y
.,E6AA A5 D8    LDA $D8         get the insert count
.,E6AC F0 02    BEQ $E6B0       skip quote flag clear if inserts to do
.,E6AE 46 D4    LSR $D4         clear cursor quote flag, $xx = quote, $00 = no quote
.,E6B0 68       PLA             pull X
.,E6B1 AA       TAX             restore X
.,E6B2 68       PLA             restore A
.,E6B3 18       CLC
.,E6B4 58       CLI             enable the interrupts
.,E6B5 60       RTS

advance the cursor

.,E6B6 20 B3 E8 JSR $E8B3       test for line increment
.,E6B9 E6 D3    INC $D3         increment the cursor column
.,E6BB A5 D5    LDA $D5         get current screen line length
.,E6BD C5 D3    CMP $D3         compare ?? with the cursor column
.,E6BF B0 3F    BCS $E700       exit if line length >= cursor column
.,E6C1 C9 4F    CMP #$4F        compare with max length
.,E6C3 F0 32    BEQ $E6F7       if at max clear column, back cursor up and do newline
.,E6C5 AD 92 02 LDA $0292       get the autoscroll flag
.,E6C8 F0 03    BEQ $E6CD       branch if autoscroll on
.,E6CA 4C 67 E9 JMP $E967       else open space on screen
.,E6CD A6 D6    LDX $D6         get the cursor row
.,E6CF E0 19    CPX #$19        compare with max + 1
.,E6D1 90 07    BCC $E6DA       if less than max + 1 go add this row to the current
                                logical line
.,E6D3 20 EA E8 JSR $E8EA       else scroll the screen
.,E6D6 C6 D6    DEC $D6         decrement the cursor row
.,E6D8 A6 D6    LDX $D6         get the cursor row
                                add this row to the current logical line
.,E6DA 16 D9    ASL $D9,X       shift start of line X pointer high byte
.,E6DC 56 D9    LSR $D9,X       shift start of line X pointer high byte back,
                                make next screen line start of logical line, increment line length and set pointers
                                clear b7, start of logical line
.,E6DE E8       INX             increment screen row
.,E6DF B5 D9    LDA $D9,X       get start of line X pointer high byte
.,E6E1 09 80    ORA #$80        mark as start of logical line
.,E6E3 95 D9    STA $D9,X       set start of line X pointer high byte
.,E6E5 CA       DEX             restore screen row
.,E6E6 A5 D5    LDA $D5         get current screen line length
                                add one line length and set the pointers for the start of the line
.,E6E8 18       CLC             clear carry for add
.,E6E9 69 28    ADC #$28        add one line length
.,E6EB 85 D5    STA $D5         save current screen line length
.,E6ED B5 D9    LDA $D9,X       get start of line X pointer high byte
.,E6EF 30 03    BMI $E6F4       exit loop if start of logical line
.,E6F1 CA       DEX             else back up one line
.,E6F2 D0 F9    BNE $E6ED       loop if not on first line
.,E6F4 4C F0 E9 JMP $E9F0       fetch a screen address
.,E6F7 C6 D6    DEC $D6         decrement the cursor row
.,E6F9 20 7C E8 JSR $E87C       do newline
.,E6FC A9 00    LDA #$00        clear A
.,E6FE 85 D3    STA $D3         clear the cursor column
.,E700 60       RTS

back onto the previous line if possible

.,E701 A6 D6    LDX $D6         get the cursor row
.,E703 D0 06    BNE $E70B       branch if not top row
.,E705 86 D3    STX $D3         clear cursor column
.,E707 68       PLA             dump return address low byte
.,E708 68       PLA             dump return address high byte
.,E709 D0 9D    BNE $E6A8       restore registers, set quote flag and exit, branch always
.,E70B CA       DEX             decrement the cursor row
.,E70C 86 D6    STX $D6         save the cursor row
.,E70E 20 6C E5 JSR $E56C       set the screen pointers for cursor row, column
.,E711 A4 D5    LDY $D5         get current screen line length
.,E713 84 D3    STY $D3         save the cursor column
.,E715 60       RTS

output a character to the screen

.,E716 48       PHA             save character
.,E717 85 D7    STA $D7         save temporary last character
.,E719 8A       TXA             copy X
.,E71A 48       PHA             save X
.,E71B 98       TYA             copy Y
.,E71C 48       PHA             save Y
.,E71D A9 00    LDA #$00        clear A
.,E71F 85 D0    STA $D0         clear input from keyboard or screen, $xx = screen,
                                $00 = keyboard
.,E721 A4 D3    LDY $D3         get cursor column
.,E723 A5 D7    LDA $D7         restore last character
.,E725 10 03    BPL $E72A       branch if unshifted
.,E727 4C D4 E7 JMP $E7D4       do shifted characters and return
.,E72A C9 0D    CMP #$0D        compare with [CR]
.,E72C D0 03    BNE $E731       branch if not [CR]
.,E72E 4C 91 E8 JMP $E891       else output [CR] and return
.,E731 C9 20    CMP #$20        compare with [SPACE]
.,E733 90 10    BCC $E745       branch if < [SPACE]
.,E735 C9 60    CMP #$60
.,E737 90 04    BCC $E73D       branch if $20 to $5F
                                character is $60 or greater
.,E739 29 DF    AND #$DF
.,E73B D0 02    BNE $E73F
.,E73D 29 3F    AND #$3F
.,E73F 20 84 E6 JSR $E684       if open quote toggle cursor direct/programmed flag
.,E742 4C 93 E6 JMP $E693
                                character was < [SPACE] so is a control character
                                of some sort
.,E745 A6 D8    LDX $D8         get the insert count
.,E747 F0 03    BEQ $E74C       if no characters to insert continue
.,E749 4C 97 E6 JMP $E697       insert reversed character
.,E74C C9 14    CMP #$14        compare the character with [INSERT]/[DELETE]
.,E74E D0 2E    BNE $E77E       if not [INSERT]/[DELETE] go ??
.,E750 98       TYA
.,E751 D0 06    BNE $E759
.,E753 20 01 E7 JSR $E701       back onto the previous line if possible
.,E756 4C 73 E7 JMP $E773
.,E759 20 A1 E8 JSR $E8A1       test for line decrement
                                now close up the line
.,E75C 88       DEY             decrement index to previous character
.,E75D 84 D3    STY $D3         save the cursor column
.,E75F 20 24 EA JSR $EA24       calculate the pointer to colour RAM
.,E762 C8       INY             increment index to next character
.,E763 B1 D1    LDA ($D1),Y     get character from current screen line
.,E765 88       DEY             decrement index to previous character
.,E766 91 D1    STA ($D1),Y     save character to current screen line
.,E768 C8       INY             increment index to next character
.,E769 B1 F3    LDA ($F3),Y     get colour RAM byte
.,E76B 88       DEY             decrement index to previous character
.,E76C 91 F3    STA ($F3),Y     save colour RAM byte
.,E76E C8       INY             increment index to next character
.,E76F C4 D5    CPY $D5         compare with current screen line length
.,E771 D0 EF    BNE $E762       loop if not there yet
.,E773 A9 20    LDA #$20        set [SPACE]
.,E775 91 D1    STA ($D1),Y     clear last character on current screen line
.,E777 AD 86 02 LDA $0286       get the current colour code
.,E77A 91 F3    STA ($F3),Y     save to colour RAM
.,E77C 10 4D    BPL $E7CB       branch always
.,E77E A6 D4    LDX $D4         get cursor quote flag, $xx = quote, $00 = no quote
.,E780 F0 03    BEQ $E785       branch if not quote mode
.,E782 4C 97 E6 JMP $E697       insert reversed character
.,E785 C9 12    CMP #$12        compare with [RVS ON]
.,E787 D0 02    BNE $E78B       if not [RVS ON] skip setting the reverse flag
.,E789 85 C7    STA $C7         else set the reverse flag
.,E78B C9 13    CMP #$13        compare with [CLR HOME]
.,E78D D0 03    BNE $E792       if not [CLR HOME] continue
.,E78F 20 66 E5 JSR $E566       home the cursor
.,E792 C9 1D    CMP #$1D        compare with [CURSOR RIGHT]
.,E794 D0 17    BNE $E7AD       if not [CURSOR RIGHT] go ??
.,E796 C8       INY             increment the cursor column
.,E797 20 B3 E8 JSR $E8B3       test for line increment
.,E79A 84 D3    STY $D3         save the cursor column
.,E79C 88       DEY             decrement the cursor column
.,E79D C4 D5    CPY $D5         compare cursor column with current screen line length
.,E79F 90 09    BCC $E7AA       exit if less
                                else the cursor column is >= the current screen line
                                length so back onto the current line and do a newline
.,E7A1 C6 D6    DEC $D6         decrement the cursor row
.,E7A3 20 7C E8 JSR $E87C       do newline
.,E7A6 A0 00    LDY #$00        clear cursor column
.,E7A8 84 D3    STY $D3         save the cursor column
.,E7AA 4C A8 E6 JMP $E6A8       restore the registers, set the quote flag and exit
.,E7AD C9 11    CMP #$11        compare with [CURSOR DOWN]
.,E7AF D0 1D    BNE $E7CE       if not [CURSOR DOWN] go ??
.,E7B1 18       CLC             clear carry for add
.,E7B2 98       TYA             copy the cursor column
.,E7B3 69 28    ADC #$28        add one line
.,E7B5 A8       TAY             copy back to Y
.,E7B6 E6 D6    INC $D6         increment the cursor row
.,E7B8 C5 D5    CMP $D5         compare cursor column with current screen line length
.,E7BA 90 EC    BCC $E7A8       if less go save cursor column and exit
.,E7BC F0 EA    BEQ $E7A8       if equal go save cursor column and exit
                                else the cursor has moved beyond the end of this line
                                so back it up until it's on the start of the logical line
.,E7BE C6 D6    DEC $D6         decrement the cursor row
.,E7C0 E9 28    SBC #$28        subtract one line
.,E7C2 90 04    BCC $E7C8       if on previous line exit the loop
.,E7C4 85 D3    STA $D3         else save the cursor column
.,E7C6 D0 F8    BNE $E7C0       loop if not at the start of the line
.,E7C8 20 7C E8 JSR $E87C       do newline
.,E7CB 4C A8 E6 JMP $E6A8       restore the registers, set the quote flag and exit
.,E7CE 20 CB E8 JSR $E8CB       set the colour code
.,E7D1 4C 44 EC JMP $EC44       go check for special character codes
.,E7D4 29 7F    AND #$7F        mask 0xxx xxxx, clear b7
.,E7D6 C9 7F    CMP #$7F        was it $FF before the mask
.,E7D8 D0 02    BNE $E7DC       branch if not
.,E7DA A9 5E    LDA #$5E        else make it $5E
.,E7DC C9 20    CMP #$20        compare the character with [SPACE]
.,E7DE 90 03    BCC $E7E3       if < [SPACE] go ??
.,E7E0 4C 91 E6 JMP $E691       insert uppercase/graphic character and return
                                character was $80 to $9F and is now $00 to $1F
.,E7E3 C9 0D    CMP #$0D        compare with [CR]
.,E7E5 D0 03    BNE $E7EA       if not [CR] continue
.,E7E7 4C 91 E8 JMP $E891       else output [CR] and return
                                was not [CR]
.,E7EA A6 D4    LDX $D4         get the cursor quote flag, $xx = quote, $00 = no quote
.,E7EC D0 3F    BNE $E82D       branch if quote mode
.,E7EE C9 14    CMP #$14        compare with [INSERT DELETE]
.,E7F0 D0 37    BNE $E829       if not [INSERT DELETE] go ??
.,E7F2 A4 D5    LDY $D5         get current screen line length
.,E7F4 B1 D1    LDA ($D1),Y     get character from current screen line
.,E7F6 C9 20    CMP #$20        compare the character with [SPACE]
.,E7F8 D0 04    BNE $E7FE       if not [SPACE] continue
.,E7FA C4 D3    CPY $D3         compare the current column with the cursor column
.,E7FC D0 07    BNE $E805       if not cursor column go open up space on line
.,E7FE C0 4F    CPY #$4F        compare current column with max line length
.,E800 F0 24    BEQ $E826       if at line end just exit
.,E802 20 65 E9 JSR $E965       else open up a space on the screen
                                now open up space on the line to insert a character
.,E805 A4 D5    LDY $D5         get current screen line length
.,E807 20 24 EA JSR $EA24       calculate the pointer to colour RAM
.,E80A 88       DEY             decrement the index to previous character
.,E80B B1 D1    LDA ($D1),Y     get the character from the current screen line
.,E80D C8       INY             increment the index to next character
.,E80E 91 D1    STA ($D1),Y     save the character to the current screen line
.,E810 88       DEY             decrement the index to previous character
.,E811 B1 F3    LDA ($F3),Y     get the current screen line colour RAM byte
.,E813 C8       INY             increment the index to next character
.,E814 91 F3    STA ($F3),Y     save the current screen line colour RAM byte
.,E816 88       DEY             decrement the index to the previous character
.,E817 C4 D3    CPY $D3         compare the index with the cursor column
.,E819 D0 EF    BNE $E80A       loop if not there yet
.,E81B A9 20    LDA #$20        set [SPACE]
.,E81D 91 D1    STA ($D1),Y     clear character at cursor position on current screen line
.,E81F AD 86 02 LDA $0286       get current colour code
.,E822 91 F3    STA ($F3),Y     save to cursor position on current screen line colour RAM
.,E824 E6 D8    INC $D8         increment insert count
.,E826 4C A8 E6 JMP $E6A8       restore the registers, set the quote flag and exit
.,E829 A6 D8    LDX $D8         get the insert count
.,E82B F0 05    BEQ $E832       branch if no insert space
.,E82D 09 40    ORA #$40        change to uppercase/graphic
.,E82F 4C 97 E6 JMP $E697       insert reversed character
.,E832 C9 11    CMP #$11        compare with [CURSOR UP]
.,E834 D0 16    BNE $E84C       branch if not [CURSOR UP]
.,E836 A6 D6    LDX $D6         get the cursor row
.,E838 F0 37    BEQ $E871       if on the top line go restore the registers, set the
                                quote flag and exit
.,E83A C6 D6    DEC $D6         decrement the cursor row
.,E83C A5 D3    LDA $D3         get the cursor column
.,E83E 38       SEC             set carry for subtract
.,E83F E9 28    SBC #$28        subtract one line length
.,E841 90 04    BCC $E847       branch if stepped back to previous line
.,E843 85 D3    STA $D3         else save the cursor column ..
.,E845 10 2A    BPL $E871       .. and exit, branch always
.,E847 20 6C E5 JSR $E56C       set the screen pointers for cursor row, column ..
.,E84A D0 25    BNE $E871       .. and exit, branch always
.,E84C C9 12    CMP #$12        compare with [RVS OFF]
.,E84E D0 04    BNE $E854       if not [RVS OFF] continue
.,E850 A9 00    LDA #$00        else clear A
.,E852 85 C7    STA $C7         clear the reverse flag
.,E854 C9 1D    CMP #$1D        compare with [CURSOR LEFT]
.,E856 D0 12    BNE $E86A       if not [CURSOR LEFT] go ??
.,E858 98       TYA             copy the cursor column
.,E859 F0 09    BEQ $E864       if at start of line go back onto the previous line
.,E85B 20 A1 E8 JSR $E8A1       test for line decrement
.,E85E 88       DEY             decrement the cursor column
.,E85F 84 D3    STY $D3         save the cursor column
.,E861 4C A8 E6 JMP $E6A8       restore the registers, set the quote flag and exit
.,E864 20 01 E7 JSR $E701       back onto the previous line if possible
.,E867 4C A8 E6 JMP $E6A8       restore the registers, set the quote flag and exit
.,E86A C9 13    CMP #$13        compare with [CLR]
.,E86C D0 06    BNE $E874       if not [CLR] continue
.,E86E 20 44 E5 JSR $E544       clear the screen
.,E871 4C A8 E6 JMP $E6A8       restore the registers, set the quote flag and exit
.,E874 09 80    ORA #$80        restore b7, colour can only be black, cyan, magenta
                                or yellow
.,E876 20 CB E8 JSR $E8CB       set the colour code
.,E879 4C 4F EC JMP $EC4F       go check for special character codes except fro switch
                                to lower case

do newline

.,E87C 46 C9    LSR $C9         shift >> input cursor row
.,E87E A6 D6    LDX $D6         get the cursor row
.,E880 E8       INX             increment the row
.,E881 E0 19    CPX #$19        compare it with last row + 1
.,E883 D0 03    BNE $E888       if not last row + 1 skip the screen scroll
.,E885 20 EA E8 JSR $E8EA       else scroll the screen
.,E888 B5 D9    LDA $D9,X       get start of line X pointer high byte
.,E88A 10 F4    BPL $E880       loop if not start of logical line
.,E88C 86 D6    STX $D6         save the cursor row
.,E88E 4C 6C E5 JMP $E56C       set the screen pointers for cursor row, column and return

output [CR]

.,E891 A2 00    LDX #$00        clear X
.,E893 86 D8    STX $D8         clear the insert count
.,E895 86 C7    STX $C7         clear the reverse flag
.,E897 86 D4    STX $D4         clear the cursor quote flag, $xx = quote, $00 = no quote
.,E899 86 D3    STX $D3         save the cursor column
.,E89B 20 7C E8 JSR $E87C       do newline
.,E89E 4C A8 E6 JMP $E6A8       restore the registers, set the quote flag and exit

test for line decrement

.,E8A1 A2 02    LDX #$02        set the count
.,E8A3 A9 00    LDA #$00        set the column
.,E8A5 C5 D3    CMP $D3         compare the column with the cursor column
.,E8A7 F0 07    BEQ $E8B0       if at the start of the line go decrement the cursor row
                                and exit
.,E8A9 18       CLC             else clear carry for add
.,E8AA 69 28    ADC #$28        increment to next line
.,E8AC CA       DEX             decrement loop count
.,E8AD D0 F6    BNE $E8A5       loop if more to test
.,E8AF 60       RTS
.,E8B0 C6 D6    DEC $D6         else decrement the cursor row
.,E8B2 60       RTS

test for line increment


                                if at end of the line, but not at end of the last line, increment the cursor row
.,E8B3 A2 02    LDX #$02        set the count
.,E8B5 A9 27    LDA #$27        set the column
.,E8B7 C5 D3    CMP $D3         compare the column with the cursor column
.,E8B9 F0 07    BEQ $E8C2       if at end of line test and possibly increment cursor row
.,E8BB 18       CLC             else clear carry for add
.,E8BC 69 28    ADC #$28        increment to the next line
.,E8BE CA       DEX             decrement the loop count
.,E8BF D0 F6    BNE $E8B7       loop if more to test
.,E8C1 60       RTS
                                cursor is at end of line
.,E8C2 A6 D6    LDX $D6         get the cursor row
.,E8C4 E0 19    CPX #$19        compare it with the end of the screen
.,E8C6 F0 02    BEQ $E8CA       if at the end of screen just exit
.,E8C8 E6 D6    INC $D6         else increment the cursor row
.,E8CA 60       RTS

set the colour code. enter with the colour character in A. if A does not contain a

                                colour character this routine exits without changing the colour
.,E8CB A2 0F    LDX #$0F
                                set the colour code count
.,E8CD DD DA E8 CMP $E8DA,X     compare the character with a table code
.,E8D0 F0 04    BEQ $E8D6       if a match go save the colour and exit
.,E8D2 CA       DEX             else decrement the index
.,E8D3 10 F8    BPL $E8CD       loop if more to do
.,E8D5 60       RTS
.,E8D6 8E 86 02 STX $0286       save the current colour code
.,E8D9 60       RTS

ASCII colour code table

                                CHR$()  colour
                                ------  ------
.:E8DA 90                        144    black
.:E8DB 05                          5    white
.:E8DC 1C                         28    red
.:E8DD 9F                        159    cyan
.:E8DE 9C                        156    purple
.:E8DF 1E                         30    green
.:E8E0 1F                         31    blue
.:E8E1 9E                        158    yellow
.:E8E2 81                        129    orange
.:E8E3 95                        149    brown
.:E8E4 96                        150    light red
.:E8E5 97                        151    dark grey
.:E8E6 98                        152    medium grey
.:E8E7 99                        153    light green
.:E8E8 9A                        154    light blue
.:E8E9 9B                        155    light grey

scroll the screen

.,E8EA A5 AC    LDA $AC         copy the tape buffer start pointer
.,E8EC 48       PHA             save it
.,E8ED A5 AD    LDA $AD         copy the tape buffer start pointer
.,E8EF 48       PHA             save it
.,E8F0 A5 AE    LDA $AE         copy the tape buffer end pointer
.,E8F2 48       PHA             save it
.,E8F3 A5 AF    LDA $AF         copy the tape buffer end pointer
.,E8F5 48       PHA             save it
.,E8F6 A2 FF    LDX #$FF        set to -1 for pre increment loop
.,E8F8 C6 D6    DEC $D6         decrement the cursor row
.,E8FA C6 C9    DEC $C9         decrement the input cursor row
.,E8FC CE A5 02 DEC $02A5       decrement the screen row marker
.,E8FF E8       INX             increment the line number
.,E900 20 F0 E9 JSR $E9F0       fetch a screen address, set the start of line X
.,E903 E0 18    CPX #$18        compare with last line
.,E905 B0 0C    BCS $E913       branch if >= $16
.,E907 BD F1 EC LDA $ECF1,X     get the start of the next line pointer low byte
.,E90A 85 AC    STA $AC         save the next line pointer low byte
.,E90C B5 DA    LDA $DA,X       get the start of the next line pointer high byte
.,E90E 20 C8 E9 JSR $E9C8       shift the screen line up
.,E911 30 EC    BMI $E8FF       loop, branch always
.,E913 20 FF E9 JSR $E9FF       clear screen line X
                                now shift up the start of logical line bits
.,E916 A2 00    LDX #$00        clear index
.,E918 B5 D9    LDA $D9,X       get the start of line X pointer high byte
.,E91A 29 7F    AND #$7F        clear the line X start of logical line bit
.,E91C B4 DA    LDY $DA,X       get the start of the next line pointer high byte
.,E91E 10 02    BPL $E922       if next line is not a start of line skip the start set
.,E920 09 80    ORA #$80        set line X start of logical line bit
.,E922 95 D9    STA $D9,X       set start of line X pointer high byte
.,E924 E8       INX             increment line number
.,E925 E0 18    CPX #$18        compare with last line
.,E927 D0 EF    BNE $E918       loop if not last line
.,E929 A5 F1    LDA $F1         get start of last line pointer high byte
.,E92B 09 80    ORA #$80        mark as start of logical line
.,E92D 85 F1    STA $F1         set start of last line pointer high byte
.,E92F A5 D9    LDA $D9         get start of first line pointer high byte
.,E931 10 C3    BPL $E8F6       if not start of logical line loop back and
                                scroll the screen up another line
.,E933 E6 D6    INC $D6         increment the cursor row
.,E935 EE A5 02 INC $02A5       increment screen row marker
.,E938 A9 7F    LDA #$7F        set keyboard column c7
.,E93A 8D 00 DC STA $DC00       save VIA 1 DRA, keyboard column drive
.,E93D AD 01 DC LDA $DC01       read VIA 1 DRB, keyboard row port
.,E940 C9 FB    CMP #$FB        compare with row r2 active, [CTL]
.,E942 08       PHP             save status
.,E943 A9 7F    LDA #$7F        set keyboard column c7
.,E945 8D 00 DC STA $DC00       save VIA 1 DRA, keyboard column drive
.,E948 28       PLP             restore status
.,E949 D0 0B    BNE $E956       skip delay if ??
                                first time round the inner loop X will be $16
.,E94B A0 00    LDY #$00        clear delay outer loop count, do this 256 times
.,E94D EA       NOP             waste cycles
.,E94E CA       DEX             decrement inner loop count
.,E94F D0 FC    BNE $E94D       loop if not all done
.,E951 88       DEY             decrement outer loop count
.,E952 D0 F9    BNE $E94D       loop if not all done
.,E954 84 C6    STY $C6         clear the keyboard buffer index
.,E956 A6 D6    LDX $D6         get the cursor row
                                restore the tape buffer pointers and exit
.,E958 68       PLA             pull tape buffer end pointer
.,E959 85 AF    STA $AF         restore it
.,E95B 68       PLA             pull tape buffer end pointer
.,E95C 85 AE    STA $AE         restore it
.,E95E 68       PLA             pull tape buffer pointer
.,E95F 85 AD    STA $AD         restore it
.,E961 68       PLA             pull tape buffer pointer
.,E962 85 AC    STA $AC         restore it
.,E964 60       RTS

open up a space on the screen

.,E965 A6 D6    LDX $D6         get the cursor row
.,E967 E8       INX             increment the row
.,E968 B5 D9    LDA $D9,X       get the start of line X pointer high byte
.,E96A 10 FB    BPL $E967       loop if not start of logical line
.,E96C 8E A5 02 STX $02A5       save the screen row marker
.,E96F E0 18    CPX #$18        compare it with the last line
.,E971 F0 0E    BEQ $E981       if = last line go ??
.,E973 90 0C    BCC $E981       if < last line go ??
                                else it was > last line
.,E975 20 EA E8 JSR $E8EA       scroll the screen
.,E978 AE A5 02 LDX $02A5       get the screen row marker
.,E97B CA       DEX             decrement the screen row marker
.,E97C C6 D6    DEC $D6         decrement the cursor row
.,E97E 4C DA E6 JMP $E6DA       add this row to the current logical line and return
.,E981 A5 AC    LDA $AC         copy tape buffer pointer
.,E983 48       PHA             save it
.,E984 A5 AD    LDA $AD         copy tape buffer pointer
.,E986 48       PHA             save it
.,E987 A5 AE    LDA $AE         copy tape buffer end pointer
.,E989 48       PHA             save it
.,E98A A5 AF    LDA $AF         copy tape buffer end pointer
.,E98C 48       PHA             save it
.,E98D A2 19    LDX #$19        set to end line + 1 for predecrement loop
.,E98F CA       DEX             decrement the line number
.,E990 20 F0 E9 JSR $E9F0       fetch a screen address
.,E993 EC A5 02 CPX $02A5       compare it with the screen row marker
.,E996 90 0E    BCC $E9A6       if < screen row marker go ??
.,E998 F0 0C    BEQ $E9A6       if = screen row marker go ??
.,E99A BD EF EC LDA $ECEF,X     else get the start of the previous line low byte from the
                                ROM table
.,E99D 85 AC    STA $AC         save previous line pointer low byte
.,E99F B5 D8    LDA $D8,X       get the start of the previous line pointer high byte
.,E9A1 20 C8 E9 JSR $E9C8       shift the screen line down
.,E9A4 30 E9    BMI $E98F       loop, branch always
.,E9A6 20 FF E9 JSR $E9FF       clear screen line X
.,E9A9 A2 17    LDX #$17
.,E9AB EC A5 02 CPX $02A5       compare it with the screen row marker
.,E9AE 90 0F    BCC $E9BF
.,E9B0 B5 DA    LDA $DA,X
.,E9B2 29 7F    AND #$7F
.,E9B4 B4 D9    LDY $D9,X       get start of line X pointer high byte
.,E9B6 10 02    BPL $E9BA
.,E9B8 09 80    ORA #$80
.,E9BA 95 DA    STA $DA,X
.,E9BC CA       DEX
.,E9BD D0 EC    BNE $E9AB
.,E9BF AE A5 02 LDX $02A5       get the screen row marker
.,E9C2 20 DA E6 JSR $E6DA       add this row to the current logical line
.,E9C5 4C 58 E9 JMP $E958       restore the tape buffer pointers and exit

shift screen line up/down

.,E9C8 29 03    AND #$03        mask 0000 00xx, line memory page
.,E9CA 0D 88 02 ORA $0288       OR with screen memory page
.,E9CD 85 AD    STA $AD         save next/previous line pointer high byte
.,E9CF 20 E0 E9 JSR $E9E0       calculate pointers to screen lines colour RAM
.,E9D2 A0 27    LDY #$27        set the column count
.,E9D4 B1 AC    LDA ($AC),Y     get character from next/previous screen line
.,E9D6 91 D1    STA ($D1),Y     save character to current screen line
.,E9D8 B1 AE    LDA ($AE),Y     get colour from next/previous screen line colour RAM
.,E9DA 91 F3    STA ($F3),Y     save colour to current screen line colour RAM
.,E9DC 88       DEY             decrement column index/count
.,E9DD 10 F5    BPL $E9D4       loop if more to do
.,E9DF 60       RTS

calculate pointers to screen lines colour RAM

.,E9E0 20 24 EA JSR $EA24       calculate the pointer to the current screen line colour
                                RAM
.,E9E3 A5 AC    LDA $AC         get the next screen line pointer low byte
.,E9E5 85 AE    STA $AE         save the next screen line colour RAM pointer low byte
.,E9E7 A5 AD    LDA $AD         get the next screen line pointer high byte
.,E9E9 29 03    AND #$03        mask 0000 00xx, line memory page
.,E9EB 09 D8    ORA #$D8        set  1101 01xx, colour memory page
.,E9ED 85 AF    STA $AF         save the next screen line colour RAM pointer high byte
.,E9EF 60       RTS

fetch a screen address

.,E9F0 BD F0 EC LDA $ECF0,X     get the start of line low byte from the ROM table
.,E9F3 85 D1    STA $D1         set the current screen line pointer low byte
.,E9F5 B5 D9    LDA $D9,X       get the start of line high byte from the RAM table
.,E9F7 29 03    AND #$03        mask 0000 00xx, line memory page
.,E9F9 0D 88 02 ORA $0288       OR with the screen memory page
.,E9FC 85 D2    STA $D2         save the current screen line pointer high byte
.,E9FE 60       RTS

clear screen line X

.,E9FF A0 27    LDY #$27        set number of columns to clear
.,EA01 20 F0 E9 JSR $E9F0       fetch a screen address
.,EA04 20 24 EA JSR $EA24       calculate the pointer to colour RAM
.,EA07 20 DA E4 JSR $E4DA       save the current colour to the colour RAM
.,EA0A A9 20    LDA #$20        set [SPACE]
.,EA0C 91 D1    STA ($D1),Y     clear character in current screen line
.,EA0E 88       DEY             decrement index
.,EA0F 10 F6    BPL $EA07       loop if more to do
.,EA11 60       RTS

orphan byte

.,EA12 EA       NOP             unused

print character A and colour X

.,EA13 A8       TAY             copy the character
.,EA14 A9 02    LDA #$02set the count to $02, usually $14 ??
.,EA16 85 CD    STA $CD         save the cursor countdown
.,EA18 20 24 EA JSR $EA24       calculate the pointer to colour RAM
.,EA1B 98       TYA             get the character back

save the character and colour to the screen @ the cursor

.,EA1C A4 D3    LDY $D3         get the cursor column
.,EA1E 91 D1    STA ($D1),Y     save the character from current screen line
.,EA20 8A       TXA             copy the colour to A
.,EA21 91 F3    STA ($F3),Y     save to colour RAM
.,EA23 60       RTS

calculate the pointer to colour RAM

.,EA24 A5 D1    LDA $D1         get current screen line pointer low byte
.,EA26 85 F3    STA $F3         save pointer to colour RAM low byte
.,EA28 A5 D2    LDA $D2         get current screen line pointer high byte
.,EA2A 29 03    AND #$03        mask 0000 00xx, line memory page
.,EA2C 09 D8    ORA #$D8        set  1101 01xx, colour memory page
.,EA2E 85 F4    STA $F4         save pointer to colour RAM high byte
.,EA30 60       RTS

IRQ vector

.,EA31 20 EA FF JSR $FFEA       increment the real time clock
.,EA34 A5 CC    LDA $CC         get the cursor enable, $00 = flash cursor
.,EA36 D0 29    BNE $EA61       if flash not enabled skip the flash
.,EA38 C6 CD    DEC $CD         decrement the cursor timing countdown
.,EA3A D0 25    BNE $EA61       if not counted out skip the flash
.,EA3C A9 14    LDA #$14        set the flash count
.,EA3E 85 CD    STA $CD         save the cursor timing countdown
.,EA40 A4 D3    LDY $D3         get the cursor column
.,EA42 46 CF    LSR $CF         shift b0 cursor blink phase into carry
.,EA44 AE 87 02 LDX $0287       get the colour under the cursor
.,EA47 B1 D1    LDA ($D1),Y     get the character from current screen line
.,EA49 B0 11    BCS $EA5C       branch if cursor phase b0 was 1
.,EA4B E6 CF    INC $CF         set the cursor blink phase to 1
.,EA4D 85 CE    STA $CE         save the character under the cursor
.,EA4F 20 24 EA JSR $EA24       calculate the pointer to colour RAM
.,EA52 B1 F3    LDA ($F3),Y     get the colour RAM byte
.,EA54 8D 87 02 STA $0287       save the colour under the cursor
.,EA57 AE 86 02 LDX $0286       get the current colour code
.,EA5A A5 CE    LDA $CE         get the character under the cursor
.,EA5C 49 80    EOR #$80        toggle b7 of character under cursor
.,EA5E 20 1C EA JSR $EA1C       save the character and colour to the screen @ the cursor
.,EA61 A5 01    LDA $01         read the 6510 I/O port
.,EA63 29 10    AND #$10        mask 000x 0000, the cassette switch sense
.,EA65 F0 0A    BEQ $EA71       if the cassette sense is low skip the motor stop
                                the cassette sense was high, the switch was open, so turn
                                off the motor and clear the interlock
.,EA67 A0 00    LDY #$00        clear Y
.,EA69 84 C0    STY $C0         clear the tape motor interlock
.,EA6B A5 01    LDA $01         read the 6510 I/O port
.,EA6D 09 20    ORA #$20        mask xxxx xx1x, turn off the motor
.,EA6F D0 08    BNE $EA79       go save the port value, branch always
                                the cassette sense was low so turn the motor on, perhaps
.,EA71 A5 C0    LDA $C0         get the tape motor interlock
.,EA73 D0 06    BNE $EA7B       if the cassette interlock <> 0 don't turn on motor
.,EA75 A5 01    LDA $01         read the 6510 I/O port
.,EA77 29 1F    AND #$1F        mask xxxx xx0x, turn on the motor
.,EA79 85 01    STA $01         save the 6510 I/O port
.,EA7B 20 87 EA JSR $EA87       scan the keyboard
.,EA7E AD 0D DC LDA $DC0D       read VIA 1 ICR, clear the timer interrupt flag
.,EA81 68       PLA             pull Y
.,EA82 A8       TAY             restore Y
.,EA83 68       PLA             pull X
.,EA84 AA       TAX             restore X
.,EA85 68       PLA             restore A
.,EA86 40       RTI

scan keyboard performs the following ..


                                1) check if key pressed, if not then exit the routine

                                2) init I/O ports of VIA ?? for keyboard scan and set pointers to decode table 1.
                                clear the character counter

                                3) set one line of port B low and test for a closed key on port A by shifting the
                                byte read from the port. if the carry is clear then a key is closed so save the
                                count which is incremented on each shift. check for shift/stop/cbm keys and
                                flag if closed

                                4) repeat step 3 for the whole matrix

                                5) evaluate the SHIFT/CTRL/C= keys, this may change the decode table selected

                                6) use the key count saved in step 3 as an index into the table selected in step 5

                                7) check for key repeat operation

                                8) save the decoded key to the buffer if first press or repeat
                                scan the keyboard
.,EA87 A9 00    LDA #$00clear A
.,EA89 8D 8D 02 STA $028D       clear the keyboard shift/control/c= flag
.,EA8C A0 40    LDY #$40        set no key
.,EA8E 84 CB    STY $CB         save which key
.,EA90 8D 00 DC STA $DC00       clear VIA 1 DRA, keyboard column drive
.,EA93 AE 01 DC LDX $DC01       read VIA 1 DRB, keyboard row port
.,EA96 E0 FF    CPX #$FF        compare with all bits set
.,EA98 F0 61    BEQ $EAFB       if no key pressed clear current key and exit (does
                                further BEQ to $EBBA)
.,EA9A A8       TAY             clear the key count
.,EA9B A9 81    LDA #$81get the decode table low byte
.,EA9D 85 F5    STA $F5         save the keyboard pointer low byte
.,EA9F A9 EB    LDA #$EB        get the decode table high byte
.,EAA1 85 F6    STA $F6save the keyboard pointer high byte
.,EAA3 A9 FE    LDA #$FE        set column 0 low
.,EAA5 8D 00 DC STA $DC00       save VIA 1 DRA, keyboard column drive
.,EAA8 A2 08    LDX #$08        set the row count
.,EAAA 48       PHA             save the column
.,EAAB AD 01 DC LDA $DC01       read VIA 1 DRB, keyboard row port
.,EAAE CD 01 DC CMP $DC01       compare it with itself
.,EAB1 D0 F8    BNE $EAAB       loop if changing
.,EAB3 4A       LSR             shift row to Cb
.,EAB4 B0 16    BCS $EACC       if no key closed on this row go do next row
.,EAB6 48       PHA             save row
.,EAB7 B1 F5    LDA ($F5),Y     get character from decode table
.,EAB9 C9 05    CMP #$05        compare with $05, there is no $05 key but the control
                                keys are all less than $05
.,EABB B0 0C    BCS $EAC9       if not shift/control/c=/stop go save key count
                                else was shift/control/c=/stop key
.,EABD C9 03    CMP #$03        compare with $03, stop
.,EABF F0 08    BEQ $EAC9       if stop go save key count and continue
                                character is $01 - shift, $02 - c= or $04 - control
.,EAC1 0D 8D 02 ORA $028D       OR it with the keyboard shift/control/c= flag
.,EAC4 8D 8D 02 STA $028D       save the keyboard shift/control/c= flag
.,EAC7 10 02    BPL $EACB       skip save key, branch always
.,EAC9 84 CB    STY $CB         save key count
.,EACB 68       PLA             restore row
.,EACC C8       INY             increment key count
.,EACD C0 41    CPY #$41        compare with max+1
.,EACF B0 0B    BCS $EADC       exit loop if >= max+1
                                else still in matrix
.,EAD1 CA       DEX             decrement row count
.,EAD2 D0 DF    BNE $EAB3       loop if more rows to do
.,EAD4 38       SEC             set carry for keyboard column shift
.,EAD5 68       PLA             restore the column
.,EAD6 2A       ROL             shift the keyboard column
.,EAD7 8D 00 DC STA $DC00       save VIA 1 DRA, keyboard column drive
.,EADA D0 CC    BNE $EAA8       loop for next column, branch always
.,EADC 68       PLA             dump the saved column
.,EADD 6C 8F 02 JMP ($028F)     evaluate the SHIFT/CTRL/C= keys, $EBDC
                                key decoding continues here after the SHIFT/CTRL/C= keys are evaluated
.,EAE0 A4 CB    LDY $CB         get saved key count
.,EAE2 B1 F5    LDA ($F5),Y     get character from decode table
.,EAE4 AA       TAX             copy character to X
.,EAE5 C4 C5    CPY $C5         compare key count with last key count
.,EAE7 F0 07    BEQ $EAF0       if this key = current key, key held, go test repeat
.,EAE9 A0 10    LDY #$10        set the repeat delay count
.,EAEB 8C 8C 02 STY $028C       save the repeat delay count
.,EAEE D0 36    BNE $EB26       go save key to buffer and exit, branch always
.,EAF0 29 7F    AND #$7F        clear b7
.,EAF2 2C 8A 02 BIT $028A       test key repeat
.,EAF5 30 16    BMI $EB0D       if repeat all go ??
.,EAF7 70 49    BVS $EB42       if repeat none go ??
.,EAF9 C9 7F    CMP #$7F        compare with end marker
.,EAFB F0 29    BEQ $EB26       if $00/end marker go save key to buffer and exit
.,EAFD C9 14    CMP #$14        compare with [INSERT]/[DELETE]
.,EAFF F0 0C    BEQ $EB0D       if [INSERT]/[DELETE] go test for repeat
.,EB01 C9 20    CMP #$20        compare with [SPACE]
.,EB03 F0 08    BEQ $EB0D       if [SPACE] go test for repeat
.,EB05 C9 1D    CMP #$1D        compare with [CURSOR RIGHT]
.,EB07 F0 04    BEQ $EB0D       if [CURSOR RIGHT] go test for repeat
.,EB09 C9 11    CMP #$11        compare with [CURSOR DOWN]
.,EB0B D0 35    BNE $EB42       if not [CURSOR DOWN] just exit
                                was one of the cursor movement keys, insert/delete
                                key or the space bar so always do repeat tests
.,EB0D AC 8C 02 LDY $028C       get the repeat delay counter
.,EB10 F0 05    BEQ $EB17       if delay expired go ??
.,EB12 CE 8C 02 DEC $028C       else decrement repeat delay counter
.,EB15 D0 2B    BNE $EB42       if delay not expired go ??
                                repeat delay counter has expired
.,EB17 CE 8B 02 DEC $028B       decrement the repeat speed counter
.,EB1A D0 26    BNE $EB42       branch if repeat speed count not expired
.,EB1C A0 04    LDY #$04        set for 4/60ths of a second
.,EB1E 8C 8B 02 STY $028B       save the repeat speed counter
.,EB21 A4 C6    LDY $C6         get the keyboard buffer index
.,EB23 88       DEY             decrement it
.,EB24 10 1C    BPL $EB42       if the buffer isn't empty just exit
                                else repeat the key immediately
                                possibly save the key to the keyboard buffer. if there was no key pressed or the key
                                was not found during the scan (possibly due to key bounce) then X will be $FF here
.,EB26 A4 CB    LDY $CB         get the key count
.,EB28 84 C5    STY $C5         save it as the current key count
.,EB2A AC 8D 02 LDY $028D       get the keyboard shift/control/c= flag
.,EB2D 8C 8E 02 STY $028E       save it as last keyboard shift pattern
.,EB30 E0 FF    CPX #$FF        compare the character with the table end marker or no key
.,EB32 F0 0E    BEQ $EB42       if it was the table end marker or no key just exit
.,EB34 8A       TXA             copy the character to A
.,EB35 A6 C6    LDX $C6         get the keyboard buffer index
.,EB37 EC 89 02 CPX $0289       compare it with the keyboard buffer size
.,EB3A B0 06    BCS $EB42       if the buffer is full just exit
.,EB3C 9D 77 02 STA $0277,X     save the character to the keyboard buffer
.,EB3F E8       INX             increment the index
.,EB40 86 C6    STX $C6         save the keyboard buffer index
.,EB42 A9 7F    LDA #$7F        enable column 7 for the stop key
.,EB44 8D 00 DC STA $DC00       save VIA 1 DRA, keyboard column drive
.,EB47 60       RTS

evaluate the SHIFT/CTRL/C= keys

.,EB48 AD 8D 02 LDA $028D       get the keyboard shift/control/c= flag
.,EB4B C9 03    CMP #$03        compare with [SHIFT][C=]
.,EB4D D0 15    BNE $EB64       if not [SHIFT][C=] go ??
.,EB4F CD 8E 02 CMP $028E       compare with last
.,EB52 F0 EE    BEQ $EB42       exit if still the same
.,EB54 AD 91 02 LDA $0291       get the shift mode switch $00 = enabled, $80 = locked
.,EB57 30 1D    BMI $EB76       if locked continue keyboard decode
                                toggle text mode
.,EB59 AD 18 D0 LDA $D018       get the start of character memory address
.,EB5C 49 02    EOR #$02        toggle address b1
.,EB5E 8D 18 D0 STA $D018       save the start of character memory address
.,EB61 4C 76 EB JMP $EB76       continue the keyboard decode
                                select keyboard table
.,EB64 0A       ASL             << 1
.,EB65 C9 08    CMP #$08        compare with [CTRL]
.,EB67 90 02    BCC $EB6B       if [CTRL] is not pressed skip the index change
.,EB69 A9 06    LDA #$06        else [CTRL] was pressed so make the index = $06
.,EB6B AA       TAX             copy the index to X
.,EB6C BD 79 EB LDA $EB79,X     get the decode table pointer low byte
.,EB6F 85 F5    STA $F5         save the decode table pointer low byte
.,EB71 BD 7A EB LDA $EB7A,X     get the decode table pointer high byte
.,EB74 85 F6    STA $F6         save the decode table pointer high byte
.,EB76 4C E0 EA JMP $EAE0       continue the keyboard decode

table addresses

.:EB79 81 EB                    standard
.:EB7B C2 EB                    shift
.:EB7D 03 EC                    commodore
.:EB7F 78 EC                    control

standard keyboard table

.:EB81 14 0D 1D 88 85 86 87 11
.:EB89 33 57 41 34 5A 53 45 01
.:EB91 35 52 44 36 43 46 54 58
.:EB99 37 59 47 38 42 48 55 56
.:EBA1 39 49 4A 30 4D 4B 4F 4E
.:EBA9 2B 50 4C 2D 2E 3A 40 2C
.:EBB1 5C 2A 3B 13 01 3D 5E 2F
.:EBB9 31 5F 04 32 20 02 51 03
.:EBC1 FF

shifted keyboard table

.:EBC2 94 8D 9D 8C 89 8A 8B 91
.:EBCA 23 D7 C1 24 DA D3 C5 01
.:EBD2 25 D2 C4 26 C3 C6 D4 D8
.:EBDA 27 D9 C7 28 C2 C8 D5 D6
.:EBE2 29 C9 CA 30 CD CB CF CE
.:EBEA DB D0 CC DD 3E 5B BA 3C
.:EBF2 A9 C0 5D 93 01 3D DE 3F
.:EBFA 21 5F 04 22 A0 02 D1 83
.:EC02 FF

CBM key keyboard table

.:EC03 94 8D 9D 8C 89 8A 8B 91
.:EC0B 96 B3 B0 97 AD AE B1 01
.:EC13 98 B2 AC 99 BC BB A3 BD
.:EC1B 9A B7 A5 9B BF B4 B8 BE
.:EC23 29 A2 B5 30 A7 A1 B9 AA
.:EC2B A6 AF B6 DC 3E 5B A4 3C
.:EC33 A8 DF 5D 93 01 3D DE 3F
.:EC3B 81 5F 04 95 A0 02 AB 83
.:EC43 FF

check for special character codes

.,EC44 C9 0E    CMP #$0E        compare with [SWITCH TO LOWER CASE]
.,EC46 D0 07    BNE $EC4F       if not [SWITCH TO LOWER CASE] skip the switch
.,EC48 AD 18 D0 LDA $D018       get the start of character memory address
.,EC4B 09 02    ORA #$02        mask xxxx xx1x, set lower case characters
.,EC4D D0 09    BNE $EC58       go save the new value, branch always
                                check for special character codes except fro switch to lower case
.,EC4F C9 8E    CMP #$8E        compare with [SWITCH TO UPPER CASE]
.,EC51 D0 0B    BNE $EC5E       if not [SWITCH TO UPPER CASE] go do the [SHIFT]+[C=] key
                                check
.,EC53 AD 18 D0 LDA $D018       get the start of character memory address
.,EC56 29 FD    AND #$FD        mask xxxx xx0x, set upper case characters
.,EC58 8D 18 D0 STA $D018       save the start of character memory address
.,EC5B 4C A8 E6 JMP $E6A8       restore the registers, set the quote flag and exit
                                do the [SHIFT]+[C=] key check
.,EC5E C9 08    CMP #$08        compare with disable [SHIFT][C=]
.,EC60 D0 07    BNE $EC69       if not disable [SHIFT][C=] skip the set
.,EC62 A9 80    LDA #$80        set to lock shift mode switch
.,EC64 0D 91 02 ORA $0291       OR it with the shift mode switch
.,EC67 30 09    BMI $EC72       go save the value, branch always
.,EC69 C9 09    CMP #$09        compare with enable [SHIFT][C=]
.,EC6B D0 EE    BNE $EC5B       exit if not enable [SHIFT][C=]
.,EC6D A9 7F    LDA #$7F        set to unlock shift mode switch
.,EC6F 2D 91 02 AND $0291       AND it with the shift mode switch
.,EC72 8D 91 02 STA $0291       save the shift mode switch $00 = enabled, $80 = locked
.,EC75 4C A8 E6 JMP $E6A8       restore the registers, set the quote flag and exit

control keyboard table

.:EC78 FF FF FF FF FF FF FF FF
.:EC80 1C 17 01 9F 1A 13 05 FF
.:EC88 9C 12 04 1E 03 06 14 18
.:EC90 1F 19 07 9E 02 08 15 16
.:EC98 12 09 0A 92 0D 0B 0F 0E
.:ECA0 FF 10 0C FF FF 1B 00 FF
.:ECA8 1C FF 1D FF FF 1F 1E FF
.:ECB0 90 06 FF 05 FF FF 11 FF
.:ECB8 FF

vic ii chip initialisation values

.:ECB9 00 00                    sprite 0 x,y
.:ECBB 00 00                    sprite 1 x,y
.:ECBD 00 00                    sprite 2 x,y
.:ECBF 00 00                    sprite 3 x,y
.:ECC1 00 00                    sprite 4 x,y
.:ECC3 00 00                    sprite 5 x,y
.:ECC5 00 00                    sprite 6 x,y
.:ECC7 00 00                    sprite 7 x,y
.:ECC9 00                       sprites 0 to 7 x bit 8
.:ECCA 9B                       enable screen, enable 25 rows
                                vertical fine scroll and control
                                bit function
                                --- -------
                                 7  raster compare bit 8
                                 6  1 = enable extended color text mode
                                 5  1 = enable bitmap graphics mode
                                 4  1 = enable screen, 0 = blank screen
                                 3  1 = 25 row display, 0 = 24 row display
                                2-0 vertical scroll count
.:ECCB 37                       raster compare
.:ECCC 00                       light pen x
.:ECCD 00                       light pen y
.:ECCE 00                       sprite 0 to 7 enable
.:ECCF 08                       enable 40 column display
                                horizontal fine scroll and control
                                bit function
                                --- -------
                                7-6 unused
                                 5  1 = vic reset, 0 = vic on
                                 4  1 = enable multicolor mode
                                 3  1 = 40 column display, 0 = 38 column display
                                2-0 horizontal scroll count
.:ECC0 00                       sprite 0 to 7 y expand
.:ECD1 14                       memory control
                                bit function
                                --- -------
                                7-4 video matrix base address
                                3-1 character data base address
                                 0  unused
.:ECD2 0F                       clear all interrupts
                                interrupt flags
                                 7 1 = interrupt
                                6-4 unused
                                 3  1 = light pen interrupt
                                 2  1 = sprite to sprite collision interrupt
                                 1  1 = sprite to foreground collision interrupt
                                 0  1 = raster compare interrupt
.:ECD3 00                       all vic IRQs disabeld
                                IRQ enable
                                bit function
                                --- -------
                                7-4 unused
                                 3  1 = enable light pen
                                 2  1 = enable sprite to sprite collision
                                 1  1 = enable sprite to foreground collision
                                 0  1 = enable raster compare
.:ECD4 00                       sprite 0 to 7 foreground priority
.:ECD5 00                       sprite 0 to 7 multicolour
.:ECD6 00                       sprite 0 to 7 x expand
.:ECD7 00                       sprite 0 to 7 sprite collision
.:ECD8 00                       sprite 0 to 7 foreground collision
.:ECD9 0E                       border colour
.:ECDA 06                       background colour 0
.:ECDB 01                       background colour 1
.:ECDC 02                       background colour 2
.:ECDD 03                       background colour 3
.:ECDE 04                       sprite multicolour 0
.:ECDF 00                       sprite multicolour 1
.:ECD0 01                       sprite 0 colour
.:ECE1 02                       sprite 1 colour
.:ECE2 03                       sprite 2 colour
.:ECE3 04                       sprite 3 colour
.:ECE4 05                       sprite 4 colour
.:ECE5 06                       sprite 5 colour
.:ECE6 07                       sprite 6 colour
                                sprite 7 colour is actually the first character of "LOAD" ($4C)

keyboard buffer for auto load/run

.:ECE7 4C 4F 41 44 0D 52 55 4E  'load (cr) run (cr)'
.:ECEA 44 0D 52 55 4E 0D

low bytes of screen line addresses

.:ECF0 00 28 50 78 A0 C8 F0 18
.:ECF8 40 68 90 B8 E0 08 30 58
.:ED00 80 A8 D0 F8 20 48 70 98
.:ED08 C0

command serial bus device to TALK

.,ED09 09 40    ORA #$40        OR with the TALK command
.:ED0B 2C       .BYTE $2C       makes next line BIT $2009

command devices on the serial bus to LISTEN

.,ED0C 09 20    ORA #$20        OR with the LISTEN command
.,ED0E 20 A4 F0 JSR $F0A4       check RS232 bus idle

send a control character

.,ED11 48       PHA             save device address
.,ED12 24 94    BIT $94         test deferred character flag
.,ED14 10 0A    BPL $ED20       if no defered character continue
.,ED16 38       SEC             else flag EOI
.,ED17 66 A3    ROR $A3         rotate into EOI flag byte
.,ED19 20 40 ED JSR $ED40       Tx byte on serial bus
.,ED1C 46 94    LSR $94         clear deferred character flag
.,ED1E 46 A3    LSR $A3         clear EOI flag
.,ED20 68       PLA             restore the device address

defer a command

.,ED21 85 95    STA $95         save as serial defered character
.,ED23 78       SEI             disable the interrupts
.,ED24 20 97 EE JSR $EE97       set the serial data out high
.,ED27 C9 3F    CMP #$3F        compare read byte with $3F
.,ED29 D0 03    BNE $ED2E       branch if not $3F, this branch will always be taken as
                                after VIA 2's PCR is read it is ANDed with $DF, so the
                                result can never be $3F ??
.,ED2B 20 85 EE JSR $EE85       set the serial clock out high
.,ED2E AD 00 DD LDA $DD00       read VIA 2 DRA, serial port and video address
.,ED31 09 08    ORA #$08        mask xxxx 1xxx, set serial ATN low
.,ED33 8D 00 DD STA $DD00       save VIA 2 DRA, serial port and video address
                                if the code drops through to here the serial clock is low and the serial data has been
                                released so the following code will have no effect apart from delaying the first byte
                                by 1ms
                                set the serial clk/data, wait and Tx byte on the serial bus
.,ED36 78       SEI             disable the interrupts
.,ED37 20 8E EE JSR $EE8E       set the serial clock out low
.,ED3A 20 97 EE JSR $EE97       set the serial data out high
.,ED3D 20 B3 EE JSR $EEB3       1ms delay

Tx byte on serial bus

.,ED40 78       SEI             disable the interrupts
.,ED41 20 97 EE JSR $EE97       set the serial data out high
.,ED44 20 A9 EE JSR $EEA9       get the serial data status in Cb
.,ED47 B0 64    BCS $EDAD       if the serial data is high go do 'device not present'
.,ED49 20 85 EE JSR $EE85       set the serial clock out high
.,ED4C 24 A3    BIT $A3         test the EOI flag
.,ED4E 10 0A    BPL $ED5A       if not EOI go ??
                                I think this is the EOI sequence so the serial clock has been released and the serial
                                data is being held low by the peripheral. first up wait for the serial data to rise
.,ED50 20 A9 EE JSR $EEA9       get the serial data status in Cb
.,ED53 90 FB    BCC $ED50       loop if the data is low
                                now the data is high, EOI is signalled by waiting for at least 200us without pulling
                                the serial clock line low again. the listener should respond by pulling the serial
                                data line low
.,ED55 20 A9 EE JSR $EEA9       get the serial data status in Cb
.,ED58 B0 FB    BCS $ED55       loop if the data is high
                                the serial data has gone low ending the EOI sequence, now just wait for the serial
                                data line to go high again or, if this isn't an EOI sequence, just wait for the serial
                                data to go high the first time
.,ED5A 20 A9 EE JSR $EEA9       get the serial data status in Cb
.,ED5D 90 FB    BCC $ED5A       loop if the data is low
                                serial data is high now pull the clock low, preferably within 60us
.,ED5F 20 8E EE JSR $EE8E       set the serial clock out low
                                now the C64 has to send the eight bits, LSB first. first it sets the serial data line
                                to reflect the bit in the byte, then it sets the serial clock to high. The serial
                                clock is left high for 26 cycles, 23us on a PAL Vic, before it is again pulled low
                                and the serial data is allowed high again
.,ED62 A9 08    LDA #$08        eight bits to do
.,ED64 85 A5    STA $A5         set serial bus bit count
.,ED66 AD 00 DD LDA $DD00       read VIA 2 DRA, serial port and video address
.,ED69 CD 00 DD CMP $DD00       compare it with itself
.,ED6C D0 F8    BNE $ED66       if changed go try again
.,ED6E 0A       ASL             shift the serial data into Cb
.,ED6F 90 3F    BCC $EDB0       if the serial data is low go do serial bus timeout
.,ED71 66 95    ROR $95         rotate the transmit byte
.,ED73 B0 05    BCS $ED7A       if the bit = 1 go set the serial data out high
.,ED75 20 A0 EE JSR $EEA0       else set the serial data out low
.,ED78 D0 03    BNE $ED7D       continue, branch always
.,ED7A 20 97 EE JSR $EE97       set the serial data out high
.,ED7D 20 85 EE JSR $EE85       set the serial clock out high
.,ED80 EA       NOP             waste ..
.,ED81 EA       NOP             .. a ..
.,ED82 EA       NOP             .. cycle ..
.,ED83 EA       NOP             .. or two
.,ED84 AD 00 DD LDA $DD00       read VIA 2 DRA, serial port and video address
.,ED87 29 DF    AND #$DF        mask xx0x xxxx, set the serial data out high
.,ED89 09 10    ORA #$10        mask xxx1 xxxx, set the serial clock out low
.,ED8B 8D 00 DD STA $DD00       save VIA 2 DRA, serial port and video address
.,ED8E C6 A5    DEC $A5         decrement the serial bus bit count
.,ED90 D0 D4    BNE $ED66       loop if not all done
                                now all eight bits have been sent it's up to the peripheral to signal the byte was
                                received by pulling the serial data low. this should be done within one milisecond
.,ED92 A9 04    LDA #$04        wait for up to about 1ms
.,ED94 8D 07 DC STA $DC07       save VIA 1 timer B high byte
.,ED97 A9 19    LDA #$19        load timer B, timer B single shot, start timer B
.,ED99 8D 0F DC STA $DC0F       save VIA 1 CRB
.,ED9C AD 0D DC LDA $DC0D       read VIA 1 ICR
.,ED9F AD 0D DC LDA $DC0D       read VIA 1 ICR
.,EDA2 29 02    AND #$02        mask 0000 00x0, timer A interrupt
.,EDA4 D0 0A    BNE $EDB0       if timer A interrupt go do serial bus timeout
.,EDA6 20 A9 EE JSR $EEA9       get the serial data status in Cb
.,EDA9 B0 F4    BCS $ED9F       if the serial data is high go wait some more
.,EDAB 58       CLI             enable the interrupts
.,EDAC 60       RTS
                                device not present
.,EDAD A9 80    LDA #$80        error $80, device not present
.:EDAF 2C       .BYTE $2C       makes next line BIT $03A9
                                timeout on serial bus
.,EDB0 A9 03    LDA #$03        error $03, read timeout, write timeout
.,EDB2 20 1C FE JSR $FE1C       OR into the serial status byte
.,EDB5 58       CLI             enable the interrupts
.,EDB6 18       CLC             clear for branch
.,EDB7 90 4A    BCC $EE03       ATN high, delay, clock high then data high, branch always

send secondary address after LISTEN

.,EDB9 85 95    STA $95         save the defered Tx byte
.,EDBB 20 36 ED JSR $ED36       set the serial clk/data, wait and Tx the byte

set serial ATN high

.,EDBE AD 00 DD LDA $DD00       read VIA 2 DRA, serial port and video address
.,EDC1 29 F7    AND #$F7        mask xxxx 0xxx, set serial ATN high
.,EDC3 8D 00 DD STA $DD00       save VIA 2 DRA, serial port and video address
.,EDC6 60       RTS

send secondary address after TALK

.,EDC7 85 95    STA $95         save the defered Tx byte
.,EDC9 20 36 ED JSR $ED36       set the serial clk/data, wait and Tx the byte

wait for the serial bus end after send

                                return address from patch 6
.,EDCC 78       SEI             disable the interrupts
.,EDCD 20 A0 EE JSR $EEA0       set the serial data out low
.,EDD0 20 BE ED JSR $EDBE       set serial ATN high
.,EDD3 20 85 EE JSR $EE85       set the serial clock out high
.,EDD6 20 A9 EE JSR $EEA9       get the serial data status in Cb
.,EDD9 30 FB    BMI $EDD6       loop if the clock is high
.,EDDB 58       CLI             enable the interrupts
.,EDDC 60       RTS

output a byte to the serial bus

.,EDDD 24 94    BIT $94         test the deferred character flag
.,EDDF 30 05    BMI $EDE6       if there is a defered character go send it
.,EDE1 38       SEC             set carry
.,EDE2 66 94    ROR $94         shift into the deferred character flag
.,EDE4 D0 05    BNE $EDEB       save the byte and exit, branch always
.,EDE6 48       PHA             save the byte
.,EDE7 20 40 ED JSR $ED40       Tx byte on serial bus
.,EDEA 68       PLA             restore the byte
.,EDEB 85 95    STA $95         save the defered Tx byte
.,EDED 18       CLC             flag ok
.,EDEE 60       RTS

command serial bus to UNTALK

.,EDEF 78       SEI             disable the interrupts
.,EDF0 20 8E EE JSR $EE8E       set the serial clock out low
.,EDF3 AD 00 DD LDA $DD00       read VIA 2 DRA, serial port and video address
.,EDF6 09 08    ORA #$08        mask xxxx 1xxx, set the serial ATN low
.,EDF8 8D 00 DD STA $DD00       save VIA 2 DRA, serial port and video address
.,EDFB A9 5F    LDA #$5F        set the UNTALK command
.:EDFD 2C       .BYTE $2C       makes next line BIT $3FA9

command serial bus to UNLISTEN

.,EDFE A9 3F    LDA #$3F        set the UNLISTEN command
.,EE00 20 11 ED JSR $ED11       send a control character
.,EE03 20 BE ED JSR $EDBE       set serial ATN high
                                1ms delay, clock high then data high
.,EE06 8A       TXA             save the device number
.,EE07 A2 0A    LDX #$0A        short delay
.,EE09 CA       DEX             decrement the count
.,EE0A D0 FD    BNE $EE09       loop if not all done
.,EE0C AA       TAX             restore the device number
.,EE0D 20 85 EE JSR $EE85       set the serial clock out high
.,EE10 4C 97 EE JMP $EE97       set the serial data out high and return

input a byte from the serial bus

.,EE13 78       SEI             disable the interrupts
.,EE14 A9 00    LDA #$00        set 0 bits to do, will flag EOI on timeour
.,EE16 85 A5    STA $A5         save the serial bus bit count
.,EE18 20 85 EE JSR $EE85       set the serial clock out high
.,EE1B 20 A9 EE JSR $EEA9       get the serial data status in Cb
.,EE1E 10 FB    BPL $EE1B       loop if the serial clock is low
.,EE20 A9 01    LDA #$01        set the timeout count high byte
.,EE22 8D 07 DC STA $DC07       save VIA 1 timer B high byte
.,EE25 A9 19    LDA #$19        load timer B, timer B single shot, start timer B
.,EE27 8D 0F DC STA $DC0F       save VIA 1 CRB
.,EE2A 20 97 EE JSR $EE97       set the serial data out high
.,EE2D AD 0D DC LDA $DC0D       read VIA 1 ICR
.,EE30 AD 0D DC LDA $DC0D       read VIA 1 ICR
.,EE33 29 02    AND #$02        mask 0000 00x0, timer A interrupt
.,EE35 D0 07    BNE $EE3E       if timer A interrupt go ??
.,EE37 20 A9 EE JSR $EEA9       get the serial data status in Cb
.,EE3A 30 F4    BMI $EE30       loop if the serial clock is low
.,EE3C 10 18    BPL $EE56       else go set 8 bits to do, branch always
                                timer A timed out
.,EE3E A5 A5    LDA $A5         get the serial bus bit count
.,EE40 F0 05    BEQ $EE47       if not already EOI then go flag EOI
.,EE42 A9 02    LDA #$02        else error $02, read timeour
.,EE44 4C B2 ED JMP $EDB2       set the serial status and exit
.,EE47 20 A0 EE JSR $EEA0       set the serial data out low
.,EE4A 20 85 EE JSR $EE85       set the serial clock out high
.,EE4D A9 40    LDA #$40        set EOI
.,EE4F 20 1C FE JSR $FE1C       OR into the serial status byte
.,EE52 E6 A5    INC $A5         increment the serial bus bit count, do error on the next
                                timeout
.,EE54 D0 CA    BNE $EE20       go try again, branch always
.,EE56 A9 08    LDA #$08        set 8 bits to do
.,EE58 85 A5    STA $A5         save the serial bus bit count
.,EE5A AD 00 DD LDA $DD00       read VIA 2 DRA, serial port and video address
.,EE5D CD 00 DD CMP $DD00       compare it with itself
.,EE60 D0 F8    BNE $EE5A       if changing go try again
.,EE62 0A       ASL             shift the serial data into the carry
.,EE63 10 F5    BPL $EE5A       loop while the serial clock is low
.,EE65 66 A4    ROR $A4         shift the data bit into the receive byte
.,EE67 AD 00 DD LDA $DD00       read VIA 2 DRA, serial port and video address
.,EE6A CD 00 DD CMP $DD00       compare it with itself
.,EE6D D0 F8    BNE $EE67       if changing go try again
.,EE6F 0A       ASL             shift the serial data into the carry
.,EE70 30 F5    BMI $EE67       loop while the serial clock is high
.,EE72 C6 A5    DEC $A5         decrement the serial bus bit count
.,EE74 D0 E4    BNE $EE5A       loop if not all done
.,EE76 20 A0 EE JSR $EEA0       set the serial data out low
.,EE79 24 90    BIT $90         test the serial status byte
.,EE7B 50 03    BVC $EE80       if EOI not set skip the bus end sequence
.,EE7D 20 06 EE JSR $EE06       1ms delay, clock high then data high
.,EE80 A5 A4    LDA $A4         get the receive byte
.,EE82 58       CLI             enable the interrupts
.,EE83 18       CLC             flag ok
.,EE84 60       RTS

set the serial clock out high

.,EE85 AD 00 DD LDA $DD00       read VIA 2 DRA, serial port and video address
.,EE88 29 EF    AND #$EF        mask xxx0 xxxx, set serial clock out high
.,EE8A 8D 00 DD STA $DD00       save VIA 2 DRA, serial port and video address
.,EE8D 60       RTS

set the serial clock out low

.,EE8E AD 00 DD LDA $DD00       read VIA 2 DRA, serial port and video address
.,EE91 09 10    ORA #$10        mask xxx1 xxxx, set serial clock out low
.,EE93 8D 00 DD STA $DD00       save VIA 2 DRA, serial port and video address
.,EE96 60       RTS

set the serial data out high

.,EE97 AD 00 DD LDA $DD00       read VIA 2 DRA, serial port and video address
.,EE9A 29 DF    AND #$DF        mask xx0x xxxx, set serial data out high
.,EE9C 8D 00 DD STA $DD00       save VIA 2 DRA, serial port and video address
.,EE9F 60       RTS

set the serial data out low

.,EEA0 AD 00 DD LDA $DD00       read VIA 2 DRA, serial port and video address
.,EEA3 09 20    ORA #$20        mask xx1x xxxx, set serial data out low
.,EEA5 8D 00 DD STA $DD00       save VIA 2 DRA, serial port and video address
.,EEA8 60       RTS

get the serial data status in Cb

.,EEA9 AD 00 DD LDA $DD00       read VIA 2 DRA, serial port and video address
.,EEAC CD 00 DD CMP $DD00       compare it with itself
.,EEAF D0 F8    BNE $EEA9       if changing got try again
.,EEB1 0A       ASL             shift the serial data into Cb
.,EEB2 60       RTS

1ms delay

.,EEB3 8A       TXA             save X
.,EEB4 A2 B8    LDX #$B8        set the loop count
.,EEB6 CA       DEX             decrement the loop count
.,EEB7 D0 FD    BNE $EEB6       loop if more to do
.,EEB9 AA       TAX             restore X
.,EEBA 60       RTS

RS232 Tx NMI routine

.,EEBB A5 B4    LDA $B4         get RS232 bit count
.,EEBD F0 47    BEQ $EF06       if zero go setup next RS232 Tx byte and return
.,EEBF 30 3F    BMI $EF00       if -ve go do stop bit(s)
                                else bit count is non zero and +ve
.,EEC1 46 B6    LSR $B6         shift RS232 output byte buffer
.,EEC3 A2 00    LDX #$00        set $00 for bit = 0
.,EEC5 90 01    BCC $EEC8       branch if bit was 0
.,EEC7 CA       DEX             set $FF for bit = 1
.,EEC8 8A       TXA             copy bit to A
.,EEC9 45 BD    EOR $BD         EOR with RS232 parity byte
.,EECB 85 BD    STA $BD         save RS232 parity byte
.,EECD C6 B4    DEC $B4         decrement RS232 bit count
.,EECF F0 06    BEQ $EED7       if RS232 bit count now zero go do parity bit
                                save bit and exit
.,EED1 8A       TXA             copy bit to A
.,EED2 29 04    AND #$04        mask 0000 0x00, RS232 Tx DATA bit
.,EED4 85 B5    STA $B5         save the next RS232 data bit to send
.,EED6 60       RTS

do RS232 parity bit, enters with RS232 bit count = 0

.,EED7 A9 20    LDA #$20        mask 00x0 0000, parity enable bit
.,EED9 2C 94 02 BIT $0294       test the pseudo 6551 command register
.,EEDC F0 14    BEQ $EEF2       if parity disabled go ??
.,EEDE 30 1C    BMI $EEFC       if fixed mark or space parity go ??
.,EEE0 70 14    BVS $EEF6       if even parity go ??
                                else odd parity
.,EEE2 A5 BD    LDA $BD         get RS232 parity byte
.,EEE4 D0 01    BNE $EEE7       if parity not zero leave parity bit = 0
.,EEE6 CA       DEX             make parity bit = 1
.,EEE7 C6 B4    DEC $B4         decrement RS232 bit count, 1 stop bit
.,EEE9 AD 93 02 LDA $0293       get pseudo 6551 control register
.,EEEC 10 E3    BPL $EED1       if 1 stop bit save parity bit and exit
                                else two stop bits ..
.,EEEE C6 B4    DEC $B4         decrement RS232 bit count, 2 stop bits
.,EEF0 D0 DF    BNE $EED1       save bit and exit, branch always
                                parity is disabled so the parity bit becomes the first,
                                and possibly only, stop bit. to do this increment the bit
                                count which effectively decrements the stop bit count.
.,EEF2 E6 B4    INC $B4         increment RS232 bit count, = -1 stop bit
.,EEF4 D0 F0    BNE $EEE6       set stop bit = 1 and exit
                                do even parity
.,EEF6 A5 BD    LDA $BD         get RS232 parity byte
.,EEF8 F0 ED    BEQ $EEE7       if parity zero leave parity bit = 0
.,EEFA D0 EA    BNE $EEE6       else make parity bit = 1, branch always
                                fixed mark or space parity
.,EEFC 70 E9    BVS $EEE7       if fixed space parity leave parity bit = 0
.,EEFE 50 E6    BVC $EEE6       else fixed mark parity make parity bit = 1, branch always
                                decrement stop bit count, set stop bit = 1 and exit. $FF is one stop bit, $FE is two
                                stop bits
.,EF00 E6 B4    INC $B4         decrement RS232 bit count
.,EF02 A2 FF    LDX #$FF        set stop bit = 1
.,EF04 D0 CB    BNE $EED1       save stop bit and exit, branch always

setup next RS232 Tx byte

.,EF06 AD 94 02 LDA $0294       read the 6551 pseudo command register
.,EF09 4A       LSR             handshake bit inot Cb
.,EF0A 90 07    BCC $EF13       if 3 line interface go ??
.,EF0C 2C 01 DD BIT $DD01       test VIA 2 DRB, RS232 port
.,EF0F 10 1D    BPL $EF2E       if DSR = 0 set DSR signal not present and exit
.,EF11 50 1E    BVC $EF31       if CTS = 0 set CTS signal not present and exit
                                was 3 line interface
.,EF13 A9 00    LDA #$00        clear A
.,EF15 85 BD    STA $BD         clear the RS232 parity byte
.,EF17 85 B5    STA $B5         clear the RS232 next bit to send
.,EF19 AE 98 02 LDX $0298       get the number of bits to be sent/received
.,EF1C 86 B4    STX $B4         set the RS232 bit count
.,EF1E AC 9D 02 LDY $029D       get the index to the Tx buffer start
.,EF21 CC 9E 02 CPY $029E       compare it with the index to the Tx buffer end
.,EF24 F0 13    BEQ $EF39       if all done go disable T?? interrupt and return
.,EF26 B1 F9    LDA ($F9),Y     else get a byte from the buffer
.,EF28 85 B6    STA $B6         save it to the RS232 output byte buffer
.,EF2A EE 9D 02 INC $029D       increment the index to the Tx buffer start
.,EF2D 60       RTS

set DSR signal not present

.,EF2E A9 40    LDA #$40        set DSR signal not present
.:EF30 2C       .BYTE $2C       makes next line BIT $10A9

set CTS signal not present

.,EF31 A9 10    LDA #$10        set CTS signal not present
.,EF33 0D 97 02 ORA $0297       OR it with the RS232 status register
.,EF36 8D 97 02 STA $0297       save the RS232 status register

disable timer A interrupt

.,EF39 A9 01    LDA #$01        disable timer A interrupt

set VIA 2 ICR from A

.,EF3B 8D 0D DD STA $DD0D       save VIA 2 ICR
.,EF3E 4D A1 02 EOR $02A1       EOR with the RS-232 interrupt enable byte
.,EF41 09 80    ORA #$80        set the interrupts enable bit
.,EF43 8D A1 02 STA $02A1       save the RS-232 interrupt enable byte
.,EF46 8D 0D DD STA $DD0D       save VIA 2 ICR
.,EF49 60       RTS

compute bit count

.,EF4A A2 09    LDX #$09        set bit count to 9, 8 data + 1 stop bit
.,EF4C A9 20    LDA #$20        mask for 8/7 data bits
.,EF4E 2C 93 02 BIT $0293       test pseudo 6551 control register
.,EF51 F0 01    BEQ $EF54       branch if 8 bits
.,EF53 CA       DEX             else decrement count for 7 data bits
.,EF54 50 02    BVC $EF58       branch if 7 bits
.,EF56 CA       DEX             else decrement count ..
.,EF57 CA       DEX             .. for 5 data bits
.,EF58 60       RTS

RS232 Rx NMI

.,EF59 A6 A9    LDX $A9         get start bit check flag
.,EF5B D0 33    BNE $EF90       if no start bit received go ??
.,EF5D C6 A8    DEC $A8         decrement receiver bit count in
.,EF5F F0 36    BEQ $EF97       if the byte is complete go add it to the buffer
.,EF61 30 0D    BMI $EF70
.,EF63 A5 A7    LDA $A7         get the RS232 received data bit
.,EF65 45 AB    EOR $AB         EOR with the receiver parity bit
.,EF67 85 AB    STA $AB         save the receiver parity bit
.,EF69 46 A7    LSR $A7         shift the RS232 received data bit
.,EF6B 66 AA    ROR $AA
.,EF6D 60       RTS
.,EF6E C6 A8    DEC $A8         decrement receiver bit count in
.,EF70 A5 A7    LDA $A7         get the RS232 received data bit
.,EF72 F0 67    BEQ $EFDB
.,EF74 AD 93 02 LDA $0293       get pseudo 6551 control register
.,EF77 0A       ASL             shift the stop bit flag to Cb
.,EF78 A9 01    LDA #$01        + 1
.,EF7A 65 A8    ADC $A8         add receiver bit count in
.,EF7C D0 EF    BNE $EF6D       exit, branch always

setup to receive an RS232 bit

.,EF7E A9 90    LDA #$90        enable FLAG interrupt
.,EF80 8D 0D DD STA $DD0D       save VIA 2 ICR
.,EF83 0D A1 02 ORA $02A1       OR with the RS-232 interrupt enable byte
.,EF86 8D A1 02 STA $02A1       save the RS-232 interrupt enable byte
.,EF89 85 A9    STA $A9         set start bit check flag, set no start bit received
.,EF8B A9 02    LDA #$02        disable timer B interrupt
.,EF8D 4C 3B EF JMP $EF3B       set VIA 2 ICR from A and return

no RS232 start bit received

.,EF90 A5 A7    LDA $A7         get the RS232 received data bit
.,EF92 D0 EA    BNE $EF7E       if ?? go setup to receive an RS232 bit and return
.,EF94 4C D3 E4 JMP $E4D3       flag the RS232 start bit and set the parity

received a whole byte, add it to the buffer

.,EF97 AC 9B 02 LDY $029B       get index to Rx buffer end
.,EF9A C8       INY             increment index
.,EF9B CC 9C 02 CPY $029C       compare with index to Rx buffer start
.,EF9E F0 2A    BEQ $EFCA       if buffer full go do Rx overrun error
.,EFA0 8C 9B 02 STY $029B       save index to Rx buffer end
.,EFA3 88       DEY             decrement index
.,EFA4 A5 AA    LDA $AA         get assembled byte
.,EFA6 AE 98 02 LDX $0298       get bit count
.,EFA9 E0 09    CPX #$09        compare with byte + stop
.,EFAB F0 04    BEQ $EFB1       branch if all nine bits received
.,EFAD 4A       LSR             else shift byte
.,EFAE E8       INX             increment bit count
.,EFAF D0 F8    BNE $EFA9       loop, branch always
.,EFB1 91 F7    STA ($F7),Y     save received byte to Rx buffer
.,EFB3 A9 20    LDA #$20        mask 00x0 0000, parity enable bit
.,EFB5 2C 94 02 BIT $0294       test the pseudo 6551 command register
.,EFB8 F0 B4    BEQ $EF6E       branch if parity disabled
.,EFBA 30 B1    BMI $EF6D       branch if mark or space parity
.,EFBC A5 A7    LDA $A7         get the RS232 received data bit
.,EFBE 45 AB    EOR $AB         EOR with the receiver parity bit
.,EFC0 F0 03    BEQ $EFC5
.,EFC2 70 A9    BVS $EF6D       if ?? just exit
.:EFC4 2C       .BYTE $2C       makes next line BIT $A650
.,EFC5 50 A6    BVC $EF6D       if ?? just exit
.,EFC7 A9 01    LDA #$01        set Rx parity error
.:EFC9 2C       .BYTE $2C       makes next line BIT $04A9
.,EFCA A9 04    LDA #$04        set Rx overrun error
.:EFCC 2C       .BYTE $2C       makes next line BIT $80A9
.,EFCD A9 80    LDA #$80        set Rx break error
.:EFCF 2C       .BYTE $2C       makes next line BIT $02A9
.,EFD0 A9 02    LDA #$02        set Rx frame error
.,EFD2 0D 97 02 ORA $0297       OR it with the RS232 status byte
.,EFD5 8D 97 02 STA $0297       save the RS232 status byte
.,EFD8 4C 7E EF JMP $EF7E       setup to receive an RS232 bit and return
.,EFDB A5 AA    LDA $AA
.,EFDD D0 F1    BNE $EFD0       if ?? do frame error
.,EFDF F0 EC    BEQ $EFCD       else do break error, branch always

open RS232 channel for output

.,EFE1 85 9A    STA $9A         save the output device number
.,EFE3 AD 94 02 LDA $0294       read the pseudo 6551 command register
.,EFE6 4A       LSR             shift handshake bit to carry
.,EFE7 90 29    BCC $F012       if 3 line interface go ??
.,EFE9 A9 02    LDA #$02        mask 0000 00x0, RTS out
.,EFEB 2C 01 DD BIT $DD01       test VIA 2 DRB, RS232 port
.,EFEE 10 1D    BPL $F00D       if DSR = 0 set DSR not present and exit
.,EFF0 D0 20    BNE $F012       if RTS = 1 just exit
.,EFF2 AD A1 02 LDA $02A1       get the RS-232 interrupt enable byte
.,EFF5 29 02    AND #$02        mask 0000 00x0, timer B interrupt
.,EFF7 D0 F9    BNE $EFF2       loop while the timer B interrupt is enebled
.,EFF9 2C 01 DD BIT $DD01       test VIA 2 DRB, RS232 port
.,EFFC 70 FB    BVS $EFF9       loop while CTS high
.,EFFE AD 01 DD LDA $DD01       read VIA 2 DRB, RS232 port
.,F001 09 02    ORA #$02        mask xxxx xx1x, set RTS high
.,F003 8D 01 DD STA $DD01       save VIA 2 DRB, RS232 port
.,F006 2C 01 DD BIT $DD01       test VIA 2 DRB, RS232 port
.,F009 70 07    BVS $F012       exit if CTS high
.,F00B 30 F9    BMI $F006       loop while DSR high
                                set no DSR and exit
.,F00D A9 40    LDA #$40        set DSR signal not present
.,F00F 8D 97 02 STA $0297       save the RS232 status register
.,F012 18       CLC             flag ok
.,F013 60       RTS

send byte to the RS232 buffer

.,F014 20 28 F0 JSR $F028       setup for RS232 transmit
                                send byte to the RS232 buffer, no setup
.,F017 AC 9E 02 LDY $029E       get index to Tx buffer end
.,F01A C8       INY             + 1
.,F01B CC 9D 02 CPY $029D       compare with index to Tx buffer start
.,F01E F0 F4    BEQ $F014       loop while buffer full
.,F020 8C 9E 02 STY $029E       set index to Tx buffer end
.,F023 88       DEY             index to available buffer byte
.,F024 A5 9E    LDA $9E         read the RS232 character buffer
.,F026 91 F9    STA ($F9),Y     save the byte to the buffer

setup for RS232 transmit

.,F028 AD A1 02 LDA $02A1       get the RS-232 interrupt enable byte
.,F02B 4A       LSR             shift the enable bit to Cb
.,F02C B0 1E    BCS $F04C       if interrupts are enabled just exit
.,F02E A9 10    LDA #$10        start timer A
.,F030 8D 0E DD STA $DD0E       save VIA 2 CRA
.,F033 AD 99 02 LDA $0299       get the baud rate bit time low byte
.,F036 8D 04 DD STA $DD04       save VIA 2 timer A low byte
.,F039 AD 9A 02 LDA $029A       get the baud rate bit time high byte
.,F03C 8D 05 DD STA $DD05       save VIA 2 timer A high byte
.,F03F A9 81    LDA #$81        enable timer A interrupt
.,F041 20 3B EF JSR $EF3B       set VIA 2 ICR from A
.,F044 20 06 EF JSR $EF06       setup next RS232 Tx byte
.,F047 A9 11    LDA #$11        load timer A, start timer A
.,F049 8D 0E DD STA $DD0E       save VIA 2 CRA
.,F04C 60       RTS

input from RS232 buffer

.,F04D 85 99    STA $99         save the input device number
.,F04F AD 94 02 LDA $0294       get pseudo 6551 command register
.,F052 4A       LSR             shift the handshake bit to Cb
.,F053 90 28    BCC $F07D       if 3 line interface go ??
.,F055 29 08    AND #$08        mask the duplex bit, pseudo 6551 command is >> 1
.,F057 F0 24    BEQ $F07D       if full duplex go ??
.,F059 A9 02    LDA #$02        mask 0000 00x0, RTS out
.,F05B 2C 01 DD BIT $DD01       test VIA 2 DRB, RS232 port
.,F05E 10 AD    BPL $F00D       if DSR = 0 set no DSR and exit
.,F060 F0 22    BEQ $F084       if RTS = 0 just exit
.,F062 AD A1 02 LDA $02A1       get the RS-232 interrupt enable byte
.,F065 4A       LSR             shift the timer A interrupt enable bit to Cb
.,F066 B0 FA    BCS $F062       loop while the timer A interrupt is enabled
.,F068 AD 01 DD LDA $DD01       read VIA 2 DRB, RS232 port
.,F06B 29 FD    AND #$FD        mask xxxx xx0x, clear RTS out
.,F06D 8D 01 DD STA $DD01       save VIA 2 DRB, RS232 port
.,F070 AD 01 DD LDA $DD01       read VIA 2 DRB, RS232 port
.,F073 29 04    AND #$04        mask xxxx x1xx, DTR in
.,F075 F0 F9    BEQ $F070       loop while DTR low
.,F077 A9 90    LDA #$90        enable the FLAG interrupt
.,F079 18       CLC             flag ok
.,F07A 4C 3B EF JMP $EF3B       set VIA 2 ICR from A and return
.,F07D AD A1 02 LDA $02A1       get the RS-232 interrupt enable byte
.,F080 29 12    AND #$12        mask 000x 00x0
.,F082 F0 F3    BEQ $F077       if FLAG or timer B bits set go enable the FLAG inetrrupt
.,F084 18       CLC             flag ok
.,F085 60       RTS

get byte from RS232 buffer

.,F086 AD 97 02 LDA $0297       get the RS232 status register
.,F089 AC 9C 02 LDY $029C       get index to Rx buffer start
.,F08C CC 9B 02 CPY $029B       compare with index to Rx buffer end
.,F08F F0 0B    BEQ $F09C       return null if buffer empty
.,F091 29 F7    AND #$F7        clear the Rx buffer empty bit
.,F093 8D 97 02 STA $0297       save the RS232 status register
.,F096 B1 F7    LDA ($F7),Y     get byte from Rx buffer
.,F098 EE 9C 02 INC $029C       increment index to Rx buffer start
.,F09B 60       RTS
.,F09C 09 08    ORA #$08        set the Rx buffer empty bit
.,F09E 8D 97 02 STA $0297       save the RS232 status register
.,F0A1 A9 00    LDA #$00        return null
.,F0A3 60       RTS

check RS232 bus idle

.,F0A4 48       PHA             save A
.,F0A5 AD A1 02 LDA $02A1       get the RS-232 interrupt enable byte
.,F0A8 F0 11    BEQ $F0BB       if no interrupts enabled just exit
.,F0AA AD A1 02 LDA $02A1       get the RS-232 interrupt enable byte
.,F0AD 29 03    AND #$03        mask 0000 00xx, the error bits
.,F0AF D0 F9    BNE $F0AA       if there are errors loop
.,F0B1 A9 10    LDA #$10        disable FLAG interrupt
.,F0B3 8D 0D DD STA $DD0D       save VIA 2 ICR
.,F0B6 A9 00    LDA #$00        clear A
.,F0B8 8D A1 02 STA $02A1       clear the RS-232 interrupt enable byte
.,F0BB 68       PLA             restore A
.,F0BC 60       RTS

kernel I/O messages

.:F0BD 0D 49 2F 4F 20 45 52 52  I/O ERROR #
.:F0C6 52 20 A3 0D 53 45 41 52
.:F0C9 0D 53 45 41 52 43 48 49  SEARCHING
.:F0D1 4E 47 A0 46 4F 52 A0 0D
.:F0D4 46 4F 52 A0 0D 50 52 45  FOR
.:F0D8 0D 50 52 45 53 53 20 50  PRESS PLAY ON TAPE
.:F0E0 4C 41 59 20 4F 4E 20 54
.:F0E8 41 50 C5 50 52 45 53 53
.:F0EB 50 52 45 53 53 20 52 45  PRESS RECORD & PLAY ON TAPE
.:F0F3 43 4F 52 44 20 26 20 50
.:F0FB 4C 41 59 20 4F 4E 20 54
.:F103 41 50 C5 0D 4C 4F 41 44
.:F106 0D 4C 4F 41 44 49 4E C7  LOADING
.:F10E 0D 53 41 56 49 4E 47 A0  SAVING
.:F116 0D 56 45 52 49 46 59 49  VERIFYING
.:F11E 4E C7 0D 46 4F 55 4E 44
.:F120 0D 46 4F 55 4E 44 A0 0D  FOUND
.:F127 0D 4F 4B 8D              OK

display control I/O message if in direct mode

.,F12B 24 9D    BIT $9D         test message mode flag
.,F12D 10 0D    BPL $F13C       exit if control messages off
                                display kernel I/O message
.,F12F B9 BD F0 LDA $F0BD,Y     get byte from message table
.,F132 08       PHP             save status
.,F133 29 7F    AND #$7F        clear b7
.,F135 20 D2 FF JSR $FFD2       output character to channel
.,F138 C8       INY             increment index
.,F139 28       PLP             restore status
.,F13A 10 F3    BPL $F12F       loop if not end of message
.,F13C 18       CLC
.,F13D 60       RTS

get character from the input device

.,F13E A5 99    LDA $99         get the input device number
.,F140 D0 08    BNE $F14A       if not the keyboard go handle other devices
                                the input device was the keyboard
.,F142 A5 C6    LDA $C6         get the keyboard buffer index
.,F144 F0 0F    BEQ $F155       if the buffer is empty go flag no byte and return
.,F146 78       SEI             disable the interrupts
.,F147 4C B4 E5 JMP $E5B4       get input from the keyboard buffer and return
                                the input device was not the keyboard
.,F14A C9 02    CMP #$02        compare the device with the RS232 device
.,F14C D0 18    BNE $F166       if not the RS232 device go ??
                                the input device is the RS232 device
.,F14E 84 97    STY $97         save Y
.,F150 20 86 F0 JSR $F086       get a byte from RS232 buffer
.,F153 A4 97    LDY $97         restore Y
.,F155 18       CLC             flag no error
.,F156 60       RTS

input a character from channel

.,F157 A5 99    LDA $99         get the input device number
.,F159 D0 0B    BNE $F166       if not the keyboard continue
                                the input device was the keyboard
.,F15B A5 D3    LDA $D3         get the cursor column
.,F15D 85 CA    STA $CA         set the input cursor column
.,F15F A5 D6    LDA $D6         get the cursor row
.,F161 85 C9    STA $C9         set the input cursor row
.,F163 4C 32 E6 JMP $E632       input from screen or keyboard
                                the input device was not the keyboard
.,F166 C9 03    CMP #$03        compare device number with screen
.,F168 D0 09    BNE $F173       if not screen continue
                                the input device was the screen
.,F16A 85 D0    STA $D0         input from keyboard or screen, $xx = screen,
                                $00 = keyboard
.,F16C A5 D5    LDA $D5         get current screen line length
.,F16E 85 C8    STA $C8         save input [EOL] pointer
.,F170 4C 32 E6 JMP $E632       input from screen or keyboard
                                the input device was not the screen
.,F173 B0 38    BCS $F1AD       if input device > screen go do IEC devices
                                the input device was < screen
.,F175 C9 02    CMP #$02        compare the device with the RS232 device
.,F177 F0 3F    BEQ $F1B8       if RS232 device go get a byte from the RS232 device
                                only the tape device left ..
.,F179 86 97    STX $97         save X
.,F17B 20 99 F1 JSR $F199       get a byte from tape
.,F17E B0 16    BCS $F196       if error just exit
.,F180 48       PHA             save the byte
.,F181 20 99 F1 JSR $F199       get the next byte from tape
.,F184 B0 0D    BCS $F193       if error just exit
.,F186 D0 05    BNE $F18D       if end reached ??
.,F188 A9 40    LDA #$40        set EOI
.,F18A 20 1C FE JSR $FE1C       OR into the serial status byte
.,F18D C6 A6    DEC $A6         decrement tape buffer index
.,F18F A6 97    LDX $97         restore X
.,F191 68       PLA             restore the saved byte
.,F192 60       RTS
.,F193 AA       TAX             copy the error byte
.,F194 68       PLA             dump the saved byte
.,F195 8A       TXA             restore error byte
.,F196 A6 97    LDX $97         restore X
.,F198 60       RTS

get byte from tape

.,F199 20 0D F8 JSR $F80D       bump tape pointer
.,F19C D0 0B    BNE $F1A9       if not end get next byte and exit
.,F19E 20 41 F8 JSR $F841       initiate tape read
.,F1A1 B0 11    BCS $F1B4       exit if error flagged
.,F1A3 A9 00    LDA #$00        clear A
.,F1A5 85 A6    STA $A6         clear tape buffer index
.,F1A7 F0 F0    BEQ $F199       loop, branch always
.,F1A9 B1 B2    LDA ($B2),Y     get next byte from buffer
.,F1AB 18       CLC             flag no error
.,F1AC 60       RTS
                                input device was serial bus
.,F1AD A5 90    LDA $90         get the serial status byte
.,F1AF F0 04    BEQ $F1B5       if no errors flagged go input byte and return
.,F1B1 A9 0D    LDA #$0D        else return [EOL]
.,F1B3 18       CLC             flag no error
.,F1B4 60       RTS
.,F1B5 4C 13 EE JMP $EE13       input byte from serial bus and return
                                input device was RS232 device
.,F1B8 20 4E F1 JSR $F14E       get byte from RS232 device
.,F1BB B0 F7    BCS $F1B4       branch if error, this doesn't get taken as the last
                                instruction in the get byte from RS232 device routine
                                is CLC ??
.,F1BD C9 00    CMP #$00        compare with null
.,F1BF D0 F2    BNE $F1B3       exit if not null
.,F1C1 AD 97 02 LDA $0297       get the RS232 status register
.,F1C4 29 60    AND #$60        mask 0xx0 0000, DSR detected and ??
.,F1C6 D0 E9    BNE $F1B1       if ?? return null
.,F1C8 F0 EE    BEQ $F1B8       else loop, branch always

output character to channel

.,F1CA 48       PHA             save the character to output
.,F1CB A5 9A    LDA $9A         get the output device number
.,F1CD C9 03    CMP #$03        compare the output device with the screen
.,F1CF D0 04    BNE $F1D5       if not the screen go ??
.,F1D1 68       PLA             else restore the output character
.,F1D2 4C 16 E7 JMP $E716       go output the character to the screen
.,F1D5 90 04    BCC $F1DB       if < screen go ??
.,F1D7 68       PLA             else restore the output character
.,F1D8 4C DD ED JMP $EDDD       go output the character to the serial bus
.,F1DB 4A       LSR             shift b0 of the device into Cb
.,F1DC 68       PLA             restore the output character

output the character to the cassette or RS232 device

.,F1DD 85 9E    STA $9E         save the character to the character buffer
.,F1DF 8A       TXA             copy X
.,F1E0 48       PHA             save X
.,F1E1 98       TYA             copy Y
.,F1E2 48       PHA             save Y
.,F1E3 90 23    BCC $F208       if Cb is clear it must be the RS232 device
                                output the character to the cassette
.,F1E5 20 0D F8 JSR $F80D       bump the tape pointer
.,F1E8 D0 0E    BNE $F1F8       if not end save next byte and exit
.,F1EA 20 64 F8 JSR $F864       initiate tape write
.,F1ED B0 0E    BCS $F1FD       exit if error
.,F1EF A9 02    LDA #$02        set data block type ??
.,F1F1 A0 00    LDY #$00        clear index
.,F1F3 91 B2    STA ($B2),Y     save type to buffer ??
.,F1F5 C8       INY             increment index
.,F1F6 84 A6    STY $A6         save tape buffer index
.,F1F8 A5 9E    LDA $9E         restore character from character buffer
.,F1FA 91 B2    STA ($B2),Y     save to buffer
.,F1FC 18       CLC             flag no error
.,F1FD 68       PLA             pull Y
.,F1FE A8       TAY             restore Y
.,F1FF 68       PLA             pull X
.,F200 AA       TAX             restore X
.,F201 A5 9E    LDA $9E         get the character from the character buffer
.,F203 90 02    BCC $F207       exit if no error
.,F205 A9 00    LDA #$00        else clear A
.,F207 60       RTS
                                output the character to the RS232 device
.,F208 20 17 F0 JSR $F017       send byte to the RS232 buffer, no setup
.,F20B 4C FC F1 JMP $F1FC       do no error exit

open channel for input

.,F20E 20 0F F3 JSR $F30F       find a file
.,F211 F0 03    BEQ $F216       if the file is open continue
.,F213 4C 01 F7 JMP $F701       else do 'file not open' error and return
.,F216 20 1F F3 JSR $F31F       set file details from table,X
.,F219 A5 BA    LDA $BA         get the device number
.,F21B F0 16    BEQ $F233       if the device was the keyboard save the device #, flag
                                ok and exit
.,F21D C9 03    CMP #$03        compare the device number with the screen
.,F21F F0 12    BEQ $F233       if the device was the screen save the device #, flag ok
                                and exit
.,F221 B0 14    BCS $F237       if the device was a serial bus device go ??
.,F223 C9 02    CMP #$02        else compare the device with the RS232 device
.,F225 D0 03    BNE $F22A       if not the RS232 device continue
.,F227 4C 4D F0 JMP $F04D       else go get input from the RS232 buffer and return
.,F22A A6 B9    LDX $B9         get the secondary address
.,F22C E0 60    CPX #$60
.,F22E F0 03    BEQ $F233
.,F230 4C 0A F7 JMP $F70A       go do 'not input file' error and return
.,F233 85 99    STA $99         save the input device number
.,F235 18       CLC             flag ok
.,F236 60       RTS
                                the device was a serial bus device
.,F237 AA       TAX             copy device number to X
.,F238 20 09 ED JSR $ED09       command serial bus device to TALK
.,F23B A5 B9    LDA $B9         get the secondary address
.,F23D 10 06    BPL $F245
.,F23F 20 CC ED JSR $EDCC       wait for the serial bus end after send
.,F242 4C 48 F2 JMP $F248
.,F245 20 C7 ED JSR $EDC7       send secondary address after TALK
.,F248 8A       TXA             copy device back to A
.,F249 24 90    BIT $90         test the serial status byte
.,F24B 10 E6    BPL $F233       if device present save device number and exit
.,F24D 4C 07 F7 JMP $F707       do 'device not present' error and return

open channel for output

.,F250 20 0F F3 JSR $F30F       find a file
.,F253 F0 03    BEQ $F258       if file found continue
.,F255 4C 01 F7 JMP $F701       else do 'file not open' error and return
.,F258 20 1F F3 JSR $F31F       set file details from table,X
.,F25B A5 BA    LDA $BA         get the device number
.,F25D D0 03    BNE $F262       if the device is not the keyboard go ??
.,F25F 4C 0D F7 JMP $F70D       go do 'not output file' error and return
.,F262 C9 03    CMP #$03        compare the device with the screen
.,F264 F0 0F    BEQ $F275       if the device is the screen go save output the output
                                device number and exit
.,F266 B0 11    BCS $F279       if > screen then go handle a serial bus device
.,F268 C9 02    CMP #$02        compare the device with the RS232 device
.,F26A D0 03    BNE $F26F       if not the RS232 device then it must be the tape device
.,F26C 4C E1 EF JMP $EFE1       else go open RS232 channel for output
                                open a tape channel for output
.,F26F A6 B9    LDX $B9         get the secondary address
.,F271 E0 60    CPX #$60
.,F273 F0 EA    BEQ $F25F       if ?? do not output file error and return
.,F275 85 9A    STA $9A         save the output device number
.,F277 18       CLC             flag ok
.,F278 60       RTS
.,F279 AA       TAX             copy the device number
.,F27A 20 0C ED JSR $ED0C       command devices on the serial bus to LISTEN
.,F27D A5 B9    LDA $B9         get the secondary address
.,F27F 10 05    BPL $F286       if address to send go ??
.,F281 20 BE ED JSR $EDBE       else set serial ATN high
.,F284 D0 03    BNE $F289       go ??, branch always
.,F286 20 B9 ED JSR $EDB9       send secondary address after LISTEN
.,F289 8A       TXA             copy device number back to A
.,F28A 24 90    BIT $90         test the serial status byte
.,F28C 10 E7    BPL $F275       if the device is present go save the output device number
                                and exit
.,F28E 4C 07 F7 JMP $F707       else do 'device not present error' and return

close a specified logical file

.,F291 20 14 F3 JSR $F314       find file A
.,F294 F0 02    BEQ $F298       if file found go close it
.,F296 18       CLC             else the file was closed so just flag ok
.,F297 60       RTS
                                file found so close it
.,F298 20 1F F3 JSR $F31F       set file details from table,X
.,F29B 8A       TXA             copy file index to A
.,F29C 48       PHA             save file index
.,F29D A5 BA    LDA $BA         get the device number
.,F29F F0 50    BEQ $F2F1       if it is the keyboard go restore the index and close the
                                file
.,F2A1 C9 03    CMP #$03        compare the device number with the screen
.,F2A3 F0 4C    BEQ $F2F1       if it is the screen go restore the index and close the
                                file
.,F2A5 B0 47    BCS $F2EE       if > screen go do serial bus device close
.,F2A7 C9 02    CMP #$02        compare the device with the RS232 device
.,F2A9 D0 1D    BNE $F2C8       if not the RS232 device go ??
                                else close RS232 device
.,F2AB 68       PLA             restore file index
.,F2AC 20 F2 F2 JSR $F2F2       close file index X
.,F2AF 20 83 F4 JSR $F483       initialise RS232 output
.,F2B2 20 27 FE JSR $FE27       read the top of memory
.,F2B5 A5 F8    LDA $F8         get the RS232 input buffer pointer high byte
.,F2B7 F0 01    BEQ $F2BA       if no RS232 input buffer go ??
.,F2B9 C8       INY             else reclaim RS232 input buffer memory
.,F2BA A5 FA    LDA $FA         get the RS232 output buffer pointer high byte
.,F2BC F0 01    BEQ $F2BF       if no RS232 output buffer skip the reclaim
.,F2BE C8       INY             else reclaim the RS232 output buffer memory
.,F2BF A9 00    LDA #$00        clear A
.,F2C1 85 F8    STA $F8         clear the RS232 input buffer pointer high byte
.,F2C3 85 FA    STA $FA         clear the RS232 output buffer pointer high byte
.,F2C5 4C 7D F4 JMP $F47D       go set the top of memory to F0xx
                                is not the RS232 device
.,F2C8 A5 B9    LDA $B9         get the secondary address
.,F2CA 29 0F    AND #$0F        mask the device #
.,F2CC F0 23    BEQ $F2F1       if ?? restore index and close file
.,F2CE 20 D0 F7 JSR $F7D0       get tape buffer start pointer in XY
.,F2D1 A9 00    LDA #$00        character $00
.,F2D3 38       SEC             flag the tape device
.,F2D4 20 DD F1 JSR $F1DD       output the character to the cassette or RS232 device
.,F2D7 20 64 F8 JSR $F864       initiate tape write
.,F2DA 90 04    BCC $F2E0
.,F2DC 68       PLA
.,F2DD A9 00    LDA #$00
.,F2DF 60       RTS
.,F2E0 A5 B9    LDA $B9         get the secondary address
.,F2E2 C9 62    CMP #$62
.,F2E4 D0 0B    BNE $F2F1       if not ?? restore index and close file
.,F2E6 A9 05    LDA #$05        set logical end of the tape
.,F2E8 20 6A F7 JSR $F76A       write tape header
.,F2EB 4C F1 F2 JMP $F2F1       restore index and close file

serial bus device close

.,F2EE 20 42 F6 JSR $F642       close serial bus device
.,F2F1 68       PLA             restore file index

close file index X

.,F2F2 AA       TAX             copy index to file to close
.,F2F3 C6 98    DEC $98         decrement the open file count
.,F2F5 E4 98    CPX $98         compare the index with the open file count
.,F2F7 F0 14    BEQ $F30D       exit if equal, last entry was closing file
                                else entry was not last in list so copy last table entry
                                file details over the details of the closing one
.,F2F9 A4 98    LDY $98         get the open file count as index
.,F2FB B9 59 02 LDA $0259,Y     get last+1 logical file number from logical file table
.,F2FE 9D 59 02 STA $0259,X     save logical file number over closed file
.,F301 B9 63 02 LDA $0263,Y     get last+1 device number from device number table
.,F304 9D 63 02 STA $0263,X     save device number over closed file
.,F307 B9 6D 02 LDA $026D,Y     get last+1 secondary address from secondary address table
.,F30A 9D 6D 02 STA $026D,X     save secondary address over closed file
.,F30D 18       CLC             flag ok
.,F30E 60       RTS

find a file

.,F30F A9 00    LDA #$00        clear A
.,F311 85 90    STA $90         clear the serial status byte
.,F313 8A       TXA             copy the logical file number to A

find file A

.,F314 A6 98    LDX $98         get the open file count
.,F316 CA       DEX             decrememnt the count to give the index
.,F317 30 15    BMI $F32E       if no files just exit
.,F319 DD 59 02 CMP $0259,X     compare the logical file number with the table logical
                                file number
.,F31C D0 F8    BNE $F316       if no match go try again
.,F31E 60       RTS

set file details from table,X

.,F31F BD 59 02 LDA $0259,X     get logical file from logical file table
.,F322 85 B8    STA $B8         save the logical file
.,F324 BD 63 02 LDA $0263,X     get device number from device number table
.,F327 85 BA    STA $BA         save the device number
.,F329 BD 6D 02 LDA $026D,X     get secondary address from secondary address table
.,F32C 85 B9    STA $B9         save the secondary address
.,F32E 60       RTS

close all channels and files

.,F32F A9 00    LDA #$00        clear A
.,F331 85 98    STA $98         clear the open file count

close input and output channels

.,F333 A2 03    LDX #$03        set the screen device
.,F335 E4 9A    CPX $9A         compare the screen with the output device number
.,F337 B0 03    BCS $F33C       if <= screen skip the serial bus unlisten
.,F339 20 FE ED JSR $EDFE       else command the serial bus to UNLISTEN
.,F33C E4 99    CPX $99         compare the screen with the input device number
.,F33E B0 03    BCS $F343       if <= screen skip the serial bus untalk
.,F340 20 EF ED JSR $EDEF       else command the serial bus to UNTALK
.,F343 86 9A    STX $9A         save the screen as the output device number
.,F345 A9 00    LDA #$00        set the keyboard as the input device
.,F347 85 99    STA $99         save the input device number
.,F349 60       RTS

open a logical file

.,F34A A6 B8    LDX $B8         get the logical file
.,F34C D0 03    BNE $F351       if there is a file continue
.,F34E 4C 0A F7 JMP $F70A       else do 'not input file error' and return
.,F351 20 0F F3 JSR $F30F       find a file
.,F354 D0 03    BNE $F359       if file not found continue
.,F356 4C FE F6 JMP $F6FE       else do 'file already open' error and return
.,F359 A6 98    LDX $98         get the open file count
.,F35B E0 0A    CPX #$0A        compare it with the maximum + 1
.,F35D 90 03    BCC $F362       if less than maximum + 1 go open the file
.,F35F 4C FB F6 JMP $F6FB       else do 'too many files error' and return
.,F362 E6 98    INC $98         increment the open file count
.,F364 A5 B8    LDA $B8         get the logical file
.,F366 9D 59 02 STA $0259,X     save it to the logical file table
.,F369 A5 B9    LDA $B9         get the secondary address
.,F36B 09 60    ORA #$60        OR with the OPEN CHANNEL command
.,F36D 85 B9    STA $B9         save the secondary address
.,F36F 9D 6D 02 STA $026D,X     save it to the secondary address table
.,F372 A5 BA    LDA $BA         get the device number
.,F374 9D 63 02 STA $0263,X     save it to the device number table
.,F377 F0 5A    BEQ $F3D3       if it is the keyboard go do the ok exit
.,F379 C9 03    CMP #$03        compare the device number with the screen
.,F37B F0 56    BEQ $F3D3       if it is the screen go do the ok exit
.,F37D 90 05    BCC $F384       if tape or RS232 device go ??
                                else it is a serial bus device
.,F37F 20 D5 F3 JSR $F3D5       send the secondary address and filename
.,F382 90 4F    BCC $F3D3       go do ok exit, branch always
.,F384 C9 02    CMP #$02
.,F386 D0 03    BNE $F38B
.,F388 4C 09 F4 JMP $F409       go open RS232 device and return
.,F38B 20 D0 F7 JSR $F7D0       get tape buffer start pointer in XY
.,F38E B0 03    BCS $F393       if >= $0200 go ??
.,F390 4C 13 F7 JMP $F713       else do 'illegal device number' and return
.,F393 A5 B9    LDA $B9         get the secondary address
.,F395 29 0F    AND #$0F
.,F397 D0 1F    BNE $F3B8
.,F399 20 17 F8 JSR $F817       wait for PLAY
.,F39C B0 36    BCS $F3D4       exit if STOP was pressed
.,F39E 20 AF F5 JSR $F5AF       print "Searching..."
.,F3A1 A5 B7    LDA $B7         get file name length
.,F3A3 F0 0A    BEQ $F3AF       if null file name just go find header
.,F3A5 20 EA F7 JSR $F7EA       find specific tape header
.,F3A8 90 18    BCC $F3C2       branch if no error
.,F3AA F0 28    BEQ $F3D4       exit if ??
.,F3AC 4C 04 F7 JMP $F704       do file not found error and return
.,F3AF 20 2C F7 JSR $F72C       find tape header, exit with header in buffer
.,F3B2 F0 20    BEQ $F3D4       exit if end of tape found
.,F3B4 90 0C    BCC $F3C2
.,F3B6 B0 F4    BCS $F3AC
.,F3B8 20 38 F8 JSR $F838       wait for PLAY/RECORD
.,F3BB B0 17    BCS $F3D4       exit if STOP was pressed
.,F3BD A9 04    LDA #$04        set data file header
.,F3BF 20 6A F7 JSR $F76A       write tape header
.,F3C2 A9 BF    LDA #$BF
.,F3C4 A4 B9    LDY $B9         get the secondary address
.,F3C6 C0 60    CPY #$60
.,F3C8 F0 07    BEQ $F3D1
.,F3CA A0 00    LDY #$00        clear index
.,F3CC A9 02    LDA #$02
.,F3CE 91 B2    STA ($B2),Y     save to tape buffer
.,F3D0 98       TYA             clear A
.,F3D1 85 A6    STA $A6         save tape buffer index
.,F3D3 18       CLC             flag ok
.,F3D4 60       RTS

send secondary address and filename

.,F3D5 A5 B9    LDA $B9         get the secondary address
.,F3D7 30 FA    BMI $F3D3       ok exit if -ve
.,F3D9 A4 B7    LDY $B7         get file name length
.,F3DB F0 F6    BEQ $F3D3       ok exit if null
.,F3DD A9 00    LDA #$00        clear A
.,F3DF 85 90    STA $90         clear the serial status byte
.,F3E1 A5 BA    LDA $BA         get the device number
.,F3E3 20 0C ED JSR $ED0C       command devices on the serial bus to LISTEN
.,F3E6 A5 B9    LDA $B9         get the secondary address
.,F3E8 09 F0    ORA #$F0        OR with the OPEN command
.,F3EA 20 B9 ED JSR $EDB9       send secondary address after LISTEN
.,F3ED A5 90    LDA $90         get the serial status byte
.,F3EF 10 05    BPL $F3F6       if device present skip the 'device not present' error
.,F3F1 68       PLA             else dump calling address low byte
.,F3F2 68       PLA             dump calling address high byte
.,F3F3 4C 07 F7 JMP $F707       do 'device not present' error and return
.,F3F6 A5 B7    LDA $B7         get file name length
.,F3F8 F0 0C    BEQ $F406       branch if null name
.,F3FA A0 00    LDY #$00        clear index
.,F3FC B1 BB    LDA ($BB),Y     get file name byte
.,F3FE 20 DD ED JSR $EDDD       output byte to serial bus
.,F401 C8       INY             increment index
.,F402 C4 B7    CPY $B7         compare with file name length
.,F404 D0 F6    BNE $F3FC       loop if not all done
.,F406 4C 54 F6 JMP $F654       command serial bus to UNLISTEN and return

open RS232 device

.,F409 20 83 F4 JSR $F483       initialise RS232 output
.,F40C 8C 97 02 STY $0297       save the RS232 status register
.,F40F C4 B7    CPY $B7         compare with file name length
.,F411 F0 0A    BEQ $F41D       exit loop if done
.,F413 B1 BB    LDA ($BB),Y     get file name byte
.,F415 99 93 02 STA $0293,Y     copy to 6551 register set
.,F418 C8       INY             increment index
.,F419 C0 04    CPY #$04        compare with $04
.,F41B D0 F2    BNE $F40F       loop if not to 4 yet
.,F41D 20 4A EF JSR $EF4A       compute bit count
.,F420 8E 98 02 STX $0298       save bit count
.,F423 AD 93 02 LDA $0293       get pseudo 6551 control register
.,F426 29 0F    AND #$0F        mask 0000 xxxx, baud rate
.,F428 F0 1C    BEQ $F446       if zero skip the baud rate setup
.,F42A 0A       ASL             * 2 bytes per entry
.,F42B AA       TAX             copy to the index
.,F42C AD A6 02 LDA $02A6       get the PAL/NTSC flag
.,F42F D0 09    BNE $F43A       if PAL go set PAL timing
.,F431 BC C1 FE LDY $FEC1,X     get the NTSC baud rate value high byte
.,F434 BD C0 FE LDA $FEC0,X     get the NTSC baud rate value low byte
.,F437 4C 40 F4 JMP $F440       go save the baud rate values
.,F43A BC EB E4 LDY $E4EB,X     get the PAL baud rate value high byte
.,F43D BD EA E4 LDA $E4EA,X     get the PAL baud rate value low byte
.,F440 8C 96 02 STY $0296       save the nonstandard bit timing high byte
.,F443 8D 95 02 STA $0295       save the nonstandard bit timing low byte
.,F446 AD 95 02 LDA $0295       get the nonstandard bit timing low byte
.,F449 0A       ASL             * 2
.,F44A 20 2E FF JSR $FF2E
.,F44D AD 94 02 LDA $0294       read the pseudo 6551 command register
.,F450 4A       LSR             shift the X line/3 line bit into Cb
.,F451 90 09    BCC $F45C       if 3 line skip the DRS test
.,F453 AD 01 DD LDA $DD01       read VIA 2 DRB, RS232 port
.,F456 0A       ASL             shift DSR in into Cb
.,F457 B0 03    BCS $F45C       if DSR present skip the error set
.,F459 20 0D F0 JSR $F00D       set no DSR
.,F45C AD 9B 02 LDA $029B       get index to Rx buffer end
.,F45F 8D 9C 02 STA $029C       set index to Rx buffer start, clear Rx buffer
.,F462 AD 9E 02 LDA $029E       get index to Tx buffer end
.,F465 8D 9D 02 STA $029D       set index to Tx buffer start, clear Tx buffer
.,F468 20 27 FE JSR $FE27       read the top of memory
.,F46B A5 F8    LDA $F8         get the RS232 input buffer pointer high byte
.,F46D D0 05    BNE $F474       if buffer already set skip the save
.,F46F 88       DEY             decrement top of memory high byte, 256 byte buffer
.,F470 84 F8    STY $F8         save the RS232 input buffer pointer high byte
.,F472 86 F7    STX $F7         save the RS232 input buffer pointer low byte
.,F474 A5 FA    LDA $FA         get the RS232 output buffer pointer high byte
.,F476 D0 05    BNE $F47D       if ?? go set the top of memory to F0xx
.,F478 88       DEY
.,F479 84 FA    STY $FA         save the RS232 output buffer pointer high byte
.,F47B 86 F9    STX $F9         save the RS232 output buffer pointer low byte

set the top of memory to F0xx

.,F47D 38       SEC             read the top of memory
.,F47E A9 F0    LDA #$F0        set $F000
.,F480 4C 2D FE JMP $FE2D       set the top of memory and return

initialise RS232 output

.,F483 A9 7F    LDA #$7F        disable all interrupts
.,F485 8D 0D DD STA $DD0D       save VIA 2 ICR
.,F488 A9 06    LDA #$06        set RS232 DTR output, RS232 RTS output
.,F48A 8D 03 DD STA $DD03       save VIA 2 DDRB, RS232 port
.,F48D 8D 01 DD STA $DD01       save VIA 2 DRB, RS232 port
.,F490 A9 04    LDA #$04        mask xxxx x1xx, set RS232 Tx DATA high
.,F492 0D 00 DD ORA $DD00       OR it with VIA 2 DRA, serial port and video address
.,F495 8D 00 DD STA $DD00       save VIA 2 DRA, serial port and video address
.,F498 A0 00    LDY #$00        clear Y
.,F49A 8C A1 02 STY $02A1       clear the RS-232 interrupt enable byte
.,F49D 60       RTS

load RAM from a device

.,F49E 86 C3    STX $C3         set kernal setup pointer low byte
.,F4A0 84 C4    STY $C4         set kernal setup pointer high byte
.,F4A2 6C 30 03 JMP ($0330)     do LOAD vector, usually points to $F4A5

load

.,F4A5 85 93    STA $93         save load/verify flag
.,F4A7 A9 00    LDA #$00        clear A
.,F4A9 85 90    STA $90         clear the serial status byte
.,F4AB A5 BA    LDA $BA         get the device number
.,F4AD D0 03    BNE $F4B2       if not the keyboard continue
                                do 'illegal device number'
.,F4AF 4C 13 F7 JMP $F713       else do 'illegal device number' and return
.,F4B2 C9 03    CMP #$03
.,F4B4 F0 F9    BEQ $F4AF
.,F4B6 90 7B    BCC $F533
.,F4B8 A4 B7    LDY $B7         get file name length
.,F4BA D0 03    BNE $F4BF       if not null name go ??
.,F4BC 4C 10 F7 JMP $F710       else do 'missing file name' error and return
.,F4BF A6 B9    LDX $B9         get the secondary address
.,F4C1 20 AF F5 JSR $F5AF       print "Searching..."
.,F4C4 A9 60    LDA #$60
.,F4C6 85 B9    STA $B9         save the secondary address
.,F4C8 20 D5 F3 JSR $F3D5       send secondary address and filename
.,F4CB A5 BA    LDA $BA         get the device number
.,F4CD 20 09 ED JSR $ED09       command serial bus device to TALK
.,F4D0 A5 B9    LDA $B9         get the secondary address
.,F4D2 20 C7 ED JSR $EDC7       send secondary address after TALK
.,F4D5 20 13 EE JSR $EE13       input byte from serial bus
.,F4D8 85 AE    STA $AE         save program start address low byte
.,F4DA A5 90    LDA $90         get the serial status byte
.,F4DC 4A       LSR             shift time out read ..
.,F4DD 4A       LSR             .. into carry bit
.,F4DE B0 50    BCS $F530       if timed out go do file not found error and return
.,F4E0 20 13 EE JSR $EE13       input byte from serial bus
.,F4E3 85 AF    STA $AF         save program start address high byte
.,F4E5 8A       TXA             copy secondary address
.,F4E6 D0 08    BNE $F4F0       load location not set in LOAD call, so continue with the
                                load
.,F4E8 A5 C3    LDA $C3         get the load address low byte
.,F4EA 85 AE    STA $AE         save the program start address low byte
.,F4EC A5 C4    LDA $C4         get the load address high byte
.,F4EE 85 AF    STA $AF         save the program start address high byte
.,F4F0 20 D2 F5 JSR $F5D2
.,F4F3 A9 FD    LDA #$FD        mask xxxx xx0x, clear time out read bit
.,F4F5 25 90    AND $90         mask the serial status byte
.,F4F7 85 90    STA $90         set the serial status byte
.,F4F9 20 E1 FF JSR $FFE1       scan stop key, return Zb = 1 = [STOP]
.,F4FC D0 03    BNE $F501       if not [STOP] go ??
.,F4FE 4C 33 F6 JMP $F633       else close the serial bus device and flag stop
.,F501 20 13 EE JSR $EE13       input byte from serial bus
.,F504 AA       TAX             copy byte
.,F505 A5 90    LDA $90         get the serial status byte
.,F507 4A       LSR             shift time out read ..
.,F508 4A       LSR             .. into carry bit
.,F509 B0 E8    BCS $F4F3       if timed out go try again
.,F50B 8A       TXA             copy received byte back
.,F50C A4 93    LDY $93         get load/verify flag
.,F50E F0 0C    BEQ $F51C       if load go load
                                else is verify
.,F510 A0 00    LDY #$00        clear index
.,F512 D1 AE    CMP ($AE),Y     compare byte with previously loaded byte
.,F514 F0 08    BEQ $F51E       if match go ??
.,F516 A9 10    LDA #$10        flag read error
.,F518 20 1C FE JSR $FE1C       OR into the serial status byte
.:F51B 2C       .BYTE $2C       makes next line BIT $AE91
.,F51C 91 AE    STA ($AE),Y     save byte to memory
.,F51E E6 AE    INC $AE         increment save pointer low byte
.,F520 D0 02    BNE $F524       if no rollover go ??
.,F522 E6 AF    INC $AF         else increment save pointer high byte
.,F524 24 90    BIT $90         test the serial status byte
.,F526 50 CB    BVC $F4F3       loop if not end of file
                                close file and exit
.,F528 20 EF ED JSR $EDEF       command serial bus to UNTALK
.,F52B 20 42 F6 JSR $F642       close serial bus device
.,F52E 90 79    BCC $F5A9       if ?? go flag ok and exit
.,F530 4C 04 F7 JMP $F704       do file not found error and return

??

.,F533 4A       LSR
.,F534 B0 03    BCS $F539
.,F536 4C 13 F7 JMP $F713       else do 'illegal device number' and return
.,F539 20 D0 F7 JSR $F7D0       get tape buffer start pointer in XY
.,F53C B0 03    BCS $F541       if ??
.,F53E 4C 13 F7 JMP $F713       else do 'illegal device number' and return
.,F541 20 17 F8 JSR $F817       wait for PLAY
.,F544 B0 68    BCS $F5AE       exit if STOP was pressed
.,F546 20 AF F5 JSR $F5AF       print "Searching..."
.,F549 A5 B7    LDA $B7         get file name length
.,F54B F0 09    BEQ $F556
.,F54D 20 EA F7 JSR $F7EA       find specific tape header
.,F550 90 0B    BCC $F55D       if no error continue
.,F552 F0 5A    BEQ $F5AE       exit if ??
.,F554 B0 DA    BCS $F530       , branch always
.,F556 20 2C F7 JSR $F72C       find tape header, exit with header in buffer
.,F559 F0 53    BEQ $F5AE       exit if ??
.,F55B B0 D3    BCS $F530
.,F55D A5 90    LDA $90         get the serial status byte
.,F55F 29 10    AND #$10        mask 000x 0000, read error
.,F561 38       SEC             flag fail
.,F562 D0 4A    BNE $F5AE       if read error just exit
.,F564 E0 01    CPX #$01
.,F566 F0 11    BEQ $F579
.,F568 E0 03    CPX #$03
.,F56A D0 DD    BNE $F549
.,F56C A0 01    LDY #$01
.,F56E B1 B2    LDA ($B2),Y
.,F570 85 C3    STA $C3
.,F572 C8       INY
.,F573 B1 B2    LDA ($B2),Y
.,F575 85 C4    STA $C4
.,F577 B0 04    BCS $F57D
.,F579 A5 B9    LDA $B9         get the secondary address
.,F57B D0 EF    BNE $F56C
.,F57D A0 03    LDY #$03
.,F57F B1 B2    LDA ($B2),Y
.,F581 A0 01    LDY #$01
.,F583 F1 B2    SBC ($B2),Y
.,F585 AA       TAX
.,F586 A0 04    LDY #$04
.,F588 B1 B2    LDA ($B2),Y
.,F58A A0 02    LDY #$02
.,F58C F1 B2    SBC ($B2),Y
.,F58E A8       TAY
.,F58F 18       CLC
.,F590 8A       TXA
.,F591 65 C3    ADC $C3
.,F593 85 AE    STA $AE
.,F595 98       TYA
.,F596 65 C4    ADC $C4
.,F598 85 AF    STA $AF
.,F59A A5 C3    LDA $C3
.,F59C 85 C1    STA $C1         set I/O start addresses low byte
.,F59E A5 C4    LDA $C4
.,F5A0 85 C2    STA $C2         set I/O start addresses high byte
.,F5A2 20 D2 F5 JSR $F5D2       display "LOADING" or "VERIFYING"
.,F5A5 20 4A F8 JSR $F84A       do the tape read
.:F5A8 24       .BYTE $24       makes next line BIT $18, keep the error flag in Cb
.,F5A9 18       CLC             flag ok
.,F5AA A6 AE    LDX $AE         get the LOAD end pointer low byte
.,F5AC A4 AF    LDY $AF         get the LOAD end pointer high byte
.,F5AE 60       RTS

print "Searching..."

.,F5AF A5 9D    LDA $9D         get message mode flag
.,F5B1 10 1E    BPL $F5D1       exit if control messages off
.,F5B3 A0 0C    LDY #$0C
                                index to "SEARCHING "
.,F5B5 20 2F F1 JSR $F12F       display kernel I/O message
.,F5B8 A5 B7    LDA $B7         get file name length
.,F5BA F0 15    BEQ $F5D1       exit if null name
.,F5BC A0 17    LDY #$17
                                else index to "FOR "
.,F5BE 20 2F F1 JSR $F12F       display kernel I/O message

print file name

.,F5C1 A4 B7    LDY $B7         get file name length
.,F5C3 F0 0C    BEQ $F5D1       exit if null file name
.,F5C5 A0 00    LDY #$00        clear index
.,F5C7 B1 BB    LDA ($BB),Y     get file name byte
.,F5C9 20 D2 FF JSR $FFD2       output character to channel
.,F5CC C8       INY             increment index
.,F5CD C4 B7    CPY $B7         compare with file name length
.,F5CF D0 F6    BNE $F5C7       loop if more to do
.,F5D1 60       RTS

display "LOADING" or "VERIFYING"

.,F5D2 A0 49    LDY #$49
                                point to "LOADING"
.,F5D4 A5 93    LDA $93         get load/verify flag
.,F5D6 F0 02    BEQ $F5DA       branch if load
.,F5D8 A0 59    LDY #$59
                                point to "VERIFYING"
.,F5DA 4C 2B F1 JMP $F12B       display kernel I/O message if in direct mode and return

save RAM to device, A = index to start address, XY = end address low/high

.,F5DD 86 AE    STX $AE         save end address low byte
.,F5DF 84 AF    STY $AF         save end address high byte
.,F5E1 AA       TAX             copy index to start pointer
.,F5E2 B5 00    LDA $00,X       get start address low byte
.,F5E4 85 C1    STA $C1         set I/O start addresses low byte
.,F5E6 B5 01    LDA $01,X       get start address high byte
.,F5E8 85 C2    STA $C2         set I/O start addresses high byte
.,F5EA 6C 32 03 JMP ($0332)     go save, usually points to $F685

save

.,F5ED A5 BA    LDA $BA         get the device number
.,F5EF D0 03    BNE $F5F4       if not keyboard go ??
                                else ..
.,F5F1 4C 13 F7 JMP $F713       else do 'illegal device number' and return
.,F5F4 C9 03    CMP #$03        compare device number with screen
.,F5F6 F0 F9    BEQ $F5F1       if screen do illegal device number and return
.,F5F8 90 5F    BCC $F659       branch if < screen
                                is greater than screen so is serial bus
.,F5FA A9 61    LDA #$61        set secondary address to $01
                                when a secondary address is to be sent to a device on
                                the serial bus the address must first be ORed with $60
.,F5FC 85 B9    STA $B9         save the secondary address
.,F5FE A4 B7    LDY $B7         get the file name length
.,F600 D0 03    BNE $F605       if filename not null continue
.,F602 4C 10 F7 JMP $F710       else do 'missing file name' error and return
.,F605 20 D5 F3 JSR $F3D5       send secondary address and filename
.,F608 20 8F F6 JSR $F68F       print saving 
.,F60B A5 BA    LDA $BA         get the device number
.,F60D 20 0C ED JSR $ED0C       command devices on the serial bus to LISTEN
.,F610 A5 B9    LDA $B9         get the secondary address
.,F612 20 B9 ED JSR $EDB9       send secondary address after LISTEN
.,F615 A0 00    LDY #$00        clear index
.,F617 20 8E FB JSR $FB8E       copy I/O start address to buffer address
.,F61A A5 AC    LDA $AC         get buffer address low byte
.,F61C 20 DD ED JSR $EDDD       output byte to serial bus
.,F61F A5 AD    LDA $AD         get buffer address high byte
.,F621 20 DD ED JSR $EDDD       output byte to serial bus
.,F624 20 D1 FC JSR $FCD1       check read/write pointer, return Cb = 1 if pointer >= end
.,F627 B0 16    BCS $F63F       go do UNLISTEN if at end
.,F629 B1 AC    LDA ($AC),Y     get byte from buffer
.,F62B 20 DD ED JSR $EDDD       output byte to serial bus
.,F62E 20 E1 FF JSR $FFE1       scan stop key
.,F631 D0 07    BNE $F63A       if stop not pressed go increment pointer and loop for next
                                else ..
                                close the serial bus device and flag stop
.,F633 20 42 F6 JSR $F642       close serial bus device
.,F636 A9 00    LDA #$00
.,F638 38       SEC             flag stop
.,F639 60       RTS
.,F63A 20 DB FC JSR $FCDB       increment read/write pointer
.,F63D D0 E5    BNE $F624       loop, branch always
.,F63F 20 FE ED JSR $EDFE       command serial bus to UNLISTEN
                                close serial bus device
.,F642 24 B9    BIT $B9         test the secondary address
.,F644 30 11    BMI $F657       if already closed just exit
.,F646 A5 BA    LDA $BA         get the device number
.,F648 20 0C ED JSR $ED0C       command devices on the serial bus to LISTEN
.,F64B A5 B9    LDA $B9         get the secondary address
.,F64D 29 EF    AND #$EF        mask the channel number
.,F64F 09 E0    ORA #$E0        OR with the CLOSE command
.,F651 20 B9 ED JSR $EDB9       send secondary address after LISTEN
.,F654 20 FE ED JSR $EDFE       command serial bus to UNLISTEN
.,F657 18       CLC             flag ok
.,F658 60       RTS
.,F659 4A       LSR
.,F65A B0 03    BCS $F65F       if not RS232 device ??
.,F65C 4C 13 F7 JMP $F713       else do 'illegal device number' and return
.,F65F 20 D0 F7 JSR $F7D0       get tape buffer start pointer in XY
.,F662 90 8D    BCC $F5F1       if < $0200 do illegal device number and return
.,F664 20 38 F8 JSR $F838       wait for PLAY/RECORD
.,F667 B0 25    BCS $F68E       exit if STOP was pressed
.,F669 20 8F F6 JSR $F68F       print saving 
.,F66C A2 03    LDX #$03        set header for a non relocatable program file
.,F66E A5 B9    LDA $B9         get the secondary address
.,F670 29 01    AND #$01        mask non relocatable bit
.,F672 D0 02    BNE $F676       if non relocatable program go ??
.,F674 A2 01    LDX #$01        else set header for a relocatable program file
.,F676 8A       TXA             copy header type to A
.,F677 20 6A F7 JSR $F76A       write tape header
.,F67A B0 12    BCS $F68E       exit if error
.,F67C 20 67 F8 JSR $F867       do tape write, 20 cycle count
.,F67F B0 0D    BCS $F68E       exit if error
.,F681 A5 B9    LDA $B9         get the secondary address
.,F683 29 02    AND #$02        mask end of tape flag
.,F685 F0 06    BEQ $F68D       if not end of tape go ??
.,F687 A9 05    LDA #$05        else set logical end of the tape
.,F689 20 6A F7 JSR $F76A       write tape header
.:F68C 24       .BYTE $24       makes next line BIT $18 so Cb is not changed
.,F68D 18       CLC             flag ok
.,F68E 60       RTS

print saving <file name>

.,F68F A5 9D    LDA $9D         get message mode flag
.,F691 10 FB    BPL $F68E       exit if control messages off
.,F693 A0 51    LDY #$51
                                index to "SAVING "
.,F695 20 2F F1 JSR $F12F       display kernel I/O message
.,F698 4C C1 F5 JMP $F5C1       print file name and return

increment the real time clock

.,F69B A2 00    LDX #$00        clear X
.,F69D E6 A2    INC $A2         increment the jiffy clock low byte
.,F69F D0 06    BNE $F6A7       if no rollover ??
.,F6A1 E6 A1    INC $A1         increment the jiffy clock mid byte
.,F6A3 D0 02    BNE $F6A7       branch if no rollover
.,F6A5 E6 A0    INC $A0         increment the jiffy clock high byte
                                now subtract a days worth of jiffies from current count
                                and remember only the Cb result
.,F6A7 38       SEC             set carry for subtract
.,F6A8 A5 A2    LDA $A2         get the jiffy clock low byte
.,F6AA E9 01    SBC #$01        subtract $4F1A01 low byte
.,F6AC A5 A1    LDA $A1         get the jiffy clock mid byte
.,F6AE E9 1A    SBC #$1A        subtract $4F1A01 mid byte
.,F6B0 A5 A0    LDA $A0         get the jiffy clock high byte
.,F6B2 E9 4F    SBC #$4F        subtract $4F1A01 high byte
.,F6B4 90 06    BCC $F6BC       if less than $4F1A01 jiffies skip the clock reset
                                else ..
.,F6B6 86 A0    STX $A0         clear the jiffy clock high byte
.,F6B8 86 A1    STX $A1         clear the jiffy clock mid byte
.,F6BA 86 A2    STX $A2         clear the jiffy clock low byte
                                this is wrong, there are $4F1A00 jiffies in a day so
                                the reset to zero should occur when the value reaches
                                $4F1A00 and not $4F1A01. this would give an extra jiffy
                                every day and a possible TI value of 24:00:00
.,F6BC AD 01 DC LDA $DC01       read VIA 1 DRB, keyboard row port
.,F6BF CD 01 DC CMP $DC01       compare it with itself
.,F6C2 D0 F8    BNE $F6BC       loop if changing
.,F6C4 AA       TAX
.,F6C5 30 13    BMI $F6DA
.,F6C7 A2 BD    LDX #$BD        set c6
.,F6C9 8E 00 DC STX $DC00       save VIA 1 DRA, keyboard column drive
.,F6CC AE 01 DC LDX $DC01       read VIA 1 DRB, keyboard row port
.,F6CF EC 01 DC CPX $DC01       compare it with itself
.,F6D2 D0 F8    BNE $F6CC       loop if changing
.,F6D4 8D 00 DC STA $DC00       save VIA 1 DRA, keyboard column drive
.,F6D7 E8       INX
.,F6D8 D0 02    BNE $F6DC
.,F6DA 85 91    STA $91         save the stop key column
.,F6DC 60       RTS

read the real time clock

.,F6DD 78       SEI             disable the interrupts
.,F6DE A5 A2    LDA $A2         get the jiffy clock low byte
.,F6E0 A6 A1    LDX $A1         get the jiffy clock mid byte
.,F6E2 A4 A0    LDY $A0         get the jiffy clock high byte

set the real time clock

.,F6E4 78       SEI             disable the interrupts
.,F6E5 85 A2    STA $A2         save the jiffy clock low byte
.,F6E7 86 A1    STX $A1         save the jiffy clock mid byte
.,F6E9 84 A0    STY $A0         save the jiffy clock high byte
.,F6EB 58       CLI             enable the interrupts
.,F6EC 60       RTS

scan the stop key, return Zb = 1 = [STOP]

.,F6ED A5 91    LDA $91         read the stop key column
.,F6EF C9 7F    CMP #$7F        compare with [STP] down
.,F6F1 D0 07    BNE $F6FA       if not [STP] or not just [STP] exit
                                just [STP] was pressed
.,F6F3 08       PHP             save status
.,F6F4 20 CC FF JSR $FFCC       close input and output channels
.,F6F7 85 C6    STA $C6         save the keyboard buffer index
.,F6F9 28       PLP             restore status
.,F6FA 60       RTS

file error messages

.,F6FB A9 01    LDA #$01        'too many files' error
.:F6FD 2C       .BYTE $2C       makes next line BIT $02A9
.,F6FE A9 02    LDA #$02        'file already open' error
.:F700 2C       .BYTE $2C       makes next line BIT $03A9
.,F701 A9 03    LDA #$03        'file not open' error
.:F703 2C       .BYTE $2C       makes next line BIT $04A9
.,F704 A9 04    LDA #$04        'file not found' error
.:F706 2C       .BYTE $2C       makes next line BIT $05A9
.,F707 A9 05    LDA #$05        'device not present' error
.:F709 2C       .BYTE $2C       makes next line BIT $06A9
.,F70A A9 06    LDA #$06        'not input file' error
.:F70C 2C       .BYTE $2C       makes next line BIT $07A9
.,F70D A9 07    LDA #$07        'not output file' error
.:F70F 2C       .BYTE $2C       makes next line BIT $08A9
.,F710 A9 08    LDA #$08        'missing file name' error
.:F712 2C       .BYTE $2C       makes next line BIT $09A9
.,F713 A9 09    LDA #$09        do 'illegal device number'
.,F715 48       PHA             save the error #
.,F716 20 CC FF JSR $FFCC       close input and output channels
.,F719 A0 00    LDY #$00
                                index to "I/O ERROR #"
.,F71B 24 9D    BIT $9D         test message mode flag
.,F71D 50 0A    BVC $F729       exit if kernal messages off
.,F71F 20 2F F1 JSR $F12F       display kernel I/O message
.,F722 68       PLA             restore error #
.,F723 48       PHA             copy error #
.,F724 09 30    ORA #$30        convert to ASCII
.,F726 20 D2 FF JSR $FFD2       output character to channel
.,F729 68       PLA             pull error number
.,F72A 38       SEC             flag error
.,F72B 60       RTS

find the tape header, exit with header in buffer

.,F72C A5 93    LDA $93         get load/verify flag
.,F72E 48       PHA             save load/verify flag
.,F72F 20 41 F8 JSR $F841       initiate tape read
.,F732 68       PLA             restore load/verify flag
.,F733 85 93    STA $93         save load/verify flag
.,F735 B0 32    BCS $F769       exit if error
.,F737 A0 00    LDY #$00        clear the index
.,F739 B1 B2    LDA ($B2),Y     read first byte from tape buffer
.,F73B C9 05    CMP #$05        compare with logical end of the tape
.,F73D F0 2A    BEQ $F769       if end of the tape exit
.,F73F C9 01    CMP #$01        compare with header for a relocatable program file
.,F741 F0 08    BEQ $F74B       if program file header go ??
.,F743 C9 03    CMP #$03        compare with header for a non relocatable program file
.,F745 F0 04    BEQ $F74B       if program file header go  ??
.,F747 C9 04    CMP #$04        compare with data file header
.,F749 D0 E1    BNE $F72C       if data file loop to find the tape header
                                was a program file header
.,F74B AA       TAX             copy header type
.,F74C 24 9D    BIT $9D         get message mode flag
.,F74E 10 17    BPL $F767       exit if control messages off
.,F750 A0 63    LDY #$63
                                index to "FOUND "
.,F752 20 2F F1 JSR $F12F       display kernel I/O message
.,F755 A0 05    LDY #$05        index to the tape filename
.,F757 B1 B2    LDA ($B2),Y     get byte from tape buffer
.,F759 20 D2 FF JSR $FFD2       output character to channel
.,F75C C8       INY             increment the index
.,F75D C0 15    CPY #$15        compare it with end+1
.,F75F D0 F6    BNE $F757       loop if more to do
.,F761 A5 A1    LDA $A1         get the jiffy clock mid byte
.,F763 20 E0 E4 JSR $E4E0       wait ~8.5 seconds for any key from the STOP key column
.,F766 EA       NOP             waste cycles
.,F767 18       CLC             flag no error
.,F768 88       DEY             decrement the index
.,F769 60       RTS

write the tape header

.,F76A 85 9E    STA $9E         save header type
.,F76C 20 D0 F7 JSR $F7D0       get tape buffer start pointer in XY
.,F76F 90 5E    BCC $F7CF       if < $0200 just exit ??
.,F771 A5 C2    LDA $C2         get I/O start address high byte
.,F773 48       PHA             save it
.,F774 A5 C1    LDA $C1         get I/O start address low byte
.,F776 48       PHA             save it
.,F777 A5 AF    LDA $AF         get tape end address high byte
.,F779 48       PHA             save it
.,F77A A5 AE    LDA $AE         get tape end address low byte
.,F77C 48       PHA             save it
.,F77D A0 BF    LDY #$BF        index to header end
.,F77F A9 20    LDA #$20        clear byte, [SPACE]
.,F781 91 B2    STA ($B2),Y     clear header byte
.,F783 88       DEY             decrement index
.,F784 D0 FB    BNE $F781       loop if more to do
.,F786 A5 9E    LDA $9E         get the header type back
.,F788 91 B2    STA ($B2),Y     write it to header
.,F78A C8       INY             increment the index
.,F78B A5 C1    LDA $C1         get the I/O start address low byte
.,F78D 91 B2    STA ($B2),Y     write it to header
.,F78F C8       INY             increment the index
.,F790 A5 C2    LDA $C2         get the I/O start address high byte
.,F792 91 B2    STA ($B2),Y     write it to header
.,F794 C8       INY             increment the index
.,F795 A5 AE    LDA $AE         get the tape end address low byte
.,F797 91 B2    STA ($B2),Y     write it to header
.,F799 C8       INY             increment the index
.,F79A A5 AF    LDA $AF         get the tape end address high byte
.,F79C 91 B2    STA ($B2),Y     write it to header
.,F79E C8       INY             increment the index
.,F79F 84 9F    STY $9F         save the index
.,F7A1 A0 00    LDY #$00        clear Y
.,F7A3 84 9E    STY $9E         clear the name index
.,F7A5 A4 9E    LDY $9E         get name index
.,F7A7 C4 B7    CPY $B7         compare with file name length
.,F7A9 F0 0C    BEQ $F7B7       if all done exit the loop
.,F7AB B1 BB    LDA ($BB),Y     get file name byte
.,F7AD A4 9F    LDY $9F         get buffer index
.,F7AF 91 B2    STA ($B2),Y     save file name byte to buffer
.,F7B1 E6 9E    INC $9E         increment file name index
.,F7B3 E6 9F    INC $9F         increment tape buffer index
.,F7B5 D0 EE    BNE $F7A5       loop, branch always
.,F7B7 20 D7 F7 JSR $F7D7       set tape buffer start and end pointers
.,F7BA A9 69    LDA #$69set write lead cycle count
.,F7BC 85 AB    STA $AB         save write lead cycle count
.,F7BE 20 6B F8 JSR $F86B       do tape write, no cycle count set
.,F7C1 A8       TAY
.,F7C2 68       PLA             pull tape end address low byte
.,F7C3 85 AE    STA $AE         restore it
.,F7C5 68       PLA             pull tape end address high byte
.,F7C6 85 AF    STA $AF         restore it
.,F7C8 68       PLA             pull I/O start addresses low byte
.,F7C9 85 C1    STA $C1         restore it
.,F7CB 68       PLA             pull I/O start addresses high byte
.,F7CC 85 C2    STA $C2         restore it
.,F7CE 98       TYA
.,F7CF 60       RTS

get the tape buffer start pointer

.,F7D0 A6 B2    LDX $B2         get tape buffer start pointer low byte
.,F7D2 A4 B3    LDY $B3         get tape buffer start pointer high byte
.,F7D4 C0 02    CPY #$02        compare high byte with $02xx
.,F7D6 60       RTS

set the tape buffer start and end pointers

.,F7D7 20 D0 F7 JSR $F7D0       get tape buffer start pointer in XY
.,F7DA 8A       TXA             copy tape buffer start pointer low byte
.,F7DB 85 C1    STA $C1         save as I/O address pointer low byte
.,F7DD 18       CLC             clear carry for add
.,F7DE 69 C0    ADC #$C0        add buffer length low byte
.,F7E0 85 AE    STA $AE         save tape buffer end pointer low byte
.,F7E2 98       TYA             copy tape buffer start pointer high byte
.,F7E3 85 C2    STA $C2         save as I/O address pointer high byte
.,F7E5 69 00    ADC #$00        add buffer length high byte
.,F7E7 85 AF    STA $AF         save tape buffer end pointer high byte
.,F7E9 60       RTS

find specific tape header

.,F7EA 20 2C F7 JSR $F72C       find tape header, exit with header in buffer
.,F7ED B0 1D    BCS $F80C       just exit if error
.,F7EF A0 05    LDY #$05        index to name
.,F7F1 84 9F    STY $9F         save as tape buffer index
.,F7F3 A0 00    LDY #$00        clear Y
.,F7F5 84 9E    STY $9E         save as name buffer index
.,F7F7 C4 B7    CPY $B7         compare with file name length
.,F7F9 F0 10    BEQ $F80B       ok exit if match
.,F7FB B1 BB    LDA ($BB),Y     get file name byte
.,F7FD A4 9F    LDY $9F         get index to tape buffer
.,F7FF D1 B2    CMP ($B2),Y     compare with tape header name byte
.,F801 D0 E7    BNE $F7EA       if no match go get next header
.,F803 E6 9E    INC $9E         else increment name buffer index
.,F805 E6 9F    INC $9F         increment tape buffer index
.,F807 A4 9E    LDY $9E         get name buffer index
.,F809 D0 EC    BNE $F7F7       loop, branch always
.,F80B 18       CLC             flag ok
.,F80C 60       RTS

bump tape pointer

.,F80D 20 D0 F7 JSR $F7D0       get tape buffer start pointer in XY
.,F810 E6 A6    INC $A6         increment tape buffer index
.,F812 A4 A6    LDY $A6         get tape buffer index
.,F814 C0 C0    CPY #$C0        compare with buffer length
.,F816 60       RTS

wait for PLAY

.,F817 20 2E F8 JSR $F82E       return cassette sense in Zb
.,F81A F0 1A    BEQ $F836       if switch closed just exit
                                cassette switch was open
.,F81C A0 1B    LDY #$1B
                                index to "PRESS PLAY ON TAPE"
.,F81E 20 2F F1 JSR $F12F       display kernel I/O message
.,F821 20 D0 F8 JSR $F8D0       scan stop key and flag abort if pressed
                                note if STOP was pressed the return is to the
                                routine that called this one and not here
.,F824 20 2E F8 JSR $F82E       return cassette sense in Zb
.,F827 D0 F8    BNE $F821       loop if the cassette switch is open
.,F829 A0 6A    LDY #$6A
                                index to "OK"
.,F82B 4C 2F F1 JMP $F12F       display kernel I/O message and return

return cassette sense in Zb

.,F82E A9 10    LDA #$10        set the mask for the cassette switch
.,F830 24 01    BIT $01         test the 6510 I/O port
.,F832 D0 02    BNE $F836       branch if cassette sense high
.,F834 24 01    BIT $01         test the 6510 I/O port
.,F836 18       CLC
.,F837 60       RTS

wait for PLAY/RECORD

.,F838 20 2E F8 JSR $F82E       return the cassette sense in Zb
.,F83B F0 F9    BEQ $F836       exit if switch closed
                                cassette switch was open
.,F83D A0 2E    LDY #$2E
                                index to "PRESS RECORD & PLAY ON TAPE"
.,F83F D0 DD    BNE $F81E       display message and wait for switch, branch always

initiate a tape read

.,F841 A9 00    LDA #$00        clear A
.,F843 85 90    STA $90         clear serial status byte
.,F845 85 93    STA $93         clear the load/verify flag
.,F847 20 D7 F7 JSR $F7D7       set the tape buffer start and end pointers
.,F84A 20 17 F8 JSR $F817       wait for PLAY
.,F84D B0 1F    BCS $F86E       exit if STOP was pressed, uses a further BCS at the
                                target address to reach final target at $F8DC
.,F84F 78       SEI             disable interrupts
.,F850 A9 00    LDA #$00        clear A
.,F852 85 AA    STA $AA
.,F854 85 B4    STA $B4
.,F856 85 B0    STA $B0         clear tape timing constant min byte
.,F858 85 9E    STA $9E         clear tape pass 1 error log/char buffer
.,F85A 85 9F    STA $9F         clear tape pass 2 error log corrected
.,F85C 85 9C    STA $9C         clear byte received flag
.,F85E A9 90    LDA #$90        enable CA1 interrupt ??
.,F860 A2 0E    LDX #$0E        set index for tape read vector
.,F862 D0 11    BNE $F875       go do tape read/write, branch always

initiate a tape write

.,F864 20 D7 F7 JSR $F7D7       set tape buffer start and end pointers
                                do tape write, 20 cycle count
.,F867 A9 14    LDA #$14        set write lead cycle count
.,F869 85 AB    STA $AB         save write lead cycle count
                                do tape write, no cycle count set
.,F86B 20 38 F8 JSR $F838       wait for PLAY/RECORD
.,F86E B0 6C    BCS $F8DC       if STOPped clear save IRQ address and exit
.,F870 78       SEI             disable interrupts
.,F871 A9 82    LDA #$82        enable ?? interrupt
.,F873 A2 08    LDX #$08        set index for tape write tape leader vector

tape read/write

.,F875 A0 7F    LDY #$7F        disable all interrupts
.,F877 8C 0D DC STY $DC0D       save VIA 1 ICR, disable all interrupts
.,F87A 8D 0D DC STA $DC0D       save VIA 1 ICR, enable interrupts according to A
                                check RS232 bus idle
.,F87D AD 0E DC LDA $DC0E       read VIA 1 CRA
.,F880 09 19    ORA #$19        load timer B, timer B single shot, start timer B
.,F882 8D 0F DC STA $DC0F       save VIA 1 CRB
.,F885 29 91    AND #$91        mask x00x 000x, TOD clock, load timer A, start timer A
.,F887 8D A2 02 STA $02A2       save VIA 1 CRB shadow copy
.,F88A 20 A4 F0 JSR $F0A4
.,F88D AD 11 D0 LDA $D011       read the vertical fine scroll and control register
.,F890 29 EF    AND #$EF        mask xxx0 xxxx, blank the screen
.,F892 8D 11 D0 STA $D011       save the vertical fine scroll and control register
.,F895 AD 14 03 LDA $0314       get IRQ vector low byte
.,F898 8D 9F 02 STA $029F       save IRQ vector low byte
.,F89B AD 15 03 LDA $0315       get IRQ vector high byte
.,F89E 8D A0 02 STA $02A0       save IRQ vector high byte
.,F8A1 20 BD FC JSR $FCBD       set the tape vector
.,F8A4 A9 02    LDA #$02        set copies count. the first copy is the load copy, the
                                second copy is the verify copy
.,F8A6 85 BE    STA $BE         save copies count
.,F8A8 20 97 FB JSR $FB97       new tape byte setup
.,F8AB A5 01    LDA $01         read the 6510 I/O port
.,F8AD 29 1F    AND #$1F        mask 000x xxxx, cassette motor on ??
.,F8AF 85 01    STA $01         save the 6510 I/O port
.,F8B1 85 C0    STA $C0         set the tape motor interlock
                                326656 cycle delay, allow tape motor speed to stabilise
.,F8B3 A2 FF    LDX #$FF        outer loop count
.,F8B5 A0 FF    LDY #$FF        inner loop count
.,F8B7 88       DEY             decrement inner loop count
.,F8B8 D0 FD    BNE $F8B7       loop if more to do
.,F8BA CA       DEX             decrement outer loop count
.,F8BB D0 F8    BNE $F8B5       loop if more to do
.,F8BD 58       CLI             enable tape interrupts
.,F8BE AD A0 02 LDA $02A0       get saved IRQ high byte
.,F8C1 CD 15 03 CMP $0315       compare with the current IRQ high byte
.,F8C4 18       CLC             flag ok
.,F8C5 F0 15    BEQ $F8DC       if tape write done go clear saved IRQ address and exit
.,F8C7 20 D0 F8 JSR $F8D0       scan stop key and flag abort if pressed
                                note if STOP was pressed the return is to the
                                routine that called this one and not here
.,F8CA 20 BC F6 JSR $F6BC       increment real time clock
.,F8CD 4C BE F8 JMP $F8BE       loop

scan stop key and flag abort if pressed

.,F8D0 20 E1 FF JSR $FFE1       scan stop key
.,F8D3 18       CLC             flag no stop
.,F8D4 D0 0B    BNE $F8E1       exit if no stop
.,F8D6 20 93 FC JSR $FC93       restore everything for STOP
.,F8D9 38       SEC             flag stopped
.,F8DA 68       PLA             dump return address low byte
.,F8DB 68       PLA             dump return address high byte

clear saved IRQ address

.,F8DC A9 00    LDA #$00        clear A
.,F8DE 8D A0 02 STA $02A0       clear saved IRQ address high byte
.,F8E1 60       RTS

# set timing

.,F8E2 86 B1    STX $B1         save tape timing constant max byte
.,F8E4 A5 B0    LDA $B0         get tape timing constant min byte
.,F8E6 0A       ASL             *2
.,F8E7 0A       ASL             *4
.,F8E8 18       CLC             clear carry for add
.,F8E9 65 B0    ADC $B0         add tape timing constant min byte *5
.,F8EB 18       CLC             clear carry for add
.,F8EC 65 B1    ADC $B1         add tape timing constant max byte
.,F8EE 85 B1    STA $B1         save tape timing constant max byte
.,F8F0 A9 00    LDA #$00
.,F8F2 24 B0    BIT $B0         test tape timing constant min byte
.,F8F4 30 01    BMI $F8F7       branch if b7 set
.,F8F6 2A       ROL             else shift carry into ??
.,F8F7 06 B1    ASL $B1         shift tape timing constant max byte
.,F8F9 2A       ROL
.,F8FA 06 B1    ASL $B1         shift tape timing constant max byte
.,F8FC 2A       ROL
.,F8FD AA       TAX
.,F8FE AD 06 DC LDA $DC06       get VIA 1 timer B low byte
.,F901 C9 16    CMP #$16        compare with ??
.,F903 90 F9    BCC $F8FE       loop if less
.,F905 65 B1    ADC $B1         add tape timing constant max byte
.,F907 8D 04 DC STA $DC04       save VIA 1 timer A low byte
.,F90A 8A       TXA
.,F90B 6D 07 DC ADC $DC07       add VIA 1 timer B high byte
.,F90E 8D 05 DC STA $DC05       save VIA 1 timer A high byte
.,F911 AD A2 02 LDA $02A2       read VIA 1 CRB shadow copy
.,F914 8D 0E DC STA $DC0E       save VIA 1 CRA
.,F917 8D A4 02 STA $02A4       save VIA 1 CRA shadow copy
.,F91A AD 0D DC LDA $DC0D       read VIA 1 ICR
.,F91D 29 10    AND #$10        mask 000x 0000, FLAG interrupt
.,F91F F0 09    BEQ $F92A       if no FLAG interrupt just exit
                                else first call the IRQ routine
.,F921 A9 F9    LDA #$F9        set the return address high byte
.,F923 48       PHA             push the return address high byte
.,F924 A9 2A    LDA #$2A        set the return address low byte
.,F926 48       PHA             push the return address low byte
.,F927 4C 43 FF JMP $FF43       save the status and do the IRQ routine
.,F92A 58       CLI             enable interrupts
.,F92B 60       RTS

On Commodore computers, the streams consist of four kinds of symbols

                                that denote different kinds of low-to-high-to-low transitions on the
                                read or write signals of the Commodore cassette interface.

                                A A break in the communications, or a pulse with very long cycle
                                  time.

                                B A short pulse, whose cycle time typically ranges from 296 to 424
                                  microseconds, depending on the computer model.

                                C A medium-length pulse, whose cycle time typically ranges from
                                  440 to 576 microseconds, depending on the computer model.

                                D A long pulse, whose cycle time typically ranges from 600 to 744
                                  microseconds, depending on the computer model.

                                 The actual interpretation of the serial data takes a little more work to explain.
                                The typical ROM tape loader (and the turbo loaders) will initialize a timer with a
                                specified value and start it counting down. If either the tape data changes or the
                                timer runs out, an IRQ will occur. The loader will determine which condition caused
                                the IRQ. If the tape data changed before the timer ran out, we have a short pulse,
                                or a "0" bit. If the timer ran out first, we have a long pulse, or a "1" bit. Doing
                                this continuously and we decode the entire file.
                                read tape bits, IRQ routine
                                read T2C which has been counting down from $FFFF. subtract this from $FFFF
.,F92C AE 07 DC LDX $DC07       read VIA 1 timer B high byte
.,F92F A0 FF    LDY #$FF        set $FF
.,F931 98       TYA             A = $FF
.,F932 ED 06 DC SBC $DC06       subtract VIA 1 timer B low byte
.,F935 EC 07 DC CPX $DC07       compare it with VIA 1 timer B high byte
.,F938 D0 F2    BNE $F92C       if timer low byte rolled over loop
.,F93A 86 B1    STX $B1         save tape timing constant max byte
.,F93C AA       TAX             copy $FF - T2C_l
.,F93D 8C 06 DC STY $DC06       save VIA 1 timer B low byte
.,F940 8C 07 DC STY $DC07       save VIA 1 timer B high byte
.,F943 A9 19    LDA #$19        load timer B, timer B single shot, start timer B
.,F945 8D 0F DC STA $DC0F       save VIA 1 CRB
.,F948 AD 0D DC LDA $DC0D       read VIA 1 ICR
.,F94B 8D A3 02 STA $02A3       save VIA 1 ICR shadow copy
.,F94E 98       TYA             y = $FF
.,F94F E5 B1    SBC $B1         subtract tape timing constant max byte
                                A = $FF - T2C_h
.,F951 86 B1    STX $B1         save tape timing constant max byte
                                $B1 = $FF - T2C_l
.,F953 4A       LSR             A = $FF - T2C_h >> 1
.,F954 66 B1    ROR $B1         shift tape timing constant max byte
                                $B1 = $FF - T2C_l >> 1
.,F956 4A       LSR             A = $FF - T2C_h >> 1
.,F957 66 B1    ROR $B1         shift tape timing constant max byte
                                $B1 = $FF - T2C_l >> 1
.,F959 A5 B0    LDA $B0         get tape timing constant min byte
.,F95B 18       CLC             clear carry for add
.,F95C 69 3C    ADC #$3C
.,F95E C5 B1    CMP $B1         compare with tape timing constant max byte
                                compare with ($FFFF - T2C) >> 2
.,F960 B0 4A    BCS $F9AC       branch if min + $3C >= ($FFFF - T2C) >> 2
                                min + $3C < ($FFFF - T2C) >> 2
.,F962 A6 9C    LDX $9C         get byte received flag
.,F964 F0 03    BEQ $F969        if not byte received ??
.,F966 4C 60 FA JMP $FA60       store the tape character
.,F969 A6 A3    LDX $A3         get EOI flag byte
.,F96B 30 1B    BMI $F988
.,F96D A2 00    LDX #$00
.,F96F 69 30    ADC #$30
.,F971 65 B0    ADC $B0         add tape timing constant min byte
.,F973 C5 B1    CMP $B1         compare with tape timing constant max byte
.,F975 B0 1C    BCS $F993
.,F977 E8       INX
.,F978 69 26    ADC #$26
.,F97A 65 B0    ADC $B0         add tape timing constant min byte
.,F97C C5 B1    CMP $B1         compare with tape timing constant max byte
.,F97E B0 17    BCS $F997
.,F980 69 2C    ADC #$2C
.,F982 65 B0    ADC $B0         add tape timing constant min byte
.,F984 C5 B1    CMP $B1         compare with tape timing constant max byte
.,F986 90 03    BCC $F98B
.,F988 4C 10 FA JMP $FA10
.,F98B A5 B4    LDA $B4         get the bit count
.,F98D F0 1D    BEQ $F9AC       if all done go ??
.,F98F 85 A8    STA $A8         save receiver bit count in
.,F991 D0 19    BNE $F9AC       branch always
.,F993 E6 A9    INC $A9         increment ?? start bit check flag
.,F995 B0 02    BCS $F999
.,F997 C6 A9    DEC $A9         decrement ?? start bit check flag
.,F999 38       SEC
.,F99A E9 13    SBC #$13
.,F99C E5 B1    SBC $B1         subtract tape timing constant max byte
.,F99E 65 92    ADC $92         add timing constant for tape
.,F9A0 85 92    STA $92         save timing constant for tape
.,F9A2 A5 A4    LDA $A4         get tape bit cycle phase
.,F9A4 49 01    EOR #$01
.,F9A6 85 A4    STA $A4         save tape bit cycle phase
.,F9A8 F0 2B    BEQ $F9D5
.,F9AA 86 D7    STX $D7
.,F9AC A5 B4    LDA $B4         get the bit count
.,F9AE F0 22    BEQ $F9D2       if all done go ??
.,F9B0 AD A3 02 LDA $02A3       read VIA 1 ICR shadow copy
.,F9B3 29 01    AND #$01        mask 0000 000x, timer A interrupt enabled
.,F9B5 D0 05    BNE $F9BC       if timer A is enabled go ??
.,F9B7 AD A4 02 LDA $02A4       read VIA 1 CRA shadow copy
.,F9BA D0 16    BNE $F9D2       if ?? just exit
.,F9BC A9 00    LDA #$00        clear A
.,F9BE 85 A4    STA $A4         clear the tape bit cycle phase
.,F9C0 8D A4 02 STA $02A4       save VIA 1 CRA shadow copy
.,F9C3 A5 A3    LDA $A3         get EOI flag byte
.,F9C5 10 30    BPL $F9F7
.,F9C7 30 BF    BMI $F988
.,F9C9 A2 A6    LDX #$A6        set timimg max byte
.,F9CB 20 E2 F8 JSR $F8E2       set timing
.,F9CE A5 9B    LDA $9B
.,F9D0 D0 B9    BNE $F98B
.,F9D2 4C BC FE JMP $FEBC       restore registers and exit interrupt
.,F9D5 A5 92    LDA $92         get timing constant for tape
.,F9D7 F0 07    BEQ $F9E0
.,F9D9 30 03    BMI $F9DE
.,F9DB C6 B0    DEC $B0         decrement tape timing constant min byte
.:F9DD 2C       .BYTE $2C       makes next line BIT $B0E6
.,F9DE E6 B0    INC $B0         increment tape timing constant min byte
.,F9E0 A9 00    LDA #$00
.,F9E2 85 92    STA $92         clear timing constant for tape
.,F9E4 E4 D7    CPX $D7
.,F9E6 D0 0F    BNE $F9F7
.,F9E8 8A       TXA
.,F9E9 D0 A0    BNE $F98B
.,F9EB A5 A9    LDA $A9         get start bit check flag
.,F9ED 30 BD    BMI $F9AC
.,F9EF C9 10    CMP #$10
.,F9F1 90 B9    BCC $F9AC
.,F9F3 85 96    STA $96         save cassette block synchronization number
.,F9F5 B0 B5    BCS $F9AC
.,F9F7 8A       TXA
.,F9F8 45 9B    EOR $9B
.,F9FA 85 9B    STA $9B
.,F9FC A5 B4    LDA $B4
.,F9FE F0 D2    BEQ $F9D2
.,FA00 C6 A3    DEC $A3         decrement EOI flag byte
.,FA02 30 C5    BMI $F9C9
.,FA04 46 D7    LSR $D7
.,FA06 66 BF    ROR $BF         parity count
.,FA08 A2 DA    LDX #$DA        set timimg max byte
.,FA0A 20 E2 F8 JSR $F8E2       set timing
.,FA0D 4C BC FE JMP $FEBC       restore registers and exit interrupt
.,FA10 A5 96    LDA $96         get cassette block synchronization number
.,FA12 F0 04    BEQ $FA18
.,FA14 A5 B4    LDA $B4
.,FA16 F0 07    BEQ $FA1F
.,FA18 A5 A3    LDA $A3         get EOI flag byte
.,FA1A 30 03    BMI $FA1F
.,FA1C 4C 97 F9 JMP $F997
.,FA1F 46 B1    LSR $B1         shift tape timing constant max byte
.,FA21 A9 93    LDA #$93
.,FA23 38       SEC
.,FA24 E5 B1    SBC $B1         subtract tape timing constant max byte
.,FA26 65 B0    ADC $B0         add tape timing constant min byte
.,FA28 0A       ASL
.,FA29 AA       TAX             copy timimg high byte
.,FA2A 20 E2 F8 JSR $F8E2       set timing
.,FA2D E6 9C    INC $9C
.,FA2F A5 B4    LDA $B4
.,FA31 D0 11    BNE $FA44
.,FA33 A5 96    LDA $96         get cassette block synchronization number
.,FA35 F0 26    BEQ $FA5D
.,FA37 85 A8    STA $A8         save receiver bit count in
.,FA39 A9 00    LDA #$00        clear A
.,FA3B 85 96    STA $96         clear cassette block synchronization number
.,FA3D A9 81    LDA #$81        enable timer A interrupt
.,FA3F 8D 0D DC STA $DC0D       save VIA 1 ICR
.,FA42 85 B4    STA $B4
.,FA44 A5 96    LDA $96         get cassette block synchronization number
.,FA46 85 B5    STA $B5
.,FA48 F0 09    BEQ $FA53
.,FA4A A9 00    LDA #$00
.,FA4C 85 B4    STA $B4
.,FA4E A9 01    LDA #$01        disable timer A interrupt
.,FA50 8D 0D DC STA $DC0D       save VIA 1 ICR
.,FA53 A5 BF    LDA $BF         parity count
.,FA55 85 BD    STA $BD         save RS232 parity byte
.,FA57 A5 A8    LDA $A8         get receiver bit count in
.,FA59 05 A9    ORA $A9         OR with start bit check flag
.,FA5B 85 B6    STA $B6
.,FA5D 4C BC FE JMP $FEBC       restore registers and exit interrupt

# store character

.,FA60 20 97 FB JSR $FB97       new tape byte setup
.,FA63 85 9C    STA $9C         clear byte received flag
.,FA65 A2 DA    LDX #$DA        set timimg max byte
.,FA67 20 E2 F8 JSR $F8E2       set timing
.,FA6A A5 BE    LDA $BE         get copies count
.,FA6C F0 02    BEQ $FA70
.,FA6E 85 A7    STA $A7         save receiver input bit temporary storage
.,FA70 A9 0F    LDA #$0F
.,FA72 24 AA    BIT $AA
.,FA74 10 17    BPL $FA8D
.,FA76 A5 B5    LDA $B5
.,FA78 D0 0C    BNE $FA86
.,FA7A A6 BE    LDX $BE         get copies count
.,FA7C CA       DEX
.,FA7D D0 0B    BNE $FA8A       if ?? restore registers and exit interrupt
.,FA7F A9 08    LDA #$08        set short block
.,FA81 20 1C FE JSR $FE1C       OR into serial status byte
.,FA84 D0 04    BNE $FA8A       restore registers and exit interrupt, branch always
.,FA86 A9 00    LDA #$00
.,FA88 85 AA    STA $AA
.,FA8A 4C BC FE JMP $FEBC       restore registers and exit interrupt
.,FA8D 70 31    BVS $FAC0
.,FA8F D0 18    BNE $FAA9
.,FA91 A5 B5    LDA $B5
.,FA93 D0 F5    BNE $FA8A
.,FA95 A5 B6    LDA $B6
.,FA97 D0 F1    BNE $FA8A
.,FA99 A5 A7    LDA $A7         get receiver input bit temporary storage
.,FA9B 4A       LSR
.,FA9C A5 BD    LDA $BD         get RS232 parity byte
.,FA9E 30 03    BMI $FAA3
.,FAA0 90 18    BCC $FABA
.,FAA2 18       CLC
.,FAA3 B0 15    BCS $FABA
.,FAA5 29 0F    AND #$0F
.,FAA7 85 AA    STA $AA
.,FAA9 C6 AA    DEC $AA
.,FAAB D0 DD    BNE $FA8A
.,FAAD A9 40    LDA #$40
.,FAAF 85 AA    STA $AA
.,FAB1 20 8E FB JSR $FB8E       copy I/O start address to buffer address
.,FAB4 A9 00    LDA #$00
.,FAB6 85 AB    STA $AB
.,FAB8 F0 D0    BEQ $FA8A
.,FABA A9 80    LDA #$80
.,FABC 85 AA    STA $AA
.,FABE D0 CA    BNE $FA8A       restore registers and exit interrupt, branch always
.,FAC0 A5 B5    LDA $B5
.,FAC2 F0 0A    BEQ $FACE
.,FAC4 A9 04    LDA #$04
.,FAC6 20 1C FE JSR $FE1C       OR into serial status byte
.,FAC9 A9 00    LDA #$00
.,FACB 4C 4A FB JMP $FB4A
.,FACE 20 D1 FC JSR $FCD1       check read/write pointer, return Cb = 1 if pointer >= end
.,FAD1 90 03    BCC $FAD6
.,FAD3 4C 48 FB JMP $FB48
.,FAD6 A6 A7    LDX $A7         get receiver input bit temporary storage
.,FAD8 CA       DEX
.,FAD9 F0 2D    BEQ $FB08
.,FADB A5 93    LDA $93         get load/verify flag
.,FADD F0 0C    BEQ $FAEB       if load go ??
.,FADF A0 00    LDY #$00        clear index
.,FAE1 A5 BD    LDA $BD         get RS232 parity byte
.,FAE3 D1 AC    CMP ($AC),Y
.,FAE5 F0 04    BEQ $FAEB
.,FAE7 A9 01    LDA #$01
.,FAE9 85 B6    STA $B6
.,FAEB A5 B6    LDA $B6
.,FAED F0 4B    BEQ $FB3A
.,FAEF A2 3D    LDX #$3D
.,FAF1 E4 9E    CPX $9E
.,FAF3 90 3E    BCC $FB33
.,FAF5 A6 9E    LDX $9E
.,FAF7 A5 AD    LDA $AD
.,FAF9 9D 01 01 STA $0101,X
.,FAFC A5 AC    LDA $AC
.,FAFE 9D 00 01 STA $0100,X
.,FB01 E8       INX
.,FB02 E8       INX
.,FB03 86 9E    STX $9E
.,FB05 4C 3A FB JMP $FB3A
.,FB08 A6 9F    LDX $9F
.,FB0A E4 9E    CPX $9E
.,FB0C F0 35    BEQ $FB43
.,FB0E A5 AC    LDA $AC
.,FB10 DD 00 01 CMP $0100,X
.,FB13 D0 2E    BNE $FB43
.,FB15 A5 AD    LDA $AD
.,FB17 DD 01 01 CMP $0101,X
.,FB1A D0 27    BNE $FB43
.,FB1C E6 9F    INC $9F
.,FB1E E6 9F    INC $9F
.,FB20 A5 93    LDA $93         get load/verify flag
.,FB22 F0 0B    BEQ $FB2F       if load ??
.,FB24 A5 BD    LDA $BD         get RS232 parity byte
.,FB26 A0 00    LDY #$00
.,FB28 D1 AC    CMP ($AC),Y
.,FB2A F0 17    BEQ $FB43
.,FB2C C8       INY
.,FB2D 84 B6    STY $B6
.,FB2F A5 B6    LDA $B6
.,FB31 F0 07    BEQ $FB3A
.,FB33 A9 10    LDA #$10
.,FB35 20 1C FE JSR $FE1C       OR into serial status byte
.,FB38 D0 09    BNE $FB43
.,FB3A A5 93    LDA $93         get load/verify flag
.,FB3C D0 05    BNE $FB43       if verify go ??
.,FB3E A8       TAY
.,FB3F A5 BD    LDA $BD         get RS232 parity byte
.,FB41 91 AC    STA ($AC),Y
.,FB43 20 DB FC JSR $FCDB       increment read/write pointer
.,FB46 D0 43    BNE $FB8B       restore registers and exit interrupt, branch always
.,FB48 A9 80    LDA #$80
.,FB4A 85 AA    STA $AA
.,FB4C 78       SEI
.,FB4D A2 01    LDX #$01        disable timer A interrupt
.,FB4F 8E 0D DC STX $DC0D       save VIA 1 ICR
.,FB52 AE 0D DC LDX $DC0D       read VIA 1 ICR
.,FB55 A6 BE    LDX $BE         get copies count
.,FB57 CA       DEX
.,FB58 30 02    BMI $FB5C
.,FB5A 86 BE    STX $BE         save copies count
.,FB5C C6 A7    DEC $A7         decrement receiver input bit temporary storage
.,FB5E F0 08    BEQ $FB68
.,FB60 A5 9E    LDA $9E
.,FB62 D0 27    BNE $FB8B       if ?? restore registers and exit interrupt
.,FB64 85 BE    STA $BE         save copies count
.,FB66 F0 23    BEQ $FB8B       restore registers and exit interrupt, branch always
.,FB68 20 93 FC JSR $FC93       restore everything for STOP
.,FB6B 20 8E FB JSR $FB8E       copy I/O start address to buffer address
.,FB6E A0 00    LDY #$00        clear index
.,FB70 84 AB    STY $AB         clear checksum
.,FB72 B1 AC    LDA ($AC),Y     get byte from buffer
.,FB74 45 AB    EOR $AB         XOR with checksum
.,FB76 85 AB    STA $AB         save new checksum
.,FB78 20 DB FC JSR $FCDB       increment read/write pointer
.,FB7B 20 D1 FC JSR $FCD1       check read/write pointer, return Cb = 1 if pointer >= end
.,FB7E 90 F2    BCC $FB72       loop if not at end
.,FB80 A5 AB    LDA $AB         get computed checksum
.,FB82 45 BD    EOR $BD         compare with stored checksum ??
.,FB84 F0 05    BEQ $FB8B       if checksum ok restore registers and exit interrupt
.,FB86 A9 20    LDA #$20        else set checksum error
.,FB88 20 1C FE JSR $FE1C       OR into the serial status byte
.,FB8B 4C BC FE JMP $FEBC       restore registers and exit interrupt

copy I/O start address to buffer address

.,FB8E A5 C2    LDA $C2         get I/O start address high byte
.,FB90 85 AD    STA $AD         set buffer address high byte
.,FB92 A5 C1    LDA $C1         get I/O start address low byte
.,FB94 85 AC    STA $AC         set buffer address low byte
.,FB96 60       RTS

new tape byte setup

.,FB97 A9 08    LDA #$08        eight bits to do
.,FB99 85 A3    STA $A3         set bit count
.,FB9B A9 00    LDA #$00        clear A
.,FB9D 85 A4    STA $A4         clear tape bit cycle phase
.,FB9F 85 A8    STA $A8         clear start bit first cycle done flag
.,FBA1 85 9B    STA $9B         clear byte parity
.,FBA3 85 A9    STA $A9         clear start bit check flag, set no start bit yet
.,FBA5 60       RTS

send lsb from tape write byte to tape

                                this routine tests the least significant bit in the tape write byte and sets VIA 2 T2
                                depending on the state of the bit. if the bit is a 1 a time of $00B0 cycles is set, if
                                the bot is a 0 a time of $0060 cycles is set. note that this routine does not shift the
                                bits of the tape write byte but uses a copy of that byte, the byte itself is shifted
                                elsewhere
.,FBA6 A5 BD    LDA $BD         get tape write byte
.,FBA8 4A       LSR             shift lsb into Cb
.,FBA9 A9 60    LDA #$60        set time constant low byte for bit = 0
.,FBAB 90 02    BCC $FBAF       branch if bit was 0
                                set time constant for bit = 1 and toggle tape
.,FBAD A9 B0    LDA #$B0        set time constant low byte for bit = 1
                                write time constant and toggle tape
.,FBAF A2 00    LDX #$00        set time constant high byte
                                write time constant and toggle tape
.,FBB1 8D 06 DC STA $DC06       save VIA 1 timer B low byte
.,FBB4 8E 07 DC STX $DC07       save VIA 1 timer B high byte
.,FBB7 AD 0D DC LDA $DC0D       read VIA 1 ICR
.,FBBA A9 19    LDA #$19        load timer B, timer B single shot, start timer B
.,FBBC 8D 0F DC STA $DC0F       save VIA 1 CRB
.,FBBF A5 01    LDA $01         read the 6510 I/O port
.,FBC1 49 08    EOR #$08        toggle tape out bit
.,FBC3 85 01    STA $01         save the 6510 I/O port
.,FBC5 29 08    AND #$08        mask tape out bit
.,FBC7 60       RTS

flag block done and exit interrupt

.,FBC8 38       SEC             set carry flag
.,FBC9 66 B6    ROR $B6         set buffer address high byte negative, flag all sync,
                                data and checksum bytes written
.,FBCB 30 3C    BMI $FC09       restore registers and exit interrupt, branch always

tape write IRQ routine

                                this is the routine that writes the bits to the tape. it is called each time VIA 2 T2
                                times out and checks if the start bit is done, if so checks if the data bits are done,
                                if so it checks if the byte is done, if so it checks if the synchronisation bytes are
                                done, if so it checks if the data bytes are done, if so it checks if the checksum byte
                                is done, if so it checks if both the load and verify copies have been done, if so it
                                stops the tape
.,FBCD A5 A8    LDA $A8         get start bit first cycle done flag
.,FBCF D0 12    BNE $FBE3       if first cycle done go do rest of byte
                                each byte sent starts with two half cycles of $0110 ststem clocks and the whole block
                                ends with two more such half cycles
.,FBD1 A9 10    LDA #$10        set first start cycle time constant low byte
.,FBD3 A2 01    LDX #$01        set first start cycle time constant high byte
.,FBD5 20 B1 FB JSR $FBB1       write time constant and toggle tape
.,FBD8 D0 2F    BNE $FC09       if first half cycle go restore registers and exit
                                interrupt
.,FBDA E6 A8    INC $A8         set start bit first start cycle done flag
.,FBDC A5 B6    LDA $B6         get buffer address high byte
.,FBDE 10 29    BPL $FC09       if block not complete go restore registers and exit
                                interrupt. the end of a block is indicated by the tape
                                buffer high byte b7 being set to 1
.,FBE0 4C 57 FC JMP $FC57       else do tape routine, block complete exit
                                continue tape byte write. the first start cycle, both half cycles of it, is complete
                                so the routine drops straight through to here
.,FBE3 A5 A9    LDA $A9         get start bit check flag
.,FBE5 D0 09    BNE $FBF0       if the start bit is complete go send the byte bits
                                after the two half cycles of $0110 ststem clocks the start bit is completed with two
                                half cycles of $00B0 system clocks. this is the same as the first part of a 1 bit
.,FBE7 20 AD FB JSR $FBAD       set time constant for bit = 1 and toggle tape
.,FBEA D0 1D    BNE $FC09       if first half cycle go restore registers and exit
                                interrupt
.,FBEC E6 A9    INC $A9         set start bit check flag
.,FBEE D0 19    BNE $FC09       restore registers and exit interrupt, branch always
                                continue tape byte write. the start bit, both cycles of it, is complete so the routine
                                drops straight through to here. now the cycle pairs for each bit, and the parity bit,
                                are sent
.,FBF0 20 A6 FB JSR $FBA6       send lsb from tape write byte to tape
.,FBF3 D0 14    BNE $FC09       if first half cycle go restore registers and exit
                                interrupt
                                else two half cycles have been done
.,FBF5 A5 A4    LDA $A4         get tape bit cycle phase
.,FBF7 49 01    EOR #$01        toggle b0
.,FBF9 85 A4    STA $A4         save tape bit cycle phase
.,FBFB F0 0F    BEQ $FC0C       if bit cycle phase complete go setup for next bit
                                each bit is written as two full cycles. a 1 is sent as a full cycle of $0160 system
                                clocks then a full cycle of $00C0 system clocks. a 0 is sent as a full cycle of $00C0
                                system clocks then a full cycle of $0160 system clocks. to do this each bit from the
                                write byte is inverted during the second bit cycle phase. as the bit is inverted it
                                is also added to the, one bit, parity count for this byte
.,FBFD A5 BD    LDA $BD         get tape write byte
.,FBFF 49 01    EOR #$01        invert bit being sent
.,FC01 85 BD    STA $BD         save tape write byte
.,FC03 29 01    AND #$01        mask b0
.,FC05 45 9B    EOR $9B         EOR with tape write byte parity bit
.,FC07 85 9B    STA $9B         save tape write byte parity bit
.,FC09 4C BC FE JMP $FEBC       restore registers and exit interrupt
                                the bit cycle phase is complete so shift out the just written bit and test for byte
                                end
.,FC0C 46 BD    LSR $BD         shift bit out of tape write byte
.,FC0E C6 A3    DEC $A3         decrement tape write bit count
.,FC10 A5 A3    LDA $A3         get tape write bit count
.,FC12 F0 3A    BEQ $FC4E       if all the data bits have been written go setup for
                                sending the parity bit next and exit the interrupt
.,FC14 10 F3    BPL $FC09       if all the data bits are not yet sent just restore the
                                registers and exit the interrupt
                                do next tape byte
                                the byte is complete. the start bit, data bits and parity bit have been written to
                                the tape so setup for the next byte
.,FC16 20 97 FB JSR $FB97       new tape byte setup
.,FC19 58       CLI             enable the interrupts
.,FC1A A5 A5    LDA $A5         get cassette synchronization character count
.,FC1C F0 12    BEQ $FC30       if synchronisation characters done go do block data
                                at the start of each block sent to tape there are a number of synchronisation bytes
                                that count down to the actual data. the commodore tape system saves two copies of all
                                the tape data, the first is loaded and is indicated by the synchronisation bytes
                                having b7 set, and the second copy is indicated by the synchronisation bytes having b7
                                clear. the sequence goes $09, $08, ..... $02, $01, data bytes
.,FC1E A2 00    LDX #$00        clear X
.,FC20 86 D7    STX $D7         clear checksum byte
.,FC22 C6 A5    DEC $A5         decrement cassette synchronization byte count
.,FC24 A6 BE    LDX $BE         get cassette copies count
.,FC26 E0 02    CPX #$02        compare with load block indicator
.,FC28 D0 02    BNE $FC2C       branch if not the load block
.,FC2A 09 80    ORA #$80        this is the load block so make the synchronisation count
                                go $89, $88, ..... $82, $81
.,FC2C 85 BD    STA $BD         save the synchronisation byte as the tape write byte
.,FC2E D0 D9    BNE $FC09       restore registers and exit interrupt, branch always
                                the synchronization bytes have been done so now check and do the actual block data
.,FC30 20 D1 FC JSR $FCD1       check read/write pointer, return Cb = 1 if pointer >= end
.,FC33 90 0A    BCC $FC3F       if not all done yet go get the byte to send
.,FC35 D0 91    BNE $FBC8       if pointer > end go flag block done and exit interrupt
                                else the block is complete, it only remains to write the
                                checksum byte to the tape so setup for that
.,FC37 E6 AD    INC $AD         increment buffer pointer high byte, this means the block
                                done branch will always be taken next time without having
                                to worry about the low byte wrapping to zero
.,FC39 A5 D7    LDA $D7         get checksum byte
.,FC3B 85 BD    STA $BD         save checksum as tape write byte
.,FC3D B0 CA    BCS $FC09       restore registers and exit interrupt, branch always
                                the block isn't finished so get the next byte to write to tape
.,FC3F A0 00    LDY #$00        clear index
.,FC41 B1 AC    LDA ($AC),Y     get byte from buffer
.,FC43 85 BD    STA $BD         save as tape write byte
.,FC45 45 D7    EOR $D7         XOR with checksum byte
.,FC47 85 D7    STA $D7         save new checksum byte
.,FC49 20 DB FC JSR $FCDB       increment read/write pointer
.,FC4C D0 BB    BNE $FC09       restore registers and exit interrupt, branch always
                                set parity as next bit and exit interrupt
.,FC4E A5 9B    LDA $9B         get parity bit
.,FC50 49 01    EOR #$01        toggle it
.,FC52 85 BD    STA $BD         save as tape write byte
.,FC54 4C BC FE JMP $FEBC       restore registers and exit interrupt
                                tape routine, block complete exit
.,FC57 C6 BE    DEC $BE         decrement copies remaining to read/write
.,FC59 D0 03    BNE $FC5E       branch if more to do
.,FC5B 20 CA FC JSR $FCCA       stop the cassette motor
.,FC5E A9 50    LDA #$50        set tape write leader count
.,FC60 85 A7    STA $A7         save tape write leader count
.,FC62 A2 08    LDX #$08        set index for write tape leader vector
.,FC64 78       SEI             disable the interrupts
.,FC65 20 BD FC JSR $FCBD       set the tape vector
.,FC68 D0 EA    BNE $FC54       restore registers and exit interrupt, branch always

write tape leader IRQ routine

.,FC6A A9 78    LDA #$78        set time constant low byte for bit = leader
.,FC6C 20 AF FB JSR $FBAF       write time constant and toggle tape
.,FC6F D0 E3    BNE $FC54       if tape bit high restore registers and exit interrupt
.,FC71 C6 A7    DEC $A7         decrement cycle count
.,FC73 D0 DF    BNE $FC54       if not all done restore registers and exit interrupt
.,FC75 20 97 FB JSR $FB97       new tape byte setup
.,FC78 C6 AB    DEC $AB         decrement cassette leader count
.,FC7A 10 D8    BPL $FC54       if not all done restore registers and exit interrupt
.,FC7C A2 0A    LDX #$0A        set index for tape write vector
.,FC7E 20 BD FC JSR $FCBD       set the tape vector
.,FC81 58       CLI             enable the interrupts
.,FC82 E6 AB    INC $AB         clear cassette leader counter, was $FF
.,FC84 A5 BE    LDA $BE         get cassette block count
.,FC86 F0 30    BEQ $FCB8       if all done restore everything for STOP and exit the
                                interrupt
.,FC88 20 8E FB JSR $FB8E       copy I/O start address to buffer address
.,FC8B A2 09    LDX #$09        set nine synchronisation bytes
.,FC8D 86 A5    STX $A5         save cassette synchronization byte count
.,FC8F 86 B6    STX $B6
.,FC91 D0 83    BNE $FC16       go do the next tape byte, branch always

restore everything for STOP

.,FC93 08       PHP             save status
.,FC94 78       SEI             disable the interrupts
.,FC95 AD 11 D0 LDA $D011       read the vertical fine scroll and control register
.,FC98 09 10    ORA #$10        mask xxx1 xxxx, unblank the screen
.,FC9A 8D 11 D0 STA $D011       save the vertical fine scroll and control register
.,FC9D 20 CA FC JSR $FCCA       stop the cassette motor
.,FCA0 A9 7F    LDA #$7F        disable all interrupts
.,FCA2 8D 0D DC STA $DC0D       save VIA 1 ICR
.,FCA5 20 DD FD JSR $FDDD
.,FCA8 AD A0 02 LDA $02A0       get saved IRQ vector high byte
.,FCAB F0 09    BEQ $FCB6       branch if null
.,FCAD 8D 15 03 STA $0315       restore IRQ vector high byte
.,FCB0 AD 9F 02 LDA $029F       get saved IRQ vector low byte
.,FCB3 8D 14 03 STA $0314       restore IRQ vector low byte
.,FCB6 28       PLP             restore status
.,FCB7 60       RTS

reset vector

.,FCB8 20 93 FC JSR $FC93       restore everything for STOP
.,FCBB F0 97    BEQ $FC54       restore registers and exit interrupt, branch always

set tape vector

.,FCBD BD 93 FD LDA $FD93,X     get tape IRQ vector low byte
.,FCC0 8D 14 03 STA $0314       set IRQ vector low byte
.,FCC3 BD 94 FD LDA $FD94,X     get tape IRQ vector high byte
.,FCC6 8D 15 03 STA $0315       set IRQ vector high byte
.,FCC9 60       RTS

stop the cassette motor

.,FCCA A5 01    LDA $01         read the 6510 I/O port
.,FCCC 09 20    ORA #$20        mask xxxx xx1x, turn the cassette motor off
.,FCCE 85 01    STA $01         save the 6510 I/O port
.,FCD0 60       RTS

check read/write pointer

                                return Cb = 1 if pointer >= end
.,FCD1 38       SEC             set carry for subtract
.,FCD2 A5 AC    LDA $AC         get buffer address low byte
.,FCD4 E5 AE    SBC $AE         subtract buffer end low byte
.,FCD6 A5 AD    LDA $AD         get buffer address high byte
.,FCD8 E5 AF    SBC $AF         subtract buffer end high byte
.,FCDA 60       RTS

increment read/write pointer

.,FCDB E6 AC    INC $AC         increment buffer address low byte
.,FCDD D0 02    BNE $FCE1       branch if no overflow
.,FCDF E6 AD    INC $AD         increment buffer address low byte
.,FCE1 60       RTS

RESET, hardware reset starts here

.,FCE2 A2 FF    LDX #$FF        set X for stack
.,FCE4 78       SEI             disable the interrupts
.,FCE5 9A       TXS             clear stack
.,FCE6 D8       CLD             clear decimal mode
.,FCE7 20 02 FD JSR $FD02       scan for autostart ROM at $8000
.,FCEA D0 03    BNE $FCEF       if not there continue startup
.,FCEC 6C 00 80 JMP ($8000)     else call ROM start code
.,FCEF 8E 16 D0 STX $D016       read the horizontal fine scroll and control register
.,FCF2 20 A3 FD JSR $FDA3       initialise SID, CIA and IRQ
.,FCF5 20 50 FD JSR $FD50       RAM test and find RAM end
.,FCF8 20 15 FD JSR $FD15       restore default I/O vectors
.,FCFB 20 5B FF JSR $FF5B       initialise VIC and screen editor
.,FCFE 58       CLIenable the interrupts
.,FCFF 6C 00 A0 JMP ($A000)     execute BASIC

scan for autostart ROM at $8000, returns Zb=1 if ROM found

.,FD02 A2 05    LDX #$05        five characters to test
.,FD04 BD 0F FD LDA $FD0F,X     get test character
.,FD07 DD 03 80 CMP $8003,X     compare wiith byte in ROM space
.,FD0A D0 03    BNE $FD0F       exit if no match
.,FD0C CA       DEX             decrement index
.,FD0D D0 F5    BNE $FD04       loop if not all done
.,FD0F 60       RTS

autostart ROM signature

.:FD10 C3 C2 CD 38 30           'CBM80’

restore default I/O vectors

.,FD15 A2 30    LDX #$30        pointer to vector table low byte
.,FD17 A0 FD    LDY #$FD        pointer to vector table high byte
.,FD19 18       CLC             flag set vectors

set/read vectored I/O from (XY), Cb = 1 to read, Cb = 0 to set

.,FD1A 86 C3    STX $C3         save pointer low byte
.,FD1C 84 C4    STY $C4         save pointer high byte
.,FD1E A0 1F    LDY #$1F        set byte count
.,FD20 B9 14 03 LDA $0314,Y     read vector byte from vectors
.,FD23 B0 02    BCS $FD27       branch if read vectors
.,FD25 B1 C3    LDA ($C3),Y     read vector byte from (XY)
.,FD27 91 C3    STA ($C3),Y     save byte to (XY)
.,FD29 99 14 03 STA $0314,Y     save byte to vector
.,FD2C 88       DEY             decrement index
.,FD2D 10 F1    BPL $FD20       loop if more to do
.,FD2F 60       RTS
                                 The above code works but it tries to write to the ROM. while this is usually harmless
                                 systems that use flash ROM may suffer. Here is a version that makes the extra write
                                 to RAM instead but is otherwise identical in function. ##

                                 set/read vectored I/O from (XY), Cb = 1 to read, Cb = 0 to set

                                STX $C3         ; save pointer low byte
                                STY $C4         ; save pointer high byte
                                LDY #$1F        ; set byte count
                                LDA ($C3),Y     ; read vector byte from (XY)
                                BCC $FD29       ; branch if set vectors

                                LDA $0314,Y     ; else read vector byte from vectors
                                STA ($C3),Y     ; save byte to (XY)
                                STA $0314,Y     ; save byte to vector
                                DEY             ; decrement index
                                BPL $FD20       ; loop if more to do

                                RTS

kernal vectors

.:FD30 31 EA                    $0314 IRQ vector
.:FD32 66 FE                    $0316 BRK vector
.:FD34 47 FE                    $0318 NMI vector
.:FD36 4A F3                    $031A open a logical file
.:FD38 91 F2                    $031C close a specified logical file
.:FD3A 0E F2                    $031E open channel for input
.:FD3C 50 F2                    $0320 open channel for output
.:FD3E 33 F3                    $0322 close input and output channels
.:FD40 57 F1                    $0324 input character from channel
.:FD42 CA F1                    $0326 output character to channel
.:FD44 ED F6                    $0328 scan stop key
.:FD46 3E F1                    $032A get character from the input device
.:FD48 2F F3                    $032C close all channels and files
.:FD4A 66 FE                    $032E user function
                                Vector to user defined command, currently points to BRK.
                                This appears to be a holdover from PET days, when the built-in machine language monitor
                                would jump through the $032E vector when it encountered a command that it did not
                                understand, allowing the user to add new commands to the monitor.
                                Although this vector is initialized to point to the routine called by STOP/RESTORE and
                                the BRK interrupt, and is updated by the kernal vector routine at $FD57, it no longer
                                has any function.
.:FD4C A5 F4                    $0330 load
.:FD4E ED F5                    $0332 save

test RAM and find RAM end

.,FD50 A9 00    LDA #$00        clear A
.,FD52 A8       TAY             clear index
.,FD53 99 02 00 STA $0002,Y     clear page 0, don't do $0000 or $0001
.,FD56 99 00 02 STA $0200,Y     clear page 2
.,FD59 99 00 03 STA $0300,Y     clear page 3
.,FD5C C8       INY             increment index
.,FD5D D0 F4    BNE $FD53       loop if more to do
.,FD5F A2 3C    LDX #$3C        set cassette buffer pointer low byte
.,FD61 A0 03    LDY #$03        set cassette buffer pointer high byte
.,FD63 86 B2    STX $B2         save tape buffer start pointer low byte
.,FD65 84 B3    STY $B3         save tape buffer start pointer high byte
.,FD67 A8       TAY             clear Y
.,FD68 A9 03    LDA #$03        set RAM test pointer high byte
.,FD6A 85 C2    STA $C2         save RAM test pointer high byte
.,FD6C E6 C2    INC $C2         increment RAM test pointer high byte
.,FD6E B1 C1    LDA ($C1),Y
.,FD70 AA       TAX
.,FD71 A9 55    LDA #$55
.,FD73 91 C1    STA ($C1),Y
.,FD75 D1 C1    CMP ($C1),Y
.,FD77 D0 0F    BNE $FD88
.,FD79 2A       ROL
.,FD7A 91 C1    STA ($C1),Y
.,FD7C D1 C1    CMP ($C1),Y
.,FD7E D0 08    BNE $FD88
.,FD80 8A       TXA
.,FD81 91 C1    STA ($C1),Y
.,FD83 C8       INY
.,FD84 D0 E8    BNE $FD6E
.,FD86 F0 E4    BEQ $FD6C
.,FD88 98       TYA
.,FD89 AA       TAX
.,FD8A A4 C2    LDY $C2
.,FD8C 18       CLC
.,FD8D 20 2D FE JSR $FE2D       set the top of memory
.,FD90 A9 08    LDA #$08
.,FD92 8D 82 02 STA $0282       save the OS start of memory high byte
.,FD95 A9 04    LDA #$04
.,FD97 8D 88 02 STA $0288       save the screen memory page
.,FD9A 60       RTS

tape IRQ vectors

.:FD9B 6A FC                    $08 write tape leader IRQ routine
.:FD9D CD FB                    $0A tape write IRQ routine
.:FD9F 31 EA                    $0C normal IRQ vector
.:FDA1 2C F9                    $0E read tape bits IRQ routine

initialise SID, CIA and IRQ

.,FDA3 A9 7F    LDA #$7F        disable all interrupts
.,FDA5 8D 0D DC STA $DC0D       save VIA 1 ICR
.,FDA8 8D 0D DD STA $DD0D       save VIA 2 ICR
.,FDAB 8D 00 DC STA $DC00       save VIA 1 DRA, keyboard column drive
.,FDAE A9 08    LDA #$08        set timer single shot
.,FDB0 8D 0E DC STA $DC0E       save VIA 1 CRA
.,FDB3 8D 0E DD STA $DD0E       save VIA 2 CRA
.,FDB6 8D 0F DC STA $DC0F       save VIA 1 CRB
.,FDB9 8D 0F DD STA $DD0F       save VIA 2 CRB
.,FDBC A2 00    LDX #$00        set all inputs
.,FDBE 8E 03 DC STX $DC03       save VIA 1 DDRB, keyboard row
.,FDC1 8E 03 DD STX $DD03       save VIA 2 DDRB, RS232 port
.,FDC4 8E 18 D4 STX $D418       clear the volume and filter select register
.,FDC7 CA       DEX             set X = $FF
.,FDC8 8E 02 DC STX $DC02       save VIA 1 DDRA, keyboard column
.,FDCB A9 07    LDA #$07        DATA out high, CLK out high, ATN out high, RE232 Tx DATA
                                high, video address 15 = 1, video address 14 = 1
.,FDCD 8D 00 DD STA $DD00       save VIA 2 DRA, serial port and video address
.,FDD0 A9 3F    LDA #$3F        set serial DATA input, serial CLK input
.,FDD2 8D 02 DD STA $DD02       save VIA 2 DDRA, serial port and video address
.,FDD5 A9 E7    LDA #$E7        set 1110 0111, motor off, enable I/O, enable KERNAL,
                                enable BASIC
.,FDD7 85 01    STA $01         save the 6510 I/O port
.,FDD9 A9 2F    LDA #$2F        set 0010 1111, 0 = input, 1 = output
.,FDDB 85 00    STA $00         save the 6510 I/O port direction register
.,FDDD AD A6 02 LDA $02A6       get the PAL/NTSC flag
.,FDE0 F0 0A    BEQ $FDEC       if NTSC go set NTSC timing
                                else set PAL timing
.,FDE2 A9 25    LDA #$25
.,FDE4 8D 04 DC STA $DC04       save VIA 1 timer A low byte
.,FDE7 A9 40    LDA #$40
.,FDE9 4C F3 FD JMP $FDF3
.,FDEC A9 95    LDA #$95
.,FDEE 8D 04 DC STA $DC04       save VIA 1 timer A low byte
.,FDF1 A9 42    LDA #$42
.,FDF3 8D 05 DC STA $DC05       save VIA 1 timer A high byte
.,FDF6 4C 6E FF JMP $FF6E

set filename

.,FDF9 85 B7    STA $B7         set file name length
.,FDFB 86 BB    STX $BB         set file name pointer low byte
.,FDFD 84 BC    STY $BC         set file name pointer high byte
.,FDFF 60       RTS

set logical, first and second addresses

.,FE00 85 B8    STA $B8         save the logical file
.,FE02 86 BA    STX $BA         save the device number
.,FE04 84 B9    STY $B9         save the secondary address
.,FE06 60       RTS

read I/O status word

.,FE07 A5 BA    LDA $BA         get the device number
.,FE09 C9 02    CMP #$02        compare device with RS232 device
.,FE0B D0 0D    BNE $FE1A       if not RS232 device go ??
                                get RS232 device status
.,FE0D AD 97 02 LDA $0297       get the RS232 status register
.,FE10 48       PHA             save the RS232 status value
.,FE11 A9 00    LDA #$00        clear A
.,FE13 8D 97 02 STA $0297       clear the RS232 status register
.,FE16 68       PLA             restore the RS232 status value
.,FE17 60       RTS

control kernal messages

.,FE18 85 9D    STA $9D         set message mode flag
.,FE1A A5 90    LDA $90         read the serial status byte

OR into the serial status byte

.,FE1C 05 90    ORA $90         OR with the serial status byte
.,FE1E 85 90    STA $90         save the serial status byte
.,FE20 60       RTS

set timeout on serial bus

.,FE21 8D 85 02 STA $0285       save serial bus timeout flag
.,FE24 60       RTS

read/set the top of memory, Cb = 1 to read, Cb = 0 to set

.,FE25 90 06    BCC $FE2D       if Cb clear go set the top of memory

read the top of memory

.,FE27 AE 83 02 LDX $0283       get memory top low byte
.,FE2A AC 84 02 LDY $0284       get memory top high byte

set the top of memory

.,FE2D 8E 83 02 STX $0283       set memory top low byte
.,FE30 8C 84 02 STY $0284       set memory top high byte
.,FE33 60       RTS

read/set the bottom of memory, Cb = 1 to read, Cb = 0 to set

.,FE34 90 06    BCC $FE3C       if Cb clear go set the bottom of memory
.,FE36 AE 81 02 LDX $0281       get the OS start of memory low byte
.,FE39 AC 82 02 LDY $0282       get the OS start of memory high byte
.,FE3C 8E 81 02 STX $0281       save the OS start of memory low byte
.,FE3F 8C 82 02 STY $0282       save the OS start of memory high byte
.,FE42 60       RTS

NMI vector

.,FE43 78       SEI             disable the interrupts
.,FE44 6C 18 03 JMP ($0318)     do NMI vector

NMI handler

.,FE47 48       PHA             save A
.,FE48 8A       TXA             copy X
.,FE49 48       PHA             save X
.,FE4A 98       TYA             copy Y
.,FE4B 48       PHA             save Y
.,FE4C A9 7F    LDA #$7F        disable all interrupts
.,FE4E 8D 0D DD STA $DD0D       save VIA 2 ICR
.,FE51 AC 0D DD LDY $DD0D       save VIA 2 ICR
.,FE54 30 1C    BMI $FE72
.,FE56 20 02 FD JSR $FD02       scan for autostart ROM at $8000
.,FE59 D0 03    BNE $FE5E       branch if no autostart ROM
.,FE5B 6C 02 80 JMP ($8002)     else do autostart ROM break entry
.,FE5E 20 BC F6 JSR $F6BC       increment real time clock
.,FE61 20 E1 FF JSR $FFE1       scan stop key
.,FE64 D0 0C    BNE $FE72       if not [STOP] restore registers and exit interrupt

user function default vector

                                BRK handler
.,FE66 20 15 FD JSR $FD15       restore default I/O vectors
.,FE69 20 A3 FD JSR $FDA3       initialise SID, CIA and IRQ
.,FE6C 20 18 E5 JSR $E518       initialise the screen and keyboard
.,FE6F 6C 02 A0 JMP ($A002)     do BASIC break entry

RS232 NMI routine

.,FE72 98       TYA
.,FE73 2D A1 02 AND $02A1       AND with the RS-232 interrupt enable byte
.,FE76 AA       TAX
.,FE77 29 01    AND #$01
.,FE79 F0 28    BEQ $FEA3
.,FE7B AD 00 DD LDA $DD00       read VIA 2 DRA, serial port and video address
.,FE7E 29 FB    AND #$FB        mask xxxx x0xx, clear RS232 Tx DATA
.,FE80 05 B5    ORA $B5         OR in the RS232 transmit data bit
.,FE82 8D 00 DD STA $DD00       save VIA 2 DRA, serial port and video address
.,FE85 AD A1 02 LDA $02A1       get the RS-232 interrupt enable byte
.,FE88 8D 0D DD STA $DD0D       save VIA 2 ICR
.,FE8B 8A       TXA
.,FE8C 29 12    AND #$12
.,FE8E F0 0D    BEQ $FE9D
.,FE90 29 02    AND #$02
.,FE92 F0 06    BEQ $FE9A
.,FE94 20 D6 FE JSR $FED6
.,FE97 4C 9D FE JMP $FE9D
.,FE9A 20 07 FF JSR $FF07
.,FE9D 20 BB EE JSR $EEBB
.,FEA0 4C B6 FE JMP $FEB6
.,FEA3 8A       TXA             get active interrupts back
.,FEA4 29 02    AND #$02        mask ?? interrupt
.,FEA6 F0 06    BEQ $FEAE       branch if not ?? interrupt
                                was ?? interrupt
.,FEA8 20 D6 FE JSR $FED6
.,FEAB 4C B6 FE JMP $FEB6
.,FEAE 8A       TXA             get active interrupts back
.,FEAF 29 10    AND #$10        mask CB1 interrupt, Rx data bit transition
.,FEB1 F0 03    BEQ $FEB6       if no bit restore registers and exit interrupt
.,FEB3 20 07 FF JSR $FF07
.,FEB6 AD A1 02 LDA $02A1       get the RS-232 interrupt enable byte
.,FEB9 8D 0D DD STA $DD0D       save VIA 2 ICR
.,FEBC 68       PLA             pull Y
.,FEBD A8       TAY             restore Y
.,FEBE 68       PLA             pull X
.,FEBF AA       TAX             restore X
.,FEC0 68       PLA             restore A
.,FEC1 40       RTI

baud rate word is calculated from ..


                                (system clock / baud rate) / 2 - 100

                                    system clock
                                    ------------
                                PAL        985248 Hz
                                NTSC     1022727 Hz
                                baud rate tables for NTSC C64
.:FEC2 C1 27                      50   baud   1027700
.:FEC4 3E 1A                      75   baud   1022700
.:FEC6 C5 11                     110   baud   1022780
.:FEC8 74 0E                     134.5 baud   1022200
.:FECA ED 0C                     150   baud   1022700
.:FECC 45 06                     300   baud   1023000
.:FECE F0 02                     600   baud   1022400
.:FED0 46 01                    1200   baud   1022400
.:FED2 B8 00                    1800   baud   1022400
.:FED4 71 00                    2400   baud   1022400

??

.,FED6 AD 01 DD LDA $DD01       read VIA 2 DRB, RS232 port
.,FED9 29 01    AND #$01        mask 0000 000x, RS232 Rx DATA
.,FEDB 85 A7    STA $A7         save the RS232 received data bit
.,FEDD AD 06 DD LDA $DD06       get VIA 2 timer B low byte
.,FEE0 E9 1C    SBC #$1C
.,FEE2 6D 99 02 ADC $0299
.,FEE5 8D 06 DD STA $DD06       save VIA 2 timer B low byte
.,FEE8 AD 07 DD LDA $DD07       get VIA 2 timer B high byte
.,FEEB 6D 9A 02 ADC $029A
.,FEEE 8D 07 DD STA $DD07       save VIA 2 timer B high byte
.,FEF1 A9 11    LDA #$11        set timer B single shot, start timer B
.,FEF3 8D 0F DD STA $DD0F       save VIA 2 CRB
.,FEF6 AD A1 02 LDA $02A1       get the RS-232 interrupt enable byte
.,FEF9 8D 0D DD STA $DD0D       save VIA 2 ICR
.,FEFC A9 FF    LDA #$FF
.,FEFE 8D 06 DD STA $DD06       save VIA 2 timer B low byte
.,FF01 8D 07 DD STA $DD07       save VIA 2 timer B high byte
.,FF04 4C 59 EF JMP $EF59
.,FF07 AD 95 02 LDA $0295       nonstandard bit timing low byte
.,FF0A 8D 06 DD STA $DD06       save VIA 2 timer B low byte
.,FF0D AD 96 02 LDA $0296       nonstandard bit timing high byte
.,FF10 8D 07 DD STA $DD07       save VIA 2 timer B high byte
.,FF13 A9 11    LDA #$11        set timer B single shot, start timer B
.,FF15 8D 0F DD STA $DD0F       save VIA 2 CRB
.,FF18 A9 12    LDA #$12
.,FF1A 4D A1 02 EOR $02A1       EOR with the RS-232 interrupt enable byte
.,FF1D 8D A1 02 STA $02A1       save the RS-232 interrupt enable byte
.,FF20 A9 FF    LDA #$FF
.,FF22 8D 06 DD STA $DD06       save VIA 2 timer B low byte
.,FF25 8D 07 DD STA $DD07       save VIA 2 timer B high byte
.,FF28 AE 98 02 LDX $0298
.,FF2B 86 A8    STX $A8
.,FF2D 60       RTS

??

.,FF2E AA       TAX
.,FF2F AD 96 02 LDA $0296       nonstandard bit timing high byte
.,FF32 2A       ROL
.,FF33 A8       TAY
.,FF34 8A       TXA
.,FF35 69 C8    ADC #$C8
.,FF37 8D 99 02 STA $0299
.,FF3A 98       TYA
.,FF3B 69 00    ADC #$00        add any carry
.,FF3D 8D 9A 02 STA $029A
.,FF40 60       RTS

unused bytes

.,FF41 EA       NOP             waste cycles
.,FF42 EA       NOP             waste cycles

save the status and do the IRQ routine

.,FF43 08       PHP             save the processor status
.,FF44 68       PLA             pull the processor status
.,FF45 29 EF    AND #$EF        mask xxx0 xxxx, clear the break bit
.,FF47 48       PHA             save the modified processor status

IRQ vector

.,FF48 48       PHA             save A
.,FF49 8A       TXA             copy X
.,FF4A 48       PHA             save X
.,FF4B 98       TYA             copy Y
.,FF4C 48       PHA             save Y
.,FF4D BA       TSX             copy stack pointer
.,FF4E BD 04 01 LDA $0104,X     get stacked status register
.,FF51 29 10    AND #$10        mask BRK flag
.,FF53 F0 03    BEQ $FF58       branch if not BRK
.,FF55 6C 16 03 JMP ($0316)     else do BRK vector (iBRK)
.,FF58 6C 14 03 JMP ($0314)     do IRQ vector (iIRQ)

initialise VIC and screen editor

.,FF5B 20 18 E5 JSR $E518       initialise the screen and keyboard
.,FF5E AD 12 D0 LDA $D012       read the raster compare register
.,FF61 D0 FB    BNE $FF5E       loop if not raster line $00
.,FF63 AD 19 D0 LDA $D019       read the vic interrupt flag register
.,FF66 29 01    AND #$01        mask the raster compare flag
.,FF68 8D A6 02 STA $02A6       save the PAL/NTSC flag
.,FF6B 4C DD FD JMP $FDDD

??

.,FF6E A9 81    LDA #$81        enable timer A interrupt
.,FF70 8D 0D DC STA $DC0D       save VIA 1 ICR
.,FF73 AD 0E DC LDA $DC0E       read VIA 1 CRA
.,FF76 29 80    AND #$80        mask x000 0000, TOD clock
.,FF78 09 11    ORA #$11        mask xxx1 xxx1, load timer A, start timer A
.,FF7A 8D 0E DC STA $DC0E       save VIA 1 CRA
.,FF7D 4C 8E EE JMP $EE8E       set the serial clock out low and return

unused

.:FF80 03

initialise VIC and screen editor

.,FF81 4C 5B FF JMP $FF5B       initialise VIC and screen editor

initialise SID, CIA and IRQ, unused

.,FF84 4C A3 FD JMP $FDA3       initialise SID, CIA and IRQ

RAM test and find RAM end

.,FF87 4C 50 FD JMP $FD50       RAM test and find RAM end

restore default I/O vectors

                                this routine restores the default values of all system vectors used in KERNAL and
                                BASIC routines and interrupts.
.,FF8A 4C 15 FD JMP $FD15       restore default I/O vectors

read/set vectored I/O

                                this routine manages all system vector jump addresses stored in RAM. Calling this
                                routine with the carry bit set will store the current contents of the RAM vectors
                                in a list pointed to by the X and Y registers. When this routine is called with
                                the carry bit clear, the user list pointed to by the X and Y registers is copied
                                to the system RAM vectors.
                                NOTE: This routine requires caution in its use. The best way to use it is to first
                                read the entire vector contents into the user area, alter the desired vectors and
                                then copy the contents back to the system vectors.
.,FF8D 4C 1A FD JMP $FD1A       read/set vectored I/O

control kernal messages

                                this routine controls the printing of error and control messages by the KERNAL.
                                Either print error messages or print control messages can be selected by setting
                                the accumulator when the routine is called.
                                FILE NOT FOUND is an example of an error message. PRESS PLAY ON CASSETTE is an
                                example of a control message.
                                bits 6 and 7 of this value determine where the message will come from. If bit 7
                                is set one of the error messages from the KERNAL will be printed. If bit 6 is set
                                a control message will be printed.
.,FF90 4C 18 FE JMP $FE18       control kernal messages

send secondary address after LISTEN

                                this routine is used to send a secondary address to an I/O device after a call to
                                the LISTEN routine is made and the device commanded to LISTEN. The routine cannot
                                be used to send a secondary address after a call to the TALK routine.
                                A secondary address is usually used to give set-up information to a device before
                                I/O operations begin.
                                When a secondary address is to be sent to a device on the serial bus the address
                                must first be ORed with $60.
.,FF93 4C B9 ED JMP $EDB9       send secondary address after LISTEN

send secondary address after TALK

                                this routine transmits a secondary address on the serial bus for a TALK device.
                                This routine must be called with a number between 4 and 31 in the accumulator.
                                The routine will send this number as a secondary address command over the serial
                                bus. This routine can only be called after a call to the TALK routine. It will
                                not work after a LISTEN.
.,FF96 4C C7 ED JMP $EDC7       send secondary address after TALK

read/set the top of memory

                                this routine is used to read and set the top of RAM. When this routine is called
                                with the carry bit set the pointer to the top of RAM will be loaded into XY. When
                                this routine is called with the carry bit clear XY will be saved as the top of
                                memory pointer changing the top of memory.
.,FF99 4C 25 FE JMP $FE25       read/set the top of memory

read/set the bottom of memory

                                this routine is used to read and set the bottom of RAM. When this routine is
                                called with the carry bit set the pointer to the bottom of RAM will be loaded
                                into XY. When this routine is called with the carry bit clear XY will be saved as
                                the bottom of memory pointer changing the bottom of memory.
.,FF9C 4C 34 FE JMP $FE34       read/set the bottom of memory

scan the keyboard

                                this routine will scan the keyboard and check for pressed keys. It is the same
                                routine called by the interrupt handler. If a key is down, its ASCII value is
                                placed in the keyboard queue.
.,FF9F 4C 87 EA JMP $EA87       scan keyboard

set timeout on serial bus

                                this routine sets the timeout flag for the serial bus. When the timeout flag is
                                set, the computer will wait for a device on the serial port for 64 milliseconds.
                                If the device does not respond to the computer's DAV signal within that time the
                                computer will recognize an error condition and leave the handshake sequence. When
                                this routine is called and the accumulator contains a 0 in bit 7, timeouts are
                                enabled. A 1 in bit 7 will disable the timeouts.
                                NOTE: The the timeout feature is used to communicate that a disk file is not found
                                on an attempt to OPEN a file.
.,FFA2 4C 21 FE JMP $FE21       set timeout on serial bus

input byte from serial bus


                                this routine reads a byte of data from the serial bus using full handshaking. the
                                data is returned in the accumulator. before using this routine the TALK routine,
                                $FFB4, must have been called first to command the device on the serial bus to
                                send data on the bus. if the input device needs a secondary command it must be sent
                                by using the TKSA routine, $FF96, before calling this routine.

                                errors are returned in the status word which can be read by calling the READST
                                routine, $FFB7.
.,FFA5 4C 13 EE JMP $EE13       input byte from serial bus

output a byte to serial bus

                                this routine is used to send information to devices on the serial bus. A call to
                                this routine will put a data byte onto the serial bus using full handshaking.
                                Before this routine is called the LISTEN routine, $FFB1, must be used to
                                command a device on the serial bus to get ready to receive data.
                                the accumulator is loaded with a byte to output as data on the serial bus. A
                                device must be listening or the status word will return a timeout. This routine
                                always buffers one character. So when a call to the UNLISTEN routine, $FFAE,
                                is made to end the data transmission, the buffered character is sent with EOI
                                set. Then the UNLISTEN command is sent to the device.
.,FFA8 4C DD ED JMP $EDDD       output byte to serial bus

command serial bus to UNTALK

                                this routine will transmit an UNTALK command on the serial bus. All devices
                                previously set to TALK will stop sending data when this command is received.
.,FFAB 4C EF ED JMP $EDEF       command serial bus to UNTALK

command serial bus to UNLISTEN

                                this routine commands all devices on the serial bus to stop receiving data from
                                the computer. Calling this routine results in an UNLISTEN command being transmitted
                                on the serial bus. Only devices previously commanded to listen will be affected.
                                This routine is normally used after the computer is finished sending data to
                                external devices. Sending the UNLISTEN will command the listening devices to get
                                off the serial bus so it can be used for other purposes.
.,FFAE 4C FE ED JMP $EDFE       command serial bus to UNLISTEN

command devices on the serial bus to LISTEN

                                this routine will command a device on the serial bus to receive data. The
                                accumulator must be loaded with a device number between 4 and 31 before calling
                                this routine. LISTEN convert this to a listen address then transmit this data as
                                a command on the serial bus. The specified device will then go into listen mode
                                and be ready to accept information.
.,FFB1 4C 0C ED JMP $ED0C       command devices on the serial bus to LISTEN

command serial bus device to TALK

                                to use this routine the accumulator must first be loaded with a device number
                                between 4 and 30. When called this routine converts this device number to a talk
                                address. Then this data is transmitted as a command on the Serial bus.
.,FFB4 4C 09 ED JMP $ED09       command serial bus device to TALK

read I/O status word

                                this routine returns the current status of the I/O device in the accumulator. The
                                routine is usually called after new communication to an I/O device. The routine
                                will give information about device status, or errors that have occurred during the
                                I/O operation.
.,FFB7 4C 07 FE JMP $FE07       read I/O status word

set logical, first and second addresses

                                this routine will set the logical file number, device address, and secondary
                                address, command number, for other KERNAL routines.
                                the logical file number is used by the system as a key to the file table created
                                by the OPEN file routine. Device addresses can range from 0 to 30. The following
                                codes are used by the computer to stand for the following CBM devices:
                                ADDRESS DEVICE
                                ======= ======
                                 0      Keyboard
                                 1      Cassette #1
                                 2      RS-232C device
                                 3      CRT display
                                 4      Serial bus printer
                                 8      CBM Serial bus disk drive
                                device numbers of four or greater automatically refer to devices on the serial
                                bus.
                                a command to the device is sent as a secondary address on the serial bus after
                                the device number is sent during the serial attention handshaking sequence. If
                                no secondary address is to be sent Y should be set to $FF.
.,FFBA 4C 00 FE JMP $FE00       set logical, first and second addresses

set the filename

                                this routine is used to set up the file name for the OPEN, SAVE, or LOAD routines.
                                The accumulator must be loaded with the length of the file and XY with the pointer
                                to file name, X being th low byte. The address can be any valid memory address in
                                the system where a string of characters for the file name is stored. If no file
                                name desired the accumulator must be set to 0, representing a zero file length,
                                in that case  XY may be set to any memory address.
.,FFBD 4C F9 FD JMP $FDF9       set the filename

open a logical file

                                this routine is used to open a logical file. Once the logical file is set up it
                                can be used for input/output operations. Most of the I/O KERNAL routines call on
                                this routine to create the logical files to operate on. No arguments need to be
                                set up to use this routine, but both the SETLFS, $FFBA, and SETNAM, $FFBD,
                                KERNAL routines must be called before using this routine.
.,FFC0 6C 1A 03 JMP ($031A)     do open a logical file

close a specified logical file

                                this routine is used to close a logical file after all I/O operations have been
                                completed on that file. This routine is called after the accumulator is loaded
                                with the logical file number to be closed, the same number used when the file was
                                opened using the OPEN routine.
.,FFC3 6C 1C 03 JMP ($031C)     do close a specified logical file

open channel for input

                                any logical file that has already been opened by the OPEN routine, $FFC0, can be
                                defined as an input channel by this routine. the device on the channel must be an
                                input device or an error will occur and the routine will abort.

                                if you are getting data from anywhere other than the keyboard, this routine must be
                                called before using either the CHRIN routine, $FFCF, or the GETIN routine,
                                $FFE4. if you are getting data from the keyboard and no other input channels are
                                open then the calls to this routine and to the OPEN routine, $FFC0, are not needed.

                                when used with a device on the serial bus this routine will automatically send the
                                listen address specified by the OPEN routine, $FFC0, and any secondary address.

                                possible errors are:

                                3 : file not open
                                5 : device not present
                                6 : file is not an input file
.,FFC6 6C 1E 03 JMP ($031E)     do open channel for input

open channel for output

                                any logical file that has already been opened by the OPEN routine, $FFC0, can be
                                defined as an output channel by this routine the device on the channel must be an
                                output device or an error will occur and the routine will abort.

                                if you are sending data to anywhere other than the screen this routine must be
                                called before using the CHROUT routine, $FFD2. if you are sending data to the
                                screen and no other output channels are open then the calls to this routine and to
                                the OPEN routine, $FFC0, are not needed.

                                when used with a device on the serial bus this routine will automatically send the
                                listen address specified by the OPEN routine, $FFC0, and any secondary address.

                                possible errors are:

                                3 : file not open
                                5 : device not present
                                7 : file is not an output file
.,FFC9 6C 20 03 JMP ($0320)     do open channel for output

close input and output channels

                                this routine is called to clear all open channels and restore the I/O channels to
                                their original default values. It is usually called after opening other I/O
                                channels and using them for input/output operations. The default input device is
                                0, the keyboard. The default output device is 3, the screen.
                                If one of the channels to be closed is to the serial port, an UNTALK signal is sent
                                first to clear the input channel or an UNLISTEN is sent to clear the output channel.
                                By not calling this routine and leaving listener(s) active on the serial bus,
                                several devices can receive the same data from the VIC at the same time. One way to
                                take advantage of this would be to command the printer to TALK and the disk to
                                LISTEN. This would allow direct printing of a disk file.
.,FFCC 6C 22 03 JMP ($0322)     do close input and output channels

input character from channel

                                this routine will get a byte of data from the channel already set up as the input
                                channel by the CHKIN routine, $FFC6.

                                If CHKIN, $FFC6, has not been used to define another input channel the data is
                                expected to be from the keyboard. the data byte is returned in the accumulator. the
                                channel remains open after the call.

                                input from the keyboard is handled in a special way. first, the cursor is turned on
                                and it will blink until a carriage return is typed on the keyboard. all characters
                                on the logical line, up to 80 characters, will be stored in the BASIC input buffer.
                                then the characters can be returned one at a time by calling this routine once for
                                each character. when the carriage return is returned the entire line has been
                                processed. the next time this routine is called the whole process begins again.
.,FFCF 6C 24 03 JMP ($0324)     do input character from channel

output character to channel

                                this routine will output a character to an already opened channel. Use the OPEN
                                routine, $FFC0, and the CHKOUT routine, $FFC9, to set up the output channel
                                before calling this routine. If these calls are omitted, data will be sent to the
                                default output device, device 3, the screen. The data byte to be output is loaded
                                into the accumulator, and this routine is called. The data is then sent to the
                                specified output device. The channel is left open after the call.
                                NOTE: Care must be taken when using routine to send data to a serial device since
                                data will be sent to all open output channels on the bus. Unless this is desired,
                                all open output channels on the serial bus other than the actually intended
                                destination channel must be closed by a call to the KERNAL close channel routine.
.,FFD2 6C 26 03 JMP ($0326)     do output character to channel

load RAM from a device

                                this routine will load data bytes from any input device directly into the memory
                                of the computer. It can also be used for a verify operation comparing data from a
                                device with the data already in memory, leaving the data stored in RAM unchanged.
                                The accumulator must be set to 0 for a load operation or 1 for a verify. If the
                                input device was OPENed with a secondary address of 0 the header information from
                                device will be ignored. In this case XY must contain the starting address for the
                                load. If the device was addressed with a secondary address of 1 or 2 the data will
                                load into memory starting at the location specified by the header. This routine
                                returns the address of the highest RAM location which was loaded.
                                Before this routine can be called, the SETLFS, $FFBA, and SETNAM, $FFBD,
                                routines must be called.
.,FFD5 4C 9E F4 JMP $F49E       load RAM from a device

save RAM to a device

                                this routine saves a section of memory. Memory is saved from an indirect address
                                on page 0 specified by A, to the address stored in XY, to a logical file. The
                                SETLFS, $FFBA, and SETNAM, $FFBD, routines must be used before calling this
                                routine. However, a file name is not required to SAVE to device 1, the cassette.
                                Any attempt to save to other devices without using a file name results in an error.
                                NOTE: device 0, the keyboard, and device 3, the screen, cannot be SAVEd to. If
                                the attempt is made, an error will occur, and the SAVE stopped.
.,FFD8 4C DD F5 JMP $F5DD       save RAM to device

set the real time clock

                                the system clock is maintained by an interrupt routine that updates the clock
                                every 1/60th of a second. The clock is three bytes long which gives the capability
                                to count from zero up to 5,184,000 jiffies - 24 hours plus one jiffy. At that point
                                the clock resets to zero. Before calling this routine to set the clock the new time,
                                in jiffies, should be in YXA, the accumulator containing the most significant byte.
.,FFDB 4C E4 F6 JMP $F6E4       set real time clock

read the real time clock

                                this routine returns the time, in jiffies, in AXY. The accumulator contains the
                                most significant byte.
.,FFDE 4C DD F6 JMP $F6DD       read real time clock

scan the stop key

                                if the STOP key on the keyboard is pressed when this routine is called the Z flag
                                will be set. All other flags remain unchanged. If the STOP key is not pressed then
                                the accumulator will contain a byte representing the last row of the keyboard scan.
                                The user can also check for certain other keys this way.
.,FFE1 6C 28 03 JMP ($0328)     do scan stop key

get character from input device

                                in practice this routine operates identically to the CHRIN routine, $FFCF,
                                for all devices except for the keyboard. If the keyboard is the current input
                                device this routine will get one character from the keyboard buffer. It depends
                                on the IRQ routine to read the keyboard and put characters into the buffer.
                                If the keyboard buffer is empty the value returned in the accumulator will be zero.
.,FFE4 6C 2A 03 JMP ($032A)     do get character from input device

close all channels and files

                                this routine closes all open files. When this routine is called, the pointers into
                                the open file table are reset, closing all files. Also the routine automatically
                                resets the I/O channels.
.,FFE7 6C 2C 03 JMP ($032C)     do close all channels and files

increment real time clock

                                this routine updates the system clock. Normally this routine is called by the
                                normal KERNAL interrupt routine every 1/60th of a second. If the user program
                                processes its own interrupts this routine must be called to update the time. Also,
                                the STOP key routine must be called if the stop key is to remain functional.
.,FFEA 4C 9B F6 JMP $F69B       increment real time clock

return X,Y organization of screen

                                this routine returns the x,y organisation of the screen in X,Y
.,FFED 4C 05 E5 JMP $E505       return X,Y organization of screen

read/set X,Y cursor position

                                this routine, when called with the carry flag set, loads the current position of
                                the cursor on the screen into the X and Y registers. X is the column number of
                                the cursor location and Y is the row number of the cursor. A call with the carry
                                bit clear moves the cursor to the position determined by the X and Y registers.
.,FFF0 4C 0A E5 JMP $E50A       read/set X,Y cursor position

return the base address of the I/O devices

                                this routine will set XY to the address of the memory section where the memory
                                mapped I/O devices are located. This address can then be used with an offset to
                                access the memory mapped I/O devices in the computer.
.,FFF3 4C 00 E5 JMP $E500       return the base address of the I/O devices

.:FFF6 52 52 42 59              RRBY

hardware vectors

.:FFFA 43 FE                    NMI Vektor
.:FFFC E2 FC                    RESET Vektor
.:FFFE 48 FF                    IRQ Vektor