Acorn BBC BASIC II
Updated 9 Jul 2026
← All Acorn BBC BASIC versions
- Disassembly source on GitHub
- BBC BASIC II in The BBC Micro ROM Library
- J.G. Harston's BBC BASIC source reconstruction (mdfs.net)
- hoglet's BBC BASIC 4r32 disassembly
- The Advanced BASIC ROM User Guide (Colin Pharo)
- Memory map
- Found a mistake or a comment that could be clearer? Report an issue.
BASIC v&01 |
Sideways ROM header — language-entry slot (3 bytes)MOS dispatches Byte 0 is Reason code in A on entry:
|
|||||||||||
| 8000 | .language_entry | ||||||||||
| CMP #1 ; A=1: language start? | |||||||||||
| 8002 | BEQ language_startup ; yes: start BASIC | ||||||||||
| 8004 | RTS ; otherwise return | ||||||||||
| 8005 | EQUB &EA | ||||||||||
| 8006 | .rom_type | ||||||||||
| ; ROM type byte | |||||||||||
| ; ┌─────┬───────┬─────────────────────────────────┐ | |||||||||||
| ; │ Bit │ Value │ Meaning │ | |||||||||||
| ; ├─────┼───────┼─────────────────────────────────┤ | |||||||||||
| ; │ 7 │ 0 │ No service entry │ | |||||||||||
| ; │ 6 │ 1 │ Language entry present │ | |||||||||||
| ; │ 5 │ 1 │ Tube relocation address present │ | |||||||||||
| ; │ 4 │ 0 │ No Electron firmkey │ | |||||||||||
| ; │ 3-0 │ 0000 │ Processor: 6502 BASIC │ | |||||||||||
| ; └─────┴───────┴─────────────────────────────────┘ | |||||||||||
| EQUB %01100000 ; ROM type | |||||||||||
| 8007 | .copyright_offset | ||||||||||
| EQUB copyright - language_entry ; Offset of NUL preceding copyright (= &0e → copyright at &800e) | |||||||||||
| 8008 | .binary_version | ||||||||||
| EQUB &01 ; Binary version: &01 (informational, not used by MOS) | |||||||||||
| 8009 | .title | ||||||||||
| EQUS "BASIC" | |||||||||||
| 800E | .copyright | ||||||||||
| EQUB &00 ; NUL preceding copyright string | |||||||||||
| 800F | .copyright_string | ||||||||||
| EQUS "(C)1982 Acorn", &0A, &0D | |||||||||||
| 801E | EQUB &00 ; NUL terminator | ||||||||||
| 801F | .tube_reloc_addr | ||||||||||
| EQUB &00, &80, ; Tube relocation address (32-bit LE) — &00, &00 ; where the ROM body relocates on a Tube ; co-processor | |||||||||||
Language startupReached from the language entry when the MOS starts BASIC (A = 1). Reads HIMEM and PAGE from the MOS, clears the print and formatting state, seeds the random-number generator if it is cold, installs the BASIC error handler in BRKV, and jumps to start_new_program, which clears any program and enters the immediate ("> ") loop.
|
|||||||||
| 8023 | .language_startup←1← 8002 BEQ | ||||||||
| LDA #osbyte_read_himem ; OSBYTE &84: read HIMEM | |||||||||
| 8025 | JSR osbyte ; Read top of available user RAM (HIMEM) | ||||||||
| 8028 | STX zp_himem ; X and Y contain the address of HIMEM (low, high) | ||||||||
| 802A | STY zp_himem_1 ; HIMEM high byte | ||||||||
| 802C | LDA #osbyte_read_oshwm ; OSBYTE &83: read OSHWM (PAGE) | ||||||||
| 802E | JSR osbyte ; Read top of operating system RAM address (OSHWM) | ||||||||
| 8031 | STY zp_page ; X and Y contain the address of OSHWM (low, high) | ||||||||
| 8033 | LDX #0 ; X = 0 | ||||||||
| 8035 | STX zp_listo ; LISTO = 0: no LIST indentation | ||||||||
| 8037 | STX resint_at_2 ; @% high two bytes = 0 | ||||||||
| 803A | STX resint_at_3 ; @% byte 3 = 0 | ||||||||
| 803D | DEX ; X = &FF | ||||||||
| 803E | STX zp_width ; WIDTH = &FF: no automatic line wrap | ||||||||
| 8040 | LDX #&0a ; @% = &0000090A: byte 0 = &0A | ||||||||
| 8042 | STX resint_at ; @% = &0000090A: default PRINT format | ||||||||
| 8045 | DEX ; X = &09 | ||||||||
| 8046 | STX resint_at_1 ; @% byte 1 = &09 | ||||||||
| 8049 | LDA #1 ; Test the LFSR state for all-zero... | ||||||||
| 804B | AND zp_rnd_seed_4 ; ...only bit 0 of &11 belongs to the register | ||||||||
| 804D | ORA zp_rnd_seed ; OR bits 0-7 | ||||||||
| 804F | ORA zp_rnd_seed_1 ; bits 8-15 | ||||||||
| 8051 | ORA zp_rnd_seed_2 ; bits 16-23 | ||||||||
| 8053 | ORA zp_rnd_seed_3 ; bits 24-31 | ||||||||
| 8055 | BNE lang_install_brkv ; Non-zero: keep the existing state | ||||||||
| ; The generator needs a non-zero state. At power-on the work | |||||||||
| ; area is zero, so a fixed seed is installed here. The three | |||||||||
| ; bytes &41/&52/&57 are the ASCII codes of Wilson's initials, | |||||||||
| ; a nod to BBC BASIC's author. Nothing else re-seeds unless the | |||||||||
| ; program calls RND(-n), so a sequence is deterministic from a | |||||||||
| ; cold start. | |||||||||
| 8057 | LDA #'A' ; Cold seed: state becomes &00575241; load &41 | ||||||||
| 8059 | STA zp_rnd_seed ; byte 0 | ||||||||
| 805B | LDA #'R' ; load &52 | ||||||||
| 805D | STA zp_rnd_seed_1 ; byte 1 | ||||||||
| 805F | LDA #'W' ; load &57 | ||||||||
| 8061 | STA zp_rnd_seed_2 ; byte 2 (bytes 3 and 4 stay zero) | ||||||||
| 8063 | .lang_install_brkv←1← 8055 BNE | ||||||||
| LDA #2 ; Install brk_handler (&B402) into BRKV | |||||||||
| 8065 | STA brkv ; (BRKV low) | ||||||||
| 8068 | LDA #&b4 ; high byte &B4 | ||||||||
| 806A | STA brkv+1 ; (BRKV high) | ||||||||
| 806D | CLI ; Enable IRQs and enter the immediate loop | ||||||||
| 806E | JMP start_new_program ; Enter via NEW and the immediate loop | ||||||||
Keyword / tokeniser tableEach entry is the keyword in ASCII, then a token byte (bit 7 set), then a flag byte that drives tokenising. The flag bits are:
Bit 6 is why a pseudo-variable like PTR reads as &8F in a function position but &CF as an assignment target. Entries are ordered so that the first acceptable abbreviation of each keyword is unambiguous. The tokeniser scan stops at WIDTH's token &FE, which doubles as the
end-of-table sentinel (see the |
|||||||||||||||||
| 8071 | .keyword_table | ||||||||||||||||
| EQUS "AND" | |||||||||||||||||
| 8074 | EQUB &80, &00 | ||||||||||||||||
| 8076 | EQUS "ABS" | ||||||||||||||||
| 8079 | EQUB &94, &00 | ||||||||||||||||
| 807B | EQUS "ACS" | ||||||||||||||||
| 807E | EQUB &95, &00 | ||||||||||||||||
| 8080 | EQUS "ADVAL" | ||||||||||||||||
| 8085 | EQUB &96, &00 | ||||||||||||||||
| 8087 | EQUS "ASC" | ||||||||||||||||
| 808A | EQUB &97, &00 | ||||||||||||||||
| 808C | EQUS "ASN" | ||||||||||||||||
| 808F | EQUB &98, &00 | ||||||||||||||||
| 8091 | EQUS "ATN" | ||||||||||||||||
| 8094 | EQUB &99, &00 | ||||||||||||||||
| 8096 | EQUS "AUTO" | ||||||||||||||||
| 809A | EQUB &C6, &10 | ||||||||||||||||
| 809C | EQUS "BGET" | ||||||||||||||||
| 80A0 | EQUB &9A, &01 | ||||||||||||||||
| 80A2 | EQUS "BPUT" | ||||||||||||||||
| 80A6 | EQUB &D5, &03 | ||||||||||||||||
| 80A8 | EQUS "COLOUR" | ||||||||||||||||
| 80AE | EQUB &FB, &02 | ||||||||||||||||
| 80B0 | EQUS "CALL" | ||||||||||||||||
| 80B4 | EQUB &D6, &02 | ||||||||||||||||
| 80B6 | EQUS "CHAIN" | ||||||||||||||||
| 80BB | EQUB &D7, &02 | ||||||||||||||||
| 80BD | EQUS "CHR$" | ||||||||||||||||
| 80C1 | EQUB &BD, &00 | ||||||||||||||||
| 80C3 | EQUS "CLEAR" | ||||||||||||||||
| 80C8 | EQUB &D8, &01 | ||||||||||||||||
| 80CA | EQUS "CLOSE" | ||||||||||||||||
| 80CF | EQUB &D9, &03 | ||||||||||||||||
| 80D1 | EQUS "CLG" | ||||||||||||||||
| 80D4 | EQUB &DA, &01 | ||||||||||||||||
| 80D6 | EQUS "CLS" | ||||||||||||||||
| 80D9 | EQUB &DB, &01 | ||||||||||||||||
| 80DB | EQUS "COS" | ||||||||||||||||
| 80DE | EQUB &9B, &00 | ||||||||||||||||
| 80E0 | EQUS "COUNT" | ||||||||||||||||
| 80E5 | EQUB &9C, &01 | ||||||||||||||||
| 80E7 | EQUS "DATA" | ||||||||||||||||
| 80EB | EQUB &DC | ||||||||||||||||
| 80EC | EQUS " DEG" | ||||||||||||||||
| 80F0 | EQUB &9D, &00 | ||||||||||||||||
| 80F2 | EQUS "DEF" | ||||||||||||||||
| 80F5 | EQUB &DD, &00 | ||||||||||||||||
| 80F7 | EQUS "DELETE" | ||||||||||||||||
| 80FD | EQUB &C7, &10 | ||||||||||||||||
| 80FF | EQUS "DIV" | ||||||||||||||||
| 8102 | EQUB &81, &00 | ||||||||||||||||
| 8104 | EQUS "DIM" | ||||||||||||||||
| 8107 | EQUB &DE, &02 | ||||||||||||||||
| 8109 | EQUS "DRAW" | ||||||||||||||||
| 810D | EQUB &DF, &02 | ||||||||||||||||
| 810F | EQUS "ENDPROC" | ||||||||||||||||
| 8116 | EQUB &E1, &01 | ||||||||||||||||
| 8118 | EQUS "END" | ||||||||||||||||
| 811B | EQUB &E0, &01 | ||||||||||||||||
| 811D | EQUS "ENVELOPE" | ||||||||||||||||
| 8125 | EQUB &E2, &02 | ||||||||||||||||
| 8127 | EQUS "ELSE" | ||||||||||||||||
| 812B | EQUB &8B, &14 | ||||||||||||||||
| 812D | EQUS "EVAL" | ||||||||||||||||
| 8131 | EQUB &A0, &00 | ||||||||||||||||
| 8133 | EQUS "ERL" | ||||||||||||||||
| 8136 | EQUB &9E, &01 | ||||||||||||||||
| 8138 | EQUS "ERROR" | ||||||||||||||||
| 813D | EQUB &85, &04 | ||||||||||||||||
| 813F | EQUS "EOF" | ||||||||||||||||
| 8142 | EQUB &C5, &01 | ||||||||||||||||
| 8144 | EQUS "EOR" | ||||||||||||||||
| 8147 | EQUB &82, &00 | ||||||||||||||||
| 8149 | EQUS "ERR" | ||||||||||||||||
| 814C | EQUB &9F, &01 | ||||||||||||||||
| 814E | EQUS "EXP" | ||||||||||||||||
| 8151 | EQUB &A1, &00 | ||||||||||||||||
| 8153 | EQUS "EXT" | ||||||||||||||||
| 8156 | EQUB &A2, &01 | ||||||||||||||||
| 8158 | EQUS "FOR" | ||||||||||||||||
| 815B | EQUB &E3, &02 | ||||||||||||||||
| 815D | EQUS "FALSE" | ||||||||||||||||
| 8162 | EQUB &A3, &01, &46, &4E, &A4, &08 | ||||||||||||||||
| 8168 | EQUS "GOTO" | ||||||||||||||||
| 816C | EQUB &E5, &12 | ||||||||||||||||
| 816E | EQUS "GET$" | ||||||||||||||||
| 8172 | EQUB &BE, &00 | ||||||||||||||||
| 8174 | EQUS "GET" | ||||||||||||||||
| 8177 | EQUB &A5, &00 | ||||||||||||||||
| 8179 | EQUS "GOSUB" | ||||||||||||||||
| 817E | EQUB &E4, &12 | ||||||||||||||||
| 8180 | EQUS "GCOL" | ||||||||||||||||
| 8184 | EQUB &E6, &02 | ||||||||||||||||
| 8186 | EQUS "HIMEM" | ||||||||||||||||
| 818B | EQUB &93 | ||||||||||||||||
| 818C | EQUS "CINPUT" | ||||||||||||||||
| 8192 | EQUB &E8, &02, &49, &46, &E7, &02 | ||||||||||||||||
| 8198 | EQUS "INKEY$" | ||||||||||||||||
| 819E | EQUB &BF, &00 | ||||||||||||||||
| 81A0 | EQUS "INKEY" | ||||||||||||||||
| 81A5 | EQUB &A6, &00 | ||||||||||||||||
| 81A7 | EQUS "INT" | ||||||||||||||||
| 81AA | EQUB &A8, &00 | ||||||||||||||||
| 81AC | EQUS "INSTR(" | ||||||||||||||||
| 81B2 | EQUB &A7, &00 | ||||||||||||||||
| 81B4 | EQUS "LIST" | ||||||||||||||||
| 81B8 | EQUB &C9, &10 | ||||||||||||||||
| 81BA | EQUS "LINE" | ||||||||||||||||
| 81BE | EQUB &86, &00 | ||||||||||||||||
| 81C0 | EQUS "LOAD" | ||||||||||||||||
| 81C4 | EQUB &C8, &02 | ||||||||||||||||
| 81C6 | EQUS "LOMEM" | ||||||||||||||||
| 81CB | EQUB &92 | ||||||||||||||||
| 81CC | EQUS "CLOCAL" | ||||||||||||||||
| 81D2 | EQUB &EA, &02 | ||||||||||||||||
| 81D4 | EQUS "LEFT$(" | ||||||||||||||||
| 81DA | EQUB &C0, &00 | ||||||||||||||||
| 81DC | EQUS "LEN" | ||||||||||||||||
| 81DF | EQUB &A9, &00 | ||||||||||||||||
| 81E1 | EQUS "LET" | ||||||||||||||||
| 81E4 | EQUB &E9, &04 | ||||||||||||||||
| 81E6 | EQUS "LOG" | ||||||||||||||||
| 81E9 | EQUB &AB, &00, &4C, &4E, &AA, &00 | ||||||||||||||||
| 81EF | EQUS "MID$(" | ||||||||||||||||
| 81F4 | EQUB &C1, &00 | ||||||||||||||||
| 81F6 | EQUS "MODE" | ||||||||||||||||
| 81FA | EQUB &EB, &02 | ||||||||||||||||
| 81FC | EQUS "MOD" | ||||||||||||||||
| 81FF | EQUB &83, &00 | ||||||||||||||||
| 8201 | EQUS "MOVE" | ||||||||||||||||
| 8205 | EQUB &EC, &02 | ||||||||||||||||
| 8207 | EQUS "NEXT" | ||||||||||||||||
| 820B | EQUB &ED, &02 | ||||||||||||||||
| 820D | EQUS "NEW" | ||||||||||||||||
| 8210 | EQUB &CA, &01 | ||||||||||||||||
| 8212 | EQUS "NOT" | ||||||||||||||||
| 8215 | EQUB &AC, &00 | ||||||||||||||||
| 8217 | EQUS "OLD" | ||||||||||||||||
| 821A | EQUB &CB, &01, &4F, &4E, &EE, &02 | ||||||||||||||||
| 8220 | EQUS "OFF" | ||||||||||||||||
| 8223 | EQUB &87, &00, &4F, &52, &84, &00 | ||||||||||||||||
| 8229 | EQUS "OPENIN" | ||||||||||||||||
| 822F | EQUB &8E, &00 | ||||||||||||||||
| 8231 | EQUS "OPENOUT" | ||||||||||||||||
| 8238 | EQUB &AE, &00 | ||||||||||||||||
| 823A | EQUS "OPENUP" | ||||||||||||||||
| 8240 | EQUB &AD, &00 | ||||||||||||||||
| 8242 | EQUS "OSCLI" | ||||||||||||||||
| 8247 | EQUB &FF, &02 | ||||||||||||||||
| 8249 | EQUS "PRINT" | ||||||||||||||||
| 824E | EQUB &F1, &02 | ||||||||||||||||
| 8250 | EQUS "PAGE" | ||||||||||||||||
| 8254 | EQUB &90 | ||||||||||||||||
| 8255 | EQUS "CPTR" | ||||||||||||||||
| 8259 | EQUB &8F | ||||||||||||||||
| 825A | EQUS "CPI" | ||||||||||||||||
| 825D | EQUB &AF, &01 | ||||||||||||||||
| 825F | EQUS "PLOT" | ||||||||||||||||
| 8263 | EQUB &F0, &02 | ||||||||||||||||
| 8265 | EQUS "POINT(" | ||||||||||||||||
| 826B | EQUB &B0, &00 | ||||||||||||||||
| 826D | EQUS "PROC" | ||||||||||||||||
| 8271 | EQUB &F2, &0A | ||||||||||||||||
| 8273 | EQUS "POS" | ||||||||||||||||
| 8276 | EQUB &B1, &01 | ||||||||||||||||
| 8278 | EQUS "RETURN" | ||||||||||||||||
| 827E | EQUB &F8, &01 | ||||||||||||||||
| 8280 | EQUS "REPEAT" | ||||||||||||||||
| 8286 | EQUB &F5, &00 | ||||||||||||||||
| 8288 | EQUS "REPORT" | ||||||||||||||||
| 828E | EQUB &F6, &01 | ||||||||||||||||
| 8290 | EQUS "READ" | ||||||||||||||||
| 8294 | EQUB &F3, &02 | ||||||||||||||||
| 8296 | EQUS "REM" | ||||||||||||||||
| 8299 | EQUB &F4 | ||||||||||||||||
| 829A | EQUS " RUN" | ||||||||||||||||
| 829E | EQUB &F9, &01 | ||||||||||||||||
| 82A0 | EQUS "RAD" | ||||||||||||||||
| 82A3 | EQUB &B2, &00 | ||||||||||||||||
| 82A5 | EQUS "RESTORE" | ||||||||||||||||
| 82AC | EQUB &F7, &12 | ||||||||||||||||
| 82AE | EQUS "RIGHT$(" | ||||||||||||||||
| 82B5 | EQUB &C2, &00 | ||||||||||||||||
| 82B7 | EQUS "RND" | ||||||||||||||||
| 82BA | EQUB &B3, &01 | ||||||||||||||||
| 82BC | EQUS "RENUMBER" | ||||||||||||||||
| 82C4 | EQUB &CC, &10 | ||||||||||||||||
| 82C6 | EQUS "STEP" | ||||||||||||||||
| 82CA | EQUB &88, &00 | ||||||||||||||||
| 82CC | EQUS "SAVE" | ||||||||||||||||
| 82D0 | EQUB &CD, &02 | ||||||||||||||||
| 82D2 | EQUS "SGN" | ||||||||||||||||
| 82D5 | EQUB &B4, &00 | ||||||||||||||||
| 82D7 | EQUS "SIN" | ||||||||||||||||
| 82DA | EQUB &B5, &00 | ||||||||||||||||
| 82DC | EQUS "SQR" | ||||||||||||||||
| 82DF | .action_lo_by_token←1Used as index base by← 8BB2 LDA | ||||||||||||||||
| EQUB &B6, &00 | |||||||||||||||||
| 82E1 | EQUS "SPC" | ||||||||||||||||
| 82E4 | EQUB &89, &00 | ||||||||||||||||
| 82E6 | EQUS "STR$" | ||||||||||||||||
| 82EA | EQUB &C3, &00 | ||||||||||||||||
| 82EC | EQUS "STRING$(" | ||||||||||||||||
| 82F4 | EQUB &C4, &00 | ||||||||||||||||
| 82F6 | EQUS "SOUND" | ||||||||||||||||
| 82FB | EQUB &D4, &02 | ||||||||||||||||
| 82FD | EQUS "STOP" | ||||||||||||||||
| 8301 | EQUB &FA, &01 | ||||||||||||||||
| 8303 | EQUS "TAN" | ||||||||||||||||
| 8306 | EQUB &B7, &00 | ||||||||||||||||
| 8308 | EQUS "THEN" | ||||||||||||||||
| 830C | EQUB &8C, &14, &54, &4F, &B8, &00 | ||||||||||||||||
| 8312 | EQUS "TAB(" | ||||||||||||||||
| 8316 | EQUB &8A, &00 | ||||||||||||||||
| 8318 | EQUS "TRACE" | ||||||||||||||||
| 831D | EQUB &FC, &12 | ||||||||||||||||
| 831F | EQUS "TIME" | ||||||||||||||||
| 8323 | EQUB &91 | ||||||||||||||||
| 8324 | EQUS "CTRUE" | ||||||||||||||||
| 8329 | EQUB &B9, &01 | ||||||||||||||||
| 832B | EQUS "UNTIL" | ||||||||||||||||
| 8330 | EQUB &FD, &02 | ||||||||||||||||
| 8332 | EQUS "USR" | ||||||||||||||||
| 8335 | EQUB &BA, &00 | ||||||||||||||||
| 8337 | EQUS "VDU" | ||||||||||||||||
| 833A | EQUB &EF, &02 | ||||||||||||||||
| 833C | EQUS "VAL" | ||||||||||||||||
| 833F | EQUB &BB, &00 | ||||||||||||||||
| 8341 | EQUS "VPOS" | ||||||||||||||||
| 8345 | EQUB &BC, &01 | ||||||||||||||||
| 8347 | EQUS "WIDTH" | ||||||||||||||||
| 834C | EQUB &FE, &02 | ||||||||||||||||
| 834E | EQUS "PAG" | ||||||||||||||||
| 8351 | .action_hi_by_token←1Used as index base by← 8BB7 LDA | ||||||||||||||||
| EQUB &45, &D0, &00 | |||||||||||||||||
| 8354 | EQUS "PTR" | ||||||||||||||||
| 8357 | EQUB &CF, &00 | ||||||||||||||||
| 8359 | EQUS "TIME" | ||||||||||||||||
| 835D | EQUB &D1, &00 | ||||||||||||||||
| 835F | EQUS "LOMEM" | ||||||||||||||||
| 8364 | EQUB &D2, &00 | ||||||||||||||||
| 8366 | EQUS "HIMEM" | ||||||||||||||||
| 836B | EQUB &D3, &00 | ||||||||||||||||
| 836D | .action_table_lo | ||||||||||||||||
| EQUB <(fn_openin) | |||||||||||||||||
| 836E | EQUB <(fn_ptr) | ||||||||||||||||
| 836F | EQUB <(fn_page) | ||||||||||||||||
| 8370 | EQUB <(fn_time) | ||||||||||||||||
| 8371 | EQUB <(fn_lomem) | ||||||||||||||||
| 8372 | EQUB <(fn_himem) | ||||||||||||||||
| 8373 | EQUB <(fn_abs) | ||||||||||||||||
| 8374 | EQUB <(fn_acs) | ||||||||||||||||
| 8375 | EQUB <(fn_adval) | ||||||||||||||||
| 8376 | EQUB <(fn_asc) | ||||||||||||||||
| 8377 | EQUB <(fn_asn) | ||||||||||||||||
| 8378 | EQUB <(fn_atn) | ||||||||||||||||
| 8379 | EQUB <(fn_bget) | ||||||||||||||||
| 837A | EQUB <(fn_cos) | ||||||||||||||||
| 837B | EQUB <(fn_count) | ||||||||||||||||
| 837C | EQUB <(fn_deg) | ||||||||||||||||
| 837D | EQUB <(fn_erl) | ||||||||||||||||
| 837E | EQUB <(fn_err) | ||||||||||||||||
| 837F | EQUB <(fn_eval) | ||||||||||||||||
| 8380 | EQUB <(fn_exp) | ||||||||||||||||
| 8381 | EQUB <(fn_ext) | ||||||||||||||||
| 8382 | EQUB <(fn_false) | ||||||||||||||||
| 8383 | EQUB <(fn_fn) | ||||||||||||||||
| 8384 | EQUB <(fn_get) | ||||||||||||||||
| 8385 | EQUB <(fn_inkey) | ||||||||||||||||
| 8386 | EQUB <(fn_instr) | ||||||||||||||||
| 8387 | EQUB <(fn_int) | ||||||||||||||||
| 8388 | EQUB <(fn_len) | ||||||||||||||||
| 8389 | EQUB <(fn_ln) | ||||||||||||||||
| 838A | EQUB <(fn_log) | ||||||||||||||||
| 838B | EQUB <(fn_not) | ||||||||||||||||
| 838C | EQUB <(fn_openup) | ||||||||||||||||
| 838D | EQUB <(fn_openout) | ||||||||||||||||
| 838E | EQUB <(fn_pi) | ||||||||||||||||
| 838F | EQUB <(fn_point) | ||||||||||||||||
| 8390 | EQUB <(fn_pos) | ||||||||||||||||
| 8391 | EQUB <(fn_rad) | ||||||||||||||||
| 8392 | EQUB <(fn_rnd) | ||||||||||||||||
| 8393 | EQUB <(fn_sgn) | ||||||||||||||||
| 8394 | EQUB <(fn_sin) | ||||||||||||||||
| 8395 | EQUB <(fn_sqr) | ||||||||||||||||
| 8396 | EQUB <(fn_tan) | ||||||||||||||||
| 8397 | EQUB <(fn_to) | ||||||||||||||||
| 8398 | EQUB <(fn_true) | ||||||||||||||||
| 8399 | EQUB <(fn_usr) | ||||||||||||||||
| 839A | EQUB <(fn_val) | ||||||||||||||||
| 839B | EQUB <(fn_vpos) | ||||||||||||||||
| 839C | EQUB <(fn_chrs) | ||||||||||||||||
| 839D | EQUB <(fn_gets) | ||||||||||||||||
| 839E | EQUB <(fn_inkeys) | ||||||||||||||||
| 839F | EQUB <(fn_lefts) | ||||||||||||||||
| 83A0 | EQUB <(fn_mids) | ||||||||||||||||
| 83A1 | EQUB <(fn_rights) | ||||||||||||||||
| 83A2 | EQUB <(fn_strs) | ||||||||||||||||
| 83A3 | EQUB <(fn_strings) | ||||||||||||||||
| 83A4 | EQUB <(fn_eof) | ||||||||||||||||
| 83A5 | EQUB <(stmt_auto) | ||||||||||||||||
| 83A6 | EQUB <(stmt_delete) | ||||||||||||||||
| 83A7 | EQUB <(stmt_load) | ||||||||||||||||
| 83A8 | EQUB <(stmt_list) | ||||||||||||||||
| 83A9 | EQUB <(stmt_new) | ||||||||||||||||
| 83AA | EQUB <(stmt_old) | ||||||||||||||||
| 83AB | EQUB <(stmt_renumber) | ||||||||||||||||
| 83AC | EQUB <(stmt_save) | ||||||||||||||||
| 83AD | EQUB <(syntax_error) | ||||||||||||||||
| 83AE | EQUB <(stmt_ptr) | ||||||||||||||||
| 83AF | EQUB <(stmt_page) | ||||||||||||||||
| 83B0 | EQUB <(stmt_time) | ||||||||||||||||
| 83B1 | EQUB <(stmt_lomem) | ||||||||||||||||
| 83B2 | EQUB <(stmt_himem) | ||||||||||||||||
| 83B3 | EQUB <(stmt_sound) | ||||||||||||||||
| 83B4 | EQUB <(stmt_bput) | ||||||||||||||||
| 83B5 | EQUB <(stmt_call) | ||||||||||||||||
| 83B6 | EQUB <(stmt_chain) | ||||||||||||||||
| 83B7 | EQUB <(stmt_clear) | ||||||||||||||||
| 83B8 | EQUB <(stmt_close) | ||||||||||||||||
| 83B9 | EQUB <(stmt_clg) | ||||||||||||||||
| 83BA | EQUB <(stmt_cls) | ||||||||||||||||
| 83BB | EQUB <(stmt_data) | ||||||||||||||||
| 83BC | EQUB <(stmt_data) | ||||||||||||||||
| 83BD | EQUB <(stmt_dim) | ||||||||||||||||
| 83BE | EQUB <(stmt_draw) | ||||||||||||||||
| 83BF | EQUB <(stmt_end) | ||||||||||||||||
| 83C0 | EQUB <(stmt_endproc) | ||||||||||||||||
| 83C1 | EQUB <(stmt_envelope) | ||||||||||||||||
| 83C2 | EQUB <(stmt_for) | ||||||||||||||||
| 83C3 | EQUB <(stmt_gosub) | ||||||||||||||||
| 83C4 | EQUB <(stmt_goto) | ||||||||||||||||
| 83C5 | EQUB <(stmt_gcol) | ||||||||||||||||
| 83C6 | EQUB <(stmt_if) | ||||||||||||||||
| 83C7 | EQUB <(stmt_input) | ||||||||||||||||
| 83C8 | EQUB <(stmt_let) | ||||||||||||||||
| 83C9 | EQUB <(stmt_local) | ||||||||||||||||
| 83CA | EQUB <(stmt_mode) | ||||||||||||||||
| 83CB | EQUB <(stmt_move) | ||||||||||||||||
| 83CC | EQUB <(stmt_next) | ||||||||||||||||
| 83CD | EQUB <(stmt_on) | ||||||||||||||||
| 83CE | EQUB <(stmt_vdu) | ||||||||||||||||
| 83CF | EQUB <(stmt_plot) | ||||||||||||||||
| 83D0 | EQUB <(stmt_print) | ||||||||||||||||
| 83D1 | EQUB <(stmt_proc) | ||||||||||||||||
| 83D2 | EQUB <(stmt_read) | ||||||||||||||||
| 83D3 | EQUB <(stmt_data) | ||||||||||||||||
| 83D4 | EQUB <(stmt_repeat) | ||||||||||||||||
| 83D5 | EQUB <(stmt_report) | ||||||||||||||||
| 83D6 | EQUB <(stmt_restore) | ||||||||||||||||
| 83D7 | EQUB <(stmt_return) | ||||||||||||||||
| 83D8 | EQUB <(stmt_run) | ||||||||||||||||
| 83D9 | EQUB <(stmt_stop) | ||||||||||||||||
| 83DA | EQUB <(stmt_colour) | ||||||||||||||||
| 83DB | EQUB <(stmt_trace) | ||||||||||||||||
| 83DC | EQUB <(stmt_until) | ||||||||||||||||
| 83DD | EQUB <(stmt_width) | ||||||||||||||||
| 83DE | EQUB <(stmt_oscli) | ||||||||||||||||
| 83DF | .action_table_hi | ||||||||||||||||
| EQUB >(fn_openin) | |||||||||||||||||
| 83E0 | EQUB >(fn_ptr) | ||||||||||||||||
| 83E1 | EQUB >(fn_page) | ||||||||||||||||
| 83E2 | EQUB >(fn_time) | ||||||||||||||||
| 83E3 | EQUB >(fn_lomem) | ||||||||||||||||
| 83E4 | EQUB >(fn_himem) | ||||||||||||||||
| 83E5 | EQUB >(fn_abs) | ||||||||||||||||
| 83E6 | EQUB >(fn_acs) | ||||||||||||||||
| 83E7 | EQUB >(fn_adval) | ||||||||||||||||
| 83E8 | EQUB >(fn_asc) | ||||||||||||||||
| 83E9 | EQUB >(fn_asn) | ||||||||||||||||
| 83EA | EQUB >(fn_atn) | ||||||||||||||||
| 83EB | EQUB >(fn_bget) | ||||||||||||||||
| 83EC | EQUB >(fn_cos) | ||||||||||||||||
| 83ED | EQUB >(fn_count) | ||||||||||||||||
| 83EE | EQUB >(fn_deg) | ||||||||||||||||
| 83EF | EQUB >(fn_erl) | ||||||||||||||||
| 83F0 | EQUB >(fn_err) | ||||||||||||||||
| 83F1 | EQUB >(fn_eval) | ||||||||||||||||
| 83F2 | EQUB >(fn_exp) | ||||||||||||||||
| 83F3 | EQUB >(fn_ext) | ||||||||||||||||
| 83F4 | EQUB >(fn_false) | ||||||||||||||||
| 83F5 | EQUB >(fn_fn) | ||||||||||||||||
| 83F6 | EQUB >(fn_get) | ||||||||||||||||
| 83F7 | EQUB >(fn_inkey) | ||||||||||||||||
| 83F8 | EQUB >(fn_instr) | ||||||||||||||||
| 83F9 | EQUB >(fn_int) | ||||||||||||||||
| 83FA | EQUB >(fn_len) | ||||||||||||||||
| 83FB | EQUB >(fn_ln) | ||||||||||||||||
| 83FC | EQUB >(fn_log) | ||||||||||||||||
| 83FD | EQUB >(fn_not) | ||||||||||||||||
| 83FE | EQUB >(fn_openup) | ||||||||||||||||
| 83FF | EQUB >(fn_openout) | ||||||||||||||||
| 8400 | EQUB >(fn_pi) | ||||||||||||||||
| 8401 | EQUB >(fn_point) | ||||||||||||||||
| 8402 | EQUB >(fn_pos) | ||||||||||||||||
| 8403 | EQUB >(fn_rad) | ||||||||||||||||
| 8404 | EQUB >(fn_rnd) | ||||||||||||||||
| 8405 | EQUB >(fn_sgn) | ||||||||||||||||
| 8406 | EQUB >(fn_sin) | ||||||||||||||||
| 8407 | EQUB >(fn_sqr) | ||||||||||||||||
| 8408 | EQUB >(fn_tan) | ||||||||||||||||
| 8409 | EQUB >(fn_to) | ||||||||||||||||
| 840A | EQUB >(fn_true) | ||||||||||||||||
| 840B | EQUB >(fn_usr) | ||||||||||||||||
| 840C | EQUB >(fn_val) | ||||||||||||||||
| 840D | EQUB >(fn_vpos) | ||||||||||||||||
| 840E | EQUB >(fn_chrs) | ||||||||||||||||
| 840F | EQUB >(fn_gets) | ||||||||||||||||
| 8410 | EQUB >(fn_inkeys) | ||||||||||||||||
| 8411 | EQUB >(fn_lefts) | ||||||||||||||||
| 8412 | EQUB >(fn_mids) | ||||||||||||||||
| 8413 | EQUB >(fn_rights) | ||||||||||||||||
| 8414 | EQUB >(fn_strs) | ||||||||||||||||
| 8415 | EQUB >(fn_strings) | ||||||||||||||||
| 8416 | EQUB >(fn_eof) | ||||||||||||||||
| 8417 | EQUB >(stmt_auto) | ||||||||||||||||
| 8418 | EQUB >(stmt_delete) | ||||||||||||||||
| 8419 | EQUB >(stmt_load) | ||||||||||||||||
| 841A | EQUB >(stmt_list) | ||||||||||||||||
| 841B | EQUB >(stmt_new) | ||||||||||||||||
| 841C | EQUB >(stmt_old) | ||||||||||||||||
| 841D | EQUB >(stmt_renumber) | ||||||||||||||||
| 841E | EQUB >(stmt_save) | ||||||||||||||||
| 841F | EQUB >(syntax_error) | ||||||||||||||||
| 8420 | EQUB >(stmt_ptr) | ||||||||||||||||
| 8421 | EQUB >(stmt_page) | ||||||||||||||||
| 8422 | EQUB >(stmt_time) | ||||||||||||||||
| 8423 | EQUB >(stmt_lomem) | ||||||||||||||||
| 8424 | EQUB >(stmt_himem) | ||||||||||||||||
| 8425 | EQUB >(stmt_sound) | ||||||||||||||||
| 8426 | EQUB >(stmt_bput) | ||||||||||||||||
| 8427 | EQUB >(stmt_call) | ||||||||||||||||
| 8428 | EQUB >(stmt_chain) | ||||||||||||||||
| 8429 | EQUB >(stmt_clear) | ||||||||||||||||
| 842A | EQUB >(stmt_close) | ||||||||||||||||
| 842B | EQUB >(stmt_clg) | ||||||||||||||||
| 842C | EQUB >(stmt_cls) | ||||||||||||||||
| 842D | EQUB >(stmt_data) | ||||||||||||||||
| 842E | EQUB >(stmt_data) | ||||||||||||||||
| 842F | EQUB >(stmt_dim) | ||||||||||||||||
| 8430 | EQUB >(stmt_draw) | ||||||||||||||||
| 8431 | EQUB >(stmt_end) | ||||||||||||||||
| 8432 | EQUB >(stmt_endproc) | ||||||||||||||||
| 8433 | EQUB >(stmt_envelope) | ||||||||||||||||
| 8434 | EQUB >(stmt_for) | ||||||||||||||||
| 8435 | EQUB >(stmt_gosub) | ||||||||||||||||
| 8436 | EQUB >(stmt_goto) | ||||||||||||||||
| 8437 | EQUB >(stmt_gcol) | ||||||||||||||||
| 8438 | EQUB >(stmt_if) | ||||||||||||||||
| 8439 | EQUB >(stmt_input) | ||||||||||||||||
| 843A | EQUB >(stmt_let) | ||||||||||||||||
| 843B | EQUB >(stmt_local) | ||||||||||||||||
| 843C | EQUB >(stmt_mode) | ||||||||||||||||
| 843D | EQUB >(stmt_move) | ||||||||||||||||
| 843E | EQUB >(stmt_next) | ||||||||||||||||
| 843F | EQUB >(stmt_on) | ||||||||||||||||
| 8440 | EQUB >(stmt_vdu) | ||||||||||||||||
| 8441 | EQUB >(stmt_plot) | ||||||||||||||||
| 8442 | EQUB >(stmt_print) | ||||||||||||||||
| 8443 | EQUB >(stmt_proc) | ||||||||||||||||
| 8444 | EQUB >(stmt_read) | ||||||||||||||||
| 8445 | EQUB >(stmt_data) | ||||||||||||||||
| 8446 | EQUB >(stmt_repeat) | ||||||||||||||||
| 8447 | EQUB >(stmt_report) | ||||||||||||||||
| 8448 | EQUB >(stmt_restore) | ||||||||||||||||
| 8449 | EQUB >(stmt_return) | ||||||||||||||||
| 844A | EQUB >(stmt_run) | ||||||||||||||||
| 844B | EQUB >(stmt_stop) | ||||||||||||||||
| 844C | EQUB >(stmt_colour) | ||||||||||||||||
| 844D | EQUB >(stmt_trace) | ||||||||||||||||
| 844E | EQUB >(stmt_until) | ||||||||||||||||
| 844F | EQUB >(stmt_width) | ||||||||||||||||
Inline-assembler mnemonic tablesThree parallel byte arrays, all indexed by the same X, that turn a typed mnemonic into a base opcode:
asm_parse_mnemonic (&85BA) reads the three mnemonic letters, keeps the low 5 bits of each (A=1..Z=26) and packs them MSB-first into a 15-bit value in &3D (low) / &3E (high). asm_mn_search (&85F1) then scans X from &3A down to 1, comparing the low half against asm_mnemonic_lo,x and, on a hit, the high half against asm_mnemonic_hi,x; the matching index selects asm_base_opcode,x. Tokenised AND/EOR/OR reach the same indices directly via asm_logic_mnemonic (&8607). Because the two hash tables are pure functions of the mnemonic text, each asm_mnemonic_lo / asm_mnemonic_hi byte is emitted as the beebasm expression that re-derives it from the three letters (the assembled value is shown in the address comment). asm_base_opcode holds real 6502 opcodes and stays a plain byte. The index order is meaningful: the operand parser keys its addressing-mode handler off cpx thresholds on the matched index.
Base opcodes are each group's column-0 value; the operand parser adds addressing-mode offsets via asm_opcode_add4/8/16, so a few bases (e.g. BIT &20, LDX/LDY-immediate &A2/&A0) are the slot value, not a legal standalone opcode. OPT (&39) and EQU (&3A) are directives and have no asm_base_opcode entry. Two space-saving quirks. Index 0 is dead: the scan starts at &3A and stops at 1, so index 0 is never tested. And the tables overlap by one byte - asm_mnemonic_lo[&3A] is the first byte of asm_mnemonic_hi, and asm_mnemonic_hi[&3A] is the first byte of asm_base_opcode. The reuse is safe precisely because index 0's own high and opcode bytes, which those shared bytes stand in for, are never read. |
||||||||||||||||||||||||||||||||||||||||||||||||
| 8450 | .asm_mnemonic_lo←1Used as index base by← 85F5 CMP | |||||||||||||||||||||||||||||||||||||||||||||||
| EQUB &be ; index &00: unused padding (never tested by the scan) | ||||||||||||||||||||||||||||||||||||||||||||||||
| 8451 | EQUB (('B' AND &1F) * &400 + ('R' AND &1F) * &20 + ('K' AND &1F)) AND &FF ; [ & a m p ; 0 1 ] B R K : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8452 | EQUB (('C' AND &1F) * &400 + ('L' AND &1F) * &20 + ('C' AND &1F)) AND &FF ; [ & a m p ; 0 2 ] C L C : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8453 | EQUB (('C' AND &1F) * &400 + ('L' AND &1F) * &20 + ('D' AND &1F)) AND &FF ; [ & a m p ; 0 3 ] C L D : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8454 | EQUB (('C' AND &1F) * &400 + ('L' AND &1F) * &20 + ('I' AND &1F)) AND &FF ; [ & a m p ; 0 4 ] C L I : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8455 | EQUB (('C' AND &1F) * &400 + ('L' AND &1F) * &20 + ('V' AND &1F)) AND &FF ; [ & a m p ; 0 5 ] C L V : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8456 | EQUB (('D' AND &1F) * &400 + ('E' AND &1F) * &20 + ('X' AND &1F)) AND &FF ; [ & a m p ; 0 6 ] D E X : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8457 | EQUB (('D' AND &1F) * &400 + ('E' AND &1F) * &20 + ('Y' AND &1F)) AND &FF ; [ & a m p ; 0 7 ] D E Y : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8458 | EQUB (('I' AND &1F) * &400 + ('N' AND &1F) * &20 + ('X' AND &1F)) AND &FF ; [ & a m p ; 0 8 ] I N X : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8459 | EQUB (('I' AND &1F) * &400 + ('N' AND &1F) * &20 + ('Y' AND &1F)) AND &FF ; [ & a m p ; 0 9 ] I N Y : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 845A | EQUB (('N' AND &1F) * &400 + ('O' AND &1F) * &20 + ('P' AND &1F)) AND &FF ; [ & a m p ; 0 a ] N O P : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 845B | EQUB (('P' AND &1F) * &400 + ('H' AND &1F) * &20 + ('A' AND &1F)) AND &FF ; [ & a m p ; 0 b ] P H A : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 845C | EQUB (('P' AND &1F) * &400 + ('H' AND &1F) * &20 + ('P' AND &1F)) AND &FF ; [ & a m p ; 0 c ] P H P : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 845D | EQUB (('P' AND &1F) * &400 + ('L' AND &1F) * &20 + ('A' AND &1F)) AND &FF ; [ & a m p ; 0 d ] P L A : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 845E | EQUB (('P' AND &1F) * &400 + ('L' AND &1F) * &20 + ('P' AND &1F)) AND &FF ; [ & a m p ; 0 e ] P L P : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 845F | EQUB (('R' AND &1F) * &400 + ('T' AND &1F) * &20 + ('I' AND &1F)) AND &FF ; [ & a m p ; 0 f ] R T I : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8460 | EQUB (('R' AND &1F) * &400 + ('T' AND &1F) * &20 + ('S' AND &1F)) AND &FF ; [ & a m p ; 1 0 ] R T S : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8461 | EQUB (('S' AND &1F) * &400 + ('E' AND &1F) * &20 + ('C' AND &1F)) AND &FF ; [ & a m p ; 1 1 ] S E C : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8462 | EQUB (('S' AND &1F) * &400 + ('E' AND &1F) * &20 + ('D' AND &1F)) AND &FF ; [ & a m p ; 1 2 ] S E D : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8463 | EQUB (('S' AND &1F) * &400 + ('E' AND &1F) * &20 + ('I' AND &1F)) AND &FF ; [ & a m p ; 1 3 ] S E I : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8464 | EQUB (('T' AND &1F) * &400 + ('A' AND &1F) * &20 + ('X' AND &1F)) AND &FF ; [ & a m p ; 1 4 ] T A X : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8465 | EQUB (('T' AND &1F) * &400 + ('A' AND &1F) * &20 + ('Y' AND &1F)) AND &FF ; [ & a m p ; 1 5 ] T A Y : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8466 | EQUB (('T' AND &1F) * &400 + ('S' AND &1F) * &20 + ('X' AND &1F)) AND &FF ; [ & a m p ; 1 6 ] T S X : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8467 | EQUB (('T' AND &1F) * &400 + ('X' AND &1F) * &20 + ('A' AND &1F)) AND &FF ; [ & a m p ; 1 7 ] T X A : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8468 | EQUB (('T' AND &1F) * &400 + ('X' AND &1F) * &20 + ('S' AND &1F)) AND &FF ; [ & a m p ; 1 8 ] T X S : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8469 | EQUB (('T' AND &1F) * &400 + ('Y' AND &1F) * &20 + ('A' AND &1F)) AND &FF ; [ & a m p ; 1 9 ] T Y A : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 846A | EQUB (('B' AND &1F) * &400 + ('C' AND &1F) * &20 + ('C' AND &1F)) AND &FF ; [ & a m p ; 1 a ] B C C : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 846B | EQUB (('B' AND &1F) * &400 + ('C' AND &1F) * &20 + ('S' AND &1F)) AND &FF ; [ & a m p ; 1 b ] B C S : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 846C | EQUB (('B' AND &1F) * &400 + ('E' AND &1F) * &20 + ('Q' AND &1F)) AND &FF ; [ & a m p ; 1 c ] B E Q : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 846D | EQUB (('B' AND &1F) * &400 + ('M' AND &1F) * &20 + ('I' AND &1F)) AND &FF ; [ & a m p ; 1 d ] B M I : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 846E | EQUB (('B' AND &1F) * &400 + ('N' AND &1F) * &20 + ('E' AND &1F)) AND &FF ; [ & a m p ; 1 e ] B N E : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 846F | EQUB (('B' AND &1F) * &400 + ('P' AND &1F) * &20 + ('L' AND &1F)) AND &FF ; [ & a m p ; 1 f ] B P L : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8470 | EQUB (('B' AND &1F) * &400 + ('V' AND &1F) * &20 + ('C' AND &1F)) AND &FF ; [ & a m p ; 2 0 ] B V C : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8471 | EQUB (('B' AND &1F) * &400 + ('V' AND &1F) * &20 + ('S' AND &1F)) AND &FF ; [ & a m p ; 2 1 ] B V S : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8472 | EQUB (('A' AND &1F) * &400 + ('N' AND &1F) * &20 + ('D' AND &1F)) AND &FF ; [ & a m p ; 2 2 ] A N D : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8473 | EQUB (('E' AND &1F) * &400 + ('O' AND &1F) * &20 + ('R' AND &1F)) AND &FF ; [ & a m p ; 2 3 ] E O R : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8474 | EQUB (('O' AND &1F) * &400 + ('R' AND &1F) * &20 + ('A' AND &1F)) AND &FF ; [ & a m p ; 2 4 ] O R A : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8475 | EQUB (('A' AND &1F) * &400 + ('D' AND &1F) * &20 + ('C' AND &1F)) AND &FF ; [ & a m p ; 2 5 ] A D C : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8476 | EQUB (('C' AND &1F) * &400 + ('M' AND &1F) * &20 + ('P' AND &1F)) AND &FF ; [ & a m p ; 2 6 ] C M P : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8477 | EQUB (('L' AND &1F) * &400 + ('D' AND &1F) * &20 + ('A' AND &1F)) AND &FF ; [ & a m p ; 2 7 ] L D A : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8478 | EQUB (('S' AND &1F) * &400 + ('B' AND &1F) * &20 + ('C' AND &1F)) AND &FF ; [ & a m p ; 2 8 ] S B C : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8479 | EQUB (('A' AND &1F) * &400 + ('S' AND &1F) * &20 + ('L' AND &1F)) AND &FF ; [ & a m p ; 2 9 ] A S L : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 847A | EQUB (('L' AND &1F) * &400 + ('S' AND &1F) * &20 + ('R' AND &1F)) AND &FF ; [ & a m p ; 2 a ] L S R : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 847B | EQUB (('R' AND &1F) * &400 + ('O' AND &1F) * &20 + ('L' AND &1F)) AND &FF ; [ & a m p ; 2 b ] R O L : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 847C | EQUB (('R' AND &1F) * &400 + ('O' AND &1F) * &20 + ('R' AND &1F)) AND &FF ; [ & a m p ; 2 c ] R O R : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 847D | EQUB (('D' AND &1F) * &400 + ('E' AND &1F) * &20 + ('C' AND &1F)) AND &FF ; [ & a m p ; 2 d ] D E C : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 847E | EQUB (('I' AND &1F) * &400 + ('N' AND &1F) * &20 + ('C' AND &1F)) AND &FF ; [ & a m p ; 2 e ] I N C : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 847F | EQUB (('C' AND &1F) * &400 + ('P' AND &1F) * &20 + ('X' AND &1F)) AND &FF ; [ & a m p ; 2 f ] C P X : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8480 | EQUB (('C' AND &1F) * &400 + ('P' AND &1F) * &20 + ('Y' AND &1F)) AND &FF ; [ & a m p ; 3 0 ] C P Y : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8481 | EQUB (('B' AND &1F) * &400 + ('I' AND &1F) * &20 + ('T' AND &1F)) AND &FF ; [ & a m p ; 3 1 ] B I T : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8482 | EQUB (('J' AND &1F) * &400 + ('M' AND &1F) * &20 + ('P' AND &1F)) AND &FF ; [ & a m p ; 3 2 ] J M P : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8483 | EQUB (('J' AND &1F) * &400 + ('S' AND &1F) * &20 + ('R' AND &1F)) AND &FF ; [ & a m p ; 3 3 ] J S R : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8484 | EQUB (('L' AND &1F) * &400 + ('D' AND &1F) * &20 + ('X' AND &1F)) AND &FF ; [ & a m p ; 3 4 ] L D X : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8485 | EQUB (('L' AND &1F) * &400 + ('D' AND &1F) * &20 + ('Y' AND &1F)) AND &FF ; [ & a m p ; 3 5 ] L D Y : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8486 | EQUB (('S' AND &1F) * &400 + ('T' AND &1F) * &20 + ('A' AND &1F)) AND &FF ; [ & a m p ; 3 6 ] S T A : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8487 | EQUB (('S' AND &1F) * &400 + ('T' AND &1F) * &20 + ('X' AND &1F)) AND &FF ; [ & a m p ; 3 7 ] S T X : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8488 | EQUB (('S' AND &1F) * &400 + ('T' AND &1F) * &20 + ('Y' AND &1F)) AND &FF ; [ & a m p ; 3 8 ] S T Y : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8489 | EQUB (('O' AND &1F) * &400 + ('P' AND &1F) * &20 + ('T' AND &1F)) AND &FF ; [ & a m p ; 3 9 ] O P T d i r e c t i v e : p a c k e d - n a m e l o w b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 848A | .asm_mnemonic_hi←1Used as index base by← 85FA LDY | |||||||||||||||||||||||||||||||||||||||||||||||
| EQUB &35 ; index &00 hi (unused); also asm_mnemonic_lo[&3A] = EQU directive packed-name low byte | ||||||||||||||||||||||||||||||||||||||||||||||||
| 848B | EQUB (('B' AND &1F) * &400 + ('R' AND &1F) * &20 + ('K' AND &1F)) DIV &100 ; [ & a m p ; 0 1 ] B R K : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 848C | EQUB (('C' AND &1F) * &400 + ('L' AND &1F) * &20 + ('C' AND &1F)) DIV &100 ; [ & a m p ; 0 2 ] C L C : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 848D | EQUB (('C' AND &1F) * &400 + ('L' AND &1F) * &20 + ('D' AND &1F)) DIV &100 ; [ & a m p ; 0 3 ] C L D : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 848E | EQUB (('C' AND &1F) * &400 + ('L' AND &1F) * &20 + ('I' AND &1F)) DIV &100 ; [ & a m p ; 0 4 ] C L I : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 848F | EQUB (('C' AND &1F) * &400 + ('L' AND &1F) * &20 + ('V' AND &1F)) DIV &100 ; [ & a m p ; 0 5 ] C L V : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8490 | EQUB (('D' AND &1F) * &400 + ('E' AND &1F) * &20 + ('X' AND &1F)) DIV &100 ; [ & a m p ; 0 6 ] D E X : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8491 | EQUB (('D' AND &1F) * &400 + ('E' AND &1F) * &20 + ('Y' AND &1F)) DIV &100 ; [ & a m p ; 0 7 ] D E Y : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8492 | EQUB (('I' AND &1F) * &400 + ('N' AND &1F) * &20 + ('X' AND &1F)) DIV &100 ; [ & a m p ; 0 8 ] I N X : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8493 | EQUB (('I' AND &1F) * &400 + ('N' AND &1F) * &20 + ('Y' AND &1F)) DIV &100 ; [ & a m p ; 0 9 ] I N Y : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8494 | EQUB (('N' AND &1F) * &400 + ('O' AND &1F) * &20 + ('P' AND &1F)) DIV &100 ; [ & a m p ; 0 a ] N O P : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8495 | EQUB (('P' AND &1F) * &400 + ('H' AND &1F) * &20 + ('A' AND &1F)) DIV &100 ; [ & a m p ; 0 b ] P H A : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8496 | EQUB (('P' AND &1F) * &400 + ('H' AND &1F) * &20 + ('P' AND &1F)) DIV &100 ; [ & a m p ; 0 c ] P H P : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8497 | EQUB (('P' AND &1F) * &400 + ('L' AND &1F) * &20 + ('A' AND &1F)) DIV &100 ; [ & a m p ; 0 d ] P L A : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8498 | EQUB (('P' AND &1F) * &400 + ('L' AND &1F) * &20 + ('P' AND &1F)) DIV &100 ; [ & a m p ; 0 e ] P L P : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 8499 | EQUB (('R' AND &1F) * &400 + ('T' AND &1F) * &20 + ('I' AND &1F)) DIV &100 ; [ & a m p ; 0 f ] R T I : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 849A | EQUB (('R' AND &1F) * &400 + ('T' AND &1F) * &20 + ('S' AND &1F)) DIV &100 ; [ & a m p ; 1 0 ] R T S : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 849B | EQUB (('S' AND &1F) * &400 + ('E' AND &1F) * &20 + ('C' AND &1F)) DIV &100 ; [ & a m p ; 1 1 ] S E C : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 849C | EQUB (('S' AND &1F) * &400 + ('E' AND &1F) * &20 + ('D' AND &1F)) DIV &100 ; [ & a m p ; 1 2 ] S E D : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 849D | EQUB (('S' AND &1F) * &400 + ('E' AND &1F) * &20 + ('I' AND &1F)) DIV &100 ; [ & a m p ; 1 3 ] S E I : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 849E | EQUB (('T' AND &1F) * &400 + ('A' AND &1F) * &20 + ('X' AND &1F)) DIV &100 ; [ & a m p ; 1 4 ] T A X : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 849F | EQUB (('T' AND &1F) * &400 + ('A' AND &1F) * &20 + ('Y' AND &1F)) DIV &100 ; [ & a m p ; 1 5 ] T A Y : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84A0 | EQUB (('T' AND &1F) * &400 + ('S' AND &1F) * &20 + ('X' AND &1F)) DIV &100 ; [ & a m p ; 1 6 ] T S X : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84A1 | EQUB (('T' AND &1F) * &400 + ('X' AND &1F) * &20 + ('A' AND &1F)) DIV &100 ; [ & a m p ; 1 7 ] T X A : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84A2 | EQUB (('T' AND &1F) * &400 + ('X' AND &1F) * &20 + ('S' AND &1F)) DIV &100 ; [ & a m p ; 1 8 ] T X S : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84A3 | EQUB (('T' AND &1F) * &400 + ('Y' AND &1F) * &20 + ('A' AND &1F)) DIV &100 ; [ & a m p ; 1 9 ] T Y A : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84A4 | EQUB (('B' AND &1F) * &400 + ('C' AND &1F) * &20 + ('C' AND &1F)) DIV &100 ; [ & a m p ; 1 a ] B C C : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84A5 | EQUB (('B' AND &1F) * &400 + ('C' AND &1F) * &20 + ('S' AND &1F)) DIV &100 ; [ & a m p ; 1 b ] B C S : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84A6 | EQUB (('B' AND &1F) * &400 + ('E' AND &1F) * &20 + ('Q' AND &1F)) DIV &100 ; [ & a m p ; 1 c ] B E Q : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84A7 | EQUB (('B' AND &1F) * &400 + ('M' AND &1F) * &20 + ('I' AND &1F)) DIV &100 ; [ & a m p ; 1 d ] B M I : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84A8 | EQUB (('B' AND &1F) * &400 + ('N' AND &1F) * &20 + ('E' AND &1F)) DIV &100 ; [ & a m p ; 1 e ] B N E : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84A9 | EQUB (('B' AND &1F) * &400 + ('P' AND &1F) * &20 + ('L' AND &1F)) DIV &100 ; [ & a m p ; 1 f ] B P L : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84AA | EQUB (('B' AND &1F) * &400 + ('V' AND &1F) * &20 + ('C' AND &1F)) DIV &100 ; [ & a m p ; 2 0 ] B V C : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84AB | EQUB (('B' AND &1F) * &400 + ('V' AND &1F) * &20 + ('S' AND &1F)) DIV &100 ; [ & a m p ; 2 1 ] B V S : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84AC | EQUB (('A' AND &1F) * &400 + ('N' AND &1F) * &20 + ('D' AND &1F)) DIV &100 ; [ & a m p ; 2 2 ] A N D : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84AD | EQUB (('E' AND &1F) * &400 + ('O' AND &1F) * &20 + ('R' AND &1F)) DIV &100 ; [ & a m p ; 2 3 ] E O R : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84AE | EQUB (('O' AND &1F) * &400 + ('R' AND &1F) * &20 + ('A' AND &1F)) DIV &100 ; [ & a m p ; 2 4 ] O R A : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84AF | EQUB (('A' AND &1F) * &400 + ('D' AND &1F) * &20 + ('C' AND &1F)) DIV &100 ; [ & a m p ; 2 5 ] A D C : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84B0 | EQUB (('C' AND &1F) * &400 + ('M' AND &1F) * &20 + ('P' AND &1F)) DIV &100 ; [ & a m p ; 2 6 ] C M P : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84B1 | EQUB (('L' AND &1F) * &400 + ('D' AND &1F) * &20 + ('A' AND &1F)) DIV &100 ; [ & a m p ; 2 7 ] L D A : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84B2 | EQUB (('S' AND &1F) * &400 + ('B' AND &1F) * &20 + ('C' AND &1F)) DIV &100 ; [ & a m p ; 2 8 ] S B C : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84B3 | EQUB (('A' AND &1F) * &400 + ('S' AND &1F) * &20 + ('L' AND &1F)) DIV &100 ; [ & a m p ; 2 9 ] A S L : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84B4 | EQUB (('L' AND &1F) * &400 + ('S' AND &1F) * &20 + ('R' AND &1F)) DIV &100 ; [ & a m p ; 2 a ] L S R : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84B5 | EQUB (('R' AND &1F) * &400 + ('O' AND &1F) * &20 + ('L' AND &1F)) DIV &100 ; [ & a m p ; 2 b ] R O L : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84B6 | EQUB (('R' AND &1F) * &400 + ('O' AND &1F) * &20 + ('R' AND &1F)) DIV &100 ; [ & a m p ; 2 c ] R O R : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84B7 | EQUB (('D' AND &1F) * &400 + ('E' AND &1F) * &20 + ('C' AND &1F)) DIV &100 ; [ & a m p ; 2 d ] D E C : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84B8 | EQUB (('I' AND &1F) * &400 + ('N' AND &1F) * &20 + ('C' AND &1F)) DIV &100 ; [ & a m p ; 2 e ] I N C : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84B9 | EQUB (('C' AND &1F) * &400 + ('P' AND &1F) * &20 + ('X' AND &1F)) DIV &100 ; [ & a m p ; 2 f ] C P X : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84BA | EQUB (('C' AND &1F) * &400 + ('P' AND &1F) * &20 + ('Y' AND &1F)) DIV &100 ; [ & a m p ; 3 0 ] C P Y : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84BB | EQUB (('B' AND &1F) * &400 + ('I' AND &1F) * &20 + ('T' AND &1F)) DIV &100 ; [ & a m p ; 3 1 ] B I T : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84BC | EQUB (('J' AND &1F) * &400 + ('M' AND &1F) * &20 + ('P' AND &1F)) DIV &100 ; [ & a m p ; 3 2 ] J M P : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84BD | EQUB (('J' AND &1F) * &400 + ('S' AND &1F) * &20 + ('R' AND &1F)) DIV &100 ; [ & a m p ; 3 3 ] J S R : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84BE | EQUB (('L' AND &1F) * &400 + ('D' AND &1F) * &20 + ('X' AND &1F)) DIV &100 ; [ & a m p ; 3 4 ] L D X : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84BF | EQUB (('L' AND &1F) * &400 + ('D' AND &1F) * &20 + ('Y' AND &1F)) DIV &100 ; [ & a m p ; 3 5 ] L D Y : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84C0 | EQUB (('S' AND &1F) * &400 + ('T' AND &1F) * &20 + ('A' AND &1F)) DIV &100 ; [ & a m p ; 3 6 ] S T A : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84C1 | EQUB (('S' AND &1F) * &400 + ('T' AND &1F) * &20 + ('X' AND &1F)) DIV &100 ; [ & a m p ; 3 7 ] S T X : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84C2 | EQUB (('S' AND &1F) * &400 + ('T' AND &1F) * &20 + ('Y' AND &1F)) DIV &100 ; [ & a m p ; 3 8 ] S T Y : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84C3 | EQUB (('O' AND &1F) * &400 + ('P' AND &1F) * &20 + ('T' AND &1F)) DIV &100 ; [ & a m p ; 3 9 ] O P T d i r e c t i v e : p a c k e d - n a m e h i g h b y t e | |||||||||||||||||||||||||||||||||||||||||||||||
| 84C4 | .asm_base_opcode←1Used as index base by← 8620 LDA | |||||||||||||||||||||||||||||||||||||||||||||||
| EQUB &16 ; index &00 base (unused); also asm_mnemonic_hi[&3A] = EQU directive packed-name high byte | ||||||||||||||||||||||||||||||||||||||||||||||||
| 84C5 | EQUB &00 ; [&01] BRK: base opcode &00 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84C6 | EQUB &18 ; [&02] CLC: base opcode &18 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84C7 | EQUB &D8 ; [&03] CLD: base opcode &d8 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84C8 | EQUB &58 ; [&04] CLI: base opcode &58 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84C9 | EQUB &B8 ; [&05] CLV: base opcode &b8 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84CA | EQUB &CA ; [&06] DEX: base opcode &ca | |||||||||||||||||||||||||||||||||||||||||||||||
| 84CB | EQUB &88 ; [&07] DEY: base opcode &88 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84CC | EQUB &E8 ; [&08] INX: base opcode &e8 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84CD | EQUB &C8 ; [&09] INY: base opcode &c8 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84CE | EQUB &EA ; [&0a] NOP: base opcode &ea | |||||||||||||||||||||||||||||||||||||||||||||||
| 84CF | EQUB &48 ; [&0b] PHA: base opcode &48 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84D0 | EQUB &08 ; [&0c] PHP: base opcode &08 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84D1 | EQUB &68 ; [&0d] PLA: base opcode &68 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84D2 | EQUB &28 ; [&0e] PLP: base opcode &28 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84D3 | EQUB &40 ; [&0f] RTI: base opcode &40 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84D4 | EQUB &60 ; [&10] RTS: base opcode &60 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84D5 | EQUB &38 ; [&11] SEC: base opcode &38 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84D6 | EQUB &F8 ; [&12] SED: base opcode &f8 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84D7 | EQUB &78 ; [&13] SEI: base opcode &78 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84D8 | EQUB &AA ; [&14] TAX: base opcode &aa | |||||||||||||||||||||||||||||||||||||||||||||||
| 84D9 | EQUB &A8 ; [&15] TAY: base opcode &a8 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84DA | EQUB &BA ; [&16] TSX: base opcode &ba | |||||||||||||||||||||||||||||||||||||||||||||||
| 84DB | EQUB &8A ; [&17] TXA: base opcode &8a | |||||||||||||||||||||||||||||||||||||||||||||||
| 84DC | EQUB &9A ; [&18] TXS: base opcode &9a | |||||||||||||||||||||||||||||||||||||||||||||||
| 84DD | EQUB &98 ; [&19] TYA: base opcode &98 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84DE | EQUB &90 ; [&1a] BCC: base opcode &90 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84DF | EQUB &B0 ; [&1b] BCS: base opcode &b0 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84E0 | EQUB &F0 ; [&1c] BEQ: base opcode &f0 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84E1 | EQUB &30 ; [&1d] BMI: base opcode &30 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84E2 | EQUB &D0 ; [&1e] BNE: base opcode &d0 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84E3 | EQUB &10 ; [&1f] BPL: base opcode &10 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84E4 | EQUB &50 ; [&20] BVC: base opcode &50 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84E5 | EQUB &70 ; [&21] BVS: base opcode &70 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84E6 | EQUB &21 ; [&22] AND: base opcode &21 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84E7 | EQUB &41 ; [&23] EOR: base opcode &41 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84E8 | EQUB &01 ; [&24] ORA: base opcode &01 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84E9 | EQUB &61 ; [&25] ADC: base opcode &61 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84EA | EQUB &C1 ; [&26] CMP: base opcode &c1 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84EB | EQUB &A1 ; [&27] LDA: base opcode &a1 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84EC | EQUB &E1 ; [&28] SBC: base opcode &e1 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84ED | EQUB &06 ; [&29] ASL: base opcode &06 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84EE | EQUB &46 ; [&2a] LSR: base opcode &46 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84EF | EQUB &26 ; [&2b] ROL: base opcode &26 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84F0 | EQUB &66 ; [&2c] ROR: base opcode &66 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84F1 | EQUB &C6 ; [&2d] DEC: base opcode &c6 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84F2 | EQUB &E6 ; [&2e] INC: base opcode &e6 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84F3 | EQUB &E0 ; [&2f] CPX: base opcode &e0 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84F4 | EQUB &C0 ; [&30] CPY: base opcode &c0 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84F5 | EQUB &20 ; [&31] BIT: base opcode &20 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84F6 | EQUB &4C ; [&32] JMP: base opcode &4c | |||||||||||||||||||||||||||||||||||||||||||||||
| 84F7 | EQUB &20 ; [&33] JSR: base opcode &20 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84F8 | EQUB &A2 ; [&34] LDX: base opcode &a2 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84F9 | EQUB &A0 ; [&35] LDY: base opcode &a0 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84FA | EQUB &81 ; [&36] STA: base opcode &81 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84FB | EQUB &86 ; [&37] STX: base opcode &86 | |||||||||||||||||||||||||||||||||||||||||||||||
| 84FC | EQUB &84 ; [&38] STY: base opcode &84 | |||||||||||||||||||||||||||||||||||||||||||||||
Finish the inline assemblerLeave the inline 6502 assembler (reached at "]"): set the OPT flag to &FF (not assembling) and jump back into the statement interpreter.
|
||||||
| 84FD | .assembler_exit←1← 850D BEQ | |||||
| LDA #&ff ; Leaving the assembler: OPT = BASIC mode | ||||||
| 84FF | STA zp_opt_flag ; store &FF (not assembling) | |||||
| 8501 | JMP next_statement ; resume execution | |||||
Enter the inline assemblerReached by the
|
||||
| 8504 | .asm_enter←1← 8B44 JMP | |||
| LDA #3 ; Entering: default OPT 3 | ||||
| 8506 | STA zp_opt_flag ; store it | |||
| 8508 | .asm_loop←1← 85A2 JMP | |||
| JSR skip_spaces ; Skip spaces | ||||
| 850B | CMP #']' ; ']' end of assembler? | |||
| 850D | BEQ assembler_exit ; yes: exit | |||
| 850F | JSR skip_to_statement_end ; Skip to the statement | |||
| 8512 | DEC zp_text_ptr_off ; back up | |||
| 8514 | JSR asm_parse_mnemonic ; Assemble one instruction | |||
| 8517 | DEC zp_text_ptr_off ; back up | |||
| 8519 | LDA zp_opt_flag ; OPT listing bit set? | |||
| 851B | LSR ; shift the list bit into carry | |||
| 851C | BCC asm_next_statement ; no: skip the listing | |||
| 851E | LDA zp_count ; Column for the source text | |||
| 8520 | ADC #4 ; COUNT + 4, | |||
| 8522 | STA zp_fwb_m2 ; source column (&3F) | |||
| 8524 | LDA zp_general_1 ; Print P% high | |||
| 8526 | JSR print_hex_byte ; as two hex digits | |||
| 8529 | LDA zp_general ; Print P% low | |||
| 852B | JSR print_hex_space ; as two hex digits | |||
| 852E | LDX #&fc ; Byte count | |||
| 8530 | LDY zp_fileblk ; String (EQUS) length? | |||
| 8532 | BPL asm_list_count ; not EQUS: use the byte count, | |||
| 8534 | LDY zp_strbuf_len ; EQUS: use the string length | |||
| 8536 | .asm_list_count←1← 8532 BPL | |||
| STY zp_general_1 ; Bytes to list | ||||
| 8538 | BEQ asm_list_pad_loop ; none | |||
| 853A | LDY #0 ; From byte 0 | |||
| 853C | .asm_list_byte_loop←1← 8554 BNE | |||
| INX ; Count printed on this line | ||||
| 853D | BNE asm_list_byte ; still on the line | |||
| 853F | JSR emit_newline ; Newline and indent for a continuation | |||
| 8542 | LDX zp_fwb_m2 ; indent to the hex column | |||
| 8544 | .asm_list_indent_loop←1← 8548 BNE | |||
| JSR print_space ; Print a space | ||||
| 8547 | DEX ; one fewer space | |||
| 8548 | BNE asm_list_indent_loop ; loop | |||
| 854A | LDX #&fd ; reset the per-line count | |||
| 854C | .asm_list_byte←1← 853D BNE | |||
| LDA (zp_fileblk_1),y ; Assembled byte | ||||
| 854E | JSR print_hex_space ; print it as hex | |||
| 8551 | INY ; next | |||
| 8552 | DEC zp_general_1 ; all bytes? | |||
| 8554 | BNE asm_list_byte_loop ; no: continue | |||
| 8556 | .asm_list_pad_loop←2← 8538 BEQ← 8562 JMP | |||
| INX ; Pad to the source column | ||||
| 8557 | BPL asm_list_source ; done | |||
| 8559 | JSR print_space ; print a space | |||
| 855C | JSR print_char ; two more spaces, | |||
| 855F | JSR print_char ; (continued) | |||
| 8562 | JMP asm_list_pad_loop ; loop | |||
| 8565 | .asm_list_source←1← 8557 BPL | |||
| LDY #0 ; Print the source: from offset 0 | ||||
| 8567 | .asm_list_src_loop←1← 8575 BNE | |||
| LDA (zp_text_ptr),y ; Next character | ||||
| 8569 | CMP #':' ; ':' end of statement? | |||
| 856B | BEQ asm_list_src_end ; yes | |||
| 856D | CMP #&0d ; end of line? | |||
| 856F | BEQ asm_list_newline ; yes | |||
| 8571 | .asm_list_src_print←1← 8579 BCC | |||
| JSR print_token ; de-tokenise and print | ||||
| 8574 | INY ; next | |||
| 8575 | BNE asm_list_src_loop ; loop | |||
| 8577 | .asm_list_src_end←1← 856B BEQ | |||
| CPY zp_text_ptr_off ; reached the statement end? | ||||
| 8579 | BCC asm_list_src_print ; no: continue | |||
| 857B | .asm_list_newline←1← 856F BEQ | |||
| JSR emit_newline ; Newline | ||||
| 857E | .asm_next_statement←1← 851C BCC | |||
| LDY zp_text_ptr_off ; Advance to the next statement | ||||
| 8580 | DEY ; back up (loop pre-increments) | |||
| 8581 | .asm_scan_end_loop←1← 858A BNE | |||
| INY ; scan for the end | ||||
| 8582 | LDA (zp_text_ptr),y ; read a character | |||
| 8584 | CMP #':' ; ':'? | |||
| 8586 | BEQ asm_stmt_end ; yes | |||
| 8588 | CMP #&0d ; end of line? | |||
| 858A | BNE asm_scan_end_loop ; no: continue | |||
| 858C | .asm_stmt_end←1← 8586 BEQ | |||
| JSR cend_back ; Check Escape and advance | ||||
| 858F | DEY ; Re-read the terminator | |||
| 8590 | LDA (zp_text_ptr),y ; read it | |||
| 8592 | CMP #':' ; ':'? | |||
| 8594 | BEQ asm_continue ; yes: same line | |||
| 8596 | LDA zp_text_ptr_1 ; at end of program memory? | |||
| 8598 | CMP #7 ; page &07 (immediate buffer)? | |||
| 859A | BNE asm_next_line ; no: next line | |||
| 859C | JMP immediate_loop ; yes: immediate mode | |||
| 859F | .asm_next_line←1← 859A BNE | |||
| JSR step_to_next_line ; Move to the next line | ||||
| 85A2 | .asm_continue←1← 8594 BEQ | |||
| JMP asm_loop ; continue assembling | ||||
| 85A5 | .asm_define_label←1← 85D1 BEQ | |||
| JSR parse_lvalue ; Label: parse the variable | ||||
| 85A8 | BEQ asm_mistake ; end: error | |||
| 85AA | BCS asm_mistake ; indirection: error | |||
| 85AC | JSR stack_integer ; stack the address | |||
| 85AF | JSR factor_pcounter ; value = P% | |||
| 85B2 | STA zp_var_type ; integer type | |||
| 85B4 | JSR assign_number ; assign P% to the label | |||
| 85B7 | JSR eeti_sync ; sync the pointer | |||
| fall through ↓ | ||||
Parse and compact an assembler mnemonicSkip to the mnemonic at PtrA, handling end-of-statement and labels, then pack its three letters (5 bits each) into &3D/&3E for the opcode-table lookup.
|
|||||||||||
| 85BA | .asm_parse_mnemonic←1← 8514 JSR | ||||||||||
| LDX #3 ; Three characters | |||||||||||
| 85BC | JSR skip_spaces ; Skip spaces | ||||||||||
| 85BF | LDY #0 ; Clear the compacted value | ||||||||||
| 85C1 | STY zp_fwb_exp ; low byte (&3D) | ||||||||||
| 85C3 | CMP #':' ; ':' end of statement? | ||||||||||
| 85C5 | BEQ asm_emit ; yes: no instruction | ||||||||||
| 85C7 | CMP #&0d ; end of line? | ||||||||||
| 85C9 | BEQ asm_emit ; yes | ||||||||||
| 85CB | CMP #'\' ; comment? | ||||||||||
| 85CD | BEQ asm_emit ; yes | ||||||||||
| 85CF | CMP #'.' ; '.' label? | ||||||||||
| 85D1 | BEQ asm_define_label ; yes: define it | ||||||||||
| 85D3 | DEC zp_text_ptr_off ; back up | ||||||||||
| 85D5 | .asm_mn_char_loop←1← 85EF BNE | ||||||||||
| LDY zp_text_ptr_off ; Next character | |||||||||||
| 85D7 | INC zp_text_ptr_off ; advance the offset, | ||||||||||
| 85D9 | LDA (zp_text_ptr),y ; read it | ||||||||||
| 85DB | BMI asm_logic_mnemonic ; token: tokenised AND/EOR/OR | ||||||||||
| 85DD | CMP #' ' ; space? | ||||||||||
| 85DF | BEQ asm_mn_search ; skip it | ||||||||||
| 85E1 | LDY #5 ; Compact the character (5 bits) | ||||||||||
| 85E3 | ASL ; shift the char up by 3, | ||||||||||
| 85E4 | ASL ; (continued) | ||||||||||
| 85E5 | ASL ; (continued) | ||||||||||
| 85E6 | .asm_mn_pack_loop←1← 85EC BNE | ||||||||||
| ASL ; shift into the value | |||||||||||
| 85E7 | ROL zp_fwb_exp ; carry into &3D, | ||||||||||
| 85E9 | ROL zp_fwb_m1 ; and &3E, | ||||||||||
| 85EB | DEY ; next bit, | ||||||||||
| 85EC | BNE asm_mn_pack_loop ; all 5 bits | ||||||||||
| 85EE | DEX ; next character | ||||||||||
| 85EF | BNE asm_mn_char_loop ; loop for three | ||||||||||
| 85F1 | .asm_mn_search←1← 85DF BEQ | ||||||||||
| LDX #&3a ; Point to the end of the opcode table | |||||||||||
| 85F3 | LDA zp_fwb_exp ; Compacted mnemonic low byte | ||||||||||
| 85F5 | .asm_mn_search_loop←1← 8602 BNE | ||||||||||
| CMP asm_mnemonic_lo,x ; Compare the low half | |||||||||||
| 85F8 | BNE asm_mn_search_next ; no match: next entry | ||||||||||
| 85FA | LDY asm_mnemonic_hi,x ; High half | ||||||||||
| 85FD | CPY zp_fwb_m1 ; match the high half? | ||||||||||
| 85FF | BEQ asm_got_opcode ; matched | ||||||||||
| 8601 | .asm_mn_search_next←1← 85F8 BNE | ||||||||||
| DEX ; Next entry | |||||||||||
| 8602 | BNE asm_mn_search_loop ; loop | ||||||||||
| 8604 | .asm_mistake←4← 85A8 BEQ← 85AA BCS← 8615 BNE← 861E BNE | ||||||||||
| JMP syntax_error ; not matched: Mistake | |||||||||||
| 8607 | .asm_logic_mnemonic←1← 85DB BMI | ||||||||||
| LDX #&22 ; opcode index for AND | |||||||||||
| 8609 | CMP #&80 ; tokenised AND? | ||||||||||
| 860B | BEQ asm_got_opcode ; yes | ||||||||||
| 860D | INX ; EOR index | ||||||||||
| 860E | CMP #&82 ; tokenised EOR? | ||||||||||
| 8610 | BEQ asm_got_opcode ; yes | ||||||||||
| 8612 | INX ; ORA index | ||||||||||
| 8613 | CMP #&84 ; tokenised OR? | ||||||||||
| 8615 | BNE asm_mistake ; no: Mistake | ||||||||||
| 8617 | INC zp_text_ptr_off ; step past, expect 'A' | ||||||||||
| 8619 | INY ; advance, | ||||||||||
| 861A | LDA (zp_text_ptr),y ; read the next character | ||||||||||
| 861C | CMP #'A' ; 'A'? | ||||||||||
| 861E | BNE asm_mistake ; no: Mistake | ||||||||||
| 8620 | .asm_got_opcode←3← 85FF BEQ← 860B BEQ← 8610 BEQ | ||||||||||
| LDA asm_base_opcode,x ; Base opcode from the table | |||||||||||
| 8623 | STA zp_asm_opcode ; Save it | ||||||||||
| 8625 | LDY #1 ; Assume a one-byte instruction | ||||||||||
| 8627 | CPX #&1a ; index &1A+ takes an operand? | ||||||||||
| 8629 | BCS asm_operand ; yes: parse the addressing mode | ||||||||||
| fall through ↓ | |||||||||||
Emit assembled bytes to P%/O%The inline assembler's byte-emit routine. Copies the assembled bytes to the destination given by P% (resint_p, &0440), or by O% (resint_o, &043C) when OPT selects offset assembly (OPT >= 4), then advances P% (and O% for offset assembly) past them. Y is the signed byte count: 0 emits nothing; a positive count stores that many opcode/operand bytes from the assembly buffer at zp_asm_opcode (&29); a negative count is an EQUS, storing zp_strbuf_len (&36) bytes taken from string_work (&0600).
|
|||||||||||||||||
| 862B | .asm_emit←7← 85C5 BEQ← 85C9 BEQ← 85CD BEQ← 86AA JMP← 879C JMP← 881E JMP← 8864 JMP | ||||||||||||||||
| LDA resint_p ; P% low -> destination | |||||||||||||||||
| 862E | STA zp_general ; to &37 | ||||||||||||||||
| 8630 | STY zp_fileblk ; Save the byte count | ||||||||||||||||
| 8632 | LDX zp_opt_flag ; OPT setting | ||||||||||||||||
| 8634 | CPX #4 ; offset assembly (OPT >= 4)? | ||||||||||||||||
| 8636 | LDX resint_p_1 ; P% high | ||||||||||||||||
| 8639 | STX zp_general_1 ; to &38 | ||||||||||||||||
| 863B | BCC asm_emit_dest ; no offset: assemble at P% | ||||||||||||||||
| 863D | LDA resint_o ; offset: assemble at O% instead | ||||||||||||||||
| 8640 | LDX resint_o_1 ; O% high | ||||||||||||||||
| 8643 | .asm_emit_dest←1← 863B BCC | ||||||||||||||||
| STA zp_fileblk_1 ; Store the destination pointer | |||||||||||||||||
| 8645 | STX zp_fwb_sign ; high byte (&3B) | ||||||||||||||||
| 8647 | TYA ; Any bytes to store? | ||||||||||||||||
| 8648 | BEQ return_1 ; none: done | ||||||||||||||||
| 864A | BPL asm_emit_loop ; positive count: store opcode bytes | ||||||||||||||||
| 864C | LDY zp_strbuf_len ; EQUS: length from the string buffer | ||||||||||||||||
| 864E | BEQ return_1 ; empty: done | ||||||||||||||||
| 8650 | .asm_emit_loop←2← 864A BPL← 8670 BNE | ||||||||||||||||
| DEY ; Next byte index | |||||||||||||||||
| 8651 | LDA zp_asm_opcode,y ; Opcode/operand byte | ||||||||||||||||
| 8654 | BIT zp_fileblk ; storing string (EQUS) bytes? | ||||||||||||||||
| 8656 | BPL asm_emit_store ; no: store the opcode byte | ||||||||||||||||
| 8658 | LDA string_work,y ; yes: take it from the string buffer | ||||||||||||||||
| 865B | .asm_emit_store←1← 8656 BPL | ||||||||||||||||
| STA (zp_fileblk_1),y ; Store the byte at the destination | |||||||||||||||||
| 865D | INC resint_p ; Advance P% | ||||||||||||||||
| 8660 | BNE asm_emit_advance ; no carry, | ||||||||||||||||
| 8662 | INC resint_p_1 ; carry into P% high | ||||||||||||||||
| 8665 | .asm_emit_advance←1← 8660 BNE | ||||||||||||||||
| BCC asm_emit_more ; offset assembly? | |||||||||||||||||
| 8667 | INC resint_o ; yes: advance O% too | ||||||||||||||||
| 866A | BNE asm_emit_more ; no carry, | ||||||||||||||||
| 866C | INC resint_o_1 ; carry into O% high | ||||||||||||||||
| 866F | .asm_emit_more←2← 8665 BCC← 866A BNE | ||||||||||||||||
| TYA ; More bytes? | |||||||||||||||||
| 8670 | BNE asm_emit_loop ; loop | ||||||||||||||||
| 8672 | .return_1←2← 8648 BEQ← 864E BEQ | ||||||||||||||||
| RTS ; Return | |||||||||||||||||
| 8673 | .asm_operand←1← 8629 BCS | ||||||||||||||||
| CPX #&22 ; index &22+ is not a branch? | |||||||||||||||||
| 8675 | BCS asm_mode_imm ; yes: other operand forms | ||||||||||||||||
| 8677 | JSR eval_expr_to_integer ; Evaluate the target address | ||||||||||||||||
| 867A | CLC ; Offset = target - (P% + 2) | ||||||||||||||||
| 867B | LDA zp_iwa ; target low, | ||||||||||||||||
| 867D | SBC resint_p ; minus P% low (- 1), | ||||||||||||||||
| 8680 | TAY ; offset low in Y, | ||||||||||||||||
| 8681 | LDA zp_iwa_1 ; target high, | ||||||||||||||||
| 8683 | SBC resint_p_1 ; minus P% high, | ||||||||||||||||
| 8686 | CPY #1 ; offset >= 1?, | ||||||||||||||||
| 8688 | DEY ; offset - 1 (for PC+2), | ||||||||||||||||
| 8689 | SBC #0 ; borrow into the high byte | ||||||||||||||||
| 868B | BEQ asm_branch_back ; in forward range? | ||||||||||||||||
| 868D | CMP #&ff ; in backward range? | ||||||||||||||||
| 868F | BEQ asm_branch_fwd ; high byte &FF: in range | ||||||||||||||||
| 8691 | .asm_branch_range_err←2← 86B0 BPL← 86B5 BMI | ||||||||||||||||
| LDA zp_opt_flag ; OPT setting errors enabled? | |||||||||||||||||
| 8693 | LSR ; errors enabled (bit 1)? | ||||||||||||||||
| 8694 | BEQ asm_branch_ok ; no: ignore the range error | ||||||||||||||||
| 8696 | BRK ; Out of range error | ||||||||||||||||
| 8697 | EQUB &01 | ||||||||||||||||
| 8698 | EQUS "Out of range" | ||||||||||||||||
| 86A4 | EQUB &00 | ||||||||||||||||
| 86A5 | .asm_branch_ok←1← 8694 BEQ | ||||||||||||||||
| TAY ; Use the offset byte | |||||||||||||||||
| 86A6 | .asm_set_operand←2← 86AE BMI← 86B3 BPL | ||||||||||||||||
| STY zp_iwa ; as the operand | |||||||||||||||||
| 86A8 | .asm_two_byte←2← 86CA BEQ← 873C JMP | ||||||||||||||||
| LDY #2 ; Two-byte instruction | |||||||||||||||||
| 86AA | JMP asm_emit ; store it | ||||||||||||||||
| 86AD | .asm_branch_fwd←1← 868F BEQ | ||||||||||||||||
| TYA ; forward: check the high byte | |||||||||||||||||
| 86AE | BMI asm_set_operand ; in range | ||||||||||||||||
| 86B0 | BPL asm_branch_range_err ; out of range | ||||||||||||||||
| 86B2 | .asm_branch_back←1← 868B BEQ | ||||||||||||||||
| TYA ; backward: check the high byte | |||||||||||||||||
| 86B3 | BPL asm_set_operand ; in range | ||||||||||||||||
| 86B5 | BMI asm_branch_range_err ; out of range | ||||||||||||||||
| 86B7 | .asm_mode_imm←1← 8675 BCS | ||||||||||||||||
| CPX #&29 ; index &29+ : not immediate? | |||||||||||||||||
| 86B9 | BCS asm_mode_indirect ; yes: indexed/absolute modes | ||||||||||||||||
| 86BB | JSR skip_spaces ; Skip spaces | ||||||||||||||||
| 86BE | CMP #'#' ; '#' immediate prefix? | ||||||||||||||||
| 86C0 | BNE asm_try_indirect ; no: absolute | ||||||||||||||||
| 86C2 | JSR asm_opcode_add8 ; Immediate mode: adjust the opcode | ||||||||||||||||
| 86C5 | .asm_imm_eval←2← 877D JMP← 87C9 JMP | ||||||||||||||||
| JSR eval_expr_to_integer ; Evaluate the immediate value | |||||||||||||||||
| 86C8 | .asm_imm_byte←2← 86F9 BEQ← 870B BEQ | ||||||||||||||||
| LDA zp_iwa_1 ; high byte zero (fits in a byte)? | |||||||||||||||||
| 86CA | BEQ asm_two_byte ; yes: two-byte instruction | ||||||||||||||||
| 86CC | .asm_byte_error←1← 880D JMP | ||||||||||||||||
| BRK ; Byte error (value > 255) | |||||||||||||||||
| 86CD | EQUB &02 | ||||||||||||||||
| 86CE | EQUS "Byte" | ||||||||||||||||
| 86D2 | EQUB &00 | ||||||||||||||||
| 86D3 | .asm_mode_indirect←1← 86B9 BCS | ||||||||||||||||
| CPX #&36 ; index &36 : the (zp),Y / (zp,X) group? | |||||||||||||||||
| 86D5 | BNE asm_mode_class2 ; no: absolute/indexed group | ||||||||||||||||
| 86D7 | JSR skip_spaces ; Skip spaces | ||||||||||||||||
| 86DA | .asm_try_indirect←1← 86C0 BNE | ||||||||||||||||
| CMP #'(' ; '(' opening an indirect mode? | |||||||||||||||||
| 86DC | BNE asm_abs_from_paren ; no: absolute | ||||||||||||||||
| 86DE | JSR eval_expr_to_integer ; Evaluate the zero-page address | ||||||||||||||||
| 86E1 | JSR skip_spaces ; Skip spaces | ||||||||||||||||
| 86E4 | CMP #')' ; ')' -> (zp),Y form | ||||||||||||||||
| 86E6 | BNE asm_indirect_zpx ; no: try (zp,X) | ||||||||||||||||
| 86E8 | JSR skip_spaces ; Skip spaces | ||||||||||||||||
| 86EB | CMP #',' ; ','? | ||||||||||||||||
| 86ED | BNE asm_index_error ; no: Index error | ||||||||||||||||
| 86EF | JSR asm_opcode_add16 ; adjust the opcode for (zp),Y | ||||||||||||||||
| 86F2 | JSR skip_spaces ; Skip spaces | ||||||||||||||||
| 86F5 | CMP #'Y' ; 'Y'? | ||||||||||||||||
| 86F7 | BNE asm_index_error ; no: Index error | ||||||||||||||||
| 86F9 | BEQ asm_imm_byte ; process as a two-byte instruction | ||||||||||||||||
| 86FB | .asm_indirect_zpx←1← 86E6 BNE | ||||||||||||||||
| CMP #',' ; ','? | |||||||||||||||||
| 86FD | BNE asm_index_error ; no: Index error | ||||||||||||||||
| 86FF | JSR skip_spaces ; Skip spaces | ||||||||||||||||
| 8702 | CMP #'X' ; 'X'? | ||||||||||||||||
| 8704 | BNE asm_index_error ; no: Index error | ||||||||||||||||
| 8706 | JSR skip_spaces ; Skip spaces | ||||||||||||||||
| 8709 | CMP #')' ; ')'? | ||||||||||||||||
| 870B | BEQ asm_imm_byte ; yes: process | ||||||||||||||||
| 870D | .asm_index_error←8← 86ED BNE← 86F7 BNE← 86FD BNE← 8704 BNE← 872D BNE← 8764 JMP← 87AF JMP← 87ED JMP | ||||||||||||||||
| BRK ; Index error | |||||||||||||||||
| 870E | EQUB &03 | ||||||||||||||||
| 870F | EQUS "Index" | ||||||||||||||||
| 8714 | EQUB &00 | ||||||||||||||||
| 8715 | .asm_abs_from_paren←1← 86DC BNE | ||||||||||||||||
| DEC zp_text_ptr_off ; Back up over the "(" | |||||||||||||||||
| 8717 | JSR eval_expr_to_integer ; Evaluate the address | ||||||||||||||||
| 871A | JSR skip_spaces ; Skip spaces | ||||||||||||||||
| 871D | CMP #',' ; ','? | ||||||||||||||||
| 871F | BNE asm_absolute ; no: process as absolute | ||||||||||||||||
| 8721 | JSR asm_opcode_add16 ; adjust the opcode for absolute,X/,Y | ||||||||||||||||
| 8724 | JSR skip_spaces ; Skip spaces | ||||||||||||||||
| 8727 | CMP #'X' ; 'X'? | ||||||||||||||||
| 8729 | BEQ asm_absolute ; yes: abs,X | ||||||||||||||||
| 872B | CMP #'Y' ; 'Y'? | ||||||||||||||||
| 872D | BNE asm_index_error ; no: Index error | ||||||||||||||||
| 872F | .asm_indexed_adjust←1← 873A BNE | ||||||||||||||||
| JSR asm_opcode_add8 ; Adjust the opcode for the indexed form | |||||||||||||||||
| 8732 | JMP asm_three_byte ; process the absolute operand | ||||||||||||||||
Assemble a zero-page or absolute operandAdjust the opcode being built for absolute addressing (asm_opcode_add4), then fall into asm_zp_or_abs, which tests the high byte of the evaluated operand address in zp_iwa: high byte zero emits the two-byte zero-page form (asm_two_byte), otherwise the three-byte absolute form (asm_indexed_adjust). The inline assembler's addressing-mode handler for absolute / zero-page operands.
|
|||||||||
| 8735 | .asm_absolute←5← 871F BNE← 8729 BEQ← 8785 JMP← 87DB JMP← 87EA JMP | ||||||||
| JSR asm_opcode_add4 ; Adjust the opcode for absolute mode | |||||||||
| 8738 | .asm_zp_or_abs←3← 8758 BNE← 8762 BEQ← 8810 JMP | ||||||||
| LDA zp_iwa_1 ; address fits in zero page (high byte 0)? | |||||||||
| 873A | BNE asm_indexed_adjust ; no: assemble as absolute (three bytes) | ||||||||
| 873C | JMP asm_two_byte ; yes: assemble as two bytes | ||||||||
| 873F | .asm_mode_class2←1← 86D5 BNE | ||||||||
| CPX #&2f ; index &2F+ : a different operand class? | |||||||||
| 8741 | BCS asm_mode_class3 ; yes | ||||||||
| 8743 | CPX #&2d ; index &2D+ (accumulator-or-absolute)? | ||||||||
| 8745 | BCS asm_acc_or_abs ; yes | ||||||||
| 8747 | JSR skip_spaces ; Skip spaces | ||||||||
| 874A | CMP #'A' ; 'A' (accumulator)? | ||||||||
| 874C | BEQ asm_accumulator ; yes | ||||||||
| 874E | DEC zp_text_ptr_off ; Back up a character | ||||||||
| 8750 | .asm_acc_or_abs←1← 8745 BCS | ||||||||
| JSR eval_expr_to_integer ; Evaluate the address | |||||||||
| 8753 | JSR skip_spaces ; Skip spaces | ||||||||
| 8756 | CMP #',' ; ','? | ||||||||
| 8758 | BNE asm_zp_or_abs ; no: process | ||||||||
| 875A | JSR asm_opcode_add16 ; adjust the opcode for indexed mode | ||||||||
| 875D | JSR skip_spaces ; Skip spaces | ||||||||
| 8760 | CMP #'X' ; 'X'? | ||||||||
| 8762 | BEQ asm_zp_or_abs ; yes: address,X | ||||||||
| 8764 | JMP asm_index_error ; Index error | ||||||||
| 8767 | .asm_accumulator←1← 874C BEQ | ||||||||
| JSR asm_opcode_add4 ; Accumulator form: adjust the opcode | |||||||||
| 876A | LDY #1 ; one byte | ||||||||
| 876C | BNE asm_three_emit ; store it | ||||||||
| 876E | .asm_mode_class3←1← 8741 BCS | ||||||||
| CPX #&32 ; index &32+ : implied/branch class? | |||||||||
| 8770 | BCS asm_mode_noop ; yes | ||||||||
| 8772 | CPX #&31 ; index &31 (immediate-only)? | ||||||||
| 8774 | BEQ asm_imm1_eval ; yes | ||||||||
| 8776 | JSR skip_spaces ; Skip spaces | ||||||||
| 8779 | CMP #'#' ; '#' immediate? | ||||||||
| 877B | BNE asm_imm1_backup ; no: address | ||||||||
| 877D | JMP asm_imm_eval ; immediate | ||||||||
| 8780 | .asm_imm1_backup←1← 877B BNE | ||||||||
| DEC zp_text_ptr_off ; Back up a character | |||||||||
| 8782 | .asm_imm1_eval←1← 8774 BEQ | ||||||||
| JSR eval_expr_to_integer ; Evaluate the value | |||||||||
| 8785 | JMP asm_absolute ; assemble as absolute | ||||||||
| 8788 | .asm_mode_noop←1← 8770 BCS | ||||||||
| CPX #&33 ; index &33 (no operand)? | |||||||||
| 878A | BEQ asm_addr_eval ; yes | ||||||||
| 878C | BCS asm_mode_equ ; index &34+ : other forms | ||||||||
| 878E | JSR skip_spaces ; Skip spaces | ||||||||
| 8791 | CMP #'(' ; '(' indirect? | ||||||||
| 8793 | BEQ asm_jmp_indirect ; yes | ||||||||
| 8795 | DEC zp_text_ptr_off ; Back up a character | ||||||||
| 8797 | .asm_addr_eval←1← 878A BEQ | ||||||||
| JSR eval_expr_to_integer ; Evaluate the address | |||||||||
| 879A | .asm_three_byte←2← 8732 JMP← 87AD BEQ | ||||||||
| LDY #3 ; Three-byte instruction | |||||||||
| 879C | .asm_three_emit←1← 876C BNE | ||||||||
| JMP asm_emit ; store it | |||||||||
| 879F | .asm_jmp_indirect←1← 8793 BEQ | ||||||||
| JSR asm_opcode_add16 ; Indirect: adjust the opcode | |||||||||
| 87A2 | JSR asm_opcode_add16 ; (continued) | ||||||||
| 87A5 | JSR eval_expr_to_integer ; evaluate the address | ||||||||
| 87A8 | JSR skip_spaces ; Skip spaces | ||||||||
| 87AB | CMP #')' ; ')' to close? | ||||||||
| 87AD | BEQ asm_three_byte ; yes: three-byte instruction | ||||||||
| 87AF | JMP asm_index_error ; Index error | ||||||||
| 87B2 | .asm_mode_equ←1← 878C BCS | ||||||||
| CPX #&39 ; index &39+ : EQU directives | |||||||||
| 87B4 | BCS asm_opt_directive ; yes | ||||||||
| 87B6 | LDA zp_fwb_exp ; Register letter from the mnemonic | ||||||||
| 87B8 | EOR #1 ; toggle bit 0 | ||||||||
| 87BA | AND #&1f ; save it index &37+ (two-register form)? | ||||||||
| 87BC | PHA ; Save the register | ||||||||
| 87BD | CPX #&37 ; yes | ||||||||
| 87BF | BCS asm_equ_eval ; two-register form? | ||||||||
| 87C1 | JSR skip_spaces ; '#' immediate? | ||||||||
| 87C4 | CMP #'#' ; no: absolute | ||||||||
| 87C6 | BNE asm_equ_backup ; discard the saved register, do immediate | ||||||||
| 87C8 | PLA ; discard the register | ||||||||
| 87C9 | JMP asm_imm_eval ; do immediate | ||||||||
| 87CC | .asm_equ_backup←1← 87C6 BNE | ||||||||
| DEC zp_text_ptr_off ; Back up a character | |||||||||
| 87CE | JSR eval_expr_to_integer ; Evaluate the address | ||||||||
| 87D1 | PLA ; recover the register letter | ||||||||
| 87D2 | STA zp_general ; into &37 | ||||||||
| 87D4 | JSR skip_spaces ; ',' index register? | ||||||||
| 87D7 | CMP #',' ; yes | ||||||||
| 87D9 | BEQ asm_equ_index ; no: assemble as absolute | ||||||||
| 87DB | JMP asm_absolute ; process as absolute | ||||||||
| 87DE | .asm_equ_index←1← 87D9 BEQ | ||||||||
| JSR skip_spaces ; Index register letter | |||||||||
| 87E1 | AND #&1f ; matches the expected register? | ||||||||
| 87E3 | CMP zp_general ; no: Index error | ||||||||
| 87E5 | BNE asm_equ_index_err ; register mismatch? | ||||||||
| 87E7 | JSR asm_opcode_add16 ; adjust the opcode for the indexed form | ||||||||
| 87EA | JMP asm_absolute ; assemble as absolute | ||||||||
| 87ED | .asm_equ_index_err←2← 87E5 BNE← 8804 BNE | ||||||||
| JMP asm_index_error ; Index error | |||||||||
| 87F0 | .asm_equ_eval←1← 87BF BCS | ||||||||
| JSR eval_expr_to_integer ; Evaluate the address | |||||||||
| 87F3 | PLA ; recover the register letter | ||||||||
| 87F4 | STA zp_general ; into &37 | ||||||||
| 87F6 | JSR skip_spaces ; ',' index register? | ||||||||
| 87F9 | CMP #',' ; no: single operand | ||||||||
| 87FB | BNE asm_force_zp ; Index register letter | ||||||||
| 87FD | JSR skip_spaces ; read the index register letter | ||||||||
| 8800 | AND #&1f ; matches? | ||||||||
| 8802 | CMP zp_general ; no: Index error | ||||||||
| 8804 | BNE asm_equ_index_err ; adjust the opcode for indexed mode | ||||||||
| 8806 | JSR asm_opcode_add16 ; high byte zero? | ||||||||
| 8809 | LDA zp_iwa_1 ; yes: continue | ||||||||
| 880B | BEQ asm_force_zp ; Byte error (value > 255) | ||||||||
| 880D | JMP asm_byte_error ; Byte error | ||||||||
| 8810 | .asm_force_zp←2← 87FB BNE← 880B BEQ | ||||||||
| JMP asm_zp_or_abs ; Assemble as zero-page | |||||||||
| 8813 | .asm_opt_directive←1← 87B4 BCS | ||||||||
| BNE equb_directive ; index &39 (OPT)? | |||||||||
| 8815 | JSR eval_expr_to_integer ; no: EQU directives OPT: evaluate the new setting | ||||||||
| 8818 | LDA zp_iwa ; OPT value | ||||||||
| 881A | STA zp_opt_flag ; store it as the OPT flag | ||||||||
| 881C | LDY #0 ; no bytes to assemble | ||||||||
| 881E | JMP asm_emit ; finish | ||||||||
Evaluate an integer expressionEvaluate the expression at the text pointer (eval_expr) and coerce the result to an integer (coerce_to_integer), then copy the secondary text offset back to the primary pointer. Used wherever a statement needs an integer argument.
|
||||
| 8821 | .eval_expr_to_integer←22← 8677 JSR← 86C5 JSR← 86DE JSR← 8717 JSR← 8750 JSR← 8782 JSR← 8797 JSR← 87A5 JSR← 87CE JSR← 87F0 JSR← 8815 JSR← 885A JSR← 9188 JSR← 92A2 JSR← 937A JSR← 9391 JSR← 939D JSR← 93F1 JSR← 9440 JSR← B44C JSR← B472 JSR← B4A0 JSR | |||
| JSR eval_expr ; Evaluate the expression | ||||
| 8824 | JSR coerce_to_integer ; coerce to an integer | |||
| 8827 | .eeti_sync←3← 85B7 JSR← 8875 JSR← 9121 JSR | |||
| LDY zp_text_ptr2_off ; Sync the primary text offset | ||||
| 8829 | STY zp_text_ptr_off ; copy PtrB offset to PtrA | |||
| 882B | RTS ; Return | |||
Advance the opcode by four addressing-mode columns (+16)Add 16 to the base opcode in zp_asm_opcode (via +8, +4, +4) to select an addressing mode four columns along.
|
|||||||||||||
| 882C | .asm_opcode_add16←7← 86EF JSR← 8721 JSR← 875A JSR← 879F JSR← 87A2 JSR← 87E7 JSR← 8806 JSR | ||||||||||||
| JSR asm_opcode_add8 ; add 8 then fall through (+16 total) | |||||||||||||
| fall through ↓ | |||||||||||||
Advance the opcode by two addressing-mode columns (+8)Add 8 to the base opcode in zp_asm_opcode (via +4, +4) to select an addressing mode two columns along.
|
|||||||||||||
| 882F | .asm_opcode_add8←3← 86C2 JSR← 872F JSR← 882C JSR | ||||||||||||
| JSR asm_opcode_add4 ; add 4 then fall through (+8 total) | |||||||||||||
| fall through ↓ | |||||||||||||
Step the opcode to the next addressing-mode column (+4)Add 4 to the base opcode in &29 to select the next 6502 addressing-mode encoding.
|
|||||||||||||
| 8832 | .asm_opcode_add4←3← 8735 JSR← 8767 JSR← 882F JSR | ||||||||||||
| LDA zp_asm_opcode ; Opcode += 4 (next addressing-mode column) | |||||||||||||
| 8834 | CLC ; clear carry, | ||||||||||||
| 8835 | ADC #4 ; add 4 (next mode column), | ||||||||||||
| 8837 | STA zp_asm_opcode ; store the opcode | ||||||||||||
| 8839 | RTS ; Return | ||||||||||||
| 883A | .equb_directive←1← 8813 BNE | ||||||||||||
| LDX #1 ; Assume one byte (EQUB) | |||||||||||||
| 883C | LDY zp_text_ptr_off ; Next character of the directive | ||||||||||||
| 883E | INC zp_text_ptr_off ; consume that character | ||||||||||||
| 8840 | LDA (zp_text_ptr),y ; 'B' (EQUB)? | ||||||||||||
| 8842 | CMP #'B' ; yes | ||||||||||||
| 8844 | BEQ equb_save_count ; two bytes (EQUW) 'W' (EQUW)? | ||||||||||||
| 8846 | INX ; two bytes | ||||||||||||
| 8847 | CMP #'W' ; yes | ||||||||||||
| 8849 | BEQ equb_save_count ; four bytes (EQUD) | ||||||||||||
| 884B | LDX #4 ; 'D' (EQUD)? | ||||||||||||
| 884D | CMP #'D' ; yes | ||||||||||||
| 884F | BEQ equb_save_count ; 'S' (EQUS)? | ||||||||||||
| 8851 | CMP #'S' ; yes | ||||||||||||
| 8853 | BEQ equs_save_opt ; none: Mistake (syntax error) | ||||||||||||
| 8855 | JMP syntax_error ; Mistake (syntax) error | ||||||||||||
| 8858 | .equb_save_count←3← 8844 BEQ← 8849 BEQ← 884F BEQ | ||||||||||||
| TXA ; Save the byte count | |||||||||||||
| 8859 | PHA ; push it | ||||||||||||
| 885A | JSR eval_expr_to_integer ; Evaluate the value | ||||||||||||
| 885D | LDX #&29 ; Store it into the opcode bytes | ||||||||||||
| 885F | JSR iwa_store_zp ; into &29 onward | ||||||||||||
| 8862 | PLA ; recover the byte count | ||||||||||||
| 8863 | TAY ; into Y | ||||||||||||
| 8864 | .equb_emit_loop←1← 887A BNE | ||||||||||||
| JMP asm_emit ; Assemble the bytes | |||||||||||||
| 8867 | .equs_type_error←1← 8870 BNE | ||||||||||||
| JMP err_type_mismatch ; String expected: Type mismatch | |||||||||||||
| 886A | .equs_save_opt←1← 8853 BEQ | ||||||||||||
| LDA zp_opt_flag ; EQUS: save the OPT flag | |||||||||||||
| 886C | PHA ; push the OPT flag | ||||||||||||
| 886D | JSR eval_expr ; evaluate the string expression | ||||||||||||
| 8870 | BNE equs_type_error ; not a string: Type mismatch | ||||||||||||
| 8872 | PLA ; restore the OPT flag | ||||||||||||
| 8873 | STA zp_opt_flag ; store it back | ||||||||||||
| 8875 | JSR eeti_sync ; sync the text offset | ||||||||||||
| 8878 | LDY #&ff ; flag EQUS (length from the string buffer) | ||||||||||||
| 887A | BNE equb_emit_loop ; assemble the string bytes | ||||||||||||
| 887C | .insert_byte←2← 88DD JSR← 8A55 JSR | ||||||||||||
| PHA ; Save the byte to insert | |||||||||||||
| 887D | CLC ; Source = dest + Y | ||||||||||||
| 887E | TYA ; offset to A, | ||||||||||||
| 887F | ADC zp_general ; + dest low, | ||||||||||||
| 8881 | STA zp_fileblk ; source low (&39), | ||||||||||||
| 8883 | LDY #0 ; reset the index, | ||||||||||||
| 8885 | TYA ; A = 0, | ||||||||||||
| 8886 | ADC zp_general_1 ; + dest high, | ||||||||||||
| 8888 | STA zp_fileblk_1 ; source high (&3A) | ||||||||||||
| 888A | PLA ; recover the byte to insert | ||||||||||||
| 888B | STA (zp_general),y ; store the inserted byte | ||||||||||||
| 888D | .insert_byte_loop←1← 8894 BNE | ||||||||||||
| INY ; Copy the rest of the line up | |||||||||||||
| 888E | LDA (zp_fileblk),y ; read from source+Y, | ||||||||||||
| 8890 | STA (zp_general),y ; write to dest+Y, | ||||||||||||
| 8892 | CMP #&0d ; until the carriage return | ||||||||||||
| 8894 | BNE insert_byte_loop ; until the CR | ||||||||||||
| 8896 | RTS ; Return | ||||||||||||
Tokenise a line-number referenceAccumulate the decimal digits at (zp_general),Y into a 16-bit value (value*10 + digit, in &3D/&3E) and, on success, replace them in place with the three-byte &8D line-number token (the GOTO/GOSUB encoding). Stops at the first non-digit; reports overflow if the value exceeds 16 bits.
|
|||||||||||||
| 8897 | .parse_decimal_u16←1← 89B0 JSR | ||||||||||||
| AND #&0f ; First digit | |||||||||||||
| 8899 | STA zp_fwb_exp ; Value low = digit | ||||||||||||
| 889B | STY zp_fwb_m1 ; Value high = 0 | ||||||||||||
| 889D | .parse_dec_loop←2← 88CE BCC← 88D2 BPL | ||||||||||||
| INY ; Next character | |||||||||||||
| 889E | LDA (zp_general),y ; read it | ||||||||||||
| 88A0 | CMP #':' ; above 9? | ||||||||||||
| 88A2 | BCS parse_dec_encode ; not a digit: done | ||||||||||||
| 88A4 | CMP #'0' ; below 0? | ||||||||||||
| 88A6 | BCC parse_dec_encode ; not a digit: done | ||||||||||||
| 88A8 | AND #&0f ; Digit value | ||||||||||||
| 88AA | PHA ; save it | ||||||||||||
| 88AB | LDX zp_fwb_m1 ; value high | ||||||||||||
| 88AD | LDA zp_fwb_exp ; value low | ||||||||||||
| 88AF | ASL ; value * 2 | ||||||||||||
| 88B0 | ROL zp_fwb_m1 ; into the high byte | ||||||||||||
| 88B2 | BMI parse_dec_overflow ; overflow | ||||||||||||
| 88B4 | ASL ; value * 4 | ||||||||||||
| 88B5 | ROL zp_fwb_m1 ; into the high byte | ||||||||||||
| 88B7 | BMI parse_dec_overflow ; overflow | ||||||||||||
| 88B9 | ADC zp_fwb_exp ; + value = value * 5 | ||||||||||||
| 88BB | STA zp_fwb_exp ; store the low byte | ||||||||||||
| 88BD | TXA ; now the high byte: | ||||||||||||
| 88BE | ADC zp_fwb_m1 ; + the x4 high byte (= x5) | ||||||||||||
| 88C0 | ASL zp_fwb_exp ; * 2 = value * 10 | ||||||||||||
| 88C2 | ROL ; into the high byte | ||||||||||||
| 88C3 | BMI parse_dec_overflow ; overflow | ||||||||||||
| 88C5 | BCS parse_dec_overflow ; overflow | ||||||||||||
| 88C7 | STA zp_fwb_m1 ; store the high byte | ||||||||||||
| 88C9 | PLA ; Add the digit | ||||||||||||
| 88CA | ADC zp_fwb_exp ; add the digit to the low byte, | ||||||||||||
| 88CC | STA zp_fwb_exp ; store it | ||||||||||||
| 88CE | BCC parse_dec_loop ; next digit | ||||||||||||
| 88D0 | INC zp_fwb_m1 ; carry into the high byte | ||||||||||||
| 88D2 | BPL parse_dec_loop ; next digit | ||||||||||||
| 88D4 | PHA ; overflow marker | ||||||||||||
| 88D5 | .parse_dec_overflow←4← 88B2 BMI← 88B7 BMI← 88C3 BMI← 88C5 BCS | ||||||||||||
| PLA ; Discard the saved digit | |||||||||||||
| 88D6 | LDY #0 ; Offset 0 | ||||||||||||
| 88D8 | SEC ; flag a value was read | ||||||||||||
| 88D9 | RTS ; Return | ||||||||||||
| 88DA | .parse_dec_encode←2← 88A2 BCS← 88A6 BCC | ||||||||||||
| DEY ; Back up | |||||||||||||
| 88DB | LDA #&8d ; Line-number token &8D | ||||||||||||
| 88DD | JSR insert_byte ; Make room for the 3 encoded bytes | ||||||||||||
| 88E0 | LDA zp_general ; Destination = source + 2 | ||||||||||||
| 88E2 | ADC #2 ; source low + 2 | ||||||||||||
| 88E4 | STA zp_fileblk ; dest low | ||||||||||||
| 88E6 | LDA zp_general_1 ; source high... | ||||||||||||
| 88E8 | ADC #0 ; + carry | ||||||||||||
| 88EA | STA zp_fileblk_1 ; dest high | ||||||||||||
| 88EC | .parse_dec_shift_loop←1← 88F1 BNE | ||||||||||||
| LDA (zp_general),y ; Shift the bytes up | |||||||||||||
| 88EE | STA (zp_fileblk),y ; up two bytes | ||||||||||||
| 88F0 | DEY ; next | ||||||||||||
| 88F1 | BNE parse_dec_shift_loop ; loop | ||||||||||||
| 88F3 | LDY #3 ; Three encoded bytes | ||||||||||||
| fall through ↓ | |||||||||||||
Encode a 16-bit line number into 3 bytesPack the line number in &3D/&3E into the BBC three-byte GOTO encoding (a control byte holding the scrambled top bits, then low|&40 and high|&40) so the bytes never collide with tokens. The control byte carries only four high bits, so the encoding is exact only for line numbers 0-32767 (above that the top bit is lost - the documented line-number ceiling), and no encoded byte is ever &0D.
|
|||||||||||
| 88F5 | .encode_line_number←1← 906A JSR | ||||||||||
| LDA zp_fwb_m1 ; Byte 2 = line-number high | &40 | |||||||||||
| 88F7 | ORA #&40 ; | &40 (lift out of token range) | ||||||||||
| 88F9 | STA (zp_general),y ; store byte 2 | ||||||||||
| 88FB | DEY ; back to byte 1 | ||||||||||
| 88FC | LDA zp_fwb_exp ; Byte 1 = line-number low (6 bits) | &40 | ||||||||||
| 88FE | AND #&3f ; keep the low 6 bits, | ||||||||||
| 8900 | ORA #&40 ; | &40 | ||||||||||
| 8902 | STA (zp_general),y ; store byte 1 | ||||||||||
| 8904 | DEY ; Byte 0: scramble the top bits | ||||||||||
| 8905 | LDA zp_fwb_exp ; low byte: its top 2 bits... | ||||||||||
| 8907 | AND #&c0 ; mask them, | ||||||||||
| 8909 | STA zp_fwb_exp ; (hold them) | ||||||||||
| 890B | LDA zp_fwb_m1 ; high byte: its top 2 bits... | ||||||||||
| 890D | AND #&c0 ; mask them, | ||||||||||
| 890F | LSR ; shift down, | ||||||||||
| 8910 | LSR ; (continued) | ||||||||||
| 8911 | ORA zp_fwb_exp ; merge with the low byte pair, | ||||||||||
| 8913 | LSR ; shift the four bits down, | ||||||||||
| 8914 | LSR ; (continued) | ||||||||||
| 8915 | EOR #&54 ; scramble (EOR &54) | ||||||||||
| 8917 | STA (zp_general),y ; store the control byte | ||||||||||
| 8919 | JSR inc_ptr_general ; Advance past the 3 bytes | ||||||||||
| 891C | JSR inc_ptr_general ; (continued) | ||||||||||
| 891F | JSR inc_ptr_general ; (continued) | ||||||||||
| 8922 | LDY #0 ; done: reset Y for the caller | ||||||||||
| 8924 | .not_name_char←3← 8928 BCS← 8930 BCS← 8938 BCS | ||||||||||
| CLC ; not a name character | |||||||||||
| 8925 | RTS ; return (carry clear) | ||||||||||
Test A for a name characterReturn carry set if A is 0-9, A-Z, a-z or _, the characters allowed in a variable or FN/PROC name.
|
|||||||||||||
| 8926 | .is_alphanumeric←5← 89CB JSR← 89D4 JSR← 8A43 JSR← 8A74 JSR← B167 JSR | ||||||||||||
| CMP #'{' ; above 'z'? | |||||||||||||
| 8928 | BCS not_name_char ; yes: no | ||||||||||||
| 892A | CMP #'_' ; '_' or above? | ||||||||||||
| 892C | BCS return_2 ; yes: name char | ||||||||||||
| 892E | CMP #'[' ; '[' to '^'? | ||||||||||||
| 8930 | BCS not_name_char ; yes: no | ||||||||||||
| 8932 | CMP #'A' ; 'A' or above? | ||||||||||||
| 8934 | BCS return_2 ; yes: name char | ||||||||||||
| 8936 | .is_digit←3← 893F BNE← 896D JSR← 89A7 JSR | ||||||||||||
| CMP #':' ; above '9'? | |||||||||||||
| 8938 | BCS not_name_char ; yes: no | ||||||||||||
| 893A | CMP #'0' ; digit? | ||||||||||||
| 893C | .return_2←2← 892C BCS← 8934 BCS | ||||||||||||
| RTS ; carry set if so | |||||||||||||
| 893D | .is_dot_or_digit←1← 89B7 JSR | ||||||||||||
| CMP #'.' ; '.'? | |||||||||||||
| 893F | BNE is_digit ; no: test alphanumeric | ||||||||||||
| 8941 | RTS ; Return | ||||||||||||
Read a byte via the general pointer, then advance itLoad the byte at (zp_general),Y and fall through to inc_ptr_general to step the 16-bit pointer on by one.
|
|||||||||||||||
| 8942 | .read_via_ptr_general←4← B3D9 JSR← B3E8 JSR← B3F1 JSR← B3F6 JSR | ||||||||||||||
| LDA (zp_general),y ; Read the byte at (zp_general)+Y, then advance | |||||||||||||||
| fall through ↓ | |||||||||||||||
Increment the general 16-bit pointerIncrement the little-endian pointer held in zp_general (&37/&38) by one, carrying into the high byte.
|
|||||||||||||
| 8944 | .inc_ptr_general←8← 8919 JSR← 891C JSR← 891F JSR← 894B JSR← 8961 JSR← 89BC JSR← 89D9 JSR← 8A79 JSR | ||||||||||||
| INC zp_general ; Increment the general pointer: low byte | |||||||||||||
| 8946 | BNE return_3 ; No carry: done | ||||||||||||
| 8948 | INC zp_general_1 ; Carry into the high byte | ||||||||||||
| 894A | .return_3←2← 8946 BNE← 895B BEQ | ||||||||||||
| RTS ; Return (shared) | |||||||||||||
Advance the general pointer and read the next byteCall inc_ptr_general to increment the 16-bit general pointer zp_general (&37/&38) by one (carrying into the high byte), then load the byte at (zp_general),Y and return it in A. The tokeniser's fetch-next-character primitive for hex constants and string literals.
|
|||||||||||||
| 894B | .general_next_byte←3← 896A JSR← 8980 JSR← BFDC JSR | ||||||||||||
| JSR inc_ptr_general ; Advance the pointer... | |||||||||||||
| 894E | LDA (zp_general),y ; ...then read the next byte | ||||||||||||
| 8950 | RTS ; Return the byte | ||||||||||||
Tokenise a lineConvert the line being entered into its internal form, replacing keywords with tokens via the keyword_table while leaving strings, line numbers and names intact. Works through the buffer using the general pointer (zp_general, &37). Three entry points share this scanner, differing only in how much of the &3B/&3C state they reset:
|
|||||||
| 8951 | .tokenise_line←1← 90C3 JSR | ||||||
| LDY #0 ; Tokeniser state (&3B/&3C): start of statement | |||||||
| 8953 | STY zp_fwb_sign ; Start-of-statement flag (&3B) | ||||||
| 8955 | .tokenise_resume←1← AC1A JSR | ||||||
| STY zp_fwb_ovf ; Clear the line-number flag (&3C) | |||||||
| 8957 | .tok_scan←5← 8964 BNE← 8974 BCC← 897A BCS← 89C8 JMP← 8B2A JSR | ||||||
| LDA (zp_general),y ; Scan the next source character | |||||||
| 8959 | CMP #&0d ; CR: end of line | ||||||
| 895B | BEQ return_3 ; Carriage return ends the line | ||||||
| 895D | CMP #' ' ; space: skip it | ||||||
| 895F | BNE tok_check_hex ; Skip spaces | ||||||
| 8961 | .tok_advance←5← 8985 BEQ← 8994 BEQ← 8998 BEQ← 89E9 JMP← 8A89 JMP | ||||||
| JSR inc_ptr_general ; advance and read the next character | |||||||
| 8964 | BNE tok_scan ; loop | ||||||
| 8966 | .tok_check_hex←1← 895F BNE | ||||||
| CMP #'&' ; An "&" introduces a hex constant: copy it unchanged | |||||||
| 8968 | BNE tok_check_string ; not "&": check the other cases | ||||||
| 896A | .tok_hex_loop←2← 8970 BCS← 8978 BCC | ||||||
| JSR general_next_byte ; Hex constant: advance and get a character | |||||||
| 896D | JSR is_digit ; a digit? | ||||||
| 8970 | BCS tok_hex_loop ; yes: keep copying | ||||||
| 8972 | CMP #'A' ; below 'A'? | ||||||
| 8974 | BCC tok_scan ; not hex: resume scanning | ||||||
| 8976 | CMP #'G' ; 'A'..'F'? | ||||||
| 8978 | BCC tok_hex_loop ; hex letter: keep copying | ||||||
| 897A | BCS tok_scan ; past F: resume | ||||||
| 897C | .tok_check_string←1← 8968 BNE | ||||||
| CMP #'"' ; A quote starts a string literal: copy it verbatim | |||||||
| 897E | BNE tok_check_colon ; not a quote: check for a colon | ||||||
| 8980 | .tok_string_loop←1← 8989 BNE | ||||||
| JSR general_next_byte ; String literal: copy to the closing quote | |||||||
| 8983 | CMP #'"' ; a quote? | ||||||
| 8985 | BEQ tok_advance ; yes: end of string | ||||||
| 8987 | CMP #&0d ; CR (unterminated)? | ||||||
| 8989 | BNE tok_string_loop ; no: keep copying | ||||||
| 898B | RTS ; Return | ||||||
| 898C | .tok_check_colon←1← 897E BNE | ||||||
| CMP #':' ; A colon starts a new statement: reset the state | |||||||
| 898E | BNE tok_check_comma_star ; not a colon: check for a comma | ||||||
| 8990 | STY zp_fwb_sign ; Colon: back to start-of-statement | ||||||
| 8992 | STY zp_fwb_ovf ; clear the line-number flag | ||||||
| 8994 | BEQ tok_advance ; continue | ||||||
| 8996 | .tok_check_comma_star←1← 898E BNE | ||||||
| CMP #',' ; a comma? | |||||||
| 8998 | BEQ tok_advance ; yes: skip it | ||||||
| 899A | CMP #'*' ; "*": maybe a *command (statement position checked next) | ||||||
| 899C | BNE tok_check_number ; not "*": try a keyword or name | ||||||
| 899E | LDA zp_fwb_sign ; at the start of a statement? | ||||||
| 89A0 | BNE tok_not_keyword ; no (mid-statement): "*" is the multiply operator | ||||||
| 89A2 | RTS ; yes: *command - RTS leaves the rest untokenised | ||||||
| 89A3 | .tok_check_number←1← 899C BNE | ||||||
| CMP #'.' ; a "." (abbreviation dot)? | |||||||
| 89A5 | BEQ tok_skip_number_loop ; yes | ||||||
| 89A7 | JSR is_digit ; a digit? | ||||||
| 89AA | BCC tok_check_letter ; no: a letter or symbol | ||||||
| 89AC | LDX zp_fwb_ovf ; line-number armed (after GOTO etc.)? | ||||||
| 89AE | BEQ tok_skip_number_loop ; not armed: an ordinary number | ||||||
| 89B0 | JSR parse_decimal_u16 ; tokenise the line number | ||||||
| 89B3 | BCC tok_continue ; continue | ||||||
| 89B5 | .tok_skip_number_loop←3← 89A5 BEQ← 89AE BEQ← 89BF JMP | ||||||
| LDA (zp_general),y ; Skip a number: read a character | |||||||
| 89B7 | JSR is_dot_or_digit ; a digit or "."? | ||||||
| 89BA | BCC tok_resume_mid ; no: end of the number | ||||||
| 89BC | JSR inc_ptr_general ; advance | ||||||
| 89BF | JMP tok_skip_number_loop ; loop | ||||||
| 89C2 | .tok_resume_mid←2← 89BA BCC← 89D7 BCC | ||||||
| LDX #&ff ; Now in the middle of a statement: | |||||||
| 89C4 | STX zp_fwb_sign ; set the flag | ||||||
| 89C6 | STY zp_fwb_ovf ; clear the line-number flag | ||||||
| 89C8 | JMP tok_scan ; resume scanning | ||||||
| 89CB | .tok_skip_name←1← 89EE BCS | ||||||
| JSR is_alphanumeric ; Skip a variable name: alphanumeric? | |||||||
| 89CE | BCC tok_not_keyword ; no: not a name | ||||||
| 89D0 | .tok_name←2← 8A16 BCS← 8A46 BCS | ||||||
| LDY #0 ; Consume the whole name run; no interior keyword match | |||||||
| 89D2 | .tok_name_loop←2← 89DC JMP← 89FA BCC | ||||||
| LDA (zp_general),y ; read it | |||||||
| 89D4 | JSR is_alphanumeric ; alphanumeric? | ||||||
| 89D7 | BCC tok_resume_mid ; no: end of the name | ||||||
| 89D9 | JSR inc_ptr_general ; advance | ||||||
| 89DC | JMP tok_name_loop ; loop | ||||||
| 89DF | .tok_check_letter←1← 89AA BCC | ||||||
| CMP #'A' ; a letter ('A'+)? | |||||||
| 89E1 | BCS tok_try_keyword ; yes: try to match a keyword | ||||||
| 89E3 | .tok_not_keyword←2← 89A0 BNE← 89CE BCC | ||||||
| LDX #&ff ; Not a keyword: middle of statement | |||||||
| 89E5 | STX zp_fwb_sign ; set mid-statement, | ||||||
| 89E7 | STY zp_fwb_ovf ; clear the line-number flag | ||||||
| 89E9 | .tok_continue←1← 89B3 BCC | ||||||
| JMP tok_advance ; continue scanning | |||||||
| 89EC | .tok_try_keyword←1← 89E1 BCS | ||||||
| CMP #'X' ; 'X' or above? | |||||||
| 89EE | BCS tok_skip_name ; nothing starts with X/Y/Z: skip the name | ||||||
| 89F0 | LDX #&71 ; Point at the keyword table (&8071): low | ||||||
| 89F2 | STX zp_fileblk ; (store) | ||||||
| 89F4 | LDX #&80 ; high &80 | ||||||
| 89F6 | STX zp_fileblk_1 ; (store) | ||||||
| 89F8 | .tok_kw_entry←1← 8A34 JMP | ||||||
| CMP (zp_fileblk),y ; Compare the first letter with this entry | |||||||
| 89FA | BCC tok_name_loop ; entry past our letter: not a keyword | ||||||
| 89FC | BNE tok_kw_check_end ; first letter differs: next entry | ||||||
| 89FE | .tok_kw_match_loop←1← 8A05 BEQ | ||||||
| INY ; matches: compare the rest of the keyword | |||||||
| 89FF | LDA (zp_fileblk),y ; entry char (bit 7 = the token) | ||||||
| 8A01 | BMI tok_kw_found ; whole keyword matched: got a token | ||||||
| 8A03 | CMP (zp_general),y ; compare with the line | ||||||
| 8A05 | BEQ tok_kw_match_loop ; match: next character | ||||||
| 8A07 | LDA (zp_general),y ; mismatch: a "." abbreviation? | ||||||
| 8A09 | CMP #'.' ; is it "."? | ||||||
| 8A0B | BEQ tok_kw_abbrev ; yes: accept the abbreviation | ||||||
| 8A0D | .tok_kw_check_end←2← 89FC BNE← 8A10 BPL | ||||||
| INY ; Skip to the next entry: past the name | |||||||
| 8A0E | LDA (zp_fileblk),y ; read it | ||||||
| 8A10 | BPL tok_kw_check_end ; until the token byte (bit 7 set) | ||||||
| 8A12 | CMP #&fe ; WIDTH token &FE doubles as the end-of-table sentinel | ||||||
| 8A14 | BNE tok_kw_next_entry ; no: a real token, try the next entry | ||||||
| 8A16 | BCS tok_name ; sentinel: not a keyword (skip the name) | ||||||
| 8A18 | .tok_kw_abbrev←1← 8A0B BEQ | ||||||
| INY ; Abbreviation: skip to this entry's token | |||||||
| 8A19 | .tok_kw_skip_loop←2← 8A1F BNE← 8A23 BNE | ||||||
| LDA (zp_fileblk),y ; read it | |||||||
| 8A1B | BMI tok_kw_found ; token byte: got it | ||||||
| 8A1D | INC zp_fileblk ; advance the table pointer | ||||||
| 8A1F | BNE tok_kw_skip_loop ; no wrap | ||||||
| 8A21 | INC zp_fileblk_1 ; carry into high | ||||||
| 8A23 | BNE tok_kw_skip_loop ; loop | ||||||
| 8A25 | .tok_kw_next_entry←1← 8A14 BNE | ||||||
| SEC ; Advance past this entry to the next: | |||||||
| 8A26 | INY ; (include the token byte) | ||||||
| 8A27 | TYA ; offset... | ||||||
| 8A28 | ADC zp_fileblk ; low | ||||||
| 8A2A | STA zp_fileblk ; (store) | ||||||
| 8A2C | BCC tok_kw_retry ; no carry | ||||||
| 8A2E | INC zp_fileblk_1 ; carry into high | ||||||
| 8A30 | .tok_kw_retry←1← 8A2C BCC | ||||||
| LDY #0 ; reset Y | |||||||
| 8A32 | LDA (zp_general),y ; re-read the first letter | ||||||
| 8A34 | JMP tok_kw_entry ; try the next entry | ||||||
| 8A37 | .tok_kw_found←2← 8A01 BMI← 8A1B BMI | ||||||
| TAX ; Token byte found: keep it in X | |||||||
| 8A38 | INY ; the flag byte follows | ||||||
| 8A39 | LDA (zp_fileblk),y ; get the token flag | ||||||
| 8A3B | STA zp_fwb_exp ; (save it in &3D) | ||||||
| 8A3D | DEY ; back up Y | ||||||
| 8A3E | LSR ; flag bit 0: conditional tokenisation? | ||||||
| 8A3F | BCC tok_emit_token ; no | ||||||
| 8A41 | LDA (zp_general),y ; a name char follows? (then keep it as a name) | ||||||
| 8A43 | JSR is_alphanumeric ; test it | ||||||
| 8A46 | BCS tok_name ; yes: keep it as a name, not a token | ||||||
| 8A48 | .tok_emit_token←1← 8A3F BCC | ||||||
| TXA ; Emit the token: A = token byte | |||||||
| 8A49 | BIT zp_fwb_exp ; flag bit 6: pseudo-variable? | ||||||
| 8A4B | BVC tok_write_token ; no | ||||||
| 8A4D | LDX zp_fwb_sign ; at the start of a statement? | ||||||
| 8A4F | BNE tok_write_token ; no | ||||||
| 8A51 | CLC ; superfluous: all paths reach here carry-clear | ||||||
| 8A52 | ADC #&40 ; assignment form: token + &40 | ||||||
| 8A54 | .tok_write_token←2← 8A4B BVC← 8A4F BNE | ||||||
| DEY ; Write the token over the keyword | |||||||
| 8A55 | JSR insert_byte ; overwrite the keyword | ||||||
| 8A58 | LDY #0 ; reset Y | ||||||
| 8A5A | LDX #&ff ; X = &FF (mid-statement marker) | ||||||
| 8A5C | LDA zp_fwb_exp ; Apply the state-change flags: | ||||||
| 8A5E | LSR ; bit 0 (already used) | ||||||
| 8A5F | LSR ; bit 1: enter middle-of-statement? | ||||||
| 8A60 | BCC tok_flag_start_stmt ; no | ||||||
| 8A62 | STX zp_fwb_sign ; set middle-of-statement | ||||||
| 8A64 | STY zp_fwb_ovf ; clear the line-number flag | ||||||
| 8A66 | .tok_flag_start_stmt←1← 8A60 BCC | ||||||
| LSR ; bit 2: enter start-of-statement? | |||||||
| 8A67 | BCC tok_flag_fnproc ; no | ||||||
| 8A69 | STY zp_fwb_sign ; set start-of-statement | ||||||
| 8A6B | STY zp_fwb_ovf ; clear the line-number flag | ||||||
| 8A6D | .tok_flag_fnproc←1← 8A67 BCC | ||||||
| LSR ; bit 3: FN/PROC (do not tokenise the name)? | |||||||
| 8A6E | BCC tok_flag_linenum ; no | ||||||
| 8A70 | PHA ; save A | ||||||
| 8A71 | INY ; skip the FN/PROC name untokenised: | ||||||
| 8A72 | .tok_skip_fnproc_loop←1← 8A7C JMP | ||||||
| LDA (zp_general),y ; char | |||||||
| 8A74 | JSR is_alphanumeric ; alphanumeric? | ||||||
| 8A77 | BCC tok_skip_fnproc_done ; no: end of the name | ||||||
| 8A79 | JSR inc_ptr_general ; advance | ||||||
| 8A7C | JMP tok_skip_fnproc_loop ; loop | ||||||
| 8A7F | .tok_skip_fnproc_done←1← 8A77 BCC | ||||||
| DEY ; step back | |||||||
| 8A80 | PLA ; restore A | ||||||
| 8A81 | .tok_flag_linenum←1← 8A6E BCC | ||||||
| LSR ; bit 4: start a line number? | |||||||
| 8A82 | BCC tok_flag_skipline ; no | ||||||
| 8A84 | STX zp_fwb_ovf ; set the line-number flag | ||||||
| 8A86 | .tok_flag_skipline←1← 8A82 BCC | ||||||
| LSR ; bit 5: skip the rest of the line (REM/DATA)? | |||||||
| 8A87 | BCS return_4 ; yes: stop tokenising | ||||||
| 8A89 | JMP tok_advance ; continue scanning | ||||||
Skip spaces at the secondary text pointerAs skip_spaces, but works on the secondary text pointer (zp_text_ptr2, &19) and its offset (&1B). Used while the primary pointer is preserved, e.g. when scanning ahead during assignment.
|
||||||||
| 8A8C | .skip_spaces_ptr2←21← 8A94 BEQ← 8AAE JSR← 8D32 JSR← 8E43 JSR← 8EE3 JSR← 9841 JSR← AC50 JSR← AC5B JSR← AC66 JSR← ADAD JSR← AE02 JSR← B094 JSR← B287 JSR← B2A0 JSR← B7EA JSR← B813 JSR← B866 JSR← BABD JSR← BB60 JSR← BB6F JSR← BFB5 JSR | |||||||
| LDY zp_text_ptr2_off ; Get the secondary text offset | ||||||||
| 8A8E | INC zp_text_ptr2_off ; advance it | |||||||
| 8A90 | LDA (zp_text_ptr2),y ; Read the character | |||||||
| 8A92 | CMP #' ' ; Loop while the character is a space | |||||||
| 8A94 | BEQ skip_spaces_ptr2 ; Space: keep skipping | |||||||
| 8A96 | .return_4←1← 8A87 BCS | |||||||
| RTS ; Return the first non-space character | ||||||||
Skip spaces at the text pointerAdvance the primary text pointer past any spaces and return the first non-space character. The workhorse of the tokeniser and interpreter: most statements call it between syntax elements.
|
|||||||||||||
| 8A97 | .skip_spaces←48← 8508 JSR← 85BC JSR← 86BB JSR← 86D7 JSR← 86E1 JSR← 86E8 JSR← 86F2 JSR← 86FF JSR← 8706 JSR← 871A JSR← 8724 JSR← 8747 JSR← 8753 JSR← 875D JSR← 8776 JSR← 878E JSR← 87A8 JSR← 87C1 JSR← 87D4 JSR← 87DE JSR← 87F6 JSR← 87FD JSR← 8A9F BEQ← 8B38 JSR← 8D89 JSR← 8D9A JSR← 8DC3 JSR← 8E8A JSR← 8F39 JSR← 8F79 JSR← 912F JSR← 91A9 JSR← 920B JSR← 9349 JSR← 942F JSR← 9446 JSR← B13F JSR← B1F9 JSR← B279 JSR← B5BE JSR← B5CF JSR← B75C JSR← B8F2 JSR← B915 JSR← B9DA JSR← BA44 JSR← BAEE JSR← BB15 JSR | ||||||||||||
| LDY zp_text_ptr_off ; Get the text offset | |||||||||||||
| 8A99 | INC zp_text_ptr_off ; advance it for next time | ||||||||||||
| 8A9B | LDA (zp_text_ptr),y ; Read the character | ||||||||||||
| 8A9D | CMP #' ' ; Loop while the character is a space | ||||||||||||
| 8A9F | BEQ skip_spaces ; Space: keep skipping | ||||||||||||
| 8AA1 | RTS ; Return the first non-space character | ||||||||||||
Raise "Missing ," errorRaise BASIC error &05, "Missing ,", via a BRK error block. Reached from the argument-list parsers when a required comma is absent. Does not return.
|
||||
| 8AA2 | .missing_comma←4← 8AB3 BNE← 8E21 JMP← AD03 JMP← B036 JMP | |||
| BRK ; BRK error block ("Missing ,") follows | ||||
| 8AA3 | EQUB &05 | |||
| 8AA4 | EQUS "Missing ," | |||
| 8AAD | EQUB &00 | |||
Skip spaces and require a commaSkip spaces at PtrB, then check the character is a comma. Raises "Missing ," if it is not. Used by statements that take a comma-separated argument list.
|
|||||||||||
| 8AAE | .skip_spaces_expect_comma←5← 92DA JSR← 93F7 JSR← AB47 JSR← B0C8 JSR← BF5C JSR | ||||||||||
| JSR skip_spaces_ptr2 ; Skip spaces at PtrB | |||||||||||
| 8AB1 | CMP #',' ; Require a comma | ||||||||||
| 8AB3 | BNE missing_comma ; Missing: "Missing ," error | ||||||||||
| 8AB5 | RTS ; Return | ||||||||||
OLDRecover the program cleared by NEW, if memory is intact. OLD.
|
|||||||||||
| 8AB6 | .stmt_old | ||||||||||
| JSR check_end_of_statement ; Check the statement ends | |||||||||||
| 8AB9 | LDA zp_page ; Point at PAGE | ||||||||||
| 8ABB | STA zp_general_1 ; high byte (&38), | ||||||||||
| 8ABD | LDA #0 ; low byte 0, | ||||||||||
| 8ABF | STA zp_general ; to &37 | ||||||||||
| 8AC1 | STA (zp_general),y ; Remove the end marker | ||||||||||
| 8AC3 | JSR check_program ; Re-check the program and set TOP | ||||||||||
| 8AC6 | BNE clear_then_immediate ; clear heap and return to immediate mode | ||||||||||
| fall through ↓ | |||||||||||
ENDEnd the program and return to the immediate prompt. END.
|
|||||||||||
| 8AC8 | .stmt_end | ||||||||||
| JSR check_end_of_statement ; Check the statement ends | |||||||||||
| 8ACB | JSR check_program ; Check the program | ||||||||||
| 8ACE | BNE immediate_loop ; return to immediate mode (keep variables) | ||||||||||
| fall through ↓ | |||||||||||
STOPStop the program, reporting "STOP at line nnnn". STOP.
|
|||||||||||
| 8AD0 | .stmt_stop | ||||||||||
| JSR check_end_of_statement ; Check the statement ends | |||||||||||
| 8AD3 | BRK ; STOP error | ||||||||||
| 8AD4 | EQUB &00 | ||||||||||
| 8AD5 | EQUS "STOP" | ||||||||||
| 8AD9 | EQUB &00 | ||||||||||
NEWClear the current program and its variables. NEW.
|
|||||||||||
| 8ADA | .stmt_new | ||||||||||
| JSR check_end_of_statement ; Check the statement ends | |||||||||||
| fall through ↓ | |||||||||||
Clear program and enter the immediate loopEntered from language_startup. Sets up an empty program (a CR and an &FF end marker at PAGE, TOP = PAGE+2), clears variables/heap/stack, and falls through into the immediate loop. Does not return.
|
|||||||
| 8ADD | .start_new_program←1← 806E JMP | ||||||
| LDA #&0d ; Empty program is a single CR... | |||||||
| 8ADF | LDY zp_page ; TOP starts at PAGE: high byte | ||||||
| 8AE1 | STY zp_top_1 ; (TOP high) | ||||||
| 8AE3 | LDY #0 ; low byte 0 | ||||||
| 8AE5 | STY zp_top ; TOP low = PAGE | ||||||
| 8AE7 | STY zp_trace_flag ; TRACE off | ||||||
| 8AE9 | STA (zp_top),y ; ...stored as the end marker at PAGE | ||||||
| 8AEB | LDA #&ff ; &FF... | ||||||
| 8AED | INY ; next byte | ||||||
| 8AEE | STA (zp_top),y ; ...marks the program end at PAGE+1 | ||||||
| 8AF0 | INY ; TOP = PAGE + 2 | ||||||
| 8AF1 | STY zp_top ; (store) | ||||||
| 8AF3 | .clear_then_immediate←6← 8AC6 BNE← 8B35 JMP← 8F66 JMP← 903A JMP← 90D9 JMP← BF27 JMP | ||||||
| JSR clear_vars_heap_stack ; Clear variables, heap and stack | |||||||
| fall through ↓ | |||||||
Immediate ("> ") loopPrint the prompt, read a line into the input buffer (PtrA = &0700), and tokenise it. A line that begins with a line number is inserted into the program; otherwise it is executed immediately. The top-level loop - does not return.
|
||||
| 8AF6 | .immediate_loop←7← 859C JMP← 8ACE BNE← 8B41 JMP← 98BC JMP← B599 JMP← B61A JMP← BEAF JMP | |||
| LDY #7 ; PtrA = &0700, the input buffer: high byte | ||||
| 8AF8 | STY zp_text_ptr_1 ; (store) | |||
| 8AFA | LDY #0 ; low byte 0 | |||
| 8AFC | STY zp_text_ptr ; (store) | |||
| 8AFE | LDA #&33 ; ON ERROR OFF: default handler at &B433 | |||
| 8B00 | STA zp_error_vec ; (low) | |||
| 8B02 | LDA #&b4 ; (high) | |||
| 8B04 | STA zp_error_vec_1 ; (store) | |||
| 8B06 | LDA #'>' ; The ">" prompt | |||
| 8B08 | JSR read_input_line ; Print it and read a line into the buffer | |||
| fall through ↓ | ||||
Execute the line at the program pointerRun the tokenised statements on the line addressed by the program pointer (zp_text_ptr, &0B), starting at offset zp_text_ptr_off. Resets the error handler and the 6502 stack, tokenises the line, and either inserts a numbered line or runs it via the statement loop.
|
|||||||||
| 8B0B | .execute_line←1← BD1D JMP | ||||||||
| LDA #&33 ; Restore the default error handler (ON ERROR OFF) | |||||||||
| 8B0D | STA zp_error_vec ; low byte = &33, | ||||||||
| 8B0F | LDA #&b4 ; high byte = &B4, | ||||||||
| 8B11 | STA zp_error_vec_1 ; store it (handler at &B433) | ||||||||
| 8B13 | LDX #&ff ; OPT = &FF: not inside the [ ] assembler | ||||||||
| 8B15 | STX zp_opt_flag ; store the OPT flag | ||||||||
| 8B17 | STX zp_fwb_ovf ; Arm line-number encoding (&3C) for a leading line number | ||||||||
| 8B19 | TXS ; Reset the 6502 hardware stack | ||||||||
| 8B1A | JSR reset_data_and_stacks ; Clear the DATA pointer and the BASIC stacks | ||||||||
| 8B1D | TAY ; Y = 0 | ||||||||
| 8B1E | LDA zp_text_ptr ; Point the general pointer at the line text | ||||||||
| 8B20 | STA zp_general ; low byte, | ||||||||
| 8B22 | LDA zp_text_ptr_1 ; high byte, | ||||||||
| 8B24 | STA zp_general_1 ; store it | ||||||||
| 8B26 | STY zp_fwb_sign ; start of statement (&3B = 0) | ||||||||
| 8B28 | STY zp_text_ptr_off ; and the offset | ||||||||
| 8B2A | JSR tok_scan ; Tokenise (&3C pre-armed for a leading number) | ||||||||
| 8B2D | JSR check_line_number ; reuse the &8D codec: decode the leading line number | ||||||||
| 8B30 | BCC exec_dispatch ; no line number: execute it | ||||||||
| 8B32 | JSR insert_line ; numbered line: insert it (IWA = the line number) | ||||||||
| 8B35 | JMP clear_then_immediate ; inserted: immediate loop | ||||||||
| 8B38 | .exec_dispatch←1← 8B30 BCC | ||||||||
| JSR skip_spaces ; Skip spaces | |||||||||
| 8B3B | CMP #&c6 ; Token >= &C6 is a command: dispatch it | ||||||||
| 8B3D | BCS dispatch_token ; command token: dispatch it | ||||||||
| 8B3F | BCC try_variable_assignment ; Otherwise treat it as a variable assignment | ||||||||
| 8B41 | .exec_immediate←1← 8B8F BEQ | ||||||||
| JMP immediate_loop ; Back to immediate mode | |||||||||
| 8B44 | .exec_assembler←1← 8B6F BEQ | ||||||||
| JMP asm_enter ; Enter the assembler | |||||||||
| 8B47 | .fn_return←1← 8B67 BEQ | ||||||||
| TSX ; Inside a function call? | |||||||||
| 8B48 | CPX #&fc ; stack near empty (no FN frame)? | ||||||||
| 8B4A | BCS no_fn_error ; no: error | ||||||||
| 8B4C | LDA hw_stack_top ; Pushed token | ||||||||
| 8B4F | CMP #&a4 ; FN? | ||||||||
| 8B51 | BNE no_fn_error ; no: error | ||||||||
| 8B53 | JSR eval_expr ; Evaluate the return value | ||||||||
| 8B56 | JMP assign_check_end ; check end, return from the function | ||||||||
| 8B59 | .no_fn_error←2← 8B4A BCS← 8B51 BNE | ||||||||
| BRK ; No FN error | |||||||||
| 8B5A | EQUB &07 | ||||||||
| 8B5B | EQUS "No " | ||||||||
| 8B5E | EQUB &A4, &00 | ||||||||
Check for =, * and [ statementsRecognise the statement forms that are not introduced by a token: "=" (return a value from FN), "*" (pass the rest of the line to OSCLI), and "[" (enter the inline assembler). Dispatches to the matching handler, otherwise checks for end of statement.
|
|||||||||
| 8B60 | .check_eq_star_bracket←1← 8BCE BCS | ||||||||
| LDY zp_text_ptr_off ; Step back to the introducing character | |||||||||
| 8B62 | DEY ; one character back | ||||||||
| 8B63 | LDA (zp_text_ptr),y ; fetch it | ||||||||
| 8B65 | CMP #'=' ; "=" returns a value from a function (FN) | ||||||||
| 8B67 | BEQ fn_return ; "=": return a value from a function | ||||||||
| 8B69 | CMP #'*' ; "*" passes the rest of the line to OSCLI | ||||||||
| 8B6B | BEQ exec_star_command ; "*": an embedded OSCLI command | ||||||||
| 8B6D | CMP #'[' ; "[" enters the inline assembler | ||||||||
| 8B6F | BEQ exec_assembler ; "[": enter the assembler | ||||||||
| 8B71 | BNE stmt_backup_end ; otherwise check for end of statement | ||||||||
| 8B73 | .exec_star_command←1← 8B6B BEQ | ||||||||
| JSR skip_to_statement_end ; Point PtrA at the command text | |||||||||
| 8B76 | LDX zp_text_ptr ; XY -> the command string | ||||||||
| 8B78 | LDY zp_text_ptr_1 ; (high byte) | ||||||||
| 8B7A | JSR oscli ; Pass it to OSCLI | ||||||||
| fall through ↓ | |||||||||
DATA / DEF / REM / ELSESkip to the end of the line. DATA introduces inline data (read by READ), DEF a PROC/FN definition, REM a comment, and ELSE the alternative of a taken IF: none execute inline, so all four share this skip-to-end handler.
|
|||||||||||
| 8B7D | .stmt_data←2← 8B89 BEQ← B907 JMP | ||||||||||
| LDA #&0d ; CR | |||||||||||
| 8B7F | LDY zp_text_ptr_off ; Line offset | ||||||||||
| 8B81 | DEY ; back up one (the loop pre-increments) | ||||||||||
| 8B82 | .data_scan_loop←1← 8B85 BNE | ||||||||||
| INY ; Scan to the end of line | |||||||||||
| 8B83 | CMP (zp_text_ptr),y ; reached the CR? | ||||||||||
| 8B85 | BNE data_scan_loop ; no: keep scanning | ||||||||||
| 8B87 | .stmt_eol←2← 8BA1 BNE← 9902 JMP | ||||||||||
| CMP #&8b ; ELSE? | |||||||||||
| 8B89 | BEQ stmt_data ; yes: skip to end of line | ||||||||||
| 8B8B | LDA zp_text_ptr_1 ; In the command buffer? | ||||||||||
| 8B8D | CMP #7 ; page &07 (command buffer)? | ||||||||||
| 8B8F | BEQ exec_immediate ; yes: immediate mode | ||||||||||
| 8B91 | JSR step_to_next_line ; Check for end of program, step past CR | ||||||||||
| 8B94 | BNE next_statement ; more: next statement | ||||||||||
| 8B96 | .stmt_backup_end←7← 8B71 BNE← 8D80 JMP← 9212 JMP← 9350 JMP← 9453 JMP← B7A1 JMP← BB1C JMP | ||||||||||
| DEC zp_text_ptr_off ; Back up | |||||||||||
| 8B98 | .stmt_check_end←4← 8D7A JMP← 9353 JMP← B9CC JMP← BA41 JMP | ||||||||||
| JSR check_end_of_statement ; check the statement ends | |||||||||||
| fall through ↓ | |||||||||||
Statement execution loopThe main interpreter loop: fetch the next statement's leading token and dispatch it, then advance to the next statement (after a colon) or line. Statement handlers jmp back here when they finish, so it is the common continuation rather than a callable subroutine.
|
|||||||||
| 8B9B | .statement_loop←23← 8BF8 JMP← 8C08 JMP← 8ECF JMP← 8F18 JMP← 926C JMP← 928A JMP← 92B4 JMP← 92D7 JMP← 9318 JMP← 93E1 JMP← 9427 JMP← B49D JMP← B4AB JMP← B8C9 JMP← B8EF JMP← BB12 JMP← BBCA JMP← BECC JMP← BF21 JMP← BF43 JMP← BF6C JMP← BFA6 JMP← BFF6 JMP | ||||||||
| LDY #0 ; Fetch the next character of the statement | |||||||||
| 8B9D | LDA (zp_text_ptr),y ; Get the current character | ||||||||
| 8B9F | CMP #':' ; A colon separates statements on a line | ||||||||
| 8BA1 | BNE stmt_eol ; Not a colon: check for ELSE / end of line | ||||||||
| fall through ↓ | |||||||||
Execute the next statement on the lineThe interpreter's per-statement entry point. Read the character at PtrA+offset while advancing zp_text_ptr_off (&0A) past the ':' separator, skipping spaces. A token >= &CF falls into dispatch_token, which indexes the action-address table and JMP (&0037)s to its handler; a byte below &CF is not a command token, so it branches to try_variable_assignment for an implied LET. Non-returning: every path transfers to a statement handler.
|
|||||||||
| 8BA3 | .next_statement←10← 8501 JMP← 8B94 BNE← 8BAB BEQ← 98DE JMP← B20B JSR← B430 JMP← B74E JMP← B84C JMP← B8E1 JMP← BBF9 JMP | ||||||||
| LDY zp_text_ptr_off ; Skip spaces to the next statement | |||||||||
| 8BA5 | INC zp_text_ptr_off ; advance past the colon | ||||||||
| 8BA7 | LDA (zp_text_ptr),y ; Get the next character | ||||||||
| 8BA9 | CMP #' ' ; Skip spaces | ||||||||
| 8BAB | BEQ next_statement ; loop | ||||||||
| 8BAD | CMP #&cf ; Below &CF: a variable assignment, not a command | ||||||||
| 8BAF | BCC try_variable_assignment ; Below &CF: a variable assignment | ||||||||
| fall through ↓ | |||||||||
Dispatch a tokenised function or commandIndex the action-address table by (token - &8E): load the handler address into zp_general (&37/&38) and JMP (&0037). This is the indirect jump that reaches every fn_* / stmt_* handler.
|
||||
| 8BB1 | .dispatch_token←2← 8B3D BCS← AE0D JMP | |||
| TAX ; Token to X for indexing | ||||
| 8BB2 | LDA action_lo_by_token,x ; Handler low byte = action_table_lo[token - &8E] | |||
| 8BB5 | STA zp_general ; Store the handler low byte | |||
| 8BB7 | LDA action_hi_by_token,x ; Handler high byte from action_table_hi | |||
| 8BBA | STA zp_general_1 ; Store the handler high byte | |||
| 8BBC | JMP (zp_general) ; Jump to the keyword handler | |||
Not a command token: try an assignmentReached when the statement does not begin with a command token: copy PtrA to PtrB, parse a variable / indirection reference, and perform an implied-LET assignment (creating the variable if new). Falls back to the =, * (OSCLI) or [ (assembler) special statement forms.
|
|||||||||
| 8BBF | .try_variable_assignment←2← 8B3F BCC← 8BAF BCC | ||||||||
| LDX zp_text_ptr ; Copy PtrA to PtrB: low | |||||||||
| 8BC1 | STX zp_text_ptr2 ; (store) | ||||||||
| 8BC3 | LDX zp_text_ptr_1 ; high | ||||||||
| 8BC5 | STX zp_text_ptr2_1 ; (store) | ||||||||
| 8BC7 | STY zp_text_ptr2_off ; offset | ||||||||
| 8BC9 | JSR pvr_parse ; Parse a variable / indirection reference | ||||||||
| 8BCC | BNE let_assign ; Existing variable: do the assignment | ||||||||
| 8BCE | BCS check_eq_star_bracket ; Not a variable: try =, * or [ | ||||||||
| 8BD0 | STX zp_text_ptr2_off ; New variable: position for "=" | ||||||||
| 8BD2 | JSR expect_eq ; Require "=" | ||||||||
| 8BD5 | JSR create_variable ; Create the new variable | ||||||||
| 8BD8 | LDX #5 ; Type 5 = floating point | ||||||||
| 8BDA | CPX zp_iwa_2 ; Is the destination a float? | ||||||||
| 8BDC | BNE assign_new_var ; no | ||||||||
| 8BDE | INX ; X = 6 | ||||||||
| 8BDF | .assign_new_var←1← 8BDC BNE | ||||||||
| JSR clear_value_bytes ; Evaluate and store the value | |||||||||
| 8BE2 | DEC zp_text_ptr_off ; Step back, continue | ||||||||
| fall through ↓ | |||||||||
LETAssign an expression to a variable; the LET keyword is optional. [LET] var = expr.
|
|||||||||||
| 8BE4 | .stmt_let | ||||||||||
| JSR parse_lvalue ; Parse the variable being assigned | |||||||||||
| 8BE7 | BEQ let_mistake ; end of statement: error | ||||||||||
| 8BE9 | .let_assign←1← 8BCC BNE | ||||||||||
| BCC let_numeric ; numeric target? | |||||||||||
| 8BEB | JSR stack_integer ; Stack the destination address | ||||||||||
| 8BEE | JSR eval_after_eq ; Expect "=" and evaluate the right-hand side | ||||||||||
| 8BF1 | LDA zp_var_type ; value type | ||||||||||
| 8BF3 | BNE err_type_mismatch ; A string variable needs a string value | ||||||||||
| 8BF5 | JSR assign_string ; Store the string | ||||||||||
| 8BF8 | JMP statement_loop ; next statement | ||||||||||
| 8BFB | .let_numeric←1← 8BE9 BCC | ||||||||||
| JSR stack_integer ; Stack the destination address | |||||||||||
| 8BFE | JSR eval_after_eq ; Expect "=" and evaluate | ||||||||||
| 8C01 | LDA zp_var_type ; value type | ||||||||||
| 8C03 | BEQ err_type_mismatch ; A numeric variable needs a numeric value | ||||||||||
| 8C05 | JSR assign_number ; Store the number | ||||||||||
| 8C08 | JMP statement_loop ; next statement | ||||||||||
| 8C0B | .let_mistake←1← 8BE7 BEQ | ||||||||||
| JMP syntax_error ; Mistake (syntax) error | |||||||||||
Raise "Type mismatch" errorRaise BASIC error &06, "Type mismatch", via a BRK error block. Reached (18 callers) whenever a routine finds a string where a number is required, or vice versa. Does not return.
|
||||
| 8C0E | .err_type_mismatch←18← 8867 JMP← 8BF3 BNE← 8C03 BEQ← 92F7 JMP← 98BF JMP← 9A9A JMP← 9C88 JMP← 9D39 JMP← ABE6 JMP← AC9B JMP← AD67 JMP← AECE JMP← B033 JMP← B0BF JMP← B4AE JMP← B9C4 JMP← BECF JMP← BF96 JMP | |||
| BRK ; Type mismatch error | ||||
| 8C0F | EQUB &06 | |||
| 8C10 | EQUS "Type mismatch" | |||
| 8C1D | EQUB &00 | |||
Store a string value into a variableAssign the string in the string buffer to the string variable whose descriptor address is on the stack. Reuses the existing allocation if the new string fits, otherwise grabs fresh space from the heap.
|
|||||||||||
| 8C1E | .assign_string←3← 8BF5 JSR← BA13 JSR← BB3D JSR | ||||||||||
| JSR unstack_integer ; Unstack the variable descriptor address | |||||||||||
| fall through ↓ | |||||||||||
Assign a string to a variable descriptor already in IWAAlternate entry to assign_string that assumes the variable descriptor address is already in zp_iwa (&2A/&2B) rather than on the stack. Assign the string in the string buffer to that variable, reusing the existing allocation if the new string fits, otherwise growing it in place or grabbing fresh heap space.
|
||||||||||
| 8C21 | .assign_string_to←2← B300 JSR← BAE0 JSR | |||||||||
| LDA zp_iwa_2 ; Variable type | ||||||||||
| 8C23 | CMP #&80 ; An absolute $-string address? | |||||||||
| 8C25 | BEQ assign_str_addr ; yes | |||||||||
| 8C27 | LDY #2 ; Bytes currently allocated | |||||||||
| 8C29 | LDA (zp_iwa),y ; read it | |||||||||
| 8C2B | CMP zp_strbuf_len ; Does the new string fit the existing allocation? | |||||||||
| 8C2D | BCS assign_str_store ; yes: reuse the allocation | |||||||||
| 8C2F | LDA zp_vartop ; Tentative new address = heap top | |||||||||
| 8C31 | STA zp_iwa_2 ; (low) | |||||||||
| 8C33 | LDA zp_vartop_1 ; high... | |||||||||
| 8C35 | STA zp_iwa_3 ; (high) | |||||||||
| 8C37 | LDA zp_strbuf_len ; Round the size up (min 8, granularity 8) | |||||||||
| 8C39 | CMP #8 ; at least 8? | |||||||||
| 8C3B | BCC assign_str_alloc_size ; under 8: take it as is | |||||||||
| 8C3D | ADC #7 ; else add 7 (round up), | |||||||||
| 8C3F | BCC assign_str_alloc_size ; no overflow | |||||||||
| 8C41 | LDA #&ff ; cap at 255 | |||||||||
| 8C43 | .assign_str_alloc_size←2← 8C3B BCC← 8C3F BCC | |||||||||
| CLC ; (clear carry) | ||||||||||
| 8C44 | PHA ; Save the new allocation size | |||||||||
| 8C45 | TAX ; keep the size in X | |||||||||
| 8C46 | LDA (zp_iwa),y ; Is the existing block at the heap top? | |||||||||
| 8C48 | LDY #0 ; offset 0 (data low) | |||||||||
| 8C4A | ADC (zp_iwa),y ; (data address + allocated == top?) | |||||||||
| 8C4C | EOR zp_vartop ; compare with heap top low | |||||||||
| 8C4E | BNE assign_str_alloc ; no: allocate fresh space | |||||||||
| 8C50 | INY ; high byte: | |||||||||
| 8C51 | ADC (zp_iwa),y ; + allocated, | |||||||||
| 8C53 | EOR zp_vartop_1 ; == heap top high? | |||||||||
| 8C55 | BNE assign_str_alloc ; no: allocate fresh space | |||||||||
| 8C57 | STA zp_iwa_3 ; yes: extend in place from this block | |||||||||
| 8C59 | TXA ; new size... | |||||||||
| 8C5A | INY ; offset 2 (old allocation) | |||||||||
| 8C5B | SEC ; new - old... | |||||||||
| 8C5C | SBC (zp_iwa),y ; reclaim the old allocation | |||||||||
| 8C5E | TAX ; X = extra bytes needed | |||||||||
| 8C5F | .assign_str_alloc←2← 8C4E BNE← 8C55 BNE | |||||||||
| TXA ; New heap top = top + allocation | ||||||||||
| 8C60 | CLC ; (clear carry) | |||||||||
| 8C61 | ADC zp_vartop ; + heap top low, | |||||||||
| 8C63 | TAY ; (low in Y) | |||||||||
| 8C64 | LDA zp_vartop_1 ; heap top high... | |||||||||
| 8C66 | ADC #0 ; + carry (new top high) | |||||||||
| 8C68 | CPY zp_stack_ptr ; collides with the stack? | |||||||||
| 8C6A | TAX ; (keep the new top high) | |||||||||
| 8C6B | SBC zp_stack_ptr_1 ; new top - stack pointer | |||||||||
| 8C6D | BCS err_no_room ; yes: No room | |||||||||
| 8C6F | STY zp_vartop ; Commit the new heap top | |||||||||
| 8C71 | STX zp_vartop_1 ; (high) | |||||||||
| 8C73 | PLA ; Store the new allocation size | |||||||||
| 8C74 | LDY #2 ; offset 2 | |||||||||
| 8C76 | STA (zp_iwa),y ; (store) | |||||||||
| 8C78 | DEY ; Store the new data address | |||||||||
| 8C79 | LDA zp_iwa_3 ; data address high | |||||||||
| 8C7B | BEQ assign_str_store ; extended in place: keep the address | |||||||||
| 8C7D | STA (zp_iwa),y ; store the data high, | |||||||||
| 8C7F | DEY ; offset 0 | |||||||||
| 8C80 | LDA zp_iwa_2 ; data low... | |||||||||
| 8C82 | STA (zp_iwa),y ; (store) | |||||||||
| 8C84 | .assign_str_store←2← 8C2D BCS← 8C7B BEQ | |||||||||
| LDY #3 ; Store the current length | ||||||||||
| 8C86 | LDA zp_strbuf_len ; the length | |||||||||
| 8C88 | STA (zp_iwa),y ; (store) | |||||||||
| 8C8A | BEQ return_5 ; empty string: done | |||||||||
| 8C8C | DEY ; Fetch the data address | |||||||||
| 8C8D | DEY ; (to offset 1) | |||||||||
| 8C8E | LDA (zp_iwa),y ; high... | |||||||||
| 8C90 | STA zp_iwa_3 ; (high) | |||||||||
| 8C92 | DEY ; offset 0 | |||||||||
| 8C93 | LDA (zp_iwa),y ; low... | |||||||||
| 8C95 | STA zp_iwa_2 ; (low) | |||||||||
| 8C97 | .assign_str_copy_loop←1← 8C9F BNE | |||||||||
| LDA string_work,y ; Copy the string buffer to the storage | ||||||||||
| 8C9A | STA (zp_iwa_2),y ; to storage | |||||||||
| 8C9C | INY ; next | |||||||||
| 8C9D | CPY zp_strbuf_len ; done? | |||||||||
| 8C9F | BNE assign_str_copy_loop ; loop | |||||||||
| 8CA1 | .return_5←1← 8C8A BEQ | |||||||||
| RTS ; Return | ||||||||||
| 8CA2 | .assign_str_addr←1← 8C25 BEQ | |||||||||
| JSR terminate_strbuf ; $addr: prepare the destination | ||||||||||
| 8CA5 | CPY #0 ; empty string? | |||||||||
| 8CA7 | BEQ assign_str_addr_cr ; yes: just the terminator | |||||||||
| 8CA9 | .assign_str_addr_loop←1← 8CAF BNE | |||||||||
| LDA string_work,y ; Copy the string to the address | ||||||||||
| 8CAC | STA (zp_iwa),y ; store it | |||||||||
| 8CAE | DEY ; next (downwards) | |||||||||
| 8CAF | BNE assign_str_addr_loop ; loop | |||||||||
| 8CB1 | LDA string_work ; First character | |||||||||
| 8CB4 | .assign_str_addr_cr←1← 8CA7 BEQ | |||||||||
| STA (zp_iwa),y ; Store it (with the CR terminator following) | ||||||||||
| 8CB6 | RTS ; Return | |||||||||
Raise the "No room" errorRaise BASIC error &00, "No room", via a BRK error block. Reached when there is insufficient memory for the requested operation. Does not return.
|
||||
| 8CB7 | .err_no_room←3← 8C6D BCS← 9553 JMP← BE41 JMP | |||
| BRK ; No room error | ||||
| 8CB8 | EQUB &00 | |||
| 8CB9 | EQUS "No room" | |||
| 8CC0 | EQUB &00 | |||
Restore a stacked value into a variablePop the value on top of the BASIC stack into the variable at zp_general, dispatched by the type/size byte: a numeric value of that many bytes, a $addr string (CR terminated), or a string variable (copied into its heap allocation). Used by the FN/PROC LOCAL and parameter machinery.
|
|||||||||||||
| 8CC1 | .unstack_value_to_var←1← B21F JSR | ||||||||||||
| LDA zp_fileblk ; Type/size byte | |||||||||||||
| 8CC3 | CMP #&80 ; $addr string? | ||||||||||||
| 8CC5 | BEQ unstack_addr ; yes | ||||||||||||
| 8CC7 | BCC unstack_numeric ; numeric? | ||||||||||||
| 8CC9 | LDY #0 ; String variable: length on the stack | ||||||||||||
| 8CCB | LDA (zp_stack_ptr),y ; read the length, | ||||||||||||
| 8CCD | TAX ; into X as the byte count | ||||||||||||
| 8CCE | BEQ unstack_str_setlen ; empty: just set the length | ||||||||||||
| 8CD0 | LDA (zp_general),y ; Data address - 1 (for 1-based copy) | ||||||||||||
| 8CD2 | SBC #1 ; low byte - 1, | ||||||||||||
| 8CD4 | STA zp_fileblk ; dest pointer low (&39), | ||||||||||||
| 8CD6 | INY ; next | ||||||||||||
| 8CD7 | LDA (zp_general),y ; high byte | ||||||||||||
| 8CD9 | SBC #0 ; - borrow, | ||||||||||||
| 8CDB | STA zp_fileblk_1 ; dest pointer high (&3A) | ||||||||||||
| 8CDD | .unstack_str_copy←1← 8CE3 BNE | ||||||||||||
| LDA (zp_stack_ptr),y ; Copy the string bytes | |||||||||||||
| 8CDF | STA (zp_fileblk),y ; into the heap allocation, | ||||||||||||
| 8CE1 | INY ; next byte, | ||||||||||||
| 8CE2 | DEX ; count down | ||||||||||||
| 8CE3 | BNE unstack_str_copy ; loop | ||||||||||||
| 8CE5 | .unstack_str_setlen←1← 8CCE BEQ | ||||||||||||
| LDA (zp_stack_ptr,x) ; String length | |||||||||||||
| 8CE7 | LDY #3 ; descriptor offset 3 | ||||||||||||
| 8CE9 | .unstack_str_drop←1← 8D01 BNE | ||||||||||||
| STA (zp_general),y ; Store the length | |||||||||||||
| 8CEB | JMP drop_stacked_string ; drop the value from the stack | ||||||||||||
| 8CEE | .unstack_addr←1← 8CC5 BEQ | ||||||||||||
| LDY #0 ; $addr: length on the stack | |||||||||||||
| 8CF0 | LDA (zp_stack_ptr),y ; read the length, | ||||||||||||
| 8CF2 | TAX ; into X as the count | ||||||||||||
| 8CF3 | BEQ unstack_addr_cr ; empty: just the terminator | ||||||||||||
| 8CF5 | .unstack_addr_copy←1← 8CFD BNE | ||||||||||||
| INY ; Copy the string to the address | |||||||||||||
| 8CF6 | LDA (zp_stack_ptr),y ; read a char from the stack, | ||||||||||||
| 8CF8 | DEY ; back to the destination offset, | ||||||||||||
| 8CF9 | STA (zp_general),y ; store it at the address, | ||||||||||||
| 8CFB | INY ; advance, | ||||||||||||
| 8CFC | DEX ; count down | ||||||||||||
| 8CFD | BNE unstack_addr_copy ; loop | ||||||||||||
| 8CFF | .unstack_addr_cr←1← 8CF3 BEQ | ||||||||||||
| LDA #&0d ; CR terminator | |||||||||||||
| 8D01 | BNE unstack_str_drop ; store it | ||||||||||||
| 8D03 | .unstack_numeric←1← 8CC7 BCC | ||||||||||||
| LDY #0 ; Numeric: copy byte 0 | |||||||||||||
| 8D05 | LDA (zp_stack_ptr),y ; read it, | ||||||||||||
| 8D07 | STA (zp_general),y ; store it, | ||||||||||||
| 8D09 | INY ; next byte | ||||||||||||
| 8D0A | CPY zp_fileblk ; all bytes done? | ||||||||||||
| 8D0C | BCS unstack_numeric_drop ; yes | ||||||||||||
| 8D0E | LDA (zp_stack_ptr),y ; Copy byte 1 | ||||||||||||
| 8D10 | STA (zp_general),y ; store it | ||||||||||||
| 8D12 | INY ; byte 2 | ||||||||||||
| 8D13 | LDA (zp_stack_ptr),y ; read it, | ||||||||||||
| 8D15 | STA (zp_general),y ; store it, | ||||||||||||
| 8D17 | INY ; byte 3 | ||||||||||||
| 8D18 | LDA (zp_stack_ptr),y ; read it, | ||||||||||||
| 8D1A | STA (zp_general),y ; store it, | ||||||||||||
| 8D1C | INY ; next byte | ||||||||||||
| 8D1D | CPY zp_fileblk ; all bytes done? | ||||||||||||
| 8D1F | BCS unstack_numeric_drop ; yes | ||||||||||||
| 8D21 | LDA (zp_stack_ptr),y ; byte 4 (real only) | ||||||||||||
| 8D23 | STA (zp_general),y ; store it, | ||||||||||||
| 8D25 | INY ; next byte | ||||||||||||
| 8D26 | .unstack_numeric_drop←2← 8D0C BCS← 8D1F BCS | ||||||||||||
| TYA ; Bytes copied | |||||||||||||
| 8D27 | CLC ; carry clear for the stack drop | ||||||||||||
| 8D28 | JMP drop_string_adv ; drop them from the stack | ||||||||||||
| 8D2B | .print_file←1← 8D9F BEQ | ||||||||||||
| DEC zp_text_ptr_off ; Back up over "#" | |||||||||||||
| 8D2D | JSR sync_ptrb_from_ptra ; Get the file handle | ||||||||||||
| 8D30 | .print_file_loop←4← 8D55 BMI← 8D62 BMI← 8D6A BEQ← 8D75 BEQ | ||||||||||||
| TYA ; Save the handle | |||||||||||||
| 8D31 | PHA ; (push it) | ||||||||||||
| 8D32 | JSR skip_spaces_ptr2 ; Skip spaces | ||||||||||||
| 8D35 | CMP #',' ; ',' another value? | ||||||||||||
| 8D37 | BNE print_file_done ; no: done | ||||||||||||
| 8D39 | JSR eval_or_eor ; Evaluate the value | ||||||||||||
| 8D3C | JSR fwa_pack_temp1 ; pack it (in case real) | ||||||||||||
| 8D3F | PLA ; Recover the handle | ||||||||||||
| 8D40 | TAY ; into Y for OSBPUT | ||||||||||||
| 8D41 | LDA zp_var_type ; Type byte | ||||||||||||
| 8D43 | JSR osbput ; write it | ||||||||||||
| 8D46 | TAX ; examine the type byte | ||||||||||||
| 8D47 | BEQ print_file_str ; string? | ||||||||||||
| 8D49 | BMI print_file_real ; real? | ||||||||||||
| 8D4B | LDX #3 ; Integer: 4 bytes | ||||||||||||
| 8D4D | .print_file_int_loop←1← 8D53 BPL | ||||||||||||
| LDA zp_iwa,x ; Write a byte | |||||||||||||
| 8D4F | JSR osbput ; send it, | ||||||||||||
| 8D52 | DEX ; next byte (MSB first) | ||||||||||||
| 8D53 | BPL print_file_int_loop ; loop | ||||||||||||
| 8D55 | BMI print_file_loop ; next value | ||||||||||||
| 8D57 | .print_file_real←1← 8D49 BMI | ||||||||||||
| LDX #4 ; Real: 5 bytes | |||||||||||||
| 8D59 | .print_file_real_loop←1← 8D60 BPL | ||||||||||||
| LDA fp_temp1,x ; Write a byte | |||||||||||||
| 8D5C | JSR osbput ; send it, | ||||||||||||
| 8D5F | DEX ; next byte (MSB first) | ||||||||||||
| 8D60 | BPL print_file_real_loop ; loop | ||||||||||||
| 8D62 | BMI print_file_loop ; next value | ||||||||||||
| 8D64 | .print_file_str←1← 8D47 BEQ | ||||||||||||
| LDA zp_strbuf_len ; String: write the length | |||||||||||||
| 8D66 | JSR osbput ; send it, | ||||||||||||
| 8D69 | TAX ; empty string? | ||||||||||||
| 8D6A | BEQ print_file_loop ; empty | ||||||||||||
| 8D6C | .print_file_str_loop←1← 8D73 BNE | ||||||||||||
| LDA strbuf_base,x ; Write a character | |||||||||||||
| 8D6F | JSR osbput ; send it, | ||||||||||||
| 8D72 | DEX ; next character (written in reverse) | ||||||||||||
| 8D73 | BNE print_file_str_loop ; loop | ||||||||||||
| 8D75 | BEQ print_file_loop ; next value | ||||||||||||
| 8D77 | .print_file_done←1← 8D37 BNE | ||||||||||||
| PLA ; Recover the handle | |||||||||||||
| 8D78 | STY zp_text_ptr_off ; sync the pointer | ||||||||||||
| 8D7A | JMP stmt_check_end ; next statement | ||||||||||||
| 8D7D | .print_newline←3← 8DC8 BEQ← 8DCC BEQ← 8DD0 BEQ | ||||||||||||
| JSR emit_newline ; Print a newline | |||||||||||||
| 8D80 | .print_done←3← 8D8E BEQ← 8D92 BEQ← 8D96 BEQ | ||||||||||||
| JMP stmt_backup_end ; next statement | |||||||||||||
| 8D83 | .print_semicolon←1← 8DDC BEQ | ||||||||||||
| LDA #0 ; Semicolon: clear the field width... | |||||||||||||
| 8D85 | STA zp_print_bytes ; the field width, | ||||||||||||
| 8D87 | STA zp_print_flag ; ...and flags | ||||||||||||
| 8D89 | JSR skip_spaces ; Next non-space character | ||||||||||||
| 8D8C | CMP #':' ; ':' end? | ||||||||||||
| 8D8E | BEQ print_done ; yes: end without a newline | ||||||||||||
| 8D90 | CMP #&0d ; end of line? | ||||||||||||
| 8D92 | BEQ print_done ; yes | ||||||||||||
| 8D94 | CMP #&8b ; ELSE? | ||||||||||||
| 8D96 | BEQ print_done ; yes | ||||||||||||
| 8D98 | BNE print_check_sep ; otherwise continue the print loop | ||||||||||||
| fall through ↓ | |||||||||||||
Print expressions to the screen, or a file with #, with formatting controlled by @% and separators. PRINT [~][items][;][,].
|
|||||||||||
| 8D9A | .stmt_print | ||||||||||
| JSR skip_spaces ; Next non-space character | |||||||||||
| 8D9D | CMP #'#' ; A leading # directs output to a file (PRINT#) | ||||||||||
| 8D9F | BEQ print_file ; '#': PRINT# to a file | ||||||||||
| 8DA1 | DEC zp_text_ptr_off ; Back up over the character | ||||||||||
| 8DA3 | JMP print_item ; enter the print loop | ||||||||||
| 8DA6 | .print_comma←1← 8DD8 BEQ | ||||||||||
| LDA resint_at ; Comma: pad with spaces to the next @% field | |||||||||||
| 8DA9 | BEQ print_item ; zero: no padding | ||||||||||
| 8DAB | LDA zp_count ; Current column (COUNT) | ||||||||||
| 8DAD | .print_field_loop←1← 8DB2 BCS | ||||||||||
| BEQ print_item ; at column 0: no padding | |||||||||||
| 8DAF | SBC resint_at ; reduce by the field width... | ||||||||||
| 8DB2 | BCS print_field_loop ; ...until COUNT mod width | ||||||||||
| 8DB4 | TAY ; spaces needed to the next field | ||||||||||
| 8DB5 | .print_pad_loop←1← 8DB9 BNE | ||||||||||
| JSR print_space ; print a space | |||||||||||
| 8DB8 | INY ; count up to zero | ||||||||||
| 8DB9 | BNE print_pad_loop ; loop | ||||||||||
| 8DBB | .print_item←3← 8DA3 JMP← 8DA9 BEQ← 8DAD BEQ | ||||||||||
| CLC ; Prepare for decimal | |||||||||||
| 8DBC | LDA resint_at ; Take the field width from @% (&0400) | ||||||||||
| 8DBF | STA zp_print_bytes ; as the print field width | ||||||||||
| 8DC1 | .print_set_hex←1← 8DD4 BEQ | ||||||||||
| ROR zp_print_flag ; Set the hex/dec flag (~ selects hex) | |||||||||||
| 8DC3 | .print_next←3← 8DE1 BCC← 8E10 BEQ← 8E1F BEQ | ||||||||||
| JSR skip_spaces ; Next non-space character | |||||||||||
| 8DC6 | CMP #':' ; ':' end of statement? | ||||||||||
| 8DC8 | BEQ print_newline ; yes | ||||||||||
| 8DCA | CMP #&0d ; end of line? | ||||||||||
| 8DCC | BEQ print_newline ; yes | ||||||||||
| 8DCE | CMP #&8b ; ELSE? | ||||||||||
| 8DD0 | BEQ print_newline ; yes | ||||||||||
| 8DD2 | .print_check_sep←1← 8D98 BNE | ||||||||||
| CMP #'~' ; '~' hex mode? | |||||||||||
| 8DD4 | BEQ print_set_hex ; yes: set the flag | ||||||||||
| 8DD6 | CMP #',' ; Comma: advance to the next print field | ||||||||||
| 8DD8 | BEQ print_comma ; yes | ||||||||||
| 8DDA | CMP #';' ; Semicolon: print the next item with no gap | ||||||||||
| 8DDC | BEQ print_semicolon ; yes | ||||||||||
| 8DDE | JSR print_special_item ; Handle the ' TAB and SPC print items | ||||||||||
| 8DE1 | BCC print_next ; handled: next item | ||||||||||
| 8DE3 | LDA zp_print_bytes ; Save the field width... | ||||||||||
| 8DE5 | PHA ; push it | ||||||||||
| 8DE6 | LDA zp_print_flag ; ...and flags (the evaluator may PRINT) | ||||||||||
| 8DE8 | PHA ; push it | ||||||||||
| 8DE9 | DEC zp_text_ptr2_off ; Back up to the item | ||||||||||
| 8DEB | JSR eval_or_eor ; Evaluate the expression to print | ||||||||||
| 8DEE | PLA ; Restore the flags... | ||||||||||
| 8DEF | STA zp_print_flag ; store them | ||||||||||
| 8DF1 | PLA ; ...and the field width | ||||||||||
| 8DF2 | STA zp_print_bytes ; store it | ||||||||||
| 8DF4 | LDA zp_text_ptr2_off ; Update the program pointer | ||||||||||
| 8DF6 | STA zp_text_ptr_off ; from PtrB offset (&1B) | ||||||||||
| 8DF8 | TYA ; String item? | ||||||||||
| 8DF9 | BEQ print_string ; A string value: print it directly | ||||||||||
| 8DFB | JSR number_to_ascii ; A number: convert to an ASCII string | ||||||||||
| 8DFE | LDA zp_print_bytes ; and right-justify it within the field width | ||||||||||
| 8E00 | SEC ; minus the string length | ||||||||||
| 8E01 | SBC zp_strbuf_len ; width - string length = pad count | ||||||||||
| 8E03 | BCC print_string ; longer than the field: print as is | ||||||||||
| 8E05 | BEQ print_string ; equal: print as is | ||||||||||
| 8E07 | TAY ; spaces to pad with | ||||||||||
| 8E08 | .print_num_pad←1← 8E0C BNE | ||||||||||
| JSR print_space ; print a leading space | |||||||||||
| 8E0B | DEY ; one fewer pad space | ||||||||||
| 8E0C | BNE print_num_pad ; loop | ||||||||||
| 8E0E | .print_string←3← 8DF9 BEQ← 8E03 BCC← 8E05 BEQ | ||||||||||
| LDA zp_strbuf_len ; String length | |||||||||||
| 8E10 | BEQ print_next ; empty: next item | ||||||||||
| 8E12 | LDY #0 ; From the start | ||||||||||
| 8E14 | .print_string_loop←1← 8E1D BNE | ||||||||||
| LDA string_work,y ; String character | |||||||||||
| 8E17 | JSR print_char ; print it | ||||||||||
| 8E1A | INY ; next | ||||||||||
| 8E1B | CPY zp_strbuf_len ; printed all characters? | ||||||||||
| 8E1D | BNE print_string_loop ; loop | ||||||||||
| 8E1F | BEQ print_next ; next item | ||||||||||
| 8E21 | .print_tab_error←1← 8E26 BNE | ||||||||||
| JMP missing_comma ; Missing , error | |||||||||||
| 8E24 | .print_tab_xy←1← 8E48 BNE | ||||||||||
| CMP #',' ; ',' TAB(x,y) form? | |||||||||||
| 8E26 | BNE print_tab_error ; no: TAB(x) or SPC | ||||||||||
| 8E28 | LDA zp_iwa ; Save the x coordinate | ||||||||||
| 8E2A | PHA ; push it | ||||||||||
| 8E2B | JSR eval_subexpr ; Evaluate y, expect ) | ||||||||||
| 8E2E | JSR coerce_to_integer ; coerce to integer | ||||||||||
| 8E31 | LDA #&1f ; VDU 31 (move cursor) | ||||||||||
| 8E33 | JSR oswrch ; send the VDU 31 control code | ||||||||||
| 8E36 | PLA ; x coordinate | ||||||||||
| 8E37 | JSR oswrch ; send the x coordinate | ||||||||||
| 8E3A | JSR vdu_send_byte ; y coordinate | ||||||||||
| 8E3D | JMP print_sync ; next item | ||||||||||
| 8E40 | .print_tab_x←1← 8E82 BEQ | ||||||||||
| JSR eval_expr_integer ; TAB(x): evaluate x | |||||||||||
| 8E43 | JSR skip_spaces_ptr2 ; skip spaces | ||||||||||
| 8E46 | CMP #')' ; ')'? | ||||||||||
| 8E48 | BNE print_tab_xy ; no: TAB(x,y) | ||||||||||
| 8E4A | LDA zp_iwa ; Spaces = x - COUNT | ||||||||||
| 8E4C | SBC zp_count ; subtract the current column | ||||||||||
| 8E4E | BEQ print_sync ; already at column x: nothing to do | ||||||||||
| 8E50 | TAY ; count | ||||||||||
| 8E51 | BCS print_spc_loop ; past column x: skip | ||||||||||
| 8E53 | JSR emit_newline ; Newline to reach a fresh line | ||||||||||
| 8E56 | BEQ print_spc_count ; fresh line: pad to column x | ||||||||||
| 8E58 | .print_spc←1← 8E86 BEQ | ||||||||||
| JSR eval_factor_integer ; SPC(n): evaluate the count | |||||||||||
| 8E5B | .print_spc_count←1← 8E56 BEQ | ||||||||||
| LDY zp_iwa ; spaces = x | |||||||||||
| 8E5D | BEQ print_sync ; none | ||||||||||
| 8E5F | .print_spc_loop←2← 8E51 BCS← 8E63 BNE | ||||||||||
| JSR print_space ; Print a space | |||||||||||
| 8E62 | DEY ; one fewer space | ||||||||||
| 8E63 | BNE print_spc_loop ; loop | ||||||||||
| 8E65 | BEQ print_sync ; next item | ||||||||||
| 8E67 | .print_spc_newline←1← 8E7E BEQ | ||||||||||
| JSR emit_newline ; SPC: print a newline | |||||||||||
| 8E6A | .print_sync←5← 8E3D JMP← 8E4E BEQ← 8E5D BEQ← 8E65 BEQ← 8EB9 BNE | ||||||||||
| CLC ; Sync the program pointer | |||||||||||
| 8E6B | LDY zp_text_ptr2_off ; load PtrB offset (&1B), | ||||||||||
| 8E6D | STY zp_text_ptr_off ; store to PtrA offset (&0A) | ||||||||||
| 8E6F | RTS ; Return | ||||||||||
Handle the PRINT ' TAB and SPC itemsRecognise and act on the special PRINT items: apostrophe (force a newline), TAB(x[,y]) and SPC(n). Returns carry clear when it consumed one, so the caller skips ordinary expression printing.
|
|||||||||||
| 8E70 | .print_special_item←2← 8DDE JSR← 8E8D JSR | ||||||||||
| LDX zp_text_ptr ; Save PtrA into PtrB: low | |||||||||||
| 8E72 | STX zp_text_ptr2 ; store it | ||||||||||
| 8E74 | LDX zp_text_ptr_1 ; high | ||||||||||
| 8E76 | STX zp_text_ptr2_1 ; store it | ||||||||||
| 8E78 | LDX zp_text_ptr_off ; offset | ||||||||||
| 8E7A | STX zp_text_ptr2_off ; store it | ||||||||||
| 8E7C | CMP #ASC("'") ; an apostrophe? | ||||||||||
| 8E7E | BEQ print_spc_newline ; yes: force a newline | ||||||||||
| 8E80 | CMP #&8a ; TAB token? | ||||||||||
| 8E82 | BEQ print_tab_x ; yes: handle TAB | ||||||||||
| 8E84 | CMP #&89 ; SPC token? | ||||||||||
| 8E86 | BEQ print_spc ; yes: handle SPC | ||||||||||
| 8E88 | SEC ; none: not consumed (carry set) | ||||||||||
| 8E89 | .return_6←1← 8E90 BCC | ||||||||||
| RTS ; Return | |||||||||||
Skip spaces then handle a PRINT special itemSkip spaces at PtrA, then dispatch the next PRINT item to print_special_item (which handles ~, TAB, SPC, ' and so on). If that consumed the item, return with carry clear; if the next character is a string literal (a double-quote), print it inline via print_inline_loop; otherwise return with carry set, leaving the character in A.
|
|||||||||||
| 8E8A | .print_special_skip←2← BA5A JSR← BA5F JSR | ||||||||||
| JSR skip_spaces ; Skip spaces, then handle a special item | |||||||||||
| 8E8D | JSR print_special_item ; handle it | ||||||||||
| 8E90 | BCC return_6 ; consumed: done | ||||||||||
| 8E92 | CMP #'"' ; a string literal (quote)? | ||||||||||
| 8E94 | BEQ print_inline_loop ; yes: print it inline | ||||||||||
| 8E96 | SEC ; not consumed | ||||||||||
| 8E97 | RTS ; Return | ||||||||||
| 8E98 | .missing_quote←2← 8EAC BEQ← ADE9 JMP | ||||||||||
| BRK ; Missing " error block | |||||||||||
| 8E99 | EQUB &09 | ||||||||||
| 8E9A | EQUS "Missing ", &22 | ||||||||||
| 8EA3 | EQUB &00 | ||||||||||
| 8EA4 | .print_inline_char←2← 8EB0 BNE← 8EBB BEQ | ||||||||||
| JSR print_char ; print a character | |||||||||||
| 8EA7 | .print_inline_loop←1← 8E94 BEQ | ||||||||||
| INY ; Print the inline string: advance | |||||||||||
| 8EA8 | LDA (zp_text_ptr2),y ; char | ||||||||||
| 8EAA | CMP #&0d ; CR (unterminated)? | ||||||||||
| 8EAC | BEQ missing_quote ; Missing " error | ||||||||||
| 8EAE | CMP #'"' ; a quote? | ||||||||||
| 8EB0 | BNE print_inline_char ; no: print it | ||||||||||
| 8EB2 | INY ; advance | ||||||||||
| 8EB3 | STY zp_text_ptr2_off ; update the offset | ||||||||||
| 8EB5 | LDA (zp_text_ptr2),y ; doubled ""? | ||||||||||
| 8EB7 | CMP #'"' ; is it another quote? | ||||||||||
| 8EB9 | BNE print_sync ; no: end of the string | ||||||||||
| 8EBB | BEQ print_inline_char ; yes: print one quote | ||||||||||
| fall through ↓ | |||||||||||
CLGClear the graphics window to the graphics background colour. CLG.
|
|||||||||||
| 8EBD | .stmt_clg | ||||||||||
| JSR check_end_of_statement ; Check the statement ends | |||||||||||
| 8EC0 | LDA #&10 ; VDU 16 (clear graphics) | ||||||||||
| 8EC2 | BNE cls_send ; send it | ||||||||||
| fall through ↓ | |||||||||||
CLSClear the text window to the text background colour. CLS.
|
|||||||||||
| 8EC4 | .stmt_cls | ||||||||||
| JSR check_end_of_statement ; Check the statement ends | |||||||||||
| 8EC7 | JSR reset_print_column ; Reset the print column | ||||||||||
| 8ECA | LDA #&0c ; VDU 12 (clear screen) | ||||||||||
| 8ECC | .cls_send←1← 8EC2 BNE | ||||||||||
| JSR oswrch ; send it | |||||||||||
| 8ECF | JMP statement_loop ; next statement | ||||||||||
CALLCall machine code, passing the resident integer variables and an optional parameter block. CALL address [,params...].
|
|||||||||||
| 8ED2 | .stmt_call | ||||||||||
| JSR eval_expr ; Evaluate the call address | |||||||||||
| 8ED5 | JSR coerce_var_to_integer ; coerce to an integer | ||||||||||
| 8ED8 | JSR stack_integer ; stack the address | ||||||||||
| 8EDB | LDY #0 ; Build the parameter block at &0600: | ||||||||||
| 8EDD | STY string_work ; zero the parameter count | ||||||||||
| 8EE0 | .call_block_init←1← 8F09 JMP | ||||||||||
| STY call_block_base ; reset the block write offset | |||||||||||
| 8EE3 | JSR skip_spaces_ptr2 ; next parameter? | ||||||||||
| 8EE6 | CMP #',' ; a comma? | ||||||||||
| 8EE8 | BNE call_check_end ; no: end of the parameters | ||||||||||
| 8EEA | LDY zp_text_ptr2_off ; parse the parameter (a variable) | ||||||||||
| 8EEC | JSR pvr_record_offset ; resolve it to an address | ||||||||||
| 8EEF | BEQ call_param_error ; bad parameter: error | ||||||||||
| 8EF1 | LDY call_block_base ; append its address to the block: | ||||||||||
| 8EF4 | INY ; advance to the next slot | ||||||||||
| 8EF5 | LDA zp_iwa ; address low | ||||||||||
| 8EF7 | STA string_work,y ; store it | ||||||||||
| 8EFA | INY ; next slot | ||||||||||
| 8EFB | LDA zp_iwa_1 ; address high | ||||||||||
| 8EFD | STA string_work,y ; store it | ||||||||||
| 8F00 | INY ; next slot | ||||||||||
| 8F01 | LDA zp_iwa_2 ; type | ||||||||||
| 8F03 | STA string_work,y ; store it | ||||||||||
| 8F06 | INC string_work ; one more parameter | ||||||||||
| 8F09 | JMP call_block_init ; next parameter | ||||||||||
| 8F0C | .call_check_end←1← 8EE8 BNE | ||||||||||
| DEC zp_text_ptr2_off ; Check for end of statement | |||||||||||
| 8F0E | JSR sync_text_ptr ; error if more follows | ||||||||||
| 8F11 | JSR unstack_integer ; pop the address into IWA | ||||||||||
| 8F14 | JSR usr_call ; set up registers and call the code | ||||||||||
| 8F17 | CLD ; clear decimal mode on return | ||||||||||
| 8F18 | JMP statement_loop ; Back to execution | ||||||||||
| 8F1B | .call_param_error←1← 8EEF BEQ | ||||||||||
| JMP no_such_variable ; parameter error (shared) | |||||||||||
Call user machine code (USR/CALL)Load A, X, Y and the carry from the resident integer variables A%, X%, Y% and C%, then JMP (IWA) to the user routine. Its RTS returns to usr_call's caller, which captures the registers back.
|
|||||||||||||||
| 8F1E | .usr_call←2← 8F14 JSR← ABD5 JSR | ||||||||||||||
| LDA resint_c ; C% supplies the carry... | |||||||||||||||
| 8F21 | LSR ; ...shifted into the carry flag | ||||||||||||||
| 8F22 | LDA resint_a ; A from A% | ||||||||||||||
| 8F25 | LDX resint_x ; X from X% | ||||||||||||||
| 8F28 | LDY resint_y ; Y from Y% | ||||||||||||||
| 8F2B | JMP (zp_iwa) ; Call the routine at the address in IWA | ||||||||||||||
| 8F2E | .call_arg_error←3← 8F34 BCC← 8F3E BNE← 8F43 BCC | ||||||||||||||
| JMP syntax_error ; error (shared) | |||||||||||||||
DELETEDelete a range of program lines. DELETE start, end.
|
|||||||||||
| 8F31 | .stmt_delete | ||||||||||
| JSR check_line_number ; Read the start line number | |||||||||||
| 8F34 | BCC call_arg_error ; none: Syntax error | ||||||||||
| 8F36 | JSR stack_integer ; stack it | ||||||||||
| 8F39 | JSR skip_spaces ; Skip spaces | ||||||||||
| 8F3C | CMP #',' ; ','? | ||||||||||
| 8F3E | BNE call_arg_error ; no: error | ||||||||||
| 8F40 | JSR check_line_number ; Read the end line number | ||||||||||
| 8F43 | BCC call_arg_error ; none: error | ||||||||||
| 8F45 | JSR check_end_of_statement ; check the statement ends | ||||||||||
| 8F48 | LDA zp_iwa ; Save the end line | ||||||||||
| 8F4A | STA zp_fileblk ; low to &39, | ||||||||||
| 8F4C | LDA zp_iwa_1 ; high byte, | ||||||||||
| 8F4E | STA zp_fileblk_1 ; to &3A | ||||||||||
| 8F50 | JSR unstack_integer ; Recover the start line | ||||||||||
| 8F53 | .delete_loop←1← 8F64 BCS | ||||||||||
| JSR delete_program_line ; Delete the line | |||||||||||
| 8F56 | JSR check_escape ; Find the next line number | ||||||||||
| 8F59 | JSR iwa_inc ; Advance the line counter | ||||||||||
| 8F5C | LDA zp_fileblk ; past the end line? | ||||||||||
| 8F5E | CMP zp_iwa ; end low - line low, | ||||||||||
| 8F60 | LDA zp_fileblk_1 ; end high, | ||||||||||
| 8F62 | SBC zp_iwa_1 ; - line high | ||||||||||
| 8F64 | BCS delete_loop ; no: delete the next | ||||||||||
| 8F66 | JMP clear_then_immediate ; done: immediate mode | ||||||||||
Parse an optional start,step line-number rangeParse the optional [start[,step]] arguments shared by AUTO and RENUMBER: default the start line to 10, read an explicit start if present and push it on the BASIC stack; then default the step to 10 and, if a comma follows, read an explicit step, raising "Silly" if the step is zero. Tail-calls check_end_of_statement to verify nothing else follows.
|
|||||||||||
| 8F69 | .parse_line_range←2← 8FA3 JSR← 90AC JSR | ||||||||||
| LDA #&0a ; Default start = 10 | |||||||||||
| 8F6B | JSR int_result_a ; IWA = 10 | ||||||||||
| 8F6E | JSR check_line_number ; Read the start line if given | ||||||||||
| 8F71 | JSR stack_integer ; stack it | ||||||||||
| 8F74 | LDA #&0a ; Default increment = 10 | ||||||||||
| 8F76 | JSR int_result_a ; IWA = 10 | ||||||||||
| 8F79 | JSR skip_spaces ; Skip spaces | ||||||||||
| 8F7C | CMP #',' ; ',' increment given? | ||||||||||
| 8F7E | BNE range_backup ; no: use the default | ||||||||||
| 8F80 | JSR check_line_number ; Read the increment | ||||||||||
| 8F83 | LDA zp_iwa_1 ; zero? | ||||||||||
| 8F85 | BNE silly_error ; no | ||||||||||
| 8F87 | LDA zp_iwa ; low byte zero too? | ||||||||||
| 8F89 | BEQ silly_error ; zero increment: error | ||||||||||
| 8F8B | INC zp_text_ptr_off ; step past | ||||||||||
| 8F8D | .range_backup←1← 8F7E BNE | ||||||||||
| DEC zp_text_ptr_off ; back up | |||||||||||
| 8F8F | JMP check_end_of_statement ; check the statement ends | ||||||||||
Point the RENUMBER scan pointers at TOP and PAGECopy TOP (&12/&13) into the table pointer at &3B/&3C, then fall into point_general_page to set the program-scan pointer at &37/&38 to PAGE (low byte forced to 1, the first line-number byte). Used by RENUMBER to initialise the old-number table (built from the heap at TOP) and the pointer that walks the program from PAGE.
|
|||||||||||||
| 8F92 | .setup_scan_top←2← 8FAE JSR← 9040 JSR | ||||||||||||
| LDA zp_top ; Copy TOP to &3B/&3C | |||||||||||||
| 8F94 | STA zp_fwb_sign ; low to &3B, | ||||||||||||
| 8F96 | LDA zp_top_1 ; high byte, | ||||||||||||
| 8F98 | STA zp_fwb_ovf ; to &3C | ||||||||||||
| 8F9A | .point_general_page←1← 8FE7 JSR | ||||||||||||
| LDA zp_page ; Point &37/&38 at PAGE | |||||||||||||
| 8F9C | STA zp_general_1 ; page to &38, | ||||||||||||
| 8F9E | LDA #1 ; offset 1, | ||||||||||||
| 8FA0 | STA zp_general ; low byte &37 | ||||||||||||
| 8FA2 | RTS ; Return | ||||||||||||
RENUMBERRenumber program lines and fix up line references. RENUMBER [start[,step]].
|
|||||||||||
| 8FA3 | .stmt_renumber | ||||||||||
| JSR parse_line_range ; Parse the start and step arguments | |||||||||||
| 8FA6 | LDX #&39 ; Pop the step into the file block (&39) | ||||||||||
| 8FA8 | JSR unstack_int_to_zp ; (pop it) | ||||||||||
| 8FAB | JSR check_program ; Pop the start number | ||||||||||
| 8FAE | JSR setup_scan_top ; Point at the program start and the table | ||||||||||
| 8FB1 | .renum_pass1_loop←1← 8FD4 BCC | ||||||||||
| LDY #0 ; Pass 1: for each line, read its number | |||||||||||
| 8FB3 | LDA (zp_general),y ; high byte | ||||||||||
| 8FB5 | BMI renum_pass2 ; high bit set marks the end of program | ||||||||||
| 8FB7 | STA (zp_fwb_sign),y ; Store the old number in the table | ||||||||||
| 8FB9 | INY ; low byte | ||||||||||
| 8FBA | LDA (zp_general),y ; read the line number low | ||||||||||
| 8FBC | STA (zp_fwb_sign),y ; (store) | ||||||||||
| 8FBE | SEC ; Advance the table pointer by 2: low | ||||||||||
| 8FBF | TYA ; offset to A, | ||||||||||
| 8FC0 | ADC zp_fwb_sign ; + table pointer (carry adds 2) | ||||||||||
| 8FC2 | STA zp_fwb_sign ; (store) | ||||||||||
| 8FC4 | TAX ; keep the low byte | ||||||||||
| 8FC5 | LDA zp_fwb_ovf ; table pointer high... | ||||||||||
| 8FC7 | ADC #0 ; + carry | ||||||||||
| 8FC9 | STA zp_fwb_ovf ; (store) | ||||||||||
| 8FCB | CPX zp_himem ; Has the table reached HIMEM? | ||||||||||
| 8FCD | SBC zp_himem_1 ; high byte vs HIMEM | ||||||||||
| 8FCF | BCS renum_no_space ; yes: no room for the table | ||||||||||
| 8FD1 | JSR advance_to_next_line ; Advance to the next program line | ||||||||||
| 8FD4 | BCC renum_pass1_loop ; loop over all lines | ||||||||||
| 8FD6 | .renum_no_space←1← 8FCF BCS | ||||||||||
| BRK ; RENUMBER ran out of space: error | |||||||||||
| 8FD7 | EQUB &00, &CC | ||||||||||
| 8FD9 | EQUS " space" | ||||||||||
| 8FDF | .silly_error←2← 8F85 BNE← 8F89 BEQ | ||||||||||
| BRK ; error block | |||||||||||
| 8FE0 | EQUB &00 | ||||||||||
| 8FE1 | EQUS "Silly" | ||||||||||
| 8FE6 | EQUB &00 | ||||||||||
| 8FE7 | .renum_pass2←1← 8FB5 BMI | ||||||||||
| JSR point_general_page ; Pass 2: reset to the program start | |||||||||||
| 8FEA | .renum_pass2_loop←1← 900B BCC | ||||||||||
| LDY #0 ; for each line: | |||||||||||
| 8FEC | LDA (zp_general),y ; line number high byte | ||||||||||
| 8FEE | BMI renum_pass3 ; end of program: go to pass 3 | ||||||||||
| 8FF0 | LDA zp_fileblk_1 ; Write the new number: high byte | ||||||||||
| 8FF2 | STA (zp_general),y ; (into the line) | ||||||||||
| 8FF4 | LDA zp_fileblk ; low byte | ||||||||||
| 8FF6 | INY ; advance | ||||||||||
| 8FF7 | STA (zp_general),y ; (into the line) | ||||||||||
| 8FF9 | CLC ; Add the step to the running number: low | ||||||||||
| 8FFA | LDA zp_iwa ; step low, | ||||||||||
| 8FFC | ADC zp_fileblk ; + current number low | ||||||||||
| 8FFE | STA zp_fileblk ; (store) | ||||||||||
| 9000 | LDA #0 ; high byte... | ||||||||||
| 9002 | ADC zp_fileblk_1 ; + carry | ||||||||||
| 9004 | AND #&7f ; keep it a valid line number (< &8000) | ||||||||||
| 9006 | STA zp_fileblk_1 ; (store) | ||||||||||
| 9008 | JSR advance_to_next_line ; Advance to the next line | ||||||||||
| 900B | BCC renum_pass2_loop ; loop | ||||||||||
| 900D | .renum_pass3←1← 8FEE BMI | ||||||||||
| LDA zp_page ; Pass 3: scan from PAGE, high byte | |||||||||||
| 900F | STA zp_text_ptr_1 ; (text pointer high) | ||||||||||
| 9011 | LDY #0 ; low byte 0 | ||||||||||
| 9013 | STY zp_text_ptr ; (store) | ||||||||||
| 9015 | INY ; advance | ||||||||||
| 9016 | LDA (zp_text_ptr),y ; read the line number high byte | ||||||||||
| 9018 | BMI renum_done ; end of program: done | ||||||||||
| 901A | .renum_line_loop←2← 9034 BCC← 9038 BCS | ||||||||||
| LDY #4 ; Scan the line from offset 4 (past the header) | |||||||||||
| 901C | .renum_scan_loop←2← 9025 BNE← 906F BNE | ||||||||||
| LDA (zp_text_ptr),y ; next token | |||||||||||
| 901E | CMP #&8d ; Is it the line-number prefix &8D? | ||||||||||
| 9020 | BEQ renum_ref ; yes: rewrite the reference | ||||||||||
| 9022 | INY ; advance | ||||||||||
| 9023 | CMP #&0d ; end of line (CR)? | ||||||||||
| 9025 | BNE renum_scan_loop ; no: keep scanning | ||||||||||
| 9027 | LDA (zp_text_ptr),y ; read the next line's header | ||||||||||
| 9029 | BMI renum_done ; end of program | ||||||||||
| 902B | LDY #3 ; line length is at offset 3 | ||||||||||
| 902D | LDA (zp_text_ptr),y ; get it | ||||||||||
| 902F | CLC ; advance to the next line: low | ||||||||||
| 9030 | ADC zp_text_ptr ; + text pointer low | ||||||||||
| 9032 | STA zp_text_ptr ; (store) | ||||||||||
| 9034 | BCC renum_line_loop ; loop | ||||||||||
| 9036 | INC zp_text_ptr_1 ; carry into high byte | ||||||||||
| 9038 | BCS renum_line_loop ; loop | ||||||||||
| 903A | .renum_done←2← 9018 BMI← 9029 BMI | ||||||||||
| JMP clear_then_immediate ; Done: back to the immediate loop | |||||||||||
| 903D | .renum_ref←1← 9020 BEQ | ||||||||||
| JSR decode_line_number ; Decode the &8D-encoded line number | |||||||||||
| 9040 | JSR setup_scan_top ; Point at the old->new table | ||||||||||
| 9043 | .renum_table_search←2← 907A BCC← 907E BCS | ||||||||||
| LDY #0 ; Search the table for this old number: | |||||||||||
| 9045 | LDA (zp_general),y ; table end marker? | ||||||||||
| 9047 | BMI renum_missing_line ; not found: reference to a missing line | ||||||||||
| 9049 | LDA (zp_fwb_sign),y ; old number high... | ||||||||||
| 904B | INY ; advance | ||||||||||
| 904C | CMP zp_iwa_1 ; match the referenced number high? | ||||||||||
| 904E | BNE renum_table_next ; no: next table entry | ||||||||||
| 9050 | LDA (zp_fwb_sign),y ; old number low... | ||||||||||
| 9052 | CMP zp_iwa ; match low? | ||||||||||
| 9054 | BNE renum_table_next ; no: next entry | ||||||||||
| 9056 | LDA (zp_general),y ; Found: take the new number high | ||||||||||
| 9058 | STA zp_fwb_exp ; (save) | ||||||||||
| 905A | DEY ; new number low | ||||||||||
| 905B | LDA (zp_general),y ; read it from the table | ||||||||||
| 905D | STA zp_fwb_m1 ; (save) | ||||||||||
| 905F | LDY zp_text_ptr_off ; position within the line | ||||||||||
| 9061 | DEY ; back up to the &8D token | ||||||||||
| 9062 | LDA zp_text_ptr ; Point at the reference in the line: low | ||||||||||
| 9064 | STA zp_general ; reference pointer low | ||||||||||
| 9066 | LDA zp_text_ptr_1 ; high | ||||||||||
| 9068 | STA zp_general_1 ; reference pointer high | ||||||||||
| 906A | JSR encode_line_number ; Re-encode the new line number in place | ||||||||||
| 906D | .renum_resume←1← 909D BEQ | ||||||||||
| LDY zp_text_ptr_off ; resume scanning | |||||||||||
| 906F | BNE renum_scan_loop ; continue the line scan | ||||||||||
| 9071 | .renum_table_next←2← 904E BNE← 9054 BNE | ||||||||||
| JSR advance_to_next_line ; Next table entry: advance... | |||||||||||
| 9074 | LDA zp_fwb_sign ; ...the table pointer by 2 | ||||||||||
| 9076 | ADC #2 ; low + 2 | ||||||||||
| 9078 | STA zp_fwb_sign ; (store) | ||||||||||
| 907A | BCC renum_table_search ; loop | ||||||||||
| 907C | INC zp_fwb_ovf ; carry | ||||||||||
| 907E | BCS renum_table_search ; loop | ||||||||||
| 9080 | .renum_missing_line←1← 9047 BMI | ||||||||||
| JSR print_inline_string ; Reference to a missing line: report it | |||||||||||
| 9083 | EQUS "Failed at " ; build the "Failed at <line>" message... print it | ||||||||||
| 908D | INY ; This line's number | ||||||||||
| 908E | LDA (zp_text_ptr),y ; high byte, | ||||||||||
| 9090 | STA zp_iwa_1 ; store high, | ||||||||||
| 9092 | INY ; low byte, | ||||||||||
| 9093 | LDA (zp_text_ptr),y ; read it, | ||||||||||
| 9095 | STA zp_iwa ; store low | ||||||||||
| 9097 | JSR print_line_number ; print it | ||||||||||
| 909A | JSR emit_newline ; newline | ||||||||||
| 909D | BEQ renum_resume ; loop | ||||||||||
| fall through ↓ | |||||||||||
Advance the general pointer to the next program lineAdd the line length byte (at offset 3 of the current line) to zp_general so it addresses the next program line. Clears carry for the caller.
|
|||||||||||||||
| 909F | .advance_to_next_line←3← 8FD1 JSR← 9008 JSR← 9071 JSR | ||||||||||||||
| INY ; Line length is at offset 3 | |||||||||||||||
| 90A0 | LDA (zp_general),y ; get the line length | ||||||||||||||
| 90A2 | ADC zp_general ; add it to the pointer: low | ||||||||||||||
| 90A4 | STA zp_general ; (store) | ||||||||||||||
| 90A6 | BCC return_7 ; no carry: done | ||||||||||||||
| 90A8 | INC zp_general_1 ; carry into the high byte | ||||||||||||||
| 90AA | CLC ; clear carry for the caller | ||||||||||||||
| 90AB | .return_7←1← 90A6 BCC | ||||||||||||||
| RTS ; Return at the next line | |||||||||||||||
AUTOGenerate line numbers automatically during program entry until Escape. AUTO [start[,step]].
|
|||||||||||
| 90AC | .stmt_auto | ||||||||||
| JSR parse_line_range ; Parse the start and increment | |||||||||||
| 90AF | LDA zp_iwa ; Save the increment | ||||||||||
| 90B1 | PHA ; push it | ||||||||||
| 90B2 | JSR unstack_integer ; Recover the start line | ||||||||||
| 90B5 | .auto_loop←2← 90D3 BCC← 90D7 BPL | ||||||||||
| JSR stack_integer ; Stack the line number | |||||||||||
| 90B8 | JSR trace_print_number ; Print it | ||||||||||
| 90BB | LDA #' ' ; Print a space and read a line | ||||||||||
| 90BD | JSR read_input_line ; do it | ||||||||||
| 90C0 | JSR unstack_integer ; Pop the line number | ||||||||||
| 90C3 | JSR tokenise_line ; Tokenise the line | ||||||||||
| 90C6 | JSR insert_line ; Insert it into the program | ||||||||||
| 90C9 | JSR clear_vars_heap_stack ; Clear variables and heap | ||||||||||
| 90CC | PLA ; Increment | ||||||||||
| 90CD | PHA ; keep it stacked | ||||||||||
| 90CE | CLC ; Next line number = line + increment | ||||||||||
| 90CF | ADC zp_iwa ; + current line low, | ||||||||||
| 90D1 | STA zp_iwa ; store low, | ||||||||||
| 90D3 | BCC auto_loop ; no carry: loop, | ||||||||||
| 90D5 | INC zp_iwa_1 ; carry into the high byte | ||||||||||
| 90D7 | BPL auto_loop ; still in range: loop | ||||||||||
| 90D9 | JMP clear_then_immediate ; overflow: stop | ||||||||||
| 90DC | .dim_no_room_jmp←1← 9106 BCS | ||||||||||
| JMP dim_no_room ; No room error | |||||||||||
| 90DF | .dim_byte_block←1← 9168 JMP | ||||||||||
| DEC zp_text_ptr_off ; Back up to the variable | |||||||||||
| 90E1 | JSR parse_lvalue ; Parse it | ||||||||||
| 90E4 | BEQ bad_dim ; not a variable: Bad DIM | ||||||||||
| 90E6 | BCS bad_dim ; indirection: Bad DIM | ||||||||||
| 90E8 | JSR stack_integer ; Stack the variable address | ||||||||||
| 90EB | JSR eval_expr_integer ; Evaluate the size | ||||||||||
| 90EE | JSR iwa_inc ; n + 1 bytes | ||||||||||
| 90F1 | LDA zp_iwa_3 ; fits in 16 bits? | ||||||||||
| 90F3 | ORA zp_iwa_2 ; OR byte 2 (any => > 65535) | ||||||||||
| 90F5 | BNE bad_dim ; no: Bad DIM | ||||||||||
| 90F7 | CLC ; New top = top + size | ||||||||||
| 90F8 | LDA zp_iwa ; size low, | ||||||||||
| 90FA | ADC zp_vartop ; + VARTOP low, | ||||||||||
| 90FC | TAY ; new top low in Y, | ||||||||||
| 90FD | LDA zp_iwa_1 ; size high, | ||||||||||
| 90FF | ADC zp_vartop_1 ; + VARTOP high, | ||||||||||
| 9101 | TAX ; new top high in X | ||||||||||
| 9102 | CPY zp_stack_ptr ; collides with the stack? | ||||||||||
| 9104 | SBC zp_stack_ptr_1 ; high byte vs the stack | ||||||||||
| 9106 | BCS dim_no_room_jmp ; yes: No room | ||||||||||
| 9108 | LDA zp_vartop ; Block address = old top | ||||||||||
| 910A | STA zp_iwa ; address low, | ||||||||||
| 910C | LDA zp_vartop_1 ; high byte, | ||||||||||
| 910E | STA zp_iwa_1 ; address high | ||||||||||
| 9110 | STY zp_vartop ; Commit the new top | ||||||||||
| 9112 | STX zp_vartop_1 ; high byte | ||||||||||
| 9114 | LDA #0 ; Result is the address | ||||||||||
| 9116 | STA zp_iwa_2 ; clear byte 2, | ||||||||||
| 9118 | STA zp_iwa_3 ; and byte 3 | ||||||||||
| 911A | LDA #&40 ; integer type | ||||||||||
| 911C | STA zp_var_type ; set the type | ||||||||||
| 911E | JSR assign_number ; assign the address to the variable | ||||||||||
| 9121 | JSR eeti_sync ; sync the pointer | ||||||||||
| 9124 | JMP dim_after ; continue | ||||||||||
Raise the "Bad DIM" errorRaise BASIC error &0A, "Bad DIM", via a BRK error block (the message ends with the DIM token &DE). Reached by the DIM/array machinery on an empty name, a re-DIM of an existing array, a bound exceeding 16383, or another invalid dimension. Does not return.
|
||||
| 9127 | .bad_dim←8← 90E4 BEQ← 90E6 BCS← 90F5 BNE← 9150 BEQ← 9172 BNE← 9193 BNE← 91B4 JMP← 925A JMP | |||
| BRK ; Bad DIM error | ||||
| 9128 | EQUB &0A | |||
| 9129 | EQUS "Bad " | |||
| 912D | EQUB &DE, &00 | |||
DIMDimension an array, or reserve a block of bytes. DIM var(subscripts) | DIM var size.
|
|||||||||||
| 912F | .stmt_dim←1← 9215 JMP | ||||||||||
| JSR skip_spaces ; Skip spaces | |||||||||||
| 9132 | TYA ; Point &37/&38 at the name | ||||||||||
| 9133 | CLC ; Clear carry for the add | ||||||||||
| 9134 | ADC zp_text_ptr ; Name offset + text pointer low | ||||||||||
| 9136 | LDX zp_text_ptr_1 ; Text pointer high in X | ||||||||||
| 9138 | BCC dim_name ; No carry into the high byte | ||||||||||
| 913A | INX ; Carry into the high byte | ||||||||||
| 913B | CLC ; Clear carry to back up by one | ||||||||||
| 913C | .dim_name←1← 9138 BCC | ||||||||||
| SBC #0 ; Back up one byte (validate reads from offset 1): low | |||||||||||
| 913E | STA zp_general ; &37 = name pointer low | ||||||||||
| 9140 | TXA ; High byte | ||||||||||
| 9141 | SBC #0 ; Back up one byte: high | ||||||||||
| 9143 | STA zp_general_1 ; &38 = name pointer high | ||||||||||
| 9145 | LDX #5 ; Default element size = 5 (real) | ||||||||||
| 9147 | STX zp_fwb_m2 ; Stash it as the element size (zp_fwb_m2) | ||||||||||
| 9149 | LDX zp_text_ptr_off ; Name offset | ||||||||||
| 914B | JSR validate_var_name ; Validate the name | ||||||||||
| 914E | CPY #1 ; empty name? | ||||||||||
| 9150 | BEQ bad_dim ; yes: Bad DIM | ||||||||||
| 9152 | CMP #'(' ; '(' array? | ||||||||||
| 9154 | BEQ dim_array ; yes | ||||||||||
| 9156 | CMP #'$' ; '$' string? | ||||||||||
| 9158 | BEQ dim_check_paren ; yes | ||||||||||
| 915A | CMP #'%' ; '%' integer? | ||||||||||
| 915C | BNE dim_byte ; no: DIM var n (byte block) | ||||||||||
| 915E | .dim_check_paren←1← 9158 BEQ | ||||||||||
| DEC zp_fwb_m2 ; Element size = 4 (integer/string) | |||||||||||
| 9160 | INY ; step past the suffix | ||||||||||
| 9161 | INX ; Count the suffix char in the name length too | ||||||||||
| 9162 | LDA (zp_general),y ; following character | ||||||||||
| 9164 | CMP #'(' ; '(' array? | ||||||||||
| 9166 | BEQ dim_array ; yes | ||||||||||
| 9168 | .dim_byte←1← 915C BNE | ||||||||||
| JMP dim_byte_block ; DIM var n: allocate a byte block | |||||||||||
| 916B | .dim_array←2← 9154 BEQ← 9166 BEQ | ||||||||||
| STY zp_fileblk ; Array: save the name length | |||||||||||
| 916D | STX zp_text_ptr_off ; Save the name offset too (&0a) | ||||||||||
| 916F | JSR find_variable ; Already defined? | ||||||||||
| 9172 | BNE bad_dim ; yes: Bad DIM (re-DIM) | ||||||||||
| 9174 | JSR create_variable ; Create the array variable | ||||||||||
| 9177 | LDX #1 ; Clear its pointer | ||||||||||
| 9179 | JSR clear_value_bytes ; Zero the value byte | ||||||||||
| 917C | LDA zp_fwb_m2 ; Save the element size | ||||||||||
| 917E | PHA ; Push it for the post-loop multiply | ||||||||||
| 917F | LDA #1 ; Descriptor write offset starts at 1 | ||||||||||
| 9181 | PHA ; Push the descriptor write offset | ||||||||||
| 9182 | JSR int_result_a ; running size = 1 | ||||||||||
| 9185 | .dim_bound_loop←1← 91AE BEQ | ||||||||||
| JSR stack_integer ; Stack the running size | |||||||||||
| 9188 | JSR eval_expr_to_integer ; Evaluate the next bound | ||||||||||
| 918B | LDA zp_iwa_1 ; fits in 14 bits? | ||||||||||
| 918D | AND #&c0 ; Isolate the top 2 bits of the bound high byte | ||||||||||
| 918F | ORA zp_iwa_2 ; OR in byte 2, | ||||||||||
| 9191 | ORA zp_iwa_3 ; and byte 3 (any set => bound > 16383) | ||||||||||
| 9193 | BNE bad_dim ; no: Bad DIM | ||||||||||
| 9195 | JSR iwa_inc ; Extent = bound + 1 | ||||||||||
| 9198 | PLA ; Restore the descriptor offset | ||||||||||
| 9199 | TAY ; into Y as the descriptor write index | ||||||||||
| 919A | LDA zp_iwa ; Store the extent in the descriptor | ||||||||||
| 919C | STA (zp_vartop),y ; extent low byte, | ||||||||||
| 919E | INY ; advance to the high byte, | ||||||||||
| 919F | LDA zp_iwa_1 ; extent high byte, | ||||||||||
| 91A1 | STA (zp_vartop),y ; store it, | ||||||||||
| 91A3 | INY ; advance past the extent | ||||||||||
| 91A4 | TYA ; save the offset | ||||||||||
| 91A5 | PHA ; Push the updated descriptor offset | ||||||||||
| 91A6 | JSR unstack_multiplier ; Multiply the running size by the extent | ||||||||||
| 91A9 | JSR skip_spaces ; Skip spaces | ||||||||||
| 91AC | CMP #',' ; ',' another dimension? | ||||||||||
| 91AE | BEQ dim_bound_loop ; yes | ||||||||||
| 91B0 | CMP #')' ; ')' end of dimensions? | ||||||||||
| 91B2 | BEQ dim_alloc ; yes | ||||||||||
| 91B4 | JMP bad_dim ; otherwise Bad DIM | ||||||||||
| 91B7 | .dim_alloc←1← 91B2 BEQ | ||||||||||
| PLA ; Recover the data offset (1 + 2*dims) | |||||||||||
| 91B8 | STA zp_print_flag ; save it | ||||||||||
| 91BA | PLA ; Recover the element size | ||||||||||
| 91BB | STA zp_fwb_m2 ; as the multiplier low byte | ||||||||||
| 91BD | LDA #0 ; element size high = 0 | ||||||||||
| 91BF | STA zp_fwb_m3 ; (16-bit element size in zp_fwb_m2/m3) | ||||||||||
| 91C1 | JSR imul16 ; Total = element count * element size | ||||||||||
| 91C4 | LDY #0 ; Store the data offset in descriptor byte 0 | ||||||||||
| 91C6 | LDA zp_print_flag ; the saved offset (1 + 2*dims) | ||||||||||
| 91C8 | STA (zp_vartop),y ; into descriptor byte 0 | ||||||||||
| 91CA | ADC zp_iwa ; Add it to the total size | ||||||||||
| 91CC | STA zp_iwa ; total size low = header + data, | ||||||||||
| 91CE | BCC dim_clear ; no carry into the high byte | ||||||||||
| 91D0 | INC zp_iwa_1 ; carry into the total size high byte | ||||||||||
| 91D2 | .dim_clear←1← 91CE BCC | ||||||||||
| LDA zp_vartop_1 ; Point at the current variable top | |||||||||||
| 91D4 | STA zp_general_1 ; high byte to &38, | ||||||||||
| 91D6 | LDA zp_vartop ; low byte | ||||||||||
| 91D8 | STA zp_general ; to &37 (saved old top) | ||||||||||
| 91DA | CLC ; New top = top + total size | ||||||||||
| 91DB | ADC zp_iwa ; + total size low, | ||||||||||
| 91DD | TAY ; new top low held in Y, | ||||||||||
| 91DE | LDA zp_iwa_1 ; high byte | ||||||||||
| 91E0 | ADC zp_vartop_1 ; + total size high | ||||||||||
| 91E2 | BCS dim_no_room ; overflow: No room | ||||||||||
| 91E4 | TAX ; new top high in X | ||||||||||
| 91E5 | CPY zp_stack_ptr ; collides with the stack? | ||||||||||
| 91E7 | SBC zp_stack_ptr_1 ; high byte vs stack high (16-bit compare) | ||||||||||
| 91E9 | BCS dim_no_room ; yes: No room | ||||||||||
| 91EB | STY zp_vartop ; Commit the new variable top | ||||||||||
| 91ED | STX zp_vartop_1 ; high byte | ||||||||||
| 91EF | LDA zp_general ; Zero the array storage from the old top | ||||||||||
| 91F1 | ADC zp_print_flag ; skip the descriptor header to the data, | ||||||||||
| 91F3 | TAY ; data start offset in Y, | ||||||||||
| 91F4 | LDA #0 ; zero byte to fill with, | ||||||||||
| 91F6 | STA zp_general ; pointer low = 0 (Y carries the offset) | ||||||||||
| 91F8 | BCC dim_clear_loop ; no page crossing | ||||||||||
| 91FA | INC zp_general_1 ; step the pointer to the next page | ||||||||||
| 91FC | .dim_clear_loop←3← 91F8 BCC← 9205 BNE← 9209 BNE | ||||||||||
| STA (zp_general),y ; store a zero byte | |||||||||||
| 91FE | INY ; next byte, | ||||||||||
| 91FF | BNE dim_clear_check ; no page wrap | ||||||||||
| 9201 | INC zp_general_1 ; cross into the next page | ||||||||||
| 9203 | .dim_clear_check←1← 91FF BNE | ||||||||||
| CPY zp_vartop ; reached the new top? | |||||||||||
| 9205 | BNE dim_clear_loop ; low byte not at top yet: keep zeroing | ||||||||||
| 9207 | CPX zp_general_1 ; compare the page to the new top page | ||||||||||
| 9209 | BNE dim_clear_loop ; not there yet: keep zeroing | ||||||||||
| 920B | .dim_after←1← 9124 JMP | ||||||||||
| JSR skip_spaces ; Skip spaces | |||||||||||
| 920E | CMP #',' ; ',' another array? | ||||||||||
| 9210 | BEQ dim_next_array ; yes | ||||||||||
| 9212 | JMP stmt_backup_end ; no: next statement | ||||||||||
| 9215 | .dim_next_array←1← 9210 BEQ | ||||||||||
| JMP stmt_dim ; DIM the next array | |||||||||||
| 9218 | .dim_no_room←3← 90DC JMP← 91E2 BCS← 91E9 BCS | ||||||||||
| BRK ; No room error | |||||||||||
| 9219 | EQUB &0B, &DE | ||||||||||
| 921B | EQUS " space" | ||||||||||
| 9221 | EQUB &00 | ||||||||||
Increment the integer accumulatorIWA = IWA + 1, carrying through all four bytes.
|
|||||||||||
| 9222 | .iwa_inc←4← 8F59 JSR← 90EE JSR← 9195 JSR← AF39 JSR | ||||||||||
| INC zp_iwa ; Increment IWA: byte 0 | |||||||||||
| 9224 | BNE return_8 ; No carry: done | ||||||||||
| 9226 | INC zp_iwa_1 ; Carry into byte 1 | ||||||||||
| 9228 | BNE return_8 ; no carry: done | ||||||||||
| 922A | INC zp_iwa_2 ; byte 2 | ||||||||||
| 922C | BNE return_8 ; no carry: done | ||||||||||
| 922E | INC zp_iwa_3 ; byte 3 | ||||||||||
| 9230 | .return_8←3← 9224 BNE← 9228 BNE← 922C BNE | ||||||||||
| RTS ; Return | |||||||||||
| 9231 | .unstack_multiplier←1← 91A6 JSR | ||||||||||
| LDX #&3f ; Unstack the multiplier (into &3F area) | |||||||||||
| 9233 | JSR unstack_int_to_zp ; into the &3F area | ||||||||||
| fall through ↓ | |||||||||||
16-bit integer multiply (IWA * FWB)Multiply IWA by the 16-bit multiplier in the FWB mantissa (m2/m3) by shift-and-add, leaving the 16-bit product in IWA low/high. Raises Too big on overflow. Used for array subscript arithmetic.
|
|||||||||||||||
| 9236 | .imul16←2← 91C1 JSR← 9736 JSR | ||||||||||||||
| LDX #0 ; Clear the running product (X:Y) | |||||||||||||||
| 9238 | LDY #0 ; high in X, low in Y | ||||||||||||||
| 923A | .imul_loop←1← 9253 BNE | ||||||||||||||
| LSR zp_fwb_m3 ; Shift the multiplier right: next bit into carry | |||||||||||||||
| 923C | ROR zp_fwb_m2 ; low byte (next bit -> carry) | ||||||||||||||
| 923E | BCC imul_double ; bit clear: skip the add | ||||||||||||||
| 9240 | CLC ; bit set: add the multiplicand (IWA) | ||||||||||||||
| 9241 | TYA ; product low... | ||||||||||||||
| 9242 | ADC zp_iwa ; low | ||||||||||||||
| 9244 | TAY ; (into Y) | ||||||||||||||
| 9245 | TXA ; product high... | ||||||||||||||
| 9246 | ADC zp_iwa_1 ; high | ||||||||||||||
| 9248 | TAX ; (into X) | ||||||||||||||
| 9249 | BCS imul_overflow ; overflow: Too big | ||||||||||||||
| 924B | .imul_double←1← 923E BCC | ||||||||||||||
| ASL zp_iwa ; Double the multiplicand: low | |||||||||||||||
| 924D | ROL zp_iwa_1 ; high | ||||||||||||||
| 924F | LDA zp_fwb_m2 ; more multiplier bits? | ||||||||||||||
| 9251 | ORA zp_fwb_m3 ; any multiplier bits left? | ||||||||||||||
| 9253 | BNE imul_loop ; loop | ||||||||||||||
| 9255 | STY zp_iwa ; Store the product: low | ||||||||||||||
| 9257 | STX zp_iwa_1 ; high | ||||||||||||||
| 9259 | RTS ; Return | ||||||||||||||
| 925A | .imul_overflow←1← 9249 BCS | ||||||||||||||
| JMP bad_dim ; overflow error | |||||||||||||||
HIMEM=Set HIMEM, the top of memory available to BASIC. HIMEM = address.
|
|||||||||||
| 925D | .stmt_himem | ||||||||||
| JSR eval_eq_integer ; Step past "=", evaluate an integer | |||||||||||
| 9260 | LDA zp_iwa ; Set HIMEM and the stack: low | ||||||||||
| 9262 | STA zp_himem ; HIMEM low | ||||||||||
| 9264 | STA zp_stack_ptr ; stack pointer low | ||||||||||
| 9266 | LDA zp_iwa_1 ; high | ||||||||||
| 9268 | STA zp_himem_1 ; HIMEM high | ||||||||||
| 926A | STA zp_stack_ptr_1 ; stack pointer high | ||||||||||
| 926C | JMP statement_loop ; Back to execution | ||||||||||
LOMEM=Set LOMEM, the start of variable storage. LOMEM = address.
|
|||||||||||
| 926F | .stmt_lomem | ||||||||||
| JSR eval_eq_integer ; Step past "=", evaluate an integer | |||||||||||
| 9272 | LDA zp_iwa ; Set LOMEM (and empty the variables): low byte | ||||||||||
| 9274 | STA zp_lomem ; LOMEM low | ||||||||||
| 9276 | STA zp_vartop ; VARTOP low (no variables yet) | ||||||||||
| 9278 | LDA zp_iwa_1 ; high byte | ||||||||||
| 927A | STA zp_lomem_1 ; LOMEM high | ||||||||||
| 927C | STA zp_vartop_1 ; VARTOP high | ||||||||||
| 927E | JSR clear_var_table ; Clear all dynamic variables | ||||||||||
| 9281 | BEQ page_done ; Back to the execution loop | ||||||||||
| fall through ↓ | |||||||||||
PAGE=Set PAGE, the start of the BASIC program. PAGE = address.
|
|||||||||||
| 9283 | .stmt_page | ||||||||||
| JSR eval_eq_integer ; Step past "=", evaluate an integer | |||||||||||
| 9286 | LDA zp_iwa_1 ; PAGE is a page number (the high byte) | ||||||||||
| 9288 | STA zp_page ; (store) | ||||||||||
| 928A | .page_done←2← 9281 BEQ← 9293 BEQ | ||||||||||
| JMP statement_loop ; Back to execution | |||||||||||
CLEARDiscard all variables and the stack. CLEAR.
|
|||||||||||
| 928D | .stmt_clear | ||||||||||
| JSR check_end_of_statement ; Check the statement ends | |||||||||||
| 9290 | JSR clear_vars_heap_stack ; Clear variables, heap and stack | ||||||||||
| 9293 | BEQ page_done ; next statement | ||||||||||
| fall through ↓ | |||||||||||
TRACETrace executed line numbers for debugging. TRACE ON | OFF | line.
|
|||||||||||
| 9295 | .stmt_trace | ||||||||||
| JSR check_line_number ; Line number following? | |||||||||||
| 9298 | BCS trace_check_end ; yes: TRACE to that line | ||||||||||
| 929A | CMP #&ee ; ON token? | ||||||||||
| 929C | BEQ trace_on ; yes | ||||||||||
| 929E | CMP #&87 ; OFF token? | ||||||||||
| 92A0 | BEQ trace_off ; yes | ||||||||||
| 92A2 | JSR eval_expr_to_integer ; Evaluate the trace ceiling | ||||||||||
| 92A5 | .trace_check_end←1← 9298 BCS | ||||||||||
| JSR check_end_of_statement ; check the statement ends | |||||||||||
| 92A8 | LDA zp_iwa ; Set the trace ceiling | ||||||||||
| 92AA | STA zp_trace_max ; low byte, | ||||||||||
| 92AC | LDA zp_iwa_1 ; high byte, | ||||||||||
| 92AE | .trace_ceiling_loop←1← 92BE BNE | ||||||||||
| STA zp_trace_max_1 ; to &22 | |||||||||||
| 92B0 | LDA #&ff ; TRACE on | ||||||||||
| 92B2 | .trace_set_flag←1← 92C7 BEQ | ||||||||||
| STA zp_trace_flag ; Set the TRACE flag | |||||||||||
| 92B4 | JMP statement_loop ; next statement | ||||||||||
| 92B7 | .trace_on←1← 929C BEQ | ||||||||||
| INC zp_text_ptr_off ; TRACE ON: step past | |||||||||||
| 92B9 | JSR check_end_of_statement ; check the statement ends | ||||||||||
| 92BC | LDA #&ff ; ceiling = max | ||||||||||
| 92BE | BNE trace_ceiling_loop ; set it on | ||||||||||
| 92C0 | .trace_off←1← 92A0 BEQ | ||||||||||
| INC zp_text_ptr_off ; TRACE OFF: step past | |||||||||||
| 92C2 | JSR check_end_of_statement ; check the statement ends | ||||||||||
| 92C5 | LDA #0 ; flag = 0 | ||||||||||
| 92C7 | BEQ trace_set_flag ; set it off | ||||||||||
| fall through ↓ | |||||||||||
TIME=Set the centisecond elapsed-time clock. TIME = value.
|
|||||||||||
| 92C9 | .stmt_time | ||||||||||
| JSR eval_eq_integer ; Step past "=", evaluate the value | |||||||||||
| 92CC | LDX #<(zp_iwa) ; Point at IWA | ||||||||||
| 92CE | LDY #>(zp_iwa) ; high byte of the address | ||||||||||
| 92D0 | STY zp_fwa_sign ; clear the 5th byte | ||||||||||
| 92D2 | LDA #osword_write_clock ; OSWORD 2 (write clock) | ||||||||||
| 92D4 | JSR osword ; Write system clock | ||||||||||
| 92D7 | JMP statement_loop ; next statement | ||||||||||
Evaluate a comma-separated integer argumentSkip a comma at PtrB (Missing , if absent), then fall into eval_expr_integer to evaluate the following expression as an integer.
|
|||||||||
| 92DA | .eval_comma_integer←4← 9380 JSR← 9403 JSR← B459 JSR← B47C JSR | ||||||||
| JSR skip_spaces_expect_comma ; Step past the comma | |||||||||
| fall through ↓ | |||||||||
Evaluate an expression as an integerEvaluate the expression at PtrB (eval_or_eor) and coerce the result to an integer (coerce_to_integer). Unlike eval_expr_to_integer it does not sync the primary pointer, so the caller keeps managing PtrB.
|
|||||||||
| 92DD | .eval_expr_integer←8← 8E40 JSR← 90EB JSR← 9702 JSR← AB41 JSR← B047 JSR← B0C2 JSR← B7F5 JSR← B81A JSR | ||||||||
| JSR eval_or_eor ; Evaluate the expression | |||||||||
| 92E0 | JMP coerce_to_integer ; ...and coerce to integer | ||||||||
Evaluate a single factor as an integerEvaluate one factor at PtrB (eval_factor, so without applying any operators) and coerce it to an integer: a string raises Type mismatch, a real is converted, an integer is returned unchanged.
|
|||||||||
| 92E3 | .eval_factor_integer←10← 8E58 JSR← 95AA JSR← 95B2 JSR← 9691 JSR← AB33 JSR← ABD2 JSR← ACD1 JSR← AFAD JSR← B3BD JSR← BFBC JSR | ||||||||
| JSR eval_factor ; Evaluate a factor | |||||||||
| 92E6 | BEQ coerce_type_error ; string: Type mismatch | ||||||||
| 92E8 | BMI coerce_real ; real: convert to integer | ||||||||
| 92EA | .return_9←2← 92F2 BPL← 92FF BMI | ||||||||
| RTS ; Return | |||||||||
Require "=" then evaluate an integerCopy PtrA to PtrB and require an "=" (sub_c9807), evaluate the value that follows, then fall into coerce_var_to_integer. Used by the pseudo-variable assignments (TIME=, PAGE=, ...).
|
|||||||||
| 92EB | .eval_eq_integer←4← 925D JSR← 926F JSR← 9283 JSR← 92C9 JSR | ||||||||
| JSR copy_ptra_to_ptrb ; Expect "=" and evaluate | |||||||||
| fall through ↓ | |||||||||
Coerce the current value to an integerLoad the value type from zp_var_type and fall into coerce_to_integer, converting the just-evaluated value to an integer. The entry to use when the type is in zp_var_type rather than A.
|
|||||||||||
| 92EE | .coerce_var_to_integer←6← 8ED5 JSR← 93FD JSR← B592 JSR← BBB7 JSR← BF37 JSR← BF62 JSR | ||||||||||
| LDA zp_var_type ; Result type, then coerce to integer | |||||||||||
| fall through ↓ | |||||||||||
Coerce the current value to an integerCheck the type of the last evaluated value (in A from zp_var_type): a string raises "Type mismatch", an integer returns unchanged, and a real is converted to a 4-byte integer in the integer accumulator.
|
||||
| 92F0 | .coerce_to_integer←21← 8824 JSR← 8E2E JSR← 92E0 JMP← 9688 JSR← 974A JSR← 976F JSR← 99BF JSR← 99CE JSR← 9B3E JSR← 9B59 JSR← 9B6C JSR← 9B7B JSR← 9B85 JSR← AB4D JSR← AD0C JSR← AF0F JSR← AFDD JSR← AFFF JSR← B05E JSR← B921 JSR← B9A2 JSR | |||
| BEQ coerce_type_error ; string? | ||||
| 92F2 | BPL return_9 ; integer: return | |||
| 92F4 | .coerce_real←1← 92E8 BMI | |||
| JMP fwa_to_int ; real: convert to integer | ||||
| 92F7 | .coerce_type_error←3← 92E6 BEQ← 92F0 BEQ← 92FD BEQ | |||
| JMP err_type_mismatch ; Type mismatch error | ||||
Evaluate an expression as a realEvaluate a factor at PtrB and ensure the result is real, converting an integer with int_to_fwa.
|
|||||||||||
| 92FA | .eval_real←11← 9E3C JSR← A6BE JSR← A7B4 JSR← A7FE JSR← A8DA JSR← A907 JSR← A98D JSR← A998 JSR← AA91 JSR← ABB1 JSR← ABC2 JSR | ||||||||||
| JSR eval_factor ; Evaluate a factor | |||||||||||
| fall through ↓ | |||||||||||
Coerce the result to a realLeave a real unchanged, convert an integer to FWA (int_to_fwa), or raise Type mismatch for a string.
|
|||||||||||||
| 92FD | .ensure_real←7← 9A59 JSR← 9D29 JSR← 9DE6 JSR← 9DF2 JSR← 9E36 JSR← B852 JSR← B870 JSR | ||||||||||||
| BEQ coerce_type_error ; string? | |||||||||||||
| 92FF | BMI return_9 ; real: return | ||||||||||||
| 9301 | JMP int_to_fwa ; integer: convert to real | ||||||||||||
PROCCall a named procedure, stacking parameters and the return position. PROCname[(params)].
|
|||||||||||
| 9304 | .stmt_proc | ||||||||||
| LDA zp_text_ptr ; Remember the call site in PtrB | |||||||||||
| 9306 | STA zp_text_ptr2 ; PtrA low to PtrB, | ||||||||||
| 9308 | LDA zp_text_ptr_1 ; high byte, | ||||||||||
| 930A | STA zp_text_ptr2_1 ; to PtrB high, | ||||||||||
| 930C | LDA zp_text_ptr_off ; offset, | ||||||||||
| 930E | STA zp_text_ptr2_off ; to PtrB offset | ||||||||||
| 9310 | LDA #&f2 ; Enter the procedure (PROC token &F2) | ||||||||||
| 9312 | JSR call_proc_fn ; call it | ||||||||||
| 9315 | JSR sync_text_ptr ; check the statement ends | ||||||||||
| 9318 | JMP statement_loop ; next statement | ||||||||||
| 931B | .proc_clear_loop←1← 9332 BMI | ||||||||||
| LDY #3 ; Clear the local string length | |||||||||||
| 931D | LDA #0 ; zero, | ||||||||||
| 931F | STA (zp_iwa),y ; string length = 0 (offset 3) | ||||||||||
| 9321 | BEQ local_bump ; always | ||||||||||
| fall through ↓ | |||||||||||
LOCALMake variables local to the current PROC/FN, stacking their old values. LOCAL var,...
|
|||||||||||
| 9323 | .stmt_local←1← 934E BEQ | ||||||||||
| TSX ; LOCAL is only meaningful inside a PROC/FN | |||||||||||
| 9324 | CPX #&fc ; inside a PROC/FN? | ||||||||||
| 9326 | BCS not_local_error ; no: Not LOCAL error | ||||||||||
| 9328 | JSR parse_lvalue ; Parse the local variable | ||||||||||
| 932B | BEQ local_not_var ; not a variable: error | ||||||||||
| 932D | JSR stack_local ; Save the variable's value for restoration | ||||||||||
| 9330 | LDY zp_iwa_2 ; string variable? | ||||||||||
| 9332 | BMI proc_clear_loop ; yes: leave it cleared | ||||||||||
| 9334 | JSR stack_integer ; stack the variable address | ||||||||||
| 9337 | LDA #0 ; Initialise the local to zero / empty | ||||||||||
| 9339 | JSR int_result_a ; value zero | ||||||||||
| 933C | STA zp_var_type ; integer type | ||||||||||
| 933E | JSR assign_number ; assign it | ||||||||||
| 9341 | .local_bump←1← 9321 BEQ | ||||||||||
| TSX ; Bump the local count in the frame | |||||||||||
| 9342 | INC frame_local_count,x ; at frame offset +6 | ||||||||||
| 9345 | LDY zp_text_ptr2_off ; Sync the program pointer | ||||||||||
| 9347 | STY zp_text_ptr_off ; from the PtrB offset | ||||||||||
| 9349 | JSR skip_spaces ; Skip spaces | ||||||||||
| 934C | CMP #',' ; A comma introduces another LOCAL | ||||||||||
| 934E | BEQ stmt_local ; yes | ||||||||||
| 9350 | JMP stmt_backup_end ; next statement | ||||||||||
| 9353 | .local_not_var←1← 932B BEQ | ||||||||||
| JMP stmt_check_end ; not a variable: error | |||||||||||
ENDPROCReturn from a procedure. Checks a PROC frame is present (the framed token at &01FF must be &F2), then falls into the end-of-statement path whose rts unwinds the frame back through call_proc_fn (&B197) -- restoring LOCAL values, the caller's text pointer and the saved 6502/value stacks. It does NOT tidy the FOR/REPEAT/GOSUB stacks, so ENDPROC from inside a loop leaks that loop's frame. ENDPROC.
|
|||||||||||
| 9356 | .stmt_endproc | ||||||||||
| TSX ; ENDPROC needs a PROC frame on the stack | |||||||||||
| 9357 | CPX #&fc ; stack near empty (no PROC frame)? | ||||||||||
| 9359 | BCS no_proc_error ; no frame: Not PROC error | ||||||||||
| 935B | LDA hw_stack_top ; Framed call token | ||||||||||
| 935E | CMP #&f2 ; The framed call must be a PROC | ||||||||||
| 9360 | BNE no_proc_error ; not PROC: error | ||||||||||
| 9362 | JMP check_end_of_statement ; Return to the caller, restoring locals | ||||||||||
| 9365 | .no_proc_error←2← 9359 BCS← 9360 BNE | ||||||||||
| BRK ; No PROC error | |||||||||||
| 9366 | EQUB &0D | ||||||||||
| 9367 | EQUS "No " | ||||||||||
| 936A | EQUB &F2 | ||||||||||
| 936B | .not_local_error←1← 9326 BCS | ||||||||||
| BRK ; Not LOCAL error | |||||||||||
| 936C | EQUB &0C | ||||||||||
| 936D | EQUS "Not " | ||||||||||
| 9371 | EQUB &EA | ||||||||||
| 9372 | .bad_statement←4← 93B2 BNE← 93B8 BNE← 93C6 BCC← 93CD BCC | ||||||||||
| BRK ; Bad statement error | |||||||||||
| 9373 | EQUB &19 | ||||||||||
| 9374 | EQUS "Bad " | ||||||||||
| 9378 | EQUB &EB, &00 | ||||||||||
GCOLSet the graphics colour and plotting action. GCOL action, colour.
|
|||||||||||
| 937A | .stmt_gcol | ||||||||||
| JSR eval_expr_to_integer ; Evaluate the GCOL mode | |||||||||||
| 937D | LDA zp_iwa ; save it | ||||||||||
| 937F | PHA ; push the GCOL mode | ||||||||||
| 9380 | JSR eval_comma_integer ; Step past the comma, evaluate the colour | ||||||||||
| 9383 | JSR sync_text_ptr ; check the statement ends | ||||||||||
| 9386 | LDA #&12 ; VDU 18 (GCOL) | ||||||||||
| 9388 | JSR oswrch ; send it | ||||||||||
| 938B | JMP mode_send ; send the mode and colour | ||||||||||
COLOURSelect the text colour or redefine a logical colour. COLOUR n.
|
|||||||||||
| 938E | .stmt_colour | ||||||||||
| LDA #&11 ; VDU 17 (COLOUR) | |||||||||||
| 9390 | PHA ; push it for later | ||||||||||
| 9391 | JSR eval_expr_to_integer ; Evaluate the colour | ||||||||||
| 9394 | JSR check_end_of_statement ; check the statement ends | ||||||||||
| 9397 | JMP mode_send ; send VDU 17 and the colour | ||||||||||
MODESelect a screen mode, resetting the display. MODE n.
|
|||||||||||
| 939A | .stmt_mode | ||||||||||
| LDA #&16 ; VDU 22 (MODE) | |||||||||||
| 939C | PHA ; push it for later | ||||||||||
| 939D | JSR eval_expr_to_integer ; Evaluate the mode number | ||||||||||
| 93A0 | JSR check_end_of_statement ; check the statement ends | ||||||||||
| 93A3 | JSR read_himem_byte ; Read the high word of the machine address | ||||||||||
| 93A6 | CPX #&ff ; not &xxFF: skip the memory test | ||||||||||
| 93A8 | BNE mode_reset_col ; addr not &xxFF: skip the check | ||||||||||
| 93AA | CPY #&ff ; not all ones: skip the memory test | ||||||||||
| 93AC | BNE mode_reset_col ; high byte &FF too: skip the check | ||||||||||
| 93AE | LDA zp_stack_ptr ; Stack not empty (STACK != HIMEM)? | ||||||||||
| 93B0 | CMP zp_himem ; STACK low vs HIMEM low | ||||||||||
| 93B2 | BNE bad_statement ; yes: Bad MODE | ||||||||||
| 93B4 | LDA zp_stack_ptr_1 ; STACK high, | ||||||||||
| 93B6 | CMP zp_himem_1 ; vs HIMEM high | ||||||||||
| 93B8 | BNE bad_statement ; Bad MODE | ||||||||||
| 93BA | LDX zp_iwa ; Top of RAM for this mode | ||||||||||
| 93BC | LDA #osbyte_read_himem_for_mode ; OSBYTE &85 | ||||||||||
| 93BE | JSR osbyte ; Read top of user RAM for given screen mode | ||||||||||
| 93C1 | CPX zp_vartop ; below the variables? | ||||||||||
| 93C3 | TYA ; new top high, | ||||||||||
| 93C4 | SBC zp_vartop_1 ; vs VARTOP high | ||||||||||
| 93C6 | BCC bad_statement ; yes: Bad MODE | ||||||||||
| 93C8 | CPX zp_top ; below the program top? | ||||||||||
| 93CA | TYA ; new top high, | ||||||||||
| 93CB | SBC zp_top_1 ; vs TOP high | ||||||||||
| 93CD | BCC bad_statement ; yes: Bad MODE | ||||||||||
| 93CF | STX zp_himem ; Set HIMEM and STACK to the new top | ||||||||||
| 93D1 | STX zp_stack_ptr ; STACK low, | ||||||||||
| 93D3 | STY zp_himem_1 ; HIMEM high, | ||||||||||
| 93D5 | STY zp_stack_ptr_1 ; STACK high | ||||||||||
| 93D7 | .mode_reset_col←2← 93A8 BNE← 93AC BNE | ||||||||||
| JSR reset_print_column ; Reset the print column | |||||||||||
| 93DA | .mode_send←2← 938B JMP← 9397 JMP | ||||||||||
| PLA ; Send the stacked VDU byte | |||||||||||
| 93DB | JSR oswrch ; send it | ||||||||||
| 93DE | JSR vdu_send_byte ; Send the parameter | ||||||||||
| 93E1 | JMP statement_loop ; next statement | ||||||||||
MOVEMove the graphics cursor without drawing (PLOT 4). MOVE x, y.
|
|||||||||||
| 93E4 | .stmt_move | ||||||||||
| LDA #4 ; MOVE is PLOT 4 (move the cursor, no draw) | |||||||||||
| 93E6 | BNE draw_save_mode ; do the PLOT | ||||||||||
| fall through ↓ | |||||||||||
DRAWDraw a line from the graphics cursor to a point (PLOT 5). DRAW x, y.
|
|||||||||||
| 93E8 | .stmt_draw | ||||||||||
| LDA #5 ; DRAW is PLOT 5 (draw a line) | |||||||||||
| 93EA | .draw_save_mode←1← 93E6 BNE | ||||||||||
| PHA ; Save the plot mode | |||||||||||
| 93EB | JSR eval_expr ; Evaluate the X coordinate | ||||||||||
| 93EE | JMP plot_coord ; evaluate Y and plot | ||||||||||
PLOTPlot a point, line or shape with a given mode. PLOT mode, x, y.
|
|||||||||||
| 93F1 | .stmt_plot | ||||||||||
| JSR eval_expr_to_integer ; Evaluate the plot mode | |||||||||||
| 93F4 | LDA zp_iwa ; save it | ||||||||||
| 93F6 | PHA ; push the plot mode | ||||||||||
| 93F7 | JSR skip_spaces_expect_comma ; Step past the comma | ||||||||||
| 93FA | JSR eval_or_eor ; Evaluate the X coordinate | ||||||||||
| 93FD | .plot_coord←1← 93EE JMP | ||||||||||
| JSR coerce_var_to_integer ; ensure integer | |||||||||||
| 9400 | JSR stack_integer ; stack X | ||||||||||
| 9403 | JSR eval_comma_integer ; Step past the comma, evaluate Y | ||||||||||
| 9406 | JSR sync_text_ptr ; check the statement ends | ||||||||||
| 9409 | LDA #&19 ; VDU 25 (PLOT) | ||||||||||
| 940B | JSR oswrch ; send it | ||||||||||
| 940E | PLA ; Send the plot action | ||||||||||
| 940F | JSR oswrch ; send it | ||||||||||
| 9412 | JSR unstack_int_to_general ; Pop X | ||||||||||
| 9415 | LDA zp_general ; Send X low | ||||||||||
| 9417 | JSR oswrch ; send it | ||||||||||
| 941A | LDA zp_general_1 ; Send X high | ||||||||||
| 941C | JSR oswrch ; send it | ||||||||||
| 941F | JSR vdu_send_byte ; Send Y low | ||||||||||
| 9422 | LDA zp_iwa_1 ; Send Y high | ||||||||||
| 9424 | JSR oswrch ; send it | ||||||||||
| 9427 | JMP statement_loop ; next statement | ||||||||||
| 942A | .plot_send_hi←1← 9451 BEQ | ||||||||||
| LDA zp_iwa_1 ; Send the high byte | |||||||||||
| 942C | JSR oswrch ; send it | ||||||||||
| fall through ↓ | |||||||||||
VDUSend bytes to the VDU drivers; ";" sends a 16-bit word. VDU n[,|;]...
|
|||||||||||
| 942F | .stmt_vdu←1← 944B BEQ | ||||||||||
| JSR skip_spaces ; Next character | |||||||||||
| 9432 | .vdu_loop←1← 944F BNE | ||||||||||
| CMP #':' ; ':' end of statement? | |||||||||||
| 9434 | BEQ vdu_done ; yes | ||||||||||
| 9436 | CMP #&0d ; end of line? | ||||||||||
| 9438 | BEQ vdu_done ; yes | ||||||||||
| 943A | CMP #&8b ; ELSE? | ||||||||||
| 943C | BEQ vdu_done ; yes | ||||||||||
| 943E | DEC zp_text_ptr_off ; Back up to the value | ||||||||||
| 9440 | JSR eval_expr_to_integer ; Evaluate it | ||||||||||
| 9443 | JSR vdu_send_byte ; send the low byte | ||||||||||
| 9446 | JSR skip_spaces ; Next character | ||||||||||
| 9449 | CMP #',' ; ',' another byte? | ||||||||||
| 944B | BEQ stmt_vdu ; yes | ||||||||||
| 944D | CMP #';' ; ';' 16-bit value? | ||||||||||
| 944F | BNE vdu_loop ; no: check the statement ends | ||||||||||
| 9451 | BEQ plot_send_hi ; yes: send the high byte too | ||||||||||
| 9453 | .vdu_done←3← 9434 BEQ← 9438 BEQ← 943C BEQ | ||||||||||
| JMP stmt_backup_end ; next statement | |||||||||||
Send the integer accumulator low byte to OSWRCHLoad the low byte of the integer work accumulator and send it to the VDU by jumping through WRCHV (OSWRCH), which returns to the caller. Used to output a computed byte value.
|
|||||||
| 9456 | .vdu_send_byte←4← 8E3A JSR← 93DE JSR← 941F JSR← 9443 JSR | ||||||
| LDA zp_iwa ; Send the low byte to OSWRCH | |||||||
| 9458 | JMP (wrchv) ; jump through WRCHV (OSWRCH) | ||||||
Find a PROC or FN definition by nameSearch the PROC (token &F2) or FN linked list for a definition whose name starts at (zp_general)+1. Shares the chain walk with find_variable; returns a pointer to the body, or "not found".
|
|||||||||||
| 945B | .find_proc_fn←1← B1E1 JSR | ||||||||||
| LDY #1 ; Look at the PROC/FN token | |||||||||||
| 945D | LDA (zp_general),y ; get it | ||||||||||
| 945F | LDY #&f6 ; Index the PROC / FN entries of the variable table | ||||||||||
| 9461 | CMP #&f2 ; Is it PROC (&F2)? | ||||||||||
| 9463 | BEQ findvar_chain_head ; PROC: scan the PROC list | ||||||||||
| 9465 | LDY #&f8 ; FN: point at the FN list head | ||||||||||
| 9467 | BNE findvar_chain_head ; scan the FN list | ||||||||||
| fall through ↓ | |||||||||||
Find a variable by nameSearch the heap for a variable whose name starts at (zp_general)+1. The initial character selects one of the per-letter linked lists via the variable table; the chain is walked comparing the rest of the name. On a match, returns a pointer to the value in zp_iwa/zp_iwa_1; otherwise reports it is not present.
|
|||||||||||
| ; Each variable chain (one per initial letter) is a list of | |||||||||||
| ; entries: a 2-byte link to the next, the rest of the name, a | |||||||||||
| ; NUL, then the value. The walk alternates two node pointers | |||||||||||
| ; (&3A/&3B and &3C/&3D), reading one node's link while it | |||||||||||
| ; compares the other - so it never copies a whole pointer. | |||||||||||
| ; On a match IWA points at the value; zp_fileblk holds the | |||||||||||
| ; length of the name being sought. | |||||||||||
| 9469 | .find_variable←4← 916F JSR← 965A JSR← 96BC JSR← 96DF JSR | ||||||||||
| LDY #1 ; Point at the first character of the name | |||||||||||
| 946B | LDA (zp_general),y ; get it | ||||||||||
| 946D | ASL ; Two bytes per entry: double the initial letter | ||||||||||
| 946E | TAY ; Y = 2 * char: index into the variable table | ||||||||||
| 946F | .findvar_chain_head←2← 9463 BEQ← 9467 BNE | ||||||||||
| LDA resint_at,y ; Head of the chain from the variable table (&0400+2*ch) | |||||||||||
| 9472 | STA zp_fileblk_1 ; Chain head low byte -> node pointer (&3A) | ||||||||||
| 9474 | LDA resint_at_1,y ; Chain head high byte (&0400 + 1 + 2*char) | ||||||||||
| 9477 | STA zp_fwb_sign ; node pointer high (&3B) | ||||||||||
| 9479 | .findvar_walk←4← 94CA BNE← 94D2 BEQ← 94D6 BNE← 94DF BNE | ||||||||||
| LDA zp_fwb_sign ; End of the chain: variable not found | |||||||||||
| 947B | BEQ return_10 ; Zero high byte: end of chain, not found | ||||||||||
| 947D | LDY #0 ; Read the node: offset 0 | ||||||||||
| 947F | LDA (zp_fileblk_1),y ; link low byte... | ||||||||||
| 9481 | STA zp_fwb_ovf ; ...saved (&3C) | ||||||||||
| 9483 | INY ; offset 1 | ||||||||||
| 9484 | LDA (zp_fileblk_1),y ; link high byte... | ||||||||||
| 9486 | STA zp_fwb_exp ; ...saved (&3D) | ||||||||||
| 9488 | INY ; offset 2: first stored name character | ||||||||||
| 9489 | LDA (zp_fileblk_1),y ; get it | ||||||||||
| 948B | BNE findvar_cmp_a ; Non-null: compare the name | ||||||||||
| 948D | DEY ; Null name (the base entry): ... | ||||||||||
| 948E | CPY zp_fileblk ; did the search name end too? | ||||||||||
| 9490 | BNE findvar_walk_b ; no: follow the link | ||||||||||
| 9492 | INY ; advance | ||||||||||
| 9493 | BCS findvar_match_a ; match: compute the value pointer | ||||||||||
| 9495 | .findvar_cmp_a_loop←1← 94A0 BNE | ||||||||||
| INY ; Compare the rest of the name against this entry | |||||||||||
| 9496 | LDA (zp_fileblk_1),y ; next stored name character | ||||||||||
| 9498 | BEQ findvar_walk_b ; entry name ended early: no match | ||||||||||
| 949A | .findvar_cmp_a←1← 948B BNE | ||||||||||
| CMP (zp_general),y ; compare with the search name | |||||||||||
| 949C | BNE findvar_walk_b ; differ: follow the link | ||||||||||
| 949E | CPY zp_fileblk ; reached the end of the search name? | ||||||||||
| 94A0 | BNE findvar_cmp_a_loop ; no: keep comparing | ||||||||||
| 94A2 | INY ; does the entry name end here too? | ||||||||||
| 94A3 | LDA (zp_fileblk_1),y ; read the stored name char | ||||||||||
| 94A5 | BNE findvar_walk_b ; entry name is longer: no match | ||||||||||
| 94A7 | .findvar_match_a←1← 9493 BCS | ||||||||||
| TYA ; Match: return a pointer to the value | |||||||||||
| 94A8 | ADC zp_fileblk_1 ; value pointer = node + name length: low | ||||||||||
| 94AA | STA zp_iwa ; (IWA low) | ||||||||||
| 94AC | LDA zp_fwb_sign ; node high... | ||||||||||
| 94AE | ADC #0 ; + carry | ||||||||||
| 94B0 | STA zp_iwa_1 ; IWA high = pointer to the value | ||||||||||
| 94B2 | .return_10←2← 947B BEQ← 94B5 BEQ | ||||||||||
| RTS ; Return (IWA = value pointer, or not found) | |||||||||||
| 94B3 | .findvar_walk_b←4← 9490 BNE← 9498 BEQ← 949C BNE← 94A5 BNE | ||||||||||
| LDA zp_fwb_exp ; No match: follow the link to the next entry | |||||||||||
| 94B5 | BEQ return_10 ; Zero high byte: end of chain, not found | ||||||||||
| 94B7 | LDY #0 ; Read the next node via its saved link (&3C) | ||||||||||
| 94B9 | LDA (zp_fwb_ovf),y ; link low byte... | ||||||||||
| 94BB | STA zp_fileblk_1 ; ...into the node pointer (&3A) | ||||||||||
| 94BD | INY ; offset 1 | ||||||||||
| 94BE | LDA (zp_fwb_ovf),y ; link high byte... | ||||||||||
| 94C0 | STA zp_fwb_sign ; ...(&3B) | ||||||||||
| 94C2 | INY ; offset 2: name character | ||||||||||
| 94C3 | LDA (zp_fwb_ovf),y ; get it | ||||||||||
| 94C5 | BNE findvar_cmp_b ; Non-null: compare the name | ||||||||||
| 94C7 | DEY ; Null name: ... | ||||||||||
| 94C8 | CPY zp_fileblk ; did the search name end too? | ||||||||||
| 94CA | BNE findvar_walk ; no: back to the other-pointer loop | ||||||||||
| 94CC | INY ; advance | ||||||||||
| 94CD | BCS findvar_match_b ; match: compute the value pointer | ||||||||||
| 94CF | .findvar_cmp_b_loop←1← 94DA BNE | ||||||||||
| INY ; compare loop | |||||||||||
| 94D0 | LDA (zp_fwb_ovf),y ; next stored character | ||||||||||
| 94D2 | BEQ findvar_walk ; entry name ended: no match | ||||||||||
| 94D4 | .findvar_cmp_b←1← 94C5 BNE | ||||||||||
| CMP (zp_general),y ; compare with the search name | |||||||||||
| 94D6 | BNE findvar_walk ; differ: next entry | ||||||||||
| 94D8 | CPY zp_fileblk ; end of the search name? | ||||||||||
| 94DA | BNE findvar_cmp_b_loop ; no: keep comparing | ||||||||||
| 94DC | INY ; does the entry name end here too? | ||||||||||
| 94DD | LDA (zp_fwb_ovf),y ; read the stored name char | ||||||||||
| 94DF | BNE findvar_walk ; entry name is longer: no match | ||||||||||
| 94E1 | .findvar_match_b←1← 94CD BCS | ||||||||||
| TYA ; value pointer = node + name length: low | |||||||||||
| 94E2 | ADC zp_fwb_ovf ; plus the node low | ||||||||||
| 94E4 | STA zp_iwa ; (IWA low) | ||||||||||
| 94E6 | LDA zp_fwb_exp ; node high... | ||||||||||
| 94E8 | ADC #0 ; + carry | ||||||||||
| 94EA | STA zp_iwa_1 ; IWA high = pointer to the value | ||||||||||
| 94EC | RTS ; Return the value pointer | ||||||||||
| 94ED | .create_def_entry←1← B171 JSR | ||||||||||
| LDY #1 ; Look at the PROC/FN token | |||||||||||
| 94EF | LDA (zp_general),y ; get it | ||||||||||
| 94F1 | TAX ; to X | ||||||||||
| 94F2 | LDA #&f6 ; PROC list index (&F6) | ||||||||||
| 94F4 | CPX #&f2 ; Is it PROC? | ||||||||||
| 94F6 | BEQ createvar_chain ; PROC: use that chain | ||||||||||
| 94F8 | LDA #&f8 ; FN list index (&F8) | ||||||||||
| 94FA | BNE createvar_chain ; use the FN chain | ||||||||||
| fall through ↓ | |||||||||||
Create a new variableAppend a new variable entry at VARTOP: walk to the end of the per-letter chain, link in the new node, and copy the name into it. The caller initialises the value bytes (clear_value_bytes) and advances VARTOP (sub_c9539).
|
|||||||||||||
| 94FC | .create_variable←3← 8BD5 JSR← 9174 JSR← 9589 JSR | ||||||||||||
| LDY #1 ; First character of the name | |||||||||||||
| 94FE | LDA (zp_general),y ; get it | ||||||||||||
| 9500 | ASL ; double it to index the variable table | ||||||||||||
| 9501 | .createvar_chain←2← 94F6 BEQ← 94FA BNE | ||||||||||||
| STA zp_fileblk_1 ; chain pointer low (&3A) | |||||||||||||
| 9503 | LDA #4 ; table base high page (&04) | ||||||||||||
| 9505 | STA zp_fwb_sign ; chain pointer high (&3B) | ||||||||||||
| 9507 | .createvar_walk_loop←1← 9514 BPL | ||||||||||||
| LDA (zp_fileblk_1),y ; Walk to the end of the chain: link high | |||||||||||||
| 9509 | BEQ createvar_link ; zero: found the end, append here | ||||||||||||
| 950B | TAX ; save it | ||||||||||||
| 950C | DEY ; link low | ||||||||||||
| 950D | LDA (zp_fileblk_1),y ; read it | ||||||||||||
| 950F | STA zp_fileblk_1 ; follow the link: low | ||||||||||||
| 9511 | STX zp_fwb_sign ; high | ||||||||||||
| 9513 | INY ; advance | ||||||||||||
| 9514 | BPL createvar_walk_loop ; loop | ||||||||||||
| 9516 | .createvar_link←1← 9509 BEQ | ||||||||||||
| LDA zp_vartop_1 ; Link the new entry (at VARTOP): high... | |||||||||||||
| 9518 | STA (zp_fileblk_1),y ; ...into the previous link | ||||||||||||
| 951A | LDA zp_vartop ; low... | ||||||||||||
| 951C | DEY ; point at the low link byte | ||||||||||||
| 951D | STA (zp_fileblk_1),y ; (store) | ||||||||||||
| 951F | TYA ; the new entry header | ||||||||||||
| 9520 | INY ; next entry byte | ||||||||||||
| 9521 | STA (zp_vartop),y ; (store) | ||||||||||||
| 9523 | CPY zp_fileblk ; name length reached? | ||||||||||||
| 9525 | BEQ return_11 ; done | ||||||||||||
| 9527 | .createvar_copy_loop←1← 952E BNE | ||||||||||||
| INY ; Copy the name into the entry: | |||||||||||||
| 9528 | LDA (zp_general),y ; name char... | ||||||||||||
| 952A | STA (zp_vartop),y ; ...into the entry | ||||||||||||
| 952C | CPY zp_fileblk ; all of the name? | ||||||||||||
| 952E | BNE createvar_copy_loop ; loop | ||||||||||||
| 9530 | RTS ; Return | ||||||||||||
Zero a run of value bytesWrite X zero bytes after a new variable name at (zp_vartop),Y, initialising its value to zero.
|
|||||||||||||||||
| 9531 | .clear_value_bytes←4← 8BDF JSR← 9179 JSR← 957F JSR← B176 JSR | ||||||||||||||||
| LDA #0 ; Zero X value bytes after the name: | |||||||||||||||||
| 9533 | .clearval_loop←1← 9537 BNE | ||||||||||||||||
| INY ; advance | |||||||||||||||||
| 9534 | STA (zp_vartop),y ; clear a byte | ||||||||||||||||
| 9536 | DEX ; count down | ||||||||||||||||
| 9537 | BNE clearval_loop ; loop | ||||||||||||||||
| 9539 | .advance_vartop←1← B184 JSR | ||||||||||||||||
| SEC ; Advance VARTOP past the new entry: | |||||||||||||||||
| 953A | TYA ; Y = bytes used | ||||||||||||||||
| 953B | ADC zp_vartop ; low | ||||||||||||||||
| 953D | BCC vartop_check ; no carry into the high byte | ||||||||||||||||
| 953F | INC zp_vartop_1 ; carry into high | ||||||||||||||||
| 9541 | .vartop_check←1← 953D BCC | ||||||||||||||||
| LDY zp_vartop_1 ; Check VARTOP hasn't reached the stack: | |||||||||||||||||
| 9543 | CPY zp_stack_ptr_1 ; compare high | ||||||||||||||||
| 9545 | BCC vartop_commit ; below: room | ||||||||||||||||
| 9547 | BNE vartop_no_room ; above: no room | ||||||||||||||||
| 9549 | CMP zp_stack_ptr ; equal: compare low | ||||||||||||||||
| 954B | BCC vartop_commit ; below: room | ||||||||||||||||
| 954D | .vartop_no_room←1← 9547 BNE | ||||||||||||||||
| LDA #0 ; No room: unlink the new entry... | |||||||||||||||||
| 954F | LDY #1 ; link field offset | ||||||||||||||||
| 9551 | STA (zp_fileblk_1),y ; (clear the link) | ||||||||||||||||
| 9553 | JMP err_no_room ; No room error | ||||||||||||||||
| 9556 | .vartop_commit←2← 9545 BCC← 954B BCC | ||||||||||||||||
| STA zp_vartop ; Commit the new VARTOP | |||||||||||||||||
| 9558 | .return_11←1← 9525 BEQ | ||||||||||||||||
| RTS ; Return | |||||||||||||||||
Validate / measure a variable nameScan the variable name at (zp_general)+1, stopping at the first non-name character (letters, digits and _ are accepted; a leading digit is rejected, giving an empty name). Advances X as the running text offset.
|
|||||||||||||
| 9559 | .validate_var_name←1← 914B JSR | ||||||||||||
| LDY #1 ; Validate the name from offset 1: | |||||||||||||
| 955B | .valname_loop←2← 956F BNE← B1D5 JSR | ||||||||||||
| LDA (zp_general),y ; character... | |||||||||||||
| 955D | CMP #'0' ; below "0": end of name | ||||||||||||
| 955F | BCC return_12 ; below "0": stop | ||||||||||||
| 9561 | CMP #'@' ; in the digit/symbol range? | ||||||||||||
| 9563 | BCS valname_check_uc ; letter range: continue | ||||||||||||
| 9565 | CMP #':' ; ":" or above (not a digit)? | ||||||||||||
| 9567 | BCS return_12 ; not a name character: stop | ||||||||||||
| 9569 | CPY #1 ; is this the first character? | ||||||||||||
| 956B | BEQ return_12 ; names can't start with a digit | ||||||||||||
| 956D | .valname_count←2← 9577 BCC← 957C BCC | ||||||||||||
| INX ; count the character | |||||||||||||
| 956E | INY ; next | ||||||||||||
| 956F | BNE valname_loop ; loop | ||||||||||||
| 9571 | .valname_check_uc←1← 9563 BCS | ||||||||||||
| CMP #'_' ; below "_"? | |||||||||||||
| 9573 | BCS valname_check_lc ; "_" or lower-case: accept | ||||||||||||
| 9575 | CMP #'[' ; A-Z? | ||||||||||||
| 9577 | BCC valname_count ; letter: accept | ||||||||||||
| 9579 | .return_12←3← 955F BCC← 9567 BCS← 956B BEQ | ||||||||||||
| RTS ; Return | |||||||||||||
| 957A | .valname_check_lc←1← 9573 BCS | ||||||||||||
| CMP #'{' ; a-z? | |||||||||||||
| 957C | BCC valname_count ; accept | ||||||||||||
| 957E | RTS ; Return | ||||||||||||
| 957F | .zero_new_value←2← 9590 BNE← 9593 BNE | ||||||||||||
| JSR clear_value_bytes ; Zero the value bytes of the new variable | |||||||||||||
| fall through ↓ | |||||||||||||
Parse an assignment target variableParse the variable reference being assigned to (parse_var_ref)
and return a pointer to its storage plus its type, creating the variable
(create_variable + clear_value_bytes) if it does not yet exist. Shared
by LET, FOR (
|
|||||||||||
| 9582 | .parse_lvalue←9← 85A5 JSR← 8BE4 JSR← 90E1 JSR← 9328 JSR← B256 JSR← B7C4 JSR← B9E4 JSR← BA7F JSR← BB1F JSR | ||||||||||
| JSR parse_var_ref ; Parse the variable reference | |||||||||||
| 9585 | BNE return_13 ; found: return | ||||||||||
| 9587 | BCS return_13 ; indirection/array: return | ||||||||||
| 9589 | JSR create_variable ; undefined: create the variable | ||||||||||
| 958C | LDX #5 ; Decide how many value bytes to clear | ||||||||||
| 958E | CPX zp_iwa_2 ; integer type (4) or real (5)? | ||||||||||
| 9590 | BNE zero_new_value ; integer: clear 5 bytes | ||||||||||
| 9592 | INX ; real: clear 6 bytes | ||||||||||
| 9593 | BNE zero_new_value ; then retry the parse so it is found | ||||||||||
| 9595 | .lvalue_indirect←1← 95DF BCC | ||||||||||
| CMP #'!' ; '!' indirection? | |||||||||||
| 9597 | BEQ lvalue_word ; yes: word indirection | ||||||||||
| 9599 | CMP #'$' ; '$' indirection? | ||||||||||
| 959B | BEQ lvalue_dollar ; yes: string indirection | ||||||||||
| 959D | EOR #&3f ; '?' indirection? | ||||||||||
| 959F | BEQ lvalue_save_width ; yes: byte indirection | ||||||||||
| 95A1 | LDA #0 ; none: not an lvalue | ||||||||||
| 95A3 | SEC ; set carry (not an lvalue) | ||||||||||
| 95A4 | .return_13←2← 9585 BNE← 9587 BCS | ||||||||||
| RTS ; Return | |||||||||||
| 95A5 | .lvalue_word←1← 9597 BEQ | ||||||||||
| LDA #4 ; '!': word width (4) | |||||||||||
| 95A7 | .lvalue_save_width←1← 959F BEQ | ||||||||||
| PHA ; Save the width | |||||||||||
| 95A8 | INC zp_text_ptr2_off ; step past the operator | ||||||||||
| 95AA | JSR eval_factor_integer ; evaluate the address | ||||||||||
| 95AD | JMP pvr_restore_type ; finish as an indirection | ||||||||||
| 95B0 | .lvalue_dollar←1← 959B BEQ | ||||||||||
| INC zp_text_ptr2_off ; '$': step past the operator | |||||||||||
| 95B2 | JSR eval_factor_integer ; evaluate the address | ||||||||||
| 95B5 | LDA zp_iwa_1 ; address in zero page? | ||||||||||
| 95B7 | BEQ lvalue_range_error ; yes: $ range error | ||||||||||
| 95B9 | LDA #&80 ; Type = string indirection (&80) | ||||||||||
| 95BB | STA zp_iwa_2 ; store the type byte | ||||||||||
| 95BD | SEC ; found: SEC | ||||||||||
| 95BE | RTS ; Return | ||||||||||
| 95BF | .lvalue_range_error←1← 95B7 BEQ | ||||||||||
| BRK ; $ range error | |||||||||||
| 95C0 | EQUB &08 | ||||||||||
| 95C1 | EQUS "$ range" | ||||||||||
| 95C8 | EQUB &00 | ||||||||||
Parse a variable reference / lvalueScan a variable name, array element, or indirection operator at the text pointer. Sets the value address in &2A/&2B and a type byte in &2C: 0=? byte indirection, 4=integer (also ! word indirection), 5=real, &80=$ indirection, &81=string lvalue. Returns A nonzero when resolved; A=0 carry clear for a valid name not yet defined (caller creates it), A=0 carry set when no name is present.
|
|||||||||||||||
| 95C9 | .parse_var_ref←2← 9582 JSR← B695 JSR | ||||||||||||||
| LDA zp_text_ptr ; Copy the text pointer into the scan pointer | |||||||||||||||
| 95CB | STA zp_text_ptr2 ; low byte, | ||||||||||||||
| 95CD | LDA zp_text_ptr_1 ; high byte, | ||||||||||||||
| 95CF | STA zp_text_ptr2_1 ; store it | ||||||||||||||
| 95D1 | LDY zp_text_ptr_off ; Start one before the text offset | ||||||||||||||
| 95D3 | DEY ; (the scan loop pre-increments) | ||||||||||||||
| 95D4 | .pvr_advance←1← 95DB BEQ | ||||||||||||||
| INY ; Advance | |||||||||||||||
| 95D5 | .pvr_record_offset←1← 8EEC JSR | ||||||||||||||
| STY zp_text_ptr2_off ; Record the scan offset | |||||||||||||||
| 95D7 | LDA (zp_text_ptr2),y ; Next character | ||||||||||||||
| 95D9 | CMP #' ' ; space? | ||||||||||||||
| 95DB | BEQ pvr_advance ; skip spaces | ||||||||||||||
| fall through ↓ | |||||||||||||||
Parse a variable reference at the scan pointerAlternate entry to parse_var_ref for callers that have already pointed the scan pointer zp_text_ptr2 (&19/&1A) at the first non-space character (in A). Classify the reference as an indirection operator, a resident integer (A%..Z%), or a named/array variable, setting the value address in zp_iwa (&2A/&2B) and the type byte in zp_iwa_2 (&2C).
|
|||||||||||||||||
| 95DD | .pvr_parse←2← 8BC9 JSR← AE22 JSR | ||||||||||||||||
| CMP #'@' ; below '@': an indirection operator | |||||||||||||||||
| 95DF | BCC lvalue_indirect ; below '@': handle as indirection ($ ! ?) | ||||||||||||||||
| 95E1 | CMP #'[' ; above 'Z'? | ||||||||||||||||
| 95E3 | BCS pvr_named ; yes: a named (dynamic) variable | ||||||||||||||||
| 95E5 | ASL ; Resident integer: hash char to &0400 + char*4 | ||||||||||||||||
| 95E6 | ASL ; (continued) | ||||||||||||||||
| 95E7 | STA zp_iwa ; value pointer low | ||||||||||||||||
| 95E9 | LDA #4 ; page &04 | ||||||||||||||||
| 95EB | STA zp_iwa_1 ; value pointer high byte (&2B) | ||||||||||||||||
| 95ED | INY ; Second character | ||||||||||||||||
| 95EE | LDA (zp_text_ptr2),y ; read it | ||||||||||||||||
| 95F0 | INY ; advance the scan offset | ||||||||||||||||
| 95F1 | CMP #'%' ; must be '%' for a resident integer | ||||||||||||||||
| 95F3 | BNE pvr_named ; not %: treat as a named variable | ||||||||||||||||
| 95F5 | LDX #4 ; Type = integer | ||||||||||||||||
| 95F7 | STX zp_iwa_2 ; store in the type byte (&2C) | ||||||||||||||||
| 95F9 | LDA (zp_text_ptr2),y ; Following character | ||||||||||||||||
| 95FB | CMP #'(' ; '(' -> array element | ||||||||||||||||
| 95FD | BNE pvr_check_indirect ; yes: handle as an array | ||||||||||||||||
| 95FF | .pvr_named←2← 95E3 BCS← 95F3 BNE | ||||||||||||||||
| LDX #5 ; Named variable: type = real/string (5) | |||||||||||||||||
| 9601 | STX zp_iwa_2 ; store in the type byte (&2C) | ||||||||||||||||
| 9603 | LDA zp_text_ptr2_off ; Point &37/&38 at the name in the text | ||||||||||||||||
| 9605 | CLC ; offset + scan pointer: | ||||||||||||||||
| 9606 | ADC zp_text_ptr2 ; low byte, | ||||||||||||||||
| 9608 | LDX zp_text_ptr2_1 ; high byte in X, | ||||||||||||||||
| 960A | BCC pvr_name_setup ; no carry into the high byte | ||||||||||||||||
| 960C | INX ; carry into the high byte | ||||||||||||||||
| 960D | CLC ; clear carry to back up one | ||||||||||||||||
| 960E | .pvr_name_setup←1← 960A BCC | ||||||||||||||||
| SBC #0 ; back up one (name reads from offset 1): low | |||||||||||||||||
| 9610 | STA zp_general ; &37 = name pointer low | ||||||||||||||||
| 9612 | BCS pvr_name_ptr_hi ; no borrow into the high byte | ||||||||||||||||
| 9614 | DEX ; borrow into the high byte | ||||||||||||||||
| 9615 | .pvr_name_ptr_hi←1← 9612 BCS | ||||||||||||||||
| STX zp_general_1 ; &38 = name pointer high | |||||||||||||||||
| 9617 | LDX zp_text_ptr2_off ; Reset the length counter | ||||||||||||||||
| 9619 | LDY #1 ; scan the name from offset 1 | ||||||||||||||||
| 961B | .pvr_scan_loop←3← 962B BNE← 9633 BNE← 963F BNE | ||||||||||||||||
| LDA (zp_general),y ; Scan the name: next character | |||||||||||||||||
| 961D | CMP #'A' ; below 'A'? | ||||||||||||||||
| 961F | BCS pvr_scan_check_uc ; no: check letters | ||||||||||||||||
| 9621 | CMP #'0' ; a digit? | ||||||||||||||||
| 9623 | BCC pvr_name_end ; no: name ends | ||||||||||||||||
| 9625 | CMP #':' ; above '9'? | ||||||||||||||||
| 9627 | BCS pvr_name_end ; no: name ends | ||||||||||||||||
| 9629 | INX ; count this character | ||||||||||||||||
| 962A | INY ; advance the scan | ||||||||||||||||
| 962B | BNE pvr_scan_loop ; continue | ||||||||||||||||
| 962D | .pvr_scan_check_uc←1← 961F BCS | ||||||||||||||||
| CMP #'[' ; above 'Z'? | |||||||||||||||||
| 962F | BCS pvr_scan_check_lc ; yes: check lower case | ||||||||||||||||
| 9631 | INX ; A-Z: count it | ||||||||||||||||
| 9632 | INY ; advance the scan | ||||||||||||||||
| 9633 | BNE pvr_scan_loop ; continue | ||||||||||||||||
| 9635 | .pvr_scan_check_lc←1← 962F BCS | ||||||||||||||||
| CMP #'_' ; below '_'? | |||||||||||||||||
| 9637 | BCC pvr_name_end ; yes: name ends | ||||||||||||||||
| 9639 | CMP #'{' ; above 'z'? | ||||||||||||||||
| 963B | BCS pvr_name_end ; yes: name ends | ||||||||||||||||
| 963D | INX ; _ or a-z: count it | ||||||||||||||||
| 963E | INY ; advance the scan | ||||||||||||||||
| 963F | BNE pvr_scan_loop ; continue | ||||||||||||||||
| 9641 | .pvr_name_end←4← 9623 BCC← 9627 BCS← 9637 BCC← 963B BCS | ||||||||||||||||
| DEY ; Back up to the terminator | |||||||||||||||||
| 9642 | BEQ pvr_no_name ; empty name: undefined | ||||||||||||||||
| 9644 | CMP #'$' ; '$' suffix -> string variable | ||||||||||||||||
| 9646 | BEQ pvr_string ; yes | ||||||||||||||||
| 9648 | CMP #'%' ; '%' suffix -> integer variable | ||||||||||||||||
| 964A | BNE pvr_name_len ; no: real variable | ||||||||||||||||
| 964C | DEC zp_iwa_2 ; mark the type integer | ||||||||||||||||
| 964E | INY ; step past the % | ||||||||||||||||
| 964F | INX ; count the % in the name length | ||||||||||||||||
| 9650 | INY ; peek at the following character | ||||||||||||||||
| 9651 | LDA (zp_general),y ; check the following character | ||||||||||||||||
| 9653 | DEY ; step back to the % | ||||||||||||||||
| 9654 | .pvr_name_len←1← 964A BNE | ||||||||||||||||
| STY zp_fileblk ; Record the name length | |||||||||||||||||
| 9656 | CMP #'(' ; '(' -> array element | ||||||||||||||||
| 9658 | BEQ pvr_resint_array ; yes | ||||||||||||||||
| 965A | JSR find_variable ; Look the variable up in storage | ||||||||||||||||
| 965D | BEQ pvr_undefined ; not found: undefined | ||||||||||||||||
| 965F | STX zp_text_ptr2_off ; Update the scan offset past the name | ||||||||||||||||
| 9661 | .pvr_after_name←1← 96AC JMP | ||||||||||||||||
| LDY zp_text_ptr2_off ; Next character after the name | |||||||||||||||||
| 9663 | LDA (zp_text_ptr2),y ; read it | ||||||||||||||||
| 9665 | .pvr_check_indirect←1← 95FD BNE | ||||||||||||||||
| CMP #'!' ; '!' indirection following? | |||||||||||||||||
| 9667 | BEQ pvr_word_indirect ; yes: word indirection | ||||||||||||||||
| 9669 | CMP #'?' ; '?' indirection following? | ||||||||||||||||
| 966B | BEQ pvr_byte_indirect ; yes: byte indirection | ||||||||||||||||
| 966D | CLC ; Plain variable: found | ||||||||||||||||
| 966E | STY zp_text_ptr2_off ; save the scan offset | ||||||||||||||||
| 9670 | LDA #&ff ; A = &FF (found) | ||||||||||||||||
| 9672 | RTS ; Return | ||||||||||||||||
| 9673 | .pvr_no_name←1← 9642 BEQ | ||||||||||||||||
| LDA #0 ; No name found: A=0, SEC | |||||||||||||||||
| 9675 | SEC ; (set carry: caller errors) | ||||||||||||||||
| 9676 | RTS ; Return | ||||||||||||||||
| 9677 | .pvr_undefined←2← 965D BEQ← 96BF BEQ | ||||||||||||||||
| LDA #0 ; Valid name, undefined: A=0, CLC | |||||||||||||||||
| 9679 | CLC ; (clear carry: caller creates it) | ||||||||||||||||
| 967A | RTS ; Return | ||||||||||||||||
| 967B | .pvr_byte_indirect←1← 966B BEQ | ||||||||||||||||
| LDA #0 ; '?' indirection: byte type (1) | |||||||||||||||||
| 967D | BEQ pvr_save_width ; always taken | ||||||||||||||||
| 967F | .pvr_word_indirect←1← 9667 BEQ | ||||||||||||||||
| LDA #4 ; '!' indirection: word type (4) | |||||||||||||||||
| 9681 | .pvr_save_width←1← 967D BEQ | ||||||||||||||||
| PHA ; Save the indirection width | |||||||||||||||||
| 9682 | INY ; step past the operator | ||||||||||||||||
| 9683 | STY zp_text_ptr2_off ; record the new scan offset | ||||||||||||||||
| 9685 | JSR load_var_by_type ; Stack the base address | ||||||||||||||||
| 9688 | JSR coerce_to_integer ; evaluate it as an integer | ||||||||||||||||
| 968B | LDA zp_iwa_1 ; Save the base address: | ||||||||||||||||
| 968D | PHA ; push high byte, | ||||||||||||||||
| 968E | LDA zp_iwa ; low byte, | ||||||||||||||||
| 9690 | PHA ; push it too | ||||||||||||||||
| 9691 | JSR eval_factor_integer ; evaluate the index expression | ||||||||||||||||
| 9694 | CLC ; address = base + index | ||||||||||||||||
| 9695 | PLA ; pull base low, | ||||||||||||||||
| 9696 | ADC zp_iwa ; + index low, | ||||||||||||||||
| 9698 | STA zp_iwa ; store low, | ||||||||||||||||
| 969A | PLA ; pull base high, | ||||||||||||||||
| 969B | ADC zp_iwa_1 ; + index high, | ||||||||||||||||
| 969D | STA zp_iwa_1 ; store high | ||||||||||||||||
| 969F | .pvr_restore_type←1← 95AD JMP | ||||||||||||||||
| PLA ; Restore the indirection type | |||||||||||||||||
| 96A0 | STA zp_iwa_2 ; into the type byte (0=? or 4=!) | ||||||||||||||||
| 96A2 | CLC ; found: A=&FF, CLC | ||||||||||||||||
| 96A3 | LDA #&ff ; A = &FF (found) | ||||||||||||||||
| 96A5 | RTS ; Return | ||||||||||||||||
| 96A6 | .pvr_resint_array←1← 9658 BEQ | ||||||||||||||||
| INX ; Resident-integer array: step past "(" | |||||||||||||||||
| 96A7 | INC zp_fileblk ; count the "(" in the name length too | ||||||||||||||||
| 96A9 | JSR index_array ; index the array | ||||||||||||||||
| 96AC | JMP pvr_after_name ; check for trailing ! or ? | ||||||||||||||||
| 96AF | .pvr_string←1← 9646 BEQ | ||||||||||||||||
| INX ; String variable: step past "$" | |||||||||||||||||
| 96B0 | INY ; advance the scan | ||||||||||||||||
| 96B1 | STY zp_fileblk ; record the name length | ||||||||||||||||
| 96B3 | INY ; peek at the char after the $ | ||||||||||||||||
| 96B4 | DEC zp_iwa_2 ; mark the type string | ||||||||||||||||
| 96B6 | LDA (zp_general),y ; following character | ||||||||||||||||
| 96B8 | CMP #'(' ; '(' -> string array | ||||||||||||||||
| 96BA | BEQ pvr_string_array ; yes | ||||||||||||||||
| 96BC | JSR find_variable ; Look the string variable up | ||||||||||||||||
| 96BF | BEQ pvr_undefined ; not found: undefined | ||||||||||||||||
| 96C1 | STX zp_text_ptr2_off ; Update the scan offset | ||||||||||||||||
| 96C3 | LDA #&81 ; Type = string lvalue (&81) | ||||||||||||||||
| 96C5 | STA zp_iwa_2 ; store in the type byte (&2C) | ||||||||||||||||
| 96C7 | SEC ; found: SEC | ||||||||||||||||
| 96C8 | RTS ; Return | ||||||||||||||||
| 96C9 | .pvr_string_array←1← 96BA BEQ | ||||||||||||||||
| INX ; String array: step past "(" | |||||||||||||||||
| 96CA | STY zp_fileblk ; record the name length | ||||||||||||||||
| 96CC | DEC zp_iwa_2 ; mark the type string | ||||||||||||||||
| 96CE | JSR index_array ; index the array | ||||||||||||||||
| 96D1 | LDA #&81 ; Type = string lvalue (&81) | ||||||||||||||||
| 96D3 | STA zp_iwa_2 ; store in the type byte (&2C) | ||||||||||||||||
| 96D5 | SEC ; found: SEC | ||||||||||||||||
| 96D6 | RTS ; Return | ||||||||||||||||
| 96D7 | .array_error←2← 96E2 BEQ← 9709 BNE | ||||||||||||||||
| BRK ; No such array: Array error | |||||||||||||||||
| 96D8 | EQUB &0E | ||||||||||||||||
| 96D9 | EQUS "Array" | ||||||||||||||||
| 96DE | EQUB &00 | ||||||||||||||||
Locate an array and evaluate one subscriptFind the named array (find_variable) and step the value pointer to the addressed element, evaluating one subscript at PtrB and bounds-checking it. Raises Array on a missing array, Subscript on an out-of-range index.
|
|||||||||||||
| 96DF | .index_array←2← 96A9 JSR← 96CE JSR | ||||||||||||
| JSR find_variable ; Find the array | |||||||||||||
| 96E2 | BEQ array_error ; missing: Array error | ||||||||||||
| 96E4 | STX zp_text_ptr2_off ; Update the scan offset | ||||||||||||
| 96E6 | LDA zp_iwa_2 ; Save the variable type... | ||||||||||||
| 96E8 | PHA ; push the type | ||||||||||||
| 96E9 | LDA zp_iwa ; ...and the array data pointer | ||||||||||||
| 96EB | PHA ; push the low byte | ||||||||||||
| 96EC | LDA zp_iwa_1 ; high byte | ||||||||||||
| 96EE | PHA ; push it | ||||||||||||
| 96EF | LDY #0 ; Offset to the array data (1 + 2*dims) | ||||||||||||
| 96F1 | LDA (zp_iwa),y ; read it | ||||||||||||
| 96F3 | CMP #4 ; more than a few? | ||||||||||||
| 96F5 | BCC idxarr_one ; no: handle the small case | ||||||||||||
| 96F7 | TYA ; Accumulate the flattened index | ||||||||||||
| 96F8 | JSR int_result_a ; running index = 0 | ||||||||||||
| 96FB | LDA #1 ; one subscript so far | ||||||||||||
| 96FD | STA zp_iwa_3 ; store it | ||||||||||||
| 96FF | .idxarr_loop←1← 9742 BCS | ||||||||||||
| JSR stack_integer ; Stack the running index | |||||||||||||
| 9702 | JSR eval_expr_integer ; Evaluate the next subscript | ||||||||||||
| 9705 | INC zp_text_ptr2_off ; step past it | ||||||||||||
| 9707 | CPX #',' ; comma (another subscript)? | ||||||||||||
| 9709 | BNE array_error ; no: wrong dimension count -> Array | ||||||||||||
| 970B | LDX #&39 ; Unstack the running index | ||||||||||||
| 970D | JSR unstack_int_to_zp ; into &39/&3A | ||||||||||||
| 9710 | LDY zp_fwb_ovf ; dimension descriptor offset | ||||||||||||
| 9712 | PLA ; Recover the array base pointer | ||||||||||||
| 9713 | STA zp_general_1 ; high byte | ||||||||||||
| 9715 | PLA ; low byte | ||||||||||||
| 9716 | STA zp_general ; set the pointer | ||||||||||||
| 9718 | PHA ; re-stack it | ||||||||||||
| 9719 | LDA zp_general_1 ; high byte | ||||||||||||
| 971B | PHA ; push it too | ||||||||||||
| 971C | JSR check_subscript_bound ; Bounds-check this subscript | ||||||||||||
| 971F | STY zp_iwa_3 ; advance to the next dimension | ||||||||||||
| 9721 | LDA (zp_general),y ; This dimension's extent: low | ||||||||||||
| 9723 | STA zp_fwb_m2 ; store it | ||||||||||||
| 9725 | INY ; ...high | ||||||||||||
| 9726 | LDA (zp_general),y ; read it | ||||||||||||
| 9728 | STA zp_fwb_m3 ; store it | ||||||||||||
| 972A | LDA zp_iwa ; Add the subscript into the running index | ||||||||||||
| 972C | ADC zp_fileblk ; + subscript low, | ||||||||||||
| 972E | STA zp_iwa ; store the low byte | ||||||||||||
| 9730 | LDA zp_iwa_1 ; high byte | ||||||||||||
| 9732 | ADC zp_fileblk_1 ; + subscript high, | ||||||||||||
| 9734 | STA zp_iwa_1 ; store the high byte | ||||||||||||
| 9736 | JSR imul16 ; index *= this extent (Horner) | ||||||||||||
| 9739 | LDY #0 ; Dimensions processed so far | ||||||||||||
| 973B | SEC ; set carry for subtract | ||||||||||||
| 973C | LDA (zp_general),y ; data offset (byte 0) | ||||||||||||
| 973E | SBC zp_iwa_3 ; minus the offset reached | ||||||||||||
| 9740 | CMP #3 ; more dimensions to come? | ||||||||||||
| 9742 | BCS idxarr_loop ; yes: next subscript | ||||||||||||
| 9744 | JSR stack_integer ; Stack the running index | ||||||||||||
| 9747 | JSR eval_subexpr ; Evaluate the final subscript | ||||||||||||
| 974A | JSR coerce_to_integer ; ...as an integer | ||||||||||||
| 974D | PLA ; Recover the array base | ||||||||||||
| 974E | STA zp_general_1 ; high byte | ||||||||||||
| 9750 | PLA ; low byte | ||||||||||||
| 9751 | STA zp_general ; set the pointer | ||||||||||||
| 9753 | LDX #&39 ; Unstack the running index | ||||||||||||
| 9755 | JSR unstack_int_to_zp ; into &39/&3A | ||||||||||||
| 9758 | LDY zp_fwb_ovf ; dimension descriptor offset | ||||||||||||
| 975A | JSR check_subscript_bound ; Bounds-check the final subscript | ||||||||||||
| 975D | CLC ; Add it into the index | ||||||||||||
| 975E | LDA zp_fileblk ; subscript low | ||||||||||||
| 9760 | ADC zp_iwa ; plus the index low, | ||||||||||||
| 9762 | STA zp_iwa ; store it | ||||||||||||
| 9764 | LDA zp_fileblk_1 ; subscript high | ||||||||||||
| 9766 | ADC zp_iwa_1 ; plus the index high, | ||||||||||||
| 9768 | STA zp_iwa_1 ; store it | ||||||||||||
| 976A | BCC idxarr_type ; scale by the element size | ||||||||||||
| 976C | .idxarr_one←1← 96F5 BCC | ||||||||||||
| JSR eval_subexpr ; One subscript: evaluate it | |||||||||||||
| 976F | JSR coerce_to_integer ; ...as an integer | ||||||||||||
| 9772 | PLA ; Recover the array base | ||||||||||||
| 9773 | STA zp_general_1 ; high byte | ||||||||||||
| 9775 | PLA ; low byte | ||||||||||||
| 9776 | STA zp_general ; set the pointer | ||||||||||||
| 9778 | LDY #1 ; descriptor offset 1 | ||||||||||||
| 977A | JSR check_subscript_bound ; Bounds-check the subscript | ||||||||||||
| 977D | .idxarr_type←1← 976A BCC | ||||||||||||
| PLA ; Element type | |||||||||||||
| 977E | STA zp_iwa_2 ; store it | ||||||||||||
| 9780 | CMP #5 ; real/string (5 bytes)? | ||||||||||||
| 9782 | BNE idxarr_scale ; no: integer (4 bytes) | ||||||||||||
| 9784 | LDX zp_iwa_1 ; index = 5 (x4 + x) | ||||||||||||
| 9786 | LDA zp_iwa ; keep the original low | ||||||||||||
| 9788 | ASL zp_iwa ; index x2: | ||||||||||||
| 978A | ROL zp_iwa_1 ; carry up to the high byte, | ||||||||||||
| 978C | ASL zp_iwa ; index x4: | ||||||||||||
| 978E | ROL zp_iwa_1 ; carry up again | ||||||||||||
| 9790 | ADC zp_iwa ; add the original (x5), | ||||||||||||
| 9792 | STA zp_iwa ; store the low byte | ||||||||||||
| 9794 | TXA ; original high byte | ||||||||||||
| 9795 | ADC zp_iwa_1 ; add x4 high (x5), | ||||||||||||
| 9797 | STA zp_iwa_1 ; store the high byte | ||||||||||||
| 9799 | BCC idxarr_offset ; done: skip the x4 path | ||||||||||||
| 979B | .idxarr_scale←1← 9782 BNE | ||||||||||||
| ASL zp_iwa ; index *= 4 | |||||||||||||
| 979D | ROL zp_iwa_1 ; carry into the high byte, | ||||||||||||
| 979F | ASL zp_iwa ; index x4: | ||||||||||||
| 97A1 | ROL zp_iwa_1 ; carry up again | ||||||||||||
| 97A3 | .idxarr_offset←1← 9799 BCC | ||||||||||||
| TYA ; Add the element offset within the descriptor | |||||||||||||
| 97A4 | ADC zp_iwa ; plus the scaled index low, | ||||||||||||
| 97A6 | STA zp_iwa ; store the low byte | ||||||||||||
| 97A8 | BCC idxarr_addr ; no carry into the high byte | ||||||||||||
| 97AA | INC zp_iwa_1 ; else bump the high byte | ||||||||||||
| 97AC | CLC ; clear carry for the base add | ||||||||||||
| 97AD | .idxarr_addr←1← 97A8 BCC | ||||||||||||
| LDA zp_general ; Element address = base + offset | |||||||||||||
| 97AF | ADC zp_iwa ; plus the offset low, | ||||||||||||
| 97B1 | STA zp_iwa ; store the low byte | ||||||||||||
| 97B3 | LDA zp_general_1 ; base high byte | ||||||||||||
| 97B5 | ADC zp_iwa_1 ; plus the offset high, | ||||||||||||
| 97B7 | STA zp_iwa_1 ; store it: element address in IWA | ||||||||||||
| 97B9 | RTS ; Return | ||||||||||||
Check a subscript against a dimension extentRaise Subscript if the subscript in IWA is negative or not less than the two-byte dimension extent at (zp_general),Y, otherwise advance Y past the extent.
|
|||||||||||||||
| 97BA | .check_subscript_bound←3← 971C JSR← 975A JSR← 977A JSR | ||||||||||||||
| LDA zp_iwa_1 ; Top bits of the subscript | |||||||||||||||
| 97BC | AND #&c0 ; keep just bits 6-7 | ||||||||||||||
| 97BE | ORA zp_iwa_2 ; combine with the high bytes... | ||||||||||||||
| 97C0 | ORA zp_iwa_3 ; and byte 3 | ||||||||||||||
| 97C2 | BNE subscript_error ; negative or huge: Subscript | ||||||||||||||
| 97C4 | LDA zp_iwa ; Compare against the dimension extent | ||||||||||||||
| 97C6 | CMP (zp_general),y ; subscript low vs extent low | ||||||||||||||
| 97C8 | INY ; next extent byte | ||||||||||||||
| 97C9 | LDA zp_iwa_1 ; subscript high... | ||||||||||||||
| 97CB | SBC (zp_general),y ; minus the extent high | ||||||||||||||
| 97CD | BCS subscript_error ; not less than the extent: Subscript | ||||||||||||||
| 97CF | INY ; advance past the extent | ||||||||||||||
| 97D0 | RTS ; Return | ||||||||||||||
| 97D1 | .subscript_error←2← 97C2 BNE← 97CD BCS | ||||||||||||||
| BRK ; Subscript error | |||||||||||||||
| 97D2 | EQUB &0F | ||||||||||||||
| 97D3 | EQUS "Subscript" | ||||||||||||||
| 97DC | EQUB &00 | ||||||||||||||
| 97DD | .chkline_skip←1← 97E5 BEQ | ||||||||||||||
| INC zp_text_ptr_off ; Advance | |||||||||||||||
| fall through ↓ | |||||||||||||||
Test for an embedded line numberSkip spaces at the text pointer; if the next token is a line-number token (&8D), fall into decode_line_number to decode it into IWA and return carry set, otherwise return carry clear.
|
|||||||||||||
| 97DF | .check_line_number←10← 8B2D JSR← 8F31 JSR← 8F40 JSR← 8F6E JSR← 8F80 JSR← 9295 JSR← 98E3 JSR← B5AC JSR← B5D8 JSR← B99A JSR | ||||||||||||
| LDY zp_text_ptr_off ; Next character | |||||||||||||
| 97E1 | LDA (zp_text_ptr),y ; read it | ||||||||||||
| 97E3 | CMP #' ' ; space? | ||||||||||||
| 97E5 | BEQ chkline_skip ; skip it | ||||||||||||
| 97E7 | CMP #&8d ; line-number token? | ||||||||||||
| 97E9 | BNE not_line_number ; no: carry clear | ||||||||||||
| fall through ↓ | |||||||||||||
Decode a 3-byte line number into IWAReverse the three-byte &8D line-number encoding, reconstructing the 16-bit line number in IWA (the two high-bit pairs are recovered from the control byte). The inverse of encode_line_number, and like it exact only for 0-32767.
|
|||||||||||||
| 97EB | .decode_line_number←2← 903D JSR← B659 JSR | ||||||||||||
| INY ; Control byte | |||||||||||||
| 97EC | LDA (zp_text_ptr),y ; read the packed top-bits byte | ||||||||||||
| 97EE | ASL ; recover the top bits | ||||||||||||
| 97EF | ASL ; (shifted left by two) | ||||||||||||
| 97F0 | TAX ; keep a copy for the high byte | ||||||||||||
| 97F1 | AND #&c0 ; low byte top bits | ||||||||||||
| 97F3 | INY ; next encoded byte | ||||||||||||
| 97F4 | EOR (zp_text_ptr),y ; XOR the encoded low byte | ||||||||||||
| 97F6 | STA zp_iwa ; line number low | ||||||||||||
| 97F8 | TXA ; high byte top bits | ||||||||||||
| 97F9 | ASL ; shift the high byte top bits into place, | ||||||||||||
| 97FA | ASL ; (two places) | ||||||||||||
| 97FB | INY ; next encoded byte | ||||||||||||
| 97FC | EOR (zp_text_ptr),y ; XOR the encoded high byte | ||||||||||||
| 97FE | STA zp_iwa_1 ; line number high | ||||||||||||
| 9800 | INY ; step past the 3 bytes | ||||||||||||
| 9801 | STY zp_text_ptr_off ; save the advanced text offset | ||||||||||||
| 9803 | SEC ; carry set: found | ||||||||||||
| 9804 | RTS ; Return | ||||||||||||
| 9805 | .not_line_number←1← 97E9 BNE | ||||||||||||
| CLC ; carry clear: not a line number | |||||||||||||
| 9806 | RTS ; Return | ||||||||||||
| 9807 | .copy_ptra_to_ptrb←1← 92EB JSR | ||||||||||||
| LDA zp_text_ptr ; Copy PtrA to PtrB | |||||||||||||
| 9809 | STA zp_text_ptr2 ; (low) | ||||||||||||
| 980B | LDA zp_text_ptr_1 ; high... | ||||||||||||
| 980D | STA zp_text_ptr2_1 ; (high) | ||||||||||||
| 980F | LDA zp_text_ptr_off ; offset... | ||||||||||||
| 9811 | STA zp_text_ptr2_off ; (offset) | ||||||||||||
| fall through ↓ | |||||||||||||
Expect "=" then evaluate the right-hand sideSkip spaces at PtrB, require an "=" sign, then evaluate the expression that follows, leaving the value in the accumulator with its type in zp_var_type. Raises Mistake if "=" is missing.
|
|||||||||||
| 9813 | .eval_after_eq←4← 8BEE JSR← 8BFE JSR← 981B BEQ← BF34 JSR | ||||||||||
| LDY zp_text_ptr2_off ; Next character | |||||||||||
| 9815 | INC zp_text_ptr2_off ; and advance | ||||||||||
| 9817 | LDA (zp_text_ptr2),y ; read it | ||||||||||
| 9819 | CMP #' ' ; space? | ||||||||||
| 981B | BEQ eval_after_eq ; skip it | ||||||||||
| 981D | CMP #'=' ; "="? | ||||||||||
| 981F | BEQ eval_rhs ; yes: evaluate | ||||||||||
| 9821 | .mistake_error←1← 9846 BNE | ||||||||||
| BRK ; Mistake error | |||||||||||
| 9822 | EQUB &04 | ||||||||||
| 9823 | EQUS "Mistake" | ||||||||||
Raise "Syntax error" errorRaise BASIC error &10, "Syntax error", via a BRK error block. Reached when a statement or expression is malformed (e.g. from check_end_of_statement when unexpected text follows a statement). Does not return.
|
||||
| 982A | .syntax_error←7← 8604 JMP← 8855 JMP← 8C0B JMP← 8F2E JMP← 986B BNE← B6A0 JMP← B9C7 JMP | |||
| BRK ; Mistake error | ||||
| 982B | EQUB &10 | |||
| 982C | EQUS "Syntax error" | |||
| 9838 | .escape_error←2← 987D BMI← BC22 JMP | |||
| BRK ; Escape error | ||||
| 9839 | EQUB &11 | |||
| 983A | EQUS "Escape" | |||
| 9840 | EQUB &00 | |||
Require "=" at the parser pointerSkip spaces at PtrB and raise Mistake unless the next character is "=".
|
|||||||||||
| 9841 | .expect_eq←2← 8BD2 JSR← B7CE JSR | ||||||||||
| JSR skip_spaces_ptr2 ; Skip spaces | |||||||||||
| 9844 | CMP #'=' ; "="? | ||||||||||
| 9846 | BNE mistake_error ; no: Mistake | ||||||||||
| 9848 | RTS ; Return | ||||||||||
| 9849 | .eval_rhs←2← 981F BEQ← BF5F JSR | ||||||||||
| JSR eval_or_eor ; Evaluate the right-hand side | |||||||||||
| fall through ↓ | |||||||||||
Sync PtrB offset and require statement end after an assignmentTail shared by assignment and function-return paths once the right-hand-side value has been computed: move the pending result byte into A, resync Y to PtrB's offset (zp_text_ptr2_off, &1B), and tail-jump into check_end_of_statement at cend_check to demand the statement terminator against PtrA. Unlike eval_rhs (&9849) it does not evaluate the RHS itself; the value is assumed already in place.
|
|||||||||||
| 984C | .assign_check_end←4← 8B56 JMP← B58F JSR← BBB4 JSR← BEDA JMP | ||||||||||
| TXA ; Result type | |||||||||||
| 984D | LDY zp_text_ptr2_off ; Sync the program pointer | ||||||||||
| 984F | JMP cend_check ; check the statement ends | ||||||||||
Resync PtrA's offset to PtrB, then require statement endLoad the resume position from PtrB's offset (zp_text_ptr2_off, &1B) into Y and tail-jump into check_end_of_statement at cend_back. Used after a sub-parse that tracked its position in PtrB (e.g. FOR / assignment operands): it resumes at PtrB's offset against the PtrA text pointer and demands the statement end there, advancing PtrA to the next statement.
|
|||||||||
| 9852 | .sync_text_ptr←8← 8F0E JSR← 9315 JSR← 9383 JSR← 9406 JSR← B461 JSR← B484 JSR← B4A3 JSR← BF9C JSR | ||||||||
| LDY zp_text_ptr2_off ; Sync the program pointer | |||||||||
| 9854 | JMP cend_back ; check the statement ends | ||||||||
Check for end of statementSkip spaces and require the statement to end here: a colon, an end-of-line (&0D), or ELSE. Anything else raises "Syntax error". Also polls for Escape.
|
|||||||||||||
| 9857 | .check_end_of_statement←25← 8AB6 JSR← 8AC8 JSR← 8AD0 JSR← 8ADA JSR← 8B98 JSR← 8EBD JSR← 8EC4 JSR← 8F45 JSR← 8F8F JMP← 928D JSR← 92A5 JSR← 92B9 JSR← 92C2 JSR← 9362 JMP← 9394 JSR← 93A0 JSR← 9880 JSR← B5E3 JSR← B88B JSR← B8B6 JSR← B8CF JSR← B8E4 JSR← BB07 JSR← BD11 JSR← BFE4 JSR | ||||||||||||
| LDY zp_text_ptr_off ; Program pointer offset | |||||||||||||
| 9859 | .cend_back←2← 858C JSR← 9854 JMP | ||||||||||||
| DEY ; step back | |||||||||||||
| 985A | .cend_skip_loop←1← 985F BEQ | ||||||||||||
| INY ; Next character | |||||||||||||
| 985B | LDA (zp_text_ptr),y ; read it | ||||||||||||
| 985D | CMP #' ' ; space? | ||||||||||||
| 985F | BEQ cend_skip_loop ; skip it | ||||||||||||
| 9861 | .cend_check←1← 984F JMP | ||||||||||||
| CMP #':' ; ':' statement separator? | |||||||||||||
| 9863 | BEQ skip_to_statement_end ; yes | ||||||||||||
| 9865 | CMP #&0d ; end of line? | ||||||||||||
| 9867 | BEQ skip_to_statement_end ; yes | ||||||||||||
| 9869 | CMP #&8b ; ELSE token? | ||||||||||||
| 986B | BNE syntax_error ; none: Mistake (syntax error) | ||||||||||||
| fall through ↓ | |||||||||||||
Advance PtrA past the current statementAdd the terminator offset in Y to the PtrA text pointer (zp_text_ptr, &0B/&0C), carrying into the high byte, so PtrA now addresses the statement terminator; reset the character offset zp_text_ptr_off (&0A) to 1; then poll ESCFLG and raise Escape if pressed before returning. The common tail of the end-of-statement check and several statement handlers.
|
|||||||||||||||
| 986D | .skip_to_statement_end←8← 850F JSR← 8B73 JSR← 9863 BEQ← 9867 BEQ← B16E JSR← B5FF JSR← B8FC JSR← BBEA JSR | ||||||||||||||
| CLC ; Advance the program pointer past the statement | |||||||||||||||
| 986E | TYA ; offset to A, | ||||||||||||||
| 986F | ADC zp_text_ptr ; + pointer low, | ||||||||||||||
| 9871 | STA zp_text_ptr ; store low, | ||||||||||||||
| 9873 | BCC reset_offset_1 ; no carry into the high byte | ||||||||||||||
| 9875 | INC zp_text_ptr_1 ; carry into the high byte | ||||||||||||||
| 9877 | .reset_offset_1←4← 9873 BCC← 98EB JSR← B74B JSR← B964 JSR | ||||||||||||||
| LDY #1 ; Reset the offset to 1 | |||||||||||||||
| 9879 | STY zp_text_ptr_off ; store it (&0A) | ||||||||||||||
| 987B | .check_escape←1← 8F56 JSR | ||||||||||||||
| BIT zp_escflg ; Escape pressed (ESCFLG)? | |||||||||||||||
| 987D | BMI escape_error ; yes: raise Escape | ||||||||||||||
| 987F | .return_14←1← 9888 BEQ | ||||||||||||||
| RTS ; Return | |||||||||||||||
| 9880 | .check_statement_terminated←1← B837 JSR | ||||||||||||||
| JSR check_end_of_statement ; Check this statement is terminated | |||||||||||||||
| 9883 | DEY ; Re-read the terminator | ||||||||||||||
| 9884 | LDA (zp_text_ptr),y ; read it | ||||||||||||||
| 9886 | CMP #':' ; ':' (more on this line)? | ||||||||||||||
| 9888 | BEQ return_14 ; yes: continue on the line | ||||||||||||||
| 988A | LDA zp_text_ptr_1 ; At the end of program memory? | ||||||||||||||
| 988C | CMP #7 ; in the &0700 buffer (immediate)? | ||||||||||||||
| 988E | BEQ to_immediate ; yes: return to immediate mode | ||||||||||||||
| fall through ↓ | |||||||||||||||
Advance PtrA to the next program lineStep from the current line's terminating CR onto the next line: if the next line-number marker has bit 7 set the program has ended and control jumps to immediate_loop; otherwise, when TRACE is enabled, load the line number into zp_iwa and call trace_line, then skip the 3-byte line header and reset the character offset. Returns with Z clear so callers can branch to run the next statement.
|
|||||||||||||||
| 9890 | .step_to_next_line←2← 859F JSR← 8B91 JSR | ||||||||||||||
| INY ; Next byte (line-number marker) | |||||||||||||||
| 9891 | LDA (zp_text_ptr),y ; read it | ||||||||||||||
| 9893 | BMI to_immediate ; end of program: immediate mode | ||||||||||||||
| 9895 | LDA zp_trace_flag ; TRACE on? | ||||||||||||||
| 9897 | BEQ step_past_line_header ; no: skip the line number | ||||||||||||||
| 9899 | TYA ; Save the offset | ||||||||||||||
| 989A | PHA ; push it | ||||||||||||||
| 989B | INY ; Line number high byte | ||||||||||||||
| 989C | LDA (zp_text_ptr),y ; read it, | ||||||||||||||
| 989E | PHA ; push it | ||||||||||||||
| 989F | DEY ; Line number low byte | ||||||||||||||
| 98A0 | LDA (zp_text_ptr),y ; read it, | ||||||||||||||
| 98A2 | TAY ; low byte to Y, | ||||||||||||||
| 98A3 | PLA ; high byte to A | ||||||||||||||
| 98A4 | JSR iwa_from_ya ; IWA = line number | ||||||||||||||
| 98A7 | JSR trace_line ; trace it | ||||||||||||||
| 98AA | PLA ; Restore the offset | ||||||||||||||
| 98AB | TAY ; into Y | ||||||||||||||
| 98AC | .step_past_line_header←1← 9897 BEQ | ||||||||||||||
| INY ; Step past the 3-byte line header | |||||||||||||||
| 98AD | SEC ; set carry (advance by offset + 1), | ||||||||||||||
| 98AE | TYA ; offset to A, | ||||||||||||||
| 98AF | ADC zp_text_ptr ; + pointer low, | ||||||||||||||
| 98B1 | STA zp_text_ptr ; store low, | ||||||||||||||
| 98B3 | BCC line_reset_offset ; no carry into the high byte | ||||||||||||||
| 98B5 | INC zp_text_ptr_1 ; carry into the high byte | ||||||||||||||
| 98B7 | .line_reset_offset←1← 98B3 BCC | ||||||||||||||
| LDY #1 ; Reset the offset to 1 | |||||||||||||||
| 98B9 | STY zp_text_ptr_off ; store it (&0A) | ||||||||||||||
| 98BB | .return_15←1← 990D BCS | ||||||||||||||
| RTS ; Return | |||||||||||||||
| 98BC | .to_immediate←2← 988E BEQ← 9893 BMI | ||||||||||||||
| JMP immediate_loop ; End of program: immediate mode | |||||||||||||||
| 98BF | .if_type_error←1← 98C5 BEQ | ||||||||||||||
| JMP err_type_mismatch ; Type mismatch error | |||||||||||||||
IFConditional execution: evaluate the expression and run the THEN part, else skip to ELSE or the end of the line. IF expr [THEN] ... [ELSE ...].
|
|||||||||||
| 98C2 | .stmt_if | ||||||||||
| JSR eval_expr ; Evaluate the condition | |||||||||||
| 98C5 | BEQ if_type_error ; string: handle elsewhere | ||||||||||
| 98C7 | BPL if_skip_cond ; integer: use as is | ||||||||||
| 98C9 | JSR fwa_to_int ; real: convert to integer | ||||||||||
| 98CC | .if_skip_cond←1← 98C7 BPL | ||||||||||
| LDY zp_text_ptr2_off ; Advance the text pointer past the condition | |||||||||||
| 98CE | STY zp_text_ptr_off ; copy it to PtrA | ||||||||||
| 98D0 | LDA zp_iwa ; Is the condition value zero (false)? | ||||||||||
| 98D2 | ORA zp_iwa_1 ; or byte 1, | ||||||||||
| 98D4 | ORA zp_iwa_2 ; byte 2, | ||||||||||
| 98D6 | ORA zp_iwa_3 ; byte 3 | ||||||||||
| 98D8 | BEQ if_false ; false: look for ELSE | ||||||||||
| 98DA | CPX #&8c ; true: is the next token THEN? | ||||||||||
| 98DC | BEQ if_then ; yes | ||||||||||
| 98DE | .if_no_then←1← 98E6 BCC | ||||||||||
| JMP next_statement ; no THEN: execute the statement that follows | |||||||||||
| 98E1 | .if_then←1← 98DC BEQ | ||||||||||
| INC zp_text_ptr_off ; Step past THEN | |||||||||||
| 98E3 | .if_then_line←2← 9900 BEQ← B997 JMP | ||||||||||
| JSR check_line_number ; Is a line number following (THEN <line>)? | |||||||||||
| 98E6 | BCC if_no_then ; no: execute the statements after THEN | ||||||||||
| 98E8 | JSR flt_find ; yes: set up the line number... | ||||||||||
| 98EB | JSR reset_offset_1 ; to the line start, test Escape | ||||||||||
| 98EE | JMP goto_trace ; ...and GOTO it | ||||||||||
| 98F1 | .if_false←1← 98D8 BEQ | ||||||||||
| LDY zp_text_ptr_off ; False: scan the rest of the line for ELSE | |||||||||||
| 98F3 | .if_scan_else_loop←1← 98FC BNE | ||||||||||
| LDA (zp_text_ptr),y ; Next character | |||||||||||
| 98F5 | CMP #&0d ; end of line? | ||||||||||
| 98F7 | BEQ if_no_else ; yes: move to the next line | ||||||||||
| 98F9 | INY ; advance | ||||||||||
| 98FA | CMP #&8b ; ELSE token? | ||||||||||
| 98FC | BNE if_scan_else_loop ; no: keep scanning | ||||||||||
| 98FE | STY zp_text_ptr_off ; found ELSE: point past it | ||||||||||
| 9900 | BEQ if_then_line ; execute what follows ELSE | ||||||||||
| 9902 | .if_no_else←1← 98F7 BEQ | ||||||||||
| JMP stmt_eol ; No ELSE: continue at the next line | |||||||||||
Print [line] when TRACE is activeIf the line number in IWA is at or below the TRACE ceiling, print it in brackets; otherwise do nothing.
|
|||||||||
| 9905 | .trace_line←2← 98A7 JSR← B8D6 JSR | ||||||||
| LDA zp_iwa ; Line number vs TRACE ceiling | |||||||||
| 9907 | CMP zp_trace_max ; vs ceiling low, | ||||||||
| 9909 | LDA zp_iwa_1 ; line high | ||||||||
| 990B | SBC zp_trace_max_1 ; minus ceiling high | ||||||||
| 990D | BCS return_15 ; above the ceiling: do not trace | ||||||||
| 990F | LDA #'[' ; Print '[' | ||||||||
| 9911 | JSR print_char ; output it | ||||||||
| 9914 | JSR print_line_number ; print the line number | ||||||||
| 9917 | LDA #']' ; Print ']' | ||||||||
| 9919 | JSR print_char ; output it | ||||||||
| 991C | JMP print_space ; and a space | ||||||||
Print a 16-bit line number in decimalConvert the value in IWA to decimal by repeated subtraction of the powers of ten at &996B/&99B9, suppressing leading zeros, optionally right-justified in a field (the sub_c9923 entry uses a 5-digit TRACE field).
|
|||||||||
| 991F | .print_line_number←3← 9097 JSR← 9914 JSR← B662 JSR | ||||||||
| LDA #0 ; Default: no field padding | |||||||||
| 9921 | BEQ plnum_setwidth ; always: skip the TRACE entry | ||||||||
| fall through ↓ | |||||||||
Print a line number in a 5-digit fieldAlternate entry to print_line_number that prints the value in zp_iwa as a decimal line number right-justified in a 5-character field (used by TRACE and LIST). Loads a field width of 5, then joins print_line_number at plnum_setwidth.
|
|||||||
| 9923 | .trace_print_number←2← 90B8 JSR← B61D JSR | ||||||
| LDA #5 ; TRACE entry: 5-digit field | |||||||
| 9925 | .plnum_setwidth←1← 9921 BEQ | ||||||
| STA zp_print_bytes ; Field width | |||||||
| 9927 | LDX #4 ; Five powers of ten, index 4..0 | ||||||
| 9929 | .plnum_clear_loop←1← 9944 BPL | ||||||
| LDA #0 ; Clear this digit | |||||||
| 992B | STA zp_fwb_m2,x ; zero its count | ||||||
| 992D | SEC ; set carry for the subtraction | ||||||
| 992E | .plnum_sub_loop←1← 9941 BNE | ||||||
| LDA zp_iwa ; Subtract this power of ten from IWA | |||||||
| 9930 | SBC powers_of_ten_lo,x ; minus the low byte, | ||||||
| 9933 | TAY ; stash the low result | ||||||
| 9934 | LDA zp_iwa_1 ; IWA high byte | ||||||
| 9936 | SBC powers_of_ten_hi,x ; minus the high byte | ||||||
| 9939 | BCC plnum_next_power ; underflow: digit complete | ||||||
| 993B | STA zp_iwa_1 ; keep the remainder | ||||||
| 993D | STY zp_iwa ; (low byte too) | ||||||
| 993F | INC zp_fwb_m2,x ; count the digit | ||||||
| 9941 | BNE plnum_sub_loop ; subtract again | ||||||
| 9943 | .plnum_next_power←1← 9939 BCC | ||||||
| DEX ; Next power of ten | |||||||
| 9944 | BPL plnum_clear_loop ; until all five powers used | ||||||
| 9946 | LDX #5 ; Find the most significant non-zero digit | ||||||
| 9948 | .plnum_digit_loop←1← 994D BEQ | ||||||
| DEX ; step down to the next digit | |||||||
| 9949 | BEQ plnum_top_digit ; units digit: always shown | ||||||
| 994B | LDA zp_fwb_m2,x ; is this digit zero? | ||||||
| 994D | BEQ plnum_digit_loop ; yes: skip the leading zero | ||||||
| 994F | .plnum_top_digit←1← 9949 BEQ | ||||||
| STX zp_general ; Index of the top digit | |||||||
| 9951 | LDA zp_print_bytes ; Field padding requested? | ||||||
| 9953 | BEQ plnum_print_loop ; no | ||||||
| 9955 | SBC zp_general ; leading spaces = field - digits | ||||||
| 9957 | BEQ plnum_print_loop ; none | ||||||
| 9959 | TAY ; space count into Y | ||||||
| 995A | .plnum_space_loop←1← 995E BNE | ||||||
| JSR print_space ; print a leading space | |||||||
| 995D | DEY ; one fewer space | ||||||
| 995E | BNE plnum_space_loop ; until the field is padded | ||||||
| 9960 | .plnum_print_loop←3← 9953 BEQ← 9957 BEQ← 9968 BPL | ||||||
| LDA zp_fwb_m2,x ; Digit | |||||||
| 9962 | ORA #'0' ; to ASCII | ||||||
| 9964 | JSR print_char ; print it | ||||||
| 9967 | DEX ; next digit | ||||||
| 9968 | BPL plnum_print_loop ; until all digits printed | ||||||
| 996A | RTS ; Return | ||||||
| 996B | .powers_of_ten_lo←1Used as index base by← 9930 SBC | ||||||
| EQUB &01, &0A, &64, &E8, &10 | |||||||
Search the program for a line numberWalk the program text from PAGE looking for the target line number in IWA. Returns a scratch pointer (zp_fwb_exp/zp_fwb_m1) to the matching line, or to the first line with a greater number (the insertion point) when there is no exact match.
|
|||||||||||
| 9970 | .find_program_line←3← B5EC JSR← B9AF JSR← BC2D JSR | ||||||||||
| LDY #0 ; Pointer low = 0 | |||||||||||
| 9972 | STY zp_fwb_exp ; scratch pointer in fwb_exp/m1 | ||||||||||
| 9974 | LDA zp_page ; Pointer high = PAGE | ||||||||||
| 9976 | STA zp_fwb_m1 ; pointer high | ||||||||||
| 9978 | .fpl_check_high←2← 9988 BCC← 998C BCS | ||||||||||
| LDY #1 ; This line's number: high byte | |||||||||||
| 997A | LDA (zp_fwb_exp),y ; read it | ||||||||||
| 997C | CMP zp_iwa_1 ; vs the target high byte | ||||||||||
| 997E | BCS fpl_found ; >=: a candidate | ||||||||||
| 9980 | .fpl_next_loop←1← 9996 BCC | ||||||||||
| LDY #3 ; Line length | |||||||||||
| 9982 | LDA (zp_fwb_exp),y ; read it | ||||||||||
| 9984 | ADC zp_fwb_exp ; Advance to the next line | ||||||||||
| 9986 | STA zp_fwb_exp ; pointer low | ||||||||||
| 9988 | BCC fpl_check_high ; no carry: same page | ||||||||||
| 998A | INC zp_fwb_m1 ; carry into the pointer high | ||||||||||
| 998C | BCS fpl_check_high ; continue | ||||||||||
| 998E | .fpl_found←1← 997E BCS | ||||||||||
| BNE fpl_return ; high byte greater: found (not exact) | |||||||||||
| 9990 | LDY #2 ; This line's number: low byte | ||||||||||
| 9992 | LDA (zp_fwb_exp),y ; read it | ||||||||||
| 9994 | CMP zp_iwa ; vs the target low byte | ||||||||||
| 9996 | BCC fpl_next_loop ; less: next line | ||||||||||
| 9998 | BNE fpl_return ; greater: found (not exact) | ||||||||||
| 999A | TYA ; Exact match: leave the pointer at this line | ||||||||||
| 999B | ADC zp_fwb_exp ; point at the line number | ||||||||||
| 999D | STA zp_fwb_exp ; (store) | ||||||||||
| 999F | BCC fpl_return ; no carry | ||||||||||
| 99A1 | INC zp_fwb_m1 ; carry into the pointer high | ||||||||||
| 99A3 | CLC ; flag the exact match (carry clear) | ||||||||||
| 99A4 | .fpl_return←3← 998E BNE← 9998 BNE← 999F BCC | ||||||||||
| LDY #2 ; Point at the line number | |||||||||||
| 99A6 | RTS ; Return | ||||||||||
| 99A7 | .div_zero_error←2← 99F0 BEQ← A6BB JMP | ||||||||||
| BRK ; Division by zero error | |||||||||||
| 99A8 | EQUB &12 | ||||||||||
| 99A9 | EQUS "Division by zero" | ||||||||||
| 99B9 | .powers_of_ten_hi←1Used as index base by← 9936 SBC | ||||||||||
| EQUB &00, &00, &00, &03, &27 | |||||||||||
Unsigned/signed 32-bit integer divisionDivide the dividend (IWA, the left operand) by the divisor (the right operand, evaluated here at PtrB). Both are made positive and a 32-step shift-subtract division runs with the dividend/quotient in &39-&3C and the remainder in &3D-&40. The quotient sign is the XOR of the operand signs (&37), the remainder sign the dividend sign (&38). Raises Division by zero. Shared by DIV (reads the quotient) and MOD (the remainder).
|
|||||||||||||||
| 99BE | .iwa_divide←2← 9E01 JSR← 9E0A JSR | ||||||||||||||
| TAY ; Coerce the dividend to integer | |||||||||||||||
| 99BF | JSR coerce_to_integer ; IWA = the integer dividend | ||||||||||||||
| 99C2 | LDA zp_iwa_3 ; Save the dividend sign | ||||||||||||||
| 99C4 | PHA ; push it | ||||||||||||||
| 99C5 | JSR iwa_abs ; take |dividend| | ||||||||||||||
| 99C8 | JSR pow_stack_eval ; Stack it, evaluate the divisor | ||||||||||||||
| 99CB | STX zp_var_type ; remember the operator | ||||||||||||||
| 99CD | TAY ; coerce the divisor to integer | ||||||||||||||
| 99CE | JSR coerce_to_integer ; IWA = the integer divisor | ||||||||||||||
| 99D1 | PLA ; Recover the dividend sign | ||||||||||||||
| 99D2 | STA zp_general_1 ; remainder takes the dividend sign | ||||||||||||||
| 99D4 | EOR zp_iwa_3 ; quotient sign = dividend XOR divisor | ||||||||||||||
| 99D6 | STA zp_general ; store the quotient sign (&37) | ||||||||||||||
| 99D8 | JSR iwa_abs ; take |divisor| | ||||||||||||||
| 99DB | LDX #&39 ; Move the dividend to the work area (&39-&3C) | ||||||||||||||
| 99DD | JSR unstack_int_to_zp ; unpack starting at &39 | ||||||||||||||
| 99E0 | STY zp_fwb_exp ; Clear the remainder (&3D-&40) | ||||||||||||||
| 99E2 | STY zp_fwb_m1 ; &3E, | ||||||||||||||
| 99E4 | STY zp_fwb_m2 ; &3F, | ||||||||||||||
| 99E6 | STY zp_fwb_m3 ; &40 | ||||||||||||||
| 99E8 | LDA zp_iwa_3 ; Divisor zero? | ||||||||||||||
| 99EA | ORA zp_iwa ; OR the low byte, | ||||||||||||||
| 99EC | ORA zp_iwa_1 ; &2B, | ||||||||||||||
| 99EE | ORA zp_iwa_2 ; &2C (all zero => /0) | ||||||||||||||
| 99F0 | BEQ div_zero_error ; yes: Division by zero | ||||||||||||||
| 99F2 | LDY #&20 ; 32 bits | ||||||||||||||
| 99F4 | .idiv_norm_loop←1← 99FF BPL | ||||||||||||||
| DEY ; Normalise: count down | |||||||||||||||
| 99F5 | BEQ return_16 ; dividend exhausted: done | ||||||||||||||
| 99F7 | ASL zp_fileblk ; shift the dividend left until the top bit is set | ||||||||||||||
| 99F9 | ROL zp_fileblk_1 ; carrying up through &3A, | ||||||||||||||
| 99FB | ROL zp_fwb_sign ; &3B, | ||||||||||||||
| 99FD | ROL zp_fwb_ovf ; &3C (until bit 7 is set) | ||||||||||||||
| 99FF | BPL idiv_norm_loop ; loop | ||||||||||||||
| 9A01 | .idiv_shift_loop←1← 9A36 BNE | ||||||||||||||
| ROL zp_fileblk ; Shift a bit from dividend into the remainder | |||||||||||||||
| 9A03 | ROL zp_fileblk_1 ; dividend &3A, | ||||||||||||||
| 9A05 | ROL zp_fwb_sign ; &3B, | ||||||||||||||
| 9A07 | ROL zp_fwb_ovf ; &3C, | ||||||||||||||
| 9A09 | ROL zp_fwb_exp ; into remainder &3D, | ||||||||||||||
| 9A0B | ROL zp_fwb_m1 ; &3E, | ||||||||||||||
| 9A0D | ROL zp_fwb_m2 ; &3F, | ||||||||||||||
| 9A0F | ROL zp_fwb_m3 ; &40 (remainder high) | ||||||||||||||
| 9A11 | SEC ; Try remainder - divisor | ||||||||||||||
| 9A12 | LDA zp_fwb_exp ; low byte &3D, | ||||||||||||||
| 9A14 | SBC zp_iwa ; minus divisor low, | ||||||||||||||
| 9A16 | PHA ; save the result, | ||||||||||||||
| 9A17 | LDA zp_fwb_m1 ; byte &3E, | ||||||||||||||
| 9A19 | SBC zp_iwa_1 ; minus divisor &2B, | ||||||||||||||
| 9A1B | PHA ; save it, | ||||||||||||||
| 9A1C | LDA zp_fwb_m2 ; byte &3F, | ||||||||||||||
| 9A1E | SBC zp_iwa_2 ; minus divisor &2C, | ||||||||||||||
| 9A20 | TAX ; hold it in X, | ||||||||||||||
| 9A21 | LDA zp_fwb_m3 ; high byte &40, | ||||||||||||||
| 9A23 | SBC zp_iwa_3 ; minus divisor high | ||||||||||||||
| 9A25 | BCC idiv_restore ; doesn't fit: leave the remainder | ||||||||||||||
| 9A27 | STA zp_fwb_m3 ; fits: keep the new remainder (quotient bit = 1) | ||||||||||||||
| 9A29 | STX zp_fwb_m2 ; and &3F, | ||||||||||||||
| 9A2B | PLA ; pull &3E, | ||||||||||||||
| 9A2C | STA zp_fwb_m1 ; store it, | ||||||||||||||
| 9A2E | PLA ; pull &3D, | ||||||||||||||
| 9A2F | STA zp_fwb_exp ; store it | ||||||||||||||
| 9A31 | BCS idiv_next_bit ; next bit | ||||||||||||||
| 9A33 | .idiv_restore←1← 9A25 BCC | ||||||||||||||
| PLA ; discard the trial subtraction | |||||||||||||||
| 9A34 | PLA ; (continued) | ||||||||||||||
| 9A35 | .idiv_next_bit←1← 9A31 BCS | ||||||||||||||
| DEY ; Next bit | |||||||||||||||
| 9A36 | BNE idiv_shift_loop ; loop | ||||||||||||||
| 9A38 | .return_16←1← 99F5 BEQ | ||||||||||||||
| RTS ; Return | |||||||||||||||
| 9A39 | .cmp_int_real←1← 9AAB BMI | ||||||||||||||
| STX zp_var_type ; Int vs real: save the operator | |||||||||||||||
| 9A3B | JSR unstack_integer ; unstack the integer | ||||||||||||||
| 9A3E | JSR stack_real ; stack the real | ||||||||||||||
| 9A41 | JSR int_to_fwa ; convert the integer to FWA | ||||||||||||||
| 9A44 | JSR fwb_copy_from_fwa ; FWB = it | ||||||||||||||
| 9A47 | JSR unstack_real ; unstack the real operand | ||||||||||||||
| 9A4A | JSR fwa_unpack_var ; into FWA | ||||||||||||||
| 9A4D | JMP cmp_bytes ; compare | ||||||||||||||
| 9A50 | .cmp_real_real←1← 9AA0 BMI | ||||||||||||||
| JSR stack_real ; Real vs real: stack the left | |||||||||||||||
| 9A53 | JSR eval_add_sub ; evaluate the right operand | ||||||||||||||
| 9A56 | STX zp_var_type ; save the operator | ||||||||||||||
| 9A58 | TAY ; type | ||||||||||||||
| 9A59 | JSR ensure_real ; ensure real | ||||||||||||||
| 9A5C | JSR unstack_real ; unstack the left operand | ||||||||||||||
| fall through ↓ | |||||||||||||||
Compare FWA with a fp variableUnpack the packed real operand into FWB and compare it with FWA by sign, exponent and mantissa, returning the ordering for the relational operators.
|
|||||||||||||
| 9A5F | .fp_compare←1← B78F JSR | ||||||||||||
| JSR fwb_unpack_var ; Unpack the operand into FWB | |||||||||||||
| 9A62 | .cmp_bytes←1← 9A4D JMP | ||||||||||||
| LDX zp_var_type ; Restore the operator | |||||||||||||
| 9A64 | LDY #0 ; assume equal | ||||||||||||
| 9A66 | LDA zp_fwb_sign ; FWB sign | ||||||||||||
| 9A68 | AND #&80 ; keep the sign bit | ||||||||||||
| 9A6A | STA zp_fwb_sign ; (store) | ||||||||||||
| 9A6C | LDA zp_fwa_sign ; FWA sign | ||||||||||||
| 9A6E | AND #&80 ; keep the sign bit | ||||||||||||
| 9A70 | CMP zp_fwb_sign ; signs differ? | ||||||||||||
| 9A72 | BNE return_17 ; yes: unequal | ||||||||||||
| 9A74 | LDA zp_fwb_exp ; Compare exponents | ||||||||||||
| 9A76 | CMP zp_fwa_exp ; vs FWA exp | ||||||||||||
| 9A78 | BNE cmp_combine ; differ | ||||||||||||
| 9A7A | LDA zp_fwb_m1 ; Compare mantissa byte 1 | ||||||||||||
| 9A7C | CMP zp_fwa_m1 ; vs FWA m1 | ||||||||||||
| 9A7E | BNE cmp_combine ; differ | ||||||||||||
| 9A80 | LDA zp_fwb_m2 ; byte 2 | ||||||||||||
| 9A82 | CMP zp_fwa_m2 ; vs FWA m2 | ||||||||||||
| 9A84 | BNE cmp_combine ; differ | ||||||||||||
| 9A86 | LDA zp_fwb_m3 ; byte 3 | ||||||||||||
| 9A88 | CMP zp_fwa_m3 ; vs FWA m3 | ||||||||||||
| 9A8A | BNE cmp_combine ; differ | ||||||||||||
| 9A8C | LDA zp_fwb_m4 ; byte 4 | ||||||||||||
| 9A8E | CMP zp_fwa_m4 ; vs FWA m4 | ||||||||||||
| 9A90 | BNE cmp_combine ; differ | ||||||||||||
| 9A92 | .return_17←1← 9A72 BNE | ||||||||||||
| RTS ; Equal: return | |||||||||||||
| 9A93 | .cmp_combine←5← 9A78 BNE← 9A7E BNE← 9A84 BNE← 9A8A BNE← 9A90 BNE | ||||||||||||
| ROR ; Combine the compare carry... | |||||||||||||
| 9A94 | EOR zp_fwb_sign ; ...with the sign | ||||||||||||
| 9A96 | ROL ; ...for the ordering | ||||||||||||
| 9A97 | LDA #1 ; result nonzero | ||||||||||||
| 9A99 | RTS ; Return | ||||||||||||
| 9A9A | .cmp_type_error←2← 9AA9 BEQ← 9AEE BNE | ||||||||||||
| JMP err_type_mismatch ; Type mismatch error | |||||||||||||
Compare the current value with the next operandTake the already-evaluated left value (whose type is in X), stack it, evaluate the next arithmetic operand at PtrB, then compare the two - integer, real or string - returning the ordering flags for the relational operators. A one-instruction head (txa) on eval_and_compare that supplies the left type in X.
|
|||||||||||||||
| 9A9D | .compare_values←5← 9BCD JSR← 9BD6 JSR← 9BE1 JSR← 9BF1 JSR← 9BFC JSR | ||||||||||||||
| TXA ; Current type | |||||||||||||||
| fall through ↓ | |||||||||||||||
Evaluate the next operand and compareStack the already-evaluated left value, evaluate the next arithmetic operand at PtrB, then compare the two (integer, real or string), returning the ordering flags for the relational operators.
|
|||||||||||||||
| 9A9E | .eval_and_compare←1← 9BAF JSR | ||||||||||||||
| BEQ str_compare ; string: compare strings | |||||||||||||||
| 9AA0 | BMI cmp_real_real ; float: compare floats | ||||||||||||||
| 9AA2 | JSR stack_integer ; Stack the integer | ||||||||||||||
| 9AA5 | JSR eval_add_sub ; evaluate the next operand | ||||||||||||||
| 9AA8 | TAY ; type | ||||||||||||||
| 9AA9 | BEQ cmp_type_error ; string: Type mismatch | ||||||||||||||
| 9AAB | BMI cmp_int_real ; float: compare floats | ||||||||||||||
| fall through ↓ | |||||||||||||||
Compare an integer variable with the accumulatorSigned 32-bit compare of the integer on top of the BASIC stack against IWA: bias both sign bits so an unsigned subtract orders signed values, then subtract, returning the ordering in C and Z (Z = equal).
|
|||||||||||||
| 9AAD | .iwa_test_var | ||||||||||||
| LDA zp_iwa_3 ; Flip the sign bit of the IWA top byte | |||||||||||||
| 9AAF | EOR #&80 ; toggle bit 7 (bias to unsigned), | ||||||||||||
| 9AB1 | STA zp_iwa_3 ; store it back | ||||||||||||
| 9AB3 | SEC ; Subtract IWA from the stacked integer: byte 0 | ||||||||||||
| 9AB4 | LDY #0 ; from offset 0, | ||||||||||||
| 9AB6 | LDA (zp_stack_ptr),y ; stacked low byte, | ||||||||||||
| 9AB8 | SBC zp_iwa ; minus IWA low, | ||||||||||||
| 9ABA | STA zp_iwa ; store the difference | ||||||||||||
| 9ABC | INY ; byte 1 | ||||||||||||
| 9ABD | LDA (zp_stack_ptr),y ; stacked byte 1, | ||||||||||||
| 9ABF | SBC zp_iwa_1 ; minus IWA &2B, | ||||||||||||
| 9AC1 | STA zp_iwa_1 ; store it | ||||||||||||
| 9AC3 | INY ; byte 2 | ||||||||||||
| 9AC4 | LDA (zp_stack_ptr),y ; stacked byte 2, | ||||||||||||
| 9AC6 | SBC zp_iwa_2 ; minus IWA &2C, | ||||||||||||
| 9AC8 | STA zp_iwa_2 ; store it | ||||||||||||
| 9ACA | INY ; byte 3 (top) | ||||||||||||
| 9ACB | LDA (zp_stack_ptr),y ; stacked top byte, | ||||||||||||
| 9ACD | LDY #0 ; reset Y (bytes done) | ||||||||||||
| 9ACF | EOR #&80 ; flip its sign bit too | ||||||||||||
| 9AD1 | SBC zp_iwa_3 ; finish the signed subtract: sets C | ||||||||||||
| 9AD3 | ORA zp_iwa ; OR the low bytes... | ||||||||||||
| 9AD5 | ORA zp_iwa_1 ; and &2B, | ||||||||||||
| 9AD7 | ORA zp_iwa_2 ; ...to set Z when the values are equal | ||||||||||||
| 9AD9 | PHP ; Save the comparison flags | ||||||||||||
| 9ADA | CLC ; Drop the integer from the stack | ||||||||||||
| 9ADB | LDA #4 ; 4 bytes, | ||||||||||||
| 9ADD | ADC zp_stack_ptr ; + stack pointer low, | ||||||||||||
| 9ADF | STA zp_stack_ptr ; store low, | ||||||||||||
| 9AE1 | BCC itest_done ; no carry into the high byte | ||||||||||||
| 9AE3 | INC zp_stack_ptr_1 ; carry into the high byte | ||||||||||||
| 9AE5 | .itest_done←1← 9AE1 BCC | ||||||||||||
| PLP ; Restore the flags | |||||||||||||
| 9AE6 | RTS ; Return | ||||||||||||
| 9AE7 | .str_compare←1← 9A9E BEQ | ||||||||||||
| JSR stack_string ; String compare: stack the left | |||||||||||||
| 9AEA | JSR eval_add_sub ; evaluate the right operand | ||||||||||||
| 9AED | TAY ; type | ||||||||||||
| 9AEE | BNE cmp_type_error ; number: Type mismatch | ||||||||||||
| 9AF0 | STX zp_general ; Save the current pointer | ||||||||||||
| 9AF2 | LDX zp_strbuf_len ; current length | ||||||||||||
| 9AF4 | LDY #0 ; from 0 | ||||||||||||
| 9AF6 | LDA (zp_stack_ptr),y ; stacked length | ||||||||||||
| 9AF8 | STA zp_fileblk ; save it | ||||||||||||
| 9AFA | CMP zp_strbuf_len ; compare lengths | ||||||||||||
| 9AFC | BCS strcmp_shorter ; use the shorter | ||||||||||||
| 9AFE | TAX ; stacked shorter: X = its length | ||||||||||||
| 9AFF | .strcmp_shorter←1← 9AFC BCS | ||||||||||||
| STX zp_fileblk_1 ; shorter length | |||||||||||||
| 9B01 | LDY #0 ; compare from 0 | ||||||||||||
| 9B03 | .strcmp_loop←1← 9B0D BEQ | ||||||||||||
| CPY zp_fileblk_1 ; Reached the shorter length? | |||||||||||||
| 9B05 | BEQ strcmp_lengths ; yes: compare lengths | ||||||||||||
| 9B07 | INY ; Next character | ||||||||||||
| 9B08 | LDA (zp_stack_ptr),y ; stacked string | ||||||||||||
| 9B0A | CMP strbuf_base,y ; vs current string | ||||||||||||
| 9B0D | BEQ strcmp_loop ; equal: continue | ||||||||||||
| 9B0F | BNE strcmp_result ; differ | ||||||||||||
| 9B11 | .strcmp_lengths←1← 9B05 BEQ | ||||||||||||
| LDA zp_fileblk ; Compare the lengths | |||||||||||||
| 9B13 | CMP zp_strbuf_len ; stacked length vs current | ||||||||||||
| 9B15 | .strcmp_result←1← 9B0F BNE | ||||||||||||
| PHP ; Save the result | |||||||||||||
| 9B16 | JSR drop_stacked_string ; Drop the stacked string | ||||||||||||
| 9B19 | LDX zp_general ; restore the saved pointer (X) | ||||||||||||
| 9B1B | PLP ; Restore the result | ||||||||||||
| 9B1C | RTS ; Return | ||||||||||||
Evaluate an expressionThe interpreter's main expression entry point. Copies the primary text pointer (PtrA: zp_text_ptr / zp_text_ptr_off) to the secondary pointer (PtrB: zp_text_ptr2 / &1B) and evaluates the expression there.
|
||||||||
| 9B1D | .eval_expr←11← 8821 JSR← 886D JSR← 8B53 JSR← 8ED2 JSR← 93EB JSR← 98C2 JSR← B58C JSR← B91E JSR← B99F JSR← BBB1 JSR← BED2 JSR | |||||||
| LDA zp_text_ptr ; Start evaluating: copy PtrA to the working PtrB | ||||||||
| 9B1F | STA zp_text_ptr2 ; PtrB low = PtrA | |||||||
| 9B21 | LDA zp_text_ptr_1 ; PtrA high... | |||||||
| 9B23 | STA zp_text_ptr2_1 ; ...to PtrB high | |||||||
| 9B25 | LDA zp_text_ptr_off ; PtrA offset... | |||||||
| 9B27 | STA zp_text_ptr2_off ; ...to PtrB offset | |||||||
| fall through ↓ | ||||||||
Evaluator level 7: OR, EORLowest precedence: bitwise OR (&84) and EOR (&82) on integers.
|
|||||||||||||||
| 9B29 | .eval_or_eor←16← 8D39 JSR← 8DEB JSR← 92DD JSR← 93FA JSR← 9849 JSR← AC1D JSR← ACE2 JSR← ACF0 JSR← AE56 JSR← AFCC JSR← AFEE JSR← B039 JSR← B28E JSR← B4B1 JSR← B84F JSR← B86D JSR | ||||||||||||||
| JSR eval_and ; Evaluate the higher-precedence (AND) operand first | |||||||||||||||
| 9B2C | .eval_or_loop←1← 9B53 BNE | ||||||||||||||
| CPX #&84 ; Is the next operator OR or EOR at this level? | |||||||||||||||
| 9B2E | BEQ do_or ; yes | ||||||||||||||
| 9B30 | CPX #&82 ; EOR token? | ||||||||||||||
| 9B32 | BEQ do_eor ; yes | ||||||||||||||
| 9B34 | DEC zp_text_ptr2_off ; neither: back up over the token | ||||||||||||||
| 9B36 | TAY ; set the result-type flags | ||||||||||||||
| 9B37 | STA zp_var_type ; store it | ||||||||||||||
| 9B39 | RTS ; Return | ||||||||||||||
| 9B3A | .do_or←1← 9B2E BEQ | ||||||||||||||
| JSR coerce_left_int ; OR: stack the left operand, evaluate the right | |||||||||||||||
| 9B3D | TAY ; ensure the right operand is integer | ||||||||||||||
| 9B3E | JSR coerce_to_integer ; coerce it | ||||||||||||||
| 9B41 | LDY #3 ; Four bytes | ||||||||||||||
| 9B43 | .or_byte_loop←1← 9B4C BPL | ||||||||||||||
| LDA (zp_stack_ptr),y ; stacked byte | |||||||||||||||
| 9B45 | ORA zp_iwa,y ; OR with IWA | ||||||||||||||
| 9B48 | STA zp_iwa,y ; store back | ||||||||||||||
| 9B4B | DEY ; next byte | ||||||||||||||
| 9B4C | BPL or_byte_loop ; until all four OR-ed | ||||||||||||||
| 9B4E | .or_drop_stack←1← 9B69 BMI | ||||||||||||||
| JSR drop_stack_integer ; Drop the stacked operand | |||||||||||||||
| 9B51 | LDA #&40 ; Result type = integer | ||||||||||||||
| 9B53 | BNE eval_or_loop ; Loop to handle any further OR / EOR | ||||||||||||||
| 9B55 | .do_eor←1← 9B32 BEQ | ||||||||||||||
| JSR coerce_left_int ; EOR: stack the left operand, evaluate the right | |||||||||||||||
| 9B58 | TAY ; ensure the right operand is integer | ||||||||||||||
| 9B59 | JSR coerce_to_integer ; coerce it | ||||||||||||||
| 9B5C | LDY #3 ; Four bytes | ||||||||||||||
| 9B5E | .eor_byte_loop←1← 9B67 BPL | ||||||||||||||
| LDA (zp_stack_ptr),y ; stacked byte | |||||||||||||||
| 9B60 | EOR zp_iwa,y ; EOR with IWA | ||||||||||||||
| 9B63 | STA zp_iwa,y ; store back | ||||||||||||||
| 9B66 | DEY ; next byte | ||||||||||||||
| 9B67 | BPL eor_byte_loop ; until all four EOR-ed | ||||||||||||||
| 9B69 | BMI or_drop_stack ; drop and loop | ||||||||||||||
| 9B6B | .coerce_left_int←2← 9B3A JSR← 9B55 JSR | ||||||||||||||
| TAY ; Coerce the left operand to integer | |||||||||||||||
| 9B6C | JSR coerce_to_integer ; coerce it | ||||||||||||||
| 9B6F | JSR stack_integer ; stack it | ||||||||||||||
| fall through ↓ | |||||||||||||||
Evaluator level 6: ANDBitwise AND (&80) on integers.
|
|||||||||||||||
| 9B72 | .eval_and←1← 9B29 JSR | ||||||||||||||
| JSR eval_relational ; Evaluate a relational operand | |||||||||||||||
| 9B75 | .eval_and_loop←1← 9B9A BNE | ||||||||||||||
| CPX #&80 ; Apply AND only if the next operator is AND | |||||||||||||||
| 9B77 | BEQ do_and ; yes | ||||||||||||||
| 9B79 | RTS ; no: return | ||||||||||||||
| 9B7A | .do_and←1← 9B77 BEQ | ||||||||||||||
| TAY ; Coerce the left operand to integer | |||||||||||||||
| 9B7B | JSR coerce_to_integer ; coerce it | ||||||||||||||
| 9B7E | JSR stack_integer ; stack it | ||||||||||||||
| 9B81 | JSR eval_relational ; evaluate the right operand | ||||||||||||||
| 9B84 | TAY ; ensure it is integer | ||||||||||||||
| 9B85 | JSR coerce_to_integer ; coerce it | ||||||||||||||
| 9B88 | LDY #3 ; Four bytes | ||||||||||||||
| 9B8A | .and_byte_loop←1← 9B93 BPL | ||||||||||||||
| LDA (zp_stack_ptr),y ; stacked byte | |||||||||||||||
| 9B8C | AND zp_iwa,y ; AND with IWA | ||||||||||||||
| 9B8F | STA zp_iwa,y ; store back | ||||||||||||||
| 9B92 | DEY ; next byte | ||||||||||||||
| 9B93 | BPL and_byte_loop ; until all four AND-ed | ||||||||||||||
| 9B95 | JSR drop_stack_integer ; Drop the stacked operand | ||||||||||||||
| 9B98 | LDA #&40 ; Result type = integer | ||||||||||||||
| 9B9A | BNE eval_and_loop ; loop for further AND | ||||||||||||||
| fall through ↓ | |||||||||||||||
Evaluator level 5: < <= = >= > <>The relational operators, yielding TRUE (-1) or FALSE (0).
|
|||||||||||||||
| 9B9C | .eval_relational←2← 9B72 JSR← 9B81 JSR | ||||||||||||||
| JSR eval_add_sub ; Evaluate a + - operand | |||||||||||||||
| 9B9F | CPX #'?' ; next token past '>'? | ||||||||||||||
| 9BA1 | BCS return_18 ; yes: not a comparison, return | ||||||||||||||
| 9BA3 | CPX #'<' ; before '<'? | ||||||||||||||
| 9BA5 | BCS rel_lt_family ; a relational operator: handle it | ||||||||||||||
| 9BA7 | .return_18←1← 9BA1 BCS | ||||||||||||||
| RTS ; not a comparison: return | |||||||||||||||
| 9BA8 | .rel_lt_family←1← 9BA5 BCS | ||||||||||||||
| BEQ rel_lt ; '<' family? | |||||||||||||||
| 9BAA | CPX #'>' ; '>' family? | ||||||||||||||
| 9BAC | BEQ rel_gt ; yes | ||||||||||||||
| 9BAE | TAX ; '=': compare for equality | ||||||||||||||
| 9BAF | JSR eval_and_compare ; evaluate the right operand and compare | ||||||||||||||
| 9BB2 | BNE store_bool ; not equal: result FALSE (0) | ||||||||||||||
| 9BB4 | .rel_true←6← 9BD0 BCC← 9BD9 BEQ← 9BDB BCC← 9BE4 BNE← 9BF6 BCS← 9BFF BCS | ||||||||||||||
| DEY ; equal: result TRUE (Y = &FF) | |||||||||||||||
| 9BB5 | .store_bool←7← 9BB2 BNE← 9BD2 BCS← 9BDD BCS← 9BE6 BEQ← 9BF4 BEQ← 9BF8 BCC← 9C01 BCC | ||||||||||||||
| STY zp_iwa ; Store 0/-1 in all four IWA bytes | |||||||||||||||
| 9BB7 | STY zp_iwa_1 ; byte 1, | ||||||||||||||
| 9BB9 | STY zp_iwa_2 ; byte 2, | ||||||||||||||
| 9BBB | STY zp_iwa_3 ; byte 3 | ||||||||||||||
| 9BBD | LDA #&40 ; Result type = integer | ||||||||||||||
| 9BBF | RTS ; Return | ||||||||||||||
| 9BC0 | .rel_lt←1← 9BA8 BEQ | ||||||||||||||
| TAX ; '<' family: discard the operator | |||||||||||||||
| 9BC1 | LDY zp_text_ptr2_off ; Peek at the next source character | ||||||||||||||
| 9BC3 | LDA (zp_text_ptr2),y ; read it | ||||||||||||||
| 9BC5 | CMP #'=' ; '='? (<=) | ||||||||||||||
| 9BC7 | BEQ rel_le ; yes | ||||||||||||||
| 9BC9 | CMP #'>' ; '>'? (<>) | ||||||||||||||
| 9BCB | BEQ rel_ne ; yes | ||||||||||||||
| 9BCD | JSR compare_values ; plain "<": evaluate and compare | ||||||||||||||
| 9BD0 | BCC rel_true ; less: TRUE | ||||||||||||||
| 9BD2 | BCS store_bool ; not less: FALSE | ||||||||||||||
| 9BD4 | .rel_le←1← 9BC7 BEQ | ||||||||||||||
| INC zp_text_ptr2_off ; '<=': step past the '=' | |||||||||||||||
| 9BD6 | JSR compare_values ; evaluate and compare | ||||||||||||||
| 9BD9 | BEQ rel_true ; equal: TRUE | ||||||||||||||
| 9BDB | BCC rel_true ; less: TRUE | ||||||||||||||
| 9BDD | BCS store_bool ; greater: FALSE | ||||||||||||||
| 9BDF | .rel_ne←1← 9BCB BEQ | ||||||||||||||
| INC zp_text_ptr2_off ; '<>': step past the '>' | |||||||||||||||
| 9BE1 | JSR compare_values ; evaluate and compare | ||||||||||||||
| 9BE4 | BNE rel_true ; unequal: TRUE | ||||||||||||||
| 9BE6 | BEQ store_bool ; equal: FALSE | ||||||||||||||
| 9BE8 | .rel_gt←1← 9BAC BEQ | ||||||||||||||
| TAX ; '>' family: discard the operator | |||||||||||||||
| 9BE9 | LDY zp_text_ptr2_off ; Peek at the next source character | ||||||||||||||
| 9BEB | LDA (zp_text_ptr2),y ; read it | ||||||||||||||
| 9BED | CMP #'=' ; '='? (>=) | ||||||||||||||
| 9BEF | BEQ rel_ge ; yes | ||||||||||||||
| 9BF1 | JSR compare_values ; plain ">": evaluate and compare | ||||||||||||||
| 9BF4 | BEQ store_bool ; equal: FALSE | ||||||||||||||
| 9BF6 | BCS rel_true ; greater: TRUE | ||||||||||||||
| 9BF8 | BCC store_bool ; less: FALSE | ||||||||||||||
| 9BFA | .rel_ge←1← 9BEF BEQ | ||||||||||||||
| INC zp_text_ptr2_off ; '>=': step past the '=' | |||||||||||||||
| 9BFC | JSR compare_values ; evaluate and compare | ||||||||||||||
| 9BFF | BCS rel_true ; greater or equal: TRUE | ||||||||||||||
| 9C01 | BCC store_bool ; less: FALSE | ||||||||||||||
| 9C03 | .string_too_long←2← 9C27 BCS← B0FB JMP | ||||||||||||||
| BRK ; String too long error | |||||||||||||||
| 9C04 | EQUB &13 | ||||||||||||||
| 9C05 | EQUS "String too long" | ||||||||||||||
| 9C14 | EQUB &00 | ||||||||||||||
| 9C15 | .relstr_stack_loop←1← 9C4F BEQ | ||||||||||||||
| JSR stack_string ; Stack the left string | |||||||||||||||
| 9C18 | JSR eval_power ; Evaluate the right operand | ||||||||||||||
| 9C1B | TAY ; type | ||||||||||||||
| 9C1C | BNE arith_type_error ; number: Type mismatch | ||||||||||||||
| 9C1E | CLC ; New length = left + right | ||||||||||||||
| 9C1F | STX zp_general ; save the pending operator (X) | ||||||||||||||
| 9C21 | LDY #0 ; index the stacked left length | ||||||||||||||
| 9C23 | LDA (zp_stack_ptr),y ; left length | ||||||||||||||
| 9C25 | ADC zp_strbuf_len ; plus the right length | ||||||||||||||
| 9C27 | BCS string_too_long ; over 255: error | ||||||||||||||
| 9C29 | TAX ; Save the new length | ||||||||||||||
| 9C2A | PHA ; keep it on the stack | ||||||||||||||
| 9C2B | LDY zp_strbuf_len ; Move the right string up | ||||||||||||||
| 9C2D | .relstr_cmp_loop←1← 9C35 BNE | ||||||||||||||
| LDA strbuf_base,y ; right string byte (at Y) | |||||||||||||||
| 9C30 | STA strbuf_base,x ; to the new tail (at X) | ||||||||||||||
| 9C33 | DEX ; back one destination | ||||||||||||||
| 9C34 | DEY ; back one source | ||||||||||||||
| 9C35 | BNE relstr_cmp_loop ; loop | ||||||||||||||
| 9C37 | JSR unstack_string ; Prepend the left string | ||||||||||||||
| 9C3A | PLA ; Set the new length | ||||||||||||||
| 9C3B | STA zp_strbuf_len ; store it | ||||||||||||||
| 9C3D | LDX zp_general ; restore the pending operator | ||||||||||||||
| 9C3F | TYA ; string result | ||||||||||||||
| 9C40 | BEQ addsub_check ; loop for further + or - | ||||||||||||||
| fall through ↓ | |||||||||||||||
Evaluator level 4: + -Addition and subtraction (numeric, or string concatenation).
|
|||||||||||||||
| 9C42 | .eval_add_sub←4← 9A53 JSR← 9AA5 JSR← 9AEA JSR← 9B9C JSR | ||||||||||||||
| JSR eval_mul_div ; Evaluate a * / DIV MOD operand | |||||||||||||||
| 9C45 | .addsub_check←4← 9C40 BEQ← 9C82 BCC← 9C86 BCS← 9CA5 BNE | ||||||||||||||
| CPX #'+' ; Apply + or - if that is the next operator | |||||||||||||||
| 9C47 | BEQ do_add ; yes: addition | ||||||||||||||
| 9C49 | CPX #'-' ; next operator "-"? | ||||||||||||||
| 9C4B | BEQ sub_dispatch ; yes: subtraction | ||||||||||||||
| 9C4D | RTS ; neither: expression complete | ||||||||||||||
| 9C4E | .do_add←1← 9C47 BEQ | ||||||||||||||
| TAY ; Addition: type of the left operand | |||||||||||||||
| 9C4F | BEQ relstr_stack_loop ; string: concatenate | ||||||||||||||
| 9C51 | BMI add_real_left ; real: handle as float add | ||||||||||||||
| 9C53 | JSR mul_stack_eval ; integer: stack it and evaluate the right operand | ||||||||||||||
| 9C56 | TAY ; Type of the right operand | ||||||||||||||
| 9C57 | BEQ arith_type_error ; string: Type mismatch | ||||||||||||||
| 9C59 | BMI add_int_real ; real: convert the left integer to float | ||||||||||||||
| fall through ↓ | |||||||||||||||
Integer addIWA = IWA + the integer operand on the BASIC stack.
|
|||||||||||
| 9C5B | .iwa_add | ||||||||||
| LDY #0 ; int + int: add the 32-bit stacked value to IWA | |||||||||||
| 9C5D | CLC ; ...byte 0 | ||||||||||
| 9C5E | LDA (zp_stack_ptr),y ; stacked low, | ||||||||||
| 9C60 | ADC zp_iwa ; + IWA low, | ||||||||||
| 9C62 | STA zp_iwa ; store, | ||||||||||
| 9C64 | INY ; ...byte 1 | ||||||||||
| 9C65 | LDA (zp_stack_ptr),y ; stacked, | ||||||||||
| 9C67 | ADC zp_iwa_1 ; + IWA &2B, | ||||||||||
| 9C69 | STA zp_iwa_1 ; store, | ||||||||||
| 9C6B | INY ; ...byte 2 | ||||||||||
| 9C6C | LDA (zp_stack_ptr),y ; stacked, | ||||||||||
| 9C6E | ADC zp_iwa_2 ; + IWA &2C, | ||||||||||
| 9C70 | STA zp_iwa_2 ; store, | ||||||||||
| 9C72 | INY ; ...byte 3 | ||||||||||
| 9C73 | LDA (zp_stack_ptr),y ; stacked, | ||||||||||
| 9C75 | ADC zp_iwa_3 ; + IWA &2D (high) | ||||||||||
| 9C77 | .iadd_store_drop←1← 9CDE JMP | ||||||||||
| STA zp_iwa_3 ; store the high byte | |||||||||||
| 9C79 | CLC ; Drop the operand (stack += 4), | ||||||||||
| 9C7A | LDA zp_stack_ptr ; low byte, | ||||||||||
| 9C7C | ADC #4 ; + 4, | ||||||||||
| 9C7E | STA zp_stack_ptr ; store low, | ||||||||||
| 9C80 | LDA #&40 ; Result type = integer | ||||||||||
| 9C82 | BCC addsub_check ; loop for further + or - | ||||||||||
| 9C84 | INC zp_stack_ptr_1 ; carry into the high byte, | ||||||||||
| 9C86 | BCS addsub_check ; back for a further + or - | ||||||||||
| 9C88 | .arith_type_error←6← 9C1C BNE← 9C57 BEQ← 9C92 BEQ← 9CB6 BEQ← 9CBE BEQ← 9CE8 BEQ | ||||||||||
| JMP err_type_mismatch ; Type mismatch error | |||||||||||
| 9C8B | .add_real_left←1← 9C51 BMI | ||||||||||
| JSR stack_real ; Left real: stack it, evaluate the right operand | |||||||||||
| 9C8E | JSR eval_mul_div ; evaluate the right operand | ||||||||||
| 9C91 | TAY ; Type of the right operand | ||||||||||
| 9C92 | BEQ arith_type_error ; string: Type mismatch | ||||||||||
| 9C94 | STX zp_var_type ; remember it for later | ||||||||||
| 9C96 | BMI add_floats ; real: no conversion needed | ||||||||||
| 9C98 | JSR int_to_fwa ; integer: convert the right operand to float | ||||||||||
| 9C9B | .add_floats←2← 9C96 BMI← 9CB2 JMP | ||||||||||
| JSR unstack_real ; Pop the stacked real as the fp operand | |||||||||||
| 9C9E | JSR fwa_add_var ; FWA = left + right | ||||||||||
| 9CA1 | .arith_result_loop←2← 9CF7 JMP← 9D0B JMP | ||||||||||
| LDX zp_var_type ; Restore the next character | |||||||||||
| 9CA3 | LDA #&ff ; Result type = real | ||||||||||
| 9CA5 | BNE addsub_check ; loop for further + or - | ||||||||||
| 9CA7 | .add_int_real←1← 9C59 BMI | ||||||||||
| STX zp_var_type ; Left int, right real: save the operator | |||||||||||
| 9CA9 | JSR unstack_integer ; pop the stacked left integer | ||||||||||
| 9CAC | JSR stack_real ; stack the right real | ||||||||||
| 9CAF | JSR int_to_fwa ; convert the left integer to float | ||||||||||
| 9CB2 | JMP add_floats ; then do float + float | ||||||||||
| 9CB5 | .sub_dispatch←1← 9C4B BEQ | ||||||||||
| TAY ; Subtraction: type of the left operand | |||||||||||
| 9CB6 | BEQ arith_type_error ; string: Type mismatch | ||||||||||
| 9CB8 | BMI sub_real_left ; real: handle as float subtract | ||||||||||
| 9CBA | JSR mul_stack_eval ; integer: stack it, evaluate the right operand | ||||||||||
| 9CBD | TAY ; Type of the right operand | ||||||||||
| 9CBE | BEQ arith_type_error ; string: Type mismatch | ||||||||||
| 9CC0 | BMI sub_int_real ; real: convert and subtract as floats | ||||||||||
| fall through ↓ | |||||||||||
Reverse integer subtractIWA = stacked operand - IWA.
|
|||||||||||
| 9CC2 | .iwa_rsub | ||||||||||
| SEC ; int - int: stacked value minus IWA, byte 0 | |||||||||||
| 9CC3 | LDY #0 ; from offset 0, | ||||||||||
| 9CC5 | LDA (zp_stack_ptr),y ; stacked low, | ||||||||||
| 9CC7 | SBC zp_iwa ; - IWA low, | ||||||||||
| 9CC9 | STA zp_iwa ; store, | ||||||||||
| 9CCB | INY ; ...byte 1 | ||||||||||
| 9CCC | LDA (zp_stack_ptr),y ; stacked, | ||||||||||
| 9CCE | SBC zp_iwa_1 ; - IWA &2B, | ||||||||||
| 9CD0 | STA zp_iwa_1 ; store, | ||||||||||
| 9CD2 | INY ; ...byte 2 | ||||||||||
| 9CD3 | LDA (zp_stack_ptr),y ; stacked, | ||||||||||
| 9CD5 | SBC zp_iwa_2 ; - IWA &2C, | ||||||||||
| 9CD7 | STA zp_iwa_2 ; store, | ||||||||||
| 9CD9 | INY ; ...byte 3 | ||||||||||
| 9CDA | LDA (zp_stack_ptr),y ; stacked, | ||||||||||
| 9CDC | SBC zp_iwa_3 ; - IWA &2D (high) | ||||||||||
| 9CDE | JMP iadd_store_drop ; store byte 3, drop the operand and loop | ||||||||||
| 9CE1 | .sub_real_left←1← 9CB8 BMI | ||||||||||
| JSR stack_real ; Left real: stack it, evaluate the right operand | |||||||||||
| 9CE4 | JSR eval_mul_div ; evaluate the right operand | ||||||||||
| 9CE7 | TAY ; Type of the right operand | ||||||||||
| 9CE8 | BEQ arith_type_error ; string: Type mismatch | ||||||||||
| 9CEA | STX zp_var_type ; remember it | ||||||||||
| 9CEC | BMI sub_floats ; real: no conversion needed | ||||||||||
| 9CEE | JSR int_to_fwa ; integer: convert the right operand to float | ||||||||||
| 9CF1 | .sub_floats←1← 9CEC BMI | ||||||||||
| JSR unstack_real ; Pop the stacked real as the fp operand | |||||||||||
| 9CF4 | JSR fwa_rsub_var ; FWA = left - right | ||||||||||
| 9CF7 | JMP arith_result_loop ; set result type and loop | ||||||||||
| 9CFA | .sub_int_real←1← 9CC0 BMI | ||||||||||
| STX zp_var_type ; Left int, right real: save the operator | |||||||||||
| 9CFC | JSR unstack_integer ; pop the stacked left integer | ||||||||||
| 9CFF | JSR stack_real ; stack the right real | ||||||||||
| 9D02 | JSR int_to_fwa ; convert the left integer to float | ||||||||||
| 9D05 | JSR unstack_real ; pop the stacked right real | ||||||||||
| 9D08 | JSR fwa_sub_var ; FWA = left - right | ||||||||||
| 9D0B | JMP arith_result_loop ; set result type and loop | ||||||||||
| 9D0E | .mul_conv_right←3← 9D60 BNE← 9D67 BNE← 9D6B BMI | ||||||||||
| JSR int_to_fwa ; Convert the right integer to float | |||||||||||
| 9D11 | .mul_conv_both←1← 9D5A BMI | ||||||||||
| JSR unstack_integer ; Pop the stacked left integer | |||||||||||
| 9D14 | JSR stack_real ; stack the right real | ||||||||||
| 9D17 | JSR int_to_fwa ; convert the left integer to float | ||||||||||
| 9D1A | JMP mul_floats ; then do float * float | ||||||||||
| 9D1D | .mul_conv_left←3← 9D45 BNE← 9D4C BNE← 9D50 BMI | ||||||||||
| JSR int_to_fwa ; Convert the left integer to float | |||||||||||
| 9D20 | .mul_real_left←1← 9D3F BMI | ||||||||||
| JSR stack_real ; Stack the left real | |||||||||||
| 9D23 | JSR eval_power ; evaluate the next (^ level) operand | ||||||||||
| 9D26 | STX zp_var_type ; remember the operand type | ||||||||||
| 9D28 | TAY ; test the operand type | ||||||||||
| 9D29 | JSR ensure_real ; ensure the operand is real | ||||||||||
| 9D2C | .mul_floats←1← 9D1A JMP | ||||||||||
| JSR unstack_real ; Pop the stacked left real | |||||||||||
| 9D2F | JSR fwa_mul_var ; FWA = left * right | ||||||||||
| 9D32 | LDA #&ff ; real result | ||||||||||
| 9D34 | LDX zp_var_type ; restore the operator | ||||||||||
| 9D36 | JMP muldiv_check ; loop for further * / DIV MOD | ||||||||||
| 9D39 | .mul_type_error←2← 9D3D BEQ← 9D58 BEQ | ||||||||||
| JMP err_type_mismatch ; String operand: Type mismatch | |||||||||||
| 9D3C | .mul_dispatch←1← 9DCB JMP | ||||||||||
| TAY ; Left operand type | |||||||||||
| 9D3D | BEQ mul_type_error ; string: Type mismatch | ||||||||||
| 9D3F | BMI mul_real_left ; real: floating-point multiply | ||||||||||
| 9D41 | LDA zp_iwa_3 ; Integer: does it fit signed 16 bits? | ||||||||||
| 9D43 | CMP zp_iwa_2 ; byte 3 == byte 2 (sign-extended)? | ||||||||||
| 9D45 | BNE mul_conv_left ; no: floating-point multiply | ||||||||||
| 9D47 | TAY ; high word zero (positive)? | ||||||||||
| 9D48 | BEQ mul_right_signed ; yes | ||||||||||
| 9D4A | CMP #&ff ; high word all ones (negative)? | ||||||||||
| 9D4C | BNE mul_conv_left ; no: floating-point multiply | ||||||||||
| 9D4E | .mul_right_signed←1← 9D48 BEQ | ||||||||||
| EOR zp_iwa_1 ; sign consistent with bit 15? | |||||||||||
| 9D50 | BMI mul_conv_left ; no: floating-point multiply | ||||||||||
| 9D52 | JSR pow_stack_eval ; Stack it, evaluate the right operand | ||||||||||
| 9D55 | STX zp_var_type ; remember the operator | ||||||||||
| 9D57 | TAY ; right operand type | ||||||||||
| 9D58 | BEQ mul_type_error ; string: Type mismatch | ||||||||||
| 9D5A | BMI mul_conv_both ; real: floating-point multiply | ||||||||||
| 9D5C | LDA zp_iwa_3 ; fits signed 16 bits? | ||||||||||
| 9D5E | CMP zp_iwa_2 ; byte 3 == byte 2 (sign-extended)? | ||||||||||
| 9D60 | BNE mul_conv_right ; no: floating-point multiply | ||||||||||
| 9D62 | TAY ; positive? | ||||||||||
| 9D63 | BEQ mul_left_signed ; yes | ||||||||||
| 9D65 | CMP #&ff ; negative? | ||||||||||
| 9D67 | BNE mul_conv_right ; no: floating-point multiply | ||||||||||
| 9D69 | .mul_left_signed←1← 9D63 BEQ | ||||||||||
| EOR zp_iwa_1 ; sign consistent? | |||||||||||
| 9D6B | BMI mul_conv_right ; no: floating-point multiply | ||||||||||
| fall through ↓ | |||||||||||
Integer multiplyIWA = IWA * the stacked operand. A product wider than 16 bits is truncated to 16 significant bits.
|
|||||||||||
| 9D6D | .iwa_mul | ||||||||||
| LDA zp_iwa_3 ; Save the right operand sign | |||||||||||
| 9D6F | PHA ; push it | ||||||||||
| 9D70 | JSR iwa_abs ; take |right| | ||||||||||
| 9D73 | LDX #&39 ; save it (via &39) | ||||||||||
| 9D75 | JSR iwa_store_zp ; store it as the multiplier | ||||||||||
| 9D78 | JSR unstack_integer ; unstack the left operand | ||||||||||
| 9D7B | PLA ; recover the right operand sign | ||||||||||
| 9D7C | EOR zp_iwa_3 ; product sign = sign XOR sign | ||||||||||
| 9D7E | STA zp_general ; (save it) | ||||||||||
| 9D80 | JSR iwa_abs ; take |left| | ||||||||||
| 9D83 | LDY #0 ; Clear the running product: | ||||||||||
| 9D85 | LDX #0 ; byte 1 (in X), | ||||||||||
| 9D87 | STY zp_fwb_m2 ; byte 2, | ||||||||||
| 9D89 | STY zp_fwb_m3 ; and byte 3 | ||||||||||
| 9D8B | .iwamul_loop←1← 9DB2 BNE | ||||||||||
| LSR zp_fileblk_1 ; Shift the multiplier right: next bit | |||||||||||
| 9D8D | ROR zp_fileblk ; low byte; bit 0 -> carry | ||||||||||
| 9D8F | BCC iwamul_double ; bit clear: skip the add | ||||||||||
| 9D91 | CLC ; bit set: add the multiplicand | ||||||||||
| 9D92 | TYA ; byte 0 | ||||||||||
| 9D93 | ADC zp_iwa ; + multiplicand byte 0, | ||||||||||
| 9D95 | TAY ; back to product byte 0 | ||||||||||
| 9D96 | TXA ; byte 1 | ||||||||||
| 9D97 | ADC zp_iwa_1 ; + byte 1, | ||||||||||
| 9D99 | TAX ; back to product byte 1 | ||||||||||
| 9D9A | LDA zp_fwb_m2 ; byte 2 | ||||||||||
| 9D9C | ADC zp_iwa_2 ; + byte 2, | ||||||||||
| 9D9E | STA zp_fwb_m2 ; back to product byte 2 | ||||||||||
| 9DA0 | LDA zp_fwb_m3 ; byte 3 | ||||||||||
| 9DA2 | ADC zp_iwa_3 ; + byte 3, | ||||||||||
| 9DA4 | STA zp_fwb_m3 ; back to product byte 3 | ||||||||||
| 9DA6 | .iwamul_double←1← 9D8F BCC | ||||||||||
| ASL zp_iwa ; Shift the multiplicand left | |||||||||||
| 9DA8 | ROL zp_iwa_1 ; byte 1, | ||||||||||
| 9DAA | ROL zp_iwa_2 ; byte 2, | ||||||||||
| 9DAC | ROL zp_iwa_3 ; byte 3 (multiplicand now x2) | ||||||||||
| 9DAE | LDA zp_fileblk ; more multiplier bits? | ||||||||||
| 9DB0 | ORA zp_fileblk_1 ; OR in the high byte | ||||||||||
| 9DB2 | BNE iwamul_loop ; loop | ||||||||||
| 9DB4 | STY zp_fwb_exp ; store the product (low 2 bytes) | ||||||||||
| 9DB6 | STX zp_fwb_m1 ; and byte 1 (bytes 2-3 already in place) | ||||||||||
| 9DB8 | LDA zp_general ; product sign | ||||||||||
| 9DBA | PHP ; save its N flag | ||||||||||
| 9DBB | .iwamul_result←1← 9E07 JMP | ||||||||||
| LDX #&3d ; load the product into IWA | |||||||||||
| 9DBD | .iwamul_copy←1← 9E1A JMP | ||||||||||
| JSR iwa_load_zp ; copy &3D..&40 into IWA | |||||||||||
| 9DC0 | PLP ; Apply the sign | ||||||||||
| 9DC1 | BPL iwamul_restore_op ; positive: done | ||||||||||
| 9DC3 | JSR iwa_negate ; negative: negate the product | ||||||||||
| 9DC6 | .iwamul_restore_op←1← 9DC1 BPL | ||||||||||
| LDX zp_var_type ; restore the operator | |||||||||||
| 9DC8 | JMP muldiv_check ; loop for further * / DIV MOD | ||||||||||
| 9DCB | .iwamul_bounce←1← 9DD6 BEQ | ||||||||||
| JMP mul_dispatch ; bounce back to the multiply code | |||||||||||
Stack the integer, then evaluate a * / DIV / MOD expressionPush the pending integer accumulator onto the arithmetic stack via stack_integer, then fall into eval_mul_div to evaluate the higher-precedence (^) operand and apply any * / DIV / MOD operators. A trampoline used when the caller already holds an integer that must be preserved across the multiply-level evaluation.
|
|||||||||||||||||
| 9DCE | .mul_stack_eval←2← 9C53 JSR← 9CBA JSR | ||||||||||||||||
| JSR stack_integer ; stack the operand, then multiply | |||||||||||||||||
| fall through ↓ | |||||||||||||||||
Evaluator level 3: * / DIV MODMultiplication, division and the integer DIV and MOD operators.
|
|||||||||||||||
| 9DD1 | .eval_mul_div←3← 9C42 JSR← 9C8E JSR← 9CE4 JSR | ||||||||||||||
| JSR eval_power ; Evaluate the higher level (^, level 2) operand | |||||||||||||||
| 9DD4 | .muldiv_check←3← 9D36 JMP← 9DC8 JMP← 9DFF BNE | ||||||||||||||
| CPX #'*' ; next operator "*"? | |||||||||||||||
| 9DD6 | BEQ iwamul_bounce ; yes: multiply | ||||||||||||||
| 9DD8 | CPX #'/' ; "/"? | ||||||||||||||
| 9DDA | BEQ do_divide ; yes: divide | ||||||||||||||
| 9DDC | CPX #&83 ; MOD token? | ||||||||||||||
| 9DDE | BEQ iwa_mod ; yes: integer remainder | ||||||||||||||
| 9DE0 | CPX #&81 ; DIV token? | ||||||||||||||
| 9DE2 | BEQ iwa_div ; yes: integer divide | ||||||||||||||
| 9DE4 | RTS ; no operator: return | ||||||||||||||
| 9DE5 | .do_divide←1← 9DDA BEQ | ||||||||||||||
| TAY ; Divide: ensure the left operand is real | |||||||||||||||
| 9DE6 | JSR ensure_real ; convert if integer | ||||||||||||||
| 9DE9 | JSR stack_real ; stack it | ||||||||||||||
| 9DEC | JSR eval_power ; evaluate the right operand | ||||||||||||||
| 9DEF | STX zp_var_type ; remember the operator | ||||||||||||||
| 9DF1 | TAY ; ensure the right operand is real | ||||||||||||||
| 9DF2 | JSR ensure_real ; convert if integer | ||||||||||||||
| 9DF5 | JSR unstack_real ; pop the left operand as the fp operand | ||||||||||||||
| 9DF8 | JSR fwa_rdiv_var ; FWA = left / right | ||||||||||||||
| 9DFB | LDX zp_var_type ; restore the operator | ||||||||||||||
| 9DFD | LDA #&ff ; real result | ||||||||||||||
| 9DFF | BNE muldiv_check ; loop for further * / DIV MOD | ||||||||||||||
| fall through ↓ | |||||||||||||||
Integer remainderIWA = IWA MOD the integer operand. Raises "Division by zero" if the divisor is zero.
|
|||||||
| 9E01 | .iwa_mod←1← 9DDE BEQ | ||||||
| JSR iwa_divide ; MOD: divide | |||||||
| 9E04 | LDA zp_general_1 ; remainder takes the dividend sign | ||||||
| 9E06 | PHP ; save the sign | ||||||
| 9E07 | JMP iwamul_result ; load the remainder (&3D-&40) and apply the sign | ||||||
Integer divideIWA = IWA DIV the integer operand. Raises "Division by zero" if the divisor is zero.
|
|||||||
| 9E0A | .iwa_div←1← 9DE2 BEQ | ||||||
| JSR iwa_divide ; DIV: divide | |||||||
| 9E0D | ROL zp_fileblk ; Shift the quotient up by one | ||||||
| 9E0F | ROL zp_fileblk_1 ; through &3A, | ||||||
| 9E11 | ROL zp_fwb_sign ; &3B, | ||||||
| 9E13 | ROL zp_fwb_ovf ; &3C | ||||||
| 9E15 | BIT zp_general ; quotient sign | ||||||
| 9E17 | PHP ; save the sign flags | ||||||
| 9E18 | LDX #&39 ; load the quotient (&39-&3C) | ||||||
| 9E1A | JMP iwamul_copy ; ...and apply the sign | ||||||
Stack the integer, then evaluate a ^ expressionPush the pending integer accumulator onto the arithmetic stack via stack_integer, then fall into eval_power to evaluate the next factor and apply any ^ operators. A trampoline used when the caller already holds an integer that must be preserved across the power-level evaluation.
|
|||||||||||||||||
| 9E1D | .pow_stack_eval←2← 99C8 JSR← 9D52 JSR | ||||||||||||||||
| JSR stack_integer ; Stack the integer, evaluate the next ^ operand | |||||||||||||||||
| fall through ↓ | |||||||||||||||||
Expression Level 2 - the ^ operatorEvaluate a factor, then for each ^ raise it to the power: an integer exponent uses repeated multiplication, otherwise x^y = x^int * exp(frac * ln x).
|
|||||||||||||||
| 9E20 | .eval_power←4← 9C18 JSR← 9D23 JSR← 9DD1 JSR← 9DEC JSR | ||||||||||||||
| JSR eval_factor ; Evaluate the base | |||||||||||||||
| 9E23 | .pow_result←2← 9E57 BNE← 9E86 BNE | ||||||||||||||
| PHA ; Save the result type | |||||||||||||||
| 9E24 | .pow_op_loop←1← 9E2C BEQ | ||||||||||||||
| LDY zp_text_ptr2_off ; Next character | |||||||||||||||
| 9E26 | INC zp_text_ptr2_off ; advance the offset | ||||||||||||||
| 9E28 | LDA (zp_text_ptr2),y ; read it | ||||||||||||||
| 9E2A | CMP #' ' ; space? | ||||||||||||||
| 9E2C | BEQ pow_op_loop ; skip it | ||||||||||||||
| 9E2E | TAX ; keep the operator | ||||||||||||||
| 9E2F | PLA ; restore the type | ||||||||||||||
| 9E30 | CPX #'^' ; '^'? | ||||||||||||||
| 9E32 | BEQ pow_apply ; yes | ||||||||||||||
| 9E34 | RTS ; no: return | ||||||||||||||
| 9E35 | .pow_apply←1← 9E32 BEQ | ||||||||||||||
| TAY ; Ensure the base is real | |||||||||||||||
| 9E36 | JSR ensure_real ; convert if integer | ||||||||||||||
| 9E39 | JSR stack_real ; stack the base | ||||||||||||||
| 9E3C | JSR eval_real ; evaluate the exponent as a real | ||||||||||||||
| 9E3F | LDA zp_fwa_exp ; Exponent magnitude | ||||||||||||||
| 9E41 | CMP #&87 ; large (>= 2^7)? | ||||||||||||||
| 9E43 | BCS pow_large ; yes: use exp(y*ln x) | ||||||||||||||
| 9E45 | JSR fp_split_int_frac ; Split into integer and fractional parts | ||||||||||||||
| 9E48 | BNE pow_frac ; fractional part nonzero? | ||||||||||||||
| 9E4A | JSR unstack_real ; no: integer power - unstack the base | ||||||||||||||
| 9E4D | JSR fwa_unpack_var ; load it into FWA | ||||||||||||||
| 9E50 | LDA zp_int_exp ; integer exponent | ||||||||||||||
| 9E52 | JSR fwa_int_power ; FWA = base ^ int | ||||||||||||||
| 9E55 | LDA #&ff ; real result | ||||||||||||||
| 9E57 | BNE pow_result ; continue | ||||||||||||||
| 9E59 | .pow_frac←1← 9E48 BNE | ||||||||||||||
| JSR fwa_pack_temp3 ; Fractional exponent: save the fraction | |||||||||||||||
| 9E5C | LDA zp_stack_ptr ; point at the stacked base | ||||||||||||||
| 9E5E | STA zp_fp_ptr ; low byte | ||||||||||||||
| 9E60 | LDA zp_stack_ptr_1 ; high byte | ||||||||||||||
| 9E62 | STA zp_fp_ptr_1 ; set the fp pointer | ||||||||||||||
| 9E64 | JSR fwa_unpack_var ; load the base | ||||||||||||||
| 9E67 | LDA zp_int_exp ; integer part of the exponent | ||||||||||||||
| 9E69 | JSR fwa_int_power ; FWA = base ^ int | ||||||||||||||
| 9E6C | .pow_combine←1← 9E8E BNE | ||||||||||||||
| JSR fwa_pack_temp2 ; save base^int in TEMP2 | |||||||||||||||
| 9E6F | JSR unstack_real ; unstack the base | ||||||||||||||
| 9E72 | JSR fwa_unpack_var ; load it into FWA | ||||||||||||||
| 9E75 | JSR ln_compute ; ln(base) | ||||||||||||||
| 9E78 | JSR mul_by_temp3 ; times the fractional exponent | ||||||||||||||
| 9E7B | JSR exp_compute ; exp(that) = base^frac | ||||||||||||||
| 9E7E | JSR point_fp_temp2 ; point at base^int | ||||||||||||||
| 9E81 | JSR fwa_mul_var ; FWA = base^int * base^frac | ||||||||||||||
| 9E84 | LDA #&ff ; real result | ||||||||||||||
| 9E86 | BNE pow_result ; continue | ||||||||||||||
| 9E88 | .pow_large←1← 9E43 BCS | ||||||||||||||
| JSR fwa_pack_temp3 ; Large exponent: x^y = exp(y * ln x) | |||||||||||||||
| 9E8B | JSR fwa_set_one ; base^int = 1 (no integer part) | ||||||||||||||
| 9E8E | BNE pow_combine ; evaluate it | ||||||||||||||
| 9E90 | .hex_convert←1← 9F07 BMI | ||||||||||||||
| TYA ; Real? | |||||||||||||||
| 9E91 | BPL hex_expand ; no | ||||||||||||||
| 9E93 | JSR fwa_to_int ; convert to integer | ||||||||||||||
| 9E96 | .hex_expand←1← 9E91 BPL | ||||||||||||||
| LDX #0 ; Expand 4 bytes into 8 nibbles | |||||||||||||||
| 9E98 | LDY #0 ; byte index = 0 | ||||||||||||||
| 9E9A | .hex_expand_loop←1← 9EAE BNE | ||||||||||||||
| LDA zp_iwa,y ; Byte | |||||||||||||||
| 9E9D | PHA ; save it | ||||||||||||||
| 9E9E | AND #&0f ; low nibble | ||||||||||||||
| 9EA0 | STA zp_fwb_m2,x ; store it | ||||||||||||||
| 9EA2 | PLA ; high nibble | ||||||||||||||
| 9EA3 | LSR ; shift the high nibble down, | ||||||||||||||
| 9EA4 | LSR ; (continued) | ||||||||||||||
| 9EA5 | LSR ; (continued) | ||||||||||||||
| 9EA6 | LSR ; (continued) | ||||||||||||||
| 9EA7 | INX ; next nibble slot | ||||||||||||||
| 9EA8 | STA zp_fwb_m2,x ; store it | ||||||||||||||
| 9EAA | INX ; next nibble slot | ||||||||||||||
| 9EAB | INY ; next byte | ||||||||||||||
| 9EAC | CPY #4 ; all four bytes? | ||||||||||||||
| 9EAE | BNE hex_expand_loop ; no: continue | ||||||||||||||
| 9EB0 | .hex_skip_zeros←1← 9EB5 BEQ | ||||||||||||||
| DEX ; Skip leading zero nibbles | |||||||||||||||
| 9EB1 | BEQ hex_digit_loop ; all zero: output one zero | ||||||||||||||
| 9EB3 | LDA zp_fwb_m2,x ; this nibble zero? | ||||||||||||||
| 9EB5 | BEQ hex_skip_zeros ; yes: skip it | ||||||||||||||
| 9EB7 | .hex_digit_loop←2← 9EB1 BEQ← 9EC5 BPL | ||||||||||||||
| LDA zp_fwb_m2,x ; Next nibble | |||||||||||||||
| 9EB9 | CMP #&0a ; above 9? | ||||||||||||||
| 9EBB | BCC hex_to_ascii ; no | ||||||||||||||
| 9EBD | ADC #6 ; adjust for A-F | ||||||||||||||
| 9EBF | .hex_to_ascii←1← 9EBB BCC | ||||||||||||||
| ADC #'0' ; to ASCII | |||||||||||||||
| 9EC1 | JSR output_char ; output the digit | ||||||||||||||
| 9EC4 | DEX ; next | ||||||||||||||
| 9EC5 | BPL hex_digit_loop ; loop | ||||||||||||||
| 9EC7 | RTS ; Return | ||||||||||||||
| 9EC8 | .num_sign←1← 9F12 BNE | ||||||||||||||
| BPL num_normalize_loop ; positive? | |||||||||||||||
| 9ECA | LDA #'-' ; negative: output '-' | ||||||||||||||
| 9ECC | STA zp_fwa_sign ; also clears the sign bit (bit 7 = 0) | ||||||||||||||
| 9ECE | JSR output_char ; print it | ||||||||||||||
| 9ED1 | .num_normalize_loop←3← 9EC8 BPL← 9EDC JMP← 9F36 JMP | ||||||||||||||
| LDA zp_fwa_exp ; Exponent | |||||||||||||||
| 9ED3 | CMP #&81 ; >= 1? | ||||||||||||||
| 9ED5 | BCS nta_check_mag ; yes: output the integer part | ||||||||||||||
| 9ED7 | JSR fwa_mul10 ; < 1: multiply by 10 | ||||||||||||||
| 9EDA | DEC zp_dec_exp ; decrement the decimal exponent | ||||||||||||||
| 9EDC | JMP num_normalize_loop ; loop | ||||||||||||||
Convert the current value to an ASCII numberConvert the integer (IWA) or real (FWA) value to an ASCII string in the string work area, in decimal or hex per the radix flag and the @% print format. Underlies PRINT and STR$.
|
|||||||||||||
| 9EDF | .number_to_ascii←2← 8DFB JSR← B0B9 JSR | ||||||||||||
| LDX resint_at_2 ; Get the @% format byte | |||||||||||||
| 9EE2 | CPX #3 ; valid (< 3)? | ||||||||||||
| 9EE4 | BCC nta_store_format ; yes: use it | ||||||||||||
| 9EE6 | LDX #0 ; invalid: use General format | ||||||||||||
| 9EE8 | .nta_store_format←1← 9EE4 BCC | ||||||||||||
| STX zp_general ; store the format type | |||||||||||||
| 9EEA | LDA resint_at_1 ; digit count from @% | ||||||||||||
| 9EED | BEQ nta_check_fixed ; zero: check the format | ||||||||||||
| 9EEF | CMP #&0a ; >= 10 digits? | ||||||||||||
| 9EF1 | BCS nta_default_digits ; yes: cap at 10 | ||||||||||||
| 9EF3 | BCC nta_store_count ; use the specified count | ||||||||||||
| 9EF5 | .nta_check_fixed←1← 9EED BEQ | ||||||||||||
| CPX #2 ; fixed format? | |||||||||||||
| 9EF7 | BEQ nta_store_count ; yes: zero digits | ||||||||||||
| 9EF9 | .nta_default_digits←2← 9EF1 BCS← B0B3 JSR | ||||||||||||
| LDA #&0a ; default to 10 digits | |||||||||||||
| 9EFB | .nta_store_count←2← 9EF3 BCC← 9EF7 BEQ | ||||||||||||
| STA zp_general_1 ; store the digit count | |||||||||||||
| 9EFD | STA zp_coeff_ptr_1 ; (copy) | ||||||||||||
| 9EFF | LDA #0 ; output length = 0... | ||||||||||||
| 9F01 | STA zp_strbuf_len ; (length = 0) | ||||||||||||
| 9F03 | STA zp_dec_exp ; decimal exponent = 0 (&49) | ||||||||||||
| 9F05 | BIT zp_print_flag ; hex mode (radix flag bit 7)? | ||||||||||||
| 9F07 | BMI hex_convert ; yes: hex conversion | ||||||||||||
| 9F09 | TYA ; an integer value? | ||||||||||||
| 9F0A | BMI nta_sign ; already a real | ||||||||||||
| 9F0C | JSR int_to_fwa ; convert the integer to a real | ||||||||||||
| 9F0F | .nta_sign←1← 9F0A BMI | ||||||||||||
| JSR fwa_sign ; sign of the value | |||||||||||||
| 9F12 | BNE num_sign ; non-zero: format it | ||||||||||||
| 9F14 | LDA zp_general ; zero, not General format? | ||||||||||||
| 9F16 | BNE nta_output_zero ; fixed/exponential zero | ||||||||||||
| 9F18 | LDA #'0' ; output a single '0' | ||||||||||||
| 9F1A | JMP output_char ; ...and return | ||||||||||||
| 9F1D | .nta_output_zero←1← 9F16 BNE | ||||||||||||
| JMP nta_check_fixed2 ; output zero in fixed/exp format | |||||||||||||
| 9F20 | .nta_set_one←1← 9F96 BCS | ||||||||||||
| JSR fwa_set_one ; FWA = 1.0 | |||||||||||||
| 9F23 | BNE nta_count_up ; always taken (count a place) | ||||||||||||
| 9F25 | .nta_check_mag←1← 9ED5 BCS | ||||||||||||
| CMP #&84 ; exponent < 4 (value < 10)? | |||||||||||||
| 9F27 | BCC nta_save_temp1 ; yes: ready to convert | ||||||||||||
| 9F29 | BNE nta_div10 ; exponent != 4: too big, divide | ||||||||||||
| 9F2B | LDA zp_fwa_m1 ; mantissa top byte | ||||||||||||
| 9F2D | CMP #&a0 ; less than &A0 (value < 10)? | ||||||||||||
| 9F2F | BCC nta_save_temp1 ; yes: ready to convert | ||||||||||||
| 9F31 | .nta_div10←1← 9F29 BNE | ||||||||||||
| JSR fwa_div10 ; FWA = FWA / 10 | |||||||||||||
| 9F34 | .nta_count_up←1← 9F23 BNE | ||||||||||||
| INC zp_dec_exp ; count one decimal place up | |||||||||||||
| 9F36 | JMP num_normalize_loop ; check the magnitude again | ||||||||||||
| 9F39 | .nta_save_temp1←2← 9F27 BCC← 9F2F BCC | ||||||||||||
| LDA zp_fwa_rnd ; Save FWA in TEMP1 (a fraction in [1,10)): | |||||||||||||
| 9F3B | STA zp_var_type ; stash the rounding byte, | ||||||||||||
| 9F3D | JSR fwa_pack_temp1 ; pack the mantissa | ||||||||||||
| 9F40 | LDA zp_coeff_ptr_1 ; digit count | ||||||||||||
| 9F42 | STA zp_general_1 ; (store) | ||||||||||||
| 9F44 | LDX zp_general ; print format | ||||||||||||
| 9F46 | CPX #2 ; not fixed format? | ||||||||||||
| 9F48 | BNE nta_round_const ; do exponent/general | ||||||||||||
| 9F4A | ADC zp_dec_exp ; fixed: digits + decimal exponent | ||||||||||||
| 9F4C | BMI nta_zero ; negative: round to zero | ||||||||||||
| 9F4E | STA zp_general_1 ; (store the digit count) | ||||||||||||
| 9F50 | CMP #&0b ; > 10? | ||||||||||||
| 9F52 | BCC nta_round_const ; no | ||||||||||||
| 9F54 | LDA #&0a ; cap at 10 | ||||||||||||
| 9F56 | STA zp_general_1 ; (store) | ||||||||||||
| 9F58 | LDA #0 ; switch to General | ||||||||||||
| 9F5A | STA zp_general ; (store) | ||||||||||||
| 9F5C | .nta_round_const←2← 9F48 BNE← 9F52 BCC | ||||||||||||
| JSR fwa_clear ; Build a rounding constant 0.5e-n: | |||||||||||||
| 9F5F | LDA #&a0 ; mantissa = &A0... | ||||||||||||
| 9F61 | STA zp_fwa_m1 ; (MSB) | ||||||||||||
| 9F63 | LDA #&83 ; exponent = &83 (0.5), | ||||||||||||
| 9F65 | STA zp_fwa_exp ; (store) | ||||||||||||
| 9F67 | LDX zp_general_1 ; shift it down by the digit count: | ||||||||||||
| 9F69 | BEQ nta_point_temp1 ; no shift needed | ||||||||||||
| 9F6B | .nta_round_loop←1← 9F6F BNE | ||||||||||||
| JSR fwa_div10 ; rounding /= 10 | |||||||||||||
| 9F6E | DEX ; count | ||||||||||||
| 9F6F | BNE nta_round_loop ; loop | ||||||||||||
| 9F71 | .nta_point_temp1←1← 9F69 BEQ | ||||||||||||
| JSR point_fp_temp1 ; point at the saved value (TEMP1) | |||||||||||||
| 9F74 | JSR fwb_unpack_var ; FWB = the value | ||||||||||||
| 9F77 | LDA zp_var_type ; the saved rnd byte... | ||||||||||||
| 9F79 | STA zp_fwb_rnd ; (into FWB) | ||||||||||||
| 9F7B | JSR fwa_add_fwb_raw ; add the rounding constant | ||||||||||||
| 9F7E | .nta_renorm_loop←1← 9F90 BNE | ||||||||||||
| LDA zp_fwa_exp ; Re-normalise to [1,10): exponent | |||||||||||||
| 9F80 | CMP #&84 ; < 4? | ||||||||||||
| 9F82 | BCS nta_renorm_mant ; in range | ||||||||||||
| 9F84 | ROR zp_fwa_m1 ; shift the mantissa right: | ||||||||||||
| 9F86 | ROR zp_fwa_m2 ; m2, | ||||||||||||
| 9F88 | ROR zp_fwa_m3 ; m3, | ||||||||||||
| 9F8A | ROR zp_fwa_m4 ; m4, | ||||||||||||
| 9F8C | ROR zp_fwa_rnd ; rnd | ||||||||||||
| 9F8E | INC zp_fwa_exp ; and bump the exponent | ||||||||||||
| 9F90 | BNE nta_renorm_loop ; loop | ||||||||||||
| 9F92 | .nta_renorm_mant←1← 9F82 BCS | ||||||||||||
| LDA zp_fwa_m1 ; mantissa top byte | |||||||||||||
| 9F94 | CMP #&a0 ; >= 10 after rounding? | ||||||||||||
| 9F96 | BCS nta_set_one ; yes: re-divide | ||||||||||||
| 9F98 | LDA zp_general_1 ; digit count | ||||||||||||
| 9F9A | BNE nta_check_general ; non-zero | ||||||||||||
| 9F9C | .nta_check_fixed2←1← 9F1D JMP | ||||||||||||
| CMP #1 ; fixed format? | |||||||||||||
| 9F9E | BEQ nta_digit_pos ; output the value | ||||||||||||
| 9FA0 | .nta_zero←1← 9F4C BMI | ||||||||||||
| JSR fwa_clear ; Clear FWA (zero / underflow): | |||||||||||||
| 9FA3 | LDA #0 ; 0... | ||||||||||||
| 9FA5 | STA zp_dec_exp ; decimal exponent = 0, | ||||||||||||
| 9FA7 | LDA zp_coeff_ptr_1 ; original digit count... | ||||||||||||
| 9FA9 | STA zp_general_1 ; (store) | ||||||||||||
| 9FAB | INC zp_general_1 ; plus one | ||||||||||||
| 9FAD | .nta_check_general←1← 9F9A BNE | ||||||||||||
| LDA #1 ; General format? | |||||||||||||
| 9FAF | CMP zp_general ; is the format General (1)? | ||||||||||||
| 9FB1 | BEQ nta_digit_pos ; output the value | ||||||||||||
| 9FB3 | LDY zp_dec_exp ; decimal exponent | ||||||||||||
| 9FB5 | BMI nta_check_fixed3 ; negative: leading zeros | ||||||||||||
| 9FB7 | CPY zp_general_1 ; within the digit count? | ||||||||||||
| 9FB9 | BCS nta_digit_pos ; no: use E-notation | ||||||||||||
| 9FBB | LDA #0 ; within range: clear the exponent, | ||||||||||||
| 9FBD | STA zp_dec_exp ; (store) | ||||||||||||
| 9FBF | INY ; one more digit | ||||||||||||
| 9FC0 | TYA ; output the value | ||||||||||||
| 9FC1 | BNE nta_digit_pos ; output the value | ||||||||||||
| 9FC3 | .nta_check_fixed3←1← 9FB5 BMI | ||||||||||||
| LDA zp_general ; fixed format? | |||||||||||||
| 9FC5 | CMP #2 ; fixed format (2)? | ||||||||||||
| 9FC7 | BEQ nta_leading_zero ; yes | ||||||||||||
| 9FC9 | LDA #1 ; (General marker) | ||||||||||||
| 9FCB | CPY #&ff ; far below: use E-notation | ||||||||||||
| 9FCD | BNE nta_digit_pos ; not far below: output | ||||||||||||
| 9FCF | .nta_leading_zero←1← 9FC7 BEQ | ||||||||||||
| LDA #'0' ; leading '0' | |||||||||||||
| 9FD1 | JSR output_char ; emit it | ||||||||||||
| 9FD4 | LDA #'.' ; decimal '.' | ||||||||||||
| 9FD6 | JSR output_char ; emit it | ||||||||||||
| 9FD9 | LDA #'0' ; prepare '0' | ||||||||||||
| 9FDB | .nta_frac_zeros_loop←1← 9FE2 BNE | ||||||||||||
| INC zp_dec_exp ; leading zeros for the fraction: | |||||||||||||
| 9FDD | BEQ nta_all_digits ; exponent reached 0: done | ||||||||||||
| 9FDF | JSR output_char ; output a zero | ||||||||||||
| 9FE2 | BNE nta_frac_zeros_loop ; loop | ||||||||||||
| 9FE4 | .nta_all_digits←1← 9FDD BEQ | ||||||||||||
| LDA #&80 ; all digits (no point yet) | |||||||||||||
| 9FE6 | .nta_digit_pos←5← 9F9E BEQ← 9FB1 BEQ← 9FB9 BCS← 9FC1 BNE← 9FCD BNE | ||||||||||||
| STA zp_coeff_ptr_1 ; digit position counter | |||||||||||||
| 9FE8 | .nta_emit_loop←1← 9FF6 BNE | ||||||||||||
| JSR output_top_digit ; Emit each digit: | |||||||||||||
| 9FEB | DEC zp_coeff_ptr_1 ; at the decimal point? | ||||||||||||
| 9FED | BNE nta_more_digits ; no | ||||||||||||
| 9FEF | LDA #'.' ; emit '.' | ||||||||||||
| 9FF1 | JSR output_char ; emit it | ||||||||||||
| 9FF4 | .nta_more_digits←1← 9FED BNE | ||||||||||||
| DEC zp_general_1 ; more digits? | |||||||||||||
| 9FF6 | BNE nta_emit_loop ; loop | ||||||||||||
| 9FF8 | LDY zp_general ; General format: trim trailing zeros | ||||||||||||
| 9FFA | DEY ; general 1 (E)? | ||||||||||||
| 9FFB | BEQ nta_output_e ; yes: go to the exponent | ||||||||||||
| 9FFD | DEY ; general 2 (fixed)? | ||||||||||||
| 9FFE | BEQ nta_check_exp ; fixed: skip trimming | ||||||||||||
| A000 | LDY zp_strbuf_len ; scan back from the end: | ||||||||||||
| A002 | .nta_trim_loop←1← A008 BEQ | ||||||||||||
| DEY ; previous char | |||||||||||||
| A003 | LDA string_work,y ; a character | ||||||||||||
| A006 | CMP #'0' ; a '0'? | ||||||||||||
| A008 | BEQ nta_trim_loop ; yes: trim it | ||||||||||||
| A00A | CMP #'.' ; a '.'? | ||||||||||||
| A00C | BEQ nta_set_length ; trim it too | ||||||||||||
| A00E | INY ; keep this one | ||||||||||||
| A00F | .nta_set_length←1← A00C BEQ | ||||||||||||
| STY zp_strbuf_len ; set the trimmed length | |||||||||||||
| A011 | .nta_check_exp←1← 9FFE BEQ | ||||||||||||
| LDA zp_dec_exp ; a decimal exponent to print? | |||||||||||||
| A013 | BEQ return_19 ; no: done | ||||||||||||
| A015 | .nta_output_e←1← 9FFB BEQ | ||||||||||||
| LDA #'E' ; output 'E' | |||||||||||||
| A017 | JSR output_char ; emit it | ||||||||||||
| A01A | LDA zp_dec_exp ; the exponent | ||||||||||||
| A01C | BPL nta_output_exp ; positive | ||||||||||||
| A01E | LDA #'-' ; negative: output '-' | ||||||||||||
| A020 | JSR output_char ; emit it | ||||||||||||
| A023 | SEC ; negate the exponent | ||||||||||||
| A024 | LDA #0 ; 0... | ||||||||||||
| A026 | SBC zp_dec_exp ; minus the exponent | ||||||||||||
| A028 | .nta_output_exp←1← A01C BPL | ||||||||||||
| JSR output_byte_decimal ; output the exponent in decimal | |||||||||||||
| A02B | LDA zp_general ; General format? | ||||||||||||
| A02D | BEQ return_19 ; done | ||||||||||||
| A02F | LDA #' ' ; pad: a space | ||||||||||||
| A031 | LDY zp_dec_exp ; check the exponent sign | ||||||||||||
| A033 | BMI nta_field_pad ; negative: no pad | ||||||||||||
| A035 | JSR output_char ; output it | ||||||||||||
| A038 | .nta_field_pad←1← A033 BMI | ||||||||||||
| CPX #0 ; any field width left? | |||||||||||||
| A03A | BNE return_19 ; done | ||||||||||||
| A03C | JMP output_char ; output a final space | ||||||||||||
| A03F | .return_19←3← A013 BEQ← A02D BEQ← A03A BNE | ||||||||||||
| RTS ; Return | |||||||||||||
Output the leading decimal digit of FWAEmit the integer part (top nibble of the mantissa MSB) as a decimal digit, mask it off, then multiply the remaining fraction by 10 ready for the next digit. The inner step of the real-to-ASCII conversion.
|
|||||||||||
| A040 | .output_top_digit←1← 9FE8 JSR | ||||||||||
| LDA zp_fwa_m1 ; Integer part: top nibble | |||||||||||
| A042 | LSR ; shift the top nibble down, | ||||||||||
| A043 | LSR ; (continued) | ||||||||||
| A044 | LSR ; (continued) | ||||||||||
| A045 | LSR ; (continued) | ||||||||||
| A046 | JSR output_digit ; output it as a digit | ||||||||||
| A049 | LDA zp_fwa_m1 ; mask off the integer part: | ||||||||||
| A04B | AND #&0f ; keep the low nibble | ||||||||||
| A04D | STA zp_fwa_m1 ; (store) | ||||||||||
| A04F | JMP mant_mul10 ; multiply the fraction by 10 | ||||||||||
Output a byte (0-99) in decimalAppend a byte 0-99 to the output string as one or two decimal digits (a leading-zero tens digit is dropped) by repeated subtraction of ten.
|
|||||||||||
| A052 | .output_byte_decimal←1← A028 JSR | ||||||||||
| LDX #&ff ; count the tens: | |||||||||||
| A054 | SEC ; ready the subtract | ||||||||||
| A055 | .obd_tens_loop←1← A058 BCS | ||||||||||
| INX ; subtract 10... | |||||||||||
| A056 | SBC #&0a ; minus 10 | ||||||||||
| A058 | BCS obd_tens_loop ; until it goes negative | ||||||||||
| A05A | ADC #&0a ; add 10 back (the units) | ||||||||||
| A05C | PHA ; save the units | ||||||||||
| A05D | TXA ; the tens digit | ||||||||||
| A05E | BEQ obd_units ; no tens: skip | ||||||||||
| A060 | JSR output_digit ; output the tens digit | ||||||||||
| A063 | .obd_units←1← A05E BEQ | ||||||||||
| PLA ; units digit | |||||||||||
| fall through ↓ | |||||||||||
Output A as a decimal digit (A + "0")Convert the digit value in A to ASCII ("0" + A) and append it via output_char.
|
|||||||||||
| A064 | .output_digit←2← A046 JSR← A060 JSR | ||||||||||
| ORA #'0' ; make it a digit ("0" + A) | |||||||||||
| fall through ↓ | |||||||||||
Append a character to the output stringAppend the character in A to the end of the output string buffer and bump its length.
|
|||||||||||||
| A066 | .output_char←11← 9EC1 JSR← 9ECE JSR← 9F1A JMP← 9FD1 JSR← 9FD6 JSR← 9FDF JSR← 9FF1 JSR← A017 JSR← A020 JSR← A035 JSR← A03C JMP | ||||||||||||
| STX zp_fwb_sign ; save X | |||||||||||||
| A068 | LDX zp_strbuf_len ; append at the end of the buffer | ||||||||||||
| A06A | STA string_work,x ; write it | ||||||||||||
| A06D | LDX zp_fwb_sign ; restore X | ||||||||||||
| A06F | INC zp_strbuf_len ; one longer | ||||||||||||
| A071 | RTS ; Return | ||||||||||||
| A072 | .make_real_result←2← A091 BCS← A095 BMI | ||||||||||||
| CLC ; set the rounding byte and test the sign | |||||||||||||
| A073 | STX zp_fwa_rnd ; (rnd = 0) | ||||||||||||
| A075 | JSR fwa_sign ; test the sign | ||||||||||||
| A078 | LDA #&ff ; real result | ||||||||||||
| A07A | RTS ; Return | ||||||||||||
Parse an unsigned number at PtrBParse an unsigned decimal number at PtrB into the accumulator: digits, a "." and an "E" exponent, choosing integer or real form (a decimal point or exponent forces real). Decimal only - there is no "&" hex path here; "&" constants are read separately by
|
|||||||||||
| A07B | .parse_number←3← AC60 JSR← AC6B JSR← AE2A JSR | ||||||||||
| LDX #0 ; Clear FWA: | |||||||||||
| A07D | STX zp_fwa_m1 ; mantissa byte 1 (top), | ||||||||||
| A07F | STX zp_fwa_m2 ; byte 2, | ||||||||||
| A081 | STX zp_fwa_m3 ; byte 3, | ||||||||||
| A083 | STX zp_fwa_m4 ; byte 4, | ||||||||||
| A085 | STX zp_fwa_rnd ; and the guard byte | ||||||||||
| A087 | STX zp_dp_flag ; clear the decimal-point flag | ||||||||||
| A089 | STX zp_dec_exp ; decimal exponent = 0 | ||||||||||
| A08B | CMP #'.' ; a leading decimal point? | ||||||||||
| A08D | BEQ pn_dup_point ; yes | ||||||||||
| A08F | CMP #':' ; not a digit (>= ':')? | ||||||||||
| A091 | BCS make_real_result ; finish | ||||||||||
| A093 | SBC #&2f ; convert to binary 0-9 | ||||||||||
| A095 | BMI make_real_result ; not a digit: finish | ||||||||||
| A097 | STA zp_fwa_rnd ; store the digit | ||||||||||
| A099 | .pn_loop←8← A0A6 BNE← A0BC BNE← A0C0 BCS← A0CF BCC← A0D3 BNE← A0D7 BNE← A0DB BNE← A0DF BNE | ||||||||||
| INY ; next character | |||||||||||
| A09A | LDA (zp_text_ptr2),y ; read it | ||||||||||
| A09C | CMP #'.' ; a decimal point? | ||||||||||
| A09E | BNE pn_check_e ; no | ||||||||||
| A0A0 | .pn_dup_point←1← A08D BEQ | ||||||||||
| LDA zp_dp_flag ; already had one? | |||||||||||
| A0A2 | BNE pn_store_offset ; yes: end of the number | ||||||||||
| A0A4 | INC zp_dp_flag ; set the decimal-point flag | ||||||||||
| A0A6 | BNE pn_loop ; next char | ||||||||||
| A0A8 | .pn_check_e←1← A09E BNE | ||||||||||
| CMP #'E' ; 'E' (exponent)? | |||||||||||
| A0AA | BEQ pn_scan_e ; yes: scan the exponent | ||||||||||
| A0AC | CMP #':' ; not a digit? | ||||||||||
| A0AE | BCS pn_store_offset ; finish | ||||||||||
| A0B0 | SBC #&2f ; convert to binary | ||||||||||
| A0B2 | BCC pn_store_offset ; not a digit: finish | ||||||||||
| A0B4 | LDX zp_fwa_m1 ; mantissa top byte | ||||||||||
| A0B6 | CPX #&18 ; room for another digit? | ||||||||||
| A0B8 | BCC pn_check_point ; yes: add it | ||||||||||
| A0BA | LDX zp_dp_flag ; too big: had a decimal point? | ||||||||||
| A0BC | BNE pn_loop ; yes: just skip the digit | ||||||||||
| A0BE | INC zp_dec_exp ; no: bump the exponent and skip | ||||||||||
| A0C0 | BCS pn_loop ; skip this over-large digit | ||||||||||
| A0C2 | .pn_check_point←1← A0B8 BCC | ||||||||||
| LDX zp_dp_flag ; had a decimal point? | |||||||||||
| A0C4 | BEQ pn_mant_x10 ; no | ||||||||||
| A0C6 | DEC zp_dec_exp ; yes: decrement the exponent | ||||||||||
| A0C8 | .pn_mant_x10←1← A0C4 BEQ | ||||||||||
| JSR mant_mul10 ; FWA mantissa *= 10 | |||||||||||
| A0CB | ADC zp_fwa_rnd ; add the digit to the low byte | ||||||||||
| A0CD | STA zp_fwa_rnd ; store the new low mantissa byte | ||||||||||
| A0CF | BCC pn_loop ; no carry: next digit | ||||||||||
| A0D1 | INC zp_fwa_m4 ; carry up through the mantissa | ||||||||||
| A0D3 | BNE pn_loop ; absorbed in byte 4: next digit | ||||||||||
| A0D5 | INC zp_fwa_m3 ; wrapped: carry into byte 3, | ||||||||||
| A0D7 | BNE pn_loop ; absorbed: next digit | ||||||||||
| A0D9 | INC zp_fwa_m2 ; byte 2, | ||||||||||
| A0DB | BNE pn_loop ; absorbed: next digit | ||||||||||
| A0DD | INC zp_fwa_m1 ; byte 1 (top) | ||||||||||
| A0DF | BNE pn_loop ; next digit | ||||||||||
| A0E1 | .pn_scan_e←1← A0AA BEQ | ||||||||||
| JSR parse_exponent ; scan the E exponent | |||||||||||
| A0E4 | ADC zp_dec_exp ; add to the decimal exponent | ||||||||||
| A0E6 | STA zp_dec_exp ; store it back | ||||||||||
| A0E8 | .pn_store_offset←3← A0A2 BNE← A0AE BCS← A0B2 BCC | ||||||||||
| STY zp_text_ptr2_off ; store the text offset | |||||||||||
| A0EA | LDA zp_dec_exp ; any exponent or decimal point? | ||||||||||
| A0EC | ORA zp_dp_flag ; combine with the decimal-point flag | ||||||||||
| A0EE | BEQ pn_check_int ; no: return an integer | ||||||||||
| A0F0 | JSR fwa_sign ; value zero? | ||||||||||
| A0F3 | BEQ pn_real_result ; yes: done | ||||||||||
| A0F5 | .pn_set_exp_loop←1← A127 BNE | ||||||||||
| LDA #&a8 ; Set the FWA exponent (40-bit mantissa)... | |||||||||||
| A0F7 | STA zp_fwa_exp ; store the exponent | ||||||||||
| A0F9 | LDA #0 ; zero for overflow and sign | ||||||||||
| A0FB | STA zp_fwa_ovf ; clear overflow | ||||||||||
| A0FD | STA zp_fwa_sign ; clear sign | ||||||||||
| A0FF | JSR fwa_normalise ; normalise | ||||||||||
| A102 | LDA zp_dec_exp ; apply the decimal exponent: | ||||||||||
| A104 | BMI pn_exp_div ; negative: divide | ||||||||||
| A106 | BEQ pn_round ; zero: done | ||||||||||
| A108 | .pn_exp_mul_loop←1← A10D BNE | ||||||||||
| JSR fwa_mul10 ; positive: multiply by 10 | |||||||||||
| A10B | DEC zp_dec_exp ; one fewer power of ten to apply | ||||||||||
| A10D | BNE pn_exp_mul_loop ; loop | ||||||||||
| A10F | BEQ pn_round ; done | ||||||||||
| A111 | .pn_exp_div←2← A104 BMI← A116 BNE | ||||||||||
| JSR fwa_div10 ; divide by 10 | |||||||||||
| A114 | INC zp_dec_exp ; count the exponent up toward zero | ||||||||||
| A116 | BNE pn_exp_div ; loop | ||||||||||
| A118 | .pn_round←2← A106 BEQ← A10F BEQ | ||||||||||
| JSR fwa_round ; round the result | |||||||||||
| A11B | .pn_real_result←1← A0F3 BEQ | ||||||||||
| SEC ; real result | |||||||||||
| A11C | LDA #&ff ; A = &FF: real result | ||||||||||
| A11E | RTS ; Return (real) | ||||||||||
| A11F | .pn_check_int←1← A0EE BEQ | ||||||||||
| LDA zp_fwa_m2 ; Integer: does it fit in 32 signed bits? | |||||||||||
| A121 | STA zp_iwa_3 ; stash byte 2 as the IWA top byte | ||||||||||
| A123 | AND #&80 ; isolate its sign bit | ||||||||||
| A125 | ORA zp_fwa_m1 ; top byte set (too big)? | ||||||||||
| A127 | BNE pn_set_exp_loop ; yes: use a real instead | ||||||||||
| A129 | LDA zp_fwa_rnd ; Copy the mantissa to IWA: | ||||||||||
| A12B | STA zp_iwa ; guard byte -> IWA low, | ||||||||||
| A12D | LDA zp_fwa_m4 ; byte 4 | ||||||||||
| A12F | STA zp_iwa_1 ; -> IWA byte 1, | ||||||||||
| A131 | LDA zp_fwa_m3 ; byte 3 | ||||||||||
| A133 | STA zp_iwa_2 ; -> IWA byte 2 | ||||||||||
| A135 | LDA #&40 ; integer result | ||||||||||
| A137 | SEC ; carry set: a valid number | ||||||||||
| A138 | RTS ; Return (integer) | ||||||||||
| A139 | .pn_neg_exp_loop←1← A145 BEQ | ||||||||||
| JSR pe_skip_sign ; negative exponent: scan the digits | |||||||||||
| A13C | EOR #&ff ; negate it | ||||||||||
| A13E | SEC ; carry so caller adc completes the negate | ||||||||||
| A13F | RTS ; Return | ||||||||||
Parse the "E" exponent (optional sign, 1-2 digits)Read the one- or two-digit decimal exponent after "E" at PtrB, returning its magnitude in A (0 if no digits). The sign is handled on a separate entry path; the caller adds the result to the FWA exponent.
|
|||||||||||||
| A140 | .parse_exponent←1← A0E1 JSR | ||||||||||||
| INY ; Scan exponent: next character | |||||||||||||
| A141 | LDA (zp_text_ptr2),y ; read it | ||||||||||||
| A143 | CMP #'-' ; '-'? | ||||||||||||
| A145 | BEQ pn_neg_exp_loop ; yes: negative exponent | ||||||||||||
| A147 | CMP #'+' ; '+'? | ||||||||||||
| A149 | BNE pe_digit ; no sign | ||||||||||||
| A14B | .pe_skip_sign←1← A139 JSR | ||||||||||||
| INY ; skip the sign | |||||||||||||
| A14C | LDA (zp_text_ptr2),y ; read the digit after the sign | ||||||||||||
| A14E | .pe_digit←1← A149 BNE | ||||||||||||
| CMP #':' ; a digit? | |||||||||||||
| A150 | BCS pe_no_exp ; no: exponent = 0 | ||||||||||||
| A152 | SBC #&2f ; convert | ||||||||||||
| A154 | BCC pe_no_exp ; not a digit: exponent = 0 | ||||||||||||
| A156 | STA zp_int_exp ; store the first exponent digit | ||||||||||||
| A158 | INY ; second digit? | ||||||||||||
| A159 | LDA (zp_text_ptr2),y ; read it | ||||||||||||
| A15B | CMP #':' ; above 9? | ||||||||||||
| A15D | BCS pe_one_digit ; one digit only | ||||||||||||
| A15F | SBC #&2f ; convert | ||||||||||||
| A161 | BCC pe_one_digit ; not a digit | ||||||||||||
| A163 | INY ; two digits: exp = d1*10 + d2 | ||||||||||||
| A164 | STA zp_fp_temp ; save d2 | ||||||||||||
| A166 | LDA zp_int_exp ; d1 | ||||||||||||
| A168 | ASL ; d1 * 10... | ||||||||||||
| A169 | ASL ; (d1 * 4) | ||||||||||||
| A16A | ADC zp_int_exp ; + d1 (now * 5) | ||||||||||||
| A16C | ASL ; * 2 (now * 10) | ||||||||||||
| A16D | ADC zp_fp_temp ; + d2 | ||||||||||||
| A16F | RTS ; Return the exponent | ||||||||||||
| A170 | .pe_one_digit←2← A15D BCS← A161 BCC | ||||||||||||
| LDA zp_int_exp ; 1-digit exponent | |||||||||||||
| A172 | CLC ; carry clear for the caller ADC | ||||||||||||
| A173 | RTS ; Return | ||||||||||||
| A174 | .pe_no_exp←2← A150 BCS← A154 BCC | ||||||||||||
| LDA #0 ; no exponent: 0 | |||||||||||||
| A176 | CLC ; carry clear for the caller ADC | ||||||||||||
| A177 | RTS ; Return | ||||||||||||
Add FWB into FWAAdd the FWB mantissa (rnd, m4-m1) into the FWA mantissa with a single carry chain. Mantissa-only: exponents must already be aligned by the caller. Used by multiply, *10 and /10.
|
|||||||||||||||||
| A178 | .fwa_acc_fwb←2← A208 JSR← A64F JSR | ||||||||||||||||
| LDA zp_fwa_rnd ; Add the mantissas: rounding byte | |||||||||||||||||
| A17A | ADC zp_fwb_rnd ; + FWB rounding | ||||||||||||||||
| A17C | STA zp_fwa_rnd ; (store) | ||||||||||||||||
| A17E | LDA zp_fwa_m4 ; m4 | ||||||||||||||||
| A180 | ADC zp_fwb_m4 ; + FWB m4 | ||||||||||||||||
| A182 | STA zp_fwa_m4 ; (store) | ||||||||||||||||
| A184 | LDA zp_fwa_m3 ; m3 | ||||||||||||||||
| A186 | ADC zp_fwb_m3 ; - FWB m3 | ||||||||||||||||
| A188 | STA zp_fwa_m3 ; (store) | ||||||||||||||||
| A18A | LDA zp_fwa_m2 ; m2 | ||||||||||||||||
| A18C | ADC zp_fwb_m2 ; - FWB m2 | ||||||||||||||||
| A18E | STA zp_fwa_m2 ; (store) | ||||||||||||||||
| A190 | LDA zp_fwa_m1 ; m1 | ||||||||||||||||
| A192 | ADC zp_fwb_m1 ; - FWB m1 | ||||||||||||||||
| A194 | STA zp_fwa_m1 ; (store) | ||||||||||||||||
| A196 | RTS ; Return (carry = overflow) | ||||||||||||||||
Multiply the FWA mantissa by 10Multiply the FWA mantissa (m1-m4 and the rounding byte) by ten as x4 + x1 = x5 then x2, leaving the exponent untouched. Used by the number<->ASCII conversions, which track the decimal point separately.
|
|||||||||||||||
| A197 | .mant_mul10←2← A04F JMP← A0C8 JSR | ||||||||||||||
| PHA ; Save A | |||||||||||||||
| A198 | LDX zp_fwa_m4 ; keep m4 in X | ||||||||||||||
| A19A | LDA zp_fwa_m1 ; save the mantissa (m1..m3): | ||||||||||||||
| A19C | PHA ; push m1, | ||||||||||||||
| A19D | LDA zp_fwa_m2 ; m2, | ||||||||||||||
| A19F | PHA ; push m2, | ||||||||||||||
| A1A0 | LDA zp_fwa_m3 ; m3, | ||||||||||||||
| A1A2 | PHA ; push m3 (m4 already in X) | ||||||||||||||
| A1A3 | LDA zp_fwa_rnd ; x2: shift the mantissa left | ||||||||||||||
| A1A5 | ASL ; shift the low byte left, | ||||||||||||||
| A1A6 | ROL zp_fwa_m4 ; carrying up through m4, | ||||||||||||||
| A1A8 | ROL zp_fwa_m3 ; m3, | ||||||||||||||
| A1AA | ROL zp_fwa_m2 ; m2, | ||||||||||||||
| A1AC | ROL zp_fwa_m1 ; m1 (mantissa now x2) | ||||||||||||||
| A1AE | ASL ; x2 again (now x4) | ||||||||||||||
| A1AF | ROL zp_fwa_m4 ; m4, | ||||||||||||||
| A1B1 | ROL zp_fwa_m3 ; m3, | ||||||||||||||
| A1B3 | ROL zp_fwa_m2 ; m2, | ||||||||||||||
| A1B5 | ROL zp_fwa_m1 ; m1 (now x4) | ||||||||||||||
| A1B7 | ADC zp_fwa_rnd ; add the saved original (x4 + x1 = x5): rnd | ||||||||||||||
| A1B9 | STA zp_fwa_rnd ; (store) | ||||||||||||||
| A1BB | TXA ; m4 | ||||||||||||||
| A1BC | ADC zp_fwa_m4 ; + original m4 (was in X) | ||||||||||||||
| A1BE | STA zp_fwa_m4 ; (store) | ||||||||||||||
| A1C0 | PLA ; m3 | ||||||||||||||
| A1C1 | ADC zp_fwa_m3 ; + original m3 (pulled) | ||||||||||||||
| A1C3 | STA zp_fwa_m3 ; (store) | ||||||||||||||
| A1C5 | PLA ; m2 | ||||||||||||||
| A1C6 | ADC zp_fwa_m2 ; + original m2 (pulled) | ||||||||||||||
| A1C8 | STA zp_fwa_m2 ; (store) | ||||||||||||||
| A1CA | PLA ; m1 | ||||||||||||||
| A1CB | ADC zp_fwa_m1 ; + original m1 -> kept in A | ||||||||||||||
| A1CD | ASL zp_fwa_rnd ; x2 (now x10): shift left | ||||||||||||||
| A1CF | ROL zp_fwa_m4 ; carrying up through m4, | ||||||||||||||
| A1D1 | ROL zp_fwa_m3 ; m3, | ||||||||||||||
| A1D3 | ROL zp_fwa_m2 ; m2, | ||||||||||||||
| A1D5 | ROL ; m1 (still in A): mantissa now x10 | ||||||||||||||
| A1D6 | STA zp_fwa_m1 ; store m1 | ||||||||||||||
| A1D8 | PLA ; restore A | ||||||||||||||
| A1D9 | RTS ; Return | ||||||||||||||
Get the sign of the FP accumulatorDetermine the sign of the floating-point accumulator by OR-ing the mantissa and rounding bytes (&31-&35) to test for zero, then reading the sign byte. Forces a clean zero (sign, exponent and overflow byte cleared) when the mantissa is empty.
|
|||||||||||||||
| A1DA | .fwa_sign←17← 9F0F JSR← A075 JSR← A0F0 JSR← A405 JSR← A48E JMP← A50B JSR← A606 JSR← A6AD JSR← A6E7 JSR← A7B7 JSR← A801 JSR← A8DD JSR← A8F0 JSR← A90A JSR← AB7F JSR← AD77 JSR← AD7E JSR | ||||||||||||||
| LDA zp_fwa_m1 ; OR the mantissa and rounding bytes to test for zero | |||||||||||||||
| A1DC | ORA zp_fwa_m2 ; (mantissa byte 2) | ||||||||||||||
| A1DE | ORA zp_fwa_m3 ; (mantissa byte 3) | ||||||||||||||
| A1E0 | ORA zp_fwa_m4 ; (mantissa byte 4) | ||||||||||||||
| A1E2 | ORA zp_fwa_rnd ; (rounding) - a non-zero value is never all zero | ||||||||||||||
| A1E4 | BEQ sign_force_zero ; All zero: clean up and return zero | ||||||||||||||
| A1E6 | LDA zp_fwa_sign ; Non-zero: the sign is in bit 7 of the sign byte | ||||||||||||||
| A1E8 | BNE return_20 ; Bit 7 set: negative, return with A < 0 | ||||||||||||||
| A1EA | LDA #1 ; Otherwise positive: return A = +1 | ||||||||||||||
| A1EC | RTS ; A and the flags now give the sign | ||||||||||||||
| A1ED | .sign_force_zero←1← A1E4 BEQ | ||||||||||||||
| STA zp_fwa_sign ; Zero path: force a clean zero - sign, | |||||||||||||||
| A1EF | STA zp_fwa_exp ; exponent, | ||||||||||||||
| A1F1 | STA zp_fwa_ovf ; and overflow byte, then return A = 0 | ||||||||||||||
| A1F3 | .return_20←1← A1E8 BNE | ||||||||||||||
| RTS ; Return (shared) | |||||||||||||||
FWA = FWA * 10Multiply FWA by ten as x8 + x2: scale the exponent by eight, build x2 in FWB, and add. Left unnormalised and unrounded (the caller normalises). Uses FWB as scratch.
|
|||||||||
| A1F4 | .fwa_mul10←2← 9ED7 JSR← A108 JSR | ||||||||
| CLC ; x*8: add 3 to the exponent | |||||||||
| A1F5 | LDA zp_fwa_exp ; exponent... | ||||||||
| A1F7 | ADC #3 ; + 3 | ||||||||
| A1F9 | STA zp_fwa_exp ; (store) | ||||||||
| A1FB | BCC mul10_x8 ; no carry | ||||||||
| A1FD | INC zp_fwa_ovf ; carry into overflow | ||||||||
| A1FF | .mul10_x8←1← A1FB BCC | ||||||||
| JSR fwb_copy_from_fwa ; FWB = x*8 | |||||||||
| A202 | JSR fwb_div2 ; FWB = x*4 | ||||||||
| A205 | JSR fwb_div2 ; FWB = x*2 | ||||||||
| fall through ↓ | |||||||||
Add FWB into FWA with carry renormalisationAdd FWB into FWA via fwa_acc_fwb, then renormalise (fwa_carry_renorm): if the mantissa addition overflowed, shift FWA's mantissa right one bit and increment the exponent. Used repeatedly by the x10 / decimal-conversion routines to accumulate shifted terms into FWA.
|
|||||||||||
| A208 | .fwa_acc10←5← A25B JSR← A26A JSR← A284 JSR← A29C JSR← A5E0 JMP | ||||||||||
| JSR fwa_acc_fwb ; FWA = x8 + x2 = x*10 | |||||||||||
| A20B | .fwa_carry_renorm←1← A2BA JMP | ||||||||||
| BCC return_21 ; no overflow: done | |||||||||||
| A20D | ROR zp_fwa_m1 ; Overflow: shift right, bump exponent: m1 | ||||||||||
| A20F | ROR zp_fwa_m2 ; m2 | ||||||||||
| A211 | ROR zp_fwa_m3 ; m3 | ||||||||||
| A213 | ROR zp_fwa_m4 ; m4 | ||||||||||
| A215 | ROR zp_fwa_rnd ; rounding | ||||||||||
| A217 | INC zp_fwa_exp ; exponent + 1 | ||||||||||
| A219 | BNE return_21 ; done | ||||||||||
| A21B | INC zp_fwa_ovf ; exponent overflow | ||||||||||
| A21D | .return_21←2← A20B BCC← A219 BNE | ||||||||||
| RTS ; Return | |||||||||||
FWB = FWACopy all ten bytes of FWA into FWB.
|
|||||||||
| A21E | .fwb_copy_from_fwa←5← 9A44 JSR← A1FF JSR← A23F JSR← A3F8 JSR← A6B2 JSR | ||||||||
| LDA zp_fwa_sign ; Copy FWA's sign... | |||||||||
| A220 | STA zp_fwb_sign ; ...into FWB | ||||||||
| A222 | LDA zp_fwa_ovf ; Copy the overflow byte... | ||||||||
| A224 | STA zp_fwb_ovf ; ...into FWB | ||||||||
| A226 | LDA zp_fwa_exp ; Copy the exponent... | ||||||||
| A228 | STA zp_fwb_exp ; ...into FWB | ||||||||
| A22A | LDA zp_fwa_m1 ; Copy mantissa byte 1... | ||||||||
| A22C | STA zp_fwb_m1 ; ...into FWB | ||||||||
| A22E | LDA zp_fwa_m2 ; Copy mantissa byte 2... | ||||||||
| A230 | STA zp_fwb_m2 ; ...into FWB | ||||||||
| A232 | LDA zp_fwa_m3 ; Copy mantissa byte 3... | ||||||||
| A234 | STA zp_fwb_m3 ; ...into FWB | ||||||||
| A236 | LDA zp_fwa_m4 ; Copy mantissa byte 4... | ||||||||
| A238 | STA zp_fwb_m4 ; ...into FWB | ||||||||
| A23A | LDA zp_fwa_rnd ; Copy the rounding byte... | ||||||||
| A23C | STA zp_fwb_rnd ; ...into FWB | ||||||||
| A23E | RTS ; FWB is now a copy of FWA | ||||||||
FWB = FWA / 2Copy FWA into FWB (fwb_copy_from_fwa), then fall into fwb_div2 to shift the FWB mantissa (including the rounding byte) right one bit. The exponent is left unchanged, so the result is de-normalised; used to build the progressively shifted terms in fwa_div10.
|
|||||||||||
| A23F | .fwb_half_fwa←2← A258 JSR← A25E JSR | ||||||||||
| JSR fwb_copy_from_fwa ; FWB = FWA, then halve it | |||||||||||
| fall through ↓ | |||||||||||
Divide FWB by twoShift the FWB mantissa right one bit (FWB = FWB / 2). Leaves the exponent alone, so the result is left de-normalised; used to align exponents before adding.
|
|||||||||||
| A242 | .fwb_div2←5← A202 JSR← A205 JSR← A261 JSR← A264 JSR← A267 JSR | ||||||||||
| LSR zp_fwb_m1 ; Shift FWB right one bit (/2): mantissa MSB | |||||||||||
| A244 | ROR zp_fwb_m2 ; byte 2 | ||||||||||
| A246 | ROR zp_fwb_m3 ; byte 3 | ||||||||||
| A248 | ROR zp_fwb_m4 ; byte 4 | ||||||||||
| A24A | ROR zp_fwb_rnd ; rounding byte | ||||||||||
| A24C | RTS ; FWB halved | ||||||||||
FWA = FWA / 10Divide FWA by ten using the binary expansion of 1/10 (x/16 plus progressively shifted terms accumulated via FWB). Left unnormalised and unrounded (the caller normalises). Uses FWB as scratch.
|
|||||||||
| ; Divide FWA by ten. In binary 1/10 = 0.000110011001100..., | |||||||||
| ; so x/10 is x/16 plus a series of progressively shifted terms. | |||||||||
| ; Each term is built in FWB as a byte/bit-shifted copy of the | |||||||||
| ; mantissa and accumulated into FWA. The result is unnormalised | |||||||||
| ; and unrounded (the caller normalises). | |||||||||
| A24D | .fwa_div10←3← 9F31 JSR← 9F6B JSR← A111 JSR | ||||||||
| SEC ; x/16: subtract 4 from the exponent | |||||||||
| A24E | LDA zp_fwa_exp ; (exponent) | ||||||||
| A250 | SBC #4 ; (- 4) | ||||||||
| A252 | STA zp_fwa_exp ; (store) | ||||||||
| A254 | BCS div10_step ; no borrow: continue | ||||||||
| A256 | DEC zp_fwa_ovf ; borrow into the overflow byte | ||||||||
| A258 | .div10_step←1← A254 BCS | ||||||||
| JSR fwb_half_fwa ; FWB = x/2 | |||||||||
| A25B | JSR fwa_acc10 ; accumulate a shifted term into FWA | ||||||||
| A25E | JSR fwb_half_fwa ; FWB = x/2 again | ||||||||
| A261 | JSR fwb_div2 ; FWB /= 2 | ||||||||
| A264 | JSR fwb_div2 ; FWB /= 2 | ||||||||
| A267 | JSR fwb_div2 ; FWB /= 2 | ||||||||
| A26A | JSR fwa_acc10 ; accumulate the next term | ||||||||
| A26D | LDA #0 ; Form a byte-shifted copy in FWB: clear MSB | ||||||||
| A26F | STA zp_fwb_m1 ; (store) | ||||||||
| A271 | LDA zp_fwa_m1 ; mantissa m1... | ||||||||
| A273 | STA zp_fwb_m2 ; ...to FWB m2 | ||||||||
| A275 | LDA zp_fwa_m2 ; m2... | ||||||||
| A277 | STA zp_fwb_m3 ; ...to m3 | ||||||||
| A279 | LDA zp_fwa_m3 ; m3... | ||||||||
| A27B | STA zp_fwb_m4 ; ...to m4 | ||||||||
| A27D | LDA zp_fwa_m4 ; m4... | ||||||||
| A27F | STA zp_fwb_rnd ; ...to the rounding byte | ||||||||
| A281 | LDA zp_fwa_rnd ; next mantissa bit... | ||||||||
| A283 | ROL ; ...into the carry | ||||||||
| A284 | JSR fwa_acc10 ; accumulate this term | ||||||||
| A287 | LDA #0 ; Form a copy shifted down two bytes: clear | ||||||||
| A289 | STA zp_fwb_m1 ; the top two mantissa bytes | ||||||||
| A28B | STA zp_fwb_m2 ; (store) | ||||||||
| A28D | LDA zp_fwa_m1 ; m1... | ||||||||
| A28F | STA zp_fwb_m3 ; ...to m3 | ||||||||
| A291 | LDA zp_fwa_m2 ; m2... | ||||||||
| A293 | STA zp_fwb_m4 ; ...to m4 | ||||||||
| A295 | LDA zp_fwa_m3 ; m3... | ||||||||
| A297 | STA zp_fwb_rnd ; ...to rounding | ||||||||
| A299 | LDA zp_fwa_m4 ; next bit... | ||||||||
| A29B | ROL ; ...into the carry | ||||||||
| A29C | JSR fwa_acc10 ; accumulate this term | ||||||||
| A29F | LDA zp_fwa_m2 ; continue propagating the shifted mantissa bits | ||||||||
| A2A1 | ROL ; ...into the carry | ||||||||
| A2A2 | LDA zp_fwa_m1 ; next bit... | ||||||||
| fall through ↓ | |||||||||
Add to the rounding byte and ripple the carry upAdd A (plus the carry-in) to the FWA rounding byte, then propagate any carry up through the mantissa (m4 -> m1). A carry out of the top renormalises the exponent (shift right, exponent + 1) and may set the overflow byte. Used to round the mantissa up.
|
|||||||||||||||
| A2A4 | .fwa_round_carry←1← A666 JSR | ||||||||||||||
| ADC zp_fwa_rnd ; Add the round increment to the rounding byte | |||||||||||||||
| A2A6 | STA zp_fwa_rnd ; Store it back | ||||||||||||||
| A2A8 | BCC return_22 ; No carry out: done | ||||||||||||||
| A2AA | INC zp_fwa_m4 ; Carry: bump mantissa byte 4 | ||||||||||||||
| A2AC | BNE return_22 ; No further carry: done | ||||||||||||||
| A2AE | INC zp_fwa_m3 ; Ripple into byte 3 | ||||||||||||||
| A2B0 | BNE return_22 ; done if no carry | ||||||||||||||
| A2B2 | INC zp_fwa_m2 ; into byte 2 | ||||||||||||||
| A2B4 | BNE return_22 ; done if no carry | ||||||||||||||
| A2B6 | INC zp_fwa_m1 ; into byte 1 (the MSB) | ||||||||||||||
| A2B8 | BNE return_22 ; done if no carry | ||||||||||||||
| A2BA | JMP fwa_carry_renorm ; Carry out of the mantissa: renormalise (exponent up) | ||||||||||||||
| A2BD | .return_22←5← A2A8 BCC← A2AC BNE← A2B0 BNE← A2B4 BNE← A2B8 BNE | ||||||||||||||
| RTS ; Return (shared) | |||||||||||||||
Convert the integer accumulator to floating pointConvert the signed 32-bit integer in IWA to a normalised real in FWA: record the sign (negating IWA if needed), copy the magnitude into the mantissa with exponent 32, and normalise.
|
|||||||||||
| A2BE | .int_to_fwa←12← 9301 JMP← 9A41 JSR← 9C98 JSR← 9CAF JSR← 9CEE JSR← 9D02 JSR← 9D0E JSR← 9D17 JSR← 9D1D JSR← 9F0C JSR← AF24 JSR← B4E6 JSR | ||||||||||
| LDX #0 ; Clear the rounding... | |||||||||||
| A2C0 | STX zp_fwa_rnd ; (rnd = 0) | ||||||||||
| A2C2 | STX zp_fwa_ovf ; ...and overflow bytes | ||||||||||
| A2C4 | LDA zp_iwa_3 ; Sign of IWA (top byte) | ||||||||||
| A2C6 | BPL itf_store_sign ; positive: sign byte = 0 | ||||||||||
| A2C8 | JSR iwa_negate ; negative: make it positive... | ||||||||||
| A2CB | LDX #&ff ; ...and set the sign byte | ||||||||||
| A2CD | .itf_store_sign←1← A2C6 BPL | ||||||||||
| STX zp_fwa_sign ; (store the sign) | |||||||||||
| A2CF | LDA zp_iwa ; Copy IWA into the mantissa (MSB first): | ||||||||||
| A2D1 | STA zp_fwa_m4 ; byte 0 -> m4 | ||||||||||
| A2D3 | LDA zp_iwa_1 ; read it | ||||||||||
| A2D5 | STA zp_fwa_m3 ; byte 1 -> m3 | ||||||||||
| A2D7 | LDA zp_iwa_2 ; read it | ||||||||||
| A2D9 | STA zp_fwa_m2 ; byte 2 -> m2 | ||||||||||
| A2DB | LDA zp_iwa_3 ; read it | ||||||||||
| A2DD | STA zp_fwa_m1 ; byte 3 -> m1 (MSB) | ||||||||||
| A2DF | LDA #&a0 ; Exponent &A0 (= 32): a 32-bit integer | ||||||||||
| A2E1 | STA zp_fwa_exp ; (store) | ||||||||||
| A2E3 | JMP fwa_normalise ; normalise the result | ||||||||||
| A2E6 | .itf_zero←1← A30F BEQ | ||||||||||
| STA zp_fwa_sign ; Zero: clear sign, | |||||||||||
| A2E8 | STA zp_fwa_exp ; exponent, | ||||||||||
| A2EA | STA zp_fwa_ovf ; overflow | ||||||||||
| A2EC | .return_23←4← A2F2 BEQ← A305 BMI← A315 BMI← A338 BMI | ||||||||||
| RTS ; Return | |||||||||||
Convert a small (8-bit) integer in A to FWAConvert the signed 8-bit integer in A to a normalised real in FWA (clears FWA, places the magnitude in the mantissa MSB with exponent 8, sets the sign, and normalises).
|
|||||||
| A2ED | .small_int_to_fwa←1← A852 JSR | ||||||
| PHA ; Small int to FWA: save it | |||||||
| A2EE | JSR fwa_clear ; clear FWA | ||||||
| A2F1 | PLA ; recover it | ||||||
| A2F2 | BEQ return_23 ; zero: done | ||||||
| A2F4 | BPL si8_set_mantissa ; positive | ||||||
| A2F6 | STA zp_fwa_sign ; negative: set the sign... | ||||||
| A2F8 | LDA #0 ; 0... | ||||||
| A2FA | SEC ; minus the value: | ||||||
| A2FB | SBC zp_fwa_sign ; ...and negate the value | ||||||
| A2FD | .si8_set_mantissa←1← A2F4 BPL | ||||||
| STA zp_fwa_m1 ; value into the mantissa MSB | |||||||
| A2FF | LDA #&88 ; Exponent &88 (= 8): an 8-bit value | ||||||
| A301 | STA zp_fwa_exp ; (store; falls into normalise) | ||||||
| fall through ↓ | |||||||
Normalise FWAShift the FWA mantissa left until bit 7 of the MSB is set, decrementing the exponent by 8 per whole-byte shift and by 1 per bit, so the implied leading 1 is restored. An all-zero mantissa is forced to a clean zero. Underflow is handled via the overflow byte.
|
|||||||
| A303 | .fwa_normalise←8← A0FF JSR← A2E3 JMP← A4B3 JMP← A5DC JMP← A602 JMP← A659 JSR← AA0E JSR← AF33 JSR | ||||||
| LDA zp_fwa_m1 ; Mantissa MSB... | |||||||
| A305 | BMI return_23 ; Top bit already set: nothing to do | ||||||
| A307 | ORA zp_fwa_m2 ; OR in the lower mantissa bytes (byte 2) | ||||||
| A309 | ORA zp_fwa_m3 ; (byte 3) | ||||||
| A30B | ORA zp_fwa_m4 ; (byte 4) to test the whole mantissa | ||||||
| A30D | ORA zp_fwa_rnd ; Mantissa entirely zero: the value is zero | ||||||
| A30F | BEQ itf_zero ; so jump away to handle the zero value | ||||||
| A311 | LDA zp_fwa_exp ; Load the exponent to adjust as we shift | ||||||
| A313 | .norm_byte_loop←2← A330 BCS← A334 BCC | ||||||
| LDY zp_fwa_m1 ; Shift up a whole byte while the MSB byte is zero | |||||||
| A315 | BMI return_23 ; Bit 7 set: already normalised, return | ||||||
| A317 | BNE norm_bit_loop ; MSB byte non-zero but bit 7 clear: bit-shift | ||||||
| A319 | LDX zp_fwa_m2 ; Shift the mantissa up a byte: load m2 | ||||||
| A31B | STX zp_fwa_m1 ; store as m1 | ||||||
| A31D | LDX zp_fwa_m3 ; load m3 | ||||||
| A31F | STX zp_fwa_m2 ; store as m2 | ||||||
| A321 | LDX zp_fwa_m4 ; load m4 | ||||||
| A323 | STX zp_fwa_m3 ; store as m3 | ||||||
| A325 | LDX zp_fwa_rnd ; load the rounding byte | ||||||
| A327 | STX zp_fwa_m4 ; store as m4 | ||||||
| A329 | STY zp_fwa_rnd ; rounding <- 0 | ||||||
| A32B | SEC ; Prepare to reduce the exponent | ||||||
| A32C | SBC #8 ; each byte shift advances the exponent by 8 | ||||||
| A32E | STA zp_fwa_exp ; Store the reduced exponent | ||||||
| A330 | BCS norm_byte_loop ; Loop to shift another byte if MSB still zero | ||||||
| A332 | DEC zp_fwa_ovf ; Borrow into the overflow byte | ||||||
| A334 | BCC norm_byte_loop ; Continue the byte-shift loop | ||||||
| A336 | .norm_bit_check←2← A348 BCS← A34C BCC | ||||||
| LDY zp_fwa_m1 ; Bit-shift loop: re-check the MSB | |||||||
| A338 | BMI return_23 ; Bit 7 set: normalised, return | ||||||
| A33A | .norm_bit_loop←1← A317 BNE | ||||||
| ASL zp_fwa_rnd ; Then shift left one bit at a time to normalise | |||||||
| A33C | ROL zp_fwa_m4 ; Shift the mantissa left one bit: byte 4 | ||||||
| A33E | ROL zp_fwa_m3 ; byte 3 | ||||||
| A340 | ROL zp_fwa_m2 ; byte 2 | ||||||
| A342 | ROL zp_fwa_m1 ; byte 1 (MSB) | ||||||
| A344 | SBC #0 ; Reduce the exponent by one | ||||||
| A346 | STA zp_fwa_exp ; Store it | ||||||
| A348 | BCS norm_bit_check ; Loop until the MSB bit is set | ||||||
| A34A | DEC zp_fwa_ovf ; Borrow into the overflow byte | ||||||
| A34C | BCC norm_bit_check ; Continue the bit-shift loop | ||||||
| fall through ↓ | |||||||
Unpack a fp variable into FWBExpand the packed five-byte float addressed by zp_fp_ptr into the unpacked FWB accumulator: split the sign out of the mantissa MSB, restore the implied leading 1 (unless the value is zero), and clear the overflow and rounding bytes.
|
|||||||||
| A34E | .fwb_unpack_var←7← 9A5F JSR← 9F74 JSR← A4D6 JSR← A500 JSR← A60B JSR← A6EC JSR← A9DF JSR | ||||||||
| LDY #4 ; Copy the packed value, exponent last | |||||||||
| A350 | LDA (zp_fp_ptr),y ; Packed byte 4... | ||||||||
| A352 | STA zp_fwb_m4 ; ...mantissa byte 4 | ||||||||
| A354 | DEY ; next byte | ||||||||
| A355 | LDA (zp_fp_ptr),y ; byte 3... | ||||||||
| A357 | STA zp_fwb_m3 ; ...mantissa byte 3 | ||||||||
| A359 | DEY ; next byte | ||||||||
| A35A | LDA (zp_fp_ptr),y ; byte 2... | ||||||||
| A35C | STA zp_fwb_m2 ; ...mantissa byte 2 | ||||||||
| A35E | DEY ; next byte | ||||||||
| A35F | LDA (zp_fp_ptr),y ; byte 1 (sign + mantissa MSB)... | ||||||||
| A361 | STA zp_fwb_sign ; ...into the sign byte | ||||||||
| A363 | DEY ; next byte | ||||||||
| A364 | STY zp_fwb_rnd ; Clear the rounding byte (Y=0) | ||||||||
| A366 | STY zp_fwb_ovf ; and the overflow byte | ||||||||
| A368 | LDA (zp_fp_ptr),y ; byte 0... | ||||||||
| A36A | STA zp_fwb_exp ; ...is the exponent | ||||||||
| A36C | ORA zp_fwb_sign ; Test for zero: OR exponent with the mantissa... | ||||||||
| A36E | ORA zp_fwb_m2 ; m2, | ||||||||
| A370 | ORA zp_fwb_m3 ; m3, | ||||||||
| A372 | ORA zp_fwb_m4 ; m4 | ||||||||
| A374 | BEQ fwb_unpack_msb ; All zero: leave the mantissa MSB clear | ||||||||
| A376 | LDA zp_fwb_sign ; Non-zero: restore the implied leading 1... | ||||||||
| A378 | ORA #&80 ; set the top bit | ||||||||
| A37A | .fwb_unpack_msb←1← A374 BEQ | ||||||||
| STA zp_fwb_m1 ; Store the true mantissa MSB | |||||||||
| A37C | RTS ; FWB now holds the unpacked value | ||||||||
Pack FWA into TEMP2Point zp_fp_ptr at FP TEMP2 (&0471), then pack FWA into it via fwa_pack_var.
|
|||||||||||
| A37D | .fwa_pack_temp2←2← 9E6C JSR← AA11 JSR | ||||||||||
| LDA #&71 ; Point at FP TEMP2 (&0471): low byte | |||||||||||
| A37F | BNE pack_temp_tail ; join the common pack code | ||||||||||
| fall through ↓ | |||||||||||
Pack FWA into TEMP3Point zp_fp_ptr at FP TEMP3 (&0476), then pack FWA into it via fwa_pack_var.
|
|||||||||||
| A381 | .fwa_pack_temp3←6← 9E59 JSR← 9E88 JSR← A8EA JSR← A93C JSR← A9C3 JSR← AABE JSR | ||||||||||
| LDA #&76 ; Point at FP TEMP3 (&0476): low byte | |||||||||||
| A383 | BNE pack_temp_tail ; join the common pack code | ||||||||||
| fall through ↓ | |||||||||||
Pack FWA into TEMP1Point zp_fp_ptr at FP TEMP1 (&046C), then pack FWA into it via fwa_pack_var.
|
|||||||||||
| A385 | .fwa_pack_temp1←9← 8D3C JSR← 9F3D JSR← A6A5 JSR← A7BE JSR← A84B JSR← A89B JSR← A9B1 JSR← A9D9 JSR← AB1F JSR | ||||||||||
| LDA #&6c ; Point at FP TEMP1 (&046C): low byte | |||||||||||
| A387 | .pack_temp_tail←3← A37F BNE← A383 BNE← A835 JSR | ||||||||||
| STA zp_fp_ptr ; set the fp-variable pointer | |||||||||||
| A389 | LDA #4 ; high byte &04 | ||||||||||
| A38B | STA zp_fp_ptr_1 ; then fall into fwa_pack_var | ||||||||||
| fall through ↓ | |||||||||||
Pack FWA into a fp variableCompress the unpacked FWA accumulator into the packed five-byte form addressed by zp_fp_ptr: exponent, then the sign folded into bit 7 of the mantissa MSB (the implied leading 1 is dropped), then mantissa bytes 2-4.
|
|||||||||||||
| A38D | .fwa_pack_var←7← A4D9 JSR← A6CA JSR← A7CF JSR← A9B7 JSR← AA20 JSR← B860 JSR← B882 JSR | ||||||||||||
| LDY #0 ; Write packed bytes from offset 0 | |||||||||||||
| A38F | LDA zp_fwa_exp ; Packed byte 0 is the exponent | ||||||||||||
| A391 | STA (zp_fp_ptr),y ; (store it) | ||||||||||||
| A393 | INY ; next byte | ||||||||||||
| A394 | LDA zp_fwa_sign ; Take the sign byte | ||||||||||||
| A396 | AND #&80 ; Isolate the sign bit | ||||||||||||
| A398 | STA zp_fwa_sign ; keep only the sign bit | ||||||||||||
| A39A | LDA zp_fwa_m1 ; Mantissa MSB | ||||||||||||
| A39C | AND #&7f ; Drop the implied leading 1 from the mantissa MSB | ||||||||||||
| A39E | ORA zp_fwa_sign ; and fold the sign back into its bit 7 | ||||||||||||
| A3A0 | STA (zp_fp_ptr),y ; Packed byte 1 = sign + mantissa MSB | ||||||||||||
| A3A2 | LDA zp_fwa_m2 ; Mantissa byte 2 | ||||||||||||
| A3A4 | INY ; next byte | ||||||||||||
| A3A5 | STA (zp_fp_ptr),y ; Packed byte 2 | ||||||||||||
| A3A7 | LDA zp_fwa_m3 ; Mantissa byte 3 | ||||||||||||
| A3A9 | INY ; next byte | ||||||||||||
| A3AA | STA (zp_fp_ptr),y ; Packed byte 3 | ||||||||||||
| A3AC | LDA zp_fwa_m4 ; Mantissa byte 4 | ||||||||||||
| A3AE | INY ; next byte | ||||||||||||
| A3AF | STA (zp_fp_ptr),y ; Packed byte 4 | ||||||||||||
| A3B1 | RTS ; The 5-byte packed value is stored | ||||||||||||
Unpack TEMP1 into FWAPoint zp_fp_ptr at FP TEMP1 (&046C), then unpack it into FWA via fwa_unpack_var.
|
|||||||||||
| A3B2 | .fwa_unpack_temp1←2← AA35 JMP← BA36 JSR | ||||||||||
| JSR point_fp_temp1 ; Point at FP TEMP1, then unpack it into FWA | |||||||||||
| fall through ↓ | |||||||||||
Unpack a floating-point variable into FWAExpand the packed five-byte float addressed by zp_fp_ptr into the unpacked FWA accumulator: split the sign out of the mantissa MSB, restore the implied leading 1 (unless the value is zero), and clear the overflow and rounding bytes.
|
|||||||||
| A3B5 | .fwa_unpack_var←10← 9A4A JSR← 9E4D JSR← 9E64 JSR← 9E72 JSR← A6B5 JSR← A8B2 JSR← A901 JSR← AA26 JSR← AAC9 JSR← B2EA JSR | ||||||||
| LDY #4 ; Copy the packed value, exponent last | |||||||||
| A3B7 | LDA (zp_fp_ptr),y ; Packed byte 4... | ||||||||
| A3B9 | STA zp_fwa_m4 ; ...is mantissa byte 4 | ||||||||
| A3BB | DEY ; next byte | ||||||||
| A3BC | LDA (zp_fp_ptr),y ; byte 3... | ||||||||
| A3BE | STA zp_fwa_m3 ; ...mantissa byte 3 | ||||||||
| A3C0 | DEY ; next byte | ||||||||
| A3C1 | LDA (zp_fp_ptr),y ; byte 2... | ||||||||
| A3C3 | STA zp_fwa_m2 ; ...mantissa byte 2 | ||||||||
| A3C5 | DEY ; next byte | ||||||||
| A3C6 | LDA (zp_fp_ptr),y ; byte 1 (sign + mantissa MSB)... | ||||||||
| A3C8 | STA zp_fwa_sign ; Packed mantissa MSB holds the sign in bit 7 | ||||||||
| A3CA | DEY ; next byte | ||||||||
| A3CB | LDA (zp_fp_ptr),y ; byte 0... | ||||||||
| A3CD | STA zp_fwa_exp ; ...is the exponent | ||||||||
| A3CF | STY zp_fwa_rnd ; Clear the rounding and overflow bytes (Y=0) | ||||||||
| A3D1 | STY zp_fwa_ovf ; clear the overflow byte too | ||||||||
| A3D3 | ORA zp_fwa_sign ; A=exponent; OR the mantissa to test for zero | ||||||||
| A3D5 | ORA zp_fwa_m2 ; (mantissa byte 2) | ||||||||
| A3D7 | ORA zp_fwa_m3 ; (mantissa byte 3) | ||||||||
| A3D9 | ORA zp_fwa_m4 ; (mantissa byte 4) | ||||||||
| A3DB | BEQ fwa_unpack_msb ; All zero: leave the mantissa MSB clear | ||||||||
| A3DD | LDA zp_fwa_sign ; Non-zero: take the packed MSB (carrying the sign) | ||||||||
| A3DF | ORA #&80 ; Non-zero: restore the implied leading 1 | ||||||||
| A3E1 | .fwa_unpack_msb←1← A3DB BEQ | ||||||||
| STA zp_fwa_m1 ; Store the true mantissa MSB | |||||||||
| A3E3 | RTS ; FWA now holds the unpacked value | ||||||||
Convert the FP accumulator to an integerConvert FWA to a 4-byte integer in IWA by denormalising (fwa_to_int2) and copying the mantissa into IWA. Truncates toward zero.
|
|||||||||
| A3E4 | .fwa_to_int←5← 92F4 JMP← 98C9 JSR← 9E93 JSR← AF36 JSR← B4C3 JSR | ||||||||
| JSR fwa_to_int2 ; Denormalise FWA to a fixed integer | |||||||||
| A3E7 | .mantissa_to_iwa←1← AC95 JSR | ||||||||
| LDA zp_fwa_m1 ; Copy the 32-bit mantissa into IWA: byte 3 | |||||||||
| A3E9 | STA zp_iwa_3 ; store it | ||||||||
| A3EB | LDA zp_fwa_m2 ; byte 2 | ||||||||
| A3ED | STA zp_iwa_2 ; store it | ||||||||
| A3EF | LDA zp_fwa_m3 ; byte 1 | ||||||||
| A3F1 | STA zp_iwa_1 ; store it | ||||||||
| A3F3 | LDA zp_fwa_m4 ; byte 0 | ||||||||
| A3F5 | STA zp_iwa ; store it | ||||||||
| A3F7 | RTS ; Return | ||||||||
| A3F8 | .fti_small←1← A400 BPL | ||||||||
| JSR fwb_copy_from_fwa ; |x| < 1: FWB = FWA | |||||||||
| A3FB | JMP fwa_clear ; integer is zero | ||||||||
Denormalise FWA to a fixed-point integerShift the FWA mantissa so it represents the integer part at a fixed scale (exponent &A0), pushing the fractional bits out into FWB. The shared core of fwa_to_int and fp_split_int_frac; the caller reads the integer from the mantissa.
|
|||||||||
| A3FE | .fwa_to_int2←4← A3E4 JSR← A491 JSR← A9EE JSR← AC82 JSR | ||||||||
| LDA zp_fwa_exp ; Exponent of FWA | |||||||||
| A400 | BPL fti_small ; < 1: result is zero | ||||||||
| A402 | JSR fwb_clear ; Clear the low-order extension (FWB) | ||||||||
| A405 | JSR fwa_sign ; Sign of FWA | ||||||||
| A408 | BNE fti2_shift_loop ; non-zero: denormalise | ||||||||
| A40A | BEQ fti2_positive ; zero: nothing to do | ||||||||
| A40C | .fti2_exp←2← A43A BEQ← A44E BNE | ||||||||
| LDA zp_fwa_exp ; Exponent | |||||||||
| A40E | CMP #&a0 ; already a 32-bit integer (exp = +32)? | ||||||||
| A410 | BCS fti2_exp_over ; yes: check it fits | ||||||||
| A412 | CMP #&99 ; within a byte-shift of integer? | ||||||||
| A414 | BCS fti2_shift_loop ; yes: finish with bit shifts | ||||||||
| A416 | ADC #8 ; Fast path: shift right one byte (exp += 8) | ||||||||
| A418 | STA zp_fwa_exp ; (store) | ||||||||
| A41A | LDA zp_fwb_m3 ; shift the mantissa down a byte, low byte into FWB | ||||||||
| A41C | STA zp_fwb_m4 ; into fwb m4, | ||||||||
| A41E | LDA zp_fwb_m2 ; m2... | ||||||||
| A420 | STA zp_fwb_m3 ; into fwb m3, | ||||||||
| A422 | LDA zp_fwb_m1 ; m1... | ||||||||
| A424 | STA zp_fwb_m2 ; into fwb m2, | ||||||||
| A426 | LDA zp_fwa_m4 ; fwa m4... | ||||||||
| A428 | STA zp_fwb_m1 ; into fwb m1, | ||||||||
| A42A | LDA zp_fwa_m3 ; m3... | ||||||||
| A42C | STA zp_fwa_m4 ; into fwa m4, | ||||||||
| A42E | LDA zp_fwa_m2 ; m2... | ||||||||
| A430 | STA zp_fwa_m3 ; into fwa m3, | ||||||||
| A432 | LDA zp_fwa_m1 ; m1... | ||||||||
| A434 | STA zp_fwa_m2 ; into fwa m2, | ||||||||
| A436 | LDA #0 ; zero... | ||||||||
| A438 | STA zp_fwa_m1 ; into fwa m1 (top) | ||||||||
| A43A | BEQ fti2_exp ; loop | ||||||||
| A43C | .fti2_shift_loop←2← A408 BNE← A414 BCS | ||||||||
| LSR zp_fwa_m1 ; Slow path: shift FWA:FWB right one bit | |||||||||
| A43E | ROR zp_fwa_m2 ; through fwa m2, | ||||||||
| A440 | ROR zp_fwa_m3 ; m3, | ||||||||
| A442 | ROR zp_fwa_m4 ; m4, | ||||||||
| A444 | ROR zp_fwb_m1 ; then fwb m1, | ||||||||
| A446 | ROR zp_fwb_m2 ; m2, | ||||||||
| A448 | ROR zp_fwb_m3 ; m3, | ||||||||
| A44A | ROR zp_fwb_m4 ; m4 | ||||||||
| A44C | INC zp_fwa_exp ; exp += 1 | ||||||||
| A44E | BNE fti2_exp ; loop until an exact integer | ||||||||
| A450 | .fti2_too_big←2← A466 BNE← A4C4 BEQ | ||||||||
| JMP err_too_big ; Magnitude too large: Too big error | |||||||||
FWB = 0Zero every byte of FWB. Exponent 0 is the special encoding for the value zero.
|
||||||||||
| A453 | .fwb_clear←3← A402 JSR← A814 JSR← A93F JSR | |||||||||
| LDA #0 ; Zero every byte of FWB | ||||||||||
| A455 | STA zp_fwb_sign ; ...sign | |||||||||
| A457 | STA zp_fwb_ovf ; ...overflow | |||||||||
| A459 | STA zp_fwb_exp ; ...exponent | |||||||||
| A45B | STA zp_fwb_m1 ; ...mantissa byte 1 | |||||||||
| A45D | STA zp_fwb_m2 ; ...byte 2 | |||||||||
| A45F | STA zp_fwb_m3 ; ...byte 3 | |||||||||
| A461 | STA zp_fwb_m4 ; ...byte 4 | |||||||||
| A463 | STA zp_fwb_rnd ; ...rounding byte | |||||||||
| A465 | RTS ; Return | |||||||||
| A466 | .fti2_exp_over←1← A410 BCS | |||||||||
| BNE fti2_too_big ; Exponent > 32: Too big error | ||||||||||
| A468 | .fti2_positive←1← A40A BEQ | |||||||||
| LDA zp_fwa_sign ; Positive: integer ready, return | ||||||||||
| A46A | BPL return_24 ; positive: nothing to do | |||||||||
| A46C | .fti2_negate←4← A4B0 JSR← A4C7 JSR← A4CD JMP← AA0B JSR | |||||||||
| SEC ; Negative: negate the 32-bit mantissa | ||||||||||
| A46D | LDA #0 ; low byte first: 0... | |||||||||
| A46F | SBC zp_fwa_m4 ; minus m4, | |||||||||
| A471 | STA zp_fwa_m4 ; (store) | |||||||||
| A473 | LDA #0 ; 0... | |||||||||
| A475 | SBC zp_fwa_m3 ; minus m3 (borrow in), | |||||||||
| A477 | STA zp_fwa_m3 ; (store) | |||||||||
| A479 | LDA #0 ; 0... | |||||||||
| A47B | SBC zp_fwa_m2 ; minus m2 (borrow in), | |||||||||
| A47D | STA zp_fwa_m2 ; (store) | |||||||||
| A47F | LDA #0 ; 0... | |||||||||
| A481 | SBC zp_fwa_m1 ; minus m1 (borrow in) | |||||||||
| A483 | STA zp_fwa_m1 ; (store) | |||||||||
| A485 | .return_24←1← A46A BPL | |||||||||
| RTS ; Return | ||||||||||
Split FWA into integer part (&4A) and fraction (FWA)Round FWA to the nearest integer, leaving that integer in &4A and the signed remainder (in [-0.5, 0.5]) in FWA. Used by EXP to separate the integer and fractional powers.
|
|||||||||||
| A486 | .fp_split_int_frac←2← 9E45 JSR← AAB8 JSR | ||||||||||
| LDA zp_fwa_exp ; Exponent of FWA | |||||||||||
| A488 | BMI sif_convert ; |x| >= 1: has an integer part | ||||||||||
| A48A | LDA #0 ; |x| < 1: integer part is zero | ||||||||||
| A48C | STA zp_int_exp ; store it | ||||||||||
| A48E | JMP fwa_sign ; return the fraction (= x) | ||||||||||
| A491 | .sif_convert←1← A488 BMI | ||||||||||
| JSR fwa_to_int2 ; Convert to a fixed integer (fraction into FWB) | |||||||||||
| A494 | LDA zp_fwa_m4 ; Low byte of the integer part... | ||||||||||
| A496 | STA zp_int_exp ; ...kept in &4A | ||||||||||
| A498 | JSR copy_fwb_mantissa ; Bring the fractional bits back into FWA | ||||||||||
| A49B | LDA #&80 ; Exponent for a value in [0,1) | ||||||||||
| A49D | STA zp_fwa_exp ; set it | ||||||||||
| A49F | LDX zp_fwa_m1 ; Top fraction bit set (fraction >= 0.5)? | ||||||||||
| A4A1 | BPL sif_normalise_frac ; no: fraction already in range | ||||||||||
| A4A3 | EOR zp_fwa_sign ; Round to nearest: flip the fraction sign | ||||||||||
| A4A5 | STA zp_fwa_sign ; store it back | ||||||||||
| A4A7 | BPL sif_round_down ; remainder positive: round the integer down | ||||||||||
| A4A9 | INC zp_int_exp ; remainder negative: round the integer up | ||||||||||
| A4AB | JMP sif_negate_frac ; done: go negate the remainder | ||||||||||
| A4AE | .sif_round_down←1← A4A7 BPL | ||||||||||
| DEC zp_int_exp ; negative: round the integer part down | |||||||||||
| A4B0 | .sif_negate_frac←1← A4AB JMP | ||||||||||
| JSR fti2_negate ; Negate the fraction mantissa | |||||||||||
| A4B3 | .sif_normalise_frac←1← A4A1 BPL | ||||||||||
| JMP fwa_normalise ; Normalise the fraction | |||||||||||
| A4B6 | .inc_int_mantissa←1← A4CA JSR | ||||||||||
| INC zp_fwa_m4 ; Increment the integer-part mantissa (carry up) | |||||||||||
| A4B8 | BNE return_25 ; done if byte 4 did not wrap | ||||||||||
| A4BA | INC zp_fwa_m3 ; wrapped: carry into byte 3, | ||||||||||
| A4BC | BNE return_25 ; done if no wrap | ||||||||||
| A4BE | INC zp_fwa_m2 ; byte 2, | ||||||||||
| A4C0 | BNE return_25 ; done if no wrap | ||||||||||
| A4C2 | INC zp_fwa_m1 ; byte 1 (top) | ||||||||||
| A4C4 | BEQ fti2_too_big ; overflow: Too big | ||||||||||
| A4C6 | .return_25←3← A4B8 BNE← A4BC BNE← A4C0 BNE | ||||||||||
| RTS ; Return | |||||||||||
| A4C7 | .negate_mantissa←1← AC92 JSR | ||||||||||
| JSR fti2_negate ; Decrement the mantissa magnitude (negate, +1, negate) | |||||||||||
| A4CA | JSR inc_int_mantissa ; add one to the magnitude | ||||||||||
| A4CD | JMP fti2_negate ; negate back | ||||||||||
FWA = FWA - fp varSubtract the packed real operand from FWA: compute operand - FWA (fwa_rsub_var) then negate the result.
|
|||||||||||
| A4D0 | .fwa_sub_var←2← 9D08 JSR← A9BD JSR | ||||||||||
| JSR fwa_rsub_var ; operand - FWA... | |||||||||||
| A4D3 | JMP fwa_negate ; ...then negate to give FWA - operand | ||||||||||
Swap FWA and a fp variableExchange FWA with the packed real at zp_fp_ptr: unpack the operand into FWB, pack FWA into the variable, then copy FWB into FWA.
|
|||||||||||||
| A4D6 | .fwa_swap_var←1← A6D5 JSR | ||||||||||||
| JSR fwb_unpack_var ; FWB = the fp variable | |||||||||||||
| A4D9 | JSR fwa_pack_var ; Store FWA into the variable; FWA = old variable | ||||||||||||
| fall through ↓ | |||||||||||||
FWA = FWBCopy all ten bytes of FWB into FWA.
|
|||||||||
| A4DC | .fwa_copy_from_fwb←2← A50E BEQ← A559 BCS | ||||||||
| LDA zp_fwb_sign ; Copy FWB's sign... | |||||||||
| A4DE | STA zp_fwa_sign ; ...into FWA | ||||||||
| A4E0 | LDA zp_fwb_ovf ; Copy the overflow byte... | ||||||||
| A4E2 | STA zp_fwa_ovf ; ...into FWA | ||||||||
| A4E4 | LDA zp_fwb_exp ; Copy the exponent... | ||||||||
| A4E6 | STA zp_fwa_exp ; ...into FWA | ||||||||
| A4E8 | .copy_fwb_mantissa←1← A498 JSR | ||||||||
| LDA zp_fwb_m1 ; Copy mantissa byte 1... | |||||||||
| A4EA | STA zp_fwa_m1 ; ...into FWA | ||||||||
| A4EC | LDA zp_fwb_m2 ; Copy mantissa byte 2... | ||||||||
| A4EE | STA zp_fwa_m2 ; ...into FWA | ||||||||
| A4F0 | LDA zp_fwb_m3 ; Copy mantissa byte 3... | ||||||||
| A4F2 | STA zp_fwa_m3 ; ...into FWA | ||||||||
| A4F4 | LDA zp_fwb_m4 ; Copy mantissa byte 4... | ||||||||
| A4F6 | STA zp_fwa_m4 ; ...into FWA | ||||||||
| A4F8 | LDA zp_fwb_rnd ; Copy the rounding byte... | ||||||||
| A4FA | STA zp_fwa_rnd ; ...into FWA | ||||||||
| A4FC | .return_26←2← A503 BEQ← A51D BCS | ||||||||
| RTS ; FWA is now a copy of FWB | |||||||||
FWA = fp var - FWAReverse subtract: negate FWA then add the packed real operand, giving operand - FWA (normalised, rounded).
|
|||||||||||
| A4FD | .fwa_rsub_var←2← 9CF4 JSR← A4D0 JSR | ||||||||||
| JSR fwa_negate ; Negate FWA, then add the variable: var - FWA | |||||||||||
| fall through ↓ | |||||||||||
FWA = FWA + fp varUnpack the packed real operand into FWB and add it to FWA (normalised, rounded).
|
|||||||||||
| A500 | .fwa_add_var←10← 9C9E JSR← A7DD JSR← A848 JSR← A863 JSR← A8CC JSR← A92A JSR← A930 JSR← AA1D JSR← AA32 JMP← B774 JSR | ||||||||||
| JSR fwb_unpack_var ; FWB = the fp variable | |||||||||||
| A503 | BEQ return_26 ; Adding zero leaves FWA unchanged | ||||||||||
| fall through ↓ | |||||||||||
FWA = FWA + FWBAdd FWB to FWA (fwa_add_fwb_raw then fwa_round), normalised and rounded.
|
|||||||||
| A505 | .fwa_add_fwb←3← A830 JSR← A94A JSR← A9E8 JSR | ||||||||
| JSR fwa_add_fwb_raw ; FWA = FWA + FWB (raw) | |||||||||
| A508 | JMP fwa_round ; then round | ||||||||
FWA = FWA + FWB (unrounded)Add FWB to FWA: align the smaller operand to the larger exponent, add the mantissas and normalise. Left unrounded (the caller rounds). Operands differing by >= 37 bits leave FWA unchanged.
|
|||||||||
| A50B | .fwa_add_fwb_raw←2← 9F7B JSR← A505 JSR | ||||||||
| JSR fwa_sign ; Is FWA zero? | |||||||||
| A50E | BEQ fwa_copy_from_fwb ; FWA is zero: the sum is simply FWB | ||||||||
| A510 | LDY #0 ; Y = 0 (the byte shifted in) | ||||||||
| A512 | SEC ; prepare the exponent compare | ||||||||
| A513 | LDA zp_fwa_exp ; FWA exponent... | ||||||||
| A515 | SBC zp_fwb_exp ; Exponent difference is the alignment shift | ||||||||
| A517 | BEQ addf_compare_signs ; Equal exponents: already aligned | ||||||||
| A519 | BCC addf_align_fwa ; FWA the smaller: align it to FWB instead | ||||||||
| A51B | CMP #&25 ; differ by >= 37 bits? | ||||||||
| A51D | BCS return_26 ; Differ by >= 37 bits: FWB too small to count | ||||||||
| A51F | PHA ; save the shift count | ||||||||
| A520 | AND #&38 ; Whole-byte part of the shift (difference / 8) | ||||||||
| A522 | BEQ addf_fwb_bits ; no whole-byte shift: go to the bit shift | ||||||||
| A524 | LSR ; shift count / 8... | ||||||||
| A525 | LSR ; (continued) | ||||||||
| A526 | LSR ; = whole-byte shifts | ||||||||
| A527 | TAX ; X = byte-shift count | ||||||||
| A528 | .addf_shift_fwb_byte←1← A53B BNE | ||||||||
| LDA zp_fwb_m4 ; Shift FWB down a byte at a time | |||||||||
| A52A | STA zp_fwb_rnd ; shift FWB down a byte: m4 -> rnd | ||||||||
| A52C | LDA zp_fwb_m3 ; m3... | ||||||||
| A52E | STA zp_fwb_m4 ; -> m4 | ||||||||
| A530 | LDA zp_fwb_m2 ; m2... | ||||||||
| A532 | STA zp_fwb_m3 ; -> m3 | ||||||||
| A534 | LDA zp_fwb_m1 ; m1... | ||||||||
| A536 | STA zp_fwb_m2 ; -> m2 | ||||||||
| A538 | STY zp_fwb_m1 ; m1 = 0 | ||||||||
| A53A | DEX ; count | ||||||||
| A53B | BNE addf_shift_fwb_byte ; loop | ||||||||
| A53D | .addf_fwb_bits←1← A522 BEQ | ||||||||
| PLA ; recover the shift count | |||||||||
| A53E | AND #7 ; then the remaining bits, to finish aligning FWB | ||||||||
| A540 | BEQ addf_compare_signs ; no bit shift: add the mantissas | ||||||||
| A542 | TAX ; X = bit-shift count | ||||||||
| A543 | .addf_shift_fwb_bit←1← A54E BNE | ||||||||
| LSR zp_fwb_m1 ; shift FWB right one bit: m1 | |||||||||
| A545 | ROR zp_fwb_m2 ; m2 | ||||||||
| A547 | ROR zp_fwb_m3 ; m3 | ||||||||
| A549 | ROR zp_fwb_m4 ; m4 | ||||||||
| A54B | ROR zp_fwb_rnd ; rnd | ||||||||
| A54D | DEX ; count | ||||||||
| A54E | BNE addf_shift_fwb_bit ; loop | ||||||||
| A550 | BEQ addf_compare_signs ; aligned: add the mantissas | ||||||||
| A552 | .addf_align_fwa←1← A519 BCC | ||||||||
| SEC ; FWA the smaller: shift FWA down to align | |||||||||
| A553 | LDA zp_fwb_exp ; FWB exponent - FWA exponent | ||||||||
| A555 | SBC zp_fwa_exp ; minus FWA exponent | ||||||||
| A557 | CMP #&25 ; differ by >= 37 bits? | ||||||||
| A559 | BCS fwa_copy_from_fwb ; FWA negligible: result is FWB | ||||||||
| A55B | PHA ; save the shift count | ||||||||
| A55C | AND #&38 ; whole-byte part | ||||||||
| A55E | BEQ addf_fwa_bits ; none: go to the bit shift | ||||||||
| A560 | LSR ; / 8... | ||||||||
| A561 | LSR ; (continued) | ||||||||
| A562 | LSR ; = whole-byte shifts | ||||||||
| A563 | TAX ; X = byte-shift count | ||||||||
| A564 | .addf_shift_fwa_byte←1← A577 BNE | ||||||||
| LDA zp_fwa_m4 ; shift FWA down a byte: m4 -> rnd | |||||||||
| A566 | STA zp_fwa_rnd ; (store) | ||||||||
| A568 | LDA zp_fwa_m3 ; m3 -> m4 | ||||||||
| A56A | STA zp_fwa_m4 ; (store) | ||||||||
| A56C | LDA zp_fwa_m2 ; m2 -> m3 | ||||||||
| A56E | STA zp_fwa_m3 ; (store) | ||||||||
| A570 | LDA zp_fwa_m1 ; m1 -> m2 | ||||||||
| A572 | STA zp_fwa_m2 ; (store) | ||||||||
| A574 | STY zp_fwa_m1 ; m1 = 0 | ||||||||
| A576 | DEX ; count | ||||||||
| A577 | BNE addf_shift_fwa_byte ; loop | ||||||||
| A579 | .addf_fwa_bits←1← A55E BEQ | ||||||||
| PLA ; recover the shift count | |||||||||
| A57A | AND #7 ; bit part | ||||||||
| A57C | BEQ addf_take_exp ; none: take the larger exponent | ||||||||
| A57E | TAX ; X = bit-shift count | ||||||||
| A57F | .addf_shift_fwa_bit←1← A58A BNE | ||||||||
| LSR zp_fwa_m1 ; shift FWA right one bit: m1 | |||||||||
| A581 | ROR zp_fwa_m2 ; m2 | ||||||||
| A583 | ROR zp_fwa_m3 ; m3 | ||||||||
| A585 | ROR zp_fwa_m4 ; m4 | ||||||||
| A587 | ROR zp_fwa_rnd ; rnd | ||||||||
| A589 | DEX ; count | ||||||||
| A58A | BNE addf_shift_fwa_bit ; loop | ||||||||
| A58C | .addf_take_exp←1← A57C BEQ | ||||||||
| LDA zp_fwb_exp ; Result takes the larger exponent | |||||||||
| A58E | STA zp_fwa_exp ; store the larger exponent | ||||||||
| A590 | .addf_compare_signs←3← A517 BEQ← A540 BEQ← A550 BEQ | ||||||||
| LDA zp_fwa_sign ; Compare the signs: load FWA sign | |||||||||
| A592 | EOR zp_fwb_sign ; Compare the operand signs | ||||||||
| A594 | BPL fp_mantissas_add ; Same sign: add; opposite: subtract smaller from larger | ||||||||
| A596 | LDA zp_fwa_m1 ; Opposite signs: compare magnitudes (m1) | ||||||||
| A598 | CMP zp_fwb_m1 ; against FWB | ||||||||
| A59A | BNE fp_mantissas_sub ; differ: subtract | ||||||||
| A59C | LDA zp_fwa_m2 ; m2 | ||||||||
| A59E | CMP zp_fwb_m2 ; against FWB | ||||||||
| A5A0 | BNE fp_mantissas_sub ; differ: subtract | ||||||||
| A5A2 | LDA zp_fwa_m3 ; m3 | ||||||||
| A5A4 | CMP zp_fwb_m3 ; against FWB | ||||||||
| A5A6 | BNE fp_mantissas_sub ; differ: subtract | ||||||||
| A5A8 | LDA zp_fwa_m4 ; m4 | ||||||||
| A5AA | CMP zp_fwb_m4 ; against FWB | ||||||||
| A5AC | BNE fp_mantissas_sub ; differ: subtract | ||||||||
| A5AE | LDA zp_fwa_rnd ; rnd | ||||||||
| A5B0 | CMP zp_fwb_rnd ; against FWB | ||||||||
| A5B2 | BNE fp_mantissas_sub ; differ: subtract | ||||||||
| A5B4 | JMP fwa_clear ; Equal magnitudes of opposite sign cancel to zero | ||||||||
| A5B7 | .fp_mantissas_sub←5← A59A BNE← A5A0 BNE← A5A6 BNE← A5AC BNE← A5B2 BNE | ||||||||
| BCS addf_subtract ; FWA >= FWB? choose the subtraction order | |||||||||
| A5B9 | SEC ; FWB - FWA: rnd | ||||||||
| A5BA | LDA zp_fwb_rnd ; FWB rnd... | ||||||||
| A5BC | SBC zp_fwa_rnd ; - FWA rnd, | ||||||||
| A5BE | STA zp_fwa_rnd ; (store) | ||||||||
| A5C0 | LDA zp_fwb_m4 ; m4 | ||||||||
| A5C2 | SBC zp_fwa_m4 ; - FWA m4, | ||||||||
| A5C4 | STA zp_fwa_m4 ; (store) | ||||||||
| A5C6 | LDA zp_fwb_m3 ; m3 | ||||||||
| A5C8 | SBC zp_fwa_m3 ; - FWA m3, | ||||||||
| A5CA | STA zp_fwa_m3 ; (store) | ||||||||
| A5CC | LDA zp_fwb_m2 ; m2 | ||||||||
| A5CE | SBC zp_fwa_m2 ; - FWA m2, | ||||||||
| A5D0 | STA zp_fwa_m2 ; (store) | ||||||||
| A5D2 | LDA zp_fwb_m1 ; m1 | ||||||||
| A5D4 | SBC zp_fwa_m1 ; - FWA m1 | ||||||||
| A5D6 | STA zp_fwa_m1 ; (store) | ||||||||
| A5D8 | LDA zp_fwb_sign ; result takes FWB's sign | ||||||||
| A5DA | STA zp_fwa_sign ; (store) | ||||||||
| A5DC | JMP fwa_normalise ; normalise the difference | ||||||||
| A5DF | .fp_mantissas_add←1← A594 BPL | ||||||||
| CLC ; Same sign: add the mantissas | |||||||||
| A5E0 | JMP fwa_acc10 ; FWA += FWB | ||||||||
| A5E3 | .addf_subtract←1← A5B7 BCS | ||||||||
| SEC ; FWA - FWB: rnd | |||||||||
| A5E4 | LDA zp_fwa_rnd ; FWA rnd... | ||||||||
| A5E6 | SBC zp_fwb_rnd ; - FWB rnd, | ||||||||
| A5E8 | STA zp_fwa_rnd ; (store) | ||||||||
| A5EA | LDA zp_fwa_m4 ; m4 | ||||||||
| A5EC | SBC zp_fwb_m4 ; - FWB m4, | ||||||||
| A5EE | STA zp_fwa_m4 ; (store) | ||||||||
| A5F0 | LDA zp_fwa_m3 ; m3 | ||||||||
| A5F2 | SBC zp_fwb_m3 ; - FWB m3, | ||||||||
| A5F4 | STA zp_fwa_m3 ; (store) | ||||||||
| A5F6 | LDA zp_fwa_m2 ; m2 | ||||||||
| A5F8 | SBC zp_fwb_m2 ; - FWB m2, | ||||||||
| A5FA | STA zp_fwa_m2 ; (store) | ||||||||
| A5FC | LDA zp_fwa_m1 ; m1 | ||||||||
| A5FE | SBC zp_fwb_m1 ; - FWB m1, | ||||||||
| A600 | STA zp_fwa_m1 ; (store) | ||||||||
| A602 | JMP fwa_normalise ; normalise the difference | ||||||||
| A605 | .return_27←1← A609 BEQ | ||||||||
| RTS ; Return | |||||||||
FWA = FWA * fp var (raw)Multiply FWA by the packed real operand (sign XOR, exponents added, mantissas multiplied by shift-and-add). A zero operand gives zero. Left unnormalised and unrounded (the caller finishes).
|
|||||||||||
| A606 | .fwa_mul_var_raw←2← A656 JSR← AF30 JSR | ||||||||||
| JSR fwa_sign ; Is FWA zero? | |||||||||||
| A609 | BEQ return_27 ; zero: the product is zero | ||||||||||
| A60B | JSR fwb_unpack_var ; FWB = the fp variable (the multiplier) | ||||||||||
| A60E | BNE mulf_add_exp ; non-zero: multiply | ||||||||||
| A610 | JMP fwa_clear ; multiplier zero: the product is zero | ||||||||||
| A613 | .mulf_add_exp←1← A60E BNE | ||||||||||
| CLC ; Add the exponents: | |||||||||||
| A614 | LDA zp_fwa_exp ; FWA exp... | ||||||||||
| A616 | ADC zp_fwb_exp ; + FWB exp | ||||||||||
| A618 | BCC mulf_unbias ; no carry | ||||||||||
| A61A | INC zp_fwa_ovf ; carry into overflow | ||||||||||
| A61C | CLC ; (clear carry) | ||||||||||
| A61D | .mulf_unbias←1← A618 BCC | ||||||||||
| SBC #&7f ; remove the excess-128 bias (added twice) | |||||||||||
| A61F | STA zp_fwa_exp ; store the product exponent | ||||||||||
| A621 | BCS mulf_setup ; no borrow | ||||||||||
| A623 | DEC zp_fwa_ovf ; borrow into overflow | ||||||||||
| A625 | .mulf_setup←1← A621 BCS | ||||||||||
| LDX #5 ; Move FWA aside as the multiplicand and clear FWA: | |||||||||||
| A627 | LDY #0 ; Y = 0 (to clear FWA with) | ||||||||||
| A629 | .mulf_copy_loop←1← A630 BNE | ||||||||||
| LDA zp_fwa_exp,x ; copy a FWA byte... | |||||||||||
| A62B | STA zp_fwb_rnd,x ; ...to the multiplicand | ||||||||||
| A62D | STY zp_fwa_exp,x ; clear the FWA byte | ||||||||||
| A62F | DEX ; count | ||||||||||
| A630 | BNE mulf_copy_loop ; loop | ||||||||||
| A632 | LDA zp_fwa_sign ; Product sign = FWA sign XOR FWB sign: | ||||||||||
| A634 | EOR zp_fwb_sign ; XOR FWB sign | ||||||||||
| A636 | STA zp_fwa_sign ; (store) | ||||||||||
| A638 | LDY #&20 ; 32 iterations, one per multiplier bit | ||||||||||
| A63A | .mulf_bit_loop←1← A653 BNE | ||||||||||
| LSR zp_fwb_m1 ; Shift the multiplier right: next bit into carry | |||||||||||
| A63C | ROR zp_fwb_m2 ; m2, | ||||||||||
| A63E | ROR zp_fwb_m3 ; m3, | ||||||||||
| A640 | ROR zp_fwb_m4 ; m4, | ||||||||||
| A642 | ROR zp_fwb_rnd ; rnd | ||||||||||
| A644 | ASL zp_fp_temp_3 ; Shift the running product left (&43-&46): | ||||||||||
| A646 | ROL zp_fp_temp_2 ; through &45, | ||||||||||
| A648 | ROL zp_fp_temp_1 ; &44, | ||||||||||
| A64A | ROL zp_fp_temp ; &43 (high) | ||||||||||
| A64C | BCC mulf_count ; multiplier bit clear: skip the add | ||||||||||
| A64E | CLC ; bit set: add the multiplicand | ||||||||||
| A64F | JSR fwa_acc_fwb ; FWA += FWB | ||||||||||
| A652 | .mulf_count←1← A64C BCC | ||||||||||
| DEY ; count | |||||||||||
| A653 | BNE mulf_bit_loop ; loop | ||||||||||
| A655 | RTS ; Return the product | ||||||||||
FWA = FWA * fp varMultiply FWA by the packed real operand (fwa_mul_var_raw then normalise and round).
|
|||||||||||
| A656 | .fwa_mul_var←12← 9D2F JSR← 9E81 JSR← A842 JSR← A845 JSR← A85D JSR← A9B4 JSR← A9C6 JSR← AA17 JSR← AA2C JSR← AAD4 JSR← AB2C JSR← ABBC JSR | ||||||||||
| JSR fwa_mul_var_raw ; FWA = FWA * fp var (raw) | |||||||||||
| A659 | .mulf_normalise←2← A7A6 JMP← AF81 JSR | ||||||||||
| JSR fwa_normalise ; normalise (round below) | |||||||||||
| fall through ↓ | |||||||||||
Round FWARound FWA to the mantissa LSB using the rounding byte: round to nearest, ties handled by the LSB. A carry out of the top renormalises and can raise Too big.
|
|||||||||
| A65C | .fwa_round←2← A118 JSR← A508 JMP | ||||||||
| LDA zp_fwa_rnd ; The rounding byte holds the bits below the LSB | |||||||||
| A65E | CMP #&80 ; compare with half (&80) | ||||||||
| A660 | BCC round_clear ; Below half: round down (truncate) | ||||||||
| A662 | BEQ round_half ; Exactly half: special-case the LSB | ||||||||
| A664 | LDA #&ff ; Above half: round up by adding 1 | ||||||||
| A666 | JSR fwa_round_carry ; add 1 via the carry ripple | ||||||||
| A669 | JMP round_clear ; then finish | ||||||||
| A66C | .err_too_big←2← A450 JMP← A684 BPL | ||||||||
| BRK ; BRK error block: "Too big" | |||||||||
| A66D | EQUB &14 | ||||||||
| A66E | EQUS "Too big" | ||||||||
| A675 | EQUB &00 | ||||||||
| A676 | .round_half←1← A662 BEQ | ||||||||
| LDA zp_fwa_m4 ; Exactly half: force the mantissa LSB | |||||||||
| A678 | ORA #1 ; set the LSB | ||||||||
| A67A | STA zp_fwa_m4 ; (store) | ||||||||
| A67C | .round_clear←2← A660 BCC← A669 JMP | ||||||||
| LDA #0 ; Clear the now-spent rounding byte | |||||||||
| A67E | STA zp_fwa_rnd ; clear the rounding byte | ||||||||
| A680 | LDA zp_fwa_ovf ; A carry may have overflowed the mantissa | ||||||||
| A682 | BEQ return_28 ; no overflow: done | ||||||||
| A684 | BPL err_too_big ; Overflowed the exponent range: Too big | ||||||||
| fall through ↓ | |||||||||
FWA = 0Zero every byte of FWA. Exponent 0 is the special encoding for the value zero.
|
||||||||||
| A686 | .fwa_clear←8← 9F5C JSR← 9FA0 JSR← A2EE JSR← A3FB JMP← A5B4 JMP← A610 JMP← A699 JSR← AAA6 JSR | |||||||||
| LDA #0 ; Zero to write into every field | ||||||||||
| A688 | STA zp_fwa_sign ; Clear the sign | |||||||||
| A68A | STA zp_fwa_ovf ; Clear the overflow byte | |||||||||
| A68C | STA zp_fwa_exp ; Exponent 0 is the special "value is zero" | |||||||||
| A68E | STA zp_fwa_m1 ; Clear mantissa byte 1 (most significant) | |||||||||
| A690 | STA zp_fwa_m2 ; Clear mantissa byte 2 | |||||||||
| A692 | STA zp_fwa_m3 ; Clear mantissa byte 3 | |||||||||
| A694 | STA zp_fwa_m4 ; Clear mantissa byte 4 (least significant) | |||||||||
| A696 | STA zp_fwa_rnd ; Clear the rounding byte | |||||||||
| A698 | .return_28←2← A682 BEQ← A6EA BEQ | |||||||||
| RTS ; FWA now holds 0.0 | ||||||||||
FWA = 1Set the floating-point accumulator to 1.0 (mantissa MSB &80, exponent &81).
|
||||||
| A699 | .fwa_set_one←6← 9E8B JSR← 9F20 JSR← A6A8 JSR← A9BA JSR← AB22 JSR← B863 JSR | |||||
| JSR fwa_clear ; Start from 0.0 | ||||||
| A69C | LDY #&80 ; Mantissa MSB &80 is the implied leading 1 | |||||
| A69E | STY zp_fwa_m1 ; Set mantissa byte 1 | |||||
| A6A0 | INY ; Y = &81 | |||||
| A6A1 | STY zp_fwa_exp ; Exponent &81 makes the value exactly 1.0 | |||||
| A6A3 | TYA ; Return non-zero (A = exponent) to flag a real | |||||
| A6A4 | RTS ; FWA now holds 1.0 | |||||
FWA = 1 / FWAReciprocal: save FWA in TEMP1, set FWA = 1, then divide by the saved value (normalised, rounded). Raises Division by zero if FWA was zero.
|
|||||||||||
| A6A5 | .fwa_reciprocal←2← A921 JSR← AB1A JSR | ||||||||||
| JSR fwa_pack_temp1 ; Save FWA (the divisor) in TEMP1 | |||||||||||
| A6A8 | JSR fwa_set_one ; FWA = 1 | ||||||||||
| A6AB | BNE fp_divide ; divide 1 by the saved value | ||||||||||
| fall through ↓ | |||||||||||
FWA = fp var / FWAReverse divide: copy FWA (the divisor) into FWB, unpack the packed real operand (the dividend) into FWA, then divide, giving operand / FWA. Raises Division by zero if FWA is zero.
|
|||||||||||
| A6AD | .fwa_rdiv_var←4← 9DF8 JSR← A7D6 JSR← A8B8 JSR← A8F8 JSR | ||||||||||
| JSR fwa_sign ; Is FWA (the divisor) zero? | |||||||||||
| A6B0 | BEQ fp_div_zero ; yes: Division by zero | ||||||||||
| A6B2 | JSR fwb_copy_from_fwa ; FWB = FWA (the divisor) | ||||||||||
| A6B5 | JSR fwa_unpack_var ; FWA = the fp variable (the dividend) | ||||||||||
| A6B8 | BNE div_signs ; non-zero: do the division | ||||||||||
| A6BA | RTS ; dividend zero: result is zero | ||||||||||
| A6BB | .fp_div_zero←2← A6B0 BEQ← A6EF BEQ | ||||||||||
| JMP div_zero_error ; Division by zero error | |||||||||||
TANFWA = tan(FWA), argument in radians. Pure routine at &A6C1.
|
|||||||||||||||
| A6BE | .fn_tan | ||||||||||||||
| JSR eval_real ; Evaluate the argument as a real | |||||||||||||||
| A6C1 | JSR sin_cos_reduce ; Compute the trig kernel | ||||||||||||||
| A6C4 | LDA zp_int_exp ; save the quadrant | ||||||||||||||
| A6C6 | PHA ; push it | ||||||||||||||
| A6C7 | JSR point_fp_temp4 ; save the first result (cos) in TEMP4 | ||||||||||||||
| A6CA | JSR fwa_pack_var ; pack FWA (cos) there | ||||||||||||||
| A6CD | INC zp_int_exp ; shift the quadrant (cos -> sin) | ||||||||||||||
| A6CF | JSR sin_quadrant ; compute the other (sin) | ||||||||||||||
| A6D2 | JSR point_fp_temp4 ; point at TEMP4 | ||||||||||||||
| A6D5 | JSR fwa_swap_var ; swap FWA (sin) with TEMP4 (cos) | ||||||||||||||
| A6D8 | PLA ; restore the quadrant | ||||||||||||||
| A6D9 | STA zp_int_exp ; store it | ||||||||||||||
| A6DB | JSR sin_quadrant ; finish the trig (cos in FWA) | ||||||||||||||
| A6DE | JSR point_fp_temp4 ; point at TEMP4 (sin) | ||||||||||||||
| A6E1 | JSR fp_divide ; TAN = sin / cos | ||||||||||||||
| A6E4 | LDA #&ff ; real result | ||||||||||||||
| A6E6 | RTS ; Return TAN | ||||||||||||||
FWA = FWA / divisor (restoring long division)Floating-point divide of FWA by the packed real divisor: sign XOR, exponents subtracted, then 32 quotient bits plus guard bits by restoring long division (compare/subtract/shift). Raises Division by zero on a zero divisor; a zero dividend gives zero.
|
|||||||||||||
| A6E7 | .fp_divide←3← A6AB BNE← A6E1 JSR← A9EB JSR | ||||||||||||
| JSR fwa_sign ; Is the dividend (FWA) zero? | |||||||||||||
| A6EA | BEQ return_28 ; zero: result is zero | ||||||||||||
| A6EC | JSR fwb_unpack_var ; unpack the divisor into FWB | ||||||||||||
| A6EF | BEQ fp_div_zero ; divisor zero: Division by zero | ||||||||||||
| A6F1 | .div_signs←1← A6B8 BNE | ||||||||||||
| LDA zp_fwa_sign ; result sign = sign XOR sign | |||||||||||||
| A6F3 | EOR zp_fwb_sign ; XOR the divisor sign | ||||||||||||
| A6F5 | STA zp_fwa_sign ; (store) | ||||||||||||
| A6F7 | SEC ; result exponent = dividend - divisor: | ||||||||||||
| A6F8 | LDA zp_fwa_exp ; dividend exp... | ||||||||||||
| A6FA | SBC zp_fwb_exp ; minus divisor exp | ||||||||||||
| A6FC | BCS div_rebias ; no borrow | ||||||||||||
| A6FE | DEC zp_fwa_ovf ; borrow into overflow | ||||||||||||
| A700 | SEC ; (set carry again) | ||||||||||||
| A701 | .div_rebias←1← A6FC BCS | ||||||||||||
| ADC #&80 ; re-bias the exponent | |||||||||||||
| A703 | STA zp_fwa_exp ; (store) | ||||||||||||
| A705 | BCC div_quotient ; no carry | ||||||||||||
| A707 | INC zp_fwa_ovf ; carry into overflow | ||||||||||||
| A709 | CLC ; (clear carry) | ||||||||||||
| A70A | .div_quotient←1← A705 BCC | ||||||||||||
| LDX #&20 ; 32 quotient bits (restoring long division): | |||||||||||||
| A70C | .div_cmp1←1← A750 BNE | ||||||||||||
| BCS div_sub1 ; remainder >= divisor? | |||||||||||||
| A70E | LDA zp_fwa_m1 ; compare FWA (remainder) with FWB (divisor): | ||||||||||||
| A710 | CMP zp_fwb_m1 ; vs divisor m1, | ||||||||||||
| A712 | BNE div_bit0_1 ; differ: decided | ||||||||||||
| A714 | LDA zp_fwa_m2 ; else m2... | ||||||||||||
| A716 | CMP zp_fwb_m2 ; vs m2, | ||||||||||||
| A718 | BNE div_bit0_1 ; differ: decided | ||||||||||||
| A71A | LDA zp_fwa_m3 ; else m3... | ||||||||||||
| A71C | CMP zp_fwb_m3 ; vs m3, | ||||||||||||
| A71E | BNE div_bit0_1 ; differ: decided | ||||||||||||
| A720 | LDA zp_fwa_m4 ; else m4... | ||||||||||||
| A722 | CMP zp_fwb_m4 ; vs m4 | ||||||||||||
| A724 | .div_bit0_1←3← A712 BNE← A718 BNE← A71E BNE | ||||||||||||
| BCC div_shift1 ; less: quotient bit 0 | |||||||||||||
| A726 | .div_sub1←1← A70C BCS | ||||||||||||
| LDA zp_fwa_m4 ; subtract the divisor from the remainder: | |||||||||||||
| A728 | SBC zp_fwb_m4 ; - divisor m4, | ||||||||||||
| A72A | STA zp_fwa_m4 ; (store) | ||||||||||||
| A72C | LDA zp_fwa_m3 ; m3... | ||||||||||||
| A72E | SBC zp_fwb_m3 ; - divisor m3, | ||||||||||||
| A730 | STA zp_fwa_m3 ; (store) | ||||||||||||
| A732 | LDA zp_fwa_m2 ; m2... | ||||||||||||
| A734 | SBC zp_fwb_m2 ; - divisor m2, | ||||||||||||
| A736 | STA zp_fwa_m2 ; (store) | ||||||||||||
| A738 | LDA zp_fwa_m1 ; m1... | ||||||||||||
| A73A | SBC zp_fwb_m1 ; - divisor m1, | ||||||||||||
| A73C | STA zp_fwa_m1 ; (store) | ||||||||||||
| A73E | SEC ; quotient bit 1 | ||||||||||||
| A73F | .div_shift1←1← A724 BCC | ||||||||||||
| ROL zp_fp_temp_3 ; shift the quotient left, bring in the bit: | |||||||||||||
| A741 | ROL zp_fp_temp_2 ; through &45, | ||||||||||||
| A743 | ROL zp_fp_temp_1 ; &44, | ||||||||||||
| A745 | ROL zp_fp_temp ; &43 (high) | ||||||||||||
| A747 | ASL zp_fwa_m4 ; shift the remainder left: | ||||||||||||
| A749 | ROL zp_fwa_m3 ; m3, | ||||||||||||
| A74B | ROL zp_fwa_m2 ; m2, | ||||||||||||
| A74D | ROL zp_fwa_m1 ; m1 | ||||||||||||
| A74F | DEX ; count | ||||||||||||
| A750 | BNE div_cmp1 ; loop 32 times | ||||||||||||
| A752 | LDX #7 ; 7 guard bits: | ||||||||||||
| A754 | .div_cmp2←1← A792 BNE | ||||||||||||
| BCS div_sub2 ; remainder >= divisor? | |||||||||||||
| A756 | LDA zp_fwa_m1 ; compare remainder vs divisor: m1... | ||||||||||||
| A758 | CMP zp_fwb_m1 ; vs m1, | ||||||||||||
| A75A | BNE div_bit0_2 ; differ: decided | ||||||||||||
| A75C | LDA zp_fwa_m2 ; else m2... | ||||||||||||
| A75E | CMP zp_fwb_m2 ; vs m2, | ||||||||||||
| A760 | BNE div_bit0_2 ; differ: decided | ||||||||||||
| A762 | LDA zp_fwa_m3 ; else m3... | ||||||||||||
| A764 | CMP zp_fwb_m3 ; vs m3, | ||||||||||||
| A766 | BNE div_bit0_2 ; differ: decided | ||||||||||||
| A768 | LDA zp_fwa_m4 ; else m4... | ||||||||||||
| A76A | CMP zp_fwb_m4 ; vs m4 | ||||||||||||
| A76C | .div_bit0_2←3← A75A BNE← A760 BNE← A766 BNE | ||||||||||||
| BCC div_shift2 ; less: bit 0 | |||||||||||||
| A76E | .div_sub2←1← A754 BCS | ||||||||||||
| LDA zp_fwa_m4 ; subtract: | |||||||||||||
| A770 | SBC zp_fwb_m4 ; - divisor m4, | ||||||||||||
| A772 | STA zp_fwa_m4 ; (store) | ||||||||||||
| A774 | LDA zp_fwa_m3 ; m3... | ||||||||||||
| A776 | SBC zp_fwb_m3 ; - divisor m3, | ||||||||||||
| A778 | STA zp_fwa_m3 ; (store) | ||||||||||||
| A77A | LDA zp_fwa_m2 ; m2... | ||||||||||||
| A77C | SBC zp_fwb_m2 ; - divisor m2, | ||||||||||||
| A77E | STA zp_fwa_m2 ; (store) | ||||||||||||
| A780 | LDA zp_fwa_m1 ; m1... | ||||||||||||
| A782 | SBC zp_fwb_m1 ; - divisor m1, | ||||||||||||
| A784 | STA zp_fwa_m1 ; (store) | ||||||||||||
| A786 | SEC ; guard bit 1 | ||||||||||||
| A787 | .div_shift2←1← A76C BCC | ||||||||||||
| ROL zp_fwa_rnd ; shift in the guard bit | |||||||||||||
| A789 | ASL zp_fwa_m4 ; shift the remainder: | ||||||||||||
| A78B | ROL zp_fwa_m3 ; m3, | ||||||||||||
| A78D | ROL zp_fwa_m2 ; m2, | ||||||||||||
| A78F | ROL zp_fwa_m1 ; m1 | ||||||||||||
| A791 | DEX ; count | ||||||||||||
| A792 | BNE div_cmp2 ; loop | ||||||||||||
| A794 | ASL zp_fwa_rnd ; final guard bit | ||||||||||||
| A796 | LDA zp_fp_temp_3 ; move the quotient into the FWA mantissa: | ||||||||||||
| A798 | STA zp_fwa_m4 ; -> m4, | ||||||||||||
| A79A | LDA zp_fp_temp_2 ; &45... | ||||||||||||
| A79C | STA zp_fwa_m3 ; -> m3, | ||||||||||||
| A79E | LDA zp_fp_temp_1 ; &44... | ||||||||||||
| A7A0 | STA zp_fwa_m2 ; -> m2, | ||||||||||||
| A7A2 | LDA zp_fp_temp ; &43... | ||||||||||||
| A7A4 | STA zp_fwa_m1 ; -> m1 | ||||||||||||
| A7A6 | JMP mulf_normalise ; normalise and round | ||||||||||||
| A7A9 | .sqr_neg_error←1← A7BC BMI | ||||||||||||
| BRK ; SQR of a negative: error block | |||||||||||||
| A7AA | EQUB &15 | ||||||||||||
| A7AB | EQUS "-ve root" | ||||||||||||
| A7B3 | EQUB &00 | ||||||||||||
SQRFWA = square root of FWA. Pure routine at &A7B7.
|
|||||||||||||||
| A7B4 | .fn_sqr | ||||||||||||||
| JSR eval_real ; Evaluate the argument as a real | |||||||||||||||
| A7B7 | .sqr_sign←1← A9C0 JMP | ||||||||||||||
| JSR fwa_sign ; Sign of the argument | |||||||||||||||
| A7BA | BEQ sqr_done ; zero: the root is zero | ||||||||||||||
| A7BC | BMI sqr_neg_error ; negative: -ve root error | ||||||||||||||
| A7BE | JSR fwa_pack_temp1 ; Save the argument in TEMP1 | ||||||||||||||
| A7C1 | LDA zp_fwa_exp ; Initial guess: halve the exponent | ||||||||||||||
| A7C3 | LSR ; halve the exponent | ||||||||||||||
| A7C4 | ADC #&40 ; (re-bias) | ||||||||||||||
| A7C6 | STA zp_fwa_exp ; store the guess exponent | ||||||||||||||
| A7C8 | LDA #5 ; 5 Newton iterations | ||||||||||||||
| A7CA | STA zp_int_exp ; (counter) | ||||||||||||||
| A7CC | JSR point_fp_temp2 ; point at TEMP2 (the guess) | ||||||||||||||
| A7CF | .sqr_iter_loop←1← A7E4 BNE | ||||||||||||||
| JSR fwa_pack_var ; save the current guess | |||||||||||||||
| A7D2 | LDA #&6c ; point at TEMP1 (the argument) | ||||||||||||||
| A7D4 | STA zp_fp_ptr ; store the pointer low | ||||||||||||||
| A7D6 | JSR fwa_rdiv_var ; FWA = argument / guess | ||||||||||||||
| A7D9 | LDA #&71 ; point at TEMP2 (the guess) | ||||||||||||||
| A7DB | STA zp_fp_ptr ; store the pointer low | ||||||||||||||
| A7DD | JSR fwa_add_var ; FWA = arg/guess + guess | ||||||||||||||
| A7E0 | DEC zp_fwa_exp ; halve it: next guess | ||||||||||||||
| A7E2 | DEC zp_int_exp ; count | ||||||||||||||
| A7E4 | BNE sqr_iter_loop ; iterate | ||||||||||||||
| A7E6 | .sqr_done←1← A7BA BEQ | ||||||||||||||
| LDA #&ff ; real result | |||||||||||||||
| A7E8 | RTS ; Return the root | ||||||||||||||
Point zp_fp_ptr at FP TEMP4 (&047B)Set zp_fp_ptr to FP TEMP4, ready for a pack/unpack.
|
||||||||
| A7E9 | .point_fp_temp4←4← A6C7 JSR← A6D2 JSR← A6DE JSR← A83F JSR | |||||||
| LDA #&7b ; TEMP4 low (&7B) | ||||||||
| A7EB | BNE set_fp_ptr ; set it (shared tail) | |||||||
| fall through ↓ | ||||||||
Point zp_fp_ptr at FP TEMP2 (&0471)Set zp_fp_ptr to FP TEMP2, ready for a pack/unpack.
|
||||||||
| A7ED | .point_fp_temp2←3← 9E7E JSR← A7CC JSR← AA23 JSR | |||||||
| LDA #&71 ; TEMP2 low (&71) | ||||||||
| A7EF | BNE set_fp_ptr ; set it (shared tail) | |||||||
| fall through ↓ | ||||||||
Point zp_fp_ptr at FP TEMP3 (&0476)Set zp_fp_ptr to FP TEMP3, ready for a pack/unpack.
|
||||||||
| A7F1 | .point_fp_temp3←2← A8F5 JSR← AAD1 JSR | |||||||
| LDA #&76 ; TEMP3 low (&76) | ||||||||
| A7F3 | BNE set_fp_ptr ; set it (shared tail) | |||||||
| fall through ↓ | ||||||||
Point zp_fp_ptr at FP TEMP1 (&046C)Set zp_fp_ptr to FP TEMP1, ready for a pack/unpack.
|
||||||||
| A7F5 | .point_fp_temp1←6← 9F71 JSR← A3B2 JSR← A860 JSR← A8B5 JSR← AA1A JSR← AA2F JSR | |||||||
| LDA #&6c ; TEMP1 low (&6C) | ||||||||
| A7F7 | .set_fp_ptr←3← A7EB BNE← A7EF BNE← A7F3 BNE | |||||||
| STA zp_fp_ptr ; set the pointer low | ||||||||
| A7F9 | LDA #4 ; high &04 | |||||||
| A7FB | STA zp_fp_ptr_1 ; pointer high | |||||||
| A7FD | RTS ; Return | |||||||
LNFWA = natural log of FWA. Pure routine at &A801.
|
|||||||||||||||
| A7FE | .fn_ln←1← ABA8 JSR | ||||||||||||||
| JSR eval_real ; Evaluate the argument as a real | |||||||||||||||
| A801 | .ln_compute←1← 9E75 JSR | ||||||||||||||
| JSR fwa_sign ; Sign of x | |||||||||||||||
| A804 | BEQ log_range_error ; zero: error | ||||||||||||||
| A806 | BPL ln_setup ; positive: compute | ||||||||||||||
| A808 | .log_range_error←1← A804 BEQ | ||||||||||||||
| BRK ; zero or negative: Log range error | |||||||||||||||
| A809 | EQUB &16 | ||||||||||||||
| A80A | EQUS "Log range" | ||||||||||||||
| A813 | EQUB &00 | ||||||||||||||
| A814 | .ln_setup←1← A806 BPL | ||||||||||||||
| JSR fwb_clear ; Set FWB = -1 (to form mantissa - 1) | |||||||||||||||
| A817 | LDY #&80 ; Y = &80, | ||||||||||||||
| A819 | STY zp_fwb_sign ; sign = negative, | ||||||||||||||
| A81B | STY zp_fwb_m1 ; mantissa top = &80, | ||||||||||||||
| A81D | INY ; Y = &81, | ||||||||||||||
| A81E | STY zp_fwb_exp ; exponent = &81 (value -1.0) | ||||||||||||||
| A820 | LDX zp_fwa_exp ; Binary exponent of x | ||||||||||||||
| A822 | BEQ ln_scale ; zero mantissa exponent? | ||||||||||||||
| A824 | LDA zp_fwa_m1 ; Mantissa top byte | ||||||||||||||
| A826 | CMP #&b5 ; below sqrt(2)? | ||||||||||||||
| A828 | BCC ln_save_exp ; yes: keep this exponent | ||||||||||||||
| A82A | .ln_scale←1← A822 BEQ | ||||||||||||||
| INX ; no: scale mantissa to [sqrt(1/2), sqrt(2)] | |||||||||||||||
| A82B | DEY ; ...and adjust the exponent | ||||||||||||||
| A82C | .ln_save_exp←1← A828 BCC | ||||||||||||||
| TXA ; Save the adjusted binary exponent | |||||||||||||||
| A82D | PHA ; push it | ||||||||||||||
| A82E | STY zp_fwa_exp ; Set the mantissa exponent | ||||||||||||||
| A830 | JSR fwa_add_fwb ; FWA = mantissa - 1 | ||||||||||||||
| A833 | LDA #&7b ; Save (m-1) in TEMP4 | ||||||||||||||
| A835 | JSR pack_temp_tail ; pack FWA there | ||||||||||||||
| A838 | LDA #&73 ; Point at the ln coefficient table: low byte | ||||||||||||||
| A83A | LDY #&a8 ; ...high | ||||||||||||||
| A83C | JSR fp_eval_cont_frac ; Evaluate the ln continued fraction | ||||||||||||||
| A83F | JSR point_fp_temp4 ; Point at (m-1) in TEMP4 | ||||||||||||||
| A842 | JSR fwa_mul_var ; Scale by (m-1)... | ||||||||||||||
| A845 | JSR fwa_mul_var ; ...and again | ||||||||||||||
| A848 | JSR fwa_add_var ; Add (m-1): FWA = ln(mantissa) | ||||||||||||||
| A84B | JSR fwa_pack_temp1 ; Save ln(mantissa) in TEMP1 | ||||||||||||||
| A84E | PLA ; Recover the adjusted exponent | ||||||||||||||
| A84F | SEC ; set carry for the subtract | ||||||||||||||
| A850 | SBC #&81 ; Binary exponent e = adjusted - &81 | ||||||||||||||
| A852 | JSR small_int_to_fwa ; FWA = e | ||||||||||||||
| A855 | LDA #&6e ; Point at the constant ln 2: low byte | ||||||||||||||
| A857 | STA zp_fp_ptr ; store the pointer low | ||||||||||||||
| A859 | LDA #&a8 ; high byte | ||||||||||||||
| A85B | STA zp_fp_ptr_1 ; store the pointer high | ||||||||||||||
| A85D | JSR fwa_mul_var ; FWA = e * ln 2 | ||||||||||||||
| A860 | JSR point_fp_temp1 ; Point at ln(mantissa) in TEMP1 | ||||||||||||||
| A863 | JSR fwa_add_var ; LN(x) = e*ln2 + ln(mantissa) | ||||||||||||||
| A866 | LDA #&ff ; real result | ||||||||||||||
| A868 | RTS ; Return | ||||||||||||||
| A869 | EQUB &7F, &5E, &5B, ; float40 0.434294482 log10(e) = &D8, &AA ; 1/ln(10) | ||||||||||||||
| A86E | EQUB &80, &31, &72, &17, &F8 ; float40 0.6931471806 ln 2 | ||||||||||||||
| A873 | EQUB &06 | ||||||||||||||
| A874 | EQUB &7A, &12, &38, &A5, &0B ; float40 0.008924637961 ln c0 | ||||||||||||||
| A879 | EQUB &88, &79, &0E, &9F, &F3 ; float40 249.0571281 ln c1 | ||||||||||||||
| A87E | EQUB &7C, &2A, &AC, &3F, &B5 ; float40 0.04166817556 ln c2 | ||||||||||||||
| A883 | EQUB &86, &34, &01, &A2, &7A ; float40 45.00159636 ln c3 | ||||||||||||||
| A888 | EQUB &7F, &63, &8E, &37, &EC ; float40 0.4444444156 ln c4 | ||||||||||||||
| A88D | EQUB &82, &3F, &FF, &FF, &C1 ; float40 2.999999941 ln c5 | ||||||||||||||
| A892 | EQUB &7F, &FF, &FF, &FF, &FF ; float40 -0.4999999999 -0.5 | ||||||||||||||
Evaluate a continued-fraction approximationA (low) and Y (high) point at a coefficient table: a count byte followed by that many five-byte fp coefficients. The argument is stashed in TEMP1; the routine folds the table from the top, alternating FWA = arg / FWA and FWA = FWA + next coefficient, to evaluate the continued fraction used by the trig kernels.
|
|||||||||||||
| A897 | .fp_eval_cont_frac←4← A83C JSR← A951 JSR← A9CD JSR← AADE JSR | ||||||||||||
| STA zp_coeff_ptr ; Save the coefficient table pointer (low) | |||||||||||||
| A899 | STY zp_coeff_ptr_1 ; ...and high | ||||||||||||
| A89B | JSR fwa_pack_temp1 ; Stash the argument in TEMP1 | ||||||||||||
| A89E | LDY #0 ; First table byte is the coefficient count | ||||||||||||
| A8A0 | LDA (zp_coeff_ptr),y ; read it | ||||||||||||
| A8A2 | STA zp_dp_flag ; use it as the loop counter | ||||||||||||
| A8A4 | INC zp_coeff_ptr ; Advance past the count byte to coefficient 0 | ||||||||||||
| A8A6 | BNE cfrac_first ; no carry into the high byte | ||||||||||||
| A8A8 | INC zp_coeff_ptr_1 ; else bump the high byte | ||||||||||||
| A8AA | .cfrac_first←1← A8A6 BNE | ||||||||||||
| LDA zp_coeff_ptr ; Point the fp pointer at the first coefficient | |||||||||||||
| A8AC | STA zp_fp_ptr ; low byte -> fp_ptr | ||||||||||||
| A8AE | LDA zp_coeff_ptr_1 ; high byte | ||||||||||||
| A8B0 | STA zp_fp_ptr_1 ; -> fp_ptr+1 | ||||||||||||
| A8B2 | JSR fwa_unpack_var ; FWA = coefficient 0 | ||||||||||||
| A8B5 | .cfrac_loop←1← A8D1 BNE | ||||||||||||
| JSR point_fp_temp1 ; Point at the argument in TEMP1 | |||||||||||||
| A8B8 | JSR fwa_rdiv_var ; FWA = arg / FWA | ||||||||||||
| A8BB | CLC ; Advance the pointer to the next coefficient | ||||||||||||
| A8BC | LDA zp_coeff_ptr ; ...(five bytes per coefficient) | ||||||||||||
| A8BE | ADC #5 ; low byte + 5 | ||||||||||||
| A8C0 | STA zp_coeff_ptr ; store the table pointer low | ||||||||||||
| A8C2 | STA zp_fp_ptr ; and the fp pointer low | ||||||||||||
| A8C4 | LDA zp_coeff_ptr_1 ; high byte | ||||||||||||
| A8C6 | ADC #0 ; plus any carry | ||||||||||||
| A8C8 | STA zp_coeff_ptr_1 ; store the table pointer high | ||||||||||||
| A8CA | STA zp_fp_ptr_1 ; and the fp pointer high | ||||||||||||
| A8CC | JSR fwa_add_var ; FWA = FWA + next coefficient | ||||||||||||
| A8CF | DEC zp_dp_flag ; One coefficient done | ||||||||||||
| A8D1 | BNE cfrac_loop ; loop until the table is exhausted | ||||||||||||
| A8D3 | RTS ; Return the continued-fraction value | ||||||||||||
ACSFWA = arccos(FWA), result in radians. Computed as arcsin then adjusted at &A927.
|
|||||||||||||||
| A8D4 | .fn_acs | ||||||||||||||
| JSR fn_asn ; Compute asn(x) | |||||||||||||||
| A8D7 | JMP fwa_complement_half_pi ; Result = pi/2 - asn(x) | ||||||||||||||
ASNFWA = arcsin(FWA), result in radians. Pure routine at &A8DD.
|
|||||||||||||||
| A8DA | .fn_asn←1← A8D4 JSR | ||||||||||||||
| JSR eval_real ; Evaluate the argument as a real | |||||||||||||||
| A8DD | JSR fwa_sign ; Sign of the argument | ||||||||||||||
| A8E0 | BPL asn_save ; positive: compute directly | ||||||||||||||
| A8E2 | LSR zp_fwa_sign ; negative: take |x|... | ||||||||||||||
| A8E4 | JSR asn_save ; compute asn(|x|) | ||||||||||||||
| A8E7 | JMP atn_neg ; ...and negate the result | ||||||||||||||
| A8EA | .asn_save←2← A8E0 BPL← A8E4 JSR | ||||||||||||||
| JSR fwa_pack_temp3 ; Save x in TEMP3 | |||||||||||||||
| A8ED | JSR sin_series ; compute sqrt(1 - x^2) | ||||||||||||||
| A8F0 | JSR fwa_sign ; is it zero (x = 1)? | ||||||||||||||
| A8F3 | BEQ asn_one ; yes: result is pi/2 | ||||||||||||||
| A8F5 | JSR point_fp_temp3 ; point at x (TEMP3) | ||||||||||||||
| A8F8 | JSR fwa_rdiv_var ; FWA = x / sqrt(1 - x^2) | ||||||||||||||
| A8FB | JMP atn_sign ; asn(x) = atn(that) | ||||||||||||||
| A8FE | .asn_one←2← A8F3 BEQ← ABCB JSR | ||||||||||||||
| JSR point_const_half_pi ; x = 1: load pi/2 | |||||||||||||||
| A901 | JSR fwa_unpack_var ; unpack pi/2 into FWA | ||||||||||||||
| A904 | .asn_done←2← A90D BEQ← A93A BCC | ||||||||||||||
| LDA #&ff ; real result | |||||||||||||||
| A906 | RTS ; Return | ||||||||||||||
ATNFWA = arctan(FWA), result in radians. Pure routine at &A90A.
|
|||||||||||||||
| A907 | .fn_atn | ||||||||||||||
| JSR eval_real ; Evaluate the argument as a real | |||||||||||||||
| A90A | .atn_sign←1← A8FB JMP | ||||||||||||||
| JSR fwa_sign ; Sign of the argument | |||||||||||||||
| A90D | BEQ asn_done ; zero: atn(0) = 0, return it | ||||||||||||||
| A90F | BPL atn_large ; positive: compute directly | ||||||||||||||
| A911 | LSR zp_fwa_sign ; negative: clear the sign to take |x| | ||||||||||||||
| A913 | JSR atn_large ; compute atn(|x|) | ||||||||||||||
| A916 | .atn_neg←1← A8E7 JMP | ||||||||||||||
| LDA #&80 ; set the result sign negative | |||||||||||||||
| A918 | STA zp_fwa_sign ; ...so atn(-x) = -atn(x) | ||||||||||||||
| A91A | RTS ; Return | ||||||||||||||
| A91B | .atn_large←2← A90F BPL← A913 JSR | ||||||||||||||
| LDA zp_fwa_exp ; Exponent of |x| | |||||||||||||||
| A91D | CMP #&81 ; |x| < 1? | ||||||||||||||
| A91F | BCC chp_exp ; yes: evaluate the series directly | ||||||||||||||
| A921 | JSR fwa_reciprocal ; |x| >= 1: FWA = 1 / x | ||||||||||||||
| A924 | JSR chp_exp ; atn(1/x) via the series | ||||||||||||||
| fall through ↓ | |||||||||||||||
FWA = pi/2 - FWASubtract FWA from pi/2 using the two-part constant at &AA59/&AA5E for extra precision, then negate. Used for ACS (pi/2 - ASN) and the large-argument arctan identity atn(x) = pi/2 - atn(1/x).
|
|||||||||
| A927 | .fwa_complement_half_pi←1← A8D7 JMP | ||||||||
| JSR point_half_pi_hi ; atn(x) = pi/2 - atn(1/x) | |||||||||
| A92A | JSR fwa_add_var ; add the high part of pi/2 | ||||||||
| A92D | JSR point_half_pi_lo ; point at the low part | ||||||||
| A930 | JSR fwa_add_var ; add the low part | ||||||||
| A933 | JMP fwa_negate ; negate: result is pi/2 - FWA (tail) | ||||||||
| A936 | .chp_exp←2← A91F BCC← A924 JSR | ||||||||
| LDA zp_fwa_exp ; Exponent of the (reduced) argument | |||||||||
| A938 | CMP #&73 ; very small (|x| < 2^-13)? | ||||||||
| A93A | BCC asn_done ; yes: atn(x) = x to working precision | ||||||||
| A93C | JSR fwa_pack_temp3 ; Save the argument x in TEMP3 | ||||||||
| A93F | JSR fwb_clear ; Set FWB = 1... | ||||||||
| A942 | LDA #&80 ; the constant &80 | ||||||||
| A944 | STA zp_fwb_exp ; exponent, | ||||||||
| A946 | STA zp_fwb_m1 ; mantissa top byte, | ||||||||
| A948 | STA zp_fwb_sign ; and sign byte | ||||||||
| A94A | JSR fwa_add_fwb ; Add it to the argument | ||||||||
| A94D | LDA #&5a ; Evaluate the arctan continued fraction | ||||||||
| A94F | LDY #&a9 ; (coefficients at &A95A) | ||||||||
| A951 | JSR fp_eval_cont_frac ; evaluate the fraction | ||||||||
| A954 | JSR mul_by_temp3 ; Scale by x (in TEMP3): atn(x) = x * P | ||||||||
| A957 | LDA #&ff ; real result | ||||||||
| A959 | RTS ; Return | ||||||||
| A95A | EQUB &09 | ||||||||
| A95B | EQUB &85, &A3, &59, &E8, &67 ; float40 -20.4189003 atn c0 | ||||||||
| A960 | EQUB &80, &1C, &9D, &07, &36 ; float40 0.6117710597 atn c1 | ||||||||
| A965 | EQUB &80, &57, &BB, &78, &DF ; float40 0.842704348 atn c2 | ||||||||
| A96A | EQUB &80, &CA, &9A, &0E, &83 ; float40 -0.7914132185 atn c3 | ||||||||
| A96F | EQUB &84, &8C, &BB, &CA, &6E ; float40 -8.795847349 atn c4 | ||||||||
| A974 | EQUB &81, &95, &96, &06, &DE ; float40 -1.168640955 atn c5 | ||||||||
| A979 | EQUB &81, &0A, &C7, &6C, &52 ; float40 1.084210911 atn c6 | ||||||||
| A97E | EQUB &7F, &7D, &AD, &90, &A1 ; float40 0.4954648205 atn c7 | ||||||||
| A983 | EQUB &82, &FB, &62, &57, &2F ; float40 -3.927877232 atn c8 | ||||||||
| A988 | EQUB &80, &6D, &63, &38, &2C ; float40 0.9272952182 | ||||||||
COSFWA = cos(FWA), argument in radians. Pure routine at &A990.
|
|||||||||||||||
| A98D | .fn_cos | ||||||||||||||
| JSR eval_real ; Evaluate the argument as a real | |||||||||||||||
| A990 | JSR sin_cos_reduce ; Compute the SIN/COS kernel | ||||||||||||||
| A993 | INC zp_int_exp ; Shift the quadrant: cos x = sin(x + pi/2) | ||||||||||||||
| A995 | JMP sin_quadrant ; Finish (shared with SIN) | ||||||||||||||
SINFWA = sin(FWA), argument in radians. Pure routine at &A99B.
|
|||||||||||||||
| A998 | .fn_sin | ||||||||||||||
| JSR eval_real ; Evaluate the argument as a real | |||||||||||||||
| A99B | JSR sin_cos_reduce ; Range-reduce: leaves the angle in FWA, quadrant in &4A | ||||||||||||||
| A99E | .sin_quadrant←3← A6CF JSR← A6DB JSR← A995 JMP | ||||||||||||||
| LDA zp_int_exp ; Quadrant | |||||||||||||||
| A9A0 | AND #2 ; second or third quadrant (result negative)? | ||||||||||||||
| A9A2 | BEQ sin_odd_quad ; no: compute and return directly | ||||||||||||||
| A9A4 | JSR sin_odd_quad ; compute the magnitude... | ||||||||||||||
| A9A7 | JMP fwa_negate ; ...then negate it | ||||||||||||||
| A9AA | .sin_odd_quad←2← A9A2 BEQ← A9A4 JSR | ||||||||||||||
| LSR zp_int_exp ; Odd quadrant (use cosine instead of sine)? | |||||||||||||||
| A9AC | BCC sin_save_r ; even: evaluate the sine series | ||||||||||||||
| A9AE | JSR sin_save_r ; odd: evaluate the sine series... | ||||||||||||||
| A9B1 | .sin_series←1← A8ED JSR | ||||||||||||||
| JSR fwa_pack_temp1 ; Save sin into TEMP1 | |||||||||||||||
| A9B4 | JSR fwa_mul_var ; FWA = sin^2 | ||||||||||||||
| A9B7 | JSR fwa_pack_var ; save sin^2 to the work var | ||||||||||||||
| A9BA | JSR fwa_set_one ; FWA = 1 | ||||||||||||||
| A9BD | JSR fwa_sub_var ; FWA = 1 - sin^2 | ||||||||||||||
| A9C0 | JMP sqr_sign ; cos = sqrt(1 - sin^2) | ||||||||||||||
| A9C3 | .sin_save_r←2← A9AC BCC← A9AE JSR | ||||||||||||||
| JSR fwa_pack_temp3 ; Save the reduced angle r in TEMP3 | |||||||||||||||
| A9C6 | JSR fwa_mul_var ; FWA = r^2 | ||||||||||||||
| A9C9 | LDA #&72 ; Point at the sine coefficient table: low byte | ||||||||||||||
| A9CB | LDY #&aa ; ...high | ||||||||||||||
| A9CD | JSR fp_eval_cont_frac ; Evaluate the sine continued fraction in r^2 | ||||||||||||||
| A9D0 | JMP mul_by_temp3 ; Scale by r (in TEMP3): sin(r) = r * P | ||||||||||||||
Range-reduce the SIN/COS argumentDivide the argument by pi/2 to find the quadrant (stored in &4A) and Cody-Waite reduce to the principal range using the two-part pi/2 constant, leaving the reduced angle in FWA for the series. Errors if the argument is too large to reduce.
|
|||||||||||
| A9D3 | .sin_cos_reduce←3← A6C1 JSR← A990 JSR← A99B JSR | ||||||||||
| LDA zp_fwa_exp ; Exponent of the argument | |||||||||||
| A9D5 | CMP #&98 ; too large to reduce accurately? | ||||||||||
| A9D7 | BCS reduce_too_big ; yes: report the error | ||||||||||
| A9D9 | JSR fwa_pack_temp1 ; Save the argument in TEMP1 | ||||||||||
| A9DC | JSR point_const_half_pi ; Point at pi/2... | ||||||||||
| A9DF | JSR fwb_unpack_var ; ...and unpack it into FWB | ||||||||||
| A9E2 | LDA zp_fwa_sign ; Take the argument sign... | ||||||||||
| A9E4 | STA zp_fwb_sign ; ...for FWB | ||||||||||
| A9E6 | DEC zp_fwb_exp ; Halve FWB to +/- pi/4 (rounding bias) | ||||||||||
| A9E8 | JSR fwa_add_fwb ; FWA = argument +/- pi/4 | ||||||||||
| A9EB | JSR fp_divide ; FWA = that / (pi/2): integer part is the quadrant | ||||||||||
| A9EE | JSR fwa_to_int2 ; Take the integer part | ||||||||||
| A9F1 | LDA zp_fwa_m4 ; Low byte of the quadrant count | ||||||||||
| A9F3 | STA zp_int_exp ; save it in &4A | ||||||||||
| A9F5 | ORA zp_fwa_m3 ; Is the whole quadrant count zero? | ||||||||||
| A9F7 | ORA zp_fwa_m2 ; or byte 2, | ||||||||||
| A9F9 | ORA zp_fwa_m1 ; or byte 1 | ||||||||||
| A9FB | BEQ reduce_in_range ; yes: argument already in range, use it as is | ||||||||||
| A9FD | LDA #&a0 ; Rebuild the quadrant count as a real: exponent | ||||||||||
| A9FF | STA zp_fwa_exp ; set it | ||||||||||
| AA01 | LDY #0 ; clear the rounding byte | ||||||||||
| AA03 | STY zp_fwa_rnd ; store it | ||||||||||
| AA05 | LDA zp_fwa_m1 ; Sign of the count | ||||||||||
| AA07 | STA zp_fwa_sign ; into the sign byte | ||||||||||
| AA09 | BPL reduce_norm_quad ; positive: skip | ||||||||||
| AA0B | JSR fti2_negate ; negative: negate the mantissa | ||||||||||
| AA0E | .reduce_norm_quad←1← AA09 BPL | ||||||||||
| JSR fwa_normalise ; Normalise the quadrant count | |||||||||||
| AA11 | JSR fwa_pack_temp2 ; Save it in TEMP2 | ||||||||||
| AA14 | JSR point_half_pi_hi ; Cody-Waite reduce: FWA = count * (pi/2 high part) | ||||||||||
| AA17 | JSR fwa_mul_var ; multiply by it | ||||||||||
| AA1A | JSR point_fp_temp1 ; FWA = argument - count*(pi/2 high) | ||||||||||
| AA1D | JSR fwa_add_var ; add the argument | ||||||||||
| AA20 | JSR fwa_pack_var ; Save the partial reduction in TEMP1 | ||||||||||
| AA23 | JSR point_fp_temp2 ; Reload the quadrant count | ||||||||||
| AA26 | JSR fwa_unpack_var ; into FWA | ||||||||||
| AA29 | JSR point_half_pi_lo ; FWA = count * (pi/2 low part) | ||||||||||
| AA2C | JSR fwa_mul_var ; multiply by it | ||||||||||
| AA2F | JSR point_fp_temp1 ; Subtract the low part too: FWA = reduced angle | ||||||||||
| AA32 | JMP fwa_add_var ; add it (tail call) | ||||||||||
| AA35 | .reduce_in_range←1← A9FB BEQ | ||||||||||
| JMP fwa_unpack_temp1 ; Argument in range: reduced angle is the argument | |||||||||||
| AA38 | .reduce_too_big←1← A9D7 BCS | ||||||||||
| BRK ; Argument too large: error | |||||||||||
| AA39 | EQUB &17 | ||||||||||
| AA3A | EQUS "Accuracy lost" | ||||||||||
| AA47 | EQUB &00 | ||||||||||
Point the fp pointer at the high part of pi/2 (&AA59)Set zp_fp_ptr to the high half of the extended-precision pi/2 constant, ready to unpack.
|
||||||||
| AA48 | .point_half_pi_hi←2← A927 JSR← AA14 JSR | |||||||
| LDA #&59 ; High part of pi/2: low byte | ||||||||
| AA4A | BNE set_pi_ptr ; ...(shared tail) | |||||||
| fall through ↓ | ||||||||
Point the fp pointer at the low part of pi/2 (&AA5E)Set zp_fp_ptr to the low half of the extended-precision pi/2 constant, ready to unpack.
|
||||||||
| AA4C | .point_half_pi_lo←2← A92D JSR← AA29 JSR | |||||||
| LDA #&5e ; Low part of pi/2: low byte | ||||||||
| AA4E | .set_pi_ptr←2← AA4A BNE← AA57 BNE | |||||||
| STA zp_fp_ptr ; Set the fp pointer low | ||||||||
| AA50 | LDA #&aa ; high &AA | |||||||
| AA52 | STA zp_fp_ptr_1 ; pointer high | |||||||
| AA54 | RTS ; Return | |||||||
Point the fp pointer at the pi/2 constant (&AA63)Set zp_fp_ptr to the packed pi/2 constant, ready to unpack (used by the range reduction in SIN/COS).
|
||||||||
| AA55 | .point_const_half_pi←2← A8FE JSR← A9DC JSR | |||||||
| LDA #&63 ; pi/2 constant: low byte | ||||||||
| AA57 | BNE set_pi_ptr ; ...(shared tail) | |||||||
| AA59 | EQUB &81, &C9, &10, ; float40 -1.570800781 pi/2, high part &00, &00 ; (Cody-Waite) | |||||||
| AA5E | EQUB &6F, &15, &77, ; float40 4.454455111e-06 pi/2, low &7A, &61 ; part (Cody-Waite) | |||||||
| AA63 | EQUB &81, &49, &0F, &DA, &A2 ; float40 1.570796327 pi/2 | |||||||
| AA68 | EQUB &7B, &0E, &FA, ; float40 0.01745329252 pi/180 (degrees &35, &12 ; -> radians, RAD) | |||||||
| AA6D | EQUB &86, &65, &2E, ; float40 57.29577951 180/pi (radians &E0, &D3 ; -> degrees, DEG) | |||||||
| AA72 | EQUB &05 | |||||||
| AA73 | EQUB &84, &8A, &EA, &0C, &1B ; float40 -8.682140451 sin c0 | |||||||
| AA78 | EQUB &84, &1A, &BE, &BB, &2B ; float40 9.671565216 sin c1 | |||||||
| AA7D | EQUB &84, &37, &45, &55, &AB ; float40 11.4544274 sin c2 | |||||||
| AA82 | EQUB &82, &D5, &55, &57, &7C ; float40 -3.333333846 sin c3 | |||||||
| AA87 | EQUB &83, &C0, &00, &00, &05 ; float40 -6.000000009 sin c4 | |||||||
| AA8C | EQUB &81, &00, &00, &00, &00 ; float40 1 1.0 | |||||||
| fall through ↓ | ||||||||
EXPFWA = e to the power FWA. Pure routine at &AA94.
|
|||||||||||||||
| AA91 | .fn_exp | ||||||||||||||
| JSR eval_real ; Evaluate the argument as a real | |||||||||||||||
| AA94 | .exp_compute←1← 9E7B JSR | ||||||||||||||
| LDA zp_fwa_exp ; Exponent of x | |||||||||||||||
| AA96 | CMP #&87 ; x small enough to compute directly? | ||||||||||||||
| AA98 | BCC exp_split ; yes: compute | ||||||||||||||
| AA9A | BNE exp_sign ; much too large: handle the overflow case | ||||||||||||||
| AA9C | LDY zp_fwa_m1 ; borderline: test the mantissa | ||||||||||||||
| AA9E | CPY #&b3 ; ...against the overflow threshold | ||||||||||||||
| AAA0 | BCC exp_split ; below it: still computable | ||||||||||||||
| AAA2 | .exp_sign←1← AA9A BNE | ||||||||||||||
| LDA zp_fwa_sign ; Sign of x | |||||||||||||||
| AAA4 | BPL exp_range_error ; x very negative: e^x underflows to 0 | ||||||||||||||
| AAA6 | JSR fwa_clear ; FWA = 0 | ||||||||||||||
| AAA9 | LDA #&ff ; real result | ||||||||||||||
| AAAB | RTS ; Return | ||||||||||||||
| AAAC | .exp_range_error←1← AAA4 BPL | ||||||||||||||
| BRK ; x very positive: Exp range error | |||||||||||||||
| AAAD | EQUB &18 | ||||||||||||||
| AAAE | EQUS "Exp range" | ||||||||||||||
| AAB7 | EQUB &00 | ||||||||||||||
| AAB8 | .exp_split←2← AA98 BCC← AAA0 BCC | ||||||||||||||
| JSR fp_split_int_frac ; Split x into integer (&4A) and fraction | |||||||||||||||
| AABB | JSR exp_coeff_table ; FWA = e^frac via the series | ||||||||||||||
| AABE | JSR fwa_pack_temp3 ; Save e^frac in TEMP3 | ||||||||||||||
| AAC1 | LDA #&e4 ; Point at the constant e: low byte | ||||||||||||||
| AAC3 | STA zp_fp_ptr ; store the pointer low | ||||||||||||||
| AAC5 | LDA #&aa ; high byte | ||||||||||||||
| AAC7 | STA zp_fp_ptr_1 ; store the pointer high | ||||||||||||||
| AAC9 | JSR fwa_unpack_var ; FWA = e | ||||||||||||||
| AACC | LDA zp_int_exp ; Integer part of x | ||||||||||||||
| AACE | JSR fwa_int_power ; FWA = e^int | ||||||||||||||
| AAD1 | .mul_by_temp3←3← 9E78 JSR← A954 JSR← A9D0 JMP | ||||||||||||||
| JSR point_fp_temp3 ; Point at the saved argument in TEMP3 | |||||||||||||||
| AAD4 | JSR fwa_mul_var ; FWA = series * argument | ||||||||||||||
| AAD7 | LDA #&ff ; real result | ||||||||||||||
| AAD9 | RTS ; Return | ||||||||||||||
| AADA | .exp_coeff_table←1← AABB JSR | ||||||||||||||
| LDA #&e9 ; Point at the coefficient table: low byte | |||||||||||||||
| AADC | LDY #&aa ; ...high | ||||||||||||||
| AADE | JSR fp_eval_cont_frac ; Evaluate the continued fraction | ||||||||||||||
| AAE1 | LDA #&ff ; real result | ||||||||||||||
| AAE3 | RTS ; Return | ||||||||||||||
| AAE4 | EQUB &82, &2D, &F8, &54, &58 ; float40 2.718281828 e | ||||||||||||||
| AAE9 | EQUB &07 | ||||||||||||||
| AAEA | EQUB &83, &E0, &20, &86, &5B ; float40 -7.003970316 exp c0 | ||||||||||||||
| AAEF | EQUB &82, &80, &53, &93, &B8 ; float40 -2.005101137 exp c1 | ||||||||||||||
| AAF4 | EQUB &83, &20, &00, &06, &A1 ; float40 5.000003161 exp c2 | ||||||||||||||
| AAF9 | EQUB &82, &00, &00, &21, &63 ; float40 2.00000796 exp c3 | ||||||||||||||
| AAFE | EQUB &82, &C0, &00, &00, &02 ; float40 -3.000000002 exp c4 | ||||||||||||||
| AB03 | EQUB &82, &80, &00, &00, &0C ; float40 -2.000000011 exp c5 | ||||||||||||||
| AB08 | EQUB &81, &00, &00, &00, &00 ; float40 1 exp c6 | ||||||||||||||
| AB0D | EQUB &81, &00, &00, &00, &00 ; float40 1 1.0 | ||||||||||||||
FWA = FWA ^ n (n in A)Raise FWA to an integer power by repeated multiplication; a negative exponent reciprocates first. Used by EXP to form e^(integer part).
|
|||||||||||
| AB12 | .fwa_int_power←3← 9E52 JSR← 9E69 JSR← AACE JSR | ||||||||||
| TAX ; Exponent n | |||||||||||
| AB13 | BPL intpow_loop ; positive? | ||||||||||
| AB15 | DEX ; negative: use |n| and reciprocate | ||||||||||
| AB16 | TXA ; n-1 into A | ||||||||||
| AB17 | EOR #&ff ; complement to give |n| | ||||||||||
| AB19 | PHA ; save the count | ||||||||||
| AB1A | JSR fwa_reciprocal ; FWA = 1 / FWA | ||||||||||
| AB1D | PLA ; restore the count | ||||||||||
| AB1E | .intpow_loop←1← AB13 BPL | ||||||||||
| PHA ; Save the count | |||||||||||
| AB1F | JSR fwa_pack_temp1 ; Stash the base in TEMP1 | ||||||||||
| AB22 | JSR fwa_set_one ; FWA = 1 (running product) | ||||||||||
| AB25 | .intpow_check←1← AB2F JMP | ||||||||||
| PLA ; Count remaining | |||||||||||
| AB26 | BEQ return_29 ; zero: done | ||||||||||
| AB28 | SEC ; One multiplication fewer | ||||||||||
| AB29 | SBC #1 ; decrement the count | ||||||||||
| AB2B | PHA ; save it back | ||||||||||
| AB2C | JSR fwa_mul_var ; FWA = FWA * base | ||||||||||
| AB2F | JMP intpow_check ; loop | ||||||||||
| AB32 | .return_29←1← AB26 BEQ | ||||||||||
| RTS ; Return | |||||||||||
ADVALRead an analogue (A/D) channel or a buffer status. ADVAL numeric.
|
|||||||||||||||
| AB33 | .fn_adval | ||||||||||||||
| JSR eval_factor_integer ; Evaluate the integer argument | |||||||||||||||
| AB36 | LDX zp_iwa ; X = the channel / buffer number | ||||||||||||||
| AB38 | LDA #osbyte_read_adc_or_get_buffer_status ; OSBYTE &80: read ADC / buffer status | ||||||||||||||
| AB3A | JSR osbyte ; Read ADC channel X or buffer status | ||||||||||||||
| AB3D | TXA ; result low byte (X) | ||||||||||||||
| AB3E | JMP iwa_from_ya ; Return as an integer | ||||||||||||||
POINTLogical colour of a graphics point. POINT(x, y).
|
|||||||||||||||
| AB41 | .fn_point | ||||||||||||||
| JSR eval_expr_integer ; Evaluate x | |||||||||||||||
| AB44 | JSR stack_integer ; stack it | ||||||||||||||
| AB47 | JSR skip_spaces_expect_comma ; Expect a comma | ||||||||||||||
| AB4A | JSR eval_subexpr ; Evaluate y, expect ) | ||||||||||||||
| AB4D | JSR coerce_to_integer ; coerce to integer | ||||||||||||||
| AB50 | LDA zp_iwa ; Save y | ||||||||||||||
| AB52 | PHA ; push the low byte | ||||||||||||||
| AB53 | LDA zp_iwa_1 ; high byte | ||||||||||||||
| AB55 | PHA ; push it | ||||||||||||||
| AB56 | JSR unstack_integer ; Recover x | ||||||||||||||
| AB59 | PLA ; pull y high | ||||||||||||||
| AB5A | STA zp_iwa_3 ; into the OSWORD block | ||||||||||||||
| AB5C | PLA ; pull y low | ||||||||||||||
| AB5D | STA zp_iwa_2 ; y low into the block | ||||||||||||||
| AB5F | LDX #&2a ; point X at the block (&2A) | ||||||||||||||
| AB61 | LDA #osword_read_pixel ; Read the pixel colour | ||||||||||||||
| AB63 | JSR osword ; Read pixel value | ||||||||||||||
| AB66 | LDA zp_fwa_sign ; Result sign (off-screen = -1) | ||||||||||||||
| AB68 | BMI sgn_negative ; off-screen? | ||||||||||||||
| AB6A | JMP int_result_a ; return as an integer | ||||||||||||||
POSHorizontal text-cursor position in the window. POS.
|
|||||||||||||||
| AB6D | .fn_pos | ||||||||||||||
| LDA #osbyte_read_text_cursor_pos ; OSBYTE &86: read the text cursor position | |||||||||||||||
| AB6F | JSR osbyte ; Read input cursor position (Sets X=POS and Y=VPOS) | ||||||||||||||
| AB72 | TXA ; X is the horizontal text position ('POS') / Y is the vertical text position ('VPOS') | ||||||||||||||
| AB73 | JMP int_result_a ; Return the column as an integer | ||||||||||||||
VPOSVertical text-cursor position in the window. VPOS.
|
|||||||||||||||
| AB76 | .fn_vpos | ||||||||||||||
| LDA #osbyte_read_text_cursor_pos ; OSBYTE &86: read the cursor position | |||||||||||||||
| AB78 | JSR osbyte ; Read input cursor position (Sets X=POS and Y=VPOS) | ||||||||||||||
| AB7B | TYA ; X is the horizontal text position ('POS') / Y is the vertical text position ('VPOS') | ||||||||||||||
| AB7C | JMP int_result_a ; Return the row (Y) as an integer | ||||||||||||||
| AB7F | .sgn_real_loop←1← AB8D BMI | ||||||||||||||
| JSR fwa_sign ; Sign of the real | |||||||||||||||
| AB82 | BEQ sgn_return ; zero: 0 | ||||||||||||||
| AB84 | BPL sgn_positive ; positive: 1 | ||||||||||||||
| AB86 | BMI sgn_negative ; negative: -1 | ||||||||||||||
| fall through ↓ | |||||||||||||||
SGNSign of a number: -1, 0 or +1. SGN numeric.
|
|||||||||||||||
| AB88 | .fn_sgn | ||||||||||||||
| JSR eval_factor ; Evaluate the argument | |||||||||||||||
| AB8B | BEQ usr_type_error ; string: error | ||||||||||||||
| AB8D | BMI sgn_real_loop ; real: use the FP sign | ||||||||||||||
| AB8F | LDA zp_iwa_3 ; Integer: test for zero | ||||||||||||||
| AB91 | ORA zp_iwa_2 ; OR &2C, | ||||||||||||||
| AB93 | ORA zp_iwa_1 ; &2B, | ||||||||||||||
| AB95 | ORA zp_iwa ; &2A (all zero => SGN 0) | ||||||||||||||
| AB97 | BEQ sgn_zero ; zero: 0 | ||||||||||||||
| AB99 | LDA zp_iwa_3 ; Sign bit | ||||||||||||||
| AB9B | BPL sgn_positive ; positive: 1 | ||||||||||||||
| AB9D | .sgn_negative←2← AB68 BMI← AB86 BMI | ||||||||||||||
| JMP fn_true ; negative: -1 | |||||||||||||||
| ABA0 | .sgn_positive←2← AB84 BPL← AB9B BPL | ||||||||||||||
| LDA #1 ; Result = 1 | |||||||||||||||
| ABA2 | .sgn_return←1← AB82 BEQ | ||||||||||||||
| JMP int_result_a ; return it | |||||||||||||||
| ABA5 | .sgn_zero←1← AB97 BEQ | ||||||||||||||
| LDA #&40 ; Result = 0 (integer) | |||||||||||||||
| ABA7 | RTS ; Return | ||||||||||||||
LOGFWA = base-10 log of FWA. Pure routine at &ABAB.
|
|||||||||||||||
| ABA8 | .fn_log | ||||||||||||||
| JSR fn_ln ; FWA = ln(x) | |||||||||||||||
| ABAB | LDY #&69 ; Point at the constant log10(e): low byte | ||||||||||||||
| ABAD | LDA #&a8 ; high byte | ||||||||||||||
| ABAF | BNE degrad_set_ptr ; FWA = ln(x) * log10(e) | ||||||||||||||
| fall through ↓ | |||||||||||||||
RADFWA = FWA degrees expressed in radians. Pure routine at &ABB4.
|
|||||||||||||||
| ABB1 | .fn_rad | ||||||||||||||
| JSR eval_real ; Evaluate the argument as a real | |||||||||||||||
| ABB4 | LDY #&68 ; Point at the constant pi/180: low byte | ||||||||||||||
| ABB6 | LDA #&aa ; high byte | ||||||||||||||
| ABB8 | .degrad_set_ptr←2← ABAF BNE← ABC9 BNE | ||||||||||||||
| STY zp_fp_ptr ; Set the fp pointer low | |||||||||||||||
| ABBA | STA zp_fp_ptr_1 ; ...and high | ||||||||||||||
| ABBC | JSR fwa_mul_var ; FWA = x * pi/180 | ||||||||||||||
| ABBF | LDA #&ff ; Flag a non-zero real result | ||||||||||||||
| ABC1 | RTS ; Return | ||||||||||||||
DEGFWA = FWA radians expressed in degrees. Pure routine at &ABC5.
|
|||||||||||||||
| ABC2 | .fn_deg | ||||||||||||||
| JSR eval_real ; Evaluate the argument as a real | |||||||||||||||
| ABC5 | LDY #&6d ; Point at the constant 180/pi: low byte | ||||||||||||||
| ABC7 | LDA #&aa ; high byte | ||||||||||||||
| ABC9 | BNE degrad_set_ptr ; Multiply FWA by it (radians -> degrees) | ||||||||||||||
| fall through ↓ | |||||||||||||||
PIFWA = pi (3.14159265). Takes no argument.
|
|||||||||||||||
| ABCB | .fn_pi | ||||||||||||||
| JSR asn_one ; Load the constant pi/2 into FWA | |||||||||||||||
| ABCE | INC zp_fwa_exp ; Double it (exponent + 1) to get pi | ||||||||||||||
| ABD0 | TAY ; Flag a non-zero real result | ||||||||||||||
| ABD1 | RTS ; FWA = pi | ||||||||||||||
USRCall machine code and return the result registers packed into a value. USR address.
|
|||||||||||||||
| ABD2 | .fn_usr | ||||||||||||||
| JSR eval_factor_integer ; Evaluate the address argument as an integer | |||||||||||||||
| ABD5 | JSR usr_call ; Set up registers and call the code | ||||||||||||||
| ABD8 | STA zp_iwa ; Returned A... | ||||||||||||||
| ABDA | STX zp_iwa_1 ; ...and X into the low result bytes | ||||||||||||||
| ABDC | STY zp_iwa_2 ; Returned Y | ||||||||||||||
| ABDE | PHP ; Returned flags... | ||||||||||||||
| ABDF | PLA ; pull them into A | ||||||||||||||
| ABE0 | STA zp_iwa_3 ; ...into the top result byte | ||||||||||||||
| ABE2 | CLD ; Clear decimal mode the code may have left set | ||||||||||||||
| ABE3 | LDA #&40 ; Integer result | ||||||||||||||
| ABE5 | RTS ; Return the packed A,X,Y,P | ||||||||||||||
| ABE6 | .usr_type_error←2← AB8B BEQ← ABEC BNE | ||||||||||||||
| JMP err_type_mismatch ; Non-numeric address: Type mismatch | |||||||||||||||
EVALTokenise a string and evaluate it as a full BASIC expression. The argument is copied onto the stack, given a CR, tokenised in place (mid-statement, so PTR/TIME etc. tokenise as functions, not assignment targets) and run through the expression evaluator - so it accepts everything the evaluator does: "&" hex (factor_hex), "E"-exponent decimals, operators, parentheses, functions and in-scope variables. Hence EVAL("&FF") is 255 where VAL("&FF") is 0, though both read "1E3" as 1000. EVAL string.
|
|||||||||||||||
| ABE9 | .fn_eval | ||||||||||||||
| JSR eval_factor ; Evaluate the argument string | |||||||||||||||
| ABEC | BNE usr_type_error ; not a string: error | ||||||||||||||
| ABEE | INC zp_strbuf_len ; Append a CR terminator | ||||||||||||||
| ABF0 | LDY zp_strbuf_len ; index the new last byte, | ||||||||||||||
| ABF2 | LDA #&0d ; CR, | ||||||||||||||
| ABF4 | STA strbuf_base,y ; append it | ||||||||||||||
| ABF7 | JSR stack_string ; Stack the string | ||||||||||||||
| ABFA | LDA zp_text_ptr2 ; Save the parser pointer | ||||||||||||||
| ABFC | PHA ; push low, | ||||||||||||||
| ABFD | LDA zp_text_ptr2_1 ; high, | ||||||||||||||
| ABFF | PHA ; push high, | ||||||||||||||
| AC00 | LDA zp_text_ptr2_off ; offset, | ||||||||||||||
| AC02 | PHA ; push offset | ||||||||||||||
| AC03 | LDY zp_stack_ptr ; Point at the stacked string | ||||||||||||||
| AC05 | LDX zp_stack_ptr_1 ; high byte in X | ||||||||||||||
| AC07 | INY ; step over the length byte | ||||||||||||||
| AC08 | STY zp_text_ptr2 ; parser pointer low | ||||||||||||||
| AC0A | STY zp_general ; name pointer low | ||||||||||||||
| AC0C | BNE eval_ptr_hi ; no carry into the high byte | ||||||||||||||
| AC0E | INX ; carry into the high byte | ||||||||||||||
| AC0F | .eval_ptr_hi←1← AC0C BNE | ||||||||||||||
| STX zp_text_ptr2_1 ; parser pointer high | |||||||||||||||
| AC11 | STX zp_general_1 ; name pointer high | ||||||||||||||
| AC13 | LDY #&ff ; Tokenise as mid-statement (&3B = &FF): | ||||||||||||||
| AC15 | STY zp_fwb_sign ; so PTR etc. tokenise as functions, not assignments | ||||||||||||||
| AC17 | INY ; Offset back to the start | ||||||||||||||
| AC18 | STY zp_text_ptr2_off ; offset = 0 (start of string) | ||||||||||||||
| AC1A | JSR tokenise_resume ; Tokenise the stacked string | ||||||||||||||
| AC1D | JSR eval_or_eor ; Evaluate the expression | ||||||||||||||
| AC20 | JSR drop_stacked_string ; Drop the stacked string | ||||||||||||||
| AC23 | .eval_restore_ptr←1← AC75 JMP | ||||||||||||||
| PLA ; Restore the parser pointer | |||||||||||||||
| AC24 | STA zp_text_ptr2_off ; the offset, | ||||||||||||||
| AC26 | PLA ; pull the high byte, | ||||||||||||||
| AC27 | STA zp_text_ptr2_1 ; high, | ||||||||||||||
| AC29 | PLA ; pull the low byte, | ||||||||||||||
| AC2A | STA zp_text_ptr2 ; low | ||||||||||||||
| AC2C | LDA zp_var_type ; Result type | ||||||||||||||
| AC2E | RTS ; Return | ||||||||||||||
VALRead a number from the start of a string, through the decimal reader only (ascii_to_number then parse_number): an optional leading sign, digits, a "." and an "E" exponent. It does NOT read "&" hex, so VAL("&FF") is 0; it stops at the first non-numeric character (VAL("12AB") is 12) and yields 0 when no number leads. Returns an integer (IWA) or a real (FWA). Contrast EVAL, which evaluates the whole string. VAL string.
|
|||||||||||||||
| AC2F | .fn_val | ||||||||||||||
| JSR eval_factor ; Evaluate the argument | |||||||||||||||
| AC32 | BNE num_type_error ; not a string: error | ||||||||||||||
| fall through ↓ | |||||||||||||||
Convert an ASCII number to a valueConvert the ASCII number in the string work area to a value
(an integer in IWA or a real in FWA) — the decimal/float reader behind
VAL and numeric tokenising. It accepts an optional leading sign, then
defers to
|
|||||||||||
| AC34 | .ascii_to_number←1← BAD3 JSR | ||||||||||
| LDY zp_strbuf_len ; NUL-terminate the SWA string | |||||||||||
| AC36 | LDA #0 ; the zero byte | ||||||||||
| AC38 | STA string_work,y ; store it past the digits | ||||||||||
| AC3B | LDA zp_text_ptr2 ; Save PtrB (we point it at the SWA): | ||||||||||
| AC3D | PHA ; push the low byte | ||||||||||
| AC3E | LDA zp_text_ptr2_1 ; high byte | ||||||||||
| AC40 | PHA ; push it | ||||||||||
| AC41 | LDA zp_text_ptr2_off ; and the offset | ||||||||||
| AC43 | PHA ; push it | ||||||||||
| AC44 | LDA #0 ; Point PtrB at the SWA (&0600): offset 0 | ||||||||||
| AC46 | STA zp_text_ptr2_off ; set the offset | ||||||||||
| AC48 | LDA #0 ; low 0 | ||||||||||
| AC4A | STA zp_text_ptr2 ; set the low byte | ||||||||||
| AC4C | LDA #6 ; high &06 | ||||||||||
| AC4E | STA zp_text_ptr2_1 ; set the high byte | ||||||||||
| AC50 | JSR skip_spaces_ptr2 ; skip spaces | ||||||||||
| AC53 | CMP #'-' ; minus sign? | ||||||||||
| AC55 | BEQ a2n_negative ; negative number | ||||||||||
| AC57 | CMP #'+' ; plus sign? | ||||||||||
| AC59 | BNE a2n_back ; no sign | ||||||||||
| AC5B | JSR skip_spaces_ptr2 ; skip the plus | ||||||||||
| AC5E | .a2n_back←1← AC59 BNE | ||||||||||
| DEC zp_text_ptr2_off ; step back | |||||||||||
| AC60 | JSR parse_number ; parse the number | ||||||||||
| AC63 | JMP a2n_store_type ; finish | ||||||||||
| AC66 | .a2n_negative←1← AC55 BEQ | ||||||||||
| JSR skip_spaces_ptr2 ; negative: skip the minus | |||||||||||
| AC69 | DEC zp_text_ptr2_off ; step back | ||||||||||
| AC6B | JSR parse_number ; parse the number | ||||||||||
| AC6E | BCC a2n_store_type ; integer: done | ||||||||||
| AC70 | JSR fneg_zero ; real: negate it | ||||||||||
| AC73 | .a2n_store_type←2← AC63 JMP← AC6E BCC | ||||||||||
| STA zp_var_type ; store the result type | |||||||||||
| AC75 | JMP eval_restore_ptr ; restore PtrB and return | ||||||||||
INTInteger part (floor) of a number. INT numeric.
|
|||||||||||||||
| AC78 | .fn_int | ||||||||||||||
| JSR eval_factor ; Evaluate the argument | |||||||||||||||
| AC7B | BEQ num_type_error ; string: error | ||||||||||||||
| AC7D | BPL return_30 ; already integer: return it | ||||||||||||||
| AC7F | LDA zp_fwa_sign ; Real: remember the sign | ||||||||||||||
| AC81 | PHP ; save the sign flags | ||||||||||||||
| AC82 | JSR fwa_to_int2 ; Take the integer part | ||||||||||||||
| AC85 | PLP ; sign | ||||||||||||||
| AC86 | BPL int_to_iwa ; positive: no adjustment | ||||||||||||||
| AC88 | LDA zp_fwb_m1 ; Negative: any fractional bits? | ||||||||||||||
| AC8A | ORA zp_fwb_m2 ; OR &3F, | ||||||||||||||
| AC8C | ORA zp_fwb_m3 ; &40, | ||||||||||||||
| AC8E | ORA zp_fwb_m4 ; &41 (any set => not exact) | ||||||||||||||
| AC90 | BEQ int_to_iwa ; none: exact | ||||||||||||||
| AC92 | JSR negate_mantissa ; round down (floor of a negative) | ||||||||||||||
| AC95 | .int_to_iwa←2← AC86 BPL← AC90 BEQ | ||||||||||||||
| JSR mantissa_to_iwa ; Copy the integer to IWA | |||||||||||||||
| AC98 | LDA #&40 ; integer result | ||||||||||||||
| AC9A | .return_30←1← AC7D BPL | ||||||||||||||
| RTS ; Return | |||||||||||||||
| AC9B | .num_type_error←5← AC32 BNE← AC7B BEQ← ACA1 BNE← ACE5 BNE← ACF3 BNE | ||||||||||||||
| JMP err_type_mismatch ; Type mismatch error | |||||||||||||||
ASCASCII code of the first character of a string, or -1 if empty. ASC string.
|
|||||||||||||||
| AC9E | .fn_asc | ||||||||||||||
| JSR eval_factor ; Evaluate the string | |||||||||||||||
| ACA1 | BNE num_type_error ; not a string: error | ||||||||||||||
| ACA3 | LDA zp_strbuf_len ; String length | ||||||||||||||
| ACA5 | BEQ fn_true ; empty: -1 | ||||||||||||||
| ACA7 | LDA string_work ; First character | ||||||||||||||
| ACAA | .asc_result←1← ACC2 BEQ | ||||||||||||||
| JMP int_result_a ; return it | |||||||||||||||
INKEYRead a key within a time limit, test a key, or read the machine ID. INKEY numeric.
|
|||||||||||||||
| ACAD | .fn_inkey | ||||||||||||||
| JSR read_key_timed ; Read a key within the time limit | |||||||||||||||
| ACB0 | CPY #0 ; timed out? | ||||||||||||||
| ACB2 | BNE fn_true ; no key: return -1 (TRUE) | ||||||||||||||
| ACB4 | TXA ; X = the key code | ||||||||||||||
| ACB5 | JMP iwa_from_ya ; Return the key code as an integer | ||||||||||||||
EOFTRUE when at the end of an open file. EOF#channel.
|
|||||||||||||||
| ACB8 | .fn_eof | ||||||||||||||
| JSR eval_channel ; Evaluate the channel number | |||||||||||||||
| ACBB | TAX ; Channel to X | ||||||||||||||
| ACBC | LDA #osbyte_check_eof ; OSBYTE &7F: test for end of file | ||||||||||||||
| ACBE | JSR osbyte ; Check for end-of-file on file handle Y | ||||||||||||||
| ACC1 | TXA ; X=0 means EOF reached, X=&FF means data remaining | ||||||||||||||
| ACC2 | BEQ asc_result ; Return TRUE/FALSE per the EOF flag | ||||||||||||||
| fall through ↓ | |||||||||||||||
TRUEThe constant TRUE (-1). Sets IWA = -1; this is also the ineg1 integer primitive.
|
|||||||||||||||
| ACC4 | .fn_true←3← AB9D JMP← ACA5 BEQ← ACB2 BNE | ||||||||||||||
| LDA #&ff ; TRUE is -1: load &FF into every IWA byte | |||||||||||||||
| ACC6 | STA zp_iwa ; byte 0 | ||||||||||||||
| ACC8 | STA zp_iwa_1 ; byte 1 | ||||||||||||||
| ACCA | STA zp_iwa_2 ; byte 2 | ||||||||||||||
| ACCC | STA zp_iwa_3 ; byte 3: IWA = -1 | ||||||||||||||
| ACCE | LDA #&40 ; Result type = integer | ||||||||||||||
| ACD0 | RTS ; Return TRUE | ||||||||||||||
NOTBitwise NOT (one's complement) of an integer. NOT numeric.
|
|||||||||||||||
| ACD1 | .fn_not | ||||||||||||||
| JSR eval_factor_integer ; Evaluate the argument as an integer | |||||||||||||||
| ACD4 | LDX #3 ; Complement all four IWA bytes | ||||||||||||||
| ACD6 | .not_loop←1← ACDD BPL | ||||||||||||||
| LDA zp_iwa,x ; byte X... | |||||||||||||||
| ACD8 | EOR #&ff ; ...one's complement | ||||||||||||||
| ACDA | STA zp_iwa,x ; (store) | ||||||||||||||
| ACDC | DEX ; next byte | ||||||||||||||
| ACDD | BPL not_loop ; loop | ||||||||||||||
| ACDF | LDA #&40 ; Integer result | ||||||||||||||
| ACE1 | RTS ; Return NOT value | ||||||||||||||
INSTRPosition of one string within another, optionally from a start. INSTR(a$, b$ [,n]).
|
|||||||||||||||
| ACE2 | .fn_instr | ||||||||||||||
| JSR eval_or_eor ; Evaluate the searched string | |||||||||||||||
| ACE5 | BNE num_type_error ; not a string: Type mismatch | ||||||||||||||
| ACE7 | CPX #',' ; ','? | ||||||||||||||
| ACE9 | BNE instr_missing_comma ; no: Missing , | ||||||||||||||
| ACEB | INC zp_text_ptr2_off ; step past | ||||||||||||||
| ACED | JSR stack_string ; Stack the searched string | ||||||||||||||
| ACF0 | JSR eval_or_eor ; Evaluate the search string | ||||||||||||||
| ACF3 | BNE num_type_error ; not a string: Type mismatch | ||||||||||||||
| ACF5 | LDA #1 ; Default start position = 1 | ||||||||||||||
| ACF7 | STA zp_iwa ; store as the start position | ||||||||||||||
| ACF9 | INC zp_text_ptr2_off ; step past | ||||||||||||||
| ACFB | CPX #')' ; ')' (no start given)? | ||||||||||||||
| ACFD | BEQ instr_dest_index ; yes: search from 1 | ||||||||||||||
| ACFF | CPX #',' ; ','? | ||||||||||||||
| AD01 | BEQ instr_stack ; yes: a start position follows | ||||||||||||||
| AD03 | .instr_missing_comma←1← ACE9 BNE | ||||||||||||||
| JMP missing_comma ; Missing , error | |||||||||||||||
| AD06 | .instr_stack←1← AD01 BEQ | ||||||||||||||
| JSR stack_string ; Stack the search string | |||||||||||||||
| AD09 | JSR eval_subexpr ; Evaluate the start, expect ) | ||||||||||||||
| AD0C | JSR coerce_to_integer ; coerce to integer | ||||||||||||||
| AD0F | JSR unstack_string ; Restore the search string | ||||||||||||||
| AD12 | .instr_dest_index←1← ACFD BEQ | ||||||||||||||
| LDY #0 ; Destination index | |||||||||||||||
| AD14 | LDX zp_iwa ; Start position | ||||||||||||||
| AD16 | BNE instr_match_pos ; non-zero? | ||||||||||||||
| AD18 | LDX #1 ; force at least 1 | ||||||||||||||
| AD1A | .instr_match_pos←1← AD16 BNE | ||||||||||||||
| STX zp_iwa ; Current match position | |||||||||||||||
| AD1C | TXA ; Zero-based start = start - 1 | ||||||||||||||
| AD1D | DEX ; start - 1, | ||||||||||||||
| AD1E | STX zp_iwa_3 ; save the zero-based start | ||||||||||||||
| AD20 | CLC ; Point at s$ + (start-1) | ||||||||||||||
| AD21 | ADC zp_stack_ptr ; + stack pointer low, | ||||||||||||||
| AD23 | STA zp_general ; pointer low, | ||||||||||||||
| AD25 | TYA ; A = 0 (from Y), | ||||||||||||||
| AD26 | ADC zp_stack_ptr_1 ; + stack pointer high, | ||||||||||||||
| AD28 | STA zp_general_1 ; pointer high | ||||||||||||||
| AD2A | LDA (zp_stack_ptr),y ; Length of s$ | ||||||||||||||
| AD2C | SEC ; minus the start offset... | ||||||||||||||
| AD2D | SBC zp_iwa_3 ; len(s$) - (start-1) | ||||||||||||||
| AD2F | BCC instr_not_found ; start beyond the end: not found | ||||||||||||||
| AD31 | SBC zp_strbuf_len ; minus the search length | ||||||||||||||
| AD33 | BCC instr_not_found ; won't fit: not found | ||||||||||||||
| AD35 | ADC #0 ; Number of start positions to try | ||||||||||||||
| AD37 | STA zp_iwa_1 ; positions to try | ||||||||||||||
| AD39 | JSR drop_stacked_string ; Re-point at the stacked string | ||||||||||||||
| AD3C | .instr_compare←2← AD61 BNE← AD65 BNE | ||||||||||||||
| LDY #0 ; Compare from index 0 | |||||||||||||||
| AD3E | LDX zp_strbuf_len ; Search length | ||||||||||||||
| AD40 | BEQ instr_match ; empty search: matches here | ||||||||||||||
| AD42 | .instr_cmp_loop←1← AD4B BNE | ||||||||||||||
| LDA (zp_general),y ; s$ character | |||||||||||||||
| AD44 | CMP string_work,y ; vs search character | ||||||||||||||
| AD47 | BNE instr_advance ; mismatch: advance | ||||||||||||||
| AD49 | INY ; next | ||||||||||||||
| AD4A | DEX ; one fewer char to match | ||||||||||||||
| AD4B | BNE instr_cmp_loop ; all matched? | ||||||||||||||
| AD4D | .instr_match←1← AD40 BEQ | ||||||||||||||
| LDA zp_iwa ; Match: result is the position | |||||||||||||||
| AD4F | .instr_result←1← AD57 BEQ | ||||||||||||||
| JMP int_result_a ; return it as an integer | |||||||||||||||
| AD52 | .instr_not_found←2← AD2F BCC← AD33 BCC | ||||||||||||||
| JSR drop_stacked_string ; Not found: drop the stacked string | |||||||||||||||
| AD55 | .instr_zero←1← AD5D BEQ | ||||||||||||||
| LDA #0 ; result = 0 | |||||||||||||||
| AD57 | BEQ instr_result ; return it | ||||||||||||||
| AD59 | .instr_advance←1← AD47 BNE | ||||||||||||||
| INC zp_iwa ; Advance the match position | |||||||||||||||
| AD5B | DEC zp_iwa_1 ; one fewer position to try | ||||||||||||||
| AD5D | BEQ instr_zero ; exhausted: not found | ||||||||||||||
| AD5F | INC zp_general ; advance the s$ pointer | ||||||||||||||
| AD61 | BNE instr_compare ; retry | ||||||||||||||
| AD63 | INC zp_general_1 ; carry into the high byte | ||||||||||||||
| AD65 | BNE instr_compare ; retry | ||||||||||||||
| AD67 | .instr_type_error←2← AD6D BEQ← AD8F BEQ | ||||||||||||||
| JMP err_type_mismatch ; Type mismatch error | |||||||||||||||
ABSAbsolute value of a number. ABS numeric.
|
|||||||||||||||
| AD6A | .fn_abs | ||||||||||||||
| JSR eval_factor ; Evaluate the argument | |||||||||||||||
| AD6D | BEQ instr_type_error ; zero: return it | ||||||||||||||
| AD6F | BMI abs_real ; real: clear the sign | ||||||||||||||
| fall through ↓ | |||||||||||||||
Make the integer accumulator positiveIWA = ABS(IWA).
|
|||||||||
| AD71 | .iwa_abs←4← 99C5 JSR← 99D8 JSR← 9D70 JSR← 9D80 JSR | ||||||||
| BIT zp_iwa_3 ; Test the sign of IWA (top byte) | |||||||||
| AD73 | BMI iwa_negate ; Negative: negate it | ||||||||
| AD75 | BPL ineg_done ; Positive: leave it | ||||||||
| AD77 | .abs_real←1← AD6F BMI | ||||||||
| JSR fwa_sign ; ABS of a real: get the sign | |||||||||
| AD7A | BPL fneg_done ; positive/zero: done | ||||||||
| AD7C | BMI fneg_toggle ; negative: clear the sign | ||||||||
| fall through ↓ | |||||||||
FWA = -FWANegate FWA by flipping the sign bit (a zero value is left unchanged).
|
|||||||||
| AD7E | .fwa_negate←5← A4D3 JMP← A4FD JSR← A933 JMP← A9A7 JMP← AD91 BMI | ||||||||
| JSR fwa_sign ; Is FWA zero? | |||||||||
| AD81 | BEQ fneg_done ; zero: nothing to negate | ||||||||
| AD83 | .fneg_toggle←1← AD7C BMI | ||||||||
| LDA zp_fwa_sign ; Toggle the sign bit... | |||||||||
| AD85 | EOR #&80 ; flip bit 7 | ||||||||
| AD87 | STA zp_fwa_sign ; (store) | ||||||||
| AD89 | .fneg_done←2← AD7A BPL← AD81 BEQ | ||||||||
| LDA #&ff ; real result type | |||||||||
| AD8B | RTS ; Return | ||||||||
| AD8C | .unary_minus←1← ADF8 BEQ | ||||||||
| JSR factor_unary_plus ; Unary minus: evaluate the operand | |||||||||
| AD8F | .fneg_zero←1← AC70 JSR | ||||||||
| BEQ instr_type_error ; zero: leave it | |||||||||
| AD91 | BMI fwa_negate ; real: negate FWA | ||||||||
| fall through ↓ | |||||||||
Negate the integer accumulatorIWA = -IWA (two's-complement negate the 32-bit integer).
|
|||||||||
| AD93 | .iwa_negate←3← 9DC3 JSR← A2C8 JSR← AD73 BMI | ||||||||
| SEC ; Negate IWA: compute 0 - IWA | |||||||||
| AD94 | LDA #0 ; from zero | ||||||||
| AD96 | TAY ; Y = 0 for the subtractions | ||||||||
| AD97 | SBC zp_iwa ; byte 0 | ||||||||
| AD99 | STA zp_iwa ; (store) | ||||||||
| AD9B | TYA ; 0... | ||||||||
| AD9C | SBC zp_iwa_1 ; byte 1 | ||||||||
| AD9E | STA zp_iwa_1 ; (store) | ||||||||
| ADA0 | TYA ; 0... | ||||||||
| ADA1 | SBC zp_iwa_2 ; byte 2 | ||||||||
| ADA3 | STA zp_iwa_2 ; (store) | ||||||||
| ADA5 | TYA ; 0... | ||||||||
| ADA6 | SBC zp_iwa_3 ; byte 3 | ||||||||
| ADA8 | STA zp_iwa_3 ; (store) | ||||||||
| ADAA | .ineg_done←1← AD75 BPL | ||||||||
| LDA #&40 ; integer result | |||||||||
| ADAC | RTS ; Return -IWA | ||||||||
Read a string literalRead a quoted ("...", with "" for a literal quote) or unquoted string at PtrB into the string buffer.
|
|||||||||||
| ADAD | .read_string_literal←2← BABA JSR← BB38 JSR | ||||||||||
| JSR skip_spaces_ptr2 ; Read a string literal: skip spaces | |||||||||||
| ADB0 | CMP #'"' ; a quote? | ||||||||||
| ADB2 | BEQ rsl_quoted ; quoted string | ||||||||||
| ADB4 | LDX #0 ; Unquoted: read until CR or comma | ||||||||||
| ADB6 | .rsl_unquoted_loop←1← ADC3 BNE | ||||||||||
| LDA (zp_text_ptr2),y ; char | |||||||||||
| ADB8 | STA string_work,x ; into the buffer | ||||||||||
| ADBB | INY ; next | ||||||||||
| ADBC | INX ; and the buffer index | ||||||||||
| ADBD | CMP #&0d ; CR? | ||||||||||
| ADBF | BEQ rsl_unquoted_end ; end | ||||||||||
| ADC1 | CMP #',' ; comma? | ||||||||||
| ADC3 | BNE rsl_unquoted_loop ; loop | ||||||||||
| ADC5 | .rsl_unquoted_end←1← ADBF BEQ | ||||||||||
| DEY ; step back | |||||||||||
| ADC6 | JMP rsl_drop_trail ; finish | ||||||||||
| ADC9 | .rsl_quoted←2← ADB2 BEQ← ADFC BEQ | ||||||||||
| LDX #0 ; Quoted: read until the closing quote | |||||||||||
| ADCB | .rsl_quoted_adv←1← ADDF BEQ | ||||||||||
| INY ; advance | |||||||||||
| ADCC | .rsl_quoted_loop←1← ADD9 BNE | ||||||||||
| LDA (zp_text_ptr2),y ; char | |||||||||||
| ADCE | CMP #&0d ; CR (unterminated)? | ||||||||||
| ADD0 | BEQ rsl_missing_quote ; Missing " error | ||||||||||
| ADD2 | INY ; next | ||||||||||
| ADD3 | STA string_work,x ; into the buffer | ||||||||||
| ADD6 | INX ; advance the buffer index | ||||||||||
| ADD7 | CMP #'"' ; a quote? | ||||||||||
| ADD9 | BNE rsl_quoted_loop ; no: keep copying | ||||||||||
| ADDB | LDA (zp_text_ptr2),y ; doubled "" = a literal quote? | ||||||||||
| ADDD | CMP #'"' ; also a quote? | ||||||||||
| ADDF | BEQ rsl_quoted_adv ; yes: keep it | ||||||||||
| ADE1 | .rsl_drop_trail←1← ADC6 JMP | ||||||||||
| DEX ; drop the trailing character | |||||||||||
| ADE2 | STX zp_strbuf_len ; set the string length | ||||||||||
| ADE4 | STY zp_text_ptr2_off ; update the text offset | ||||||||||
| ADE6 | LDA #0 ; string type | ||||||||||
| ADE8 | RTS ; Return the string | ||||||||||
| ADE9 | .rsl_missing_quote←1← ADD0 BEQ | ||||||||||
| JMP missing_quote ; Missing " error | |||||||||||
Evaluate a factor (evaluator level 1)Evaluate the highest-precedence level of an expression at PtrB: unary minus, unary plus and NOT; parenthesised sub-expressions; the ?, !, $ and | indirection operators; string literals; and the built-in functions. Unlike the higher levels, it does not read the trailing operator - the caller does that.
|
|||||||||||||
| ADEC | .eval_factor←13← 92E3 JSR← 92FA JSR← 9E20 JSR← AB88 JSR← ABE9 JSR← AC2F JSR← AC78 JSR← AC9E JSR← AD6A JSR← ADF4 BEQ← AED1 JSR← B0A3 JSR← BF83 JSR | ||||||||||||
| LDY zp_text_ptr2_off ; Next character | |||||||||||||
| ADEE | INC zp_text_ptr2_off ; advance the offset | ||||||||||||
| ADF0 | LDA (zp_text_ptr2),y ; read it | ||||||||||||
| ADF2 | CMP #' ' ; space? | ||||||||||||
| ADF4 | BEQ eval_factor ; skip it | ||||||||||||
| ADF6 | CMP #'-' ; '-' unary minus? | ||||||||||||
| ADF8 | BEQ unary_minus ; yes | ||||||||||||
| ADFA | CMP #'"' ; '"' string literal? | ||||||||||||
| ADFC | BEQ rsl_quoted ; yes | ||||||||||||
| ADFE | CMP #'+' ; '+' unary plus? | ||||||||||||
| AE00 | BNE factor_classify ; no: classify the token | ||||||||||||
| AE02 | .factor_unary_plus←1← AD8C JSR | ||||||||||||
| JSR skip_spaces_ptr2 ; unary plus: re-read the next character | |||||||||||||
| AE05 | .factor_classify←1← AE00 BNE | ||||||||||||
| CMP #&8e ; below the lowest function token? | |||||||||||||
| AE07 | BCC factor_indirect ; yes: indirection, number or variable | ||||||||||||
| AE09 | CMP #&c6 ; above the highest function token? | ||||||||||||
| AE0B | BCS no_such_variable ; yes: No such variable | ||||||||||||
| AE0D | JMP dispatch_token ; a function: dispatch it | ||||||||||||
| AE10 | .factor_indirect←1← AE07 BCC | ||||||||||||
| CMP #'?' ; '?' (byte indirection) or higher? | |||||||||||||
| AE12 | BCS factor_name ; yes: variable or indirection | ||||||||||||
| AE14 | CMP #'.' ; '.' or a digit? | ||||||||||||
| AE16 | BCS factor_number ; yes: a number | ||||||||||||
| AE18 | CMP #'&' ; '&' hex number? | ||||||||||||
| AE1A | BEQ factor_hex ; yes | ||||||||||||
| AE1C | CMP #'(' ; '(' sub-expression? | ||||||||||||
| AE1E | BEQ eval_subexpr ; yes | ||||||||||||
| AE20 | .factor_name←1← AE12 BCS | ||||||||||||
| DEC zp_text_ptr2_off ; Back up to the name | |||||||||||||
| AE22 | JSR pvr_parse ; Parse the variable reference | ||||||||||||
| AE25 | BEQ factor_undefined ; undefined: handle below | ||||||||||||
| AE27 | JMP load_var_by_type ; load the variable value | ||||||||||||
| AE2A | .factor_number←1← AE16 BCS | ||||||||||||
| JSR parse_number ; Parse the decimal number | |||||||||||||
| AE2D | BCC no_such_variable ; ok Return | ||||||||||||
| AE2F | RTS ; Return | ||||||||||||
| AE30 | .factor_undefined←1← AE25 BEQ | ||||||||||||
| LDA zp_opt_flag ; Undefined: OPT flag | |||||||||||||
| AE32 | AND #2 ; ignore-undefined set? | ||||||||||||
| AE34 | BNE no_such_variable ; no: No such variable | ||||||||||||
| AE36 | BCS no_such_variable ; bad name: No such variable | ||||||||||||
| AE38 | STX zp_text_ptr2_off ; accept; advance the offset | ||||||||||||
| AE3A | .factor_pcounter←1← 85AF JSR | ||||||||||||
| LDA resint_p ; Use P% as the value | |||||||||||||
| AE3D | LDY resint_p_1 ; return it as an integer | ||||||||||||
| AE40 | JMP iwa_from_ya ; return as a 16-bit integer | ||||||||||||
Raise "No such variable" errorRaise BASIC error &1A, "No such variable", via a BRK error block. Reached when an expression or lvalue names a variable that has not been created. Does not return.
|
||||
| AE43 | .no_such_variable←6← 8F1B JMP← AE0B BCS← AE2D BCC← AE34 BNE← AE36 BCS← AEC7 JMP | |||
| BRK ; No such variable error | ||||
| AE44 | EQUB &1A | |||
| AE45 | EQUS "No such variable" | |||
| AE55 | EQUB &00 | |||
Evaluate a parenthesised sub-expressionEvaluate a full expression at PtrB via eval_or_eor, then require a closing ")" - raising Missing ) if the terminating operator is anything else. Used wherever a bracketed sub-expression appears in the grammar.
|
|||||||||||||||
| AE56 | .eval_subexpr←11← 8E2B JSR← 9747 JSR← 976C JSR← AB4A JSR← AD09 JSR← AE1E BEQ← AF0C JSR← AFDA JSR← AFFC JSR← B05B JSR← B0CB JSR | ||||||||||||||
| JSR eval_or_eor ; Sub-expression: evaluate it | |||||||||||||||
| AE59 | INC zp_text_ptr2_off ; step past | ||||||||||||||
| AE5B | CPX #')' ; ')' to close? | ||||||||||||||
| AE5D | BNE missing_paren ; no: Missing ) | ||||||||||||||
| AE5F | TAY ; flag the result type | ||||||||||||||
| AE60 | RTS ; Return | ||||||||||||||
| AE61 | .missing_paren←1← AE5D BNE | ||||||||||||||
| BRK ; Missing ) error | |||||||||||||||
| AE62 | EQUB &1B | ||||||||||||||
| AE63 | EQUS "Missing )" | ||||||||||||||
| AE6C | EQUB &00 | ||||||||||||||
Scan an & hex constantShift each hex digit's nibble into the 32-bit IWA
(&2A-&2D); the bit rolled off the top is discarded, so there is no
overflow check — a 9th or later digit silently drops the high nibble and
only the low 32 bits survive (so |
|
| AE6D | .factor_hex←1← AE1A BEQ |
| LDX #0 ; Hex number: clear IWA | |
| AE6F | STX zp_iwa ; byte 0, |
| AE71 | STX zp_iwa_1 ; byte 1, |
| AE73 | STX zp_iwa_2 ; byte 2, |
| AE75 | STX zp_iwa_3 ; byte 3 |
| AE77 | LDY zp_text_ptr2_off ; scan offset |
| AE79 | .factor_hex_loop←1← AEA0 BNE |
| LDA (zp_text_ptr2),y ; Next character | |
| AE7B | CMP #'0' ; below '0'? |
| AE7D | BCC factor_hex_check ; yes: end of number |
| AE7F | CMP #':' ; a digit 0-9? |
| AE81 | BCC factor_hex_nibble ; yes |
| AE83 | SBC #&37 ; fold A-F to 10-15 |
| AE85 | CMP #&0a ; below 10 (a gap char)? |
| AE87 | BCC factor_hex_check ; yes: end of number |
| AE89 | CMP #&10 ; above F? (also rejects lowercase a-f) |
| AE8B | BCS factor_hex_check ; yes: end of number |
| AE8D | .factor_hex_nibble←1← AE81 BCC |
| ASL ; Shift the digit into the high nibble | |
| AE8E | ASL ; (continued) |
| AE8F | ASL ; (continued) |
| AE90 | ASL ; (continued) |
| AE91 | LDX #3 ; four bits to shift |
| AE93 | .factor_hex_shift←1← AE9D BPL |
| ASL ; Shift one bit into IWA | |
| AE94 | ROL zp_iwa ; byte 0, |
| AE96 | ROL zp_iwa_1 ; byte 1, |
| AE98 | ROL zp_iwa_2 ; byte 2, |
| AE9A | ROL zp_iwa_3 ; byte 3 (bit rolled out here is dropped: no check) |
| AE9C | DEX ; one of four bits done |
| AE9D | BPL factor_hex_shift ; next bit |
| AE9F | INY ; advance |
| AEA0 | BNE factor_hex_loop ; next digit: unbounded run, low 32 bits survive |
| AEA2 | .factor_hex_check←3← AE7D BCC← AE87 BCC← AE8B BCS |
| TXA ; Any digits seen? | |
| AEA3 | BPL bad_hex ; no: Bad HEX |
| AEA5 | STY zp_text_ptr2_off ; Save the offset |
| AEA7 | LDA #&40 ; Type = integer |
| AEA9 | RTS ; Return |
| AEAA | .bad_hex←1← AEA3 BPL |
| BRK ; Bad HEX error | |
| AEAB | EQUB &1C |
| AEAC | EQUS "Bad HEX" |
| AEB3 | EQUB &00 |
=TIMERead the centisecond elapsed-time clock. TIME.
|
|||||||||||||||
| AEB4 | .fn_time | ||||||||||||||
| LDX #<(zp_iwa) ; Point OSWORD at IWA: low byte | |||||||||||||||
| AEB6 | LDY #>(zp_iwa) ; high byte | ||||||||||||||
| AEB8 | LDA #osword_read_clock ; OSWORD &01: read the centisecond clock into IWA | ||||||||||||||
| AEBA | JSR osword ; Read system clock | ||||||||||||||
| AEBD | LDA #&40 ; Integer result | ||||||||||||||
| AEBF | RTS ; Return TIME | ||||||||||||||
=PAGERead PAGE, the start of the BASIC program. PAGE.
|
|||||||||||||||
| AEC0 | .fn_page | ||||||||||||||
| LDA #0 ; PAGE low byte is always 0... | |||||||||||||||
| AEC2 | LDY zp_page ; ...high byte is the page number | ||||||||||||||
| AEC4 | JMP iwa_from_ya ; Return PAGE as an integer | ||||||||||||||
| AEC7 | .pseudovar_syntax_error←1← AEE2 BNE | ||||||||||||||
| JMP no_such_variable ; syntax error (shared) | |||||||||||||||
FALSEThe constant FALSE (0). Sets IWA = 0; this is also the izero integer primitive.
|
|||||||||||||||
| AECA | .fn_false | ||||||||||||||
| LDA #0 ; FALSE is 0 | |||||||||||||||
| AECC | BEQ int_result_a ; Return 0 as an integer | ||||||||||||||
| AECE | .bool_type_error←1← AED4 BNE | ||||||||||||||
| JMP err_type_mismatch ; String operand here is a Type mismatch | |||||||||||||||
LENLength of a string. LEN string.
|
|||||||||||||||
| AED1 | .fn_len | ||||||||||||||
| JSR eval_factor ; Evaluate the string | |||||||||||||||
| AED4 | BNE bool_type_error ; not a string: error | ||||||||||||||
| AED6 | LDA zp_strbuf_len ; Length, returned as an integer | ||||||||||||||
| fall through ↓ | |||||||||||||||
Return A as an integer resultSet IWA to the unsigned byte in A (high bytes zero) and report the integer type. The common tail for functions returning a small integer.
|
|||||||||||
| AED8 | .int_result_a←18← 8F6B JSR← 8F76 JSR← 9182 JSR← 9339 JSR← 96F8 JSR← AB6A JMP← AB73 JMP← AB7C JMP← ABA2 JMP← ACAA JMP← AD4F JMP← AECC BEQ← AEF9 JMP← AFBC JMP← B5A9 JSR← B810 JSR← BF75 JMP← BF93 JMP | ||||||||||
| LDY #0 ; High byte zero | |||||||||||
| AEDA | BEQ iwa_from_ya ; return A as the integer | ||||||||||
| fall through ↓ | |||||||||||
TOThe TO keyword. "TO P" reads TOP, the end of the BASIC program, as an integer; any other TO is a syntax error.
|
|||||||||||||||
| AEDC | .fn_to | ||||||||||||||
| LDY zp_text_ptr2_off ; Look at the character after TO | |||||||||||||||
| AEDE | LDA (zp_text_ptr2),y ; (get it) | ||||||||||||||
| AEE0 | CMP #'P' ; Is it "P"? TO + P spells TOP | ||||||||||||||
| AEE2 | BNE pseudovar_syntax_error ; No: a bare TO here is a syntax error | ||||||||||||||
| AEE4 | INC zp_text_ptr2_off ; Consume the P | ||||||||||||||
| AEE6 | LDA zp_top ; TOP: end-of-program address, low byte | ||||||||||||||
| AEE8 | LDY zp_top_1 ; high byte (returned as an integer) | ||||||||||||||
| fall through ↓ | |||||||||||||||
Set the integer accumulator to a small integerIWA = 256*Y + A, zero-extended to 32 bits (unsigned 0-65535), then report the integer type.
|
|||||||||||||
| AEEA | .iwa_from_ya←11← 98A4 JSR← AB3E JMP← ACB5 JMP← AE40 JMP← AEC4 JMP← AEDA BEQ← AF00 JMP← AF07 JMP← AFA3 JMP← AFAA JMP← B351 JMP | ||||||||||||
| STA zp_iwa ; Low byte (A) into IWA byte 0 | |||||||||||||
| AEEC | STY zp_iwa_1 ; High byte (Y) into IWA byte 1 | ||||||||||||
| AEEE | LDA #0 ; Clear the top 16 bits: the result is 0-65535 | ||||||||||||
| AEF0 | STA zp_iwa_2 ; Clear IWA byte 2 | ||||||||||||
| AEF2 | STA zp_iwa_3 ; Clear byte 3: the value is unsigned 0-65535 | ||||||||||||
| AEF4 | LDA #&40 ; Report the value as an integer (type &40) | ||||||||||||
| AEF6 | RTS ; Return the integer | ||||||||||||
COUNTCharacters printed since the last newline. COUNT.
|
|||||||||||||||
| AEF7 | .fn_count | ||||||||||||||
| LDA zp_count ; COUNT: characters printed since the last newline | |||||||||||||||
| AEF9 | JMP int_result_a ; Return it as an integer | ||||||||||||||
=LOMEMRead LOMEM, the start of variable storage. LOMEM.
|
|||||||||||||||
| AEFC | .fn_lomem | ||||||||||||||
| LDA zp_lomem ; LOMEM low byte | |||||||||||||||
| AEFE | LDY zp_lomem_1 ; high byte | ||||||||||||||
| AF00 | JMP iwa_from_ya ; Return LOMEM as an integer | ||||||||||||||
=HIMEMRead HIMEM, the top of memory for BASIC. HIMEM.
|
|||||||||||||||
| AF03 | .fn_himem | ||||||||||||||
| LDA zp_himem ; HIMEM low | |||||||||||||||
| AF05 | LDY zp_himem_1 ; HIMEM high | ||||||||||||||
| AF07 | JMP iwa_from_ya ; return as an integer | ||||||||||||||
| AF0A | .rnd_dispatch←1← AF4F BEQ | ||||||||||||||
| INC zp_text_ptr2_off ; Skip the "(" | |||||||||||||||
| AF0C | JSR eval_subexpr ; Evaluate the argument expression | ||||||||||||||
| AF0F | JSR coerce_to_integer ; Coerce it to an integer | ||||||||||||||
| AF12 | LDA zp_iwa_3 ; Examine the argument: high byte | ||||||||||||||
| AF14 | BMI rnd_seed ; Negative: re-seed the generator | ||||||||||||||
| AF16 | ORA zp_iwa_2 ; Any of bits 16-31 set... | ||||||||||||||
| AF18 | ORA zp_iwa_1 ; ...(magnitude >= 256) | ||||||||||||||
| AF1A | BNE rnd_range ; Large: RND(X) over a range | ||||||||||||||
| AF1C | LDA zp_iwa ; Low byte | ||||||||||||||
| AF1E | BEQ rnd_repeat ; RND(0): repeat the last fraction | ||||||||||||||
| AF20 | CMP #1 ; RND(1)? | ||||||||||||||
| AF22 | BEQ rnd_fraction ; RND(1): a fresh fraction (else 2..255: RND(X)) | ||||||||||||||
| fall through ↓ | |||||||||||||||
RND(X), X>=2: a random integer 1 to XCompute 1 + INT(RND(1) * X). int_to_fwa(X), push X (stack_real), take a fraction (rnd_fraction), pop X back into the operand (unstack_real), multiply (fwa_mul_var_raw), convert to an integer (fwa_to_int) and add one (iwa_inc), giving a value in 1..X.
|
|||||||||
| AF24 | .rnd_range←1← AF1A BNE | ||||||||
| JSR int_to_fwa ; FWA = X | |||||||||
| AF27 | JSR stack_real ; Push X onto the stack | ||||||||
| AF2A | JSR rnd_fraction ; FWA = a fraction in [0, 1) | ||||||||
| AF2D | JSR unstack_real ; Pop X back as the multiply operand | ||||||||
| AF30 | JSR fwa_mul_var_raw ; FWA = fraction * X | ||||||||
| AF33 | JSR fwa_normalise ; Normalise the product | ||||||||
| AF36 | JSR fwa_to_int ; IWA = INT(fraction * X) = 0..X-1 | ||||||||
| AF39 | JSR iwa_inc ; Add one: 1..X | ||||||||
| AF3C | LDA #&40 ; Integer result | ||||||||
| AF3E | RTS ; Return RND(X) | ||||||||
RND(-X): seed the generator and return XStore the integer argument into the 32-bit state (&0D-&10) and set &11 to &40. Only bit 0 of &11 is part of the LFSR, so the overflow bit becomes 0. Returns the argument as an integer.
|
|||||||||||
| AF3F | .rnd_seed←1← AF14 BMI | ||||||||||
| LDX #&0d ; Point at the state bytes (&0D) | |||||||||||
| AF41 | JSR iwa_store_zp ; Store the argument as the 32-bit state | ||||||||||
| AF44 | LDA #&40 ; Bit-32 byte = | ||||||||||
| AF46 | STA zp_rnd_seed_4 ; &40: bit 32 (its bit 0) becomes 0 | ||||||||||
| AF48 | RTS ; Return the argument (A = &40 = integer) | ||||||||||
RNDRandom number; the form depends on the argument (see rnd_*). RND[(numeric)].
|
|||||||||||||||
| AF49 | .fn_rnd | ||||||||||||||
| LDY zp_text_ptr2_off ; Look at the character after RND | |||||||||||||||
| AF4B | LDA (zp_text_ptr2),y ; (get it) | ||||||||||||||
| AF4D | CMP #'(' ; Is it "("? then RND(expr) | ||||||||||||||
| AF4F | BEQ rnd_dispatch ; Yes: select the RND form | ||||||||||||||
| fall through ↓ | |||||||||||||||
RND: a full-range random integerBare RND. Advance the generator (rnd_step) then read the 32-bit state (&0D-&10) into IWA as a signed integer, returning the integer type (&40). The result spans the full signed 32-bit range.
|
|||||||||||
| AF51 | .rnd_integer | ||||||||||
| JSR rnd_step ; Advance the generator | |||||||||||
| AF54 | LDX #&0d ; Point at the state (&0D), then copy it to IWA | ||||||||||
| fall through ↓ | |||||||||||
Load a zero-page integer variable into the accumulatorCopy the 4-byte integer at &00+X (a resident integer variable A%-Z% or @%) into IWA, then report the integer type.
|
|||||||||||||
| AF56 | .iwa_load_zp←2← 9DBD JSR← B326 JSR | ||||||||||||
| LDA zp_lomem,x ; Copy 4-byte value at &00+X into IWA: byte 0 | |||||||||||||
| AF58 | STA zp_iwa ; (store) | ||||||||||||
| AF5A | LDA zp_lomem_1,x ; byte 1 | ||||||||||||
| AF5C | STA zp_iwa_1 ; (store) | ||||||||||||
| AF5E | LDA zp_vartop,x ; byte 2 | ||||||||||||
| AF60 | STA zp_iwa_2 ; (store) | ||||||||||||
| AF62 | LDA zp_vartop_1,x ; byte 3 | ||||||||||||
| AF64 | STA zp_iwa_3 ; (store) | ||||||||||||
| AF66 | LDA #&40 ; Integer type | ||||||||||||
| AF68 | RTS ; Return the integer | ||||||||||||
RND(1): a random real in [0, 1)Advance the generator (rnd_step) then fall into rnd_repeat to build the fraction. The value is the byte-reversed 32-bit state divided by 2^32: a real in [0, 1).
|
|||||||||||
| AF69 | .rnd_fraction←2← AF22 BEQ← AF2A JSR | ||||||||||
| JSR rnd_step ; Advance the generator, then build the fraction | |||||||||||
| fall through ↓ | |||||||||||
RND(0): repeat the last RND(1) without advancingBuild the floating-point fraction from the CURRENT generator state WITHOUT stepping it (so RND(0) repeats the last RND(1)). The mantissa bytes m1..m4 are loaded most-significant-first from the little-endian state &0D,&0E,&0F,&10, which byte-reverses the 32-bit value; with exponent &80 and after normalisation the result is state-reversed / 2^32, a real in [0, 1).
|
|||||||||||
| AF6C | .rnd_repeat←1← AF1E BEQ | ||||||||||
| LDX #0 ; Zero for the FP fields | |||||||||||
| AF6E | STX zp_fwa_sign ; Sign positive | ||||||||||
| AF70 | STX zp_fwa_ovf ; Clear overflow | ||||||||||
| AF72 | STX zp_fwa_rnd ; Clear rounding | ||||||||||
| AF74 | LDA #&80 ; Exponent &80 (= 2^0) | ||||||||||
| AF76 | STA zp_fwa_exp ; (store it) | ||||||||||
| AF78 | .rnd_state_loop←1← AF7F BNE | ||||||||||
| LDA zp_rnd_seed,x ; State byte X (little-endian)... | |||||||||||
| AF7A | STA zp_fwa_m1,x ; ...into mantissa byte X (MSB first): byte-reverses | ||||||||||
| AF7C | INX ; next byte | ||||||||||
| AF7D | CPX #4 ; all four? | ||||||||||
| AF7F | BNE rnd_state_loop ; loop | ||||||||||
| AF81 | JSR mulf_normalise ; Normalise: value = reversed-state / 2^32 | ||||||||||
| AF84 | LDA #&ff ; Real result type | ||||||||||
| AF86 | RTS ; Return RND(1) / RND(0) | ||||||||||
Advance the random-number LFSR by 32 stepsAdvance the 33-bit linear-feedback shift register in zp_rnd_seed by exactly 32 single-bit steps (one RND call). The register uses the primitive trinomial x^33 + x^20 + 1, i.e. taps (33, 20, 0): each step feeds (bit 19 XOR bit 32) into bit 0 and shifts the whole register left by one. Per step: take byte 2 (bits 16-23), shift right 3 so bit 19 reaches bit 0, EOR with byte 4 to bring in bit 32, rotate to put the feedback bit into carry, then ROL the five state bytes so carry enters bit 0.
|
|||||||||
| AF87 | .rnd_step←2← AF51 JSR← AF69 JSR | ||||||||
| LDY #&20 ; 32 single-bit steps make one RND advance | |||||||||
| AF89 | .rnd_step_loop←1← AF9C BNE | ||||||||
| LDA zp_rnd_seed_2 ; Byte 2 holds register bits 16-23 | |||||||||
| AF8B | LSR ; Shift right so bit 19 (tap 20)... | ||||||||
| AF8C | LSR ; shifting it down | ||||||||
| AF8D | LSR ; ...reaches bit 0 | ||||||||
| AF8E | EOR zp_rnd_seed_4 ; EOR byte 4 to bring in bit 32: bit19 XOR bit32 | ||||||||
| AF90 | ROR ; Rotate the feedback bit into carry | ||||||||
| AF91 | ROL zp_rnd_seed ; Shift the register left, feedback into bit 0 | ||||||||
| AF93 | ROL zp_rnd_seed_1 ; bits 8-15 | ||||||||
| AF95 | ROL zp_rnd_seed_2 ; bits 16-23 | ||||||||
| AF97 | ROL zp_rnd_seed_3 ; bits 24-31 | ||||||||
| AF99 | ROL zp_rnd_seed_4 ; bit 32 | ||||||||
| AF9B | DEY ; Next step | ||||||||
| AF9C | BNE rnd_step_loop ; Loop for all 32 steps | ||||||||
| AF9E | RTS ; The register has advanced | ||||||||
ERLLine number where the last error occurred. ERL.
|
|||||||||||||||
| AF9F | .fn_erl | ||||||||||||||
| LDY zp_erl_1 ; ERL high byte | |||||||||||||||
| AFA1 | LDA zp_erl ; low byte | ||||||||||||||
| AFA3 | JMP iwa_from_ya ; Return ERL as an integer | ||||||||||||||
ERRError number of the last error. ERR.
|
|||||||||||||||
| AFA6 | .fn_err | ||||||||||||||
| LDY #0 ; Read the error number... | |||||||||||||||
| AFA8 | LDA (zp_error_ptr),y ; ...from the error block (&FD) | ||||||||||||||
| AFAA | JMP iwa_from_ya ; Return ERR as an integer | ||||||||||||||
Read a key within a time limit (INKEY)Evaluate the time-limit argument at PtrB into IWA, then tail-call OSBYTE &81 (INKEY) to read a key with that timeout. Shared by the INKEY and INKEY$ functions.
|
|||||||||||
| AFAD | .read_key_timed←2← ACAD JSR← B026 JSR | ||||||||||
| JSR eval_factor_integer ; Evaluate the time-limit argument | |||||||||||
| AFB0 | LDA #osbyte_inkey ; OSBYTE &81: INKEY (read a key with a timeout) | ||||||||||
| AFB2 | LDX zp_iwa ; time limit low | ||||||||||
| AFB4 | LDY zp_iwa_1 ; time limit high | ||||||||||
| AFB6 | JMP osbyte ; INKEY: Scan for a key with positive X, or read internal key number EOR 128 for negative X | ||||||||||
GETWait for a key and return its ASCII code. GET.
|
|||||||||||||||
| AFB9 | .fn_get | ||||||||||||||
| JSR osrdch ; X=ASCII code typed (positive timeout) or internal key number EOR 128 (negative scan) / Y=0 if a key was pressed, Y=&FF on time-out, Y=&1B on Escape | |||||||||||||||
| AFBC | JMP int_result_a ; Return the key code as an integer | ||||||||||||||
GET$Read a key as a one-character string, or a byte / line from a file. GET$[#channel].
|
|||||||||||||||
| AFBF | .fn_gets | ||||||||||||||
| JSR osrdch ; Wait for a key | |||||||||||||||
| AFC2 | .gets_char←2← B02C BEQ← B3C2 JMP | ||||||||||||||
| STA string_work ; Store it as the one-character string body | |||||||||||||||
| AFC5 | LDA #1 ; Length 1 | ||||||||||||||
| AFC7 | STA zp_strbuf_len ; (store) | ||||||||||||||
| AFC9 | LDA #0 ; String type | ||||||||||||||
| AFCB | RTS ; Return the one-character string | ||||||||||||||
LEFT$Leftmost n characters of a string. LEFT$(string, n).
|
|||||||||||||||
| AFCC | .fn_lefts | ||||||||||||||
| JSR eval_or_eor ; Evaluate the source string | |||||||||||||||
| AFCF | BNE str_type_error ; not a string: Type mismatch | ||||||||||||||
| AFD1 | CPX #',' ; ','? | ||||||||||||||
| AFD3 | BNE str_missing_comma ; no: Missing , | ||||||||||||||
| AFD5 | INC zp_text_ptr2_off ; step past | ||||||||||||||
| AFD7 | JSR stack_string ; Stack the string | ||||||||||||||
| AFDA | JSR eval_subexpr ; Evaluate the count, expect ) | ||||||||||||||
| AFDD | JSR coerce_to_integer ; coerce to integer | ||||||||||||||
| AFE0 | JSR unstack_string ; Restore the string | ||||||||||||||
| AFE3 | LDA zp_iwa ; Count | ||||||||||||||
| AFE5 | CMP zp_strbuf_len ; count >= length? | ||||||||||||||
| AFE7 | BCS lefts_result ; yes: keep the whole string | ||||||||||||||
| AFE9 | STA zp_strbuf_len ; truncate to the count | ||||||||||||||
| AFEB | .lefts_result←1← AFE7 BCS | ||||||||||||||
| LDA #0 ; String result | |||||||||||||||
| AFED | RTS ; Return | ||||||||||||||
RIGHT$Rightmost n characters of a string. RIGHT$(string, n).
|
|||||||||||||||
| AFEE | .fn_rights | ||||||||||||||
| JSR eval_or_eor ; Evaluate the source string | |||||||||||||||
| AFF1 | BNE str_type_error ; not a string: Type mismatch | ||||||||||||||
| AFF3 | CPX #',' ; ','? | ||||||||||||||
| AFF5 | BNE str_missing_comma ; no: Missing , | ||||||||||||||
| AFF7 | INC zp_text_ptr2_off ; step past | ||||||||||||||
| AFF9 | JSR stack_string ; Stack the string | ||||||||||||||
| AFFC | JSR eval_subexpr ; Evaluate the count, expect ) | ||||||||||||||
| AFFF | JSR coerce_to_integer ; coerce to integer | ||||||||||||||
| B002 | JSR unstack_string ; Restore the string | ||||||||||||||
| B005 | LDA zp_strbuf_len ; Start = length - count | ||||||||||||||
| B007 | SEC ; ready the subtract | ||||||||||||||
| B008 | SBC zp_iwa ; minus the count: A = start offset | ||||||||||||||
| B00A | BCC rights_whole ; count > length: keep the whole string | ||||||||||||||
| B00C | BEQ return_31 ; count == length: keep it | ||||||||||||||
| B00E | TAX ; Start offset | ||||||||||||||
| B00F | LDA zp_iwa ; New length = count | ||||||||||||||
| B011 | STA zp_strbuf_len ; store the new (shorter) length | ||||||||||||||
| B013 | BEQ return_31 ; zero: empty string | ||||||||||||||
| B015 | LDY #0 ; Copy the last count chars to the front | ||||||||||||||
| B017 | .rights_copy_down←1← B021 BNE | ||||||||||||||
| LDA string_work,x ; Read a kept char from the tail (at X) | |||||||||||||||
| B01A | STA string_work,y ; Pack it down to the front (at Y) | ||||||||||||||
| B01D | INX ; Advance the read cursor | ||||||||||||||
| B01E | INY ; Advance the write cursor | ||||||||||||||
| B01F | DEC zp_iwa ; One fewer char to move | ||||||||||||||
| B021 | BNE rights_copy_down ; Until all count chars are shifted
down |
||||||||||||||
| B023 | .rights_whole←1← B00A BCC | ||||||||||||||
| LDA #0 ; Keep the whole string | |||||||||||||||
| B025 | .return_31←2← B00C BEQ← B013 BEQ | ||||||||||||||
| RTS ; Return | |||||||||||||||
INKEY$Read a key within a time limit as a string. INKEY$ numeric.
|
|||||||||||||||
| B026 | .fn_inkeys | ||||||||||||||
| JSR read_key_timed ; Read a key within the time limit | |||||||||||||||
| B029 | TXA ; X holds the key | ||||||||||||||
| B02A | CPY #0 ; Y=0 means a key was read | ||||||||||||||
| B02C | BEQ gets_char ; Got one: return it as a 1-char string | ||||||||||||||
| B02E | .inkeys_timeout←2← B06B BCS← B081 BEQ | ||||||||||||||
| LDA #0 ; Timeout: empty string | |||||||||||||||
| B030 | STA zp_strbuf_len ; length 0 | ||||||||||||||
| B032 | RTS ; Return the (possibly empty) string | ||||||||||||||
| B033 | .str_type_error←3← AFCF BNE← AFF1 BNE← B03C BNE | ||||||||||||||
| JMP err_type_mismatch ; Type mismatch (shared) | |||||||||||||||
| B036 | .str_missing_comma←4← AFD3 BNE← AFF5 BNE← B040 BNE← B059 BNE | ||||||||||||||
| JMP missing_comma ; Missing , error (shared) | |||||||||||||||
MID$Substring from a start position. MID$(string, start [,length]).
|
|||||||||||||||
| B039 | .fn_mids | ||||||||||||||
| JSR eval_or_eor ; Evaluate the source string | |||||||||||||||
| B03C | BNE str_type_error ; not a string: Type mismatch | ||||||||||||||
| B03E | CPX #',' ; ','? | ||||||||||||||
| B040 | BNE str_missing_comma ; no: Missing , | ||||||||||||||
| B042 | JSR stack_string ; Stack the string | ||||||||||||||
| B045 | INC zp_text_ptr2_off ; step past | ||||||||||||||
| B047 | JSR eval_expr_integer ; Evaluate the start position | ||||||||||||||
| B04A | LDA zp_iwa ; Save it | ||||||||||||||
| B04C | PHA ; push the start position | ||||||||||||||
| B04D | LDA #&ff ; Default length = 255 | ||||||||||||||
| B04F | STA zp_iwa ; as the length | ||||||||||||||
| B051 | INC zp_text_ptr2_off ; step past | ||||||||||||||
| B053 | CPX #')' ; ')' (no length given)? | ||||||||||||||
| B055 | BEQ mids_restore ; yes: use the default | ||||||||||||||
| B057 | CPX #',' ; ','? | ||||||||||||||
| B059 | BNE str_missing_comma ; no: Missing , | ||||||||||||||
| B05B | JSR eval_subexpr ; Evaluate the length, expect ) | ||||||||||||||
| B05E | JSR coerce_to_integer ; coerce to integer | ||||||||||||||
| B061 | .mids_restore←1← B055 BEQ | ||||||||||||||
| JSR unstack_string ; Restore the string | |||||||||||||||
| B064 | PLA ; Start position | ||||||||||||||
| B065 | TAY ; into Y (also tests for 0), | ||||||||||||||
| B066 | CLC ; clear carry for the compare | ||||||||||||||
| B067 | BEQ mids_start ; position 0: treat as 1 | ||||||||||||||
| B069 | SBC zp_strbuf_len ; past the end? | ||||||||||||||
| B06B | BCS inkeys_timeout ; yes: empty string | ||||||||||||||
| B06D | DEY ; Zero-based start = p - 1 | ||||||||||||||
| B06E | TYA ; A = start - 1 | ||||||||||||||
| B06F | .mids_start←1← B067 BEQ | ||||||||||||||
| STA zp_iwa_2 ; Save the start offset | |||||||||||||||
| B071 | TAX ; also into X (source index) | ||||||||||||||
| B072 | LDY #0 ; Destination index | ||||||||||||||
| B074 | LDA zp_strbuf_len ; Available = length - start | ||||||||||||||
| B076 | SEC ; set carry, | ||||||||||||||
| B077 | SBC zp_iwa_2 ; length - start offset | ||||||||||||||
| B079 | CMP zp_iwa ; more than requested? | ||||||||||||||
| B07B | BCS mids_length ; no: use the available count | ||||||||||||||
| B07D | STA zp_iwa ; clamp the length | ||||||||||||||
| B07F | .mids_length←1← B07B BCS | ||||||||||||||
| LDA zp_iwa ; Length | |||||||||||||||
| B081 | BEQ inkeys_timeout ; zero: empty string | ||||||||||||||
| B083 | .mids_copy_loop←1← B08D BNE | ||||||||||||||
| LDA string_work,x ; Copy the substring to the front | |||||||||||||||
| B086 | STA string_work,y ; to the front, | ||||||||||||||
| B089 | INY ; next dest, | ||||||||||||||
| B08A | INX ; next source, | ||||||||||||||
| B08B | CPY zp_iwa ; copied the requested length? | ||||||||||||||
| B08D | BNE mids_copy_loop ; loop | ||||||||||||||
| B08F | STY zp_strbuf_len ; Set the result length | ||||||||||||||
| B091 | LDA #0 ; String result | ||||||||||||||
| B093 | RTS ; Return | ||||||||||||||
STR$String form of a number (STR$~ for hex). STR$[~] numeric.
|
|||||||||||||||
| B094 | .fn_strs | ||||||||||||||
| JSR skip_spaces_ptr2 ; Next character | |||||||||||||||
| B097 | LDY #&ff ; assume hex | ||||||||||||||
| B099 | CMP #'~' ; '~' hex prefix? | ||||||||||||||
| B09B | BEQ strs_save_flag ; yes | ||||||||||||||
| B09D | LDY #0 ; no: decimal | ||||||||||||||
| B09F | DEC zp_text_ptr2_off ; back up | ||||||||||||||
| B0A1 | .strs_save_flag←1← B09B BEQ | ||||||||||||||
| TYA ; Save the hex/dec flag | |||||||||||||||
| B0A2 | PHA ; push it | ||||||||||||||
| B0A3 | JSR eval_factor ; Evaluate the number | ||||||||||||||
| B0A6 | BEQ strs_type_error ; string: error | ||||||||||||||
| B0A8 | TAY ; Restore the flag | ||||||||||||||
| B0A9 | PLA ; recover the hex/dec flag | ||||||||||||||
| B0AA | STA zp_print_flag ; @% formatting set? | ||||||||||||||
| B0AC | LDA resint_at_3 ; yes: use it | ||||||||||||||
| B0AF | BNE strs_formatted ; Default conversion | ||||||||||||||
| B0B1 | STA zp_general ; clear &37 (default format) | ||||||||||||||
| B0B3 | JSR nta_default_digits ; string result | ||||||||||||||
| B0B6 | LDA #0 ; Return | ||||||||||||||
| B0B8 | RTS ; Return | ||||||||||||||
| B0B9 | .strs_formatted←1← B0AF BNE | ||||||||||||||
| JSR number_to_ascii ; Formatted conversion (@%) | |||||||||||||||
| B0BC | LDA #0 ; string result | ||||||||||||||
| B0BE | RTS ; Return | ||||||||||||||
| B0BF | .strs_type_error←2← B0A6 BEQ← B0CE BNE | ||||||||||||||
| JMP err_type_mismatch ; Type mismatch error | |||||||||||||||
STRING$A string repeated n times. STRING$(n, string).
|
|||||||||||||||
| B0C2 | .fn_strings | ||||||||||||||
| JSR eval_expr_integer ; Evaluate the count (n) as an integer | |||||||||||||||
| B0C5 | JSR stack_integer ; stack it | ||||||||||||||
| B0C8 | JSR skip_spaces_expect_comma ; require a comma | ||||||||||||||
| B0CB | JSR eval_subexpr ; evaluate the string s$ | ||||||||||||||
| B0CE | BNE strs_type_error ; not a string: Type mismatch | ||||||||||||||
| B0D0 | JSR unstack_integer ; recover the count | ||||||||||||||
| B0D3 | LDY zp_strbuf_len ; source string length | ||||||||||||||
| B0D5 | BEQ strings_type ; empty source: empty result | ||||||||||||||
| B0D7 | LDA zp_iwa ; count = 0? | ||||||||||||||
| B0D9 | BEQ strings_empty ; yes: empty result | ||||||||||||||
| B0DB | DEC zp_iwa ; one copy is already there; need count-1 more | ||||||||||||||
| B0DD | BEQ strings_type ; count = 1: done | ||||||||||||||
| B0DF | .strings_append←1← B0F1 BNE | ||||||||||||||
| LDX #0 ; Append another copy: | |||||||||||||||
| B0E1 | .strings_copy_loop←1← B0ED BCC | ||||||||||||||
| LDA string_work,x ; source char... | |||||||||||||||
| B0E4 | STA string_work,y ; ...appended | ||||||||||||||
| B0E7 | INX ; next source | ||||||||||||||
| B0E8 | INY ; next dest | ||||||||||||||
| B0E9 | BEQ strings_too_long ; too long: error | ||||||||||||||
| B0EB | CPX zp_strbuf_len ; end of this copy? | ||||||||||||||
| B0ED | BCC strings_copy_loop ; no: keep copying | ||||||||||||||
| B0EF | DEC zp_iwa ; one fewer copy | ||||||||||||||
| B0F1 | BNE strings_append ; loop | ||||||||||||||
| B0F3 | STY zp_strbuf_len ; set the result length | ||||||||||||||
| B0F5 | .strings_type←2← B0D5 BEQ← B0DD BEQ | ||||||||||||||
| LDA #0 ; string type | |||||||||||||||
| B0F7 | RTS ; Return | ||||||||||||||
| B0F8 | .strings_empty←1← B0D9 BEQ | ||||||||||||||
| STA zp_strbuf_len ; empty result (length 0) | |||||||||||||||
| B0FA | RTS ; Return | ||||||||||||||
| B0FB | .strings_too_long←1← B0E9 BEQ | ||||||||||||||
| JMP string_too_long ; String too long error | |||||||||||||||
| B0FE | .no_such_fn_proc←1← B11E BMI | ||||||||||||||
| PLA ; No such FN/PROC: restore the text pointer | |||||||||||||||
| B0FF | STA zp_text_ptr_1 ; pointer high | ||||||||||||||
| B101 | PLA ; pull the low byte | ||||||||||||||
| B102 | STA zp_text_ptr ; pointer low | ||||||||||||||
| B104 | BRK ; "No such FN/PROC" error block | ||||||||||||||
| B105 | EQUB &1D | ||||||||||||||
| B106 | EQUS "No such " | ||||||||||||||
| B10E | EQUB &A4, &2F, &F2, &00 | ||||||||||||||
Find a PROC/FN definition by nameWalk the program from PAGE for the DEF PROC/FN line whose name matches the reference at (zp_general), then cache its body address in the variable entry so later calls resolve quickly. Raises No such FN/PROC.
|
|||||||||
| B112 | .find_def←1← B1E6 JMP | ||||||||
| LDA zp_page ; Search from PAGE: high | |||||||||
| B114 | STA zp_text_ptr_1 ; (store) | ||||||||
| B116 | LDA #0 ; low 0 | ||||||||
| B118 | STA zp_text_ptr ; (store) | ||||||||
| B11A | .finddef_scan←2← B136 BCC← B13A BCS | ||||||||
| LDY #1 ; line number high byte | |||||||||
| B11C | LDA (zp_text_ptr),y ; read it | ||||||||
| B11E | BMI no_such_fn_proc ; end of program: not found | ||||||||
| B120 | LDY #3 ; skip to the line body | ||||||||
| B122 | .finddef_advance←1← B127 BEQ | ||||||||
| INY ; advance | |||||||||
| B123 | LDA (zp_text_ptr),y ; char | ||||||||
| B125 | CMP #' ' ; skip leading spaces | ||||||||
| B127 | BEQ finddef_advance ; skip it | ||||||||
| B129 | CMP #&dd ; DEF token at the start? | ||||||||
| B12B | BEQ finddef_found ; yes: check the name | ||||||||
| B12D | .finddef_next_line←2← B15E BNE← B16A BCS | ||||||||
| LDY #3 ; no DEF: skip to the next line | |||||||||
| B12F | LDA (zp_text_ptr),y ; line length | ||||||||
| B131 | CLC ; add the line length... | ||||||||
| B132 | ADC zp_text_ptr ; to the pointer low, | ||||||||
| B134 | STA zp_text_ptr ; (store) | ||||||||
| B136 | BCC finddef_scan ; no carry | ||||||||
| B138 | INC zp_text_ptr_1 ; carry into the pointer high | ||||||||
| B13A | BCS finddef_scan ; next line | ||||||||
| B13C | .finddef_found←1← B12B BEQ | ||||||||
| INY ; DEF found: skip past the FN/PROC token | |||||||||
| B13D | STY zp_text_ptr_off ; (store the offset) | ||||||||
| B13F | JSR skip_spaces ; skip spaces | ||||||||
| B142 | TYA ; point at the definition name: | ||||||||
| B143 | TAX ; X = the name offset | ||||||||
| B144 | CLC ; pointer + offset: | ||||||||
| B145 | ADC zp_text_ptr ; low, | ||||||||
| B147 | LDY zp_text_ptr_1 ; high, | ||||||||
| B149 | BCC finddef_name_setup ; no carry | ||||||||
| B14B | INY ; carry into high | ||||||||
| B14C | CLC ; (borrow for the -1) | ||||||||
| B14D | .finddef_name_setup←1← B149 BCC | ||||||||
| SBC #0 ; minus 1 (loop pre-increments Y) | |||||||||
| B14F | STA zp_fwb_ovf ; (save pointer low) | ||||||||
| B151 | TYA ; high byte... | ||||||||
| B152 | SBC #0 ; minus the borrow | ||||||||
| B154 | STA zp_fwb_exp ; (save pointer high) | ||||||||
| B156 | LDY #0 ; Compare the definition name with the called name: | ||||||||
| B158 | .finddef_match_loop←1← B162 BNE | ||||||||
| INY ; next char | |||||||||
| B159 | INX ; advance both cursors | ||||||||
| B15A | LDA (zp_fwb_ovf),y ; definition char | ||||||||
| B15C | CMP (zp_general),y ; vs called char | ||||||||
| B15E | BNE finddef_next_line ; differ: next line | ||||||||
| B160 | CPY zp_fileblk ; end of the called name? | ||||||||
| B162 | BNE finddef_match_loop ; no: keep comparing | ||||||||
| B164 | INY ; definition name also ends? | ||||||||
| B165 | LDA (zp_fwb_ovf),y ; read the next def char | ||||||||
| B167 | JSR is_alphanumeric ; alphanumeric? | ||||||||
| B16A | BCS finddef_next_line ; definition name is longer: next line | ||||||||
| B16C | TXA ; Match: cache the definition | ||||||||
| B16D | TAY ; Y = name length | ||||||||
| B16E | JSR skip_to_statement_end ; point PtrA at the body | ||||||||
| B171 | JSR create_def_entry ; create/find the FN/PROC entry | ||||||||
| B174 | LDX #1 ; init it | ||||||||
| B176 | JSR clear_value_bytes ; initialise the value | ||||||||
| B179 | LDY #0 ; store the body pointer: | ||||||||
| B17B | LDA zp_text_ptr ; pointer low... | ||||||||
| B17D | STA (zp_vartop),y ; (store) | ||||||||
| B17F | INY ; next byte | ||||||||
| B180 | LDA zp_text_ptr_1 ; pointer high... | ||||||||
| B182 | STA (zp_vartop),y ; (store) | ||||||||
| B184 | JSR advance_vartop ; advance VARTOP | ||||||||
| B187 | JMP callpf_push_count ; continue | ||||||||
| B18A | .finddef_not_found←1← B1DA BEQ | ||||||||
| BRK ; error block | |||||||||
| B18B | EQUB &1E | ||||||||
| B18C | EQUS "Bad call" | ||||||||
| B194 | EQUB &00 | ||||||||
FNCall a user-defined function and return its value. FNname[(params)].
|
|||||||||||||||
| B195 | .fn_fn | ||||||||||||||
| LDA #&a4 ; FN token: enter via the PROC/FN call mechanism | |||||||||||||||
| fall through ↓ | |||||||||||||||
Enter a PROC or FNThe procedure/function call mechanism. It lets PROCs and FNs nest far beyond the 256-byte 6502 stack by moving that stack out of the way for each call:
The 10-byte call frame, on the freshly emptied hardware stack while the body runs (deepest byte first):
The addresses are absolute because the stack was just emptied -- which
is why Unwinding is indirect: ENDPROC and What is NOT saved: only the hardware stack and the BASIC value stack
are preserved. The FOR/REPEAT/GOSUB stacks (page 5, counters
&26/&24/&25) are global and untouched, so a loop left early via
ENDPROC or GOTO leaks its frame. See
|
|||||||||||||||||||||||||||||||||||||
| B197 | .call_proc_fn←1← 9312 JSR | ||||||||||||||||||||||||||||||||||||
| STA zp_var_type ; Save the PROC/FN token | |||||||||||||||||||||||||||||||||||||
| B199 | TSX ; Copy the 6502 stack onto the BASIC stack | ||||||||||||||||||||||||||||||||||||
| B19A | TXA ; stack pointer to A, | ||||||||||||||||||||||||||||||||||||
| B19B | CLC ; add the BASIC stack pointer | ||||||||||||||||||||||||||||||||||||
| B19C | ADC zp_stack_ptr ; Drop the BASIC stack by the 6502 stack size | ||||||||||||||||||||||||||||||||||||
| B19E | JSR reserve_stack ; so procedures can nest far beyond 256 bytes | ||||||||||||||||||||||||||||||||||||
| B1A1 | LDY #0 ; Store the 6502 stack pointer first | ||||||||||||||||||||||||||||||||||||
| B1A3 | TXA ; the saved SP, | ||||||||||||||||||||||||||||||||||||
| B1A4 | STA (zp_stack_ptr),y ; at offset 0 | ||||||||||||||||||||||||||||||||||||
| B1A6 | .callpf_save_stack←1← B1AF BNE | ||||||||||||||||||||||||||||||||||||
| INX ; Copy each 6502 stack byte | |||||||||||||||||||||||||||||||||||||
| B1A7 | INY ; next dest, | ||||||||||||||||||||||||||||||||||||
| B1A8 | LDA hw_stack,x ; read a stack byte, | ||||||||||||||||||||||||||||||||||||
| B1AB | STA (zp_stack_ptr),y ; to the BASIC stack, | ||||||||||||||||||||||||||||||||||||
| B1AD | CPX #&ff ; whole stack copied? | ||||||||||||||||||||||||||||||||||||
| B1AF | BNE callpf_save_stack ; loop | ||||||||||||||||||||||||||||||||||||
| B1B1 | TXS ; Empty the 6502 stack | ||||||||||||||||||||||||||||||||||||
| B1B2 | LDA zp_var_type ; PROC/FN token | ||||||||||||||||||||||||||||||||||||
| B1B4 | PHA ; Push the call context and return pointers | ||||||||||||||||||||||||||||||||||||
| B1B5 | LDA zp_text_ptr_off ; return line offset | ||||||||||||||||||||||||||||||||||||
| B1B7 | PHA ; push it | ||||||||||||||||||||||||||||||||||||
| B1B8 | LDA zp_text_ptr ; return line pointer | ||||||||||||||||||||||||||||||||||||
| B1BA | PHA ; push low, | ||||||||||||||||||||||||||||||||||||
| B1BB | LDA zp_text_ptr_1 ; high byte, | ||||||||||||||||||||||||||||||||||||
| B1BD | PHA ; push high | ||||||||||||||||||||||||||||||||||||
| B1BE | LDA zp_text_ptr2_off ; Point &37/&38 at the PROC/FN name | ||||||||||||||||||||||||||||||||||||
| B1C0 | TAX ; keep the offset, | ||||||||||||||||||||||||||||||||||||
| B1C1 | CLC ; add the parser pointer: | ||||||||||||||||||||||||||||||||||||
| B1C2 | ADC zp_text_ptr2 ; low byte, | ||||||||||||||||||||||||||||||||||||
| B1C4 | LDY zp_text_ptr2_1 ; high byte in Y, | ||||||||||||||||||||||||||||||||||||
| B1C6 | BCC callpf_back ; no carry, | ||||||||||||||||||||||||||||||||||||
| B1C8 | INY ; carry into high, | ||||||||||||||||||||||||||||||||||||
| B1C9 | CLC ; clear carry, | ||||||||||||||||||||||||||||||||||||
| B1CA | .callpf_back←1← B1C6 BCC | ||||||||||||||||||||||||||||||||||||
| SBC #1 ; back up one: low, | |||||||||||||||||||||||||||||||||||||
| B1CC | STA zp_general ; to &37, | ||||||||||||||||||||||||||||||||||||
| B1CE | TYA ; high byte, | ||||||||||||||||||||||||||||||||||||
| B1CF | SBC #0 ; with borrow, | ||||||||||||||||||||||||||||||||||||
| B1D1 | STA zp_general_1 ; to &38 | ||||||||||||||||||||||||||||||||||||
| B1D3 | LDY #2 ; Validate the name | ||||||||||||||||||||||||||||||||||||
| B1D5 | JSR valname_loop ; scan it from offset 2 | ||||||||||||||||||||||||||||||||||||
| B1D8 | CPY #2 ; no valid characters? | ||||||||||||||||||||||||||||||||||||
| B1DA | BEQ finddef_not_found ; yes: Bad call | ||||||||||||||||||||||||||||||||||||
| B1DC | STX zp_text_ptr2_off ; Offset past the name | ||||||||||||||||||||||||||||||||||||
| B1DE | DEY ; Name length | ||||||||||||||||||||||||||||||||||||
| B1DF | STY zp_fileblk ; store it (&39) | ||||||||||||||||||||||||||||||||||||
| B1E1 | JSR find_proc_fn ; Look it up in the heap cache | ||||||||||||||||||||||||||||||||||||
| B1E4 | BNE callpf_set_ptr ; found: jump to it | ||||||||||||||||||||||||||||||||||||
| B1E6 | JMP find_def ; not cached: scan the program | ||||||||||||||||||||||||||||||||||||
| B1E9 | .callpf_set_ptr←1← B1E4 BNE | ||||||||||||||||||||||||||||||||||||
| LDY #0 ; Set PtrA to the definition address | |||||||||||||||||||||||||||||||||||||
| B1EB | LDA (zp_iwa),y ; low byte, | ||||||||||||||||||||||||||||||||||||
| B1ED | STA zp_text_ptr ; to PtrA low, | ||||||||||||||||||||||||||||||||||||
| B1EF | INY ; next, | ||||||||||||||||||||||||||||||||||||
| B1F0 | LDA (zp_iwa),y ; high byte, | ||||||||||||||||||||||||||||||||||||
| B1F2 | STA zp_text_ptr_1 ; to PtrA high | ||||||||||||||||||||||||||||||||||||
| B1F4 | .callpf_push_count←1← B187 JMP | ||||||||||||||||||||||||||||||||||||
| LDA #0 ; Push the parameter count (0 so far) | |||||||||||||||||||||||||||||||||||||
| B1F6 | PHA ; push it, | ||||||||||||||||||||||||||||||||||||
| B1F7 | STA zp_text_ptr_off ; offset = 0 | ||||||||||||||||||||||||||||||||||||
| B1F9 | JSR skip_spaces ; Next character | ||||||||||||||||||||||||||||||||||||
| B1FC | CMP #'(' ; '(' parameters? | ||||||||||||||||||||||||||||||||||||
| B1FE | BEQ callpf_save_parser2 ; yes: bind them | ||||||||||||||||||||||||||||||||||||
| B200 | DEC zp_text_ptr_off ; no: back up | ||||||||||||||||||||||||||||||||||||
| B202 | .callpf_save_parser←1← B30A JMP | ||||||||||||||||||||||||||||||||||||
| LDA zp_text_ptr2_off ; Save the parser pointer | |||||||||||||||||||||||||||||||||||||
| B204 | PHA ; push offset, | ||||||||||||||||||||||||||||||||||||
| B205 | LDA zp_text_ptr2 ; low byte, | ||||||||||||||||||||||||||||||||||||
| B207 | PHA ; push low, | ||||||||||||||||||||||||||||||||||||
| B208 | LDA zp_text_ptr2_1 ; high byte, | ||||||||||||||||||||||||||||||||||||
| B20A | PHA ; push high | ||||||||||||||||||||||||||||||||||||
| B20B | JSR next_statement ; Execute the body | ||||||||||||||||||||||||||||||||||||
| B20E | PLA ; Restore the parser pointer | ||||||||||||||||||||||||||||||||||||
| B20F | STA zp_text_ptr2_1 ; high byte, | ||||||||||||||||||||||||||||||||||||
| B211 | PLA ; pull low, | ||||||||||||||||||||||||||||||||||||
| B212 | STA zp_text_ptr2 ; low byte, | ||||||||||||||||||||||||||||||||||||
| B214 | PLA ; pull offset, | ||||||||||||||||||||||||||||||||||||
| B215 | STA zp_text_ptr2_off ; offset | ||||||||||||||||||||||||||||||||||||
| B217 | PLA ; Number of LOCAL/parameter values to restore | ||||||||||||||||||||||||||||||||||||
| B218 | BEQ callpf_restore_ptr ; none: skip | ||||||||||||||||||||||||||||||||||||
| B21A | STA zp_fwb_m2 ; count | ||||||||||||||||||||||||||||||||||||
| B21C | .callpf_restore_locals←1← B224 BNE | ||||||||||||||||||||||||||||||||||||
| JSR unstack_int_to_general ; Unstack the variable address | |||||||||||||||||||||||||||||||||||||
| B21F | JSR unstack_value_to_var ; restore its saved value | ||||||||||||||||||||||||||||||||||||
| B222 | DEC zp_fwb_m2 ; one done | ||||||||||||||||||||||||||||||||||||
| B224 | BNE callpf_restore_locals ; loop | ||||||||||||||||||||||||||||||||||||
| B226 | .callpf_restore_ptr←1← B218 BEQ | ||||||||||||||||||||||||||||||||||||
| PLA ; Restore PtrA | |||||||||||||||||||||||||||||||||||||
| B227 | STA zp_text_ptr_1 ; high byte, | ||||||||||||||||||||||||||||||||||||
| B229 | PLA ; pull low, | ||||||||||||||||||||||||||||||||||||
| B22A | STA zp_text_ptr ; low byte, | ||||||||||||||||||||||||||||||||||||
| B22C | PLA ; pull offset, | ||||||||||||||||||||||||||||||||||||
| B22D | STA zp_text_ptr_off ; offset | ||||||||||||||||||||||||||||||||||||
| B22F | PLA ; Recover the saved 6502 stack pointer | ||||||||||||||||||||||||||||||||||||
| B230 | LDY #0 ; from offset 0, | ||||||||||||||||||||||||||||||||||||
| B232 | LDA (zp_stack_ptr),y ; the saved SP, | ||||||||||||||||||||||||||||||||||||
| B234 | TAX ; into X | ||||||||||||||||||||||||||||||||||||
| B235 | TXS ; restore it | ||||||||||||||||||||||||||||||||||||
| B236 | .callpf_restore_stack←1← B23F BNE | ||||||||||||||||||||||||||||||||||||
| INY ; Copy each byte back to the 6502 stack | |||||||||||||||||||||||||||||||||||||
| B237 | INX ; next slot, | ||||||||||||||||||||||||||||||||||||
| B238 | LDA (zp_stack_ptr),y ; read from the BASIC stack, | ||||||||||||||||||||||||||||||||||||
| B23A | STA hw_stack,x ; to the 6502 stack, | ||||||||||||||||||||||||||||||||||||
| B23D | CPX #&ff ; whole stack restored? | ||||||||||||||||||||||||||||||||||||
| B23F | BNE callpf_restore_stack ; loop | ||||||||||||||||||||||||||||||||||||
| B241 | TYA ; Adjust the BASIC stack pointer back up | ||||||||||||||||||||||||||||||||||||
| B242 | ADC zp_stack_ptr ; free the copied bytes, | ||||||||||||||||||||||||||||||||||||
| B244 | STA zp_stack_ptr ; store low, | ||||||||||||||||||||||||||||||||||||
| B246 | BCC callpf_return ; no carry, | ||||||||||||||||||||||||||||||||||||
| B248 | INC zp_stack_ptr_1 ; carry into high | ||||||||||||||||||||||||||||||||||||
| B24A | .callpf_return←1← B246 BCC | ||||||||||||||||||||||||||||||||||||
| LDA zp_var_type ; Return the PROC/FN token | |||||||||||||||||||||||||||||||||||||
| B24C | RTS ; Return | ||||||||||||||||||||||||||||||||||||
Bind the PROC/FN parametersEach formal is parsed by |
|
| B24D | .callpf_save_parser2←2← B1FE BEQ← B27E BEQ |
| LDA zp_text_ptr2_off ; Save the parser pointer | |
| B24F | PHA ; push offset, |
| B250 | LDA zp_text_ptr2 ; low byte, |
| B252 | PHA ; push low, |
| B253 | LDA zp_text_ptr2_1 ; high byte, |
| B255 | PHA ; push high |
| B256 | JSR parse_lvalue ; Parse a formal parameter (any lvalue: parse_lvalue) |
| B259 | BEQ callpf_reset_stack ; invalid: error |
| B25B | LDA zp_text_ptr2_off ; Update the program pointer |
| B25D | STA zp_text_ptr_off ; from the PtrB offset |
| B25F | PLA ; Restore the parser pointer |
| B260 | STA zp_text_ptr2_1 ; high byte, |
| B262 | PLA ; pull low, |
| B263 | STA zp_text_ptr2 ; low byte, |
| B265 | PLA ; pull offset, |
| B266 | STA zp_text_ptr2_off ; offset |
| B268 | PLA ; Recover the running count |
| B269 | TAX ; into X |
| B26A | LDA zp_iwa_2 ; Push the formal's type/address |
| B26C | PHA ; push type, |
| B26D | LDA zp_iwa_1 ; address high, |
| B26F | PHA ; push it, |
| B270 | LDA zp_iwa ; address low, |
| B272 | PHA ; push it |
| B273 | INX ; count this parameter |
| B274 | TXA ; the new count, |
| B275 | PHA ; push it |
| B276 | JSR stack_local ; Stack the current value for LOCAL restore |
| B279 | JSR skip_spaces ; Skip spaces |
| B27C | CMP #',' ; ',' another parameter? |
| B27E | BEQ callpf_save_parser2 ; yes |
| B280 | CMP #')' ; ')' end of parameter list? |
| B282 | BNE callpf_reset_stack ; no: error |
| B284 | LDA #0 ; Push the end marker |
| B286 | PHA ; push it |
| B287 | JSR skip_spaces_ptr2 ; Expect "(" for the arguments |
| B28A | CMP #'(' ; '(' ? |
| B28C | BNE callpf_reset_stack ; missing: error |
| B28E | .callpf_arg_loop←1← B2A5 BEQ |
| JSR eval_or_eor ; Evaluate an argument | |
| B291 | JSR stack_value ; stack its value |
| B294 | LDA zp_var_type ; save the type |
| B296 | STA zp_iwa_3 ; keep it |
| B298 | JSR stack_integer ; stack the type |
| B29B | PLA ; Bump the argument count |
| B29C | TAX ; into X, |
| B29D | INX ; increment, |
| B29E | TXA ; back to A, |
| B29F | PHA ; push it |
| B2A0 | JSR skip_spaces_ptr2 ; Skip spaces |
| B2A3 | CMP #',' ; ',' another argument? |
| B2A5 | BEQ callpf_arg_loop ; yes |
| B2A7 | CMP #')' ; ')' end of arguments? |
| B2A9 | BNE callpf_reset_stack ; no: error |
| B2AB | PLA ; Recover the argument count |
| B2AC | PLA ; and the formal count |
| B2AD | STA zp_coeff_ptr ; to &4D, |
| B2AF | STA zp_coeff_ptr_1 ; and &4E |
| B2B1 | CPX zp_coeff_ptr ; counts match? |
| B2B3 | BEQ callpf_unstack_arg ; yes: bind them |
| B2B5 | .callpf_reset_stack←6← B259 BEQ← B282 BNE← B28C BNE← B2A9 BNE← B2DA BEQ← B2FB BNE |
| LDX #&fb ; Reset the stack | |
| B2B7 | TXS ; set SP = &FB |
| B2B8 | PLA ; restore PtrA |
| B2B9 | STA zp_text_ptr_1 ; high byte, |
| B2BB | PLA ; pull low, |
| B2BC | STA zp_text_ptr ; low byte |
| B2BE | BRK ; Arguments error |
| B2BF | EQUB &1F |
| B2C0 | EQUS "Arguments" |
| B2C9 | EQUB &00 |
| B2CA | .callpf_unstack_arg←2← B2B3 BEQ← B305 BNE |
| JSR unstack_integer ; Unstack the argument type | |
| B2CD | PLA ; Unstack the formal address/type |
| B2CE | STA zp_iwa ; address low, |
| B2D0 | PLA ; pull high, |
| B2D1 | STA zp_iwa_1 ; address high, |
| B2D3 | PLA ; pull type, |
| B2D4 | STA zp_iwa_2 ; type |
| B2D6 | BMI callpf_string_formal ; string formal? |
| B2D8 | LDA zp_iwa_3 ; Argument type |
| B2DA | BEQ callpf_reset_stack ; string argument: Arguments error |
| B2DC | STA zp_var_type ; numeric: set the formal address |
| B2DE | LDX #&37 ; address via &37, |
| B2E0 | JSR iwa_store_zp ; copy the address there |
| B2E3 | LDA zp_var_type ; Argument type |
| B2E5 | BPL callpf_assign_int ; integer? |
| B2E7 | JSR unstack_real ; real: unstack the real value |
| B2EA | JSR fwa_unpack_var ; into FWA |
| B2ED | JMP callpf_assign ; assign it |
| B2F0 | .callpf_assign_int←1← B2E5 BPL |
| JSR unstack_integer ; unstack the integer value | |
| B2F3 | .callpf_assign←1← B2ED JMP |
| JSR assign_num_by_type ; Assign to the formal | |
| B2F6 | JMP callpf_bound ; next argument |
| B2F9 | .callpf_string_formal←1← B2D6 BMI |
| LDA zp_iwa_3 ; String formal: argument type | |
| B2FB | BNE callpf_reset_stack ; numeric argument: Arguments error |
| B2FD | JSR unstack_string ; Unstack the string |
| B300 | JSR assign_string_to ; assign it |
| B303 | .callpf_bound←1← B2F6 JMP |
| DEC zp_coeff_ptr ; One parameter bound | |
| B305 | BNE callpf_unstack_arg ; loop |
| B307 | LDA zp_coeff_ptr_1 ; Push the parameter count for restore |
| B309 | PHA ; push it |
| B30A | JMP callpf_save_parser ; Execute the body |
Save a variable for LOCALPush a variable's current value and identity (address and type) onto the BASIC stack so ENDPROC can restore it, implementing LOCAL.
|
|||||||||
| B30D | .stack_local←2← 932D JSR← B276 JSR | ||||||||
| LDY zp_iwa_2 ; Variable type | |||||||||
| B30F | CPY #4 ; an integer? | ||||||||
| B311 | BNE local_load_value ; no | ||||||||
| B313 | LDX #&37 ; integer: address its 4 bytes via &37 | ||||||||
| B315 | JSR iwa_store_zp ; copy them there | ||||||||
| B318 | .local_load_value←1← B311 BNE | ||||||||
| JSR load_var_by_type ; Load the variable's current value by type | |||||||||
| B31B | PHP ; save the type flags | ||||||||
| B31C | JSR stack_value ; push the value onto the stack | ||||||||
| B31F | PLP ; restore the type | ||||||||
| B320 | BEQ local_push_id ; byte/string | ||||||||
| B322 | BMI local_push_id ; or string | ||||||||
| B324 | LDX #&37 ; integer: reload | ||||||||
| B326 | JSR iwa_load_zp ; from &37 | ||||||||
| B329 | .local_push_id←2← B320 BEQ← B322 BMI | ||||||||
| JMP stack_integer ; push the variable identity (as an integer) | |||||||||
Load a variable by typeDispatch on the variable type code in zp_iwa_2 and load the variable addressed by (zp_iwa) into the appropriate accumulator: a string into the string buffer (load_string_var), a byte or 4-byte integer into IWA (iwa_load_var / load_byte_var), or a 5-byte real into FWA (load_real_var). Negative = string, 0 = byte, 5 = real, anything else = integer.
|
|||||||||||||||
| B32C | .load_var_by_type←3← 9685 JSR← AE27 JMP← B318 JSR | ||||||||||||||
| LDY zp_iwa_2 ; Load the variable by type: | |||||||||||||||
| B32E | BMI load_string_var ; string | ||||||||||||||
| B330 | BEQ load_byte_var ; byte | ||||||||||||||
| B332 | CPY #5 ; real? | ||||||||||||||
| B334 | BEQ load_real_var ; real (else integer) | ||||||||||||||
| fall through ↓ | |||||||||||||||
Load an integer variable into the accumulatorCopy the 4-byte integer addressed by zp_iwa into IWA.
|
|||||||||
| B336 | .iwa_load_var | ||||||||
| LDY #3 ; Load a 4-byte integer (MSB first): byte 3 | |||||||||
| B338 | LDA (zp_iwa),y ; read it | ||||||||
| B33A | STA zp_iwa_3 ; (into IWA) | ||||||||
| B33C | DEY ; next | ||||||||
| B33D | LDA (zp_iwa),y ; byte 2 | ||||||||
| B33F | STA zp_iwa_2 ; (into IWA) | ||||||||
| B341 | DEY ; next | ||||||||
| B342 | LDA (zp_iwa),y ; byte 1 | ||||||||
| B344 | TAX ; (keep in X) | ||||||||
| B345 | DEY ; next | ||||||||
| B346 | LDA (zp_iwa),y ; byte 0 | ||||||||
| B348 | STA zp_iwa ; (store last) | ||||||||
| B34A | STX zp_iwa_1 ; byte 1 from X | ||||||||
| B34C | LDA #&40 ; integer type | ||||||||
| B34E | RTS ; Return the integer | ||||||||
Load a byte variable into IWARead the byte addressed by zp_iwa and return it as an unsigned integer in IWA (via iwa_from_ya). Part of the typed variable loader.
|
|||||||||||
| B34F | .load_byte_var←1← B330 BEQ | ||||||||||
| LDA (zp_iwa),y ; Read the byte | |||||||||||
| B351 | JMP iwa_from_ya ; return as an integer | ||||||||||
Load a real variable into FWAUnpack the 5-byte packed real addressed by zp_iwa (used here as a pointer to the variable) into FWA, restoring the implied leading 1 unless the value is zero. Part of the typed variable loader.
|
|||||||||||
| B354 | .load_real_var←2← B334 BEQ← B766 JSR | ||||||||||
| DEY ; Unpack a 5-byte real into FWA: byte 4... | |||||||||||
| B355 | LDA (zp_iwa),y ; read it | ||||||||||
| B357 | STA zp_fwa_m4 ; -> m4 | ||||||||||
| B359 | DEY ; next | ||||||||||
| B35A | LDA (zp_iwa),y ; byte 3... | ||||||||||
| B35C | STA zp_fwa_m3 ; -> m3 | ||||||||||
| B35E | DEY ; next | ||||||||||
| B35F | LDA (zp_iwa),y ; byte 2... | ||||||||||
| B361 | STA zp_fwa_m2 ; -> m2 | ||||||||||
| B363 | DEY ; next | ||||||||||
| B364 | LDA (zp_iwa),y ; byte 1 (sign + MSB)... | ||||||||||
| B366 | STA zp_fwa_sign ; -> sign byte | ||||||||||
| B368 | DEY ; next | ||||||||||
| B369 | LDA (zp_iwa),y ; byte 0... | ||||||||||
| B36B | STA zp_fwa_exp ; -> exponent | ||||||||||
| B36D | STY zp_fwa_rnd ; clear rounding | ||||||||||
| B36F | STY zp_fwa_ovf ; clear overflow | ||||||||||
| B371 | ORA zp_fwa_sign ; test for zero... | ||||||||||
| B373 | ORA zp_fwa_m2 ; m2, | ||||||||||
| B375 | ORA zp_fwa_m3 ; m3, | ||||||||||
| B377 | ORA zp_fwa_m4 ; m4 | ||||||||||
| B379 | BEQ lrv_set_msb ; zero: leave the MSB clear | ||||||||||
| B37B | LDA zp_fwa_sign ; restore the implied 1... | ||||||||||
| B37D | ORA #&80 ; set the top bit | ||||||||||
| B37F | .lrv_set_msb←1← B379 BEQ | ||||||||||
| STA zp_fwa_m1 ; store the mantissa MSB | |||||||||||
| B381 | LDA #&ff ; real type | ||||||||||
| B383 | RTS ; Return the real | ||||||||||
Load a string variable into the bufferCopy a string variable into the string buffer. A normal string variable carries its pointer and length in the descriptor at (zp_iwa); a $-string (Y = &80) is read from (zp_iwa) up to the terminating CR. Part of the typed variable loader.
|
|||||||||||||
| B384 | .load_string_var←1← B32E BMI | ||||||||||||
| CPY #&80 ; $-string (absolute address)? | |||||||||||||
| B386 | BEQ lsv_dollar ; yes | ||||||||||||
| B388 | LDY #3 ; normal string: length at offset 3 | ||||||||||||
| B38A | LDA (zp_iwa),y ; read it | ||||||||||||
| B38C | STA zp_strbuf_len ; string length | ||||||||||||
| B38E | BEQ return_32 ; empty: done | ||||||||||||
| B390 | LDY #1 ; string pointer high | ||||||||||||
| B392 | LDA (zp_iwa),y ; read it | ||||||||||||
| B394 | STA zp_general_1 ; into the source pointer (high) | ||||||||||||
| B396 | DEY ; low | ||||||||||||
| B397 | LDA (zp_iwa),y ; read it | ||||||||||||
| B399 | STA zp_general ; and the low byte | ||||||||||||
| B39B | LDY zp_strbuf_len ; copy into the buffer: | ||||||||||||
| B39D | .lsv_copy_loop←1← B3A4 BNE | ||||||||||||
| DEY ; char... | |||||||||||||
| B39E | LDA (zp_general),y ; read it | ||||||||||||
| B3A0 | STA string_work,y ; -> buffer | ||||||||||||
| B3A3 | TYA ; count | ||||||||||||
| B3A4 | BNE lsv_copy_loop ; loop | ||||||||||||
| B3A6 | .return_32←1← B38E BEQ | ||||||||||||
| RTS ; Return the string | |||||||||||||
| B3A7 | .lsv_dollar←1← B386 BEQ | ||||||||||||
| LDA zp_iwa_1 ; $-string: copy until CR | |||||||||||||
| B3A9 | BEQ chrs_code ; null pointer: empty | ||||||||||||
| B3AB | LDY #0 ; from the start | ||||||||||||
| B3AD | .lsv_dollar_loop←1← B3B7 BNE | ||||||||||||
| LDA (zp_iwa),y ; char... | |||||||||||||
| B3AF | STA string_work,y ; -> buffer | ||||||||||||
| B3B2 | EOR #&0d ; CR? | ||||||||||||
| B3B4 | BEQ lsv_set_length ; yes: end | ||||||||||||
| B3B6 | INY ; next | ||||||||||||
| B3B7 | BNE lsv_dollar_loop ; loop | ||||||||||||
| B3B9 | TYA ; ran 256 chars without CR: length 0 | ||||||||||||
| B3BA | .lsv_set_length←1← B3B4 BEQ | ||||||||||||
| STY zp_strbuf_len ; set the length | |||||||||||||
| B3BC | RTS ; Return | ||||||||||||
CHR$One-character string for an ASCII code. CHR$ numeric.
|
|||||||||||||||
| B3BD | .fn_chrs | ||||||||||||||
| JSR eval_factor_integer ; Evaluate the integer argument | |||||||||||||||
| B3C0 | .chrs_code←1← B3A9 BEQ | ||||||||||||||
| LDA zp_iwa ; A = the character code | |||||||||||||||
| B3C2 | JMP gets_char ; return a one-character string | ||||||||||||||
Find the line an error occurred inWalk the program from PAGE to locate the line whose text span contains the current program pointer and record its number in ERL (0 in immediate mode).
|
|||||||||
| B3C5 | .find_error_line←1← B402 JSR | ||||||||
| LDY #0 ; Clear ERL: | |||||||||
| B3C7 | STY zp_erl ; (low) | ||||||||
| B3C9 | STY zp_erl_1 ; (high) | ||||||||
| B3CB | LDX zp_page ; Scan the program from PAGE: high | ||||||||
| B3CD | STX zp_general_1 ; (store) | ||||||||
| B3CF | STY zp_general ; low 0 | ||||||||
| B3D1 | LDX zp_text_ptr_1 ; past the error position? | ||||||||
| B3D3 | CPX #7 ; page 7 (the input line)? | ||||||||
| B3D5 | BEQ return_33 ; reached it: done | ||||||||
| B3D7 | LDX zp_text_ptr ; X = error position low | ||||||||
| B3D9 | .fel_scan_loop←1← B3FF BCS | ||||||||
| JSR read_via_ptr_general ; read a program byte | |||||||||
| B3DC | CMP #&0d ; a line end (CR)? | ||||||||
| B3DE | BNE fel_check ; no: keep scanning | ||||||||
| B3E0 | CPX zp_general ; is this line past the error? | ||||||||
| B3E2 | LDA zp_text_ptr_1 ; error high... | ||||||||
| B3E4 | SBC zp_general_1 ; minus the scan high | ||||||||
| B3E6 | BCC return_33 ; yes: keep the previous line | ||||||||
| B3E8 | JSR read_via_ptr_general ; read the line number high byte | ||||||||
| B3EB | ORA #0 ; end of program? | ||||||||
| B3ED | BMI return_33 ; yes: done | ||||||||
| B3EF | STA zp_erl_1 ; record ERL high | ||||||||
| B3F1 | JSR read_via_ptr_general ; line number low byte | ||||||||
| B3F4 | STA zp_erl ; record ERL low | ||||||||
| B3F6 | JSR read_via_ptr_general ; skip the line length byte | ||||||||
| B3F9 | .fel_check←1← B3DE BNE | ||||||||
| CPX zp_general ; still before the error? | |||||||||
| B3FB | LDA zp_text_ptr_1 ; error high... | ||||||||
| B3FD | SBC zp_general_1 ; minus the scan high | ||||||||
| B3FF | BCS fel_scan_loop ; yes: scan the next line | ||||||||
| B401 | .return_33←3← B3D5 BEQ← B3E6 BCC← B3ED BMI | ||||||||
| RTS ; Return | |||||||||
| B402 | .brk_handler | ||||||||
| JSR find_error_line ; Find the line number (set ERL) | |||||||||
| B405 | STY zp_trace_flag ; TRACE off | ||||||||
| B407 | LDA (zp_error_ptr),y ; error number | ||||||||
| B409 | BNE fel_set_handler ; non-zero: an ON ERROR handler is active | ||||||||
| B40B | LDA #&33 ; no handler: reset to the default (ON ERROR OFF) | ||||||||
| B40D | STA zp_error_vec ; default handler &B433: low, | ||||||||
| B40F | LDA #&b4 ; high... | ||||||||
| B411 | STA zp_error_vec_1 ; (store) | ||||||||
| B413 | .fel_set_handler←1← B409 BNE | ||||||||
| LDA zp_error_vec ; Point the program pointer at the handler code: low | |||||||||
| B415 | STA zp_text_ptr ; (low) | ||||||||
| B417 | LDA zp_error_vec_1 ; high | ||||||||
| B419 | STA zp_text_ptr_1 ; (store) | ||||||||
| B41B | JSR reset_data_and_stacks ; clear DATA and the stacks | ||||||||
| B41E | TAX ; offset 0 | ||||||||
| B41F | STX zp_text_ptr_off ; (store) | ||||||||
| B421 | LDA #osbyte_vdu_queue_size ; OSBYTE &DA: flush the VDU queue | ||||||||
| B423 | JSR osbyte ; osbyte: vdu queue size | ||||||||
| B426 | LDA #osbyte_acknowledge_escape ; OSBYTE &7E: acknowledge any Escape | ||||||||
| B428 | JSR osbyte ; Clear escape condition and perform escape effects | ||||||||
| B42B | LDX #&ff ; reset the 6502 stack... | ||||||||
| B42D | STX zp_opt_flag ; OPT = &FF | ||||||||
| B42F | TXS ; S = &FF (empty the stack) | ||||||||
| B430 | JMP next_statement ; enter the execution loop at the handler | ||||||||
| B433 | EQUB &F6, &3A, &E7, &9E, &F1 | ||||||||
| B438 | EQUS &22, " at line ", &22, ";" | ||||||||
| B444 | EQUB &9E, &3A, &E0, &8B, &F1, &3A, &E0, &0D | ||||||||
SOUNDMake a sound on a channel. SOUND channel, amplitude, pitch, duration.
|
|||||||||||
| B44C | .stmt_sound | ||||||||||
| JSR eval_expr_to_integer ; Evaluate the first parameter | |||||||||||
| B44F | LDX #3 ; three more | ||||||||||
| B451 | .sound_stack_loop←1← B45F BNE | ||||||||||
| LDA zp_iwa ; Stack the 16-bit value | |||||||||||
| B453 | PHA ; push low, | ||||||||||
| B454 | LDA zp_iwa_1 ; high, | ||||||||||
| B456 | PHA ; push high | ||||||||||
| B457 | TXA ; save the counter | ||||||||||
| B458 | PHA ; push it | ||||||||||
| B459 | JSR eval_comma_integer ; step past the comma, evaluate the next | ||||||||||
| B45C | PLA ; restore the counter | ||||||||||
| B45D | TAX ; into X, | ||||||||||
| B45E | DEX ; one fewer parameter | ||||||||||
| B45F | BNE sound_stack_loop ; loop | ||||||||||
| B461 | JSR sync_text_ptr ; Check the statement ends | ||||||||||
| B464 | LDA zp_iwa ; Last value to the block end | ||||||||||
| B466 | STA zp_fwb_exp ; low byte to &3D, | ||||||||||
| B468 | LDA zp_iwa_1 ; high, | ||||||||||
| B46A | STA zp_fwb_m1 ; high byte to &3E | ||||||||||
| B46C | LDY #7 ; OSWORD 7, 6 bytes | ||||||||||
| B46E | LDX #5 ; 6-byte block (X=5) | ||||||||||
| B470 | BNE env_pop_loop ; pop into the block and call | ||||||||||
| fall through ↓ | |||||||||||
ENVELOPEDefine a pitch/amplitude envelope for SOUND. ENVELOPE n,t,... (14 parameters).
|
|||||||||||
| B472 | .stmt_envelope | ||||||||||
| JSR eval_expr_to_integer ; Evaluate the first parameter | |||||||||||
| B475 | LDX #&0d ; 13 more | ||||||||||
| B477 | .env_stack_loop←1← B482 BNE | ||||||||||
| LDA zp_iwa ; Stack the 8-bit value | |||||||||||
| B479 | PHA ; push it | ||||||||||
| B47A | TXA ; save the counter | ||||||||||
| B47B | PHA ; push it | ||||||||||
| B47C | JSR eval_comma_integer ; step past the comma, evaluate the next | ||||||||||
| B47F | PLA ; restore the counter | ||||||||||
| B480 | TAX ; into X, | ||||||||||
| B481 | DEX ; one fewer parameter | ||||||||||
| B482 | BNE env_stack_loop ; loop | ||||||||||
| B484 | JSR sync_text_ptr ; Check the statement ends | ||||||||||
| B487 | LDA zp_iwa ; Last value to the block end | ||||||||||
| B489 | STA zp_fp_temp_1 ; into &44 (the block end) | ||||||||||
| B48B | LDX #&0c ; OSWORD 8, 12 bytes | ||||||||||
| B48D | LDY #osword_envelope ; OSWORD number 8 | ||||||||||
| B48F | .env_pop_loop←2← B470 BNE← B493 BPL | ||||||||||
| PLA ; Pop a byte into the control block | |||||||||||
| B490 | STA zp_general,x ; store at offset X, | ||||||||||
| B492 | DEX ; next lower offset | ||||||||||
| B493 | BPL env_pop_loop ; loop | ||||||||||
| B495 | TYA ; OSWORD number | ||||||||||
| B496 | LDX #<(zp_general) ; Point at the control block | ||||||||||
| B498 | LDY #>(zp_general) ; block address high | ||||||||||
| B49A | JSR osword ; ENVELOPE command | ||||||||||
| B49D | JMP statement_loop ; next statement | ||||||||||
WIDTHSet the output line width for PRINT. WIDTH n.
|
|||||||||||
| B4A0 | .stmt_width | ||||||||||
| JSR eval_expr_to_integer ; Evaluate the width | |||||||||||
| B4A3 | JSR sync_text_ptr ; check the statement ends | ||||||||||
| B4A6 | LDY zp_iwa ; Auto-newline column = width - 1 | ||||||||||
| B4A8 | DEY ; width - 1 | ||||||||||
| B4A9 | STY zp_width ; store it | ||||||||||
| B4AB | JMP statement_loop ; next statement | ||||||||||
| B4AE | .width_type_error←2← B4BF BEQ← B4E2 BEQ | ||||||||||
| JMP err_type_mismatch ; Type mismatch error | |||||||||||
Evaluate a numeric value and assign it to a variableEvaluate the numeric expression at PtrB via eval_or_eor, then fall straight into assign_number, which pops the variable's data address off the BASIC stack and stores the value there, coercing to the variable's own type.
|
||||||
| B4B1 | .width_eval_value←2← B7D1 JSR← BB2C JSR | |||||
| JSR eval_or_eor ; Evaluate the value | ||||||
| fall through ↓ | ||||||
Store a numeric value into a variableAssign the current numeric value (integer or real) to the
variable whose data address is on the stack, coercing to the variable's
own type (real variables get the value converted to FP). An integer
value is written raw and wraps — there is no range check — so
|
|||||||||||
| B4B4 | .assign_number←6← 85B4 JSR← 8C05 JSR← 911E JSR← 933E JSR← BA39 JSR← BAD6 JSR | ||||||||||
| JSR unstack_int_to_general ; Pop the variable data address from the stack | |||||||||||
| B4B7 | .assign_num_by_type←1← B2F3 JSR | ||||||||||
| LDA zp_fileblk ; Variable's size/type byte | |||||||||||
| B4B9 | CMP #5 ; size 5 = real variable? | ||||||||||
| B4BB | BEQ store_var_type ; yes: store as a real | ||||||||||
| B4BD | LDA zp_var_type ; Type of the value | ||||||||||
| B4BF | BEQ width_type_error ; string: Type mismatch | ||||||||||
| B4C1 | BPL iwa_store_var ; integer: store raw, 4-byte wrap (no range check) | ||||||||||
| B4C3 | JSR fwa_to_int ; real value, integer variable: convert | ||||||||||
| fall through ↓ | |||||||||||
Store the accumulator into an integer variableCopy IWA into the integer variable addressed by &37. The
width comes from &39, which is the lvalue type byte rather than a
separate size field: it rode in as byte 2 of the stacked destination
address (
|
|||||||||
| B4C6 | .iwa_store_var←1← B4C1 BPL | ||||||||
| LDY #0 ; Offset 0 | |||||||||
| B4C8 | LDA zp_iwa ; Store byte 1 | ||||||||
| B4CA | STA (zp_general),y ; write it | ||||||||
| B4CC | LDA zp_fileblk ; Size byte: 0 -> 1-byte (? indir), else 4 bytes | ||||||||
| B4CE | BEQ return_34 ; 1-byte value: done | ||||||||
| B4D0 | LDA zp_iwa_1 ; Store byte 2 | ||||||||
| B4D2 | INY ; next byte slot | ||||||||
| B4D3 | STA (zp_general),y ; write it | ||||||||
| B4D5 | LDA zp_iwa_2 ; Store byte 3 | ||||||||
| B4D7 | INY ; next byte slot | ||||||||
| B4D8 | STA (zp_general),y ; write it | ||||||||
| B4DA | LDA zp_iwa_3 ; Store byte 4 | ||||||||
| B4DC | INY ; next byte slot | ||||||||
| B4DD | STA (zp_general),y ; write it | ||||||||
| B4DF | .return_34←1← B4CE BEQ | ||||||||
| RTS ; Return | |||||||||
| B4E0 | .store_var_type←1← B4BB BEQ | ||||||||
| LDA zp_var_type ; Value type | |||||||||
| B4E2 | BEQ width_type_error ; string: Type mismatch | ||||||||
| B4E4 | BMI store_real ; real: store it | ||||||||
| B4E6 | JSR int_to_fwa ; integer: convert to real | ||||||||
| B4E9 | .store_real←2← B4E4 BMI← B77F JSR | ||||||||
| LDY #0 ; Store the 5-byte real: exponent | |||||||||
| B4EB | LDA zp_fwa_exp ; load the exponent | ||||||||
| B4ED | STA (zp_general),y ; to variable+0 | ||||||||
| B4EF | INY ; next byte slot | ||||||||
| B4F0 | LDA zp_fwa_sign ; Pack the sign into the mantissa | ||||||||
| B4F2 | AND #&80 ; keep only the sign bit | ||||||||
| B4F4 | STA zp_fwa_sign ; save it | ||||||||
| B4F6 | LDA zp_fwa_m1 ; mantissa top byte | ||||||||
| B4F8 | AND #&7f ; drop its implicit top bit | ||||||||
| B4FA | ORA zp_fwa_sign ; merge the sign bit in | ||||||||
| B4FC | STA (zp_general),y ; to variable+1 | ||||||||
| B4FE | INY ; mantissa 2 | ||||||||
| B4FF | LDA zp_fwa_m2 ; load it | ||||||||
| B501 | STA (zp_general),y ; to variable+2 | ||||||||
| B503 | INY ; mantissa 3 | ||||||||
| B504 | LDA zp_fwa_m3 ; load it | ||||||||
| B506 | STA (zp_general),y ; to variable+3 | ||||||||
| B508 | INY ; mantissa 4 | ||||||||
| B509 | LDA zp_fwa_m4 ; load it | ||||||||
| B50B | STA (zp_general),y ; to variable+4 | ||||||||
| B50D | RTS ; Return | ||||||||
De-tokenise and print a character or tokenPrint A directly if below &80, otherwise look the token up in the keyword table at &8071 and print its expanded keyword text.
|
|||||||||||
| B50E | .print_token←3← 8571 JSR← B688 JSR← BFF0 JSR | ||||||||||
| STA zp_general ; Save the character | |||||||||||
| B510 | CMP #&80 ; a token? | ||||||||||
| B512 | BCC print_char ; no: print it directly | ||||||||||
| B514 | LDA #&71 ; Point at the token table (&8071) | ||||||||||
| B516 | STA zp_general_1 ; pointer low = &71 | ||||||||||
| B518 | LDA #&80 ; pointer high = &80 | ||||||||||
| B51A | STA zp_fileblk ; set it | ||||||||||
| B51C | STY zp_fileblk_1 ; save Y | ||||||||||
| B51E | .ptok_entry_start←2← B530 BCC← B534 BCS | ||||||||||
| LDY #0 ; Start of an entry | |||||||||||
| B520 | .ptok_scan_loop←1← B523 BPL | ||||||||||
| INY ; Scan to the token byte | |||||||||||
| B521 | LDA (zp_general_1),y ; read it | ||||||||||
| B523 | BPL ptok_scan_loop ; ...(skip the keyword text) | ||||||||||
| B525 | CMP zp_general ; this token? | ||||||||||
| B527 | BEQ ptok_print ; yes: print its keyword | ||||||||||
| B529 | INY ; Advance to the next entry | ||||||||||
| B52A | TYA ; offset into A | ||||||||||
| B52B | SEC ; set carry: +1 past the flag byte | ||||||||||
| B52C | ADC zp_general_1 ; add to the pointer low, | ||||||||||
| B52E | STA zp_general_1 ; store it | ||||||||||
| B530 | BCC ptok_entry_start ; no carry: scan the next entry | ||||||||||
| B532 | INC zp_fileblk ; else carry into the high byte | ||||||||||
| B534 | BCS ptok_entry_start ; continue | ||||||||||
| B536 | .ptok_print←1← B527 BEQ | ||||||||||
| LDY #0 ; Print the keyword text: from the start | |||||||||||
| B538 | .ptok_print_loop←1← B540 BNE | ||||||||||
| LDA (zp_general_1),y ; Next character | |||||||||||
| B53A | BMI ptok_restore_y ; token byte: done | ||||||||||
| B53C | JSR print_char ; print it | ||||||||||
| B53F | INY ; next | ||||||||||
| B540 | BNE ptok_print_loop ; loop | ||||||||||
| B542 | .ptok_restore_y←1← B53A BMI | ||||||||||
| LDY zp_fileblk_1 ; Restore Y | |||||||||||
| B544 | RTS ; Return | ||||||||||
Print A as two hex digitsPrint the byte in A as two hex digits (high nibble then low) via print_hex_digit / print_char.
|
|||||||||||||
| B545 | .print_hex_byte←2← 8526 JSR← B562 JSR | ||||||||||||
| PHA ; Save the byte | |||||||||||||
| B546 | LSR ; High nibble | ||||||||||||
| B547 | LSR ; shift it down, | ||||||||||||
| B548 | LSR ; (continued) | ||||||||||||
| B549 | LSR ; (continued) | ||||||||||||
| B54A | JSR print_hex_digit ; print it | ||||||||||||
| B54D | PLA ; Low nibble | ||||||||||||
| B54E | AND #&0f ; keep the low nibble | ||||||||||||
| fall through ↓ | |||||||||||||
Print the low nibble of A as a hex digitConvert A (0-15) to the ASCII hex digit 0-9 / A-F and fall into print_char to emit it with column tracking.
|
|||||||||||||
| B550 | .print_hex_digit←1← B54A JSR | ||||||||||||
| CMP #&0a ; above 9? | |||||||||||||
| B552 | BCC phd_ascii ; no | ||||||||||||
| B554 | ADC #6 ; adjust for A-F | ||||||||||||
| B556 | .phd_ascii←1← B552 BCC | ||||||||||||
| ADC #'0' ; to ASCII, then fall into print_char | |||||||||||||
| fall through ↓ | |||||||||||||
Print a character with column trackingOutput A through the print formatter, handling CR specially and maintaining the print column COUNT. Auto-newlines when the column reaches WIDTH.
|
|||||||||||||||
| B558 | .print_char←13← 855C JSR← 855F JSR← 8E17 JSR← 8EA4 JSR← 9911 JSR← 9919 JSR← 9964 JSR← B512 BCC← B53C JSR← B583 JSR← B64B JSR← BA9F JSR← BC02 JSR | ||||||||||||||
| CMP #&0d ; carriage return? | |||||||||||||||
| B55A | BNE print_char_body ; no: format and print | ||||||||||||||
| B55C | JSR oswrch ; print the CR | ||||||||||||||
| B55F | JMP reset_print_column ; reset the column | ||||||||||||||
Print A as two hex digits then a spacePrint the byte in A as two hexadecimal digits (print_hex_byte), then fall through into print_space to emit a trailing space through the print formatter, which auto-newlines when the column reaches WIDTH.
|
|||||||||||||||||
| B562 | .print_hex_space←2← 852B JSR← 854E JSR | ||||||||||||||||
| JSR print_hex_byte ; Print A as hex then a space | |||||||||||||||||
| fall through ↓ | |||||||||||||||||
Print a space through the print formatterPrint a space via print_char, auto-newlining when the column reaches WIDTH.
|
|||||||||||||||
| B565 | .print_space←9← 8544 JSR← 8559 JSR← 8DB5 JSR← 8E08 JSR← 8E5F JSR← 991C JMP← 995A JSR← B57E BMI← B580 JSR | ||||||||||||||
| LDA #' ' ; Space | |||||||||||||||
| B567 | .print_char_body←1← B55A BNE | ||||||||||||||
| PHA ; Save the character | |||||||||||||||
| B568 | LDA zp_width ; WIDTH limit | ||||||||||||||
| B56A | CMP zp_count ; vs the current column | ||||||||||||||
| B56C | BCS print_char_emit ; within the width | ||||||||||||||
| B56E | JSR emit_newline ; else auto-newline | ||||||||||||||
| B571 | .print_char_emit←1← B56C BCS | ||||||||||||||
| PLA ; Recover the character | |||||||||||||||
| B572 | INC zp_count ; Advance the column | ||||||||||||||
| B574 | JMP (wrchv) ; Print it via WRCHV | ||||||||||||||
Print LISTO indentationIf the LISTO flag bit in A is set against zp_listo, print 2*X spaces of indentation for a LIST line.
|
|||||||||||
| B577 | .print_listo_indent←3← B626 JSR← B62D JSR← B634 JSR | ||||||||||
| AND zp_listo ; LISTO bit set? | |||||||||||
| B579 | BEQ return_35 ; no: no indent | ||||||||||
| B57B | TXA ; Indent count | ||||||||||
| B57C | BEQ return_35 ; zero: none | ||||||||||
| B57E | BMI print_space ; single space | ||||||||||
| B580 | .listo_space_loop←1← B587 BNE | ||||||||||
| JSR print_space ; Print a space... | |||||||||||
| B583 | JSR print_char ; ...and a space (two per level) | ||||||||||
| B586 | DEX ; next level | ||||||||||
| B587 | BNE listo_space_loop ; loop | ||||||||||
| B589 | .return_35←2← B579 BEQ← B57C BEQ | ||||||||||
| RTS ; Return | |||||||||||
LISTO - set the listing optionsEvaluate the option value and store it in the LISTO flag (&1F), which controls LIST indentation and spacing. LISTO n.
|
|||||||||||||
| B58A | .stmt_listo←1← B5A1 BEQ | ||||||||||||
| INC zp_text_ptr_off ; Step past LISTO | |||||||||||||
| B58C | JSR eval_expr ; Evaluate the option value | ||||||||||||
| B58F | JSR assign_check_end ; check the statement ends | ||||||||||||
| B592 | JSR coerce_var_to_integer ; coerce to a byte | ||||||||||||
| B595 | LDA zp_iwa ; Store the LISTO flag | ||||||||||||
| B597 | STA zp_listo ; into &1F | ||||||||||||
| B599 | JMP immediate_loop ; next statement | ||||||||||||
LISTList program lines, de-tokenising them. LIST [start[,end]].
|
|||||||||||
| B59C | .stmt_list | ||||||||||
| INY ; Peek at the next character | |||||||||||
| B59D | LDA (zp_text_ptr),y ; read it | ||||||||||
| B59F | CMP #'O' ; 'O' (LISTO)? | ||||||||||
| B5A1 | BEQ stmt_listo ; yes: set the option | ||||||||||
| B5A3 | LDA #0 ; Clear the indent levels | ||||||||||
| B5A5 | STA zp_fwb_sign ; FOR/REPEAT indent = 0, | ||||||||||
| B5A7 | STA zp_fwb_ovf ; second indent = 0 | ||||||||||
| B5A9 | JSR int_result_a ; Start line default 0 | ||||||||||
| B5AC | JSR check_line_number ; Embedded start line number? | ||||||||||
| B5AF | PHP ; remember whether one was given | ||||||||||
| B5B0 | JSR stack_integer ; Stack the start line | ||||||||||
| B5B3 | LDA #&ff ; End line default 32767 | ||||||||||
| B5B5 | STA zp_iwa ; low byte = &FF, | ||||||||||
| B5B7 | LDA #&7f ; high byte &7F, | ||||||||||
| B5B9 | STA zp_iwa_1 ; high byte (= 32767) | ||||||||||
| B5BB | PLP ; Was a start line given? | ||||||||||
| B5BC | BCC list_skip_spaces ; no: check for a range comma | ||||||||||
| B5BE | JSR skip_spaces ; Skip spaces | ||||||||||
| B5C1 | CMP #',' ; ',' range separator? | ||||||||||
| B5C3 | BEQ list_end_line ; yes: read the end line | ||||||||||
| B5C5 | JSR unstack_integer ; Single line: end = start | ||||||||||
| B5C8 | JSR stack_integer ; re-stack it | ||||||||||
| B5CB | DEC zp_text_ptr_off ; back up | ||||||||||
| B5CD | BPL list_save_end ; always taken | ||||||||||
| B5CF | .list_skip_spaces←1← B5BC BCC | ||||||||||
| JSR skip_spaces ; Skip spaces | |||||||||||
| B5D2 | CMP #',' ; ',' range separator? | ||||||||||
| B5D4 | BEQ list_end_line ; yes | ||||||||||
| B5D6 | DEC zp_text_ptr_off ; back up | ||||||||||
| B5D8 | .list_end_line←2← B5C3 BEQ← B5D4 BEQ | ||||||||||
| JSR check_line_number ; Read the end line number | |||||||||||
| B5DB | .list_save_end←1← B5CD BPL | ||||||||||
| LDA zp_iwa ; Save the end line | |||||||||||
| B5DD | STA zp_fwa_m1 ; low to &31, | ||||||||||
| B5DF | LDA zp_iwa_1 ; high byte, | ||||||||||
| B5E1 | STA zp_fwa_m2 ; high to &32 | ||||||||||
| B5E3 | JSR check_end_of_statement ; Check the statement ends | ||||||||||
| B5E6 | JSR check_program ; Check a program is present | ||||||||||
| B5E9 | JSR unstack_integer ; Recover the start line | ||||||||||
| B5EC | JSR find_program_line ; Find the first line | ||||||||||
| B5EF | LDA zp_fwb_exp ; Point at it | ||||||||||
| B5F1 | STA zp_text_ptr ; pointer low, | ||||||||||
| B5F3 | LDA zp_fwb_m1 ; high byte, | ||||||||||
| B5F5 | STA zp_text_ptr_1 ; pointer high | ||||||||||
| B5F7 | BCC list_past_end ; exact line: start here | ||||||||||
| B5F9 | DEY ; back up the offset, | ||||||||||
| B5FA | BCS list_check_high ; inexact: start at the next line | ||||||||||
| B5FC | .list_line_loop←1← B63D BEQ | ||||||||||
| JSR emit_newline ; Newline after the previous line | |||||||||||
| B5FF | JSR skip_to_statement_end ; check Escape | ||||||||||
| B602 | .list_check_high←1← B5FA BCS | ||||||||||
| LDA (zp_text_ptr),y ; This line's number: high byte | |||||||||||
| B604 | STA zp_iwa_1 ; store high, | ||||||||||
| B606 | INY ; next byte | ||||||||||
| B607 | LDA (zp_text_ptr),y ; ...low byte | ||||||||||
| B609 | STA zp_iwa ; store low | ||||||||||
| B60B | INY ; skip the length byte | ||||||||||
| B60C | INY ; (continued) | ||||||||||
| B60D | STY zp_text_ptr_off ; save the body offset | ||||||||||
| B60F | .list_past_end←1← B5F7 BCC | ||||||||||
| LDA zp_iwa ; Past the end line? | |||||||||||
| B611 | CLC ; clear carry, | ||||||||||
| B612 | SBC zp_fwa_m1 ; line - end low, | ||||||||||
| B614 | LDA zp_iwa_1 ; high byte, | ||||||||||
| B616 | SBC zp_fwa_m2 ; line - end high | ||||||||||
| B618 | BCC list_print_num ; no: list this line | ||||||||||
| B61A | JMP immediate_loop ; yes: done | ||||||||||
| B61D | .list_print_num←1← B618 BCC | ||||||||||
| JSR trace_print_number ; Print the line number | |||||||||||
| B620 | LDX #&ff ; Reset the quote flag | ||||||||||
| B622 | STX zp_coeff_ptr ; store it (&4D) | ||||||||||
| B624 | LDA #1 ; Print the LISTO leading space | ||||||||||
| B626 | JSR print_listo_indent ; do it | ||||||||||
| B629 | LDX zp_fwb_sign ; FOR/REPEAT indent | ||||||||||
| B62B | LDA #2 ; LISTO bit 1 indent | ||||||||||
| B62D | JSR print_listo_indent ; do it | ||||||||||
| B630 | LDX zp_fwb_ovf ; second indent level | ||||||||||
| B632 | LDA #4 ; LISTO bit 2 indent | ||||||||||
| B634 | JSR print_listo_indent ; do it | ||||||||||
| B637 | .list_line_offset←1← B665 JMP | ||||||||||
| LDY zp_text_ptr_off ; Line offset | |||||||||||
| B639 | .list_char_loop←2← B64F BNE← B68C BNE | ||||||||||
| LDA (zp_text_ptr),y ; Next character | |||||||||||
| B63B | CMP #&0d ; end of line? | ||||||||||
| B63D | BEQ list_line_loop ; yes: next line | ||||||||||
| B63F | CMP #'"' ; quote? | ||||||||||
| B641 | BNE list_in_quote ; no: a token or literal | ||||||||||
| B643 | LDA #&ff ; toggle the quote flag | ||||||||||
| B645 | EOR zp_coeff_ptr ; flip the flag, | ||||||||||
| B647 | STA zp_coeff_ptr ; store it | ||||||||||
| B649 | LDA #'"' ; print the quote | ||||||||||
| B64B | .list_emit←1← B653 BPL | ||||||||||
| JSR print_char ; do it | |||||||||||
| B64E | INY ; next character | ||||||||||
| B64F | BNE list_char_loop ; continue the line | ||||||||||
| B651 | .list_in_quote←1← B641 BNE | ||||||||||
| BIT zp_coeff_ptr ; Inside a quoted string? | |||||||||||
| B653 | BPL list_emit ; yes: print literally | ||||||||||
| B655 | CMP #&8d ; line-number token? | ||||||||||
| B657 | BNE list_for_token ; no | ||||||||||
| B659 | JSR decode_line_number ; decode the embedded line number | ||||||||||
| B65C | STY zp_text_ptr_off ; save the advanced offset | ||||||||||
| B65E | LDA #0 ; no field padding | ||||||||||
| B660 | STA zp_print_bytes ; clear the field width | ||||||||||
| B662 | JSR print_line_number ; print it | ||||||||||
| B665 | JMP list_line_offset ; continue | ||||||||||
| B668 | .list_for_token←1← B657 BNE | ||||||||||
| CMP #&e3 ; FOR token? | |||||||||||
| B66A | BNE list_next_token ; no | ||||||||||
| B66C | INC zp_fwb_sign ; increase the indent | ||||||||||
| B66E | .list_next_token←1← B66A BNE | ||||||||||
| CMP #&ed ; NEXT token? | |||||||||||
| B670 | BNE list_repeat_token ; no | ||||||||||
| B672 | LDX zp_fwb_sign ; indent active? | ||||||||||
| B674 | BEQ list_repeat_token ; no | ||||||||||
| B676 | DEC zp_fwb_sign ; decrease the indent | ||||||||||
| B678 | .list_repeat_token←2← B670 BNE← B674 BEQ | ||||||||||
| CMP #&f5 ; REPEAT token? | |||||||||||
| B67A | BNE list_until_token ; no | ||||||||||
| B67C | INC zp_fwb_ovf ; increase the indent | ||||||||||
| B67E | .list_until_token←1← B67A BNE | ||||||||||
| CMP #&fd ; UNTIL token? | |||||||||||
| B680 | BNE list_print_char ; no | ||||||||||
| B682 | LDX zp_fwb_ovf ; indent active? | ||||||||||
| B684 | BEQ list_print_char ; no | ||||||||||
| B686 | DEC zp_fwb_ovf ; decrease the indent | ||||||||||
| B688 | .list_print_char←2← B680 BNE← B684 BEQ | ||||||||||
| JSR print_token ; De-tokenise and print the character | |||||||||||
| B68B | INY ; next | ||||||||||
| B68C | BNE list_char_loop ; loop | ||||||||||
| B68E | .list_error←2← B69C BEQ← B6A7 BEQ | ||||||||||
| BRK ; No FN error | |||||||||||
| B68F | EQUS " No " | ||||||||||
| B693 | EQUB &E3, &00 | ||||||||||
NEXTEnd a FOR loop: update the counter and loop back unless the limit is passed. NEXT [var,...].
|
|||||||||||
| B695 | .stmt_next←1← B763 JMP | ||||||||||
| JSR parse_var_ref ; Parse the optional control variable | |||||||||||
| B698 | BNE next_bad_var ; a variable named after NEXT? | ||||||||||
| B69A | LDX zp_for_level ; innermost FOR frame | ||||||||||
| B69C | BEQ list_error ; no FOR active: error | ||||||||||
| B69E | BCS next_found ; no variable: use the innermost loop | ||||||||||
| B6A0 | .next_not_var←1← B6A3 BCS | ||||||||||
| JMP syntax_error ; not a variable: error | |||||||||||
| B6A3 | .next_bad_var←1← B698 BNE | ||||||||||
| BCS next_not_var ; string/array: not a loop variable | |||||||||||
| B6A5 | LDX zp_for_level ; Search the FOR stack for the named variable: | ||||||||||
| B6A7 | BEQ list_error ; not found: error | ||||||||||
| B6A9 | .next_find_frame←1← B6C5 BNE | ||||||||||
| LDA zp_iwa ; Find the matching FOR frame on the stack | |||||||||||
| B6AB | CMP for_var_lo,x ; match the variable address low? | ||||||||||
| B6AE | BNE next_discard_frame ; no: next frame | ||||||||||
| B6B0 | LDA zp_iwa_1 ; address high | ||||||||||
| B6B2 | CMP for_var_hi,x ; match the frame address high? | ||||||||||
| B6B5 | BNE next_discard_frame ; no: next frame | ||||||||||
| B6B7 | LDA zp_iwa_2 ; type | ||||||||||
| B6B9 | CMP for_type,x ; match the frame type? | ||||||||||
| B6BC | BEQ next_found ; match: this loop | ||||||||||
| B6BE | .next_discard_frame←2← B6AE BNE← B6B5 BNE | ||||||||||
| TXA ; Not this loop: discard the frame and look outward | |||||||||||
| B6BF | SEC ; step out one frame (15 bytes) | ||||||||||
| B6C0 | SBC #&0f ; minus 15 bytes, | ||||||||||
| B6C2 | TAX ; new frame index, | ||||||||||
| B6C3 | STX zp_for_level ; update the FOR level | ||||||||||
| B6C5 | BNE next_find_frame ; keep searching | ||||||||||
| B6C7 | BRK ; No FOR error block | ||||||||||
| B6C8 | EQUS "!Can't Match " | ||||||||||
| B6D5 | EQUB &E3, &00 | ||||||||||
| B6D7 | .next_found←2← B69E BCS← B6BC BEQ | ||||||||||
| LDA for_var_lo,x ; Found: reload the control variable to update it | |||||||||||
| B6DA | STA zp_iwa ; control variable address: low | ||||||||||
| B6DC | LDA for_var_hi,x ; high | ||||||||||
| B6DF | STA zp_iwa_1 ; address high | ||||||||||
| B6E1 | LDY for_type,x ; type | ||||||||||
| B6E4 | CPY #5 ; a real (float) loop? | ||||||||||
| B6E6 | BEQ next_float ; yes: float NEXT | ||||||||||
| B6E8 | LDY #0 ; Integer: add STEP to the variable: | ||||||||||
| B6EA | LDA (zp_iwa),y ; byte 0 | ||||||||||
| B6EC | ADC for_step0,x ; + step byte 0 | ||||||||||
| B6EF | STA (zp_iwa),y ; (store) | ||||||||||
| B6F1 | STA zp_general ; (keep) | ||||||||||
| B6F3 | INY ; byte 1 | ||||||||||
| B6F4 | LDA (zp_iwa),y ; variable byte 1 | ||||||||||
| B6F6 | ADC for_step1,x ; + step byte 1 | ||||||||||
| B6F9 | STA (zp_iwa),y ; (store) | ||||||||||
| B6FB | STA zp_general_1 ; (keep) | ||||||||||
| B6FD | INY ; byte 2 | ||||||||||
| B6FE | LDA (zp_iwa),y ; variable byte 2 | ||||||||||
| B700 | ADC for_step2,x ; + step byte 2 | ||||||||||
| B703 | STA (zp_iwa),y ; (store) | ||||||||||
| B705 | STA zp_fileblk ; (keep) | ||||||||||
| B707 | INY ; byte 3 | ||||||||||
| B708 | LDA (zp_iwa),y ; variable byte 3 | ||||||||||
| B70A | ADC for_step3,x ; + step byte 3 | ||||||||||
| B70D | STA (zp_iwa),y ; (store) | ||||||||||
| B70F | TAY ; (keep) | ||||||||||
| B710 | LDA zp_general ; Compare the new value with LIMIT: | ||||||||||
| B712 | SEC ; set carry for the subtract | ||||||||||
| B713 | SBC for_limit0,x ; value - limit: byte 0 | ||||||||||
| B716 | STA zp_general ; (keep) | ||||||||||
| B718 | LDA zp_general_1 ; byte 1 | ||||||||||
| B71A | SBC for_limit1,x ; minus limit byte 1 | ||||||||||
| B71D | STA zp_general_1 ; (keep) | ||||||||||
| B71F | LDA zp_fileblk ; byte 2 | ||||||||||
| B721 | SBC for_limit2,x ; minus limit byte 2 | ||||||||||
| B724 | STA zp_fileblk ; (keep) | ||||||||||
| B726 | TYA ; byte 3 | ||||||||||
| B727 | SBC for_limit3,x ; minus limit byte 3 | ||||||||||
| B72A | ORA zp_general ; exactly equal to the limit? | ||||||||||
| B72C | ORA zp_general_1 ; OR byte 1, | ||||||||||
| B72E | ORA zp_fileblk ; byte 2 (all zero => equal) | ||||||||||
| B730 | BEQ next_continue ; at the limit: last iteration, continue | ||||||||||
| B732 | TYA ; Past the limit? (sign of step vs difference) | ||||||||||
| B733 | EOR for_step3,x ; XOR the step sign, | ||||||||||
| B736 | EOR for_limit3,x ; XOR the limit sign, | ||||||||||
| B739 | BPL next_exit ; sign positive: use the carry test | ||||||||||
| B73B | BCS next_continue ; within range: continue | ||||||||||
| B73D | BCC next_pop_frame ; past: exit the loop | ||||||||||
| B73F | .next_exit←1← B739 BPL | ||||||||||
| BCS next_pop_frame ; past: exit the loop | |||||||||||
| B741 | .next_continue←5← B730 BEQ← B73B BCS← B792 BEQ← B799 BCS← B79D BCC | ||||||||||
| LDY for_loopback_lo,x ; Continue: reload the loop-back position: | |||||||||||
| B744 | LDA for_loopback_hi,x ; loop-back pointer high | ||||||||||
| B747 | STY zp_text_ptr ; (text pointer) | ||||||||||
| B749 | STA zp_text_ptr_1 ; text pointer high | ||||||||||
| B74B | JSR reset_offset_1 ; restore the offset | ||||||||||
| B74E | JMP next_statement ; jump back to the loop body | ||||||||||
| B751 | .next_pop_frame←4← B73D BCC← B73F BCS← B79B BCC← B79F BCS | ||||||||||
| LDA zp_for_level ; Exit: pop the FOR frame: | |||||||||||
| B753 | SEC ; set carry, | ||||||||||
| B754 | SBC #&0f ; minus 15 bytes, | ||||||||||
| B756 | STA zp_for_level ; pop the frame | ||||||||||
| B758 | LDY zp_text_ptr2_off ; continue after NEXT: | ||||||||||
| B75A | STY zp_text_ptr_off ; sync the program offset | ||||||||||
| B75C | JSR skip_spaces ; another NEXT variable (comma)? | ||||||||||
| B75F | CMP #',' ; ','? | ||||||||||
| B761 | BNE next_end ; no: end of statement | ||||||||||
| B763 | JMP stmt_next ; yes: handle the next variable | ||||||||||
| B766 | .next_float←1← B6E6 BEQ | ||||||||||
| JSR load_real_var ; Float loop: load the control variable | |||||||||||
| B769 | LDA zp_for_level ; point at the STEP in the frame: | ||||||||||
| B76B | CLC ; clear carry, | ||||||||||
| B76C | ADC #&f4 ; level + &F4, | ||||||||||
| B76E | STA zp_fp_ptr ; pointer low, | ||||||||||
| B770 | LDA #5 ; page &05, | ||||||||||
| B772 | STA zp_fp_ptr_1 ; pointer high (STEP address) | ||||||||||
| B774 | JSR fwa_add_var ; add STEP to the variable | ||||||||||
| B777 | LDA zp_iwa ; store it back: | ||||||||||
| B779 | STA zp_general ; var address low, | ||||||||||
| B77B | LDA zp_iwa_1 ; high byte, | ||||||||||
| B77D | STA zp_general_1 ; var address high | ||||||||||
| B77F | JSR store_real ; store the updated variable | ||||||||||
| B782 | LDA zp_for_level ; point at the LIMIT: | ||||||||||
| B784 | STA zp_var_type ; stash the level in &27, | ||||||||||
| B786 | CLC ; clear carry, | ||||||||||
| B787 | ADC #&f9 ; level + &F9, | ||||||||||
| B789 | STA zp_fp_ptr ; pointer low, | ||||||||||
| B78B | LDA #5 ; page &05, | ||||||||||
| B78D | STA zp_fp_ptr_1 ; pointer high (LIMIT address) | ||||||||||
| B78F | JSR fp_compare ; compare the variable with LIMIT | ||||||||||
| B792 | BEQ next_continue ; at the limit: continue | ||||||||||
| B794 | LDA for_step1,x ; sign of STEP... | ||||||||||
| B797 | BMI next_in_range ; negative step | ||||||||||
| B799 | BCS next_continue ; within range: continue | ||||||||||
| B79B | BCC next_pop_frame ; past: exit | ||||||||||
| B79D | .next_in_range←1← B797 BMI | ||||||||||
| BCC next_continue ; within range: continue | |||||||||||
| B79F | BCS next_pop_frame ; past: exit | ||||||||||
| B7A1 | .next_end←1← B761 BNE | ||||||||||
| JMP stmt_backup_end ; End of statement | |||||||||||
| B7A4 | .no_for_error←2← B7C7 BEQ← B7C9 BCS | ||||||||||
| BRK ; No FOR error block | |||||||||||
| B7A5 | EQUB &22, &E3 | ||||||||||
| B7A7 | EQUS " variable" | ||||||||||
| B7B0 | .too_many_fors←1← B7D8 BCS | ||||||||||
| BRK ; error block | |||||||||||
| B7B1 | EQUS "#Too many " | ||||||||||
| B7BB | EQUB &E3, &73 | ||||||||||
| B7BD | .cant_match_for←1← B7EF BNE | ||||||||||
| BRK ; error block | |||||||||||
| B7BE | EQUS "$No " | ||||||||||
| B7C2 | EQUB &B8, &00 | ||||||||||
FORBegin a counted loop, stacking the control variable, limit and step. FOR var = start TO limit [STEP step].
|
|||||||||||
| B7C4 | .stmt_for | ||||||||||
| JSR parse_lvalue ; Parse the control variable (numvar =) | |||||||||||
| B7C7 | BEQ no_for_error ; not a variable: error | ||||||||||
| B7C9 | BCS no_for_error ; indirection: error | ||||||||||
| B7CB | JSR stack_integer ; Stack the variable pointer | ||||||||||
| B7CE | JSR expect_eq ; Expect "=" | ||||||||||
| B7D1 | JSR width_eval_value ; Assign the initial value | ||||||||||
| B7D4 | LDY zp_for_level ; Index the FOR stack by nesting level | ||||||||||
| B7D6 | CPY #&96 ; At most 10 nested FOR loops (10 * 15) | ||||||||||
| B7D8 | BCS too_many_fors ; yes: error | ||||||||||
| B7DA | LDA zp_general ; Store the variable pointer in the frame (+0) | ||||||||||
| B7DC | STA for_stack,y ; pointer low (+0), | ||||||||||
| B7DF | LDA zp_general_1 ; high byte, | ||||||||||
| B7E1 | STA for_set_ptr_hi,y ; pointer high (+1) | ||||||||||
| B7E4 | LDA zp_fileblk ; ...and its type (+2) | ||||||||||
| B7E6 | STA for_set_type,y ; type (+2) | ||||||||||
| B7E9 | TAX ; keep the type | ||||||||||
| B7EA | JSR skip_spaces_ptr2 ; Next character | ||||||||||
| B7ED | CMP #&b8 ; Require the TO keyword | ||||||||||
| B7EF | BNE cant_match_for ; no: No TO error | ||||||||||
| B7F1 | CPX #5 ; real loop variable? | ||||||||||
| B7F3 | BEQ for_eval_limit ; yes: real FOR loop | ||||||||||
| B7F5 | JSR eval_expr_integer ; Integer: evaluate the limit | ||||||||||
| B7F8 | LDY zp_for_level ; FOR level | ||||||||||
| B7FA | LDA zp_iwa ; Store the limit in the frame (+8) | ||||||||||
| B7FC | STA for_set_limit0,y ; limit byte 0 (+8), | ||||||||||
| B7FF | LDA zp_iwa_1 ; byte 1, | ||||||||||
| B801 | STA for_set_limit1,y ; (+9), | ||||||||||
| B804 | LDA zp_iwa_2 ; byte 2, | ||||||||||
| B806 | STA for_set_limit2,y ; (+A), | ||||||||||
| B809 | LDA zp_iwa_3 ; byte 3, | ||||||||||
| B80B | STA for_set_limit3,y ; (+B) | ||||||||||
| B80E | LDA #1 ; Default STEP = 1 | ||||||||||
| B810 | JSR int_result_a ; IWA = 1 | ||||||||||
| B813 | JSR skip_spaces_ptr2 ; Next character | ||||||||||
| B816 | CMP #&88 ; Optional STEP (otherwise step defaults to 1) | ||||||||||
| B818 | BNE for_sync ; no: use the default | ||||||||||
| B81A | JSR eval_expr_integer ; Evaluate the step | ||||||||||
| B81D | LDY zp_text_ptr2_off ; update the offset | ||||||||||
| B81F | .for_sync←1← B818 BNE | ||||||||||
| STY zp_text_ptr_off ; Sync the program pointer | |||||||||||
| B821 | LDY zp_for_level ; FOR level | ||||||||||
| B823 | LDA zp_iwa ; Store the step in the frame (+3) | ||||||||||
| B825 | STA for_set_step0,y ; step byte 0 (+3), | ||||||||||
| B828 | LDA zp_iwa_1 ; byte 1, | ||||||||||
| B82A | STA for_set_step1,y ; (+4), | ||||||||||
| B82D | LDA zp_iwa_2 ; byte 2, | ||||||||||
| B82F | STA for_set_step2,y ; (+5), | ||||||||||
| B832 | LDA zp_iwa_3 ; byte 3, | ||||||||||
| B834 | STA for_set_step3,y ; (+6) | ||||||||||
| B837 | .for_skip_body←1← B885 JMP | ||||||||||
| JSR check_statement_terminated ; Step over the loop body to find its start | |||||||||||
| B83A | LDY zp_for_level ; FOR level | ||||||||||
| B83C | LDA zp_text_ptr ; Store the loop-body pointer (+D) | ||||||||||
| B83E | STA for_set_loop_lo,y ; low (+D), | ||||||||||
| B841 | LDA zp_text_ptr_1 ; high byte, | ||||||||||
| B843 | STA for_set_loop_hi,y ; (+E) | ||||||||||
| B846 | CLC ; Advance the FOR level by 15 | ||||||||||
| B847 | TYA ; level to A, | ||||||||||
| B848 | ADC #&0f ; + 15, | ||||||||||
| B84A | STA zp_for_level ; store it | ||||||||||
| B84C | JMP next_statement ; Continue execution | ||||||||||
| B84F | .for_eval_limit←1← B7F3 BEQ | ||||||||||
| JSR eval_or_eor ; Evaluate the limit | |||||||||||
| B852 | JSR ensure_real ; ensure it is real | ||||||||||
| B855 | LDA zp_for_level ; Point at frame +8 (limit slot) | ||||||||||
| B857 | CLC ; level + 8: | ||||||||||
| B858 | ADC #8 ; offset, | ||||||||||
| B85A | STA zp_fp_ptr ; pointer low, | ||||||||||
| B85C | LDA #5 ; page &05, | ||||||||||
| B85E | STA zp_fp_ptr_1 ; pointer high | ||||||||||
| B860 | JSR fwa_pack_var ; Pack the limit there | ||||||||||
| B863 | JSR fwa_set_one ; Default STEP = 1.0 | ||||||||||
| B866 | JSR skip_spaces_ptr2 ; Next character | ||||||||||
| B869 | CMP #&88 ; STEP token? | ||||||||||
| B86B | BNE for_sync2 ; no: use the default | ||||||||||
| B86D | JSR eval_or_eor ; Evaluate the step | ||||||||||
| B870 | JSR ensure_real ; ensure it is real | ||||||||||
| B873 | LDY zp_text_ptr2_off ; update the offset | ||||||||||
| B875 | .for_sync2←1← B86B BNE | ||||||||||
| STY zp_text_ptr_off ; Sync the program pointer | |||||||||||
| B877 | LDA zp_for_level ; Point at frame +3 (step slot) | ||||||||||
| B879 | CLC ; level + 3: | ||||||||||
| B87A | ADC #3 ; offset, | ||||||||||
| B87C | STA zp_fp_ptr ; pointer low, | ||||||||||
| B87E | LDA #5 ; page &05, | ||||||||||
| B880 | STA zp_fp_ptr_1 ; pointer high | ||||||||||
| B882 | JSR fwa_pack_var ; Pack the step there | ||||||||||
| B885 | JMP for_skip_body ; Join the common tail | ||||||||||
GOSUBCall a subroutine at a line number, stacking the return position. GOSUB line.
|
|||||||||||
| B888 | .stmt_gosub | ||||||||||
| JSR find_line_target ; Resolve the destination line | |||||||||||
| B88B | .gosub_check_end←1← B97A JMP | ||||||||||
| JSR check_end_of_statement ; Check the statement ends | |||||||||||
| B88E | LDY zp_gosub_level ; Index the GOSUB return stack | ||||||||||
| B890 | CPY #&1a ; At most 26 nested GOSUBs | ||||||||||
| B892 | BCS err_too_many_gosubs ; too many: error | ||||||||||
| B894 | LDA zp_text_ptr ; Push the return position (text pointer) | ||||||||||
| B896 | STA gosub_stack,y ; low byte | ||||||||||
| B899 | LDA zp_text_ptr_1 ; return position high byte | ||||||||||
| B89B | STA gosub_stack_hi,y ; store it | ||||||||||
| B89E | INC zp_gosub_level ; one more nesting level | ||||||||||
| B8A0 | BCC goto_trace ; jump to the line | ||||||||||
| B8A2 | .err_too_many_gosubs←1← B892 BCS | ||||||||||
| BRK ; Too many GOSUBs error | |||||||||||
| B8A3 | EQUS "%Too many " | ||||||||||
| B8AD | EQUB &E4, &73 | ||||||||||
| B8AF | .err_no_gosub←1← B8BB BEQ | ||||||||||
| BRK ; No GOSUB error | |||||||||||
| B8B0 | EQUS "&No " | ||||||||||
| B8B4 | EQUB &E4, &00 | ||||||||||
RETURNReturn from a GOSUB to the stacked return position. RETURN.
|
|||||||||||
| B8B6 | .stmt_return | ||||||||||
| JSR check_end_of_statement ; Check the statement ends | |||||||||||
| B8B9 | LDX zp_gosub_level ; RETURN with nothing on the GOSUB stack: error | ||||||||||
| B8BB | BEQ err_no_gosub ; nothing stacked: error | ||||||||||
| B8BD | DEC zp_gosub_level ; Pop the return position | ||||||||||
| B8BF | LDY gosub_return_lo,x ; return position low byte | ||||||||||
| B8C2 | LDA gosub_return_hi,x ; ...high byte | ||||||||||
| B8C5 | STY zp_text_ptr ; restore the text pointer | ||||||||||
| B8C7 | STA zp_text_ptr_1 ; high byte | ||||||||||
| B8C9 | JMP statement_loop ; Resume execution after the GOSUB | ||||||||||
GOTOJump to a line number. GOTO line.
|
|||||||||||
| B8CC | .stmt_goto | ||||||||||
| JSR find_line_target ; Resolve the destination line | |||||||||||
| B8CF | JSR check_end_of_statement ; check the statement ends | ||||||||||
| B8D2 | .goto_trace←3← 98EE JMP← B8A0 BCC← B967 JMP | ||||||||||
| LDA zp_trace_flag ; TRACE: report the destination line number | |||||||||||
| B8D4 | BEQ goto_dest_ptr ; TRACE off? | ||||||||||
| B8D6 | JSR trace_line ; trace the line | ||||||||||
| B8D9 | .goto_dest_ptr←1← B8D4 BEQ | ||||||||||
| LDY zp_fwb_exp ; Destination line pointer | |||||||||||
| B8DB | LDA zp_fwb_m1 ; high byte | ||||||||||
| B8DD | .goto_jump←1← BBD3 JMP | ||||||||||
| STY zp_text_ptr ; Point the interpreter at the destination line | |||||||||||
| B8DF | STA zp_text_ptr_1 ; PtrA high | ||||||||||
| B8E1 | JMP next_statement ; execute from there | ||||||||||
| B8E4 | .goto_check_end←1← B8F7 BEQ | ||||||||||
| JSR check_end_of_statement ; Check the statement ends | |||||||||||
| B8E7 | LDA #&33 ; Restore the default error handler | ||||||||||
| B8E9 | STA zp_error_vec ; low byte = &33, | ||||||||||
| B8EB | LDA #&b4 ; high byte = &B4, | ||||||||||
| B8ED | STA zp_error_vec_1 ; handler at &B433 | ||||||||||
| B8EF | JMP statement_loop ; next statement | ||||||||||
| B8F2 | .goto_char_loop←1← B91A BEQ | ||||||||||
| JSR skip_spaces ; Next character | |||||||||||
| B8F5 | CMP #&87 ; OFF token? | ||||||||||
| B8F7 | BEQ goto_check_end ; yes: ON ERROR OFF | ||||||||||
| B8F9 | LDY zp_text_ptr_off ; Point at the handler statement | ||||||||||
| B8FB | DEY ; back up, | ||||||||||
| B8FC | JSR skip_to_statement_end ; check Escape | ||||||||||
| B8FF | LDA zp_text_ptr ; Set the error handler to this line | ||||||||||
| B901 | STA zp_error_vec ; low byte, | ||||||||||
| B903 | LDA zp_text_ptr_1 ; high byte, | ||||||||||
| B905 | STA zp_error_vec_1 ; store it | ||||||||||
| B907 | JMP stmt_data ; skip the rest of the line | ||||||||||
| B90A | .on_syntax_error←1← B92F BNE | ||||||||||
| BRK ; ON syntax error | |||||||||||
| B90B | EQUB &27, &EE | ||||||||||
| B90D | EQUS " syntax" | ||||||||||
| B914 | EQUB &00 | ||||||||||
ONON expr GOTO/GOSUB computed jump, or ON ERROR error trapping. ON expr GOTO/GOSUB list | ON ERROR stmts.
|
|||||||||||
| B915 | .stmt_on | ||||||||||
| JSR skip_spaces ; Next character | |||||||||||
| B918 | CMP #&85 ; ERROR token? | ||||||||||
| B91A | BEQ goto_char_loop ; yes: ON ERROR | ||||||||||
| B91C | DEC zp_text_ptr_off ; Back up over the character | ||||||||||
| B91E | JSR eval_expr ; Evaluate the selector | ||||||||||
| B921 | JSR coerce_to_integer ; coerce to integer | ||||||||||
| B924 | LDY zp_text_ptr2_off ; Advance past it | ||||||||||
| B926 | INY ; past the token, | ||||||||||
| B927 | STY zp_text_ptr_off ; sync the offset | ||||||||||
| B929 | CPX #&e5 ; GOTO token? | ||||||||||
| B92B | BEQ on_save_token ; yes | ||||||||||
| B92D | CPX #&e4 ; GOSUB token? | ||||||||||
| B92F | BNE on_syntax_error ; no: syntax error | ||||||||||
| B931 | .on_save_token←1← B92B BEQ | ||||||||||
| TXA ; Save the GOTO/GOSUB token | |||||||||||
| B932 | PHA ; push it | ||||||||||
| B933 | LDA zp_iwa_1 ; Selector > 255? | ||||||||||
| B935 | ORA zp_iwa_2 ; OR byte 2, | ||||||||||
| B937 | ORA zp_iwa_3 ; byte 3 (any => > 255) | ||||||||||
| B939 | BNE on_out_of_range ; yes: out of range | ||||||||||
| B93B | LDX zp_iwa ; Selector zero? | ||||||||||
| B93D | BEQ on_out_of_range ; yes: out of range | ||||||||||
| B93F | DEX ; Count down to the n-th destination | ||||||||||
| B940 | BEQ on_read_dest ; reached it: use the first | ||||||||||
| B942 | LDY zp_text_ptr_off ; Line index | ||||||||||
| B944 | .on_char_loop←2← B955 BNE← B958 BNE | ||||||||||
| LDA (zp_text_ptr),y ; Next character | |||||||||||
| B946 | INY ; advance | ||||||||||
| B947 | CMP #&0d ; end of line? | ||||||||||
| B949 | BEQ on_out_of_range ; yes: out of range | ||||||||||
| B94B | CMP #':' ; ':' end of statement? | ||||||||||
| B94D | BEQ on_out_of_range ; yes: out of range | ||||||||||
| B94F | CMP #&8b ; ELSE? | ||||||||||
| B951 | BEQ on_out_of_range ; yes: out of range | ||||||||||
| B953 | CMP #',' ; ',' separator? | ||||||||||
| B955 | BNE on_char_loop ; no: keep scanning | ||||||||||
| B957 | DEX ; count this destination | ||||||||||
| B958 | BNE on_char_loop ; not yet reached: continue | ||||||||||
| B95A | STY zp_text_ptr_off ; Save the line index | ||||||||||
| B95C | .on_read_dest←1← B940 BEQ | ||||||||||
| JSR find_line_target ; Read the destination line number | |||||||||||
| B95F | PLA ; Recover the token | ||||||||||
| B960 | CMP #&e4 ; GOSUB? | ||||||||||
| B962 | BEQ on_gosub_ptr ; yes | ||||||||||
| B964 | JSR reset_offset_1 ; GOTO: update the index and check Escape | ||||||||||
| B967 | JMP goto_trace ; jump to the line | ||||||||||
| B96A | .on_gosub_ptr←1← B962 BEQ | ||||||||||
| LDY zp_text_ptr_off ; GOSUB: line pointer | |||||||||||
| B96C | .on_skip_loop←1← B975 BNE | ||||||||||
| LDA (zp_text_ptr),y ; Next character | |||||||||||
| B96E | INY ; advance | ||||||||||
| B96F | CMP #&0d ; end of line? | ||||||||||
| B971 | BEQ on_return_index ; yes: return point here | ||||||||||
| B973 | CMP #':' ; ':' separator? | ||||||||||
| B975 | BNE on_skip_loop ; no: keep scanning to the return point | ||||||||||
| B977 | .on_return_index←1← B971 BEQ | ||||||||||
| DEY ; Set the return index | |||||||||||
| B978 | STY zp_text_ptr_off ; save it | ||||||||||
| B97A | JMP gosub_check_end ; do the GOSUB | ||||||||||
| B97D | .on_out_of_range←5← B939 BNE← B93D BEQ← B949 BEQ← B94D BEQ← B951 BEQ | ||||||||||
| LDY zp_text_ptr_off ; Out of range: line index | |||||||||||
| B97F | PLA ; drop the token | ||||||||||
| B980 | .on_scan_loop←1← B989 BNE | ||||||||||
| LDA (zp_text_ptr),y ; Next character | |||||||||||
| B982 | INY ; advance | ||||||||||
| B983 | CMP #&8b ; ELSE? | ||||||||||
| B985 | BEQ on_else ; yes: use it | ||||||||||
| B987 | CMP #&0d ; end of line? | ||||||||||
| B989 | BNE on_scan_loop ; no: keep scanning | ||||||||||
| B98B | BRK ; ON range error | ||||||||||
| B98C | EQUB &28, &EE | ||||||||||
| B98E | EQUS " range" | ||||||||||
| B994 | EQUB &00 | ||||||||||
| B995 | .on_else←1← B985 BEQ | ||||||||||
| STY zp_text_ptr_off ; Step past ELSE | |||||||||||
| B997 | JMP if_then_line ; execute what follows | ||||||||||
Resolve a line-number operand to a program lineRead a line-number argument (an embedded tokenised line number or an evaluated integer expression) and locate that line in the program via find_program_line. Used by GOTO, GOSUB and RESTORE. Raises "No such line" if absent.
|
|||||||||||
| B99A | .find_line_target←4← B888 JSR← B8CC JSR← B95C JSR← BAFF JSR | ||||||||||
| JSR check_line_number ; Embedded line-number token? | |||||||||||
| B99D | BCS flt_find ; yes: use it | ||||||||||
| B99F | JSR eval_expr ; Evaluate the line-number expression | ||||||||||
| B9A2 | JSR coerce_to_integer ; ensure integer | ||||||||||
| B9A5 | LDA zp_text_ptr2_off ; Update the program pointer | ||||||||||
| B9A7 | STA zp_text_ptr_off ; from the PtrB offset | ||||||||||
| B9A9 | LDA zp_iwa_1 ; Mask the high byte to 7 bits | ||||||||||
| B9AB | AND #&7f ; (so GOTO &8000+n == GOTO n) | ||||||||||
| B9AD | STA zp_iwa_1 ; store the masked high byte | ||||||||||
| B9AF | .flt_find←2← 98E8 JSR← B99D BCS | ||||||||||
| JSR find_program_line ; Find the line | |||||||||||
| B9B2 | BCS err_no_such_line ; not found: No such line | ||||||||||
| B9B4 | RTS ; Return | ||||||||||
| B9B5 | .err_no_such_line←1← B9B2 BCS | ||||||||||
| BRK ; No such line error | |||||||||||
| B9B6 | EQUS ")No such line" | ||||||||||
| B9C3 | EQUB &00 | ||||||||||
| B9C4 | .flt_type_error←2← BA00 BNE← BA1B BEQ | ||||||||||
| JMP err_type_mismatch ; Type mismatch error | |||||||||||
| B9C7 | .flt_mistake←1← B9E7 BEQ | ||||||||||
| JMP syntax_error ; Mistake error | |||||||||||
| B9CA | .flt_sync←1← B9DF BNE | ||||||||||
| STY zp_text_ptr_off ; Sync the pointer | |||||||||||
| B9CC | JMP stmt_check_end ; check the statement ends | ||||||||||
| B9CF | .inputf_skip_hash←1← BA49 BEQ | ||||||||||
| DEC zp_text_ptr_off ; Back up over "#" | |||||||||||
| B9D1 | JSR sync_ptrb_from_ptra ; Get the file handle | ||||||||||
| B9D4 | LDA zp_text_ptr2_off ; Sync the program pointer | ||||||||||
| B9D6 | STA zp_text_ptr_off ; from the PtrB offset | ||||||||||
| B9D8 | STY zp_coeff_ptr ; save the handle | ||||||||||
| B9DA | .inputf_skip_spaces←2← BA16 JMP← BA3C JMP | ||||||||||
| JSR skip_spaces ; Skip spaces | |||||||||||
| B9DD | CMP #',' ; ',' another variable? | ||||||||||
| B9DF | BNE flt_sync ; no: done | ||||||||||
| B9E1 | LDA zp_coeff_ptr ; Save the handle | ||||||||||
| B9E3 | PHA ; push it | ||||||||||
| B9E4 | JSR parse_lvalue ; Parse the target variable | ||||||||||
| B9E7 | BEQ flt_mistake ; end: error | ||||||||||
| B9E9 | LDA zp_text_ptr2_off ; Sync the program pointer | ||||||||||
| B9EB | STA zp_text_ptr_off ; from the PtrB offset | ||||||||||
| B9ED | PLA ; Recover the handle | ||||||||||
| B9EE | STA zp_coeff_ptr ; store it (&4D), | ||||||||||
| B9F0 | PHP ; save the type flags | ||||||||||
| B9F1 | JSR stack_integer ; Stack the variable address | ||||||||||
| B9F4 | LDY zp_coeff_ptr ; Handle | ||||||||||
| B9F6 | JSR osbget ; Read the type byte | ||||||||||
| B9F9 | STA zp_var_type ; save it | ||||||||||
| B9FB | PLP ; restore the type flags | ||||||||||
| B9FC | BCC inputf_numeric ; string? | ||||||||||
| B9FE | LDA zp_var_type ; String type byte | ||||||||||
| BA00 | BNE flt_type_error ; mismatch: error | ||||||||||
| BA02 | JSR osbget ; Read the length | ||||||||||
| BA05 | STA zp_strbuf_len ; store the length, | ||||||||||
| BA07 | TAX ; into X as the count | ||||||||||
| BA08 | BEQ inputf_assign_str ; empty | ||||||||||
| BA0A | .inputf_read_loop←1← BA11 BNE | ||||||||||
| JSR osbget ; Read a character | |||||||||||
| BA0D | STA strbuf_base,x ; into the buffer (reversed), | ||||||||||
| BA10 | DEX ; next character | ||||||||||
| BA11 | BNE inputf_read_loop ; loop | ||||||||||
| BA13 | .inputf_assign_str←1← BA08 BEQ | ||||||||||
| JSR assign_string ; Assign the string | |||||||||||
| BA16 | JMP inputf_skip_spaces ; next variable | ||||||||||
| BA19 | .inputf_numeric←1← B9FC BCC | ||||||||||
| LDA zp_var_type ; Numeric type byte | |||||||||||
| BA1B | BEQ flt_type_error ; mismatch: error | ||||||||||
| BA1D | BMI inputf_real ; real? | ||||||||||
| BA1F | LDX #3 ; Integer: 4 bytes | ||||||||||
| BA21 | .inputf_int_loop←1← BA27 BPL | ||||||||||
| JSR osbget ; Read a byte | |||||||||||
| BA24 | STA zp_iwa,x ; into IWA (MSB first), | ||||||||||
| BA26 | DEX ; next byte | ||||||||||
| BA27 | BPL inputf_int_loop ; loop | ||||||||||
| BA29 | BMI inputf_assign_num ; assign | ||||||||||
| BA2B | .inputf_real←1← BA1D BMI | ||||||||||
| LDX #4 ; Real: 5 bytes | |||||||||||
| BA2D | .inputf_real_loop←1← BA34 BPL | ||||||||||
| JSR osbget ; Read a byte | |||||||||||
| BA30 | STA fp_temp1,x ; into TEMP1 (MSB first), | ||||||||||
| BA33 | DEX ; next byte | ||||||||||
| BA34 | BPL inputf_real_loop ; loop | ||||||||||
| BA36 | JSR fwa_unpack_temp1 ; unpack into FWA | ||||||||||
| BA39 | .inputf_assign_num←1← BA29 BMI | ||||||||||
| JSR assign_number ; Assign the number | |||||||||||
| BA3C | JMP inputf_skip_spaces ; next variable | ||||||||||
| BA3F | .inputf_drop_loop←1← BA82 BEQ | ||||||||||
| PLA ; Drop the stacked values | |||||||||||
| BA40 | PLA ; (continued) | ||||||||||
| BA41 | JMP stmt_check_end ; done | ||||||||||
INPUTRead values from the keyboard, or a file with #, into variables. INPUT [LINE] [prompt] var,...
|
|||||||||||
| BA44 | .stmt_input | ||||||||||
| JSR skip_spaces ; Next non-space character | |||||||||||
| BA47 | CMP #'#' ; '#': INPUT# from a file | ||||||||||
| BA49 | BEQ inputf_skip_hash ; go handle INPUT# | ||||||||||
| BA4B | CMP #&86 ; LINE token? | ||||||||||
| BA4D | BEQ input_line_flag ; yes: LINE mode (carry set) | ||||||||||
| BA4F | DEC zp_text_ptr_off ; no: step back, carry clear | ||||||||||
| BA51 | CLC ; carry clear (not LINE) | ||||||||||
| BA52 | .input_line_flag←1← BA4D BEQ | ||||||||||
| ROR zp_coeff_ptr ; Record the LINE flag in bit 6 | |||||||||||
| BA54 | LSR zp_coeff_ptr ; shift it into bit 6 | ||||||||||
| BA56 | LDA #&ff ; Prompt flag = -1 | ||||||||||
| BA58 | STA zp_coeff_ptr_1 ; store it (&4E) | ||||||||||
| BA5A | .input_prompt←4← BA71 BEQ← BA75 BEQ← BAD9 JMP← BAE3 JMP | ||||||||||
| JSR print_special_skip ; Process a prompt item | |||||||||||
| BA5D | BCS input_item_flag ; none found: parse a variable | ||||||||||
| BA5F | .input_prompt_loop←1← BA62 BCC | ||||||||||
| JSR print_special_skip ; Process further prompt items | |||||||||||
| BA62 | BCC input_prompt_loop ; more printed items: loop | ||||||||||
| BA64 | LDX #&ff ; A printed item suppresses the ? prompt | ||||||||||
| BA66 | STX zp_coeff_ptr_1 ; flag = -1 (printed), | ||||||||||
| BA68 | CLC ; carry clear | ||||||||||
| BA69 | .input_item_flag←1← BA5D BCS | ||||||||||
| PHP ; Preserve the item-seen flag | |||||||||||
| BA6A | ASL zp_coeff_ptr ; shift out the old bit, | ||||||||||
| BA6C | PLP ; recover the flag, | ||||||||||
| BA6D | ROR zp_coeff_ptr ; rotate it into bit 7 | ||||||||||
| BA6F | CMP #',' ; ',' next item? | ||||||||||
| BA71 | BEQ input_prompt ; yes | ||||||||||
| BA73 | CMP #';' ; ';' next item? | ||||||||||
| BA75 | BEQ input_prompt ; yes | ||||||||||
| BA77 | DEC zp_text_ptr_off ; Back up to the variable | ||||||||||
| BA79 | LDA zp_coeff_ptr ; Save the flags... | ||||||||||
| BA7B | PHA ; push &4D, | ||||||||||
| BA7C | LDA zp_coeff_ptr_1 ; &4E, | ||||||||||
| BA7E | PHA ; push it | ||||||||||
| BA7F | JSR parse_lvalue ; Parse the target variable | ||||||||||
| BA82 | BEQ inputf_drop_loop ; end of statement: done | ||||||||||
| BA84 | PLA ; Restore the flags | ||||||||||
| BA85 | STA zp_coeff_ptr_1 ; &4E, | ||||||||||
| BA87 | PLA ; pull &4D, | ||||||||||
| BA88 | STA zp_coeff_ptr ; store it | ||||||||||
| BA8A | LDA zp_text_ptr2_off ; Update the program pointer | ||||||||||
| BA8C | STA zp_text_ptr_off ; from the PtrB offset | ||||||||||
| BA8E | PHP ; Save the LINE flag | ||||||||||
| BA8F | BIT zp_coeff_ptr ; Still reading the current input line? | ||||||||||
| BA91 | BVS input_line_mode ; yes: no new prompt | ||||||||||
| BA93 | LDA zp_coeff_ptr_1 ; Prompt flag | ||||||||||
| BA95 | CMP #&ff ; item already printed? | ||||||||||
| BA97 | BNE input_set_offset ; yes: read without a ? prompt | ||||||||||
| BA99 | .input_line_mode←1← BA91 BVS | ||||||||||
| BIT zp_coeff_ptr ; LINE mode? | |||||||||||
| BA9B | BPL input_read_line ; yes: no ? prompt | ||||||||||
| BA9D | LDA #'?' ; Print '?' | ||||||||||
| BA9F | JSR print_char ; do it | ||||||||||
| BAA2 | .input_read_line←1← BA9B BPL | ||||||||||
| JSR point_string_buffer ; Read an input line | |||||||||||
| BAA5 | STY zp_strbuf_len ; Store its length | ||||||||||
| BAA7 | ASL zp_coeff_ptr ; Mark the input line as fresh | ||||||||||
| BAA9 | CLC ; clear carry, | ||||||||||
| BAAA | ROR zp_coeff_ptr ; rotate into bit 7 | ||||||||||
| BAAC | BIT zp_coeff_ptr ; LINE mode? | ||||||||||
| BAAE | BVS input_recover_flag ; yes: take the whole line | ||||||||||
| BAB0 | .input_set_offset←1← BA97 BNE | ||||||||||
| STA zp_text_ptr2_off ; Set the read offset | |||||||||||
| BAB2 | LDA #0 ; Point at the input buffer (&0600) | ||||||||||
| BAB4 | STA zp_text_ptr2 ; PtrB low = 0, | ||||||||||
| BAB6 | LDA #6 ; page &06, | ||||||||||
| BAB8 | STA zp_text_ptr2_1 ; PtrB high | ||||||||||
| BABA | JSR read_string_literal ; Read the field literal | ||||||||||
| BABD | .input_skip_spaces←1← BAC6 BNE | ||||||||||
| JSR skip_spaces_ptr2 ; Skip spaces | |||||||||||
| BAC0 | CMP #',' ; ',' field delimiter? | ||||||||||
| BAC2 | BEQ input_field_offset ; yes | ||||||||||
| BAC4 | CMP #&0d ; end of line? | ||||||||||
| BAC6 | BNE input_skip_spaces ; no: keep scanning | ||||||||||
| BAC8 | LDY #&fe ; mark end of input | ||||||||||
| BACA | .input_field_offset←1← BAC2 BEQ | ||||||||||
| INY ; Note the next field offset | |||||||||||
| BACB | STY zp_coeff_ptr_1 ; store it (&4E) | ||||||||||
| BACD | .input_recover_flag←1← BAAE BVS | ||||||||||
| PLP ; Recover the LINE flag | |||||||||||
| BACE | BCS input_line_string ; LINE mode: assign the whole line | ||||||||||
| BAD0 | JSR stack_integer ; Stack the variable address | ||||||||||
| BAD3 | JSR ascii_to_number ; Parse the field as a number | ||||||||||
| BAD6 | JSR assign_number ; assign it | ||||||||||
| BAD9 | JMP input_prompt ; next variable | ||||||||||
| BADC | .input_line_string←1← BACE BCS | ||||||||||
| LDA #0 ; LINE: string type | |||||||||||
| BADE | STA zp_var_type ; type 0 (string) | ||||||||||
| BAE0 | JSR assign_string_to ; assign the line as a string | ||||||||||
| BAE3 | JMP input_prompt ; next variable | ||||||||||
RESTOREReset the DATA pointer, optionally to a given line. RESTORE [line].
|
|||||||||||
| BAE6 | .stmt_restore | ||||||||||
| LDY #0 ; DATA pointer = PAGE | |||||||||||
| BAE8 | STY zp_fwb_exp ; low byte 0 (&3D), | ||||||||||
| BAEA | LDY zp_page ; PAGE, | ||||||||||
| BAEC | STY zp_fwb_m1 ; high byte (&3E) | ||||||||||
| BAEE | JSR skip_spaces ; Skip spaces | ||||||||||
| BAF1 | DEC zp_text_ptr_off ; back up | ||||||||||
| BAF3 | CMP #':' ; ':' end? | ||||||||||
| BAF5 | BEQ restore_check_end ; yes: restore to PAGE | ||||||||||
| BAF7 | CMP #&0d ; end of line? | ||||||||||
| BAF9 | BEQ restore_check_end ; yes | ||||||||||
| BAFB | CMP #&8b ; ELSE? | ||||||||||
| BAFD | BEQ restore_check_end ; yes | ||||||||||
| BAFF | JSR find_line_target ; Find the given line | ||||||||||
| BB02 | LDY #1 ; point at it | ||||||||||
| BB04 | JSR fwb_scale_clc ; set the pointer to the line | ||||||||||
| BB07 | .restore_check_end←3← BAF5 BEQ← BAF9 BEQ← BAFD BEQ | ||||||||||
| JSR check_end_of_statement ; Check the statement ends | |||||||||||
| BB0A | LDA zp_fwb_exp ; Set the DATA pointer | ||||||||||
| BB0C | STA zp_data_ptr ; low byte (&1C), | ||||||||||
| BB0E | LDA zp_fwb_m1 ; high byte, | ||||||||||
| BB10 | STA zp_data_ptr_1 ; high (&1D) | ||||||||||
| BB12 | JMP statement_loop ; next statement | ||||||||||
| BB15 | .restore_skip_spaces←2← BB22 BEQ← BB4D JMP | ||||||||||
| JSR skip_spaces ; Skip spaces | |||||||||||
| BB18 | CMP #',' ; ','? | ||||||||||
| BB1A | BEQ stmt_read ; yes: READ | ||||||||||
| BB1C | JMP stmt_backup_end ; next statement | ||||||||||
READRead values from DATA statements into variables. READ var,...
|
|||||||||||
| BB1F | .stmt_read←1← BB1A BEQ | ||||||||||
| JSR parse_lvalue ; Parse the target variable | |||||||||||
| BB22 | BEQ restore_skip_spaces ; end of statement: done | ||||||||||
| BB24 | BCS read_string ; string variable? | ||||||||||
| BB26 | JSR next_data_item ; Numeric: find the next DATA item | ||||||||||
| BB29 | JSR stack_integer ; Stack the variable address | ||||||||||
| BB2C | JSR width_eval_value ; read the value and assign it | ||||||||||
| BB2F | JMP read_advance ; update the DATA pointer | ||||||||||
| BB32 | .read_string←1← BB24 BCS | ||||||||||
| JSR next_data_item ; String: find the next DATA item | |||||||||||
| BB35 | JSR stack_integer ; Stack the variable address | ||||||||||
| BB38 | JSR read_string_literal ; read the DATA item as a string | ||||||||||
| BB3B | STA zp_var_type ; string type | ||||||||||
| BB3D | JSR assign_string ; assign it | ||||||||||
| BB40 | .read_advance←1← BB2F JMP | ||||||||||
| CLC ; Advance the DATA pointer past the item | |||||||||||
| BB41 | LDA zp_text_ptr2_off ; PtrB offset, | ||||||||||
| BB43 | ADC zp_text_ptr2 ; + PtrB low, | ||||||||||
| BB45 | STA zp_data_ptr ; DATA pointer low, | ||||||||||
| BB47 | LDA zp_text_ptr2_1 ; PtrB high, | ||||||||||
| BB49 | ADC #0 ; + carry, | ||||||||||
| BB4B | STA zp_data_ptr_1 ; DATA pointer high | ||||||||||
| BB4D | JMP restore_skip_spaces ; next variable | ||||||||||
Advance the DATA pointer to the next itemMove the DATA pointer past the current item to the next comma- or DATA-separated value, searching forward through the program for the next DATA statement at end of line; raises Out of DATA.
|
|||||||||||
| BB50 | .next_data_item←2← BB26 JSR← BB32 JSR | ||||||||||
| LDA zp_text_ptr2_off ; Save the program pointer | |||||||||||
| BB52 | STA zp_text_ptr_off ; (save) | ||||||||||
| BB54 | LDA zp_data_ptr ; Point at the DATA position | ||||||||||
| BB56 | STA zp_text_ptr2 ; (low) | ||||||||||
| BB58 | LDA zp_data_ptr_1 ; high... | ||||||||||
| BB5A | STA zp_text_ptr2_1 ; (high) | ||||||||||
| BB5C | LDY #0 ; From offset 0 | ||||||||||
| BB5E | STY zp_text_ptr2_off ; (offset 0) | ||||||||||
| BB60 | JSR skip_spaces_ptr2 ; Next character | ||||||||||
| BB63 | CMP #',' ; ',' item separator? | ||||||||||
| BB65 | BEQ return_36 ; yes: at the next item | ||||||||||
| BB67 | CMP #&dc ; DATA token? | ||||||||||
| BB69 | BEQ return_36 ; yes: at the first item | ||||||||||
| BB6B | CMP #&0d ; end of line? | ||||||||||
| BB6D | BEQ ndi_line_marker ; yes: find the next DATA line | ||||||||||
| BB6F | .ndi_scan_loop←1← BB78 BNE | ||||||||||
| JSR skip_spaces_ptr2 ; Scan to the item end: next character | |||||||||||
| BB72 | CMP #',' ; ',' separator? | ||||||||||
| BB74 | BEQ return_36 ; yes | ||||||||||
| BB76 | CMP #&0d ; end of line? | ||||||||||
| BB78 | BNE ndi_scan_loop ; no: keep scanning | ||||||||||
| BB7A | .ndi_line_marker←3← BB6D BEQ← BB96 BCC← BB9A BCS | ||||||||||
| LDY zp_text_ptr2_off ; Line marker | |||||||||||
| BB7C | LDA (zp_text_ptr2),y ; read it | ||||||||||
| BB7E | BMI out_of_data ; end of program: Out of DATA | ||||||||||
| BB80 | INY ; Skip the line number | ||||||||||
| BB81 | INY ; past the low byte | ||||||||||
| BB82 | LDA (zp_text_ptr2),y ; Line length | ||||||||||
| BB84 | TAX ; X = length | ||||||||||
| BB85 | .ndi_scan_loop2←1← BB8A BEQ | ||||||||||
| INY ; Next character | |||||||||||
| BB86 | LDA (zp_text_ptr2),y ; read it | ||||||||||
| BB88 | CMP #' ' ; space? | ||||||||||
| BB8A | BEQ ndi_scan_loop2 ; skip leading spaces | ||||||||||
| BB8C | CMP #&dc ; DATA token? | ||||||||||
| BB8E | BEQ ndi_skip_token ; yes: use this line | ||||||||||
| BB90 | TXA ; Advance to the next line | ||||||||||
| BB91 | CLC ; add the length... | ||||||||||
| BB92 | ADC zp_text_ptr2 ; to the pointer low, | ||||||||||
| BB94 | STA zp_text_ptr2 ; (store) | ||||||||||
| BB96 | BCC ndi_line_marker ; no carry | ||||||||||
| BB98 | INC zp_text_ptr2_1 ; carry into high | ||||||||||
| BB9A | BCS ndi_line_marker ; continue | ||||||||||
| BB9C | .out_of_data←1← BB7E BMI | ||||||||||
| BRK ; Out of DATA error | |||||||||||
| BB9D | EQUS "*Out of " | ||||||||||
| BBA5 | EQUB &DC | ||||||||||
| BBA6 | .err_no_repeat←1← BBBC BEQ | ||||||||||
| BRK ; No REPEAT error | |||||||||||
| BBA7 | EQUS "+No " | ||||||||||
| BBAB | EQUB &F5, &00 | ||||||||||
| BBAD | .ndi_skip_token←1← BB8E BEQ | ||||||||||
| INY ; Step past the DATA token | |||||||||||
| BBAE | STY zp_text_ptr2_off ; record the offset | ||||||||||
| BBB0 | .return_36←3← BB65 BEQ← BB69 BEQ← BB74 BEQ | ||||||||||
| RTS ; Return | |||||||||||
UNTILEnd a REPEAT loop: loop back unless the condition is true. UNTIL expr.
|
|||||||||||
| BBB1 | .stmt_until | ||||||||||
| JSR eval_expr ; Evaluate the UNTIL condition | |||||||||||
| BBB4 | JSR assign_check_end ; Check for end of statement | ||||||||||
| BBB7 | JSR coerce_var_to_integer ; coerce the condition to an integer | ||||||||||
| BBBA | LDX zp_repeat_level ; UNTIL with no REPEAT pending: error | ||||||||||
| BBBC | BEQ err_no_repeat ; UNTIL with no REPEAT: error | ||||||||||
| BBBE | LDA zp_iwa ; Test the condition for true (non-zero): | ||||||||||
| BBC0 | ORA zp_iwa_1 ; byte 1, | ||||||||||
| BBC2 | ORA zp_iwa_2 ; byte 2, | ||||||||||
| BBC4 | ORA zp_iwa_3 ; byte 3 | ||||||||||
| BBC6 | BEQ until_reload ; Condition false: loop back to the REPEAT | ||||||||||
| BBC8 | DEC zp_repeat_level ; Condition true: pop the frame and continue | ||||||||||
| BBCA | JMP statement_loop ; true: exit the loop, continue | ||||||||||
| BBCD | .until_reload←1← BBC6 BEQ | ||||||||||
| LDY repeat_loop_lo,x ; Reload the saved loop-start position | |||||||||||
| BBD0 | LDA repeat_loop_hi,x ; Reload the loop position: high | ||||||||||
| BBD3 | JMP goto_jump ; jump back to the REPEAT | ||||||||||
| BBD6 | .err_too_many_repeats←1← BBE8 BCS | ||||||||||
| BRK ; BRK error block: too many REPEATs | |||||||||||
| BBD7 | EQUS ",Too many " | ||||||||||
| BBE1 | EQUB &F5, &73, &00 | ||||||||||
REPEATBegin a REPEAT...UNTIL loop, stacking the loop position. REPEAT.
|
|||||||||||
| BBE4 | .stmt_repeat | ||||||||||
| LDX zp_repeat_level ; Index the REPEAT stack | |||||||||||
| BBE6 | CPX #&14 ; At most 20 nested REPEATs | ||||||||||
| BBE8 | BCS err_too_many_repeats ; Too many nested REPEATs | ||||||||||
| BBEA | JSR skip_to_statement_end ; Point PtrA at the loop start | ||||||||||
| BBED | LDA zp_text_ptr ; Push the loop-start position | ||||||||||
| BBEF | STA repeat_stack,x ; Store the loop position: low | ||||||||||
| BBF2 | LDA zp_text_ptr_1 ; high | ||||||||||
| BBF4 | STA repeat_stack_hi,x ; (store) | ||||||||||
| BBF7 | INC zp_repeat_level ; One more REPEAT outstanding | ||||||||||
| BBF9 | JMP next_statement ; Continue execution | ||||||||||
| BBFC | .point_string_buffer←1← BAA2 JSR | ||||||||||
| LDY #0 ; Point at the string buffer (&0600): low | |||||||||||
| BBFE | LDA #6 ; high | ||||||||||
| BC00 | BNE ril_set_addr ; set it (shared tail) | ||||||||||
| fall through ↓ | |||||||||||
Print the prompt and read a linePrint the character in A as a prompt, then read a line into the input buffer at &0700 via OSWORD 0.
|
|||||||||
| BC02 | .read_input_line←2← 8B08 JSR← 90BD JSR | ||||||||
| JSR print_char ; Print the prompt character | |||||||||
| BC05 | LDY #0 ; Input buffer at &0700 | ||||||||
| BC07 | LDA #7 ; high byte &07 | ||||||||
| BC09 | .ril_set_addr←1← BC00 BNE | ||||||||
| STY zp_general ; address low = &00 | |||||||||
| BC0B | STA zp_general_1 ; address high = &07 | ||||||||
| BC0D | LDA #&ee ; Max length 238 | ||||||||
| BC0F | STA zp_fileblk ; store it | ||||||||
| BC11 | LDA #' ' ; Lowest accepted character | ||||||||
| BC13 | STA zp_fileblk_1 ; store it | ||||||||
| BC15 | LDY #&ff ; Highest accepted character (&FF) | ||||||||
| BC17 | STY zp_fwb_sign ; store it | ||||||||
| BC19 | INY ; Y wraps back to 0 | ||||||||
| BC1A | LDX #&37 ; Point at the OSWORD block | ||||||||
| BC1C | TYA ; A = 0: OSWORD read line | ||||||||
| BC1D | JSR osword ; Read a line | ||||||||
| BC20 | BCC reset_print_column ; ok: reset the column | ||||||||
| BC22 | JMP escape_error ; Escape: raise it | ||||||||
Print a newline and reset the print columnEmit a newline via OSNEWL, then fall through into reset_print_column to zero the print-column counter. The standard way BASIC ends an output line so the column-tracking auto-newline logic stays in step.
|
||||||||||
| BC25 | .emit_newline←9← 853F JSR← 857B JSR← 8D7D JSR← 8E53 JSR← 8E67 JSR← 909A JSR← B56E JSR← B5FC JSR← BFE7 JSR | |||||||||
| JSR osnewl ; Print a newline | ||||||||||
| BC28 | .reset_print_column←4← 8EC7 JSR← 93D7 JSR← B55F JMP← BC20 BCC | |||||||||
| LDA #0 ; Reset the column to 0 | ||||||||||
| BC2A | STA zp_count ; store it | |||||||||
| BC2C | RTS ; Return | |||||||||
Delete a program line and close the gapFind the line (find_program_line), then shift every later line down over it and update TOP. No-op if the line is absent.
|
|||||||||
| BC2D | .delete_program_line←2← 8F53 JSR← BC8F JSR | ||||||||
| JSR find_program_line ; Find the line | |||||||||
| BC30 | BCS return_37 ; not present: nothing to do | ||||||||
| BC32 | LDA zp_fwb_exp ; Destination = line start | ||||||||
| BC34 | SBC #2 ; line start - 2, | ||||||||
| BC36 | STA zp_general ; destination low (&37), | ||||||||
| BC38 | STA zp_fwb_exp ; also &3D, | ||||||||
| BC3A | STA zp_top ; and TOP (&12), | ||||||||
| BC3C | LDA zp_fwb_m1 ; high byte, | ||||||||
| BC3E | SBC #0 ; with borrow, | ||||||||
| BC40 | STA zp_general_1 ; destination high (&38), | ||||||||
| BC42 | STA zp_top_1 ; and TOP+1 (&13), | ||||||||
| BC44 | STA zp_fwb_m1 ; and &3E | ||||||||
| BC46 | LDY #3 ; Line length | ||||||||
| BC48 | LDA (zp_general),y ; read it (offset 3) | ||||||||
| BC4A | CLC ; Source = the next line | ||||||||
| BC4B | ADC zp_general ; destination + length, | ||||||||
| BC4D | STA zp_general ; source low, | ||||||||
| BC4F | BCC del_copy_start ; no carry into the high byte | ||||||||
| BC51 | INC zp_general_1 ; carry into the high byte | ||||||||
| BC53 | .del_copy_start←1← BC4F BCC | ||||||||
| LDY #0 ; From offset 0 | |||||||||
| BC55 | .del_copy_loop←2← BC5E BNE← BC64 BNE | ||||||||
| LDA (zp_general),y ; Copy a byte down | |||||||||
| BC57 | STA (zp_top),y ; to the destination | ||||||||
| BC59 | CMP #&0d ; end of line? | ||||||||
| BC5B | BEQ del_skip_cr ; yes: handle the line boundary | ||||||||
| BC5D | .del_copy_next←1← BC79 JMP | ||||||||
| INY ; next byte | |||||||||
| BC5E | BNE del_copy_loop ; no page wrap | ||||||||
| BC60 | INC zp_general_1 ; cross a page | ||||||||
| BC62 | INC zp_top_1 ; destination page too | ||||||||
| BC64 | BNE del_copy_loop ; continue | ||||||||
| BC66 | .del_skip_cr←1← BC5B BEQ | ||||||||
| INY ; Step past the CR | |||||||||
| BC67 | BNE del_next_marker ; no page wrap, | ||||||||
| BC69 | INC zp_general_1 ; source page, | ||||||||
| BC6B | INC zp_top_1 ; destination page | ||||||||
| BC6D | .del_next_marker←1← BC67 BNE | ||||||||
| LDA (zp_general),y ; Next line marker | |||||||||
| BC6F | STA (zp_top),y ; copy it down | ||||||||
| BC71 | BMI del_set_top ; end of program? | ||||||||
| BC73 | JSR copy_byte ; no: copy the line number | ||||||||
| BC76 | JSR copy_byte ; ...and the length byte | ||||||||
| BC79 | JMP del_copy_next ; continue with the line body | ||||||||
| BC7C | .del_set_top←1← BC71 BMI | ||||||||
| JSR add_y_to_top ; Set the new top of program | |||||||||
| BC7F | CLC ; carry clear: line was deleted | ||||||||
| BC80 | .return_37←1← BC30 BCS | ||||||||
| RTS ; Return | |||||||||
Copy one byte, advancing the offsetIncrement the shared offset Y (bumping both pointer high bytes on a page crossing), then copy one byte from (zp_general) to (zp_top). The per-byte helper used by delete_program_line to copy the line-number and length bytes while compacting the program.
|
|||||||||||||||
| BC81 | .copy_byte←2← BC73 JSR← BC76 JSR | ||||||||||||||
| INY ; Copy one byte (source -> destination) | |||||||||||||||
| BC82 | BNE copy_byte_read ; no page wrap | ||||||||||||||
| BC84 | INC zp_top_1 ; cross a page | ||||||||||||||
| BC86 | INC zp_general_1 ; source page too | ||||||||||||||
| BC88 | .copy_byte_read←1← BC82 BNE | ||||||||||||||
| LDA (zp_general),y ; read the byte, | |||||||||||||||
| BC8A | STA (zp_top),y ; write it down | ||||||||||||||
| BC8C | RTS ; Return | ||||||||||||||
Insert a tokenised program lineInsert the numbered, tokenised line held in the &0700 input buffer into the program. First deletes any existing line with the same number (delete_program_line); if the buffer holds only a CR the edit was a pure deletion and it returns. Otherwise it measures the line, checks the new TOP still fits below HIMEM (raising 'LINE space' after tidying if not), shifts the program up to open a gap, writes the 4-byte line header (line number + length), copies the line body in, and sets the new TOP.
|
|||||||||||||
| BC8D | .insert_line←2← 8B32 JSR← 90C6 JSR | ||||||||||||
| STY zp_fwb_sign ; Save the line-buffer pointer | |||||||||||||
| BC8F | JSR delete_program_line ; Delete any existing line with this number | ||||||||||||
| BC92 | LDY #7 ; Point past the line header | ||||||||||||
| BC94 | STY zp_fwb_ovf ; save offset 7 in &3C | ||||||||||||
| BC96 | LDY #0 ; Measure the new line: from offset 0 | ||||||||||||
| BC98 | LDA #&0d ; CR | ||||||||||||
| BC9A | CMP (zp_fwb_sign),y ; empty line (deletion only)? | ||||||||||||
| BC9C | BEQ return_38 ; yes: done | ||||||||||||
| BC9E | .insline_scan←1← BCA1 BNE | ||||||||||||
| INY ; Scan to the CR | |||||||||||||
| BC9F | CMP (zp_fwb_sign),y ; CR yet? | ||||||||||||
| BCA1 | BNE insline_scan ; keep scanning | ||||||||||||
| BCA3 | INY ; Add the 4-byte header | ||||||||||||
| BCA4 | INY ; (continued) | ||||||||||||
| BCA5 | INY ; (continued) | ||||||||||||
| BCA6 | STY zp_fwb_m2 ; Line length | ||||||||||||
| BCA8 | INC zp_fwb_m2 ; include the CR | ||||||||||||
| BCAA | LDA zp_top ; Old top of program | ||||||||||||
| BCAC | STA zp_fileblk ; low to &39, | ||||||||||||
| BCAE | LDA zp_top_1 ; high byte, | ||||||||||||
| BCB0 | STA zp_fileblk_1 ; to &3A | ||||||||||||
| BCB2 | JSR add_y_to_top ; New top = old top + line length | ||||||||||||
| BCB5 | STA zp_general ; new top low (&37), | ||||||||||||
| BCB7 | LDA zp_top_1 ; high byte, | ||||||||||||
| BCB9 | STA zp_general_1 ; new top high (&38), | ||||||||||||
| BCBB | DEY ; index the last byte (length-1) | ||||||||||||
| BCBC | LDA zp_himem ; New top vs HIMEM | ||||||||||||
| BCBE | CMP zp_top ; low byte vs TOP, | ||||||||||||
| BCC0 | LDA zp_himem_1 ; high byte, | ||||||||||||
| BCC2 | SBC zp_top_1 ; HIMEM >= new top? | ||||||||||||
| BCC4 | BCS insline_shift ; fits: shift the program up | ||||||||||||
| BCC6 | JSR check_program ; no room: tidy up | ||||||||||||
| BCC9 | JSR clear_vars_heap_stack ; clear variables/heap/stack | ||||||||||||
| BCCC | BRK ; LINE space error | ||||||||||||
| BCCD | EQUB &00, &86 | ||||||||||||
| BCCF | EQUS " space" | ||||||||||||
| BCD5 | EQUB &00 | ||||||||||||
| BCD6 | .insline_shift←2← BCC4 BCS← BCEF BCS | ||||||||||||
| LDA (zp_fileblk),y ; Shift a byte up | |||||||||||||
| BCD8 | STA (zp_general),y ; to the higher address, | ||||||||||||
| BCDA | TYA ; at a page boundary?, | ||||||||||||
| BCDB | BNE insline_shift_next ; no | ||||||||||||
| BCDD | DEC zp_fileblk_1 ; cross a page | ||||||||||||
| BCDF | DEC zp_general_1 ; destination page too | ||||||||||||
| BCE1 | .insline_shift_next←1← BCDB BNE | ||||||||||||
| DEY ; Next byte down | |||||||||||||
| BCE2 | TYA ; offset to A, | ||||||||||||
| BCE3 | ADC zp_fileblk ; + source low, | ||||||||||||
| BCE5 | LDX zp_fileblk_1 ; source high in X, | ||||||||||||
| BCE7 | BCC insline_check ; no carry, | ||||||||||||
| BCE9 | INX ; carry into the high byte | ||||||||||||
| BCEA | .insline_check←1← BCE7 BCC | ||||||||||||
| CMP zp_fwb_exp ; reached the insertion point? | |||||||||||||
| BCEC | TXA ; high byte, | ||||||||||||
| BCED | SBC zp_fwb_m1 ; source vs the insertion point | ||||||||||||
| BCEF | BCS insline_shift ; no: keep shifting | ||||||||||||
| BCF1 | SEC ; Write the new line header | ||||||||||||
| BCF2 | LDY #1 ; from offset 1 | ||||||||||||
| BCF4 | LDA zp_iwa_1 ; line number high | ||||||||||||
| BCF6 | STA (zp_fwb_exp),y ; store it, | ||||||||||||
| BCF8 | INY ; next | ||||||||||||
| BCF9 | LDA zp_iwa ; line number low | ||||||||||||
| BCFB | STA (zp_fwb_exp),y ; store it, | ||||||||||||
| BCFD | INY ; next | ||||||||||||
| BCFE | LDA zp_fwb_m2 ; line length | ||||||||||||
| BD00 | STA (zp_fwb_exp),y ; store it | ||||||||||||
| BD02 | JSR fwb_scale ; Set the new top of program | ||||||||||||
| BD05 | LDY #&ff ; Copy the line body in: offset 0 | ||||||||||||
| BD07 | .insline_advance←1← BD0E BNE | ||||||||||||
| INY ; advance the index | |||||||||||||
| BD08 | LDA (zp_fwb_sign),y ; buffer byte | ||||||||||||
| BD0A | STA (zp_fwb_exp),y ; store it | ||||||||||||
| BD0C | CMP #&0d ; until the CR | ||||||||||||
| BD0E | BNE insline_advance ; loop | ||||||||||||
| BD10 | .return_38←1← BC9C BEQ | ||||||||||||
| RTS ; Return | |||||||||||||
RUNRun the current program from the start. RUN.
|
|||||||||||
| BD11 | .stmt_run | ||||||||||
| JSR check_end_of_statement ; Check the statement ends | |||||||||||
| BD14 | .run_clear←1← BF2D JMP | ||||||||||
| JSR clear_vars_heap_stack ; Clear variables, heap and stack | |||||||||||
| BD17 | LDA zp_page ; Point PtrA at PAGE | ||||||||||
| BD19 | STA zp_text_ptr_1 ; page to the high byte, | ||||||||||
| BD1B | STX zp_text_ptr ; low byte = 0 (X) | ||||||||||
| BD1D | JMP execute_line ; execute from the start | ||||||||||
Clear all variables, the heap and the stackReset LOMEM and VARTOP to TOP, empty the per-letter variable table, and clear the DATA pointer and the BASIC stacks (NEW/CLEAR/RUN).
|
|||||||||||
| BD20 | .clear_vars_heap_stack←5← 8AF3 JSR← 90C9 JSR← 9290 JSR← BCC9 JSR← BD14 JSR | ||||||||||
| LDA zp_top ; LOMEM and VARTOP = TOP: low | |||||||||||
| BD22 | STA zp_lomem ; LOMEM low | ||||||||||
| BD24 | STA zp_vartop ; VARTOP low | ||||||||||
| BD26 | LDA zp_top_1 ; high | ||||||||||
| BD28 | STA zp_lomem_1 ; LOMEM high | ||||||||||
| BD2A | STA zp_vartop_1 ; VARTOP high | ||||||||||
| BD2C | JSR reset_data_and_stacks ; Clear the DATA pointer and the stacks | ||||||||||
| BD2F | .clear_var_table←1← 927E JSR | ||||||||||
| LDX #&80 ; Clear the variable table (&0480-&04FF): | |||||||||||
| BD31 | LDA #0 ; zero byte | ||||||||||
| BD33 | .clear_var_table_loop←1← BD37 BNE | ||||||||||
| STA var_table_base,x ; clear a byte | |||||||||||
| BD36 | DEX ; count down | ||||||||||
| BD37 | BNE clear_var_table_loop ; loop | ||||||||||
| BD39 | RTS ; Return | ||||||||||
Reset the DATA pointer and the BASIC stacksReset the READ/DATA pointer to PAGE and empty the FOR/REPEAT/GOSUB and value stacks: point the stack pointer back at HIMEM and zero the REPEAT, FOR and GOSUB nesting levels. Variables and the heap are left intact. Called on NEW/CLEAR/RUN as part of clear_vars_heap_stack, and on the error path.
|
|||||||||||||||||
| BD3A | .reset_data_and_stacks←3← 8B1A JSR← B41B JSR← BD2C JSR | ||||||||||||||||
| LDA zp_page ; DATA pointer = PAGE: high | |||||||||||||||||
| BD3C | STA zp_data_ptr_1 ; (data pointer high) | ||||||||||||||||
| BD3E | LDA zp_himem ; STACK = HIMEM: low | ||||||||||||||||
| BD40 | STA zp_stack_ptr ; (store) | ||||||||||||||||
| BD42 | LDA zp_himem_1 ; HIMEM high | ||||||||||||||||
| BD44 | STA zp_stack_ptr_1 ; (store) | ||||||||||||||||
| BD46 | LDA #0 ; Clear the loop/subroutine levels: | ||||||||||||||||
| BD48 | STA zp_repeat_level ; REPEAT | ||||||||||||||||
| BD4A | STA zp_for_level ; FOR | ||||||||||||||||
| BD4C | STA zp_gosub_level ; GOSUB | ||||||||||||||||
| BD4E | STA zp_data_ptr ; DATA pointer low = 0 (= PAGE) | ||||||||||||||||
| BD50 | RTS ; Return | ||||||||||||||||
Push the floating-point accumulator onto the BASIC stackReserve five bytes on the BASIC stack and copy the packed floating-point accumulator onto it. Errors if the stack meets the heap.
|
|||||||
| BD51 | .stack_real←12← 9A3E JSR← 9A50 JSR← 9C8B JSR← 9CAC JSR← 9CE1 JSR← 9CFF JSR← 9D14 JSR← 9D20 JSR← 9DE9 JSR← 9E39 JSR← AF27 JSR← BD92 BMI | ||||||
| LDA zp_stack_ptr ; From the stack top... | |||||||
| BD53 | SEC ; prepare subtraction | ||||||
| BD54 | SBC #5 ; Lower the stack by 5 bytes (a packed real) | ||||||
| BD56 | JSR reserve_stack ; reserve the space | ||||||
| BD59 | LDY #0 ; Packed byte 0 = exponent | ||||||
| BD5B | LDA zp_fwa_exp ; read it | ||||||
| BD5D | STA (zp_stack_ptr),y ; (store) | ||||||
| BD5F | INY ; advance | ||||||
| BD60 | LDA zp_fwa_sign ; Take the sign... | ||||||
| BD62 | AND #&80 ; Pack: fold the sign into the mantissa MSB | ||||||
| BD64 | STA zp_fwa_sign ; keep just the sign bit | ||||||
| BD66 | LDA zp_fwa_m1 ; mantissa MSB | ||||||
| BD68 | AND #&7f ; drop the implied 1 | ||||||
| BD6A | ORA zp_fwa_sign ; fold in the sign | ||||||
| BD6C | STA (zp_stack_ptr),y ; byte 1 | ||||||
| BD6E | INY ; advance | ||||||
| BD6F | LDA zp_fwa_m2 ; byte 2 | ||||||
| BD71 | STA (zp_stack_ptr),y ; (store) | ||||||
| BD73 | INY ; advance | ||||||
| BD74 | LDA zp_fwa_m3 ; byte 3 | ||||||
| BD76 | STA (zp_stack_ptr),y ; (store) | ||||||
| BD78 | INY ; advance | ||||||
| BD79 | LDA zp_fwa_m4 ; byte 4 | ||||||
| BD7B | STA (zp_stack_ptr),y ; (store) | ||||||
| BD7D | RTS ; Real pushed | ||||||
Pop a real off the BASIC stackPoint zp_fp_ptr at the 5-byte real on top of the BASIC stack and drop it (advance the stack pointer by 5), so an FP routine can use the popped value as its (zp_fp_ptr) operand.
|
|||||||||||||
| BD7E | .unstack_real←11← 9A47 JSR← 9A5C JSR← 9C9B JSR← 9CF1 JSR← 9D05 JSR← 9D2C JSR← 9DF5 JSR← 9E4A JSR← 9E6F JSR← AF2D JSR← B2E7 JSR | ||||||||||||
| LDA zp_stack_ptr ; Stack top is where the real sits... | |||||||||||||
| BD80 | CLC ; clear carry for the add | ||||||||||||
| BD81 | STA zp_fp_ptr ; ...point the fp operand there | ||||||||||||
| BD83 | ADC #5 ; Drop 5 bytes (a packed real) | ||||||||||||
| BD85 | STA zp_stack_ptr ; (store the new stack low byte) | ||||||||||||
| BD87 | LDA zp_stack_ptr_1 ; Stack-pointer high byte | ||||||||||||
| BD89 | STA zp_fp_ptr_1 ; into the fp-operand pointer too | ||||||||||||
| BD8B | ADC #0 ; Carry into the high byte | ||||||||||||
| BD8D | STA zp_stack_ptr_1 ; (store it) | ||||||||||||
| BD8F | RTS ; zp_fp_ptr now addresses the popped real | ||||||||||||
Push the current value by typePush the current value onto the BASIC stack in the form matching its type: a string (stack_string), a real (stack_real) or, falling through, an integer (stack_integer).
|
|||||||||
| BD90 | .stack_value←2← B291 JSR← B31C JSR | ||||||||
| BEQ stack_string ; Type 0 (string): stack as a string | |||||||||
| BD92 | BMI stack_real ; Negative (real): stack 5 bytes; else integer below | ||||||||
| fall through ↓ | |||||||||
Push the integer accumulator onto the BASIC stackReserve four bytes on the BASIC stack (zp_stack_ptr, &04) and copy the integer accumulator (zp_iwa) onto it. Errors if the stack would collide with the heap.
|
|||||||
| BD94 | .stack_integer←29← 85AC JSR← 8BEB JSR← 8BFB JSR← 8ED8 JSR← 8F36 JSR← 8F71 JSR← 90B5 JSR← 90E8 JSR← 9185 JSR← 9334 JSR← 9400 JSR← 96FF JSR← 9744 JSR← 9AA2 JSR← 9B6F JSR← 9B7E JSR← 9DCE JSR← 9E1D JSR← AB44 JSR← B0C5 JSR← B298 JSR← B329 JMP← B5B0 JSR← B5C8 JSR← B7CB JSR← B9F1 JSR← BAD0 JSR← BB29 JSR← BB35 JSR | ||||||
| LDA zp_stack_ptr ; From the stack top... | |||||||
| BD96 | SEC ; prepare subtraction | ||||||
| BD97 | SBC #4 ; Lower the stack by 4 bytes (an integer) | ||||||
| BD99 | JSR reserve_stack ; reserve the space (check for room) | ||||||
| BD9C | LDY #3 ; Copy IWA, MSB first: byte 3 | ||||||
| BD9E | LDA zp_iwa_3 ; read it | ||||||
| BDA0 | STA (zp_stack_ptr),y ; (store) | ||||||
| BDA2 | DEY ; next | ||||||
| BDA3 | LDA zp_iwa_2 ; byte 2 | ||||||
| BDA5 | STA (zp_stack_ptr),y ; (store) | ||||||
| BDA7 | DEY ; next | ||||||
| BDA8 | LDA zp_iwa_1 ; byte 1 | ||||||
| BDAA | STA (zp_stack_ptr),y ; (store) | ||||||
| BDAC | DEY ; next | ||||||
| BDAD | LDA zp_iwa ; byte 0 (LSB) | ||||||
| BDAF | STA (zp_stack_ptr),y ; (store) | ||||||
| BDB1 | RTS ; Integer pushed | ||||||
Push the current string onto the BASIC stackCopy the string from the string buffer (length zp_strbuf_len, &36; text at &0600) onto the BASIC stack, length last. Errors if the stack meets the heap.
|
|||||||||
| BDB2 | .stack_string←9← 9AE7 JSR← 9C15 JSR← ABF7 JSR← ACED JSR← AD06 JSR← AFD7 JSR← AFF9 JSR← B042 JSR← BD90 BEQ | ||||||||
| CLC ; From the stack top... | |||||||||
| BDB3 | LDA zp_stack_ptr ; low... | ||||||||
| BDB5 | SBC zp_strbuf_len ; Lower the stack by length+1 bytes (carry clear) | ||||||||
| BDB7 | JSR reserve_stack ; reserve the space | ||||||||
| BDBA | LDY zp_strbuf_len ; string length | ||||||||
| BDBC | BEQ ss_push_length ; zero length: just push the length | ||||||||
| BDBE | .ss_copy_loop←1← BDC4 BNE | ||||||||
| LDA strbuf_base,y ; Copy the string from the buffer (&0600): char Y | |||||||||
| BDC1 | STA (zp_stack_ptr),y ; (onto the stack) | ||||||||
| BDC3 | DEY ; next | ||||||||
| BDC4 | BNE ss_copy_loop ; loop | ||||||||
| BDC6 | .ss_push_length←1← BDBC BEQ | ||||||||
| LDA zp_strbuf_len ; Push the length last | |||||||||
| BDC8 | STA (zp_stack_ptr),y ; (store) | ||||||||
| BDCA | RTS ; String pushed | ||||||||
Pop a string off the BASIC stackCopy the length-prefixed string on top of the stack into the string buffer and drop it (advance the stack pointer past the length byte and the characters).
|
|||||||||||||
| BDCB | .unstack_string←6← 9C37 JSR← AD0F JSR← AFE0 JSR← B002 JSR← B061 JSR← B2FD JSR | ||||||||||||
| LDY #0 ; Pop a string: read its length | |||||||||||||
| BDCD | LDA (zp_stack_ptr),y ; read it | ||||||||||||
| BDCF | STA zp_strbuf_len ; (store) | ||||||||||||
| BDD1 | BEQ drop_stacked_string ; zero length: just drop the length | ||||||||||||
| BDD3 | TAY ; Y = length | ||||||||||||
| BDD4 | .us_copy_loop←1← BDDA BNE | ||||||||||||
| LDA (zp_stack_ptr),y ; Copy the string to the buffer: char Y | |||||||||||||
| BDD6 | STA strbuf_base,y ; (into the buffer) | ||||||||||||
| BDD9 | DEY ; next | ||||||||||||
| BDDA | BNE us_copy_loop ; loop | ||||||||||||
| fall through ↓ | |||||||||||||
Drop a string off the BASIC stackRead the length byte of the length-prefixed string on top of the BASIC stack and advance the stack pointer past both the length byte and the string characters, discarding the string without copying it.
|
|||||||||
| BDDC | .drop_stacked_string←6← 8CEB JMP← 9B16 JSR← AC20 JSR← AD39 JSR← AD52 JSR← BDD1 BEQ | ||||||||
| LDY #0 ; Drop the string: get its length | |||||||||
| BDDE | LDA (zp_stack_ptr),y ; read it | ||||||||
| BDE0 | SEC ; so the +1 covers the length byte | ||||||||
| BDE1 | .drop_string_adv←1← 8D28 JMP | ||||||||
| ADC zp_stack_ptr ; advance the stack pointer past it: low | |||||||||
| BDE3 | STA zp_stack_ptr ; (store) | ||||||||
| BDE5 | BCC return_39 ; done | ||||||||
| BDE7 | INC zp_stack_ptr_1 ; carry into high | ||||||||
| BDE9 | RTS ; Return | ||||||||
Pop an integer from the BASIC stackCopy the four-byte integer on top of the BASIC stack into the integer accumulator (zp_iwa), then fall into drop_stack_integer to advance the stack pointer past it.
|
|||||||||||
| BDEA | .unstack_integer←16← 8C1E JSR← 8F11 JSR← 8F50 JSR← 90B2 JSR← 90C0 JSR← 9A3B JSR← 9CA9 JSR← 9CFC JSR← 9D11 JSR← 9D78 JSR← AB56 JSR← B0D0 JSR← B2CA JSR← B2F0 JSR← B5C5 JSR← B5E9 JSR | ||||||||||
| LDY #3 ; Index the stacked integer (4 bytes, MSB first) | |||||||||||
| BDEC | LDA (zp_stack_ptr),y ; Top byte (MSB)... | ||||||||||
| BDEE | STA zp_iwa_3 ; ...into IWA byte 3 | ||||||||||
| BDF0 | DEY ; next byte | ||||||||||
| BDF1 | LDA (zp_stack_ptr),y ; byte 2... | ||||||||||
| BDF3 | STA zp_iwa_2 ; ...into IWA | ||||||||||
| BDF5 | DEY ; next byte | ||||||||||
| BDF6 | LDA (zp_stack_ptr),y ; byte 1... | ||||||||||
| BDF8 | STA zp_iwa_1 ; ...into IWA | ||||||||||
| BDFA | DEY ; last byte | ||||||||||
| BDFB | LDA (zp_stack_ptr),y ; byte 0 (LSB)... | ||||||||||
| BDFD | STA zp_iwa ; ...into IWA, then fall into drop_stack_integer | ||||||||||
| fall through ↓ | |||||||||||
Drop an integer off the stackAdvance the BASIC stack pointer by four bytes.
|
|||||||||||
| BDFF | .drop_stack_integer←2← 9B4E JSR← 9B95 JSR | ||||||||||
| CLC ; Prepare to add | |||||||||||
| BE00 | LDA zp_stack_ptr ; Drop four bytes: stack pointer... | ||||||||||
| BE02 | ADC #4 ; ...+ 4 | ||||||||||
| BE04 | STA zp_stack_ptr ; (store) | ||||||||||
| BE06 | BCC return_39 ; No carry: done | ||||||||||
| BE08 | INC zp_stack_ptr_1 ; Carry into the high byte | ||||||||||
| BE0A | .return_39←3← BDE5 BCC← BE06 BCC← BE29 BCC | ||||||||||
| RTS ; Return (shared) | |||||||||||
Pop a stacked integer into the general work areaSet the destination to zp_general (&37) and fall into unstack_int_to_zp, which copies the 4-byte integer on top of the BASIC stack to (&37..&3A) and drops it from the stack.
|
|||||||||||
| BE0B | .unstack_int_to_general←3← 9412 JSR← B21C JSR← B4B4 JSR | ||||||||||
| LDX #&37 ; Default destination: zp_general (&37) | |||||||||||
| fall through ↓ | |||||||||||
Pop a stacked integer into a zero-page variableCopy the four-byte integer on top of the BASIC stack into the zero-page bytes at (X .. X+3), then drop it from the stack. The &BE0B entry uses X = &37 (the general work area).
|
|||||||||||||
| BE0D | .unstack_int_to_zp←5← 8FA8 JSR← 9233 JSR← 970D JSR← 9755 JSR← 99DD JSR | ||||||||||||
| LDY #3 ; Copy the stacked integer to (X): top byte | |||||||||||||
| BE0F | LDA (zp_stack_ptr),y ; (read) | ||||||||||||
| BE11 | STA zp_vartop_1,x ; ...byte 3 | ||||||||||||
| BE13 | DEY ; next | ||||||||||||
| BE14 | LDA (zp_stack_ptr),y ; (read) | ||||||||||||
| BE16 | STA zp_vartop,x ; byte 2 | ||||||||||||
| BE18 | DEY ; next | ||||||||||||
| BE19 | LDA (zp_stack_ptr),y ; (read) | ||||||||||||
| BE1B | STA zp_lomem_1,x ; byte 1 | ||||||||||||
| BE1D | DEY ; next | ||||||||||||
| BE1E | LDA (zp_stack_ptr),y ; (read) | ||||||||||||
| BE20 | STA zp_lomem,x ; byte 0 | ||||||||||||
| BE22 | CLC ; Now drop the integer from the stack | ||||||||||||
| BE23 | LDA zp_stack_ptr ; stack pointer... | ||||||||||||
| BE25 | ADC #4 ; ...+ 4 | ||||||||||||
| BE27 | STA zp_stack_ptr ; (store) | ||||||||||||
| BE29 | BCC return_39 ; No carry: done | ||||||||||||
| BE2B | INC zp_stack_ptr_1 ; Carry into the high byte | ||||||||||||
| BE2D | RTS ; Return | ||||||||||||
Set the stack pointer and check for roomSet the BASIC value-stack pointer to a new top (low byte in A, borrow already taken into the high byte) and check it has not run down into the top of variable storage (zp_vartop). Raises "No room" on collision; otherwise returns with the stack lowered.
|
||||||
| BE2E | .reserve_stack←4← B19E JSR← BD56 JSR← BD99 JSR← BDB7 JSR | |||||
| STA zp_stack_ptr ; Set the new stack-pointer low byte | ||||||
| BE30 | BCS rs_set_high ; No borrow: high byte unchanged | |||||
| BE32 | DEC zp_stack_ptr_1 ; Borrow: decrement the high byte | |||||
| BE34 | .rs_set_high←1← BE30 BCS | |||||
| LDY zp_stack_ptr_1 ; New stack-pointer high byte | ||||||
| BE36 | CPY zp_vartop_1 ; Compare the new top against the heap top | |||||
| BE38 | BCC stack_no_room ; New top below the heap page: No room | |||||
| BE3A | BNE return_40 ; Clearly above the heap: room available | |||||
| BE3C | CMP zp_vartop ; Same page: compare the low bytes | |||||
| BE3E | BCC stack_no_room ; Below the heap top: No room | |||||
| BE40 | .return_40←1← BE3A BNE | |||||
| RTS ; Room available: return | ||||||
| BE41 | .stack_no_room←2← BE38 BCC← BE3E BCC | |||||
| JMP err_no_room ; Stack meets heap: No room | ||||||
Store the accumulator into a zero-page integer variableCopy IWA into the 4-byte resident integer variable at &00+X (the inverse of iwa_load_zp).
|
|||||||||||||
| BE44 | .iwa_store_zp←5← 885F JSR← 9D75 JSR← AF41 JSR← B2E0 JSR← B315 JSR | ||||||||||||
| LDA zp_iwa ; Copy IWA to the zp variable at X: byte 0 | |||||||||||||
| BE46 | STA zp_lomem,x ; (&00+X) | ||||||||||||
| BE48 | LDA zp_iwa_1 ; byte 1 | ||||||||||||
| BE4A | STA zp_lomem_1,x ; (&01+X) | ||||||||||||
| BE4C | LDA zp_iwa_2 ; byte 2 | ||||||||||||
| BE4E | STA zp_vartop,x ; (&02+X) | ||||||||||||
| BE50 | LDA zp_iwa_3 ; byte 3 | ||||||||||||
| BE52 | STA zp_vartop_1,x ; (&03+X) | ||||||||||||
| BE54 | RTS ; Done | ||||||||||||
| BE55 | .fwb_scale_clc←1← BB04 JSR | ||||||||||||
| CLC ; Add without carry | |||||||||||||
| BE56 | .fwb_scale←1← BD02 JSR | ||||||||||||
| TYA ; A = the amount (Y) | |||||||||||||
| BE57 | ADC zp_fwb_exp ; add it to the FWB exponent | ||||||||||||
| BE59 | STA zp_fwb_exp ; (store) | ||||||||||||
| BE5B | BCC fwb_scale_done ; no carry: done | ||||||||||||
| BE5D | INC zp_fwb_m1 ; carry into the mantissa MSB | ||||||||||||
| BE5F | .fwb_scale_done←1← BE5B BCC | ||||||||||||
| LDY #1 ; Y = 1 | |||||||||||||
| BE61 | RTS ; Return | ||||||||||||
Load a program from the filing systemSet the OSFILE load address to PAGE and call OSFILE &FF to read the named BASIC program into memory. Used by LOAD and CHAIN. LOAD/SAVE drive OSFILE through an 18-byte control block in zero page, pointed at by XY = &0037. Each address field is 4 bytes (the BBC's 32-bit address space; the high words come from OSBYTE &82):
This routine fills only the filename pointer, the load address (PAGE),
and exec = 0 (so OSFILE &FF loads to the block's load address rather
than the file's own).
|
|||||||||||||||||||||
| BE62 | .load_program←2← BF24 JSR← BF2A JSR | ||||||||||||||||||||
| JSR eval_filename ; Set the OSFILE load address to PAGE | |||||||||||||||||||||
| BE65 | TAY ; Y = 0 (for the exec address) | ||||||||||||||||||||
| BE66 | LDA #osfile_load ; OSFILE &FF: load the named file | ||||||||||||||||||||
| BE68 | STY zp_fwb_exp ; exec address = 0 (load to the given address) | ||||||||||||||||||||
| BE6A | LDX #&37 ; control block at &37 | ||||||||||||||||||||
| BE6C | JSR osfile ; osfile: load file | ||||||||||||||||||||
| fall through ↓ | |||||||||||||||||||||
Validate the program and set TOPWalk the lines from PAGE checking each is well-formed (CR-terminated, non-zero length), and set TOP past the end. Raises "Bad program" if a line is malformed.
|
|||||||||
| BE6F | .check_program←6← 8AC3 JSR← 8ACB JSR← 8FAB JSR← B5E6 JSR← BCC6 JSR← BEF3 JSR | ||||||||
| LDA zp_page ; Set TOP = PAGE: high | |||||||||
| BE71 | STA zp_top_1 ; (TOP high) | ||||||||
| BE73 | LDY #0 ; low 0 | ||||||||
| BE75 | STY zp_top ; (store) | ||||||||
| BE77 | INY ; Y = 1 | ||||||||
| BE78 | .chkprog_loop←1← BE8E BNE | ||||||||
| DEY ; step back to the byte before the line | |||||||||
| BE79 | LDA (zp_top),y ; get it | ||||||||
| BE7B | CMP #&0d ; each line must be CR-terminated | ||||||||
| BE7D | BNE bad_program ; not a CR: Bad program | ||||||||
| BE7F | INY ; step to the line number / end marker | ||||||||
| BE80 | LDA (zp_top),y ; get it | ||||||||
| BE82 | BMI chkprog_end ; high bit set: end of program | ||||||||
| BE84 | LDY #3 ; line length is at offset 3 | ||||||||
| BE86 | LDA (zp_top),y ; get it | ||||||||
| BE88 | BEQ bad_program ; zero length: Bad program | ||||||||
| BE8A | CLC ; advance to the next line | ||||||||
| BE8B | JSR add_y_to_top_lo ; TOP += line length | ||||||||
| BE8E | BNE chkprog_loop ; loop over all lines | ||||||||
| BE90 | .chkprog_end←1← BE82 BMI | ||||||||
| INY ; End of program: skip the &FF marker | |||||||||
| BE91 | CLC ; clear carry for TOP += Y | ||||||||
| BE92 | .add_y_to_top←2← BC7C JSR← BCB2 JSR | ||||||||
| TYA ; TOP += Y | |||||||||
| BE93 | .add_y_to_top_lo←1← BE8B JSR | ||||||||
| ADC zp_top ; add: low | |||||||||
| BE95 | STA zp_top ; (store) | ||||||||
| BE97 | BCC chkprog_ok ; no carry | ||||||||
| BE99 | INC zp_top_1 ; carry into high | ||||||||
| BE9B | .chkprog_ok←1← BE97 BCC | ||||||||
| LDY #1 ; return Y=1 (NE) | |||||||||
| BE9D | RTS ; Return | ||||||||
| BE9E | .bad_program←2← BE7D BNE← BE88 BEQ | ||||||||
| JSR print_inline_string ; Bad program: print the message | |||||||||
| BEA1 | EQUS &0D, "Bad program", &0D | ||||||||
| BEAE | NOP ; (string terminator) | ||||||||
| BEAF | JMP immediate_loop ; back to the immediate loop | ||||||||
| BEB2 | .point_strbuf_lo←1← BED7 JSR | ||||||||
| LDA #0 ; Point the general pointer at the string buffer: low | |||||||||
| BEB4 | STA zp_general ; (store) | ||||||||
| BEB6 | LDA #6 ; high (&06) | ||||||||
| BEB8 | STA zp_general_1 ; (store) | ||||||||
| fall through ↓ | |||||||||
Terminate the string buffer with a CRWrite a carriage return (&0D) into string_work (&0600) at the offset given by zp_strbuf_len, marking the end of the string buffer. Reached both by fall-through from point_strbuf_lo and by jsr from assign_str_addr and &BF88.
|
|||||||||||
| BEBA | .terminate_strbuf←2← 8CA2 JSR← BF88 JSR | ||||||||||
| LDY zp_strbuf_len ; Terminate the string buffer with a CR: | |||||||||||
| BEBC | LDA #&0d ; CR | ||||||||||
| BEBE | STA string_work,y ; at the end of the buffer | ||||||||||
| BEC1 | RTS ; Return | ||||||||||
OSCLIPass a string to the OS command-line interpreter. OSCLI string.
|
|||||||||||
| BEC2 | .stmt_oscli | ||||||||||
| JSR eval_string_arg ; Evaluate the command string, CR-terminate it | |||||||||||
| BEC5 | LDX #0 ; XY -> the string (&0600): low | ||||||||||
| BEC7 | LDY #6 ; high byte &06 | ||||||||||
| BEC9 | JSR oscli ; Pass it to OSCLI | ||||||||||
| BECC | JMP statement_loop ; Back to execution | ||||||||||
| BECF | .oscli_type_error←1← BED5 BNE | ||||||||||
| JMP err_type_mismatch ; not a string: Type mismatch | |||||||||||
Evaluate a string argument and CR-terminate itEvaluate an expression via eval_expr, require it to be a string (Type mismatch otherwise), CR-terminate it in the string buffer, and check that the statement ends. Used by OSCLI-style commands and eval_filename to fetch a single string argument.
|
|||||||||||
| BED2 | .eval_string_arg←2← BEC2 JSR← BEDD JSR | ||||||||||
| JSR eval_expr ; Evaluate the expression | |||||||||||
| BED5 | BNE oscli_type_error ; not a string: error | ||||||||||
| BED7 | JSR point_strbuf_lo ; CR-terminate the string buffer | ||||||||||
| BEDA | JMP assign_check_end ; Check for end of statement | ||||||||||
Evaluate a filename and build the OSFILE load addressEvaluate a CR-terminated filename string via eval_string_arg, then set the load address to PAGE (low byte 0, high byte PAGE) and read the machine's high-order address word via OSBYTE &82. Shared setup for SAVE/LOAD/CHAIN.
|
|||||||||||||||||||
| BEDD | .eval_filename←2← BE62 JSR← BF0A JSR | ||||||||||||||||||
| JSR eval_string_arg ; Evaluate the filename, CR-terminate | |||||||||||||||||||
| BEE0 | DEY ; Y = 0 for the low byte | ||||||||||||||||||
| BEE1 | STY zp_fileblk ; LOAD address low = 0 | ||||||||||||||||||
| BEE3 | LDA zp_page ; LOAD address high = PAGE | ||||||||||||||||||
| BEE5 | STA zp_fileblk_1 ; (store) | ||||||||||||||||||
| BEE7 | .read_himem_byte←1← 93A3 JSR | ||||||||||||||||||
| LDA #osbyte_read_high_order_address ; OSBYTE &82: read the high-order address | |||||||||||||||||||
| BEE9 | JSR osbyte ; Read high-order address (machine high word) | ||||||||||||||||||
| BEEC | STX zp_fwb_sign ; set the LOAD high word | ||||||||||||||||||
| BEEE | STY zp_fwb_ovf ; high word: X and Y | ||||||||||||||||||
| BEF0 | LDA #0 ; A = 0 | ||||||||||||||||||
| BEF2 | RTS ; Return | ||||||||||||||||||
SAVESave the current program to the filing system. SAVE string.
|
|||||||||||
| BEF3 | .stmt_save | ||||||||||
| JSR check_program ; Check the program, set TOP | |||||||||||
| BEF6 | LDA zp_top ; End address = TOP | ||||||||||
| BEF8 | STA zp_fp_temp_2 ; low byte to &45, | ||||||||||
| BEFA | LDA zp_top_1 ; high byte, | ||||||||||
| BEFC | STA zp_fp_temp_3 ; to &46 | ||||||||||
| BEFE | LDA #&23 ; Exec address = language startup | ||||||||||
| BF00 | STA zp_fwb_exp ; low byte &23 to &3D, | ||||||||||
| BF02 | LDA #&80 ; high byte &80, | ||||||||||
| BF04 | STA zp_fwb_m1 ; to &3E (exec &8023) | ||||||||||
| BF06 | LDA zp_page ; Start address = PAGE | ||||||||||
| BF08 | STA zp_fwb_rnd ; PAGE to &42 | ||||||||||
| BF0A | JSR eval_filename ; Read the machine high address words | ||||||||||
| BF0D | STX zp_fwb_m2 ; Fill the address high words | ||||||||||
| BF0F | STY zp_fwb_m3 ; &40, | ||||||||||
| BF11 | STX zp_fp_temp ; &43, | ||||||||||
| BF13 | STY zp_fp_temp_1 ; &44, | ||||||||||
| BF15 | STX zp_fp_temp_4 ; &47, | ||||||||||
| BF17 | STY zp_dp_flag ; &48 | ||||||||||
| BF19 | STA zp_fwb_m4 ; Load address low = PAGE | ||||||||||
| BF1B | TAY ; into Y too | ||||||||||
| BF1C | LDX #&37 ; Point at the OSFILE block (&37) | ||||||||||
| BF1E | JSR osfile ; Save the file | ||||||||||
| BF21 | JMP statement_loop ; next statement | ||||||||||
LOADLoad a BASIC program without running it. LOAD string.
|
|||||||||||
| BF24 | .stmt_load | ||||||||||
| JSR load_program ; Load the named program | |||||||||||
| BF27 | JMP clear_then_immediate ; Back to the immediate loop | ||||||||||
CHAINLoad a BASIC program and run it. CHAIN string.
|
|||||||||||
| BF2A | .stmt_chain | ||||||||||
| JSR load_program ; Load the named program | |||||||||||
| BF2D | JMP run_clear ; then RUN it | ||||||||||
PTR#=Set the sequential pointer of an open file. PTR#channel = position.
|
|||||||||||
| BF30 | .stmt_ptr | ||||||||||
| JSR sync_ptrb_from_ptra ; Evaluate the #handle | |||||||||||
| BF33 | PHA ; save it | ||||||||||
| BF34 | JSR eval_after_eq ; Expect "=" and evaluate | ||||||||||
| BF37 | JSR coerce_var_to_integer ; coerce to integer | ||||||||||
| BF3A | PLA ; Recover the handle | ||||||||||
| BF3B | TAY ; Y = the handle | ||||||||||
| BF3C | LDX #&2a ; Point at the value | ||||||||||
| BF3E | LDA #1 ; Write the file pointer | ||||||||||
| BF40 | JSR osargs ; Write sequential file pointer from zero page address X (A=1) | ||||||||||
| BF43 | JMP statement_loop ; next statement | ||||||||||
EXTLength (extent) of an open file. EXT#channel.
|
|||||||||||||||
| BF46 | .fn_ext | ||||||||||||||
| SEC ; Carry set selects EXT (otherwise PTR) | |||||||||||||||
| fall through ↓ | |||||||||||||||
=PTRRead the sequential pointer of an open file. PTR#channel.
|
|||||||||||||||
| BF47 | .fn_ptr | ||||||||||||||
| LDA #0 ; Build the OSARGS sub-function from the carry... | |||||||||||||||
| BF49 | ROL ; ...0 = PTR, non-zero = EXT | ||||||||||||||
| BF4A | ROL ; (BBC: A becomes 0 or 2) | ||||||||||||||
| BF4B | PHA ; Save the function code | ||||||||||||||
| BF4C | JSR eval_channel ; Evaluate the #handle, point at IWA | ||||||||||||||
| BF4F | LDX #&2a ; X -> IWA for the result | ||||||||||||||
| BF51 | PLA ; Restore the function code | ||||||||||||||
| BF52 | JSR osargs ; OSARGS: read PTR or EXT into IWA | ||||||||||||||
| BF55 | LDA #&40 ; Integer result | ||||||||||||||
| BF57 | RTS ; Return PTR/EXT | ||||||||||||||
BPUTWrite a byte to an open file. BPUT#channel, value.
|
|||||||||||
| BF58 | .stmt_bput | ||||||||||
| JSR sync_ptrb_from_ptra ; Evaluate the #handle | |||||||||||
| BF5B | PHA ; save it | ||||||||||
| BF5C | JSR skip_spaces_expect_comma ; require a comma | ||||||||||
| BF5F | JSR eval_rhs ; evaluate the value | ||||||||||
| BF62 | JSR coerce_var_to_integer ; coerce to an integer | ||||||||||
| BF65 | PLA ; recover the handle | ||||||||||
| BF66 | TAY ; Y = handle | ||||||||||
| BF67 | LDA zp_iwa ; A = the byte to write | ||||||||||
| BF69 | JSR osbput ; OSBPUT: write the byte | ||||||||||
| BF6C | JMP statement_loop ; Back to execution | ||||||||||
BGETRead a byte from an open file. BGET#channel.
|
|||||||||||||||
| BF6F | .fn_bget | ||||||||||||||
| JSR eval_channel ; Evaluate the #handle | |||||||||||||||
| BF72 | JSR osbget ; OSBGET: read a byte from the channel | ||||||||||||||
| BF75 | JMP int_result_a ; Return the byte as an integer | ||||||||||||||
OPENINOpen a file for input, returning its channel (0 if not found). OPENIN string.
|
|||||||||||||||
| BF78 | .fn_openin | ||||||||||||||
| LDA #&40 ; OSFIND &40: open an existing file for input | |||||||||||||||
| BF7A | BNE openup_action ; do the open | ||||||||||||||
| fall through ↓ | |||||||||||||||
OPENOUTCreate a file for output, returning its channel. OPENOUT string.
|
|||||||||||||||
| BF7C | .fn_openout | ||||||||||||||
| LDA #&80 ; OSFIND &80: create a file for output | |||||||||||||||
| BF7E | BNE openup_action ; do the open | ||||||||||||||
| fall through ↓ | |||||||||||||||
OPENUPOpen a file for update (read and write), returning its channel. OPENUP string.
|
|||||||||||||||
| BF80 | .fn_openup | ||||||||||||||
| LDA #&c0 ; OPENUP action &C0 | |||||||||||||||
| BF82 | .openup_action←2← BF7A BNE← BF7E BNE | ||||||||||||||
| PHA ; Save the action | |||||||||||||||
| BF83 | JSR eval_factor ; Evaluate the filename | ||||||||||||||
| BF86 | BNE openup_type_error ; not a string: error | ||||||||||||||
| BF88 | JSR terminate_strbuf ; CR-terminate it | ||||||||||||||
| BF8B | LDX #0 ; Point at the string buffer | ||||||||||||||
| BF8D | LDY #6 ; high byte = &06 (&0600) | ||||||||||||||
| BF8F | PLA ; recover the action | ||||||||||||||
| BF90 | JSR osfind ; Open the file | ||||||||||||||
| BF93 | JMP int_result_a ; return the handle | ||||||||||||||
| BF96 | .openup_type_error←1← BF86 BNE | ||||||||||||||
| JMP err_type_mismatch ; Type mismatch error | |||||||||||||||
CLOSEClose an open file, or all files with #0. CLOSE#channel.
|
|||||||||||
| BF99 | .stmt_close | ||||||||||
| JSR sync_ptrb_from_ptra ; Evaluate the #handle | |||||||||||
| BF9C | JSR sync_text_ptr ; Check for end of statement | ||||||||||
| BF9F | LDY zp_iwa ; Y = the handle | ||||||||||
| BFA1 | LDA #osfind_close ; OSFIND &00: close the file | ||||||||||
| BFA3 | JSR osfind ; osfind: close one or all files | ||||||||||
| BFA6 | JMP statement_loop ; Back to execution | ||||||||||
Copy PtrA to PtrB, then evaluate a #channelCopy the three fields of the primary text pointer PtrA (offset &0A, low &0B, high &0C) into the secondary pointer PtrB (offset &1B, low &19, high &1A), then fall straight through into eval_channel. In effect: rewind PtrB to PtrA's position and parse the '#channel' file handle that follows.
|
|||||||||||
| BFA9 | .sync_ptrb_from_ptra←5← 8D2D JSR← B9D1 JSR← BF30 JSR← BF58 JSR← BF99 JSR | ||||||||||
| LDA zp_text_ptr_off ; Set PtrB = PtrA: offset | |||||||||||
| BFAB | STA zp_text_ptr2_off ; (store) | ||||||||||
| BFAD | LDA zp_text_ptr ; low | ||||||||||
| BFAF | STA zp_text_ptr2 ; (store) | ||||||||||
| BFB1 | LDA zp_text_ptr_1 ; high | ||||||||||
| BFB3 | STA zp_text_ptr2_1 ; (store) | ||||||||||
| fall through ↓ | |||||||||||
Evaluate a #channel argumentRequire "#" at PtrB then evaluate the file handle as an integer, leaving it in IWA. Raises Missing # if the "#" is absent. The shared entry point for the channel-based file words. BBC BASIC's file vocabulary maps onto five MOS calls; the handle is passed in Y (except OSFILE), and OSARGS reads/writes its 4-byte value through X -> IWA (&2A):
OSFIND returns the new handle in A (0 = open failed); CLOSE #0 closes
every open file. OSFILE uses the control block at &37 (see
|
|||||||||||||||||||||||||||||||||||||||||||||||||
| BFB5 | .eval_channel←3← ACB8 JSR← BF4C JSR← BF6F JSR | ||||||||||||||||||||||||||||||||||||||||||||||||
| JSR skip_spaces_ptr2 ; Skip spaces | |||||||||||||||||||||||||||||||||||||||||||||||||
| BFB8 | CMP #'#' ; Require "#" | ||||||||||||||||||||||||||||||||||||||||||||||||
| BFBA | BNE missing_hash ; missing: error | ||||||||||||||||||||||||||||||||||||||||||||||||
| BFBC | JSR eval_factor_integer ; Evaluate the handle as an integer | ||||||||||||||||||||||||||||||||||||||||||||||||
| BFBF | LDY zp_iwa ; Y = the handle | ||||||||||||||||||||||||||||||||||||||||||||||||
| BFC1 | TYA ; A = the handle too | ||||||||||||||||||||||||||||||||||||||||||||||||
| BFC2 | RTS ; Return | ||||||||||||||||||||||||||||||||||||||||||||||||
| BFC3 | .missing_hash←1← BFBA BNE | ||||||||||||||||||||||||||||||||||||||||||||||||
| BRK ; BRK error block ("Missing #") | |||||||||||||||||||||||||||||||||||||||||||||||||
| BFC4 | EQUS "-Missing #" | ||||||||||||||||||||||||||||||||||||||||||||||||
| BFCE | EQUB &00 | ||||||||||||||||||||||||||||||||||||||||||||||||
Print an inline string following the callPrint the string embedded in the code immediately after the JSR to this routine. It pulls the return address into zp_general as a text pointer, then walks forward with general_next_byte printing each byte through osasci, stopping at the first byte with bit 7 set. It resumes execution at that terminating byte via jmp (zp_general) - so the terminator doubles as the opcode of the continuation.
|
||||
| BFCF | .print_inline_string←2← 9080 JSR← BE9E JSR | |||
| PLA ; Pull the return address: it points at the string | ||||
| BFD0 | STA zp_general ; (low) | |||
| BFD2 | PLA ; (pull high) | |||
| BFD3 | STA zp_general_1 ; (high) | |||
| BFD5 | LDY #0 ; Start before the first character | |||
| BFD7 | BEQ print_msg_next ; jump in to fetch it | |||
| BFD9 | .print_msg_loop←1← BFDF BPL | |||
| JSR osasci ; Print the character | ||||
| BFDC | .print_msg_next←1← BFD7 BEQ | |||
| JSR general_next_byte ; Advance and fetch the next character | ||||
| BFDF | BPL print_msg_loop ; Loop while bit 7 is clear | |||
| BFE1 | JMP (zp_general) ; Resume at the terminator (the next instruction) | |||
REPORTPrint the message for the last error. REPORT.
|
|||||||||||
| BFE4 | .stmt_report | ||||||||||
| JSR check_end_of_statement ; Check the statement ends | |||||||||||
| BFE7 | JSR emit_newline ; Newline | ||||||||||
| BFEA | LDY #1 ; From offset 1 | ||||||||||
| BFEC | .report_loop←1← BFF4 BNE | ||||||||||
| LDA (zp_error_ptr),y ; Error message byte | |||||||||||
| BFEE | BEQ report_done ; terminator: done | ||||||||||
| BFF0 | JSR print_token ; print it | ||||||||||
| BFF3 | INY ; next | ||||||||||
| BFF4 | BNE report_loop ; loop | ||||||||||
| BFF6 | .report_done←1← BFEE BEQ | ||||||||||
| JMP statement_loop ; next statement | |||||||||||
| BFF9 | EQUB &00 | ||||||||||
| BFFA | EQUS "Roger" | ||||||||||
| BFFF | EQUB &00 | ||||||||||
