tinybasic.asm (55700B)
1 ; v0.2.2 2 ; 3 ; Bill O'Neill - Last update: 2011/11/11 4 ; 5 ; Monitor code is Open License and can be used freely 6 ; Tiny Basic code is Copyright, Tom Pitman 7 ; 8 ; Consist of a minimal terminal monitor and Tom 9 ; Pitman's Tiny Basic as a high-level 10 ; programming language 11 ; 12 ; This code assembles as-is with the macro assembler in the 13 ; Michal Kowalski simulator. 14 ; 15 ; It should be easy enough to configure this to run any- 16 ; where in memory or convert it to assemble with any 6502 17 ; assembler. 18 ; 19 ; Next steps: 20 ; More comments to document this code 21 ; 22 ; 23 ; Revision History: 24 ; 25 ; v0.2.2q - 2017/08/12 26 ; Reverse engineering the code; added a lot of labels 27 ; and comments to the source code. Still a work in progress. 28 ; 29 ; v0.2.2p - 2017/07/25 30 ; Ported to Simple 65816 computer by TBW. Recoded so ACME 31 ; assembler can assemble it; changes made to I/O calls 32 ; and warm boot vector; and implement input line hook. 33 ; Also modified the startup code to avoid video memory 34 ; area. One difficulty: The BIOS's PRCH treats CR as if 35 ; it is a CR/LF sequence, which may play havoc with Tiny 36 ; Basic in its current form. We'll see... 37 ; 38 ; v0.2.2 - 2011/11/11 39 ; Reduced version containing only a terminal monitor 40 ; for a 6850 ACIA and Tom Pitman's Tiny Basic 41 ; 42 ; v0.2.1 - 2011/05/18 43 ; Ported to Michal Kowalski's macro assembler 44 ; 45 ; v0.2.0 - 2011/01/04 46 ; Corrected some label problems 47 ; Added/corrected some comments 48 ; 49 ; v0.1.3 - 2009/11/28 50 ; Changed the look-up table for the IL op-code 51 ; handlers to use labels instead of literal addresses 52 ; this helps make the code re-locatable. 53 ; Added some comments to source 54 ; 55 ; v0.1.2 - 2009/01/12 56 ; Added BREAK routine 57 ; Fixed my bad reference to error string " AT " 58 ; Compressed gaps in monitor code 59 ; Added some comments to source 60 ; 61 ; v0.1.1 - 2008/12/15 62 ; Initial working version 63 ; 64 ; 65 ; Notes: 66 ; - I changed the prompt character from a ":" ($3A) to a ">" ($3E) for no 67 ; other reason than I think it looks a bit better. The prompt character 68 ; is the second byte of the IL program table. 69 ; 70 ; - This version is to run in Simple 65816. The memory map is as follows. 71 ; 72 ; $0000-$CFFF RAM (was: $0000-$7FFF) 73 ; $D000-$EFFF Video RAM, I/O and microRAM area 74 ; ($F000-$F7FF I/O - ACIA is at $F000 ... will be deleted) 75 ; $F000-$FBFF ROM - Tiny Basic (was: $8000-$EFFF) 76 ; $FC00-$FFFF ROM - Simple monitor 77 ; 78 ; - Starting address in this version (referred to as "S" in the EXPERIMENTER'S 79 ; KIT) is $F000 (was: $8000) 80 81 .include "os.inc" 82 83 84 ; 85 ; Tiny Basic starts here 86 ; 87 88 ; Zero page variables 89 90 LOWEST = $20 ; Lowest address of user program area 91 HIGHST = $22 ; Highest address of user program area 92 STACK = $24 ; End of user program area plus stack reserve 93 RETPTR = $26 ; Top of GOSUB stack 94 LINNUM = $28 ; Current line number of BASIC line 95 96 PGMPTR = $2A ; Pointer to TBIL program table 97 TXTPTR = $2C ; Pointer to program text area 98 99 INPLIN = $30 ; Input line buffer and computation stack ($30-$7F) 100 RNDNUM = $80 ; Random number generator workspace 101 VARS = $82 ; Variable "A" at $82-$83, "B" at $84-$85, etc. ($82-$B5) 102 TEMPS = $B6 ; Interpreter temporaries ($B6-$C7) 103 104 WORK = $BC ; Working register (two byte pair) 105 RUNNIN = $BE ; Running status flag 106 107 CSTOP = $C0 ; Computation stack pointer boundary variable 108 CSPTR = $C1 ; Computation stack pointer (points to $0030-$007F area) 109 ; Note that CSPTR+1 is set to zero (in WARM_S routine) so that 110 ; (CSPTR) actually points to $0030-$007F stack area as well, 111 ; which is used in XCHBYT routine 112 113 TERMPOS = $BF ; Terminal position 114 115 TXTBGN = tiny_basic_end ; Start of available RAM area 116 ENDMEM = $E000 ; Barrier against video RAM area in Simple 65816 117 118 START 119 120 jmp FBLK ; Jump to initialization code. So load address is start address. 121 122 CV jmp COLD_S ; Cold start vector 123 WV jmp WARM_S ; Warm start vector 124 IN_V jmp RCCHR ; Input routine address. 125 OUT_V jmp SNDCHR ; Output routine address. 126 BV jmp CHKBREAK ; Begin check break routine 127 128 ; 129 ; Some codes 130 ; 131 BSC .byte $5f ; Backspace code 132 LSC .byte $18 ; Line cancel code 133 PCC .byte $80 ; Pad character control 134 TMC .byte $00 ; Tape mode control 135 SSS .byte $04 ; Spare Stack size. (was $04 but documentation suggests $20) 136 137 ; 138 ; Code fragment for 'PEEK' and 'POKE' 139 ; 140 PEEK stx $C3 ; 'PEEK' - store X in $C3 141 bcc LBL008 ; On carry clear goto LBL008 142 stx $C3 ; 'POKE' - store X in $C3 143 sta ($C2),y ; Store A in location pointed to by $C3 (hi) and Y (lo) 144 rts ; Return 145 LBL008 lda ($C2),y ; Load A with value pointed to by $C3 (hi) and Y (lo) 146 ldy #$00 ; Reset Y 147 rts ; Return 148 149 ; 150 ; The following table contains the addresses for the ML handlers for the IL opcodes. 151 ; 152 ; ($30-$3F) (need to annotate that) 153 SRVT .word IL_BBR ; ($40-$5F) Backward Branch Relative 154 .word IL_FBR ; ($60-$7F) Forward Branch Relative 155 .word IL__BC ; ($80-$9F) String Match Branch 156 .word IL__BV ; ($A0-$BF) Branch if not Variable 157 .word IL__BN ; ($C0-$DF) Branch if not a Number 158 .word IL__BE ; ($E0-$FF) Branch if not End of line 159 ; ($00-$07) opcodes are used for stack exchange; no addresses needed here 160 .word IL__NO ; ($08) No Operation 161 .word IL__LB ; ($09) Push Literal Byte onto Stack 162 .word IL__LN ; ($0A) Push Literal Number 163 .word IL__DS ; ($0B) Duplicate Top two bytes on Stack 164 .word IL__SP ; ($0C) Stack Pop 165 .word IL__NO ; ($0D) (Reserved) 166 .word IL__NO ; ($0E) (Reserved) 167 .word IL__NO ; ($0F) (Reserved) 168 .word IL__SB ; ($10) Save Basic Pointer 169 .word IL__RB ; ($11) Restore Basic Pointer 170 .word IL__FV ; ($12) Fetch Variable 171 .word IL__SV ; ($13) Store Variable 172 .word IL__GS ; ($14) Save GOSUB line 173 .word IL__RS ; ($15) Restore saved line 174 .word IL__GO ; ($16) GOTO 175 .word IL__NE ; ($17) Negate 176 .word IL__AD ; ($18) Add 177 .word IL__SU ; ($19) Subtract 178 .word IL__MP ; ($1A) Multiply 179 .word IL__DV ; ($1B) Divide 180 .word IL__CP ; ($1C) Compare 181 .word IL__NX ; ($1D) Next BASIC statement 182 .word IL__NO ; ($1E) (Reserved) 183 .word IL__LS ; ($1F) List the program 184 .word IL__PN ; ($20) Print Number 185 .word IL__PQ ; ($21) Print BASIC string 186 .word IL__PT ; ($22) Print Tab 187 .word IL__NL ; ($23) New Line 188 .word IL__PC ; ($24) Print Literal String 189 .word IL__NO ; ($25) (Reserved) 190 .word IL__NO ; ($26) (Reserved) 191 .word IL__GL ; ($27) Get input Line 192 .word ILRES1 ; ($28) (Seems to be reserved - No IL opcode calls this) 193 .word ILRES2 ; ($29) (Seems to be reserved - No IL opcode calls this) 194 .word IL__IL ; ($2A) Insert BASIC Line 195 .word IL__MT ; ($2B) Mark the BASIC program space Empty 196 .word IL__XQ ; ($2C) Execute 197 .word WARM_S ; ($2D) Stop (Warm Start) 198 .word IL__US ; ($2E) Machine Language Subroutine Call 199 .word IL__RT ; ($2F) IL subroutine return 200 201 ERRSTR .text " AT " ; " AT " string used in error reporting. Tom was right about this. 202 .text $80 ; String terminator 203 204 PGMADR .word ILTBL ; Address of IL program table 205 206 ; 207 ; Begin Cold Start 208 ; 209 ; Load start of free ram (TXTBGN; was: $0200) into LOWEST 210 ; and initialize the address for end of free ram (HIGHST) 211 ; 212 COLD_S lda #<TXTBGN ; Load accumulator with TXTBGN 213 sta LOWEST ; Store $00 in $20 214 sta HIGHST ; Store $00 in $22 215 lda #>TXTBGN ; Load accumulator with TXTBGN 216 sta LOWEST+1 ; Store TXTBGN in $21 217 sta HIGHST+1 ; Store TXTBGN in $23 218 ; 219 ; 220 ; Begin test for free RAM 221 ; 222 223 ldy #1 ; Load register Y with 1 224 MEM_T lda (HIGHST),y ; Load accumulator With the contents of a byte of memory 225 tax ; Save it to X 226 eor #$FF ; Next 4 instuctions test to see if this memory location 227 sta (HIGHST),y ; is RAM by trying to write something new to it - new value 228 cmp (HIGHST),y ; gets created by XORing the old value with $FF - store the 229 php ; result of the test on the stack to look at later 230 txa ; Retrieve the old memory value 231 sta (HIGHST),y ; Put it back where it came from 232 inc HIGHST ; Increment HIGHST (for next memory location) 233 bne SKP_PI ; Skip if we don't need to increment page 234 inc HIGHST+1 ; Increment HIGHST+1 (for next memory page) 235 SKP_PI lda HIGHST+1 ; Get high byte of memory address 236 cmp #>ENDMEM ; Did we reach start address of Tiny Basic? 237 bne PULL ; Branch if not 238 lda HIGHST ; Get low byte of memory address 239 cmp #<ENDMEM ; Did we reach start address of Tiny Basic? 240 beq TOP ; If so, stop memory test so we don't overwrite ourselves 241 PULL 242 plp ; Now look at the result of the memory test 243 beq MEM_T ; Go test the next memory location if the last one was RAM 244 TOP 245 dey ; If last memory location did not test as RAM, decrement Y (should be zero now) 246 ; 247 ; TBIL MT (Mark the BASIC program space Empty) 248 ; 249 IL__MT cld ; Make sure we're not in decimal mode 250 lda LOWEST ; Load up the low order byte of the start of free ram 251 adc SSS ; Add to the spare stack size 252 sta $24 ; Store the result in $0024 253 tya ; Y is zero 254 adc LOWEST+1 ; And add it to the high order byte of the start of free RAM 255 sta $25 ; Store the result in $0025 256 tya ; Retrieve Y again 257 sta (LOWEST),y ; Store A in the first byte of program memory 258 iny ; Increment Y 259 sta (LOWEST),y ; Store A in the second byte of program memory 260 ; 261 ; Begin Warm Start 262 ; 263 WARM_S lda HIGHST ; Set $C6 and RETPTR to HIGHST 264 sta $C6 265 sta RETPTR 266 lda HIGHST+1 267 sta $C7 268 sta RETPTR+1 269 jsr P_NWLN ; Go print CR, LF and pad characters 270 ; 271 ; Restart the interpreter state 272 ; 273 RESTRT lda PGMADR ; Reset the start of the IL Table 274 sta PGMPTR ; by setting PGMPTR to PGMADR 275 lda PGMADR+1 ; 276 sta PGMPTR+1 277 lda #$80 ; Reset the computation stack pointer 278 sta CSPTR ; to bottom 279 lda #$30 280 sta CSTOP ; Set computation stack top boundary to $30 281 ldx #$00 ; Set RUNNIN to zero 282 stx RUNNIN 283 stx CSPTR+1 ; CSPTR+1 is permanently set to zero 284 dex 285 txs ; Reset system stack pointer to $FF (bottom) 286 287 ; 288 ; IL execution loop 289 ; 290 loop cld ; Make sure we're in binary mode 291 jsr PGMBYT ; Go read a byte from the IL program table 292 jsr EXECUT ; Go decide what to do with it 293 jmp loop ; Repeat 294 ; 295 ; 296 ; 297 .byte $83 ; No idea about this 298 .byte $65 ; No idea about this 299 ; 300 ; 301 ; Routine to service the TBIL Instructions 302 ; 303 EXECUT cmp #$30 ; 304 bcs LBL011 ; If it's $30 or higher, it's a Branch or Jump - go handle it 305 cmp #$08 ; 306 bcc XCHBYT ; If it's less than $08, it's a stack exchange - go handle it 307 asl a ; Multiply the OP code by 2 308 tax ; and make it an index 309 EXEC lda SRVT-$03,x ; Get the high byte of the OP Code handling routine 310 pha ; and save it on the stack 311 lda SRVT-$04,x ; Get the low byte 312 pha ; and save it on the stack 313 php ; Save the processor status too 314 rti ; Now go execute the OP Code handling routine 315 ; 316 ; 317 ; Routine to handle the stack exchange 318 ; Exchange the low byte of TOS with the low byte of CSPTR+n, 319 ; where n is passed in accumulator 320 ; 321 XCHBYT adc CSPTR ; Add index number (should be even number) to 322 tax ; CSPTR so that it points to CSPTR+n 323 lda (CSPTR),y ; Get low byte of TOS 324 pha 325 lda $00,x ; Get low byte of CSPTR+n and 326 sta (CSPTR),y ; write into low byte of TOS 327 pla 328 sta $00,x ; Write original low byte of TOS into 329 rts ; low byte of CSPTR+n and exit 330 ; 331 ; Print error message? 332 ; 333 PRERR jsr P_NWLN ; Go print CR, LF and pad characters 334 lda #'!' ; '!' character 335 jsr OUT_V ; Go print it 336 lda PGMPTR ; Load the current TBIL pointer (low) 337 sec ; Set the carry flag 338 sbc PGMADR ; Subtract the TBIL table origin (low) 339 tax ; Move the difference to X 340 lda PGMPTR+1 ; Load the current TBIL pointer (high) 341 sbc PGMADR+1 ; Subtract the TBIL table origin (high) 342 jsr PRAXNM 343 lda RUNNIN ; Was the program in running state? 344 beq serr ; No, just a simple error (bell) 345 lda #<ERRSTR ; Get low byte of error string address 346 sta PGMPTR ; Put in PGMPTR 347 lda #>ERRSTR ; Get high byte of error string address 348 sta PGMPTR+1 ; Put in PGMPTR+1 349 jsr IL__PC ; Go report an error has been detected 350 ldx LINNUM ; Print the current line number 351 lda LINNUM+1 352 jsr PRAXNM 353 serr lda #$07 ; ASCII Bell 354 jsr OUT_V ; Go ring Bell 355 jsr P_NWLN ; Go print CR, LF and pad characters 356 CLRSTK lda RETPTR ; Set $C6 to RETPTR 357 sta $C6 358 lda RETPTR+1 359 sta $C7 360 jmp RESTRT 361 ; 362 ; Pop computation stack pointer 363 ; 364 POPNBR ldx #$7C ; Does the computation stack have at 365 POPNB1 cpx CSPTR ; least two items (four bytes)? 366 PRERR1 bcc PRERR ; No, error 367 ldx CSPTR ; Load old computation stack pointer 368 inc CSPTR ; into X and increment computation 369 inc CSPTR ; stack pointer by two 370 clc ; Carry cleared for use by math routines 371 rts 372 ; 373 ; TBIL Backward Branch Relative 374 ; 375 IL_BBR dec WORK+1 ; Entry point for 376 ; 377 ; TBIL Forward Branch Relative 378 ; 379 IL_FBR lda WORK+1 ; Entry point for 380 beq PRERR 381 LBL017 lda WORK ; Set PGMPTR to WORK 382 sta PGMPTR 383 lda WORK+1 384 sta PGMPTR+1 385 rts 386 ; 387 ; Jump handling routine 388 ; 389 LBL011 cmp #$40 390 bcs LBL016 ; If it's not a Jump, go to branch handler 391 pha 392 jsr PGMBYT ; Go read a byte from the TBIL table 393 adc PGMADR 394 sta WORK 395 pla 396 pha 397 and #$07 398 adc PGMADR+1 399 sta WORK+1 400 pla 401 and #$08 402 bne LBL017 403 lda WORK ; Swap WORK and PGMPTR 404 ldx PGMPTR 405 sta PGMPTR 406 stx WORK 407 lda WORK+1 408 ldx PGMPTR+1 409 sta PGMPTR+1 410 stx WORK+1 411 LBL126 lda $C6 ; Decrement $C6 by 1 412 sbc #$01 413 sta $C6 414 bcs skip 415 dec $C7 416 skip cmp $24 ; Is $C6 < $24? 417 lda $C7 418 sbc $25 419 bcc PRERR1 ; Yes, error (go to PRERR) 420 lda WORK 421 sta ($C6),y 422 iny 423 lda WORK+1 424 sta ($C6),y 425 rts 426 ; 427 ; 428 ; Branch Handler 429 ; 430 LBL016 pha 431 lsr a 432 lsr a 433 lsr a 434 lsr a 435 and #$0E 436 tax 437 pla 438 cmp #$60 ; Is it a forward branch IL code? 439 and #$1F 440 bcs LBL020 ; Yes, go and add its offset 441 ora #$E0 ; Create a negative offset 442 LBL020 clc 443 beq LBL021 ; Offset is zero, so skip the addition 444 adc PGMPTR ; Add offset to PGMPTR and save to WORK 445 sta WORK 446 tya 447 adc PGMPTR+1 448 LBL021 sta WORK+1 449 jmp EXEC ; And go to IL table dispatcher 450 ; 451 ; TBIL BC (String Match Branch) 452 ; 453 IL__BC lda TXTPTR ; Save TXTPTR into $B8 454 sta $B8 455 lda TXTPTR+1 456 sta $B9 457 match jsr CHRGOT 458 jsr CHRGET 459 eor (PGMPTR),y ; Test for char match and end of 460 tax ; string (high bit), then save it 461 jsr PGMBYT ; Go read a byte from the TBIL table 462 txa ; Is it a plain match? 463 beq match ; Yes, continue checking for a match 464 asl a ; Mask out high bit, then is it a final match? 465 beq BCEXIT ; Yes, exit 466 lda $B8 ; Restore TXTPTR from $B8 467 sta TXTPTR 468 lda $B9 469 sta TXTPTR+1 470 DO_FBR jmp IL_FBR ; Match failed, so do a (forward) branch 471 ; 472 ; TBIL BE (Branch if not End of line) 473 ; 474 IL__BE jsr CHRGOT ; Check that CR is there 475 cmp #$0D 476 bne DO_FBR ; Else do a (forward) branch 477 BCEXIT rts 478 ; 479 ; TBIL BV (Branch if not Variable) 480 ; 481 IL__BV jsr CHRGOT ; Get current char from program area 482 cmp #'Z'+1 ; Is it a letter ('A' to 'Z')? 483 bcs DO_FBR ; No, do a (forward) branch 484 cmp #'A' 485 bcc DO_FBR ; No, do a (forward) branch 486 asl a ; Yes, so create an index out of it 487 jsr PSHACC ; and push it on stack 488 CHRGET ldy #$00 489 lda (TXTPTR),y ; Get a char from program text 490 inc TXTPTR ; and increment TXTPTR by one 491 bne chk 492 inc TXTPTR+1 493 chk cmp #$0D ; CR? 494 clc 495 rts 496 ; 497 ; CHRGOT - Starting with current character in the program area, skip 498 ; any blanks until a nonblank character is reached, and return 499 ; with carry clear (nondigit) or set (digit) 500 ; 501 chgot1 jsr CHRGET 502 CHRGOT lda (TXTPTR),y ; Get a char from program text 503 cmp #' ' ; Space? 504 beq chgot1 ; Yes, skip it 505 cmp #':' ; Colon? 506 clc 507 bpl exit ; Yes, exit with carry flag clear 508 cmp #'0' ; Digit char? (carry set if yes) 509 exit rts 510 ; 511 ; TBIL BN (Branch if not a Number) 512 ; 513 IL__BN jsr CHRGOT ; Get current char from program area 514 bcc DO_FBR ; Not a digit, so do a (forward) branch 515 sty WORK ; Set WORK to zero 516 sty WORK+1 517 loop1 lda WORK ; Set WORK to 10*WORK 518 ldx WORK+1 519 asl WORK 520 rol WORK+1 521 asl WORK 522 rol WORK+1 523 clc 524 adc WORK 525 sta WORK 526 txa 527 adc WORK+1 528 asl WORK 529 rol a 530 sta WORK+1 531 jsr CHRGET ; Get next char from program area 532 and #$0F ; Assuming it is a digit, get the value 533 adc WORK ; and add it to WORK 534 sta WORK 535 tya 536 adc WORK+1 537 sta WORK+1 538 jsr CHRGOT ; Get the same char again 539 bcs loop1 ; It is a digit, so continue adding it to WORK 540 jmp PSHWRK 541 ; 542 ; Find BASIC line with target line number 543 ; 544 FINDLN jsr IL__SP ; Pop the number into WORK 545 lda WORK ; Is WORK zero? 546 ora WORK+1 547 beq PQERR ; Yes, print error 548 FNDLN1 lda LOWEST ; Set TXTPTR to LOWEST 549 sta TXTPTR 550 lda LOWEST+1 551 sta TXTPTR+1 552 LBL040 jsr GETNUM 553 beq LBL038 554 lda LINNUM ; Is LINNUM >= WORK? 555 cmp WORK 556 lda LINNUM+1 557 sbc WORK+1 558 bcs LBL038 ; Yes, ... 559 skip5 jsr CHRGET ; Skip the BASIC program line 560 bne skip5 ; by searching for $00 sentinel 561 jmp LBL040 ; Continue looking for ... 562 LBL038 lda LINNUM ; Test whether LINNUM = WORK 563 eor WORK 564 bne skip6 565 lda LINNUM+1 566 eor WORK+1 567 skip6 rts 568 ; 569 ; TBIL PC (Print Literal String) 570 ; 571 pcloop jsr CPRCHR 572 IL__PC jsr PGMBYT ; Go read a byte from the TBIL table 573 bpl pcloop ; ...else fall thru to ... 574 ; 575 ; Counted printing a character 576 ; 577 CPRCHR inc TERMPOS ; Update terminal position 578 bmi nopr ; 127 is maximum allowed; won't print beyond that 579 jmp OUT_V ; Go print it 580 nopr dec TERMPOS ; Keep TERMPOS at its maximum 581 prexit rts 582 ; 583 ; 584 ; 585 LBL046 cmp #'"' ; Is it a quote? 586 beq prexit ; No, quit 587 jsr CPRCHR 588 ; 589 ; TBIL PQ (Print BASIC string) 590 ; 591 IL__PQ jsr CHRGET ; Entry point for 592 bne LBL046 593 PQERR jmp PRERR 594 ; 595 ; TBIL PT (Print Tab) 596 ; 597 IL__PT lda #' ' ; Print a space 598 jsr CPRCHR 599 lda TERMPOS 600 and #$87 ; Do a modulo of 8, plus see if it it has gone past 127 601 bmi prexit ; Yes, it went past 127, so quit 602 bne IL__PT ; It is not divisible by 8, so continue printing spaces 603 rts ; Else it's all done 604 ; 605 ; TBIL CP (Compare) 606 ; 607 IL__CP ldx #$7B ; Make sure the computation stack has 608 jsr POPNB1 ; at least 5 bytes, then decrement 609 inc CSPTR ; CSPTR by 5 bytes (POPNB1 already 610 inc CSPTR ; decremented it by 2) 611 inc CSPTR 612 sec ; Subtract TOS from $03 and store into TOS 613 lda $03,x 614 sbc $00,x 615 sta $00,x 616 lda $04,x 617 sbc $01,x 618 bvc LBL052 ; No overflow 619 eor #$80 ; No idea what it does 620 ora #$01 621 LBL052 bmi LBL053 ; It's negative, so that means TOS < $03 622 bne LBL054 623 ora $00,x 624 beq LBL049 625 LBL054 lsr $02,x 626 LBL049 lsr $02,x 627 LBL053 lsr $02,x 628 bcc LBL050 629 PGMBYT ldy #$00 ; Read a byte from the TBIL Table 630 lda (PGMPTR),y ; 631 inc PGMPTR ; Increment TBIL Table pointer as required 632 bne skip0 ; 633 inc PGMPTR+1 ; 634 skip0 ora #$00 ; Check for $00 and set the 'Z' flag acordingly 635 LBL050 rts ; Return 636 ; 637 ; TBIL NX (Next BASIC statement) 638 ; 639 IL__NX lda RUNNIN ; Is the program running? 640 beq QUIT ; No, go to inputting 641 skip7 jsr CHRGET ; Skip rest of BASIC statement until it hits $00 642 bne skip7 643 jsr GETNUM ; Get BASIC line number 644 beq RPERR ; It's zero, so error 645 DOSTMT jsr LBL058 ; Set RUNNIN to 1 646 jsr BV ; Test for break 647 bcs RESETP ; Break invoked, so quit running 648 lda $C4 ; Set PGMPTR to $C4 649 sta PGMPTR 650 lda $C5 651 sta PGMPTR+1 652 rts 653 ; 654 ; Reset IL program pointer and go to error 655 ; 656 RESETP lda PGMADR ; Reset PGMPTR back to the beginning of 657 sta PGMPTR ; the IL program table (PGMADR) 658 lda PGMADR+1 659 sta PGMPTR+1 660 RPERR jmp PRERR ; And go to error 661 ; 662 ; 663 ; 664 QUIT sta TERMPOS ; Set TERMPOS to zero, 665 jmp CLRSTK ; clear stack and resume inputting 666 ; 667 ; TBIL XQ (Execute) 668 ; 669 IL__XQ lda LOWEST ; Set TXTPTR to LOWEST 670 sta TXTPTR 671 lda LOWEST+1 672 sta TXTPTR+1 673 jsr GETNUM ; Get line number 674 beq RPERR ; Error if it's zero 675 lda PGMPTR ; Set $C4 to PGMPTR 676 sta $C4 677 lda PGMPTR+1 678 sta $C5 679 LBL058 lda #$01 ; Set RUNNIN to 1 680 sta RUNNIN 681 rts 682 ; 683 ; TBIL GO (GOTO) 684 ; 685 IL__GO jsr FINDLN ; Find BASIC line with target line number 686 beq DOSTMT ; Found; execute it 687 GOERR lda WORK ; Otherwise set LINNUM to WORK 688 sta LINNUM 689 lda WORK+1 690 sta LINNUM+1 691 jmp PRERR ; and print error 692 ; 693 ; TBIL RS (Restore saved line) 694 ; 695 IL__RS jsr LBL063 ; Entry point for 696 jsr LBL064 697 jsr FNDLN1 698 bne GOERR 699 rts 700 ; 701 ; Read line number into LINNUM 702 ; 703 GETNUM jsr CHRGET ; Read next two bytes in program area 704 sta LINNUM ; into LINNUM, and return with zero flag 705 jsr CHRGET ; set according to whether LINNUM is zero 706 sta LINNUM+1 707 ora LINNUM 708 rts 709 ; 710 ; TBIL DS (Duplicate Top two bytes on Stack) 711 ; 712 IL__DS jsr IL__SP ; Pop TOS onto WORK then push WORK twice 713 jsr PSHWRK 714 PSHWRK lda WORK+1 ; Push WORK onto computation stack 715 PSHWKA jsr PSHACC ; Push WORK(low)/Accum(high) onto 716 lda WORK ; computation stack 717 PSHACC ldx CSPTR ; Push accumulator onto computation 718 dex ; stack 719 sta $00,x 720 stx CSPTR ; Update computation stack pointer 721 cpx CSTOP ; Has it hit the top boundary of 722 bne IL__NO ; computation stack area? No 723 LBL068 jmp PRERR ; Error: computation stack overflow 724 ; 725 ; Pop a byte from computation stack 726 ; 727 POPBYT ldx CSPTR ; Load computation stack pointer 728 cpx #$80 ; Is the stack empty? 729 bpl LBL068 ; Yes, error 730 lda $00,x ; Pop a byte from the stack 731 inc CSPTR ; and update the pointer 732 ; 733 ; TBIL NO (No Operation) 734 ; 735 IL__NO rts ; Just that...no operation :-) 736 ; 737 ; Print acc/X as (unsigned) number 738 ; 739 PRAXNM sta WORK+1 ; Copy accumulator and X register 740 stx WORK ; to WORK 741 jmp PRNUM ; Go print (unsigned) number 742 ; 743 ; TBIL PN (Print Number) 744 ; 745 IL__PN ldx CSPTR ; Load computation stack pointer 746 lda $01,x ; See whether the number is 747 bpl skip1 ; negative...no, skip it 748 jsr IL__NE ; Else negate the number on stack 749 lda #'-' ; Print a '-' to show minus sign 750 jsr CPRCHR 751 skip1 jsr IL__SP 752 PRNUM lda #$1F 753 sta $B8 754 sta $BA 755 lda #$2A 756 sta $B9 757 sta $BB 758 ldx WORK 759 ldy WORK+1 760 sec 761 sub10k inc $B8 762 txa ; Subtract 10000 ($2710) from Y/X register pair 763 sbc #$10 764 tax 765 tya 766 sbc #$27 767 tay 768 bcs sub10k 769 add1k dec $B9 770 txa ; Add 1000 ($03E8) to Y/X register pair 771 adc #$E8 772 tax 773 tya 774 adc #$03 775 tay 776 bcc add1k 777 txa 778 sub100 sec ; Subtract 100 ($64) from accumulator 779 inc $BA 780 sbc #$64 781 bcs sub100 782 dey 783 bpl sub100 784 add10 dec $BB ; Add 10 ($0A) to accumulator 785 adc #$0A 786 bcc add10 787 ora #$30 ; Convert it to ASCII digit 788 sta WORK 789 lda #$20 790 sta WORK+1 791 ldx #$FB 792 LBL199 stx $C3 793 lda WORK+1,x 794 ora WORK+1 795 cmp #$20 796 beq LBL076 797 ldy #$30 798 sty WORK+1 799 ora WORK+1 800 jsr CPRCHR 801 LBL076 ldx $C3 802 inx 803 bne LBL199 804 rts 805 ; 806 ; TBIL LS (List the program) 807 ; 808 IL__LS lda TXTPTR+1 ; Save TXTPTR on system stack 809 pha 810 lda TXTPTR 811 pha 812 lda LOWEST ; Set TXTPTR to LOWEST 813 sta TXTPTR 814 lda LOWEST+1 815 sta TXTPTR+1 816 lda $24 817 ldx $25 818 jsr LBL077 819 beq LBL078 820 jsr LBL077 821 LBL078 lda TXTPTR ; Is TXTPTR >= $B6? 822 sec 823 sbc $B6 824 lda TXTPTR+1 825 sbc $B7 826 bcs LBL079 ; Yes, exiting 827 jsr GETNUM 828 beq LBL079 ; Reach the end of program area, exiting 829 ldx LINNUM ; Print line number and ... 830 lda LINNUM+1 831 jsr PRAXNM 832 lda #' ' ; a blank after that number 833 LBL080 jsr CPRCHR 834 jsr BV ; Test for break 835 bcs LBL079 ; Break hit, so exiting 836 jsr CHRGET ; Get a char from program area 837 bne LBL080 ; and print it until it hits a $00 838 jsr IL__NL ; Print a new line 839 jmp LBL078 ; Loop back to LIST 840 ; 841 ; 842 ; 843 LBL077 sta $B6 844 inc $B6 845 bne LBL082 846 inx 847 LBL082 stx $B7 848 ldy CSPTR ; Load computation stack pointer 849 cpy #$80 850 beq LBL083 851 jsr FINDLN ; Find BASIC line with target line number 852 ; 853 ; 854 ; 855 LBL099 lda TXTPTR ; Decrement TXTPTR by 2 856 ldx TXTPTR+1 857 sec 858 sbc #$02 859 bcs skip2 860 dex 861 skip2 sta TXTPTR 862 jmp LBL085 ; 863 LBL079 pla ; Restore TXTPTR from system stack 864 sta TXTPTR 865 pla 866 sta TXTPTR+1 867 LBL083 rts 868 ; 869 ; TBIL NL (New Line) 870 ; 871 IL__NL lda TERMPOS ; Is the terminal position past 127? 872 bmi LBL083 ; Yes, exit. Otherwise fall thru to ... 873 ; 874 ; Routine to print a new line. It handles CR, LF 875 ; and adds pad characters to the ouput 876 ; 877 P_NWLN lda #$0D ; Load up a CR 878 jsr OUT_V ; Go print it 879 lda PCC ; Load the pad character code 880 and #$7F ; Test to see - 881 sta TERMPOS ; how many pad characters to print 882 beq prlf ; Skip if 0 883 prpad jsr LBL087 ; Go print pad character 884 dec TERMPOS ; One less 885 bne prpad ; Loop until 0 886 prlf lda #$0A ; Load up a LF 887 jmp LBL089 ; Go print it 888 ; 889 ; 890 ; 891 LBL092 ldy TMC 892 LBL091 sty TERMPOS 893 bcs LBL090 894 ; 895 ; TBIL GL (Get input Line) 896 ; 897 IL__GL lda #$30 ; Set TXTPTR and CSTOP to $0030 898 sta TXTPTR 899 sta CSTOP 900 sty TXTPTR+1 901 jsr PSHWRK 902 LBL090 eor $80 903 sta $80 904 jsr IN_V 905 ldy #$00 906 ldx CSTOP 907 and #$7F 908 beq LBL090 ; It is a NUL 909 cmp #$7F ; Is it a rubout? 910 beq LBL090 911 cmp #$13 ; Is it a ...? 912 beq LBL091 913 cmp #$0A ; Is it a line feed? 914 beq LBL092 915 cmp LSC ; Is it a line cancel? 916 beq cancl 917 cmp BSC ; Is it a backspace? 918 bne back 919 cpx #$30 ; Has it reached the end of input buffer? 920 bne LBL095 ; No, ... 921 cancl ldx TXTPTR 922 sty TERMPOS ; Reset TERMPOS to zero 923 lda #$0D 924 back cpx CSPTR ; ... computation stack pointer 925 bmi LBL096 926 lda #$07 ; ASCII Bell 927 jsr CPRCHR ; Ring the bell 928 jmp LBL090 929 LBL096 sta $00,x ; Append a char to the buffer 930 inx 931 inx 932 LBL095 dex 933 stx CSTOP ; Set CSTOP to current buffer position 934 cmp #$0D ; Is it a CR? 935 bne LBL090 ; No, continue inputting 936 jsr IL__NL ; Print a new line and ... 937 ; 938 ; TBIL SP (Stack Pop) 939 ; 940 IL__SP jsr POPBYT ; Pop value from computation 941 sta WORK ; stack onto WORK 942 jsr POPBYT 943 sta WORK+1 944 rts 945 ; 946 ; TBIL IL (Insert BASIC Line) 947 ; 948 IL__IL jsr LBL098 ; Entry point for 949 jsr FINDLN ; Find BASIC line with target line number 950 php 951 jsr LBL099 952 sta $B8 ; Set $B8 to TXTPTR 953 stx $B9 954 lda WORK ; Set $B6 to WORK 955 sta $B6 956 lda WORK+1 957 sta $B7 958 ldx #$00 959 plp 960 bne LBL100 961 jsr GETNUM 962 dex 963 dex 964 LBL101 dex 965 jsr CHRGET 966 bne LBL101 967 LBL100 sty LINNUM 968 sty LINNUM+1 969 jsr LBL098 970 lda #$0D 971 cmp (TXTPTR),y 972 beq LBL102 973 inx 974 inx 975 inx 976 LBL103 inx 977 iny 978 cmp (TXTPTR),y 979 bne LBL103 980 lda $B6 ; Set LINNUM to $B6 981 sta LINNUM 982 lda $B7 983 sta LINNUM+1 984 LBL102 lda $B8 ; Set WORK to $B8 985 sta WORK 986 lda $B9 987 sta WORK+1 988 clc 989 ldy #$00 990 txa 991 beq LBL104 992 bpl LBL105 993 adc $2E 994 sta $B8 995 lda $2F 996 sbc #$00 997 sta $B9 998 LBL109 lda ($2E),y 999 sta ($B8),y 1000 ldx $2E 1001 cpx $24 1002 bne LBL106 1003 lda $2F 1004 cmp $25 1005 beq LBL107 1006 LBL106 inx 1007 stx $2E 1008 bne LBL108 1009 inc $2F 1010 LBL108 inc $B8 1011 bne LBL109 1012 inc $B9 1013 bne LBL109 1014 LBL105 adc $24 1015 sta $B8 1016 sta $2E 1017 tya 1018 adc $25 1019 sta $B9 1020 sta $2F 1021 lda $2E 1022 sbc $C6 1023 lda $2F 1024 sbc $C7 1025 bcc LBL110 1026 dec PGMPTR 1027 jmp PRERR 1028 LBL110 lda ($24),y 1029 sta ($2E),y 1030 ldx $24 ; Decrement $24 by 1 1031 bne LBL111 1032 dec $25 1033 LBL111 dec $24 1034 ldx $2E ; Decrement $2E by 1 1035 bne LBL112 1036 dec $2F 1037 LBL112 dex 1038 stx $2E 1039 cpx WORK ; Is $2E = WORK? 1040 bne LBL110 ; No, go to ... 1041 ldx $2F 1042 cpx WORK+1 1043 bne LBL110 ; No, go to ... 1044 LBL107 lda $B8 ; Set $24 to $B8 1045 sta $24 1046 lda $B9 1047 sta $25 1048 LBL104 lda LINNUM ; Is LINNUM zero? 1049 ora LINNUM+1 1050 beq LBL113 ; Yes, ... 1051 lda LINNUM ; Else write LINNUM to (WORK) 1052 sta (WORK),y 1053 iny 1054 lda LINNUM+1 1055 sta (WORK),y 1056 LBL114 iny 1057 sty $B6 1058 jsr CHRGET 1059 php 1060 ldy $B6 1061 sta (WORK),y 1062 plp 1063 bne LBL114 1064 LBL113 jmp RESTRT 1065 ; 1066 ; TBIL DV (Divide) 1067 ; 1068 IL__DV jsr POPNBR ; Entry point for 1069 lda $03,x 1070 and #$80 1071 beq LBL116 1072 lda #$FF 1073 LBL116 sta WORK 1074 sta WORK+1 1075 pha 1076 adc $02,x 1077 sta $02,x 1078 pla 1079 pha 1080 adc $03,x 1081 sta $03,x 1082 pla 1083 eor $01,x 1084 sta $BB 1085 bpl LBL117 1086 jsr LBL118 1087 LBL117 ldy #$11 1088 lda $00,x 1089 ora $01,x 1090 bne LBL119 1091 jmp PRERR 1092 LBL119 sec 1093 lda WORK 1094 sbc $00,x 1095 pha 1096 lda WORK+1 1097 sbc $01,x 1098 pha 1099 eor WORK+1 1100 bmi LBL120 1101 pla 1102 sta WORK+1 1103 pla 1104 sta WORK 1105 sec 1106 jmp LBL121 1107 LBL120 pla 1108 pla 1109 clc 1110 LBL121 rol $02,x 1111 rol $03,x 1112 rol WORK 1113 rol WORK+1 1114 dey 1115 bne LBL119 1116 lda $BB 1117 bpl LBL122 1118 ; 1119 ; TBIL NE (Negate) 1120 ; 1121 IL__NE ldx CSPTR ; Load computation stack pointer 1122 LBL118 sec ; Negates the TOS by subtracting 1123 tya ; it from zero (Y is zero) and 1124 sbc $00,x ; replacing TOS with it 1125 sta $00,x 1126 tya 1127 sbc $01,x 1128 sta $01,x 1129 LBL122 rts 1130 ; 1131 ; TBIL SU (Subtract) 1132 ; 1133 IL__SU jsr IL__NE ; Negate the TOS and falls thru to... 1134 ; 1135 ; TBIL AD (Add) 1136 ; 1137 IL__AD jsr POPNBR ; Add TOS to NOS and NOS becomes TOS 1138 lda $00,x 1139 adc $02,x 1140 sta $02,x 1141 lda $01,x 1142 adc $03,x 1143 sta $03,x 1144 rts 1145 ; 1146 ; TBIL MP (Multiply) 1147 ; 1148 IL__MP jsr POPNBR 1149 ldy #$10 ; Loop 16 times 1150 lda $02,x ; Copy NOS to WORK 1151 sta WORK 1152 lda $03,x 1153 sta WORK+1 1154 mult asl $02,x ; Shift WORK/NOS unit left by 1 1155 rol $03,x 1156 rol WORK 1157 rol WORK+1 1158 bcc skip3 1159 clc ; Add TOS to NOS 1160 lda $02,x 1161 adc $00,x 1162 sta $02,x 1163 lda $03,x 1164 adc $01,x 1165 sta $03,x 1166 skip3 dey 1167 bne mult 1168 rts 1169 ; 1170 ; TBIL FV (Fetch Variable) 1171 ; 1172 IL__FV jsr POPBYT ; Pop a variable index into X 1173 tax 1174 lda $00,x 1175 ldy $01,x 1176 dec CSPTR 1177 ldx CSPTR 1178 sty $00,x 1179 jmp PSHACC 1180 ; 1181 ; TBIL SV (Store Variable) 1182 ; 1183 IL__SV ldx #$7D ; Make sure the computation stack 1184 jsr POPNB1 ; has at least three bytes on it 1185 lda $01,x ; Pop value and stask it on system stack 1186 pha 1187 lda $00,x 1188 pha 1189 jsr POPBYT ; Pop a variable index into X 1190 tax 1191 pla ; Retrieve saved value and write it 1192 sta $00,x ; into variable pointed to by X 1193 pla 1194 sta $01,x 1195 rts 1196 ; 1197 ; TBIL RT (IL subroutine return) 1198 ; 1199 IL__RT jsr LBL063 ; Entry point for 1200 lda WORK ; Set PGMPTR to WORK 1201 sta PGMPTR 1202 lda WORK+1 1203 sta PGMPTR+1 1204 rts 1205 ; 1206 ; TBIL SB (Save Basic Pointer) 1207 ; 1208 IL__SB ldx #$2C ; Entry point for 1209 bne LBL125 ; go to common routine 1210 ; 1211 ; TBIL RB (Restore Basic Pointer) 1212 ; 1213 IL__RB ldx #$2E ; Entry point for 1214 LBL125 lda $00,x 1215 cmp #$80 1216 bcs LBL098 1217 lda $01,x 1218 bne LBL098 1219 lda TXTPTR ; Set $2E to TXTPTR 1220 sta $2E 1221 lda TXTPTR+1 1222 sta $2F 1223 rts 1224 ; 1225 ; Swap TXTPTR and $2E 1226 ; 1227 LBL098 lda TXTPTR ; Swap TXTPTR and $2E 1228 ldy $2E 1229 sty TXTPTR 1230 sta $2E 1231 lda TXTPTR+1 1232 ldy $2F 1233 sty TXTPTR+1 1234 sta $2F 1235 ldy #$00 1236 rts 1237 ; 1238 ; TBIL GS (Save GOSUB line) 1239 ; 1240 IL__GS lda LINNUM ; Set WORK to LINNUM 1241 sta WORK 1242 lda LINNUM+1 1243 sta WORK+1 1244 jsr LBL126 1245 lda $C6 ; Set RETPTR to $C6 1246 sta RETPTR 1247 lda $C7 1248 LBL064 sta RETPTR+1 1249 LBL129 rts 1250 ; 1251 ; 1252 ; 1253 LBL063 lda ($C6),y ; Set WORK to ($C6) 1254 sta WORK 1255 jsr check 1256 lda ($C6),y 1257 sta WORK+1 1258 check inc $C6 ; Increment $C6 by 1 1259 bne skip4 1260 inc $C7 1261 skip4 lda HIGHST ; Is HIGHST < $C6? 1262 cmp $C6 1263 lda HIGHST+1 1264 sbc $C7 1265 bcs LBL129 ; No, exit 1266 jmp PRERR ; Error 1267 ; 1268 ; TBIL US (Machine Language Subroutine Call) 1269 ; 1270 IL__US jsr dousr ; Execute USR() function, then 1271 sta WORK ; push the accumulator onto 1272 tya ; the computation stack 1273 jmp PSHWKA 1274 dousr jsr IL__SP ; Copy low byte of third argument 1275 lda WORK ; ("A" register value) to $B6 1276 sta $B6 1277 jsr IL__SP ; Copy high byte of second argument 1278 lda WORK+1 ; ("X" register value) to $B7 1279 sta $B7 1280 ldy WORK 1281 jsr IL__SP ; Copy first argument (machine 1282 ldx $B7 ; code address) to WORK 1283 lda $B6 ; Load accumulator and X register with values 1284 clc 1285 jmp (WORK) ; Invoke the machine routine 1286 ; 1287 ; TBIL LN (Push Literal Number) 1288 ; 1289 IL__LN jsr IL__LB ; Read two bytes from the IL program table and push it 1290 ; 1291 ; TBIL LB (Push Literal Byte onto Stack) - Go read a byte from the IL table 1292 ; 1293 IL__LB jsr PGMBYT ; Read a byte from the IL program table 1294 jmp PSHACC ; and push it on stack 1295 LBL085 stx TXTPTR+1 1296 cpx #$00 1297 rts 1298 ; 1299 ; 1300 ; 1301 ILRES2 ldy #$02 ; These two entry points are for code that 1302 ILRES1 sty WORK ; does not seem to get called. Need more research. 1303 ldy #$29 ; My analysis: Set WORK to $2902, fetch a 1304 sty WORK+1 ; byte from it and if it is $08, go to 1305 ldy #$00 ; some code inside IL__DV (Divide) routine...?!? 1306 lda (WORK),y ; Why this code? Beats me 1307 cmp #$08 1308 bne LBL133 1309 jmp LBL117 1310 LBL133 rts 1311 ; 1312 ; Subroutine to decide which pad characters to print 1313 ; 1314 LBL089 jsr OUT_V ; Entry point with a character to print first 1315 LBL087 lda #$FF ; Normal entry point - Set pad to $FF 1316 bit PCC ; Check if the pad flag is on 1317 bmi LBL134 ; Skip it if not 1318 lda #$00 ; set pad to $00 1319 LBL134 jmp OUT_V ; Go print it 1320 1321 1322 ; 1323 ; TBIL program table 1324 ; 1325 ILTBL .byte $24, '>', $91, $27, $10, $E1, $59, $C5, $2A, $56, $10, $11, $2C 1326 .byte $8B, 'L', 'E', 'T'+$80, $A0, $80, '='+$80, $30, $BC, $E0, $13, $1D 1327 .byte $94, 'G', 'O'+$80 1328 .byte $88, 'T', 'O'+$80, $30, $BC, $E0, $10, $11, $16 1329 .byte $80, 'S', 'U', 'B'+$80, $30, $BC, $E0, $14, $16 1330 .byte $90, 'P', 'R'+$80, $83, 'I', 'N', 'T'+$80, $E5, $71, $88, ';'+$80, $E1, $1D, $8F 1331 .byte $A2, $21, $58, $6F, $83, ','+$80, $22, $55, $83, ':'+$80, $24, $93, $E0, $23, $1D 1332 .byte $30, $BC, $20, $48 1333 .byte $91, 'I', 'F'+$80, $30, $BC, $31, $34, $30, $BC 1334 .byte $84, 'T', 'H', 'E', 'N'+$80, $1C, $1D, $38, $0D 1335 .byte $9A, 'I', 'N', 'P', 'U', 'T'+$80, $A0, $10 1336 .byte $E7, $24, $3F, $20, $91, $27, $E1, $59, $81, ','+$80, $30, $BC, $13, $11 1337 .byte $82, ','+$80, $4D, $E0, $1D 1338 .byte $89, 'R', 'E', 'T', 'U', 'R', 'N'+$80, $E0, $15, $1D 1339 .byte $85, 'E', 'N', 'D'+$80, $E0, $2D 1340 .byte $98, 'L', 'I', 'S', 'T'+$80, $EC, $24, $00, $00, $00 1341 .byte $00, $0A, $80, $1F, $24, $93, $23, $1D, $30, $BC, $E1, $50, $80, ','+$80, $59 1342 .byte $85, 'R', 'U', 'N'+$80, $38, $0A 1343 .byte $86, 'C', 'L', 'E', 'A', 'R'+$80, $2B 1344 .byte $84, 'R', 'E', 'M'+$80, $1D, $A0 1345 .byte $80, '='+$80, $38, $14 1346 .byte $85, '-'+$80, $30, $D3, $17, $64 1347 .byte $81, '+'+$80, $30, $D3 1348 .byte $85, '+'+$80, $30, $D3, $18, $5A 1349 .byte $85, '-'+$80, $30, $D3, $19, $54, $2F, $30, $E2 1350 .byte $85, '*'+$80, $30, $E2, $1A, $5A 1351 .byte $85, '/'+$80, $30, $E2, $1B, $54, $2F 1352 .byte $98, 'R', 'N', 'D'+$80, $0A, $80, $80, $12, $0A, $09, $29, $1A, $0A, $1A 1353 .byte $85, $18, $13, $09, $80, $12, $01, $0B, $31, $30, $61, $72, $0B, $04, $02 1354 .byte $03, $05, $03, $1B, $1A, $19, $0B, $09, $06, $0A, $00, $00, $1C, $17, $2F 1355 .byte $8F, 'U', 'S', 'R'+$80, $80, '('+$80, $30, $BC, $31, $2A, $31, $2A, $80, ')'+$80, $2E 1356 .byte $2F, $A2, $12, $2F, $C1, $2F, $80, '('+$80, $30, $BC, $80, ')'+$80, $2F, $83, ','+$80 1357 .byte $38, $BC, $0B, $2F, $80, '('+$80, $52, $2F, $84, '='+$80, $09, $02, $2F, $8E, '<'+$80 1358 .byte $84, '='+$80, $09, $93, $2F, $84, '>'+$80, $09, $05, $2F, $09, $91, $2F, $80, '>'+$80 1359 .byte $84, '='+$80, $09, $06, $2F, $84, '<'+$80, $09, $95, $2F, $09, $04, $2F, $00, $00 1360 .byte $00 1361 1362 ; ['24', '3E', '91', '27', '10', 'E1', '59', 'C5', '2A', '56', '10', '11', '2C', '8B', '4C', '45', 'D4', 'A0', '80', 'BD', '30', 'BC', 'E0', '13', '1D', '94', '47', 'CF', '88', '54', 'CF', '30', 'BC', 'E0', '10', '11', '16', '80', '53', '55', 'C2', '30', 'BC', 'E0', '14', '16', '90', '50', 'D2', '83', '49', '4E', 'D4', 'E5', '71', '88', 'BB', 'E1', '1D', '8F', 'A2', '21', '58', '6F', '83', 'AC', '22', '55', '83', 'BA', '24', '93', 'E0', '23', '1D', '30', 'BC', '20', '48', '91', '49', 'C6', '30', 'BC', '31', '34', '30', 'BC', '84', '54', '48', '45', 'CE', '1C', '1D', '38', '0D', '9A', '49', '4E', '50', '55', 'D4', 'A0', '10', 'E7', '24', '3F', '20', '91', '27', 'E1', '59', '81', 'AC', '30', 'BC', '13', '11', '82', 'AC', '4D', 'E0', '1D', '89', '52', '45', '54', '55', '52', 'CE', 'E0', '15', '1D', '85', '45', '4E', 'C4', 'E0', '2D', '98', '4C', '49', '53', 'D4', 'EC', '24', '00', '00', '00', '00', '0A', '80', '1F', '24', '93', '23', '1D', '30', 'BC', 'E1', '50', '80', 'AC', '59', '85', '52', '55', 'CE', '38', '0A', '86', '43', '4C', '45', '41', 'D2', '2B', '84', '52', '45', 'CD', '1D', 'A0', '80', 'BD', '38', '14', '85', 'AD', '30', 'D3', '17', '64', '81', 'AB', '30', 'D3', '85', 'AB', '30', 'D3', '18', '5A', '85', 'AD', '30', 'D3', '19', '54', '2F', '30', 'E2', '85', 'AA', '30', 'E2', '1A', '5A', '85', 'AF', '30', 'E2', '1B', '54', '2F', '98', '52', '4E', 'C4', '0A', '80', '80', '12', '0A', '09', '29', '1A', '0A', '1A', '85', '18', '13', '09', '80', '12', '01', '0B', '31', '30', '61', '72', '0B', '04', '02', '03', '05', '03', '1B', '1A', '19', '0B', '09', '06', '0A', '00', '00', '1C', '17', '2F', '8F', '55', '53', 'D2', '80', 'A8', '30', 'BC', '31', '2A', '31', '2A', '80', 'A9', '2E', '2F', 'A2', '12', '2F', 'C1', '2F', '80', 'A8', '30', 'BC', '80', 'A9', '2F', '83', 'AC', '38', 'BC', '0B', '2F', '80', 'A8', '52', '2F', '84', 'BD', '09', '02', '2F', '8E', 'BC', '84', 'BD', '09', '93', '2F', '84', 'BE', '09', '05', '2F', '09', '91', '2F', '80', 'BE', '84', 'BD', '09', '06', '2F', '84', 'BC', '09', '95', '2F', '09', '04', '2F'] 1363 ; ['$', '>', '\x11*', "'", '\x10', 'a*', 'Y', 'E*', '*', 'V', '\x10', '\x11', ',', '\x0b*', 'L', 'E', 'T*', ' *', '\x00*', '=*', '0', '<*', '`*', '\x13', '\x1d', '\x14*', 'G', 'O*', '\x08*', 'T', 'O*', '0', '<*', '`*', '\x10', '\x11', '\x16', '\x00*', 'S', 'U', 'B*', '0', '<*', '`*', '\x14', '\x16', '\x10*', 'P', 'R*', '\x03*', 'I', 'N', 'T*', 'e*', 'q', '\x08*', ';*', 'a*', '\x1d', '\x0f*', '"*', '!', 'X', 'o', '\x03*', ',*', '"', 'U', '\x03*', ':*', '$', '\x13*', '`*', '#', '\x1d', '0', '<*', ' ', 'H', '\x11*', 'I', 'F*', '0', '<*', '1', '4', '0', '<*', '\x04*', 'T', 'H', 'E', 'N*', '\x1c', '\x1d', '8', '\r', '\x1a*', 'I', 'N', 'P', 'U', 'T*', ' *', '\x10', 'g*', '$', '?', ' ', '\x11*', "'", 'a*', 'Y', '\x01*', ',*', '0', '<*', '\x13', '\x11', '\x02*', ',*', 'M', '`*', '\x1d', '\t*', 'R', 'E', 'T', 'U', 'R', 'N*', '`*', '\x15', '\x1d', '\x05*', 'E', 'N', 'D*', '`*', '-', '\x18*', 'L', 'I', 'S', 'T*', 'l*', '$', '\x00', '\x00', '\x00', '\x00', '\n', '\x00*', '\x1f', '$', '\x13*', '#', '\x1d', '0', '<*', 'a*', 'P', '\x00*', ',*', 'Y', '\x05*', 'R', 'U', 'N*', '8', '\n', '\x06*', 'C', 'L', 'E', 'A', 'R*', '+', '\x04*', 'R', 'E', 'M*', '\x1d', ' *', '\x00*', '=*', '8', '\x14', '\x05*', '-*', '0', 'S*', '\x17', 'd', '\x01*', '+*', '0', 'S*', '\x05*', '+*', '0', 'S*', '\x18', 'Z', '\x05*', '-*', '0', 'S*', '\x19', 'T', '/', '0', 'b*', '\x05*', '**', '0', 'b*', '\x1a', 'Z', '\x05*', '/*', '0', 'b*', '\x1b', 'T', '/', '\x18*', 'R', 'N', 'D*', '\n', '\x00*', '\x00*', '\x12', '\n', '\t', ')', '\x1a', '\n', '\x1a', '\x05*', '\x18', '\x13', '\t', '\x00*', '\x12', '\x01', '\x0b', '1', '0', 'a', 'r', '\x0b', '\x04', '\x02', '\x03', '\x05', '\x03', '\x1b', '\x1a', '\x19', '\x0b', '\t', '\x06', '\n', '\x00', '\x00', '\x1c', '\x17', '/', '\x0f*', 'U', 'S', 'R*', '\x00*', '(*', '0', '<*', '1', '*', '1', '*', '\x00*', ')*', '.', '/', '"*', '\x12', '/', 'A*', '/', '\x00*', '(*', '0', '<*', '\x00*', ')*', '/', '\x03*', ',*', '8', '<*', '\x0b', '/', '\x00*', '(*', 'R', '/', '\x04*', '=*', '\t', '\x02', '/', '\x0e*', '<*', '\x04*', '=*', '\t', '\x13*', '/', '\x04*', '>*', '\t', '\x05', '/', '\t', '\x11*', '/', '\x00*', '>*', '\x04*', '=*', '\t', '\x06', '/', '\x04*', '<*', '\t', '\x15*', '/', '\t', '\x04', '/'] 1364 ; http://www.nicholson.com/rhn/basic/basic.info.html#2 1365 1366 ; 1367 ; End of Tiny Basic 1368 1369 ; 1370 ; Begin base system initialization 1371 ; 1372 FBLK jsr io.init_acia 1373 ldx #$00 1374 ldy #$00 1375 delay: ; Wait for initialization of serial line 1376 dey 1377 bne delay 1378 dex 1379 bne delay 1380 jsr CLRSC ; Go clear the screen 1381 ldx #$00 ; Offset for welcome message and prompt 1382 jsr SNDMSG ; Go print it 1383 ST_LP jsr RCCHR ; Go get a character from the console 1384 cmp #'C' ; Check for 'C' 1385 bne IS_WRM ; If not branch to next check 1386 jmp COLD_S ; Otherwise cold-start Tiny Basic 1387 IS_WRM cmp #'W' ; Check for 'W' 1388 bne PRMPT ; If not, branch to re-prompt them 1389 jmp WARM_S ; Otherwise warm-start Tiny Basic 1390 PRMPT ldx #$22 ; Offset of prompt in message block 1391 jsr SNDMSG ; Go print the prompt 1392 jmp ST_LP ; Go get the response 1393 1394 ; 1395 ; The message block. It terminates with an FF. 1396 ; 1397 MBLK 1398 .text "TINY BASIC - Copyright, Tom Pitman" 1399 .text $0D, $0A, $0D, $0A 1400 .text "Boot (C/W)? " 1401 .text $07, $FF 1402 1403 ; 1404 ; Begin BIOS subroutines 1405 ; 1406 1407 ; 1408 ; Clear the screen 1409 ; 1410 CLRSC jsr term.clear_screen 1411 #term.SET_CURSOR #$01, #$01 1412 rts 1413 1414 ; 1415 ; Print a message. 1416 ; This sub expects the message offset from MBLK in X. 1417 ; 1418 SNDMSG lda MBLK,x ; Get a character from the message block 1419 cmp #$FF ; Look for end of message marker 1420 beq EXSM ; Finish up if it is 1421 jsr SNDCHR ; Otherwise send the character 1422 inx ; Increment the pointer 1423 jmp SNDMSG ; Go get next character 1424 EXSM rts ; Return 1425 1426 ; 1427 ; Get a character from the keyboard 1428 ; Runs into SNDCHR to provide echo 1429 ; 1430 RCCHR sec ; Wait for keypress 1431 phx 1432 phy 1433 jsr io.getc 1434 ply 1435 plx 1436 1437 ; 1438 ; Send a character to the screen 1439 ; 1440 SNDCHR sta $FE ; Save the character to be printed 1441 cmp #$FF ; Check for a bunch of characters 1442 beq EXSC ; that we don't want to print to 1443 cmp #$00 ; the terminal and discard them to 1444 beq EXSC ; clean up the output 1445 cmp #$91 ; 1446 beq EXSC ; 1447 cmp #$93 ; 1448 beq EXSC ; 1449 cmp #$80 ; 1450 beq EXSC ; 1451 beq EXSC ; 1452 1453 GETSTS pha 1454 phx 1455 phy 1456 jsr io.putc 1457 ply 1458 plx 1459 pla 1460 1461 EXSC rts ; Return 1462 1463 ; 1464 ; Check break routine 1465 ; Any keystroke will produce a break condition (carry set) 1466 ; Note: BREAK is renamed CHKBREAK to prevent conflict with 1467 ; BREAK routine in SimpleMon program. 1468 ; 1469 CHKBREAK .block 1470 pha 1471 txa 1472 pha 1473 clc ; set no waiting flag 1474 jsr io.getc_nonblocking ; if key pressed, carry is set; otherwise it is clear 1475 bcc set_carry ; Since getc_nonblocking 1476 clc ; does it the other way 1477 jmp cont ; around, we have to 1478 set_carry: ; reverse it. 1479 sec 1480 cont: 1481 pla 1482 tax 1483 pla 1484 rts 1485 .bend 1486 1487 tiny_basic_end: 1488