1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767
|
; Altirra BASIC
; Copyright (C) 2014-2016 Avery Lee, All Rights Reserved.
;
; Copying and distribution of this file, with or without modification,
; are permitted in any medium without royalty provided the copyright
; notice and this notice are preserved. This file is offered as-is,
; without any warranty.
opt m-
icl 'system.inc'
icl 'tokens.inc'
;===========================================================================
.macro _MSG_BANNER
dta c'Altirra 8K BASIC 1.58'
.endm
;===========================================================================
; Zero page variables
;
; We try to be sort of compatible with Atari BASIC here, supporting all
; public variables and trying to support some unofficial usage as well.
;
; Test cases:
; QUADRATO.BAS
; - Uses $B0-B3 from USR() routine
org $0080
opt o-
argstk equ *
lomem dta a(0) ;$0080 (compat) from lomem; argument/operator stack
vntp dta a(0) ;$0082 (compat - loaded) variable name table pointer
vntd dta a(0) ;$0084 (compat - loaded) variable name table end
vvtp dta a(0) ;$0086 (compat - loaded) variable value table pointer
stmtab dta a(0) ;$0088 (compat - loaded) statement table pointer
stmcur dta a(0) ;$008A (compat - loaded) current statement pointer
starp dta a(0) ;$008C (compat - loaded) string and array table
runstk dta a(0) ;$008E (compat) runtime stack pointer
memtop2 dta a(0) ;$0090 (compat) top of BASIC memory
exLineOffset dta 0 ;offset within current line being executed
exLineOffsetNxt dta 0 ;offset of next statement
exLineEnd dta 0 ;offset of end of current line
exTrapLine dta a(0) ;TRAP line
exFloatStk dta 0 ;bit 7 set if stack is floating (line numbers)
parPtrSav: ;[6 bytes] VNTD/VVTP/STMTAB save area for parser rollback
opsp dta 0 ;operand stack pointer offset
argsp dta 0 ;argument stack pointer offset
expCommas dta 0 ;expression evaluator comma count
expFCommas dta 0
expAsnCtx dta 0 ;flag - set if this is an assignment context for arrays
expType dta 0 ;bit 7 = 0 for numeric, 1 for string
varptr dta a(0) ;pointer to current variable
lvarptr dta a(0) ;lvar pointer for array assignment
parptr dta a(0) ;parsing state machine pointer
parout dta 0 ;parsing output idx
expCurPrec dta 0 ;expression evaluator current operator precedence
iocbexec dta 0 ;current immediate/deferred mode IOCB
iocbidx dta 0 ;current IOCB*16
iocbidx2 dta 0 ;current IOCB (used to distinguish #0 and #16)
iterPtr dta a(0) ;pointer used for sequential name table indexing
ioPrintCol dta 0 ;IO: current PRINT column
ioTermSave dta 0 ;IO: String terminator byte save location
ioTermOff dta 0 ;IO: String terminator byte offset
argstk2 dta a(0) ;Evaluator: Second argument stack pointer
dataLnEnd dta 0 ;current DATA statement line end
pmgbase dta 0
pmgmode dta 0
ioTermFlag dta 0
.if grColor!=$c8
.error "Graphics color is at ",grColor," but must be at $C8 for PEEK(200) to work (see Space Station Multiplication.bas)"
.endif
.if *>$b7
.error "Zero page overflow: ",*
.endif
org $b7
dataln dta a(0) ;(compat - Mapping the Atari / ANALOG verifier) current DATA statement line
stopln = $ba ;(compat - Atari BASIC manual): line number of error
; $bb
;--------------------------------------------------------------------------
; $BC-BF are reserved as scratch space for use by the currently executing
; statement or by the parser. They must not be used by functions or library
; code.
;
org $bc
stScratch dta 0
stScratch2 dta 0
stScratch3 dta 0
stScratch4 dta 0
printDngl = stScratch ;set if the print statement is 'dangling' - no follow EOL
parStrType = prefr0 ;parsing string type: set if string exp, clear if numeric
parStBegin = stScratch2 ;parsing offset of statement begin (0 if none)
;--------------------------------------------------------------------------
; $C0-C1 are reserved as scratch space for use by the currently executing
; function.
;
funScratch1 = $c0
funScratch2 = $c1
;--------------------------------------------------------------------------
errno = $c2
errsave = $c3 ;(compat - Atari BASIC manual): error number
org $c4
dataptr dta a(0) ;current DATA statement pointer
dataoff dta 0 ;current DATA statement offset
dta 0 ;(unused)
grColor dta 0 ;graphics color (must be at $C8 for Space Station Multiplication)
ptabw dta 0 ;(compat - Atari BASIC manual): tab width
.if ptabw != $C9
.error "PTABW is wrong"
.endif
.if * > $CB
.error "$CB-D1 are reserved"
.endif
;--------------------------------------------------------------------------
; $CB-D1 are reserved for use by annoying people that read Mapping The
; Atari.
;--------------------------------------------------------------------------
; Floating-point library vars
;
; $D2-D3 is used as an extension prefix to FR0; $D4-FF are used by the FP
; library, but can be reused outside of it.
;
prefr0 = fr0-2
a0 = fr0 ;temporary pointer 0
a1 = fr0+2 ;temporary pointer 1
a2 = fr0+4 ;temporary pointer 2
a3 = fr0+6 ;temporary pointer 3
a4 = fr0+8 ;temporary pointer 4
a5 = fr0+10 ;temporary pointer 5
degflg = $fb ;(compat) degree/radian flag: 0 for radians, 6 for degrees
lbuff equ $0580
.macro _STATIC_ASSERT
.if :1
.else
.error ":2"
.endif
.endm
.macro _PAGE_CHECK
.if [:1^*]&$ff00
.error "Page boundary crossed between ",:1," and ",*
.endif
.endm
;==========================================================================
; EXE loader start
;
.if CART==0
org $3000
opt o+
;==========================================================================
; Preloader
;
; The preloader executes before the main load.
.proc __preloader
;check if BASIC is on
jsr __testROM
beq basic_ok
;try to turn basic off
lda #0
sta basicf
lda portb
ora #2
sta portb
;check again if BASIC is on
jsr __testROM
beq basic_ok
;print failure
mwa #msg_romconflict_begin icbal
mwa #msg_romconflict_end-msg_romconflict_begin icbll
mva #CIOCmdPutChars iccmd
ldx #0
jsr ciov
lda #$ff
cmp:req ch
sta ch
;exit
jmp (dosvec)
basic_ok:
;print loading banner and continue disk load
mwa #msg_loading_begin icbal
mwa #msg_loading_end-msg_loading_begin icbll
mva #CIOCmdPutChars iccmd
ldx #0
jmp ciov
msg_loading_begin:
dta 'Loading Altirra BASIC...'
msg_loading_end:
msg_romconflict_begin:
dta $9B
dta 'Cannot load Altirra BASIC: another',$9B
dta 'ROM is already present at $A000.',$9B
dta $9B
dta 'If you are running under SpartaDOS X,',$9B
dta 'use the X command to run ATBasic.',$9B
dta $9B
dta 'Press a key',$9B
msg_romconflict_end:
.endp
;--------------------------------------------------------------------------
; Exit:
; Z=0: Not writable
; Z=1: Writable
;
.proc __testROM
lda $a000
tax
eor #$ff
sta $a000
cmp $a000
stx $a000
rts
.endp
;--------------------------------------------------------------------------
ini __preloader
;--------------------------------------------------------------------------
.proc __loader
;reset RAMTOP if it is above $A000
lda #$a0
cmp ramtop
bcs ramtop_ok
adjust_ramtop:
sta ramtop
;reinitialize GR.0 screen if needed (XEP80 doesn't)
lda sdmctl
and #$20
beq dma_off
jsr wait_vbl
ldx #0
stx dmactl
stx sdmctl
lda #4
cmp:rcc vcount
mva #CIOCmdClose iccmd
jsr ciov
mva #CIOCmdOpen iccmd
mwa #editor icbal
mva #$0c icax1
mva #$00 icax2
ldx #0
jsr ciov
;Wait for a VBLANK to ensure that the screen has taken place;
;we don't just use RTCLOK because we need to ensure that stage
;2 VBLANK has been run, not just stage 1.
jsr wait_vbl
dma_off:
ramtop_ok:
;Check if we might have the OS-A or OS-B screen editor. The OS-A/B
;screen editor has a nasty bug of clearing up to one page more than
;it should on a screen clear, which will trash the beginning of our
;soft-loaded BASIC interpreter. In that case, we need to drop RAMTOP
;by another 4K to compensate. 4K is a lot, but is necessary since
;the screen editor does not align playfields properly otherwise.
;The first check we do is to see if the memory limit is already $9F00
;or lower; if so, we don't have a problem.
lda ramtop
cmp #$A0
bcc editor_ok
;The first check we do is to see if the put char routine for E: is
;that of OS-A/B. If it isn't, then either we aren't running on OS-A/B,
;or E: has been replaced. Either way, we're fine.
lda icptl
cmp #$A3
bne editor_ok
lda #$F6
cmp icptl+1
bne editor_ok
;Okay, we might have OS-A/B. However, there's a chance that someone
;preserved that entry point but fixed the editor (hah). So, let's do
;a test: put a test byte at $A000 and clear the screen. If it gets
;wiped, we have a problem.
sta $A000
ldx #0
stx icbll
stx icblh
mva #CIOCmdPutChars iccmd
lda #$7d
jsr ciov
lda $A000
cmp #$FC
beq editor_ok
;Whoops... the test byte was overwritten. Lower RAMTOP from $A0 to
;$90 and reinitialize E:.
lda #$90
bne adjust_ramtop
editor_ok:
;reset RUNAD to $A000 so we can be re-invoked
mwa #$a000 runad
;move $3800-57FF to $A000-BFFF
mva #$38 fr0+1
mva #$a0 fr1+1
ldy #0
sty fr0
sty fr1
ldx #$20
copy_loop:
mva:rne (fr0),y (fr1),y+
inc fr0+1
inc fr1+1
dex
bne copy_loop
;check if there is a command line to process
ldy #0
sty iocbidx ;!! - needed since we will be skipping it
lda (dosvec),y
cmp #$4c
bne no_cmdline
ldy #3
lda (dosvec),y
cmp #$4c
beq have_cmdline
no_cmdline:
lda #0
jmp no_filename
have_cmdline:
;skip spaces
ldy #10
lda (dosvec),y
clc
adc #63
tay
space_loop:
lda (dosvec),y
cmp #$9b
beq no_filename
iny
cmp #' '
beq space_loop
;stash filename base offset
dey
sty fr0+3
;check if the first character is other than D and there is a colon
;afterward -- if so, we should skip DOS's parser and use it straight
;as it may be a CIO filename that DOS would munge
cmp #'D'
beq possibly_dos_file
cio_file:
;copy filename to LBUFF
ldx #0
cio_copy_loop:
lda (dosvec),y
sta lbuff,x
inx
iny
cmp #$9b
bne cio_copy_loop
;stash length
stx fr0+2
tya
jmp have_filename_nz
possibly_dos_file:
;scan for colon
colon_loop:
lda (dosvec),y
iny
cmp #':'
beq cio_file
cmp #$9b
bne colon_loop
;okay, assume it's a DOS file - clear the CIO filename flag
lda #0
sta fr0+2
;try to parse out a filename
ldy fr0+3
sec
sbc #63
ldy #10
sta (dosvec),y
ldy #4
mva (dosvec),y fr0
iny
mva (dosvec),y fr0+1
jsr jump_fr0
no_filename:
have_filename_nz:
;save off filename flag
php
;cold boot ATBasic
ldx #0
stx iocbidx
stx iocbexec
inx
stx errno
;print startup banner
mwa #msg_banner_begin icbal
mwa #msg_banner_end-msg_banner_begin icbll
mva #CIOCmdPutChars iccmd
ldx #0
jsr ciov
jsr _stNew.reset_entry
jsr ExecReset
;read filename flag
plp
bne explicit_fn
;no filename... try loading implicit file
ldx #$70
stx iocbidx
mwa #default_fn_start icbal+$70
mwa #default_fn_end-default_fn_start icbll+$70
mva #CIOCmdOpen iccmd+$70
mva #$04 icax1+$70
jsr ciov
bmi load_failed
;load and run
lsr stLoadRun._loadflg
jmp stLoadRun.with_open_iocb
load_failed:
;failed... undo the EOL with an up arrow so the prompt is in the right place
mva #0 iocbidx
lda #$1c
jsr putchar
;close IOCB and jump to prompt
ldx #$70
mva #CIOCmdClose iccmd+$70
jsr ciov
jmp immediateModeReset
explicit_fn:
;move filename to line buffer
ldy #33
ldx #0
stx fr0+3
;check if filename is already there
lda fr0+2
bne fncopy_skip
fncopy_loop:
lda (dosvec),y
sta lbuff,x
cmp #$9b
beq fncopy_exit
iny
inx
bne fncopy_loop
fncopy_exit:
;finish length
stx fr0+2
fncopy_skip:
;set string pointer
mwa #lbuff fr0
;set up for RUN statement
jsr IoPutNewline
lsr stLoadRun._loadflg
ldx #$70
stx iocbidx
jmp stLoadRun.loader_entry
wait_vbl:
sei
mwa #1 cdtmv3
cli
lda:rne cdtmv4
rts
jump_fr0:
jmp (fr0)
editor:
dta c'E',$9B
default_fn_start:
dta 'D:AUTORUN.BAS',$9B
default_fn_end:
msg_banner_begin:
dta $9c ;delete loading line
_MSG_BANNER
dta $9b
msg_banner_end:
.endp
opt h-
dta a($ffff),a($3800),a($57ff)
.endif
;==========================================================================
; Cartridge start
;
opt h-
org $a000
opt o+f+
;==========================================================================
; Entry point
;
; This is totally skipped in the EXE version, where we reuse the space for
; a reload-E: stub when returning to DOS.
;
.if CART==0
msg_base = *+13
ReturnToDOS:
ldx #0
jsr IoCloseX
mva #$c0 ramtop
sta icax2
lda #$0c
ldy #<devname_e
jsr IoOpenStockDeviceX ;!! this overwrites $BC20+
jmp (dosvec)
:13 dta 0
.else
main:
;check if this is a warm start
ldx warmst
bmi immediateModeReset
;print banner
sec
rol ioTermFlag
jsr IoPrintMessageIOCB0 ;!! - X=0
jmp stNew
;==========================================================================
; Message base
;
msg_base:
msg_banner:
_MSG_BANNER
dta 0
.endif
.if msg_base != $A00D
.error "msg_base misaligned: ",*
.endif
.if * != $A023
.error "msg_ready misaligned: ",*
.endif
org $A023
msg_ready:
dta $9B,c'Ready',$9B,0
msg_stopped:
dta $9B,c"Stopped",0
msg_error:
dta $9B
msg_error2:
dta c"Error- ",0
msg_atline:
dta c" at line ",0
msg_end:
_STATIC_ASSERT (msg_end - msg_base) <= $100
;==========================================================================
immediateModeReset:
jsr ExecReset
immediateMode:
;use IOCB #0 (E:) for commands
ldx #0
stx iocbexec
.proc execLoop
;display prompt
ldx #msg_ready-msg_base
jsr IoPrintMessageIOCB0
loop2:
;reset stack
ldx #$ff
txs
;read read pointer
inx
stx cix
;reset errno
inx
stx errno
;read line
ldx iocbexec
jsr IoReadLineX ;also sets iocbidx for error handling
beq eof
;float the stack if it isn't already
jsr ExecFloatStack
;##TRACE "Parsing immediate mode line: [%.*s]" dw(icbll) lbuff
jsr parseLine
bcc loop2
;execute immediate mode line
jmp execDirect
eof:
;close IOCB #7
jsr IoSetupIOCB7 ;closes #7 as side effect
;restart in immediate mode with IOCB 0
jmp immediateMode
.endp
;==========================================================================
icl 'parserbytecode.s'
icl 'parser.s'
icl 'exec.s'
icl 'data.s'
icl 'statements.s'
icl 'evaluator.s'
icl 'functions.s'
icl 'variables.s'
icl 'math.s'
icl 'io.s'
icl 'memory.s'
icl 'list.s'
icl 'error.s'
icl 'util.s'
;==========================================================================
pmg_dmactl_tab: ;3 bytes ($1c 0c 00)
dta $1c,$0c
empty_program: ;4 bytes ($00 00 80 03)
dta $00
pmgmode_tab: ;2 bytes ($00 80)
dta $00,$80
dta $03
;==========================================================================
const_table = $bffa - 4 - 6*9 - 6 - 7
.echo "Main program ends at ",*," (",[((((*-$a000)*100/8192)/10)*16+(((*-$a000)*100)/8192)%10)],"% full) (", const_table-*," bytes free)"
org const_table
.echo "Constant table begins at ",*
.pages 1
devname_c:
dta 'C'
devname_s:
dta 'S'
devname_e:
dta 'E'
devname_p:
dta 'P'
devpath_d1all:
dta 'D:*.*',$9B
;The Maclaurin expansion for sin(x) is as follows:
;
; sin(x) = x - x^3/3! + x^5/5! - x^7/7! + x^9/9! - x^11/11!...
;
;We modify it this way:
;
; let y = x / pi2 (for x in [0, pi], pi2 = pi/2
; sin(x) = y*[pi2 - y^2*pi2^3/3! + y^4*pi2^5/5! - y^6*pi2^7/7! + y^8*pi2*9/9! - y^10*pi2^11/11!...]
;
; let z = y^2
; sin(x) = y*[pi2 - z*pi2^3/3! + z^2*pi2^5/5! - z^3*pi2^7/7! + z^4*pi2*9/9! - z^5*pi2^11/11!...]
;
fpconst_sin:
dta $BD,$03,$43,$18,$69,$61 ;-0.00 00 03 43 18 69 61 07114469471
dta $3E,$01,$60,$25,$47,$91 ; 0.00 01 60 25 47 91 80067132008
dta $BE,$46,$81,$65,$78,$84 ;-0.00 46 81 65 78 83 6641486819
dta $3F,$07,$96,$92,$60,$37 ; 0.07 96 92 60 37 48579552158
dta $BF,$64,$59,$64,$09,$56 ;-0.64 59 64 09 55 8200198258
angle_conv_tab:
fpconst_pi2:
dta $40,$01,$57,$07,$96,$33 ; 1.57 07 96 32 67682236008 (also last sin coefficient)
dta $40,$90,$00,$00,$00 ; 90 (!! - last byte shared with next table!)
hvstick_table:
dta $00,$FF,$01,$00
fp_180_div_pi:
.fl 57.295779513082
const_one:
dta $40,$01
pmg_move_mask_tab:
dta $00,$00,$00,$00,$fc,$f3,$cf,$3f
.endpg
_STATIC_ASSERT *=$bffa
;==========================================================================
.echo "Program ends at ",*," (",[((((*-$a000)*100/8192)/10)*16+(((*-$a000)*100)/8192)%10)],"% full)"
org $bffa
dta a($a000) ;boot vector
dta $00 ;do not init
dta $05 ;boot disk/tape, boot cart
dta a(ExNop) ;init vector (no-op)
.if CART==0
opt f-h+
run __loader
.endif
end
|