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
|
; Altirra BASIC - Expression evaluator module
; Copyright (C) 2014 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.
;===========================================================================
; The stack handling is conceptually similar to that of Atari BASIC, but
; has diverged quite a bit for efficiency. It now looks like this:
;
; +----------------------+ LOMEM + $100
; | operator stack |
; +----------------------+
; . | .
; . v .
; . .
; . ^ .
; . | .
; +----------------------+
; | argument stack 2 |
; +----------------------+ LOMEM + $6C
; . .
; . .
; . ^ .
; . | .
; +----------------------+
; | argument stack 1 |
; +----------------------+ LOMEM
;
; The argument stacks together contain the values pushed onto the stack
; and grow upward, while the operator stack grows downward from the top.
; opsp points to the last valid location. There is enough room for 36
; levels of nesting.
;
; The paired argument stack is very different from Atari BASIC. First,
; it only contains six bytes per entry instead of eight, omitting the
; type and variable bytes. This is because most of the time keeping
; these on the stack is unnecessary -- the argument types for each token
; type are already known and enforced by the parser. A couple of statements
; do take both types, including LIST, INPUT, and PRINT, and for those we
; maintain a type byte for the top of stack. Variable information is
; available from LVARPTR for the leftmost variable and VARPTR for the
; rightmost variable.
;
; The six bytes of the argument stack are split between the two argument
; stacks, with even bytes in stack 1 and odd bytes in stack 2. This serves
; two purposes, one being to reduce the amount of stack pointer futzing
; we have to do, and also to provide easy access to 16-bit quantities.
; argsp points to the next available location. It would be faster to
; store the stack as SoA like Turbo Basic XL does, but since we are running
; from ROM and have neither a suitable absolute addressed writable area
; nor enough zero page to burn on 6 pointers, we sacrifice a little
; speed here.
;
; There is one other trick that we do, which is to cache the top of stack
; in FR0. Each argument stack is actually shifted up one entry, with the
; first entry not used. This is a substantial performance and size
; optimization as it eliminates a lot of paired pushes and pops. For
; instance, instead of doing pop(fr1)/pop(fr0)/fadd/push(fr0) for an add
; token, we simply just do pop(fr1)/fadd. Unary operators are even
; simpler -- ABS() just has to clear FR0 bit 7!
;
; The bottom of the stack, argsp=0, has special significance when in an
; assignment context (expAsnCtx bit 7 = 1). Two differences in execution
; occur in this situation. First, a pointer to the variable's value is
; stashed in LVARPTR for later use. Second, the string indexing function
; allows selecting a range beyond the current length of a string.
;===========================================================================
ExprEvalIOCBCommaInt:
jsr evaluateHashIOCB
ExprSkipCommaAndEvalPopInt:
inc exLineOffset
.proc evaluateInt
jsr evaluate
jmp ExprConvFR0Int
.endp
;===========================================================================
.proc evaluateHashIOCBOpt
;default to IOCB #0
ldx #0
stx iocbidx
;check if we have an IOCB
jsr ExecTestEnd
cmp #TOK_EXP_HASH
sec ;set C=1 to indicate no #iocb found
bne valid_iocb
.def :evaluateHashIOCBNoCheckZero = *
;fetch IOCB# -- note that we deliberately don't check the high
;byte, for compatbility with Atari BASIC
jsr ExprSkipCommaAndEvalPopIntPos
;IOCB #0 is allowed by some statements, so we don't check it here.
; OPEN - not allowed
; CLOSE - not allowed
; XIO - not allowed
; GET - not allowed
; PUT - not allowed
; NOTE - not allowed
; POINT - not allowed
; STATUS - not allowed
; PRINT - allowed
; INPUT - allowed
;IOCB #8-15 aren't allowed, but #16 is (#$&*#)
txa
asl
asl
asl
asl
bmi invalid_iocb
sta iocbidx
clc ;set C=0 to indicate #iocb found
valid_iocb:
stx iocbidx2
rts
invalid_iocb:
jmp errorBadDeviceNo
.endp
;===========================================================================
.proc evaluateHashIOCB
jsr evaluateHashIOCBNoCheckZero
txa
beq evaluateHashIOCBOpt.invalid_iocb
rts
.endp
;===========================================================================
ExprSkipCommaAndEvalVar = ExprSkipCommaAndEval
evaluateVar = evaluate
;===========================================================================
.proc ExprPushLiteralConst
sta expType
jsr ExprPushExtFR0
ldy exLineOffset
:6 mva (stmcur),y+ fr0+#
sty exLineOffset
;##TRACE "Pushing literal constant: %g" fr0
bne evaluate.loop
.endp
;===========================================================================
.proc ExprPushLiteralStr
;build argument stack entry
jsr ExprPushExtFR0
lda #$83
sta expType
;length
;dimensioned length
;load and stash string literal length (so we don't have to thrash Y)
ldy exLineOffset
lda (stmcur),y
sta fr0+2
;skip past length and string in statement text
sec
adc exLineOffset
sta exLineOffset
;address
tya
sec ;+1 to skip length
adc stmcur
sta fr0
lda #0
sta fr0+3
adc stmcur+1
sta fr0+1
;all done
bne evaluate.loop
.endp
;===========================================================================
; Main expression evaluator.
;
; _assign_entry:
; Special entry point that takes custom evaluation flags in the A
; register:
;
; bit 7 = assignment context - allow string bounds beyond current
; length for first lvalue
;
; bit 6 = DIM context - allow references to undimensioned array/string
; variables
;
ExprSkipCommaAndEval:
inc exLineOffset
.proc evaluate
_tmpadr = fr0+1
;set up rvalue context
lda #0
dta {bit $0100} ;bit $80xx
.def :evaluateAssignment
lda #$80
_assign_entry:
sta expAsnCtx
;;##TRACE "Beginning evaluation at $%04x+$%02x = $%04x" dw(stmcur) db(exLineOffset) dw(stmcur)+db(exLineOffset)
;reset stack pointers
ldy #0
sty opsp
sty argsp
loop_open_parens:
sty expCommas
loop:
;get next token
ldy exLineOffset
inc exLineOffset
lda (stmcur),y
;;##TRACE "Processing token: $%02x ($%04x+$%02x=$%04x)" (a) dw(stmcur) y dw(stmcur)+y
;check if this token needs to be reduced immediately
bmi is_variable
cmp #$0f
bcc ExprPushLiteralConst
beq ExprPushLiteralStr
;==== reduce loop ====
;reduce while precedence of new operator is equal or lower than
;precedence of last operator on stack
;get push-on / shift precedence
;
;if bit 7 is set, we immedately shift
pha
tax
lda prec_table-$12,x
bmi shift
sta expCurPrec
;;##TRACE "Current operator get-on precedence = $%02x" a
reduce_loop:
ldy opsp
beq reduce_done
lda (argstk),y
;get pull-off/reduce precendence
tax
lda prec_table-$12,x ;!! - $10 (COM) and $11 (CLOSE) can never follow an expression
and #$7e
;stop reducing if the current operator has higher precedence
;;##TRACE "Checking precedence: tos $%02x vs. cur $%02x" a db(expCurPrec)
cmp expCurPrec
bcc reduce_done
inc opsp
jsr dispatch
;##ASSERT (db(argsp)%3)=0
jmp reduce_loop
reduce_done:
;exit if this is not an expression token
lda expCurPrec
beq done
;push current operator on stack
shift:
dec opsp
ldy opsp
pla
;##TRACE "Shift: $%02x" (a)
sta (argstk),y
bne loop ;!! - unconditional (we would never shift a $00 token)
done:
pla
;;##TRACE "Exiting evaluator"
dec exLineOffset
rts
is_variable:
;##TRACE "Push variable $%02X" (a)
;get value address of variable
jsr VarGetAddr0
;check if this is the first var at the base -- if so, set the
;lvalue ptr for possible assignment
ldy argsp
bne not_lvalue
lda varptr
adc #2
sta lvarptr
lda varptr+1
adc #0
sta lvarptr+1
;since we know the stack is empty, we know we don't need to push, either
ldy #3
sty argsp
bne skip_push_fr0
not_lvalue:
;push variable entry from VNTP onto argument stack
jsr ExprPushFR0NonEmpty
skip_push_fr0:
;load variable
jsr VarLoadFR0
;fetch type and set expression type
ldy #0
lda (varptr),y
sta expType
;check if we had an array or string
;;##TRACE "arg %02x %02x %02x %02x" db(dw(argstk)+0) db(dw(argstk)+1) db(dw(argstk)+2) db(dw(argstk)+3)
cmp #$40
bcc loop
;check if it is dimensioned
lsr
bcc not_dimmed
undim_ok:
;check if we have a relative pointer
lsr
bcs loop
;it's relative -- convert relative pointer to absolute
;;##TRACE "Converting to absolute"
ldy #starp
jsr IntAddToFR0
bne loop ;!! - unconditional
not_dimmed:
;check if we allow unDIM'd vars (i.e. we're in DIM)
bit expAsnCtx
bvs undim_ok
jmp errorDimError
dispatch:
;##TRACE "Reduce: $%02x (%y) by %02x - %u values on stack (%02X%02X%02X%02X%02X%02X %g)" (x) db(functionDispatchTableLo-$1D+x)+256*db(functionDispatchTableHi-$1D+x)+1 db($100+((s+1)&$ff)) db(argsp)/3 db(dw(argstk)+db(argsp)-3) db(dw(argstk2)+db(argsp)-3) db(dw(argstk)+db(argsp)-2) db(dw(argstk2)+db(argsp)-2) db(dw(argstk)+db(argsp)-1) db(dw(argstk2)+db(argsp)-1) fr0
lda functionDispatchTableHi-$1D,x
pha
lda functionDispatchTableLo-$1D,x
pha
;On entry to all functions, X is guaranteed to hold the operator
;token. This is used by some multi-dispatch points.
rts
.endp
;===========================================================================
; Precedence tables
;
; There are two precedences for each operator, a go-on and come-off
; precedence. A reduce happens if prec_on(cur) <= prec_off(tos); a
; shift happens otherwise. A prec_on of zero also terminates evaluation
; after the entire stack is reduced. prec_on is the value from the table,
; while prec_off = prec_on & $7F.
;
; If bit 7 is set, the operator always shifts when it is encountered.
; Unary operators and open parens need this.
;
; For arithmetic operators, prec_on <= prec_off for left associativity and
; prec_on > prec_off for right associativity. Bit 0 therefore indicates
; right associativity.
;
; Parentheses use a bit of a hack: open parens are force-shifted onto the
; stack but have a low precedence to allow arguments to accumulate. The
; close parens also has a low precedence and causes reduction of everything
; in between, including comma operators and the open paren. The open paren's
; reduction routine then terminates the reduction loop to prevent the close
; paren from reducing more than one nesting level or itself being
; shifted/reduced.
;
; Commas are shifted onto the stack along with the parameters they separate,
; and when finally reduced due to the close parenthesis, increment the comma
; count as they reduce. They have to be shifted onto the stack instead of
; reducing immediately so that expressions like USR(X,USR(A,B,C)) work --
; the outer call's commas need to be stacked so they don't collide with those
; of the inner call.
;
; Unary operators have to be right-associative. We don't care about order of
; unary +/-, but we do need to preserve ordering of NOT versus +/- so that
; -NOT 0 works. Atari BASIC does not allow this sequence, but Basic XE does.
;
PREC_PCLOSE = 2
PREC_POPEN = 4+$80
PREC_COMMA = 6+$01 ;Commas must be right associative so that nesting works, i.e. USR(0,1,2*(X-Y)
PREC_ASSIGN = 8
PREC_OR = 10
PREC_AND = 12
PREC_NOT = 14+$80
PREC_REL = 16
PREC_ADD = 18
PREC_MUL = 20
PREC_BITWISE = 22
PREC_EXP = 24
PREC_UNARY = 26+$80
PREC_RELSTR = 28
;Normally, making functions right associative wouldn't make sense because
;there are always parentheses in between -- the closing parens will force
;reduction to the open parens, which will in turn force reduction of the
;function operator. However, SYSGEN from the Corvus disk has a uniquely
;broken statement:
;
; $494B: 22001
; $494F: $12 $36
; $4950: $80 DAT$
; $4951: $2E =
; $4952: $3E CHR$
; $4953: $3A (
; $4954: $0E 16
; $495B: $2C )
; $495C: $14 :
; $495E: $2C $36
; $495F: $80 DAT$
; $4960: $37 (
; $4961: $0E 2
; $4968: $3C ,
; $4969: $0E 2
; $4970: $2C )
; $4971: $2E =
; $4972: $3E CHR$
; $4973: $47 SIN
; $4974: $9B DRVNUM
; $4975: $2C )
; $4976: $14 :
; $4978: $38 $36
; $4979: $9C THELEN
; $497A: $2D =
; $497B: $0E 2
; $4982: $14 :
; $4984: $3C $0C GOSUB
; $4985: $8A BCI
; $4986: $14 :
; $4988: $3F $24 RETURN {end $498A}
;
;There is a SIN token where there should be a function open token. This
;happens to work because Atari BASIC computes SIN(DRVNUM) first, which
;rounds off to be 1 again. To make this work, we have to ensure that the
;SIN reduces first.
;
PREC_FUNC = 30+$80
.proc prec_table
dta 0 ;$12 ,
dta 0 ;$13 $
dta 0 ;$14 : (statement end)
dta 0 ;$15 ;
dta 0 ;$16 EOL
dta 0 ;$17 goto
dta 0 ;$18 gosub
dta 0 ;$19 to
dta 0 ;$1A step
dta 0 ;$1B then
dta 0 ;$1C #
dta PREC_REL ;$1D <=
dta PREC_REL ;$1E <>
dta PREC_REL ;$1F >=
dta PREC_REL ;$20 <
dta PREC_REL ;$21 >
dta PREC_REL ;$22 =
dta PREC_EXP ;$23 ^
dta PREC_MUL ;$24 *
dta PREC_ADD ;$25 +
dta PREC_ADD ;$26 -
dta PREC_MUL ;$27 /
dta PREC_NOT ;$28 not
dta PREC_OR ;$29 or
dta PREC_AND ;$2A and
dta PREC_POPEN ;$2B (
dta PREC_PCLOSE ;$2C )
dta PREC_ASSIGN ;$2D = (numeric assignment)
dta PREC_ASSIGN ;$2E = (string assignment)
dta PREC_RELSTR ;$2F <= (strings)
dta PREC_RELSTR ;$30 <>
dta PREC_RELSTR ;$31 >=
dta PREC_RELSTR ;$32 <
dta PREC_RELSTR ;$33 >
dta PREC_RELSTR ;$34 =
dta PREC_UNARY ;$35 + (unary)
dta PREC_UNARY ;$36 -
dta PREC_POPEN ;$37 ( (string left paren)
dta PREC_POPEN ;$38 ( (array left paren)
dta PREC_POPEN ;$39 ( (dim array left paren)
dta PREC_POPEN ;$3A ( (fun left paren)
dta PREC_POPEN ;$3B ( (dim str left paren)
dta PREC_COMMA ;$3C , (array/argument comma)
;$3D and on are functions
dta PREC_FUNC ;$3D
dta PREC_FUNC ;$3E
dta PREC_FUNC ;$3F
dta PREC_FUNC ;$40
dta PREC_FUNC ;$41
dta PREC_FUNC ;$42
dta PREC_FUNC ;$43
dta PREC_FUNC ;$44
dta PREC_FUNC ;$45
dta PREC_FUNC ;$46
dta PREC_FUNC ;$47
dta PREC_FUNC ;$48
dta PREC_FUNC ;$49
dta PREC_FUNC ;$4A
dta PREC_FUNC ;$4B
dta PREC_FUNC ;$4C
dta PREC_FUNC ;$4D
dta PREC_FUNC ;$4E
dta PREC_FUNC ;$4F
dta PREC_FUNC ;$50
dta PREC_FUNC ;$51
dta PREC_FUNC ;$52
dta PREC_FUNC ;$53
dta PREC_FUNC ;$54
dta PREC_FUNC ;$55
dta PREC_BITWISE ;$56 % (xor)
dta PREC_BITWISE ;$57 ! (or)
dta PREC_BITWISE ;$58 & (and)
dta PREC_FUNC ;$59
dta PREC_POPEN ;$5A BUMP(
dta PREC_FUNC ;$5B
dta PREC_FUNC ;$5C
dta PREC_FUNC ;$5D
dta PREC_FUNC ;$5E
dta PREC_FUNC ;$5F
dta PREC_FUNC ;$60
dta PREC_FUNC ;$61
.endp
;===========================================================================
ExprPopExtFR0 = expPopFR0
;===========================================================================
ExprFmoveAndPopFR0:
jsr fmove
.proc expPopFR0
ldy argsp
;##ASSERT (y%3)=0 and y
dey
mva (argstk2),y fr0+5
mva (argstk),y fr0+4
dey
mva (argstk2),y fr0+3
mva (argstk),y fr0+2
dey
mva (argstk2),y fr0+1
mva (argstk),y fr0
sty argsp
rts
.endp
;===========================================================================
; Output:
; A:X = integer value
; P.N,Z = set from A
; P.C = 0 (since we fire an error if C=1 from FPI)
;
.proc expPopFR0Int
jsr expPopFR0
.def :ExprConvFR0Int = *
jsr fpi
bcs fail
ldx fr0
lda fr0+1
exit:
rts
fail:
jmp errorValueErr
.endp
;===========================================================================
; Output:
; A:X = integer value
; P.N,Z = set from A
; P.C = 0
;
ExprSkipCommaAndEvalPopIntPos:
inc exLineOffset
ExprEvalPopIntPos:
jsr evaluate
.proc ExprConvFR0IntPos
jsr ExprConvFR0Int
bpl expPopFR0Int.exit
jmp errorValue32K
.endp
;===========================================================================
; Exit:
; A = exponent/sign of popped value
; P.NZ = set from A
;
.proc expPopFR1
ldy argsp
;##ASSERT (y%3)=0 and y
dey
mva (argstk2),y fr1+5
mva (argstk),y fr1+4
dey
mva (argstk2),y fr1+3
mva (argstk),y fr1+2
dey
mva (argstk2),y fr1+1
mva (argstk),y fr1
sty argsp
rts
.endp
;===========================================================================
.proc ExprPushExtFR0
ldy argsp
beq stack_empty
.def :ExprPushFR0NonEmpty = *
mva fr0 (argstk),y
mva fr0+1 (argstk2),y+
mva fr0+2 (argstk),y
mva fr0+3 (argstk2),y+
mva fr0+4 (argstk),y
mva fr0+5 (argstk2),y+
dta {bit $0100}
stack_empty:
ldy #3
sty argsp
.def :funNoOp
rts
.endp
;===========================================================================
.macro FUNCTION_DISPATCH_TABLE
;$1D
dta :1[funCompare-1]
dta :1[funCompare-1]
dta :1[funCompare-1]
;$20
dta :1[funCompare-1]
dta :1[funCompare-1]
dta :1[funCompare-1]
dta :1[funPower-1]
dta :1[funMultiply-1]
dta :1[funAdd-1]
dta :1[funSubtract-1]
dta :1[funDivide-1]
dta :1[funNot-1]
dta :1[funOr-1]
dta :1[funAnd-1]
dta :1[funOpenParens-1]
dta :1[funNoOp-1] ;Necessary for SYSGEN (see above).
dta :1[funAssignNum-1]
dta :1[funAssignStr-1]
dta :1[funStringCompare-1]
;$30
dta :1[funStringCompare-1]
dta :1[funStringCompare-1]
dta :1[funStringCompare-1]
dta :1[funStringCompare-1]
dta :1[funStringCompare-1]
dta :1[funUnaryPlus-1]
dta :1[funUnaryMinus-1]
dta :1[funArrayStr-1]
dta :1[funArrayNum-1]
dta :1[funDimArray-1]
dta :1[funOpenParens-1]
dta :1[funDimStr-1]
dta :1[funArrayComma-1]
;$3D
dta :1[funStr-1]
dta :1[funChr-1]
dta :1[funUsr-1]
;$40
dta :1[funAsc-1]
dta :1[funVal-1]
dta :1[funLen-1]
dta :1[funAdr-1]
dta :1[funAtn-1]
dta :1[funCos-1]
dta :1[funPeek-1]
dta :1[funSin-1]
dta :1[funRnd-1]
dta :1[funFre-1]
dta :1[funExp-1]
dta :1[funLog-1]
dta :1[funClog-1]
dta :1[funSqr-1]
dta :1[funSgn-1]
dta :1[funAbs-1]
;$50
dta :1[funInt-1]
dta :1[funPaddleStick-1] ;PADDLE
dta :1[funPaddleStick-1] ;STICK
dta :1[funPaddleStick-1] ;PTRIG
dta :1[funPaddleStick-1] ;STRIG
dta :1[funInvalid-1] ;USING
dta :1[funBitwiseXor-1]
dta :1[funBitwiseOr-1]
dta :1[funBitwiseAnd-1]
dta :1[funInvalid-1] ;semicolon
dta :1[funBump-1] ;BUMP
dta :1[funInvalid-1] ;FIND
dta :1[funHex-1]
dta :1[funInvalid-1] ;RANDOM
dta :1[funDpeek-1]
dta :1[funInvalid-1] ;SYS
;$60
dta :1[funVstick-1]
dta :1[funHstick-1]
dta :1[funPmadr-1] ;PMADR
dta :1[funErr-1]
.endm
funInvalid = errorWTF
;===========================================================================
.proc functionDispatchTableLo
FUNCTION_DISPATCH_TABLE <
.endp
.proc functionDispatchTableHi
FUNCTION_DISPATCH_TABLE >
.endp
|