zx81dual.html (386998B)
1 ; =========================================================== 2 ; An Assembly Listing of the Operating System of the ZX81 ROM 3 ; =========================================================== 4 ------------------------------------------------------------------------ 5 6 ; Last updated: 13-DEC-2004 7 ; 2011 Updated to remove -, +, /, *, &, 8 ; characters from labels (which confuse assemblers) 9 ; 10 ; 2011 Updated for conditional assembly of ORIGINAL or "Shoulders of Giants" ROM 11 ; 12 ; 2014-08-01 Updated to add CHARS_PER_LINE_WINDOW which is normally 32. 13 ; 14 ; The ideal pixel rates for square pixels on a PAL system are 15 ; 14.75 MHz (interlaced) and 16 ; 7.375 MHz (non-interlaced, which the ZX80/ZX81 are). 17 ; These are not commonly available but fortunately one can buy 18 ; baud-rate generator frequencies such as 19 ; 14.7456 and 7.3728 MHz that are only 0.03% low 20 ; which is more than close enough. 21 ; 22 ; ZX video normally has 6.5 MHz pixel rate, 23 ; so 32 characters take 256 pixels in 39.4 microseconds. 24 ; A 7.3728 MHz clock and 40 characters produces 25 ; 320 pixels in 43.4 microseconds. 26 ; 27 ; ZX80 video generation is software defined so it is 28 ; easy to get square pixels simply by subtracting 8 from the bytes 29 ; at hex addresses 287, 2AA and 2B8. 30 ; The video will appear to the left of the screen but 31 ; the characters will be square and a diagonal graphic line 32 ; will be at 45 degrees. 33 ; 34 ; ZX81 video generation in fast mode exactly the same as the ZX80. 35 ; 36 ; ZX81 video generation in slow mode is problematic, in that 37 ; the NMI generator expects a 3.25 MHz CPU clock 38 ; (3.25MHz / 208 = 15.625 kHz = 64 microsecond line period) 39 ; It is inside the ULA where it cannot be modified. 40 ; 41 ; Simply fitting a 7.3728 MHz crystal would reduce the line period to 42 ; 57.3 microseconds. Slow mode would require the CPU clock to be 43 ; divided by 236. 44 ; 45 ; Square pixels on NTSC requires 11+3/11 = 11.272... MHz (interlaced) 46 ; or 5.63.. non-interlaced which is slower than the original 6.5 MHz. 47 ; The NTSC line period is still 64 microseconds, so 256 pixels 48 ; stretch over 45 microseconds, and 320 pixels over 56 microseconds. 49 ; Thus it is possible to get square pixels on an NTSC display, 50 ; it is not possible to get 40 column text as well. 51 ; That would require the PAL clock, but pixels would not be square. 52 ; 53 ; The ZX printer is fixed in hardware. 54 ; It will not work in 40-column mode. 55 ; 56 ; 57 ; 58 ; PIXEL_CLOCK equ 7372500 59 ; 60 ; on-line assembler complains about the line above 61 ; 62 ; CHARS_PER_LINE_WINDOW always 32 for 6.5 MHz pixel rate 63 ; always 40 for 7.375 MHz PAL square pixel rate 64 ; 65 CHARS_PER_LINE_WINDOW equ 40 ; 32 originally 66 ; 67 ; CHARS_PER_LINE always 32 for 6.5 MHz pixel rate 68 ; but 32 or 40 if using PAL square pixel rate 69 ; 70 CHARS_HORIZONTAL equ 40 ; 32 originally 71 CHARS_VERTICAL equ 24 72 ; 73 ; 2014-08-01 74 ; Largely working but some bugs remain. 75 ; Working: 76 ; You can type text and it takes 40 characters before new line. 77 ; 40 characters are nicely centred in the screen. 78 ; PLOT X,Y accepts X from 0 to 79. 79 ; Faulty: 80 ; System crashing in an authentic ZX81 fashion, 81 ; I don't know if this is due to software bugs 82 ; or socket joint disturbance from key presses. 83 ; 84 ; 85 ; 2018-01-09 add org 86 ; Assembles using on-line assembler "zasm" at: 87 ; 88 ; http://k1.spdns.de/cgi-bin/zasm.cgi 89 ; 90 org 0 91 92 FALSE equ 0 93 94 ORIGINAL equ 0 95 NOT_BODGED equ 1 96 97 ; 2018-02-09 CHARS_HORIZONTAL placed in SCROLL routine. 98 ; Thanks to Adam Klotblixt for testing code and spotting this bug. 99 ; Also added to some G007 routines. 100 ; 101 102 ------------------------------------------------------------------------ 103 104 ; 105 ; Work in progress. 106 ; This file will cross-assemble an original version of the "Improved" 107 ; ZX81 ROM. 108 ; The file can be modified to change the behaviour of the ROM 109 ; when used in emulators although there is no spare space available. 110 ; 111 ; The documentation is incomplete and if you can find a copy 112 ; of "The Complete Spectrum ROM Disassembly" then many routines 113 ; such as POINTERS and most of the mathematical routines are 114 ; similar and often identical. 115 ; 116 ; I've used the labels from the above book in this file and also 117 ; some from the more elusive Complete ZX81 ROM Disassembly 118 ; by the same publishers, Melbourne House. 119 120 #if 0 121 ; zasm does not understand these: 122 #define DEFB .BYTE ; TASM cross-assembler definitions 123 #define DEFW .WORD 124 #define EQU .EQU 125 #endif 126 127 ; define stuff sensibly: 128 ; 129 ; I/O locations: 130 ; 131 IO_PORT_TAPE equ $FF ; write 132 IO_PORT_SCREEN equ $FF ; write 133 134 IO_PORT_KEYBOARD_RD equ $FE ; A0 low 135 IO_PORT_NMI_GEN_ON equ $FE ; A0 low 136 IO_PORT_NMI_GEN_OFF equ $FD ; A1 low 137 IO_PORT_PRINTER equ $FB ; A2 low 138 ------------------------------------------------------------------------ 139 140 ; 141 ; System variables: 142 ; 143 RAMBASE equ $4000 144 ERR_NR equ $4000 ; The report code. Incremented before printing. 145 FLAGS equ $4001 ; Bit 0: Suppression of leading space. 146 ; Bit 1: Control Flag for the printer. 147 ; Bit 2: Selects K or F mode; or, F or G 148 ; Bit 6: FP no. or string parameters. 149 ; Bit 7: Reset during syntax checking." 150 ERR_SP equ $4002 ; Pointer to the GOSUB stack. 151 RAMTOP equ $4004 ; The top of available RAM, or as specified. 152 MODE equ $4006 ; Holds the code for K or F 153 PPC equ $4007 ; Line number of the current statement. 154 PPC_hi equ PPC+1 155 VERSN equ $4009 ; Marks the start of the RAM that is saved. 156 E_PPC equ $400A ; The BASIC line with the cursor 157 D_FILE equ $400C ; Pointer to Display file 158 DF_CC equ $400E ; Address for PRINT AT position 159 VARS equ $4010 ; Pointer to variable area 160 DEST equ $4012 ; Address of current variable in program area 161 E_LINE equ $4014 ; Pointer to workspace 162 E_LINE_hi equ E_LINE+1 163 CH_ADD equ $4016 ; Pointer for scanning a line, in program or workspace 164 X_PTR equ $4018 ; Pointer to syntax error. 165 X_PTR_lo equ X_PTR 166 X_PTR_hi equ X_PTR+1 167 STKBOT equ $401A ; Pointer to calculator stack bottom. 168 STKEND equ $401C ; Pointer to calculator stack end. 169 BERG equ $401E ; Used for many different counting purposes 170 MEM equ $401F ; Pointer to base of table of fp. nos, either in calc. stack or variable area. 171 ; ; Unused by ZX BASIC. Or FLAG Y for G007 172 DF_SZ equ $4022 ; Number of lines in the lower screen 173 S_TOP equ $4023 ; Current line number of automatic listing 174 LAST_K equ $4025 ; Last Key pressed 175 DEBOUNCE_VAR equ $4027 ; The de-bounce status 176 MARGIN equ $4028 ; Adjusts for differing TV standards 177 NXTLIN equ $4029 ; Next BASIC line to be interpreted 178 OLDPPC equ $402B ; Last line number, in case needed. 179 FLAGX equ $402D ; Bit 0: Reset indicates an arrayed variable 180 ; Bit 1: Reset indicates a given variable exists 181 ; Bit 5: Set during INPUT mode 182 ; Bit 7: Set when INPUT is to be numeric 183 STRLEN equ $402E ; Length of a string, or a BASIC line 184 STRLEN_lo equ STRLEN ; 185 T_ADDR equ $4030 ; Pointer to parameter table. & distinguishes between PLOT & UNPLOT 186 SEED equ $4032 ; For RANDOM function 187 FRAMES equ $4034 ; Frame counter 188 FRAMES_hi equ FRAMES+1 ; 189 COORDS equ $4036 ; X & Y for PLOT 190 COORDS_x equ COORDS ; 191 PR_CC equ $4038 ; Print buffer counter 192 S_POSN equ $4039 ; Line & Column for PRINT AT 193 S_POSN_x equ $4039 ; 194 S_POSN_y equ $403A ; 195 CDFLAG equ $403B ; Bit 6 = the true fast/slow flag 196 ; Bit 7 = copy of the fast/slow flag. RESET when FAST needed 197 PRBUFF equ $403C ; Printer buffer 198 PRBUFF_END equ $405C ; 199 MEM_0_1st equ $405D ; room for 5 floating point numbers (meme_0 to mem_ 5???) 200 ; $407B ; unused. Or RESTART to G007 201 ; $407D ; The BASIC program starts here 202 ; equ $40 203 ; equ $40 204 ; equ $40 205 ; First byte after system variables: 206 USER_RAM equ $407D 207 MAX_RAM equ $7FFF 208 ------------------------------------------------------------------------ 209 210 ;=============================== 211 ; ZX81 constants: 212 ;=============================== 213 ; ZX characters (not the same as ASCII) 214 ;------------------------------- 215 ZX_SPACE equ $00 216 ; ZX_graphic equ $01 217 ; ZX_graphic equ $02 218 ; ZX_graphic equ $03 219 ; ZX_graphic equ $04 220 ; ZX_graphic equ $05 221 ; ZX_graphic equ $06 222 ; ZX_graphic equ $07 223 ; ZX_graphic equ $08 224 ; ZX_graphic equ $09 225 ; ZX_graphic equ $0A 226 ZX_QUOTE equ $0B 227 ZX_POUND equ $0C 228 ZX_DOLLAR equ $0D 229 ZX_COLON equ $0E 230 ZX_QUERY equ $0F 231 ZX_BRACKET_LEFT equ $10 232 ZX_BRACKET_RIGHT equ $11 233 ZX_GREATER_THAN equ $12 234 ZX_LESS_THAN equ $13 235 ZX_EQUAL equ $14 236 ZX_PLUS equ $15 237 ZX_MINUS equ $16 238 ZX_STAR equ $17 239 ZX_SLASH equ $18 240 ZX_SEMICOLON equ $19 241 ZX_COMMA equ $1A 242 ZX_PERIOD equ $1B 243 ZX_0 equ $1C 244 ZX_1 equ $1D 245 ZX_2 equ $1E 246 ZX_3 equ $1F 247 ZX_4 equ $20 248 ZX_5 equ $21 249 ZX_6 equ $22 250 ZX_7 equ $23 251 ZX_8 equ $24 252 ZX_9 equ $25 253 ZX_A equ $26 254 ZX_B equ $27 255 ZX_C equ $28 256 ZX_D equ $29 257 ZX_E equ $2A 258 ZX_F equ $2B 259 ZX_G equ $2C 260 ZX_H equ $2D 261 ZX_I equ $2E 262 ZX_J equ $2F 263 ZX_K equ $30 264 ZX_L equ $31 265 ZX_M equ $32 266 ZX_N equ $33 267 ZX_O equ $34 268 ZX_P equ $35 269 ZX_Q equ $36 270 ZX_R equ $37 271 ZX_S equ $38 272 ZX_T equ $39 273 ZX_U equ $3A 274 ZX_V equ $3B 275 ZX_W equ $3C 276 ZX_X equ $3D 277 ZX_Y equ $3E 278 ZX_Z equ $3F 279 ZX_RND equ $40 280 ZX_INKEY_STR equ $41 281 ZX_PI equ $42 282 ; 283 ; $43 to $6F not used 284 ; 285 ZX_cursor_up equ $70 286 ZX_cursor_down equ $71 287 ZX_cursor_left equ $72 288 ZX_cursor_right equ $73 289 290 ZX_GRAPHICS equ $74 291 ZX_EDIT equ $75 292 ZX_NEWLINE equ $76 293 ZX_RUBOUT equ $77 294 ZX_KL equ $78 295 ZX_FUNCTION equ $79 296 ; 297 ; $7A to $7F not used 298 ; 299 ZX_CURSOR equ $7F 300 ; 301 ; $80 to $BF are inverses of $00 to $3F 302 ; 303 ; ZX_graphic equ $80 ; inverse space 304 ; ZX_graphic equ $81 305 ; ZX_graphic equ $82 306 ; ZX_graphic equ $83 307 ; ZX_graphic equ $84 308 ; ZX_graphic equ $85 309 ; ZX_graphic equ $86 310 ; ZX_graphic equ $87 311 ; ZX_graphic equ $88 312 ; ZX_graphic equ $89 313 ; ZX_graphic equ $8A 314 ZX_INV_QUOTE equ $8B 315 ZX_INV_POUND equ $8C 316 ZX_INV_DOLLAR equ $8D 317 ZX_INV_COLON equ $8E 318 ZX_INV_QUERY equ $8F 319 ZX_INV_BRACKET_RIGHT equ $90 320 ZX_INV_BRACKET_LEFT equ $91 321 ZX_INV_GT equ $92 322 323 ZX_INV_PLUS equ $95 324 ZX_INV_MINUS equ $96 325 326 ZX_INV_K equ $B0 327 ZX_INV_S equ $B8 328 329 ZX_DOUBLE_QUOTE equ $C0 330 ZX_AT equ $C1 331 ZX_TAB equ $C2 332 ; not used equ $C3 333 ZX_CODE equ $C4 334 ZX_VAL equ $C5 335 ZX_LEN equ $C6 336 ZX_SIN equ $C7 337 ZX_COS equ $C8 338 ZX_TAN equ $C9 339 ZX_ASN equ $CA 340 ZX_ACS equ $CB 341 ZX_ATN equ $CC 342 ZX_LN equ $CD 343 ZX_EXP equ $CE 344 ZX_INT equ $CF 345 346 ZX_SQR equ $D0 347 ZX_SGN equ $D1 348 ZX_ABS equ $D2 349 ZX_PEEK equ $D3 350 ZX_USR equ $D4 351 ZX_STR_STR equ $D5 ; STR$ 352 ZX_CHR_STR equ $D6 ; CHR$ 353 ZX_NOT equ $D7 354 ZX_POWER equ $D8 355 ZX_OR equ $D9 356 ZX_AND equ $DA 357 ZX_LESS_OR_EQUAL equ $DB 358 ZX_GREATER_OR_EQUAL equ $DC 359 ZX_NOT_EQUAL equ $DD 360 ZX_THEN equ $DE 361 ZX_TO equ $DF 362 363 ZX_STEP equ $E0 364 ZX_LPRINT equ $E1 365 ZX_LLIST equ $E2 366 ZX_STOP equ $E3 367 ZX_SLOW equ $E4 368 ZX_FAST equ $E5 369 ZX_NEW equ $E6 370 ZX_SCROLL equ $E7 371 ZX_CONT equ $E8 372 ZX_DIM equ $E9 373 ZX_REM equ $EA 374 ZX_FOR equ $EB 375 ZX_GOTO equ $EC 376 ZX_GOSUB equ $ED 377 ZX_INPUT equ $EE 378 ZX_LOAD equ $EF 379 380 ZX_LIST equ $F0 381 ZX_LET equ $F1 382 ZX_PAUSE equ $F2 383 ZX_NEXT equ $F3 384 ZX_POKE equ $F4 385 ZX_PRINT equ $F5 386 ZX_PLOT equ $F6 387 ZX_RUN equ $F7 388 ZX_SAVE equ $F8 389 ZX_RAND equ $F9 390 ZX_IF equ $FA 391 ZX_CLS equ $FB 392 ZX_UNPLOT equ $FC 393 ZX_CLEAR equ $FD 394 ZX_RETURN equ $FE 395 ZX_COPY equ $FF 396 ------------------------------------------------------------------------ 397 398 399 ; 400 _CLASS_00 equ 0 401 _CLASS_01 equ 1 402 _CLASS_02 equ 2 403 _CLASS_03 equ 3 404 _CLASS_04 equ 4 405 _CLASS_05 equ 5 406 _CLASS_06 equ 6 407 ------------------------------------------------------------------------ 408 409 410 411 ; These values taken from BASIC manual 412 ; 413 ; 414 ERROR_CODE_SUCCESS equ 0 415 ERROR_CODE_CONTROL_VARIABLE equ 1 416 ERROR_CODE_UNDEFINED_VARIABLE equ 2 417 ERROR_CODE_SUBSCRIPT_OUT_OF_RANGE equ 3 418 ERROR_CODE_NOT_ENOUGH_MEMORY equ 4 419 ERROR_CODE_NO_ROOM_ON_SCREEN equ 5 420 ERROR_CODE_ARITHMETIC_OVERFLOW equ 6 421 ERROR_CODE_RETURN_WITHOUT_GOSUB equ 7 422 ERROR_CODE_INPUT_AS_A_COMMAND equ 8 423 ERROR_CODE_STOP equ 9 424 ERROR_CODE_INVALID_ARGUMENT equ 10 425 426 ERROR_CODE_INTEGER_OUT_OF_RANGE equ 11 427 ERROR_CODE_VAL_STRING_INVALID equ 12 428 ERROR_CODE_BREAK equ 13 429 430 ERROR_CODE_EMPTY_PROGRAM_NAME equ 15 431 ------------------------------------------------------------------------ 432 433 ; 434 ; codes for Forth-like calculator 435 ; 436 __jump_true equ $00 437 __exchange equ $01 438 __delete equ $02 439 __subtract equ $03 440 __multiply equ $04 441 __division equ $05 442 __to_power equ $06 443 __or equ $07 444 __boolean_num_and_num equ $08 445 __num_l_eql equ $09 446 __num_gr_eql equ $0A 447 __nums_neql equ $0B 448 __num_grtr equ $0C 449 __num_less equ $0D 450 __nums_eql equ $0E 451 __addition equ $0F 452 __strs_and_num equ $10 453 __str_l_eql equ $11 454 __str_gr_eql equ $12 455 __strs_neql equ $13 456 __str_grtr equ $14 457 __str_less equ $15 458 __strs_eql equ $16 459 __strs_add equ $17 460 __negate equ $18 461 __code equ $19 462 __val equ $1A 463 __len equ $1B 464 __sin equ $1C 465 __cos equ $1D 466 __tan equ $1E 467 __asn equ $1F 468 __acs equ $20 469 __atn equ $21 470 __ln equ $22 471 __exp equ $23 472 __int equ $24 473 __sqr equ $25 474 __sgn equ $26 475 __abs equ $27 476 __peek equ $28 477 __usr_num equ $29 478 __str_dollar equ $2A 479 __chr_dollar equ $2B 480 __not equ $2C 481 __duplicate equ $2D 482 __n_mod_m equ $2E 483 __jump equ $2F 484 __stk_data equ $30 485 __dec_jr_nz equ $31 486 __less_0 equ $32 487 __greater_0 equ $33 488 __end_calc equ $34 489 __get_argt equ $35 490 __truncate equ $36 491 __fp_calc_2 equ $37 492 __e_to_fp equ $38 493 494 ; 495 ; __series_xx equ $39 : $80__$9F. 496 ; tells the stack machine to push 497 ; 0 to 31 floating-point values on the stack. 498 ; 499 __series_06 equ $86 500 __series_08 equ $88 501 __series_0C equ $8C 502 ; __stk_const_xx equ $3A : $A0__$BF. 503 ; __st_mem_xx equ $3B : $C0__$DF. 504 ; __get_mem_xx equ $3C : $E0__$FF. 505 506 __st_mem_0 equ $C0 507 __st_mem_1 equ $C1 508 __st_mem_2 equ $C2 509 __st_mem_3 equ $C3 510 __st_mem_4 equ $C4 511 __st_mem_5 equ $C5 512 __st_mem_6 equ $C6 513 __st_mem_7 equ $C7 514 515 516 __get_mem_0 equ $E0 517 __get_mem_1 equ $E1 518 __get_mem_2 equ $E2 519 __get_mem_3 equ $E3 520 __get_mem_4 equ $E4 521 522 523 __stk_zero equ $A0 524 __stk_one equ $A1 525 __stk_half equ $A2 526 __stk_half_pi equ $A3 527 __stk_ten equ $A4 528 ------------------------------------------------------------------------ 529 530 ;***************************************** 531 ;** Part 1. RESTART ROUTINES AND TABLES ** 532 ;***************************************** 533 534 ------------------------------------------------------------------------ 535 536 ; THE *'START'* 537 ------------------------------------------------------------------------ 538 539 ; All Z80 chips start at location zero. 540 ; At start-up the Interrupt Mode is 0, ZX computers use Interrupt Mode 1. 541 ; Interrupts are disabled . 542 543 mark_0000: 544 *START:* 545 OUT (IO_PORT_NMI_GEN_OFF),A ; Turn off the NMI generator if this ROM is 546 ; running in ZX81 hardware. This does nothing 547 ; if this ROM is running within an upgraded 548 ; ZX80. 549 LD BC,MAX_RAM ; Set BC to the top of possible RAM. 550 ; The higher unpopulated addresses are used for 551 ; video generation. 552 JP RAM_CHECK <#RAM_CHECK> ; Jump forward to RAM_CHECK. 553 554 ------------------------------------------------------------------------ 555 556 ; THE *'ERROR'* RESTART 557 ------------------------------------------------------------------------ 558 559 ; The error restart deals immediately with an error. 560 ; ZX computers execute the same code in runtime as when checking syntax. 561 ; If the error occurred while running a program 562 ; then a brief report is produced. 563 ; If the error occurred while entering a BASIC line or in input etc., 564 ; then the error marker indicates the exact point at which the error lies. 565 566 mark_0008: 567 *ERROR_1:* 568 LD HL,(CH_ADD) ; fetch character address from CH_ADD. 569 LD (X_PTR),HL ; and set the error pointer X_PTR. 570 JR ERROR_2 <#ERROR_2> ; forward to continue at ERROR_2. 571 572 ------------------------------------------------------------------------ 573 574 ; THE *'PRINT A CHARACTER'* RESTART 575 ------------------------------------------------------------------------ 576 577 ; This restart prints the character in the accumulator using the alternate 578 ; register set so there is no requirement to save the main registers. 579 ; There is sufficient room available to separate a space (zero) from other 580 ; characters as leading spaces need not be considered with a space. 581 582 mark_0010: 583 *PRINT_A:* 584 AND A ; test for zero - space. 585 JP NZ,PRINT_CH <#PRINT_CH> ; jump forward if not to PRINT_CH. 586 587 JP PRINT_SP <#PRINT_SP> ; jump forward to PRINT_SP. 588 589 ; ___ 590 #if ORIGINAL 591 DEFB $FF ; unused location. 592 #else 593 DEFB $01 ;+ unused location. Version. PRINT PEEK 23 594 #endif 595 596 ------------------------------------------------------------------------ 597 598 ; THE *'COLLECT A CHARACTER'* RESTART 599 ------------------------------------------------------------------------ 600 601 ; The character addressed by the system variable CH_ADD is fetched and if it 602 ; is a non-space, non-cursor character it is returned else CH_ADD is 603 ; incremented and the new addressed character tested until it is not a space. 604 605 mark_0018: 606 *GET_CHAR:* 607 LD HL,(CH_ADD) ; set HL to character address CH_ADD. 608 LD A,(HL) ; fetch addressed character to A. 609 610 *TEST_SP:* 611 AND A ; test for space. 612 RET NZ ; return if not a space 613 614 NOP ; else trickle through 615 NOP ; to the next routine. 616 617 ------------------------------------------------------------------------ 618 619 ; THE *'COLLECT NEXT CHARACTER'* RESTART 620 ------------------------------------------------------------------------ 621 622 ; The character address is incremented and the new addressed character is 623 ; returned if not a space, or cursor, else the process is repeated. 624 625 mark_0020: 626 *NEXT_CHAR:* 627 CALL CH_ADD_PLUS_1 <#CH_ADD_PLUS_1> ; gets next immediate 628 ; character. 629 JR TEST_SP <#TEST_SP> ; back 630 ; ___ 631 632 DEFB $FF, $FF, $FF ; unused locations. 633 634 ------------------------------------------------------------------------ 635 636 ; THE *'FLOATING POINT CALCULATOR'* RESTART 637 ------------------------------------------------------------------------ 638 639 ; this restart jumps to the recursive floating-point calculator. 640 ; the ZX81's internal, FORTH-like, stack-based language. 641 ; 642 ; In the five remaining bytes there is, appropriately, enough room for the 643 ; end-calc literal - the instruction which exits the calculator. 644 645 mark_0028: 646 *FP_CALC:* 647 #if ORIGINAL 648 JP CALCULATE <#CALCULATE> ; jump immediately to the CALCULATE routine. 649 #else 650 651 JP CALCULATE <#CALCULATE> ;+ jump to the NEW calculate routine address. 652 #endif 653 654 mark_002B: 655 *end_calc:* 656 POP AF ; drop the calculator return address RE_ENTRY 657 EXX ; switch to the other set. 658 659 EX (SP),HL ; transfer H'L' to machine stack for the 660 ; return address. 661 ; when exiting recursion then the previous 662 ; pointer is transferred to H'L'. 663 664 EXX ; back to main set. 665 RET ; return. 666 667 668 ------------------------------------------------------------------------ 669 670 ; THE *'MAKE BC SPACES'* RESTART 671 ------------------------------------------------------------------------ 672 673 ; This restart is used eight times to create, in workspace, the number of 674 ; spaces passed in the BC register. 675 676 mark_0030: 677 *BC_SPACES:* 678 PUSH BC ; push number of spaces on stack. 679 LD HL,(E_LINE) ; fetch edit line location from E_LINE. 680 PUSH HL ; save this value on stack. 681 JP RESERVE <#RESERVE> ; jump forward to continue at RESERVE. 682 683 684 ------------------------------------------------------------------------ 685 686 _START equ $00 687 _ERROR_1 equ $08 688 _PRINT_A equ $10 689 _GET_CHAR equ $18 690 _NEXT_CHAR equ $20 691 _FP_CALC equ $28 692 _BC_SPACES equ $30 693 ------------------------------------------------------------------------ 694 695 ; THE *'INTERRUPT'* RESTART 696 ------------------------------------------------------------------------ 697 698 ; The Mode 1 Interrupt routine is concerned solely with generating the central 699 ; television picture. 700 ; On the ZX81 interrupts are enabled only during the interrupt routine, 701 ; although the interrupt 702 ; 703 ; This Interrupt Service Routine automatically disables interrupts at the 704 ; outset and the last interrupt in a cascade exits before the interrupts are 705 ; enabled. 706 ; 707 ; There is no DI instruction in the ZX81 ROM. 708 ; 709 ; A maskable interrupt is triggered when bit 6 of the Z80's Refresh register 710 ; changes from set to reset. 711 ; 712 ; The Z80 will always be executing a HALT (NEWLINE) when the interrupt occurs. 713 ; A HALT instruction repeatedly executes NOPS but the seven lower bits 714 ; of the Refresh register are incremented each time as they are when any 715 ; simple instruction is executed. (The lower 7 bits are incremented twice for 716 ; a prefixed instruction) 717 ; 718 ; This is controlled by the Sinclair Computer Logic Chip - manufactured from 719 ; a Ferranti Uncommitted Logic Array. 720 ; 721 ; When a Mode 1 Interrupt occurs the Program Counter, which is the address in 722 ; the upper echo display following the NEWLINE/HALT instruction, goes on the 723 ; machine stack. 193 interrupts are required to generate the last part of 724 ; the 56th border line and then the 192 lines of the central TV picture and, 725 ; although each interrupt interrupts the previous one, there are no stack 726 ; problems as the 'return address' is discarded each time. 727 ; 728 ; The scan line counter in C counts down from 8 to 1 within the generation of 729 ; each text line. For the first interrupt in a cascade the initial value of 730 ; C is set to 1 for the last border line. 731 ; Timing is of the utmost importance as the RH border, horizontal retrace 732 ; and LH border are mostly generated in the 58 clock cycles this routine 733 ; takes . 734 735 736 ------------------------------------------------------------------------ 737 738 MARK_0038: 739 *INTERRUPT:* 740 DEC C ; (4) decrement C - the scan line counter. 741 JP NZ,SCAN_LINE <#SCAN_LINE> ; (10/10) JUMP forward if not zero to SCAN_LINE 742 743 POP HL ; (10) point to start of next row in display 744 ; file. 745 746 DEC B ; (4) decrement the row counter. (4) 747 RET Z ; (11/5) return when picture complete to R_IX_1_LAST_NEWLINE 748 ; with interrupts disabled. 749 750 SET 3,C ; (8) Load the scan line counter with eight. 751 ; Note. LD C,$08 is 7 clock cycles which 752 ; is way too fast. 753 754 ; -> 755 756 mark_0041: 757 *WAIT_INT:* 758 ; 759 ; NB $DD is for 32-column display 760 ; 761 LD R,A ; (9) Load R with initial rising value $DD. 762 763 EI ; (4) Enable Interrupts. [ R is now $DE ]. 764 765 JP (HL) ; (4) jump to the echo display file in upper 766 ; memory and execute characters $00 - $3F 767 ; as NOP instructions. The video hardware 768 ; is able to read these characters and, 769 ; with the I register is able to convert 770 ; the character bitmaps in this ROM into a 771 ; line of bytes. Eventually the NEWLINE/HALT 772 ; will be encountered before R reaches $FF. 773 ; It is however the transition from $FF to 774 ; $80 that triggers the next interrupt. 775 ; [ The Refresh register is now $DF ] 776 777 ; ___ 778 779 mark_0045: 780 *SCAN_LINE:* 781 POP DE ; (10) discard the address after NEWLINE as the 782 ; same text line has to be done again 783 ; eight times. 784 785 RET Z ; (5) Harmless Nonsensical Timing. 786 ; (condition never met) 787 788 JR WAIT_INT <#WAIT_INT> ; (12) back to WAIT_INT 789 790 ; Note. that a computer with less than 4K or RAM will have a collapsed 791 ; display file and the above mechanism deals with both types of display. 792 ; 793 ; With a full display, the 32 characters in the line are treated as NOPS 794 ; and the Refresh register rises from $E0 to $FF and, at the next instruction 795 ; - HALT, the interrupt occurs. 796 ; With a collapsed display and an initial NEWLINE/HALT, it is the NOPs 797 ; generated by the HALT that cause the Refresh value to rise from $E0 to $FF, 798 ; triggering an Interrupt on the next transition. 799 ; This works happily for all display lines between these extremes and the 800 ; generation of the 32 character, 1 pixel high, line will always take 128 801 ; clock cycles. 802 803 ------------------------------------------------------------------------ 804 805 ; THE *'INCREMENT CH_ADD'* SUBROUTINE 806 ------------------------------------------------------------------------ 807 808 ; This is the subroutine that increments the character address system variable 809 ; and returns if it is not the cursor character. The ZX81 has an actual 810 ; character at the cursor position rather than a pointer system variable 811 ; as is the case with prior and subsequent ZX computers. 812 813 mark_0049: 814 CH_ADD_PLUS_1: 815 LD HL,(CH_ADD) ; fetch character address to CH_ADD. 816 817 mark_004C: 818 *TEMP_PTR1:* 819 INC HL ; address next immediate location. 820 821 mark_004D: 822 *TEMP_PTR2:* 823 LD (CH_ADD),HL ; update system variable CH_ADD. 824 825 LD A,(HL) ; fetch the character. 826 CP ZX_CURSOR ; compare to cursor character. 827 RET NZ ; return if not the cursor. 828 829 JR TEMP_PTR1 <#TEMP_PTR1> ; back for next character to TEMP_PTR1. 830 831 ------------------------------------------------------------------------ 832 833 ; THE *'ERROR_2'* BRANCH 834 ------------------------------------------------------------------------ 835 836 ; This is a continuation of the error restart. 837 ; If the error occurred in runtime then the error stack pointer will probably 838 ; lead to an error report being printed unless it occurred during input. 839 ; If the error occurred when checking syntax then the error stack pointer 840 ; will be an editing routine and the position of the error will be shown 841 ; when the lower screen is reprinted. 842 843 mark_0056: 844 *ERROR_2:* 845 POP HL ; pop the return address which points to the 846 ; DEFB, error code, after the RST 08. 847 LD L,(HL) ; load L with the error code. HL is not needed 848 ; anymore. 849 850 mark_0058: 851 *ERROR_3:* 852 LD (IY+ERR_NR-RAMBASE),L ; place error code in system variable ERR_NR 853 LD SP,(ERR_SP) ; set the stack pointer from ERR_SP 854 CALL SLOW_FAST <#SLOW_FAST> ; selects slow mode. 855 JP SET_MIN <#SET_MIN> ; exit to address on stack via routine SET_MIN. 856 857 ; ___ 858 859 DEFB $FF ; unused. 860 861 ------------------------------------------------------------------------ 862 863 ; THE *'NON MASKABLE INTERRUPT'* ROUTINE 864 ------------------------------------------------------------------------ 865 866 ; Jim Westwood's technical dodge using Non-Maskable Interrupts solved the 867 ; flicker problem of the ZX80 and gave the ZX81 a multi-tasking SLOW mode 868 ; with a steady display. Note that the AF' register is reserved for this 869 ; function and its interaction with the display routines. When counting 870 ; TV lines, the NMI makes no use of the main registers. 871 ; The circuitry for the NMI generator is contained within the SCL (Sinclair 872 ; Computer Logic) chip. 873 ; ( It takes 32 clock cycles while incrementing towards zero ). 874 875 mark_0066: 876 *NMI:* 877 EX AF,AF' ; (4) switch in the NMI's copy of the 878 ; accumulator. 879 INC A ; (4) increment. 880 JP M,NMI_RET <#NMI_RET> ; (10/10) jump, if minus, to NMI_RET as this is 881 ; part of a test to see if the NMI 882 ; generation is working or an intermediate 883 ; value for the ascending negated blank 884 ; line counter. 885 886 JR Z,NMI_CONT <#NMI_CONT> ; (12) forward to NMI_CONT 887 ; when line count has incremented to zero. 888 889 ; Note. the synchronizing NMI when A increments from zero to one takes this 890 ; 7 clock cycle route making 39 clock cycles in all. 891 892 mark_006D: 893 *NMI_RET:* 894 EX AF,AF' ; (4) switch out the incremented line counter 895 ; or test result $80 896 RET ; (10) return to User application for a while. 897 898 ; ___ 899 900 ; This branch is taken when the 55 (or 31) lines have been drawn. 901 902 mark_006F: 903 *NMI_CONT:* 904 EX AF,AF' ; (4) restore the main accumulator. 905 906 PUSH AF ; (11) * Save Main Registers 907 PUSH BC ; (11) ** 908 PUSH DE ; (11) *** 909 PUSH HL ; (11) **** 910 911 ; the next set-up procedure is only really applicable when the top set of 912 ; blank lines have been generated. 913 914 LD HL,(D_FILE) ; (16) fetch start of Display File from D_FILE 915 ; points to the HALT at beginning. 916 SET 7,H ; (8) point to upper 32K 'echo display file' 917 918 HALT ; (1) HALT synchronizes with NMI. 919 ; Used with special hardware connected to the 920 ; Z80 HALT and WAIT lines to take 1 clock cycle. 921 922 ------------------------------------------------------------------------ 923 924 ; the NMI has been generated - start counting. 925 ; The cathode ray is at the RH side of the TV. 926 ; 927 ; First the NMI servicing, similar to CALL = 17 clock cycles. 928 ; Then the time taken by the NMI for zero-to-one path = 39 cycles 929 ; The HALT above = 01 cycles. 930 ; The two instructions below = 19 cycles. 931 ; The code at R_IX_1 <#R_IX_1> up to and including the CALL = 43 cycles. 932 ; The Called routine at DISPLAY_5 <#DISPLAY_5> = 24 cycles. 933 ; -------------------------------------- --- 934 ; Total Z80 instructions = 143 cycles. 935 ; 936 ; Meanwhile in TV world, 937 ; Horizontal retrace = 15 cycles. 938 ; Left blanking border 8 character positions = 32 cycles 939 ; Generation of 75% scanline from the first NEWLINE = 96 cycles 940 ; --------------------------------------- --- 941 ; = 143 cycles 942 ; 943 ; Since at the time the first JP (HL) is encountered to execute the echo 944 ; display another 8 character positions have to be put out, then the 945 ; Refresh register need to hold $F8. Working back and counteracting 946 ; the fact that every instruction increments the Refresh register then 947 ; the value that is loaded into R needs to be $F5. :-) 948 ; 949 ; 950 OUT (IO_PORT_NMI_GEN_OFF),A ; (11) Stop the NMI generator. 951 952 JP (IX) ; (8) forward to R_IX_1 (after top) or R_IX_2 953 954 ; **************** 955 ; ** KEY TABLES ** 956 ; **************** 957 958 ------------------------------------------------------------------------ 959 960 ; THE *'UNSHIFTED'* CHARACTER CODES 961 ------------------------------------------------------------------------ 962 963 964 mark_007E: 965 *K_UNSHIFT*: 966 DEFB ZX_Z 967 DEFB ZX_X 968 DEFB ZX_C 969 DEFB ZX_V 970 971 DEFB ZX_A 972 DEFB ZX_S 973 DEFB ZX_D 974 DEFB ZX_F 975 DEFB ZX_G 976 977 DEFB ZX_Q 978 DEFB ZX_W 979 DEFB ZX_E 980 DEFB ZX_R 981 DEFB ZX_T 982 983 DEFB ZX_1 984 DEFB ZX_2 985 DEFB ZX_3 986 DEFB ZX_4 987 DEFB ZX_5 988 989 DEFB ZX_0 990 DEFB ZX_9 991 DEFB ZX_8 992 DEFB ZX_7 993 DEFB ZX_6 994 995 DEFB ZX_P 996 DEFB ZX_O 997 DEFB ZX_I 998 DEFB ZX_U 999 DEFB ZX_Y 1000 1001 DEFB ZX_NEWLINE 1002 DEFB ZX_L 1003 DEFB ZX_K 1004 DEFB ZX_J 1005 DEFB ZX_H 1006 1007 DEFB ZX_SPACE 1008 DEFB ZX_PERIOD 1009 DEFB ZX_M 1010 DEFB ZX_N 1011 DEFB ZX_B 1012 1013 1014 ------------------------------------------------------------------------ 1015 1016 ; THE *'SHIFTED'* CHARACTER CODES 1017 ------------------------------------------------------------------------ 1018 1019 1020 1021 mark_00A5: 1022 K_SHIFT: 1023 DEFB ZX_COLON ; : 1024 DEFB ZX_SEMICOLON ; ; 1025 DEFB ZX_QUERY ; ? 1026 DEFB ZX_SLASH ; / 1027 DEFB ZX_STOP 1028 DEFB ZX_LPRINT 1029 DEFB ZX_SLOW 1030 DEFB ZX_FAST 1031 DEFB ZX_LLIST 1032 DEFB $C0 ; "" 1033 DEFB ZX_OR 1034 DEFB ZX_STEP 1035 DEFB $DB ; <= 1036 DEFB $DD ; <> 1037 DEFB ZX_EDIT 1038 DEFB ZX_AND 1039 DEFB ZX_THEN 1040 DEFB ZX_TO 1041 DEFB $72 ; cursor-left 1042 DEFB ZX_RUBOUT 1043 DEFB ZX_GRAPHICS 1044 DEFB $73 ; cursor-right 1045 DEFB $70 ; cursor-up 1046 DEFB $71 ; cursor-down 1047 DEFB ZX_QUOTE ; " 1048 DEFB $11 ; ) 1049 DEFB $10 ; ( 1050 DEFB ZX_DOLLAR ; $ 1051 DEFB $DC ; >= 1052 DEFB ZX_FUNCTION 1053 DEFB ZX_EQUAL 1054 DEFB ZX_PLUS 1055 DEFB ZX_MINUS 1056 DEFB ZX_POWER ; ** 1057 DEFB ZX_POUND ; £ 1058 DEFB ZX_COMMA ; , 1059 DEFB ZX_GREATER_THAN ; > 1060 DEFB ZX_LESS_THAN ; < 1061 DEFB ZX_STAR ; * 1062 1063 ------------------------------------------------------------------------ 1064 1065 ; THE *'FUNCTION'* CHARACTER CODES 1066 ------------------------------------------------------------------------ 1067 1068 1069 1070 mark_00CC: 1071 *K_FUNCT:* 1072 DEFB ZX_LN 1073 DEFB ZX_EXP 1074 DEFB ZX_AT 1075 DEFB ZX_KL 1076 DEFB ZX_ASN 1077 DEFB ZX_ACS 1078 DEFB ZX_ATN 1079 DEFB ZX_SGN 1080 DEFB ZX_ABS 1081 DEFB ZX_SIN 1082 DEFB ZX_COS 1083 DEFB ZX_TAN 1084 DEFB ZX_INT 1085 DEFB ZX_RND 1086 DEFB ZX_KL 1087 DEFB ZX_KL 1088 DEFB ZX_KL 1089 DEFB ZX_KL 1090 DEFB ZX_KL 1091 DEFB ZX_KL 1092 DEFB ZX_KL 1093 DEFB ZX_KL 1094 DEFB ZX_KL 1095 DEFB ZX_KL 1096 DEFB ZX_TAB 1097 DEFB ZX_PEEK 1098 DEFB ZX_CODE 1099 DEFB ZX_CHR_STR ; CHR$ 1100 DEFB ZX_STR_STR ; STR$ 1101 DEFB ZX_KL 1102 DEFB ZX_USR 1103 DEFB ZX_LEN 1104 DEFB ZX_VAL 1105 DEFB ZX_SQR 1106 DEFB ZX_KL 1107 DEFB ZX_KL 1108 DEFB ZX_PI 1109 DEFB ZX_NOT 1110 DEFB ZX_INKEY_STR 1111 1112 1113 ------------------------------------------------------------------------ 1114 1115 ; THE *'GRAPHIC'* CHARACTER CODES 1116 ------------------------------------------------------------------------ 1117 1118 1119 1120 mark_00F3: 1121 *K_GRAPH:* 1122 DEFB $08 ; graphic 1123 DEFB $0A ; graphic 1124 DEFB $09 ; graphic 1125 DEFB $8A ; graphic 1126 DEFB $89 ; graphic 1127 1128 DEFB $81 ; graphic 1129 DEFB $82 ; graphic 1130 DEFB $07 ; graphic 1131 DEFB $84 ; graphic 1132 DEFB $06 ; graphic 1133 1134 DEFB $01 ; graphic 1135 DEFB $02 ; graphic 1136 DEFB $87 ; graphic 1137 DEFB $04 ; graphic 1138 DEFB $05 ; graphic 1139 1140 DEFB ZX_RUBOUT 1141 DEFB ZX_KL 1142 DEFB $85 ; graphic 1143 DEFB $03 ; graphic 1144 DEFB $83 ; graphic 1145 1146 DEFB $8B ; graphic 1147 DEFB $91 ; inverse ) 1148 DEFB $90 ; inverse ( 1149 DEFB $8D ; inverse $ 1150 DEFB $86 ; graphic 1151 1152 DEFB ZX_KL 1153 DEFB $92 ; inverse > 1154 DEFB $95 ; inverse + 1155 DEFB $96 ; inverse - 1156 DEFB $88 ; graphic 1157 1158 ------------------------------------------------------------------------ 1159 1160 ; THE *'TOKEN'* TABLES 1161 ------------------------------------------------------------------------ 1162 1163 1164 1165 mark_0111: 1166 *TOKEN_TABLE:* 1167 DEFB ZX_QUERY +$80; '?' 1168 DEFB ZX_QUOTE, ZX_QUOTE +$80; "" 1169 DEFB ZX_A, ZX_T +$80; AT 1170 DEFB ZX_T, ZX_A, ZX_B +$80; TAB 1171 DEFB ZX_QUERY +$80; '?' 1172 DEFB ZX_C, ZX_O, ZX_D, ZX_E +$80; CODE 1173 DEFB ZX_V, ZX_A, ZX_L +$80; VAL 1174 DEFB ZX_L, ZX_E, ZX_N +$80; LEN 1175 DEFB ZX_S, ZX_I, ZX_N +$80; SIN 1176 DEFB ZX_C, ZX_O, ZX_S +$80; COS 1177 DEFB ZX_T, ZX_A, ZX_N +$80; TAN 1178 DEFB ZX_A, ZX_S, ZX_N +$80; ASN 1179 DEFB ZX_A, ZX_C, ZX_S +$80; ACS 1180 DEFB ZX_A, ZX_T, ZX_N +$80; ATN 1181 DEFB ZX_L, ZX_N +$80; LN 1182 DEFB ZX_E, ZX_X, ZX_P +$80; EXP 1183 DEFB ZX_I, ZX_N, ZX_T +$80; INT 1184 DEFB ZX_S, ZX_Q, ZX_R +$80; SQR 1185 DEFB ZX_S, ZX_G, ZX_N +$80; SGN 1186 DEFB ZX_A, ZX_B, ZX_S +$80; ABS 1187 DEFB ZX_P, ZX_E, ZX_E, ZX_K +$80; PEEK 1188 DEFB ZX_U, ZX_S, ZX_R +$80; USR 1189 DEFB ZX_S, ZX_T, ZX_R, ZX_DOLLAR +$80; STR$ 1190 DEFB ZX_C, ZX_H, ZX_R, ZX_DOLLAR +$80; CHR$ 1191 DEFB ZX_N, ZX_O, ZX_T +$80; NOT 1192 DEFB ZX_STAR, ZX_STAR +$80; ** 1193 DEFB ZX_O, ZX_R +$80; OR 1194 DEFB ZX_A, ZX_N, ZX_D +$80; AND 1195 DEFB ZX_LESS_THAN, ZX_EQUAL +$80; >= 1196 DEFB ZX_GREATER_THAN, ZX_EQUAL +$80; <= 1197 DEFB ZX_LESS_THAN, ZX_GREATER_THAN +$80; >< 1198 DEFB ZX_T, ZX_H, ZX_E, ZX_N +$80; THEN 1199 DEFB ZX_T, ZX_O +$80; TO 1200 DEFB ZX_S, ZX_T, ZX_E, ZX_P +$80; STEP 1201 DEFB ZX_L, ZX_P, ZX_R, ZX_I, ZX_N, ZX_T +$80; LPRINT 1202 DEFB ZX_L, ZX_L, ZX_I, ZX_S, ZX_T +$80; LLIST 1203 DEFB ZX_S, ZX_T, ZX_O, ZX_P +$80; STOP 1204 DEFB ZX_S, ZX_L, ZX_O, ZX_W +$80; SLOW 1205 DEFB ZX_F, ZX_A, ZX_S, ZX_T +$80; FAST 1206 DEFB ZX_N, ZX_E, ZX_W +$80; NEW 1207 DEFB ZX_S, ZX_C, ZX_R, ZX_O, ZX_L, ZX_L +$80; SCROLL 1208 DEFB ZX_C, ZX_O, ZX_N, ZX_T +$80; CONT 1209 DEFB ZX_D, ZX_I, ZX_M +$80; DIM 1210 DEFB ZX_R, ZX_E, ZX_M +$80; REM 1211 DEFB ZX_F, ZX_O, ZX_R +$80; FOR 1212 DEFB ZX_G, ZX_O, ZX_T, ZX_O +$80; GOTO 1213 DEFB ZX_G, ZX_O, ZX_S, ZX_U, ZX_B +$80; GOSUB 1214 DEFB ZX_I, ZX_N, ZX_P, ZX_U, ZX_T +$80; INPUT 1215 DEFB ZX_L, ZX_O, ZX_A, ZX_D +$80; LOAD 1216 DEFB ZX_L, ZX_I, ZX_S, ZX_T +$80; LIST 1217 DEFB ZX_L, ZX_E, ZX_T +$80; LET 1218 DEFB ZX_P, ZX_A, ZX_U, ZX_S, ZX_E +$80; PAUSE 1219 DEFB ZX_N, ZX_E, ZX_X, ZX_T +$80; NEXT 1220 DEFB ZX_P, ZX_O, ZX_K, ZX_E +$80; POKE 1221 DEFB ZX_P, ZX_R, ZX_I, ZX_N, ZX_T +$80; PRINT 1222 DEFB ZX_P, ZX_L, ZX_O, ZX_T +$80; PLOT 1223 DEFB ZX_R, ZX_U, ZX_N +$80; RUN 1224 DEFB ZX_S, ZX_A, ZX_V, ZX_E +$80; SAVE 1225 DEFB ZX_R, ZX_A, ZX_N, ZX_D +$80; RAND 1226 DEFB ZX_I, ZX_F +$80; IF 1227 DEFB ZX_C, ZX_L, ZX_S +$80; CLS 1228 DEFB ZX_U, ZX_N, ZX_P, ZX_L, ZX_O, ZX_T +$80; UNPLOT 1229 DEFB ZX_C, ZX_L, ZX_E, ZX_A, ZX_R +$80; CLEAR 1230 DEFB ZX_R, ZX_E, ZX_T, ZX_U, ZX_R, ZX_N +$80; RETURN 1231 DEFB ZX_C, ZX_O, ZX_P, ZX_Y +$80; COPY 1232 DEFB ZX_R, ZX_N, ZX_D +$80; RND 1233 DEFB ZX_I, ZX_N, ZX_K, ZX_E, ZX_Y, ZX_DOLLAR +$80; INKEY$ 1234 DEFB ZX_P, ZX_I +$80; PI 1235 1236 ------------------------------------------------------------------------ 1237 1238 ; THE *'LOAD_SAVE UPDATE'* ROUTINE 1239 ------------------------------------------------------------------------ 1240 1241 ; 1242 ; 1243 1244 mark_01FC: 1245 *LOAD_SAVE:* 1246 INC HL ; 1247 EX DE,HL ; 1248 LD HL,(E_LINE) ; system variable edit line E_LINE. 1249 SCF ; set carry flag 1250 SBC HL,DE ; 1251 EX DE,HL ; 1252 RET NC ; return if more bytes to LOAD_SAVE. 1253 1254 POP HL ; else drop return address 1255 1256 ------------------------------------------------------------------------ 1257 1258 ; THE *'DISPLAY'* ROUTINES 1259 ------------------------------------------------------------------------ 1260 1261 ; 1262 ; 1263 1264 mark_0207: 1265 *SLOW_FAST:* 1266 LD HL,CDFLAG ; Address the system variable CDFLAG. 1267 LD A,(HL) ; Load value to the accumulator. 1268 RLA ; rotate bit 6 to position 7. 1269 XOR (HL) ; exclusive or with original bit 7. 1270 RLA ; rotate result out to carry. 1271 RET NC ; return if both bits were the same. 1272 1273 ; Now test if this really is a ZX81 or a ZX80 running the upgraded ROM. 1274 ; The standard ZX80 did not have an NMI generator. 1275 1276 LD A,$7F ; Load accumulator with %011111111 1277 EX AF,AF' ; save in AF' 1278 1279 LD B,17 ; A counter within which an NMI should occur 1280 ; if this is a ZX81. 1281 OUT (IO_PORT_NMI_GEN_ON),A ; start the NMI generator. 1282 1283 ; Note that if this is a ZX81 then the NMI will increment AF'. 1284 1285 mark_0216: 1286 *LOOP_11:* 1287 1288 DJNZ LOOP_11 <#LOOP_11> ; self loop to give the NMI a chance to kick in. 1289 ; = 16*13 clock cycles + 8 = 216 clock cycles. 1290 1291 OUT (IO_PORT_NMI_GEN_OFF),A ; Turn off the NMI generator. 1292 EX AF,AF' ; bring back the AF' value. 1293 RLA ; test bit 7. 1294 JR NC,NO_SLOW <#NO_SLOW> ; forward, if bit 7 is still reset, to NO_SLOW. 1295 1296 ; If the AF' was incremented then the NMI generator works and SLOW mode can 1297 ; be set. 1298 1299 SET 7,(HL) ; Indicate SLOW mode - Compute and Display. 1300 1301 PUSH AF ; * Save Main Registers 1302 PUSH BC ; ** 1303 PUSH DE ; *** 1304 PUSH HL ; **** 1305 1306 JR DISPLAY_1 <#DISPLAY_1> ; skip forward - to DISPLAY_1. 1307 1308 ; ___ 1309 1310 mark_0226: 1311 *NO_SLOW:* 1312 RES 6,(HL) ; reset bit 6 of CDFLAG. 1313 RET ; return. 1314 1315 ------------------------------------------------------------------------ 1316 1317 ; THE *'MAIN DISPLAY'* LOOP 1318 ------------------------------------------------------------------------ 1319 1320 ; This routine is executed once for every frame displayed. 1321 1322 mark_0229: 1323 *DISPLAY_1:* 1324 1325 LD HL,(FRAMES) ; fetch two-byte system variable FRAMES. 1326 DEC HL ; decrement frames counter. 1327 mark_022D: 1328 *DISPLAY_P:* 1329 LD A,$7F ; prepare a mask 1330 AND H ; pick up bits 6-0 of H. 1331 OR L ; and any bits of L. 1332 LD A,H ; reload A with all bits of H for PAUSE test. 1333 1334 ; Note both branches must take the same time. 1335 1336 JR NZ,ANOTHER <#ANOTHER> ; (12/7) forward if bits 14-0 are not zero 1337 ; to ANOTHER 1338 1339 RLA ; (4) test bit 15 of FRAMES. 1340 JR OVER_NC <#OVER_NC> ; (12) forward with result to OVER_NC 1341 1342 ; ___ 1343 1344 mark_0237: 1345 *ANOTHER:* 1346 LD B,(HL) ; (7) Note. Harmless Nonsensical Timing weight. 1347 SCF ; (4) Set Carry Flag. 1348 1349 ; Note. the branch to here takes either (12)(7)(4) cyles or (7)(4)(12) cycles. 1350 1351 mark_0239: 1352 *OVER_NC:* 1353 LD H,A ; (4) set H to zero 1354 LD (FRAMES),HL ; (16) update system variable FRAMES 1355 RET NC ; (11/5) return if FRAMES is in use by PAUSE 1356 ; command. 1357 1358 mark_023E: 1359 *DISPLAY_2:* 1360 CALL KEYBOARD <#KEYBOARD> ; gets the key row in H and the column in L. 1361 ; Reading the ports also starts 1362 ; the TV frame synchronization pulse. (VSYNC) 1363 1364 LD BC,(LAST_K) ; fetch the last key values 1365 LD (LAST_K),HL ; update LAST_K with new values. 1366 1367 LD A,B ; load A with previous column - will be $FF if 1368 ; there was no key. 1369 ADD A,2 ; adding two will set carry if no previous key. 1370 1371 SBC HL,BC ; subtract with the carry the two key values. 1372 1373 ; If the same key value has been returned twice then HL will be zero. 1374 1375 LD A,(DEBOUNCE_VAR) 1376 OR H ; and OR with both bytes of the difference 1377 OR L ; setting the zero flag for the upcoming branch. 1378 1379 LD E,B ; transfer the column value to E 1380 LD B,11 ; and load B with eleven 1381 1382 LD HL,CDFLAG ; address system variable CDFLAG 1383 RES 0,(HL) ; reset the rightmost bit of CDFLAG 1384 JR NZ,NO_KEY <#NO_KEY> ; skip forward if debounce/diff >0 to NO_KEY 1385 1386 BIT 7,(HL) ; test compute and display bit of CDFLAG 1387 SET 0,(HL) ; set the rightmost bit of CDFLAG. 1388 RET Z ; return if bit 7 indicated fast mode. 1389 1390 DEC B ; (4) decrement the counter. 1391 NOP ; (4) Timing - 4 clock cycles. ?? 1392 SCF ; (4) Set Carry Flag 1393 1394 mark_0264: 1395 *NO_KEY:* 1396 1397 LD HL,DEBOUNCE_VAR ; 1398 CCF ; Complement Carry Flag 1399 RL B ; rotate left B picking up carry 1400 ; C<-76543210<-C 1401 1402 1403 1404 1405 1406 1407 mark_026A: 1408 *LOOP_B:* 1409 1410 DJNZ LOOP_B <#LOOP_B> ; self-loop while B>0 to LOOP_B 1411 1412 LD B,(HL) ; fetch value of DEBOUNCE_VAR to B 1413 LD A,E ; transfer column value 1414 CP $FE ; 1415 SBC A,A ; A = A-A-C = 0-Carry 1416 #if 1 1417 ; I think this truncating DEBOUNCE_VAR 1418 ; which would explain why the VSYNC time didn't match 1419 ; my calculations that assumed debouncing for 255 loops. 1420 ; 1421 ; 1422 LD B,$1F ; binary 000 11111 1423 OR (HL) ; 1424 AND B ; truncate column, 0 to 31 1425 #endif 1426 RRA ; 1427 LD (HL),A ; 1428 1429 OUT (IO_PORT_SCREEN),A ; end the TV frame synchronization pulse. 1430 1431 LD HL,(D_FILE) ; (12) set HL to the Display File from D_FILE 1432 SET 7,H ; (8) set bit 15 to address the echo display. 1433 1434 CALL DISPLAY_3 <#DISPLAY_3> ; (17) routine DISPLAY_3 displays the top set 1435 ; of blank lines. 1436 1437 ------------------------------------------------------------------------ 1438 1439 ; THE *'VIDEO_1'* ROUTINE 1440 ------------------------------------------------------------------------ 1441 1442 1443 mark_0281: 1444 *R_IX_1:* 1445 LD A,R ; (9) Harmless Nonsensical Timing 1446 ; or something very clever? 1447 LD BC,25*256+1 ; (10) 25 lines, 1 scanline in first. ($1901) 1448 1449 ; 32 characters, use $F5 (i.e. minus 11) 1450 ; 40 characters, use $ED (i.e. minus 19) 1451 ; 1452 1453 mark_0286: 1454 LD A,277-CHARS_PER_LINE_WINDOW ; $F5 for 6.5MHz clocked machines 1455 ; (7) This value will be loaded into R and 1456 ; ensures that the cycle starts at the right 1457 ; part of the display - after last character 1458 ; position. 1459 1460 CALL DISPLAY_5 <#DISPLAY_5> ; (17) routine DISPLAY_5 completes the current 1461 ; blank line and then generates the display of 1462 ; the live picture using INT interrupts 1463 ; The final interrupt returns to the next 1464 ; address. 1465 *R_IX_1_LAST_NEWLINE:* 1466 DEC HL ; point HL to the last NEWLINE/HALT. 1467 1468 CALL DISPLAY_3 <#DISPLAY_3> ; displays the bottom set of blank lines. 1469 1470 ; ___ 1471 1472 mark_028F: 1473 *R_IX_2:* 1474 JP DISPLAY_1 <#DISPLAY_1> ; JUMP back to DISPLAY_1 1475 1476 ------------------------------------------------------------------------ 1477 1478 ; THE *'DISPLAY BLANK LINES'* ROUTINE 1479 ------------------------------------------------------------------------ 1480 1481 ; This subroutine is called twice (see above) to generate first the blank 1482 ; lines at the top of the television display and then the blank lines at the 1483 ; bottom of the display. 1484 ; 1485 ; It is actually pretty bad. 1486 ; PAL or NTSC = 312 or 1487 ; 1 to 5 = 5 long and 5 short sync 1488 ; 6 to 23 = blank 1489 ; 24 to 309 = image 1490 ; 310 to 312 = 6 short sync 1491 ; 1492 ; The ZX80 generates either 62 or 110 blank lines 1493 ; 1494 ; 262 - 31 - 31 = 200 1495 ; 312 - 55 - 55 = 202 1496 ; 1497 ; This does not include 'VSYNC' line periods. 1498 ; 1499 1500 mark_0292: 1501 *DISPLAY_3:* 1502 POP IX ; pop the return address to IX register. 1503 ; will be either R_IX_1 or R_IX_2 - see above. 1504 1505 LD C,(IY+MARGIN-RAMBASE) ; load C with value of system constant MARGIN. 1506 BIT 7,(IY+CDFLAG-RAMBASE) ; test CDFLAG for compute and display. 1507 JR Z,DISPLAY_4 <#DISPLAY_4> ; forward, with FAST mode, to DISPLAY_4 1508 1509 LD A,C ; move MARGIN to A - 31d or 55d. 1510 NEG ; Negate 1511 INC A ; 1512 EX AF,AF' ; place negative count of blank lines in A' 1513 1514 OUT (IO_PORT_NMI_GEN_ON),A ; enable the NMI generator. 1515 1516 POP HL ; **** 1517 POP DE ; *** 1518 POP BC ; ** 1519 POP AF ; * Restore Main Registers 1520 1521 RET ; return - end of interrupt. Return is to 1522 ; user's program - BASIC or machine code. 1523 ; which will be interrupted by every NMI. 1524 1525 ------------------------------------------------------------------------ 1526 1527 ; THE *'FAST MODE'* ROUTINES 1528 ------------------------------------------------------------------------ 1529 1530 1531 mark_02A9: 1532 1533 *DISPLAY_4:* 1534 1535 LD A,284-CHARS_PER_LINE_WINDOW ; $FC for 6.5MHz clocked machines 1536 ; (7) load A with first R delay value 1537 1538 LD B,1 ; (7) one row only. 1539 1540 CALL DISPLAY_5 <#DISPLAY_5> ; (17) routine DISPLAY_5 1541 1542 DEC HL ; (6) point back to the HALT. 1543 EX (SP),HL ; (19) Harmless Nonsensical Timing if paired. 1544 EX (SP),HL ; (19) Harmless Nonsensical Timing. 1545 JP (IX) ; (8) to R_IX_1 or R_IX_2 1546 1547 ------------------------------------------------------------------------ 1548 1549 ; THE *'DISPLAY_5'* SUBROUTINE 1550 ------------------------------------------------------------------------ 1551 1552 ; This subroutine is called from SLOW mode and FAST mode to generate the 1553 ; central TV picture. With SLOW mode the R register is incremented, with 1554 ; each instruction, to $F7 by the time it completes. With fast mode, the 1555 ; final R value will be $FF and an interrupt will occur as soon as the 1556 ; Program Counter reaches the HALT. (24 clock cycles) 1557 1558 mark_02B5: 1559 *DISPLAY_5:* 1560 LD R,A ; (9) Load R from A. R = slow: $F5 fast: $FC 1561 1562 ;; Original, for 32 column display: 1563 ;; 1564 ;; LD A,$DD ; (7) load future R value. $F6 $FD 1565 ;; 1566 ;; For other display widths, 1567 ;; need to count down three instructions then the number of characters 1568 ;; 1569 LD A,256-3-CHARS_PER_LINE_WINDOW ; (7) load future R value. $F6 $FD 1570 1571 EI ; (4) Enable Interrupts $F7 $FE 1572 1573 JP (HL) ; (4) jump to the echo display. $F8 $FF 1574 1575 ------------------------------------------------------------------------ 1576 1577 ; THE *'KEYBOARD SCANNING'* SUBROUTINE 1578 ------------------------------------------------------------------------ 1579 1580 ; The keyboard is read during the vertical sync interval while no video is 1581 ; being displayed. Reading a port with address bit 0 low i.e. $FE starts the 1582 ; vertical sync pulse. 1583 1584 mark_02BB: 1585 *KEYBOARD:* 1586 LD HL,$FFFF ; (16) prepare a buffer to take key. 1587 LD BC,$FEFE ; (20) set BC to port $FEFE. The B register, 1588 ; with its single reset bit also acts as 1589 ; an 8-counter. 1590 IN A,(C) ; (11) read the port - all 16 bits are put on 1591 ; the address bus. Start VSYNC pulse. 1592 OR $01 ; (7) set the rightmost bit so as to ignore 1593 ; the SHIFT key. 1594 1595 mark_02C5: 1596 *EACH_LINE:* 1597 OR $E0 ; [7] OR %11100000 1598 LD D,A ; [4] transfer to D. 1599 CPL ; [4] complement - only bits 4-0 meaningful now. 1600 CP 1 ; [7] sets carry if A is zero. 1601 SBC A,A ; [4] $FF if $00 else zero. 1602 OR B ; [7] $FF or port FE,FD,FB.... 1603 AND L ; [4] unless more than one key, L will still be 1604 ; $FF. if more than one key is pressed then A is 1605 ; now invalid. 1606 LD L,A ; [4] transfer to L. 1607 1608 ; now consider the column identifier. 1609 1610 LD A,H ; [4] will be $FF if no previous keys. 1611 AND D ; [4] 111xxxxx 1612 LD H,A ; [4] transfer A to H 1613 1614 ; since only one key may be pressed, H will, if valid, be one of 1615 ; 11111110, 11111101, 11111011, 11110111, 11101111 1616 ; reading from the outer column, say Q, to the inner column, say T. 1617 1618 RLC B ; [8] rotate the 8-counter/port address. 1619 ; sets carry if more to do. 1620 IN A,(C) ; [10] read another half-row. 1621 ; all five bits this time. 1622 1623 JR C,EACH_LINE <#EACH_LINE> ; [12](7) loop back, until done, to EACH_LINE 1624 1625 ; The last row read is SHIFT,Z,X,C,V for the second time. 1626 1627 RRA ; (4) test the shift key - carry will be reset 1628 ; if the key is pressed. 1629 RL H ; (8) rotate left H picking up the carry giving 1630 ; column values - 1631 ; $FD, $FB, $F7, $EF, $DF. 1632 ; or $FC, $FA, $F6, $EE, $DE if shifted. 1633 1634 ; We now have H identifying the column and L identifying the row in the 1635 ; keyboard matrix. 1636 1637 ; This is a good time to test if this is an American or British machine. 1638 ; The US machine has an extra diode that causes bit 6 of a byte read from 1639 ; a port to be reset. 1640 1641 RLA ; (4) compensate for the shift test. 1642 RLA ; (4) rotate bit 7 out. 1643 RLA ; (4) test bit 6. 1644 1645 SBC A,A ; (4) $FF or 0 {USA} 1646 AND $18 ; (7) 24 or 0 1647 ADD A,31 ; (7) 55 or 31 1648 1649 ; result is either 31 (USA) or 55 (UK) blank lines above and below the TV 1650 ; picture. 1651 1652 LD (MARGIN),A ; (13) update system variable MARGIN 1653 1654 RET ; (10) return 1655 1656 ------------------------------------------------------------------------ 1657 1658 ; THE *'SET FAST MODE'* SUBROUTINE 1659 ------------------------------------------------------------------------ 1660 1661 ; 1662 ; 1663 1664 mark_02E7: 1665 *SET_FAST:* 1666 BIT 7,(IY+CDFLAG-RAMBASE) 1667 RET Z ; 1668 1669 HALT ; Wait for Interrupt 1670 OUT (IO_PORT_NMI_GEN_OFF),A ; 1671 RES 7,(IY+CDFLAG-RAMBASE) 1672 RET ; return. 1673 1674 1675 ------------------------------------------------------------------------ 1676 1677 ; THE *'REPORT_F'* 1678 ------------------------------------------------------------------------ 1679 1680 1681 mark_02F4: 1682 *REPORT_F:* 1683 RST _ERROR_1 1684 DEFB $0E ; Error Report: No Program Name supplied. 1685 1686 ------------------------------------------------------------------------ 1687 1688 ; THE *'SAVE COMMAND'* ROUTINE 1689 ------------------------------------------------------------------------ 1690 1691 ; 1692 ; 1693 1694 mark_02F6: 1695 *SAVE:* 1696 CALL NAME <#NAME> 1697 JR C,REPORT_F <#REPORT_F> ; back with null name 1698 1699 EX DE,HL ; 1700 1701 1702 1703 1704 ; 1705 ; The next 6 bytes differ 1706 ; 1707 #if NOT_BODGED 1708 ; what ZASM assembled: 1709 ; 02FC: 11CB12 1710 LD DE,$12CB ; five seconds timing value (4811 decimal) 1711 ; 02FF: CD460F 1712 mark_02FF: 1713 *HEADER:* 1714 CALL BREAK_1 <#BREAK_1> 1715 1716 #else 1717 ; what the SG ROM disassembled to: 1718 ; 02FC ED;FD 1719 LDIR ; Patch tape SAVE 1720 ; 02FE C3;07;02 1721 JP SLOW_FAST ; to $0207 1722 ; 0301 0F 1723 RRCA 1724 #endif 1725 1726 1727 mark_0302: 1728 JR NC,BREAK_2 <#BREAK_2> 1729 1730 mark_0304: 1731 *DELAY_1:* 1732 DJNZ DELAY_1 <#DELAY_1> 1733 1734 DEC DE ; 1735 LD A,D ; 1736 OR E ; 1737 JR NZ,HEADER <#HEADER> ; back for delay to HEADER 1738 1739 mark_030B: 1740 *OUT_NAME:* 1741 CALL OUT_BYTE <#OUT_BYTE> 1742 BIT 7,(HL) ; test for inverted bit. 1743 INC HL ; address next character of name. 1744 JR Z,OUT_NAME <#OUT_NAME> ; back if not inverted to OUT_NAME 1745 1746 ; now start saving the system variables onwards. 1747 1748 LD HL,VERSN ; set start of area to VERSN thereby 1749 ; preserving RAMTOP etc. 1750 1751 mark_0316: 1752 *OUT_PROG:* 1753 CALL OUT_BYTE <#OUT_BYTE> 1754 1755 CALL LOAD_SAVE <#LOAD_SAVE> ; >> 1756 JR OUT_PROG <#OUT_PROG> ; loop back 1757 1758 ------------------------------------------------------------------------ 1759 1760 ; THE *'OUT_BYTE'* SUBROUTINE 1761 ------------------------------------------------------------------------ 1762 1763 ; This subroutine outputs a byte a bit at a time to a domestic tape recorder. 1764 1765 mark_031E: 1766 *OUT_BYTE:* 1767 LD E,(HL) ; fetch byte to be saved. 1768 SCF ; set carry flag - as a marker. 1769 1770 mark_0320: 1771 *EACH_BIT:* 1772 RL E ; C < 76543210 < C 1773 RET Z ; return when the marker bit has passed 1774 ; right through. >> 1775 1776 SBC A,A ; $FF if set bit or $00 with no carry. 1777 AND $05 ; $05 " " " " $00 1778 ADD A,$04 ; $09 " " " " $04 1779 LD C,A ; transfer timer to C. a set bit has a longer 1780 ; pulse than a reset bit. 1781 1782 mark_0329: 1783 *PULSES:* 1784 OUT (IO_PORT_TAPE),A ; pulse to cassette. 1785 LD B,$23 ; set timing constant 1786 1787 mark_032D: 1788 *DELAY_2:* 1789 DJNZ DELAY_2 <#DELAY_2> ; self-loop 1790 1791 CALL BREAK_1 <#BREAK_1> ; test for BREAK key. 1792 1793 mark_0332: 1794 *BREAK_2:* 1795 JR NC,REPORT_D <#REPORT_D> ; forward with break to REPORT_D 1796 1797 LD B,$1E ; set timing value. 1798 1799 mark_0336: 1800 *DELAY_3:* 1801 1802 DJNZ DELAY_3 <#DELAY_3> ; self-loop 1803 1804 DEC C ; decrement counter 1805 JR NZ,PULSES <#PULSES> ; loop back 1806 1807 mark_033B: 1808 *DELAY_4:* 1809 AND A ; clear carry for next bit test. 1810 DJNZ DELAY_4 <#DELAY_4> ; self loop (B is zero - 256) 1811 1812 JR EACH_BIT <#EACH_BIT> ; loop back 1813 1814 ------------------------------------------------------------------------ 1815 1816 ; THE *'LOAD COMMAND'* ROUTINE 1817 ------------------------------------------------------------------------ 1818 1819 1820 mark_0340: 1821 *LOAD:* 1822 CALL NAME <#NAME> 1823 1824 ; DE points to start of name in RAM. 1825 1826 RL D ; pick up carry 1827 RRC D ; carry now in bit 7. 1828 1829 mark_0347: 1830 1831 1832 1833 #if NOT_BODGED 1834 1835 *LNEXT_PROG:* 1836 CALL IN_BYTE <#IN_BYTE> 1837 JR LNEXT_PROG <#LNEXT_PROG> ; loop 1838 1839 ------------------------------------------------------------------------ 1840 1841 ; THE *'IN_BYTE'* SUBROUTINE 1842 ------------------------------------------------------------------------ 1843 1844 1845 mark_034C: 1846 *IN_BYTE:* 1847 LD C,$01 ; prepare an eight counter 00000001. 1848 1849 mark_034E: 1850 *NEXT_BIT:* 1851 LD B,$00 ; set counter to 256 1852 1853 #else 1854 ; what the SG ROM has: 1855 ;0347 EB 1856 EX DE,HL ; NEXT-PROG 1857 ;0348 ED;FC 1858 LDIR ; Patch tape LOAD 1859 ;034A C3;07;02 1860 JP SLOW_FAST 1861 ;034D 01;06;00 1862 LD BC,6 1863 #endif 1864 1865 1866 1867 1868 mark_0350: 1869 *BREAK_3:* 1870 LD A,$7F ; read the keyboard row 1871 IN A,(IO_PORT_KEYBOARD_RD) ; with the SPACE key. 1872 1873 OUT (IO_PORT_SCREEN),A ; output signal to screen. 1874 1875 RRA ; test for SPACE pressed. 1876 JR NC,BREAK_4 <#BREAK_4> ; forward if so to BREAK_4 1877 1878 RLA ; reverse above rotation 1879 RLA ; test tape bit. 1880 JR C,GET_BIT <#GET_BIT> ; forward if set to GET_BIT 1881 1882 DJNZ BREAK_3 <#BREAK_3> ; loop back 1883 1884 POP AF ; drop the return address. 1885 CP D ; ugh. 1886 1887 mark_0361: 1888 *RESTART:* 1889 JP NC,INITIAL <#INITIAL> ; jump forward to INITIAL if D is zero 1890 ; to reset the system 1891 ; if the tape signal has timed out for example 1892 ; if the tape is stopped. Not just a simple 1893 ; report as some system variables will have 1894 ; been overwritten. 1895 1896 LD H,D ; else transfer the start of name 1897 LD L,E ; to the HL register 1898 1899 mark_0366: 1900 *IN_NAME:* 1901 CALL IN_BYTE <#IN_BYTE> ; is sort of recursion for name 1902 ; part. received byte in C. 1903 BIT 7,D ; is name the null string ? 1904 LD A,C ; transfer byte to A. 1905 JR NZ,MATCHING <#MATCHING> ; forward with null string 1906 1907 CP (HL) ; else compare with string in memory. 1908 JR NZ,LNEXT_PROG <#LNEXT_PROG> ; back with mis-match 1909 ; (seemingly out of subroutine but return 1910 ; address has been dropped). 1911 1912 1913 mark_0371: 1914 *MATCHING:* 1915 INC HL ; address next character of name 1916 RLA ; test for inverted bit. 1917 JR NC,IN_NAME <#IN_NAME> ; back if not 1918 1919 ; the name has been matched in full. 1920 ; proceed to load the data but first increment the high byte of E_LINE, which 1921 ; is one of the system variables to be loaded in. Since the low byte is loaded 1922 ; before the high byte, it is possible that, at the in-between stage, a false 1923 ; value could cause the load to end prematurely - see LOAD_SAVE check. 1924 1925 INC (IY+E_LINE_hi-RAMBASE) ; increment E_LINE_hi. 1926 LD HL,VERSN ; start loading at VERSN. 1927 1928 mark_037B: 1929 *IN_PROG:* 1930 LD D,B ; set D to zero as indicator. 1931 CALL IN_BYTE <#IN_BYTE> ; loads a byte 1932 LD (HL),C ; insert assembled byte in memory. 1933 CALL LOAD_SAVE <#LOAD_SAVE> ; >> 1934 JR IN_PROG <#IN_PROG> ; loop back 1935 1936 ; ___ 1937 1938 ; this branch assembles a full byte before exiting normally 1939 ; from the IN_BYTE subroutine. 1940 1941 mark_0385: 1942 *GET_BIT:* 1943 PUSH DE ; save the 1944 LD E,$94 ; timing value. 1945 1946 mark_0388: 1947 *TRAILER:* 1948 LD B,26 ; counter to twenty six. 1949 1950 mark_038A: 1951 *COUNTER:* 1952 DEC E ; decrement the measuring timer. 1953 IN A,(IO_PORT_KEYBOARD_RD) ; read the tape input 1954 RLA ; 1955 BIT 7,E ; 1956 LD A,E ; 1957 JR C,TRAILER <#TRAILER> ; loop back with carry to TRAILER 1958 1959 DJNZ COUNTER <#COUNTER> 1960 1961 POP DE ; 1962 JR NZ,BIT_DONE <#BIT_DONE> 1963 1964 CP $56 ; 1965 JR NC,NEXT_BIT <#NEXT_BIT> 1966 1967 mark_039C: 1968 *BIT_DONE:* 1969 CCF ; complement carry flag 1970 RL C ; 1971 JR NC,NEXT_BIT <#NEXT_BIT> 1972 1973 RET ; return with full byte. 1974 1975 ; ___ 1976 1977 ; if break is pressed while loading data then perform a reset. 1978 ; if break pressed while waiting for program on tape then OK to break. 1979 1980 mark_03A2: 1981 *BREAK_4:* 1982 LD A,D ; transfer indicator to A. 1983 AND A ; test for zero. 1984 JR Z,RESTART <#RESTART> ; back if so 1985 1986 1987 mark_03A6: 1988 *REPORT_D:* 1989 RST _ERROR_1 1990 DEFB $0C ; Error Report: BREAK - CONT repeats 1991 1992 ------------------------------------------------------------------------ 1993 1994 ; THE *'PROGRAM NAME'* SUBROUTINE 1995 ------------------------------------------------------------------------ 1996 1997 1998 mark_03A8: 1999 *NAME:* 2000 CALL SCANNING <#SCANNING> 2001 LD A,(FLAGS) ; sv 2002 ADD A,A ; 2003 JP M,REPORT_C <#REPORT_C> 2004 2005 POP HL ; 2006 RET NC ; 2007 2008 PUSH HL ; 2009 CALL SET_FAST <#SET_FAST> 2010 CALL STK_FETCH <#STK_FETCH> 2011 LD H,D ; 2012 LD L,E ; 2013 DEC C ; 2014 RET M ; 2015 2016 ADD HL,BC ; 2017 SET 7,(HL) ; 2018 RET ; 2019 2020 ------------------------------------------------------------------------ 2021 2022 ; THE *'NEW'* COMMAND ROUTINE 2023 ------------------------------------------------------------------------ 2024 2025 2026 mark_03C3: 2027 *NEW:* 2028 CALL SET_FAST <#SET_FAST> 2029 LD BC,(RAMTOP) ; fetch value of system variable RAMTOP 2030 DEC BC ; point to last system byte. 2031 2032 ------------------------------------------------------------------------ 2033 2034 ; THE *'RAM CHECK'* ROUTINE 2035 ------------------------------------------------------------------------ 2036 2037 2038 mark_03CB: 2039 *RAM_CHECK:* 2040 LD H,B ; 2041 LD L,C ; 2042 LD A,$3F ; 2043 2044 mark_03CF: 2045 *RAM_FILL:* 2046 LD (HL),$02 ; 2047 DEC HL ; 2048 CP H ; 2049 JR NZ,RAM_FILL <#RAM_FILL> 2050 2051 mark_03D5: 2052 *RAM_READ:* 2053 AND A ; 2054 SBC HL,BC ; 2055 ADD HL,BC ; 2056 INC HL ; 2057 JR NC,SET_TOP <#SET_TOP> 2058 2059 DEC (HL) ; 2060 JR Z,SET_TOP <#SET_TOP> 2061 2062 DEC (HL) ; 2063 JR Z,RAM_READ <#RAM_READ> 2064 2065 mark_03E2: 2066 *SET_TOP:* 2067 LD (RAMTOP),HL ; set system variable RAMTOP to first byte 2068 ; above the BASIC system area. 2069 2070 ------------------------------------------------------------------------ 2071 2072 ; THE *'INITIALIZATION'* ROUTINE 2073 ------------------------------------------------------------------------ 2074 2075 2076 mark_03E5: 2077 *INITIAL:* 2078 LD HL,(RAMTOP) ; fetch system variable RAMTOP. 2079 DEC HL ; point to last system byte. 2080 LD (HL),$3E ; make GO SUB end-marker $3E - too high for 2081 ; high order byte of line number. 2082 ; (was $3F on ZX80) 2083 DEC HL ; point to unimportant low-order byte. 2084 LD SP,HL ; and initialize the stack-pointer to this 2085 ; location. 2086 DEC HL ; point to first location on the machine stack 2087 DEC HL ; which will be filled by next CALL/PUSH. 2088 LD (ERR_SP),HL ; set the error stack pointer ERR_SP to 2089 ; the base of the now empty machine stack. 2090 2091 ; Now set the I register so that the video hardware knows where to find the 2092 ; character set. This ROM only uses the character set when printing to 2093 ; the ZX Printer. The TV picture is formed by the external video hardware. 2094 ; Consider also, that this 8K ROM can be retro-fitted to the ZX80 instead of 2095 ; its original 4K ROM so the video hardware could be on the ZX80. 2096 2097 LD A,$1E ; address for this ROM is $1E00. 2098 LD I,A ; set I register from A. 2099 IM 1 ; select Z80 Interrupt Mode 1. 2100 2101 LD IY,ERR_NR ; set IY to the start of RAM so that the 2102 ; system variables can be indexed. 2103 2104 LD (IY+CDFLAG-RAMBASE),%01000000 2105 ; Bit 6 indicates Compute and Display required. 2106 2107 LD HL,USER_RAM ; The first location after System Variables - 2108 ; 16509 decimal. 2109 LD (D_FILE),HL ; set system variable D_FILE to this value. 2110 LD B,$19 ; prepare minimal screen of 24 NEWLINEs 2111 ; following an initial NEWLINE. 2112 2113 mark_0408: 2114 *LINE:* 2115 LD (HL),ZX_NEWLINE ; insert NEWLINE (HALT instruction) 2116 INC HL ; point to next location. 2117 DJNZ LINE <#LINE> ; loop back for all twenty five to LINE 2118 2119 LD (VARS),HL ; set system variable VARS to next location 2120 2121 CALL CLEAR <#CLEAR> ; sets $80 end-marker and the 2122 ; dynamic memory pointers E_LINE, STKBOT and 2123 ; STKEND. 2124 2125 mark_0413: 2126 *N_L_ONLY:* 2127 CALL CURSOR_IN <#CURSOR_IN> ; inserts the cursor and 2128 ; end-marker in the Edit Line also setting 2129 ; size of lower display to two lines. 2130 2131 CALL SLOW_FAST <#SLOW_FAST> ; selects COMPUTE and DISPLAY 2132 2133 ------------------------------------------------------------------------ 2134 2135 ; THE *'BASIC LISTING'* SECTION 2136 ------------------------------------------------------------------------ 2137 2138 2139 mark_0419: 2140 *UPPER:* 2141 CALL CLS <#CLS> 2142 LD HL,(E_PPC) ; sv 2143 LD DE,(S_TOP) ; sv 2144 AND A ; 2145 SBC HL,DE ; 2146 EX DE,HL ; 2147 JR NC,ADDR_TOP <#ADDR_TOP> 2148 2149 ADD HL,DE ; 2150 LD (S_TOP),HL ; sv 2151 2152 mark_042D: 2153 *ADDR_TOP:* 2154 CALL LINE_ADDR <#LINE_ADDR> 2155 JR Z,LIST_TOP <#LIST_TOP> 2156 2157 EX DE,HL ; 2158 2159 mark_0433: 2160 *LIST_TOP:* 2161 CALL LIST_PROG <#LIST_PROG> 2162 DEC (IY+BERG-RAMBASE) 2163 JR NZ,LOWER <#LOWER> 2164 2165 LD HL,(E_PPC) ; sv 2166 CALL LINE_ADDR <#LINE_ADDR> 2167 LD HL,(CH_ADD) ; sv 2168 SCF ; Set Carry Flag 2169 SBC HL,DE ; 2170 LD HL,S_TOP ; sv 2171 JR NC,INC_LINE <#INC_LINE> 2172 2173 EX DE,HL ; 2174 LD A,(HL) ; 2175 INC HL ; 2176 LDI ; 2177 LD (DE),A ; 2178 JR UPPER <#UPPER> 2179 ; ___ 2180 2181 mark_0454: 2182 *DOWN_KEY:* 2183 2184 LD HL,E_PPC ; sv 2185 2186 mark_0457: 2187 *INC_LINE:* 2188 LD E,(HL) ; 2189 INC HL ; 2190 LD D,(HL) ; 2191 PUSH HL ; 2192 EX DE,HL ; 2193 INC HL ; 2194 CALL LINE_ADDR <#LINE_ADDR> 2195 CALL LINE_NUM <#LINE_NUM> 2196 POP HL ; 2197 2198 mark_0464: 2199 *KEY_INPUT:* 2200 BIT 5,(IY+FLAGX-RAMBASE) 2201 JR NZ,LOWER <#LOWER> ; forward 2202 2203 LD (HL),D ; 2204 DEC HL ; 2205 LD (HL),E ; 2206 JR UPPER <#UPPER> 2207 2208 ------------------------------------------------------------------------ 2209 2210 ; THE *'EDIT LINE COPY'* SECTION 2211 ------------------------------------------------------------------------ 2212 2213 ; This routine sets the edit line to just the cursor when 2214 ; 1) There is not enough memory to edit a BASIC line. 2215 ; 2) The edit key is used during input. 2216 ; The entry point LOWER 2217 2218 2219 mark_046F: 2220 *EDIT_INP:* 2221 CALL CURSOR_IN <#CURSOR_IN> ; sets cursor only edit line. 2222 2223 ; -> 2224 2225 mark_0472: 2226 *LOWER:* 2227 LD HL,(E_LINE) ; fetch edit line start from E_LINE. 2228 2229 mark_0475: 2230 *EACH_CHAR:* 2231 LD A,(HL) ; fetch a character from edit line. 2232 CP $7E ; compare to the number marker. 2233 JR NZ,END_LINE <#END_LINE> ; forward if not 2234 2235 LD BC,6 ; else six invisible bytes to be removed. 2236 CALL RECLAIM_2 <#RECLAIM_2> 2237 JR EACH_CHAR <#EACH_CHAR> ; back 2238 ; ___ 2239 2240 mark_0482: 2241 *END_LINE:* 2242 CP ZX_NEWLINE ; 2243 INC HL ; 2244 JR NZ,EACH_CHAR <#EACH_CHAR> 2245 2246 mark_0487: 2247 *EDIT_LINE:* 2248 CALL CURSOR <#CURSOR> ; sets cursor K or L. 2249 2250 mark_048A: 2251 *EDIT_ROOM:* 2252 CALL LINE_ENDS <#LINE_ENDS> 2253 LD HL,(E_LINE) ; sv 2254 LD (IY+ERR_NR-RAMBASE),$FF 2255 CALL COPY_LINE <#COPY_LINE> 2256 BIT 7,(IY+ERR_NR-RAMBASE) 2257 JR NZ,DISPLAY_6 <#DISPLAY_6> 2258 2259 LD A,(DF_SZ) ; 2260 CP CHARS_VERTICAL ; $18 = 24 2261 JR NC,DISPLAY_6 <#DISPLAY_6> 2262 2263 INC A ; 2264 LD (DF_SZ),A ; 2265 LD B,A ; 2266 LD C,1 ; 2267 CALL LOC_ADDR <#LOC_ADDR> 2268 LD D,H ; 2269 LD E,L ; 2270 LD A,(HL) ; 2271 2272 mark_04B1: 2273 *FREE_LINE:* 2274 DEC HL ; 2275 CP (HL) ; 2276 JR NZ,FREE_LINE <#FREE_LINE> 2277 2278 INC HL ; 2279 EX DE,HL ; 2280 LD A,(RAMTOP+1) ; sv RAMTOP_hi 2281 CP $4D ; 2282 CALL C,RECLAIM_1 <#RECLAIM_1> 2283 JR EDIT_ROOM <#EDIT_ROOM> 2284 2285 ------------------------------------------------------------------------ 2286 2287 ; THE *'WAIT FOR KEY'* SECTION 2288 ------------------------------------------------------------------------ 2289 2290 2291 mark_04C1: 2292 *DISPLAY_6:* 2293 LD HL,$0000 ; 2294 LD (X_PTR),HL ; sv 2295 2296 LD HL,CDFLAG ; system variable CDFLAG 2297 2298 2299 2300 2301 #if NOT_BODGED 2302 BIT 7,(HL) ; 2303 2304 CALL Z,DISPLAY_1 <#DISPLAY_1> 2305 2306 mark_04CF: 2307 *SLOW_DISP:* 2308 BIT 0,(HL) ; 2309 JR Z,SLOW_DISP <#SLOW_DISP> 2310 2311 #else 2312 ; 04CA D3;00 2313 OUT ($00),A ; PORT 0 2314 ; 04CC CB;46 2315 L04CC: 2316 BIT 0,(HL) 2317 ; 04CE 28;FC 2318 JR Z,L04CC 2319 ; 04D0 D3;01 2320 OUT ($01),A ; PORT 1 2321 ; 04D2 00 2322 NOP 2323 2324 2325 #endif 2326 2327 2328 2329 2330 LD BC,(LAST_K) ; sv 2331 CALL DEBOUNCE <#DEBOUNCE> 2332 CALL DECODE <#DECODE> 2333 2334 JR NC,LOWER <#LOWER> ; back 2335 2336 ------------------------------------------------------------------------ 2337 2338 ; THE *'KEYBOARD DECODING'* SECTION 2339 ------------------------------------------------------------------------ 2340 2341 ; The decoded key value is in E and HL points to the position in the 2342 ; key table. D contains zero. 2343 2344 mark_04DF: 2345 *K_DECODE:* 2346 LD A,(MODE) ; Fetch value of system variable MODE 2347 DEC A ; test the three values together 2348 2349 JP M,FETCH_2 <#FETCH_2> ; forward, if was zero 2350 2351 JR NZ,FETCH_1 <#FETCH_1> ; forward, if was 2 2352 2353 ; The original value was one and is now zero. 2354 2355 LD (MODE),A ; update the system variable MODE 2356 2357 DEC E ; reduce E to range $00 - $7F 2358 LD A,E ; place in A 2359 SUB 39 ; subtract 39 setting carry if range 00 - 38 2360 JR C,FUNC_BASE <#FUNC_BASE> ; forward, if so 2361 2362 LD E,A ; else set E to reduced value 2363 2364 mark_04F2: 2365 *FUNC_BASE:* 2366 LD HL,K_FUNCT <#K_FUNCT> ; address of K_FUNCT table for function keys. 2367 JR TABLE_ADD <#TABLE_ADD> ; forward 2368 ; ___ 2369 mark_04F7: 2370 *FETCH_1:* 2371 LD A,(HL) ; 2372 CP ZX_NEWLINE ; 2373 JR Z,K_L_KEY <#K_L_KEY> 2374 2375 CP ZX_RND ; $40 2376 SET 7,A ; 2377 JR C,ENTER <#ENTER> 2378 2379 LD HL,$00C7 ; (expr reqd) 2380 2381 mark_0505: 2382 *TABLE_ADD:* 2383 ADD HL,DE ; 2384 JR FETCH_3 <#FETCH_3> 2385 2386 ; ___ 2387 2388 mark_0508: 2389 *FETCH_2:* 2390 LD A,(HL) ; 2391 BIT 2,(IY+FLAGS-RAMBASE) ; K or L mode ? 2392 JR NZ,TEST_CURS <#TEST_CURS> 2393 2394 ADD A,$C0 ; 2395 CP $E6 ; 2396 JR NC,TEST_CURS <#TEST_CURS> 2397 2398 mark_0515: 2399 *FETCH_3:* 2400 LD A,(HL) ; 2401 2402 mark_0516: 2403 *TEST_CURS:* 2404 CP $F0 ; 2405 JP PE,KEY_SORT <#KEY_SORT> 2406 2407 mark_051B: 2408 *ENTER:* 2409 LD E,A ; 2410 CALL CURSOR <#CURSOR> 2411 2412 LD A,E ; 2413 CALL ADD_CHAR <#ADD_CHAR> 2414 2415 mark_0523: 2416 *BACK_NEXT:* 2417 JP LOWER <#LOWER> ; back 2418 2419 ------------------------------------------------------------------------ 2420 2421 ; THE *'ADD CHARACTER'* SUBROUTINE 2422 ------------------------------------------------------------------------ 2423 2424 mark_0526: 2425 *ADD_CHAR:* 2426 CALL ONE_SPACE <#ONE_SPACE> 2427 LD (DE),A ; 2428 RET ; 2429 2430 ------------------------------------------------------------------------ 2431 2432 ; THE *'CURSOR KEYS'* ROUTINE 2433 ------------------------------------------------------------------------ 2434 2435 mark_052B: 2436 *K_L_KEY:* 2437 LD A,ZX_KL ; 2438 2439 mark_052D: 2440 *KEY_SORT:* 2441 LD E,A ; 2442 LD HL,$0482 ; base address of ED_KEYS (exp reqd) 2443 ADD HL,DE ; 2444 ADD HL,DE ; 2445 LD C,(HL) ; 2446 INC HL ; 2447 LD B,(HL) ; 2448 PUSH BC ; 2449 2450 mark_0537: 2451 *CURSOR:* 2452 LD HL,(E_LINE) ; sv 2453 BIT 5,(IY+FLAGX-RAMBASE) 2454 JR NZ,L_MODE <#L_MODE> 2455 2456 mark_0540: 2457 *K_MODE:* 2458 RES 2,(IY+FLAGS-RAMBASE) ; Signal use K mode 2459 2460 mark_0544: 2461 *TEST_CHAR:* 2462 LD A,(HL) ; 2463 CP ZX_CURSOR ; 2464 RET Z ; return 2465 2466 INC HL ; 2467 CALL NUMBER <#NUMBER> 2468 JR Z,TEST_CHAR <#TEST_CHAR> 2469 2470 CP ZX_A ; $26 2471 JR C,TEST_CHAR <#TEST_CHAR> 2472 2473 CP $DE ; ZX_THEN ?? 2474 JR Z,K_MODE <#K_MODE> 2475 2476 mark_0556: 2477 *L_MODE:* 2478 SET 2,(IY+FLAGS-RAMBASE) ; Signal use L mode 2479 JR TEST_CHAR <#TEST_CHAR> 2480 2481 ------------------------------------------------------------------------ 2482 2483 ; THE *'CLEAR_ONE'* SUBROUTINE 2484 ------------------------------------------------------------------------ 2485 2486 mark_055C: 2487 *CLEAR_ONE:* 2488 LD BC,$0001 ; 2489 JP RECLAIM_2 <#RECLAIM_2> 2490 2491 ------------------------------------------------------------------------ 2492 2493 ; THE *'EDITING KEYS'* TABLE 2494 ------------------------------------------------------------------------ 2495 2496 mark_0562: 2497 *ED_KEYS:* 2498 DEFW UP_KEY <#UP_KEY> 2499 DEFW DOWN_KEY <#DOWN_KEY> 2500 DEFW LEFT_KEY <#LEFT_KEY> 2501 DEFW RIGHT_KEY <#RIGHT_KEY> 2502 DEFW FUNCTION <#FUNCTION> 2503 DEFW EDIT_KEY <#EDIT_KEY> 2504 DEFW N_L_KEY <#N_L_KEY> 2505 DEFW RUBOUT <#RUBOUT> 2506 DEFW FUNCTION <#FUNCTION> 2507 DEFW FUNCTION <#FUNCTION> 2508 2509 2510 ------------------------------------------------------------------------ 2511 2512 ; THE *'CURSOR LEFT'* ROUTINE 2513 ------------------------------------------------------------------------ 2514 2515 ; 2516 ; 2517 2518 mark_LEFT_KEY: 2519 *LEFT_KEY:* 2520 CALL LEFT_EDGE <#LEFT_EDGE> 2521 LD A,(HL) ; 2522 LD (HL),ZX_CURSOR ; 2523 INC HL ; 2524 JR GET_CODE <#GET_CODE> 2525 2526 ------------------------------------------------------------------------ 2527 2528 ; THE *'CURSOR RIGHT'* ROUTINE 2529 ------------------------------------------------------------------------ 2530 2531 2532 mark_RIGHT_KEY: 2533 *RIGHT_KEY:* 2534 INC HL ; 2535 LD A,(HL) ; 2536 CP ZX_NEWLINE ; 2537 JR Z,ENDED_2 <#ENDED_2> 2538 2539 LD (HL),ZX_CURSOR ; 2540 DEC HL ; 2541 2542 mark_0588: 2543 *GET_CODE:* 2544 LD (HL),A ; 2545 2546 mark_0589: 2547 *ENDED_1:* 2548 JR BACK_NEXT <#BACK_NEXT> 2549 2550 ------------------------------------------------------------------------ 2551 2552 ; THE *'RUBOUT'* ROUTINE 2553 ------------------------------------------------------------------------ 2554 2555 2556 mark_058B: 2557 *RUBOUT:* 2558 CALL LEFT_EDGE <#LEFT_EDGE> 2559 CALL CLEAR_ONE <#CLEAR_ONE> 2560 JR ENDED_1 <#ENDED_1> 2561 2562 ------------------------------------------------------------------------ 2563 2564 ; THE *'ED_EDGE'* SUBROUTINE 2565 ------------------------------------------------------------------------ 2566 2567 ; 2568 ; 2569 2570 mark_0593: 2571 *LEFT_EDGE:* 2572 DEC HL ; 2573 LD DE,(E_LINE) ; sv 2574 LD A,(DE) ; 2575 CP ZX_CURSOR ; 2576 RET NZ ; 2577 2578 POP DE ; 2579 2580 mark_059D: 2581 *ENDED_2:* 2582 JR ENDED_1 <#ENDED_1> 2583 2584 ------------------------------------------------------------------------ 2585 2586 ; THE *'CURSOR UP'* ROUTINE 2587 ------------------------------------------------------------------------ 2588 2589 ; 2590 ; 2591 2592 mark_059F: 2593 *UP_KEY:* 2594 LD HL,(E_PPC) ; sv 2595 CALL LINE_ADDR <#LINE_ADDR> 2596 EX DE,HL ; 2597 CALL LINE_NUM <#LINE_NUM> 2598 LD HL,E_PPC+1 ; point to system variable E_PPC_hi 2599 JP KEY_INPUT <#KEY_INPUT> ; jump back 2600 2601 ------------------------------------------------------------------------ 2602 2603 ; THE *'FUNCTION KEY'* ROUTINE 2604 ------------------------------------------------------------------------ 2605 2606 ; 2607 ; 2608 2609 mark_FUNCTION: 2610 *FUNCTION:* 2611 LD A,E ; 2612 AND $07 ; 2613 LD (MODE),A ; sv 2614 JR ENDED_2 <#ENDED_2> ; back 2615 2616 ------------------------------------------------------------------------ 2617 2618 ; THE *'COLLECT LINE NUMBER'* SUBROUTINE 2619 ------------------------------------------------------------------------ 2620 2621 mark_05B7: 2622 *ZERO_DE:* 2623 EX DE,HL ; 2624 LD DE,DISPLAY_6 <#DISPLAY_6> + 1 ; $04C2 - a location addressing two zeros. 2625 2626 ; -> 2627 2628 mark_05BB: 2629 *LINE_NUM:* 2630 LD A,(HL) ; 2631 AND $C0 ; 2632 JR NZ,ZERO_DE <#ZERO_DE> 2633 2634 LD D,(HL) ; 2635 INC HL ; 2636 LD E,(HL) ; 2637 RET ; 2638 2639 ------------------------------------------------------------------------ 2640 2641 ; THE *'EDIT KEY'* ROUTINE 2642 ------------------------------------------------------------------------ 2643 2644 2645 mark_EDIT_KEY: 2646 *EDIT_KEY:* 2647 CALL LINE_ENDS <#LINE_ENDS> ; clears lower display. 2648 2649 LD HL,EDIT_INP <#EDIT_INP> ; Address: EDIT_INP 2650 PUSH HL ; ** is pushed as an error looping address. 2651 2652 BIT 5,(IY+FLAGX-RAMBASE) ; test FLAGX 2653 RET NZ ; indirect jump if in input mode 2654 ; to EDIT_INP <#EDIT_INP> (begin again). 2655 2656 ; 2657 2658 LD HL,(E_LINE) ; fetch E_LINE 2659 LD (DF_CC),HL ; and use to update the screen cursor DF_CC 2660 2661 ; so now RST $10 will print the line numbers to the edit line instead of screen. 2662 ; first make sure that no newline/out of screen can occur while sprinting the 2663 ; line numbers to the edit line. 2664 2665 ; prepare line 0, column 0. 2666 2667 LD HL,256*CHARS_VERTICAL + CHARS_HORIZONTAL + 1 2668 ; 2669 LD (S_POSN),HL ; update S_POSN with these dummy values. 2670 2671 LD HL,(E_PPC) ; fetch current line from E_PPC may be a 2672 ; non-existent line e.g. last line deleted. 2673 CALL LINE_ADDR <#LINE_ADDR> ; gets address or that of 2674 ; the following line. 2675 CALL LINE_NUM <#LINE_NUM> ; gets line number if any in DE 2676 ; leaving HL pointing at second low byte. 2677 2678 LD A,D ; test the line number for zero. 2679 OR E ; 2680 RET Z ; return if no line number - no program to edit. 2681 2682 DEC HL ; point to high byte. 2683 CALL OUT_NO <#OUT_NO> ; writes number to edit line. 2684 2685 INC HL ; point to length bytes. 2686 LD C,(HL) ; low byte to C. 2687 INC HL ; 2688 LD B,(HL) ; high byte to B. 2689 2690 INC HL ; point to first character in line. 2691 LD DE,(DF_CC) ; fetch display file cursor DF_CC 2692 2693 LD A,ZX_CURSOR ; prepare the cursor character. 2694 LD (DE),A ; and insert in edit line. 2695 INC DE ; increment intended destination. 2696 2697 PUSH HL ; * save start of BASIC. 2698 2699 LD HL,29 ; set an overhead of 29 bytes. 2700 ADD HL,DE ; add in the address of cursor. 2701 ADD HL,BC ; add the length of the line. 2702 SBC HL,SP ; subtract the stack pointer. 2703 2704 POP HL ; * restore pointer to start of BASIC. 2705 2706 RET NC ; return if not enough room to EDIT_INP EDIT_INP. 2707 ; the edit key appears not to work. 2708 2709 LDIR ; else copy bytes from program to edit line. 2710 ; Note. hidden floating point forms are also 2711 ; copied to edit line. 2712 2713 EX DE,HL ; transfer free location pointer to HL 2714 2715 POP DE ; ** remove address EDIT_INP from stack. 2716 2717 CALL SET_STK_B <#SET_STK_B> ; sets STKEND from HL. 2718 2719 JR ENDED_2 <#ENDED_2> ; back to ENDED_2 and after 3 more jumps 2720 ; to LOWER <#LOWER>, LOWER. 2721 ; Note. The LOWER routine removes the hidden 2722 ; floating-point numbers from the edit line. 2723 2724 ------------------------------------------------------------------------ 2725 2726 ; THE *'NEWLINE KEY'* ROUTINE 2727 ------------------------------------------------------------------------ 2728 2729 2730 mark_060C: 2731 *N_L_KEY:* 2732 CALL LINE_ENDS <#LINE_ENDS> 2733 2734 LD HL,LOWER <#LOWER> ; prepare address: LOWER 2735 2736 BIT 5,(IY+FLAGX-RAMBASE) 2737 JR NZ,NOW_SCAN <#NOW_SCAN> 2738 2739 LD HL,(E_LINE) ; sv 2740 LD A,(HL) ; 2741 CP $FF ; 2742 JR Z,STK_UPPER <#STK_UPPER> 2743 2744 CALL CLEAR_PRB <#CLEAR_PRB> 2745 CALL CLS <#CLS> 2746 2747 mark_0626: 2748 *STK_UPPER:* 2749 LD HL,UPPER <#UPPER> ; Address: UPPER 2750 2751 mark_0629: 2752 *NOW_SCAN:* 2753 PUSH HL ; push routine address (LOWER or UPPER). 2754 CALL LINE_SCAN <#LINE_SCAN> 2755 POP HL ; 2756 CALL CURSOR <#CURSOR> 2757 CALL CLEAR_ONE <#CLEAR_ONE> 2758 CALL E_LINE_NUM <#E_LINE_NUM> 2759 JR NZ,N_L_INP <#N_L_INP> 2760 2761 LD A,B ; 2762 OR C ; 2763 JP NZ,N_L_LINE <#N_L_LINE> 2764 2765 DEC BC ; 2766 DEC BC ; 2767 LD (PPC),BC ; sv 2768 LD (IY+DF_SZ-RAMBASE),2 2769 LD DE,(D_FILE) ; sv 2770 2771 JR TEST_NULL <#TEST_NULL> ; forward 2772 2773 ; ___ 2774 2775 mark_064E: 2776 *N_L_INP:* 2777 CP ZX_NEWLINE ; 2778 JR Z,N_L_NULL <#N_L_NULL> 2779 2780 LD BC,(T_ADDR) ; 2781 CALL LOC_ADDR <#LOC_ADDR> 2782 LD DE,(NXTLIN) ; 2783 LD (IY+DF_SZ-RAMBASE),2 2784 2785 mark_0661: 2786 *TEST_NULL:* 2787 RST _GET_CHAR 2788 CP ZX_NEWLINE ; 2789 2790 mark_0664: 2791 *N_L_NULL:* 2792 JP Z,N_L_ONLY <#N_L_ONLY> 2793 2794 LD (IY+FLAGS-RAMBASE),$80 2795 EX DE,HL ; 2796 2797 mark_066C: 2798 *NEXT_LINE:* 2799 LD (NXTLIN),HL ; 2800 EX DE,HL ; 2801 CALL TEMP_PTR2 <#TEMP_PTR2> 2802 CALL LINE_RUN <#LINE_RUN> 2803 RES 1,(IY+FLAGS-RAMBASE) ; Signal printer not in use 2804 LD A,$C0 ; 2805 ;; LD (IY+X_PTR_lo-RAMBASE),A ;; ERROR IN htm SOURCE! IY+$19 is X_PTR_hi 2806 LD (IY+X_PTR_hi-RAMBASE),A 2807 CALL X_TEMP <#X_TEMP> 2808 RES 5,(IY+FLAGX-RAMBASE) 2809 BIT 7,(IY+ERR_NR-RAMBASE) 2810 JR Z,STOP_LINE <#STOP_LINE> 2811 2812 LD HL,(NXTLIN) ; 2813 AND (HL) ; 2814 JR NZ,STOP_LINE <#STOP_LINE> 2815 2816 LD D,(HL) ; 2817 INC HL ; 2818 LD E,(HL) ; 2819 LD (PPC),DE ; 2820 INC HL ; 2821 LD E,(HL) ; 2822 INC HL ; 2823 LD D,(HL) ; 2824 INC HL ; 2825 EX DE,HL ; 2826 ADD HL,DE ; 2827 CALL BREAK_1 <#BREAK_1> 2828 JR C,NEXT_LINE <#NEXT_LINE> 2829 2830 LD HL,ERR_NR 2831 BIT 7,(HL) 2832 JR Z,STOP_LINE <#STOP_LINE> 2833 2834 LD (HL),$0C 2835 2836 mark_06AE: 2837 *STOP_LINE:* 2838 BIT 7,(IY+PR_CC-RAMBASE) 2839 CALL Z,COPY_BUFF <#COPY_BUFF> 2840 ; 2841 #if 0 2842 LD BC,$0121 ; 2843 #else 2844 LD BC,256*1 + CHARS_HORIZONTAL + 1 2845 #endif 2846 ; 2847 ; 2848 CALL LOC_ADDR <#LOC_ADDR> 2849 LD A,(ERR_NR) 2850 LD BC,(PPC) 2851 INC A 2852 JR Z,REPORT <#REPORT> 2853 2854 CP $09 2855 JR NZ,CONTINUE <#CONTINUE> 2856 2857 INC BC 2858 2859 mark_06CA: 2860 *CONTINUE:* 2861 LD (OLDPPC),BC ; 2862 JR NZ,REPORT <#REPORT> 2863 2864 DEC BC ; 2865 2866 mark_06D1: 2867 *REPORT:* 2868 CALL OUT_CODE <#OUT_CODE> 2869 LD A,ZX_SLASH 2870 2871 RST _PRINT_A 2872 CALL OUT_NUM <#OUT_NUM> 2873 CALL CURSOR_IN <#CURSOR_IN> 2874 JP DISPLAY_6 <#DISPLAY_6> 2875 2876 ; ___ 2877 2878 mark_06E0: 2879 *N_L_LINE:* 2880 LD (E_PPC),BC ; 2881 LD HL,(CH_ADD) ; 2882 EX DE,HL ; 2883 LD HL,N_L_ONLY <#N_L_ONLY> 2884 PUSH HL ; 2885 LD HL,(STKBOT) ; 2886 SBC HL,DE ; 2887 PUSH HL ; 2888 PUSH BC ; 2889 CALL SET_FAST <#SET_FAST> 2890 CALL CLS <#CLS> 2891 POP HL ; 2892 CALL LINE_ADDR <#LINE_ADDR> 2893 JR NZ,COPY_OVER <#COPY_OVER> 2894 2895 CALL NEXT_ONE <#NEXT_ONE> 2896 CALL RECLAIM_2 <#RECLAIM_2> 2897 2898 mark_0705: 2899 *COPY_OVER:* 2900 POP BC ; 2901 LD A,C ; 2902 DEC A ; 2903 OR B ; 2904 RET Z ; 2905 2906 PUSH BC ; 2907 INC BC ; 2908 INC BC ; 2909 INC BC ; 2910 INC BC ; 2911 DEC HL ; 2912 CALL MAKE_ROOM <#MAKE_ROOM> 2913 CALL SLOW_FAST <#SLOW_FAST> 2914 POP BC ; 2915 PUSH BC ; 2916 INC DE ; 2917 LD HL,(STKBOT) ; 2918 DEC HL ; 2919 LDDR ; copy bytes 2920 LD HL,(E_PPC) ; 2921 EX DE,HL ; 2922 POP BC ; 2923 LD (HL),B ; 2924 DEC HL ; 2925 LD (HL),C ; 2926 DEC HL ; 2927 LD (HL),E ; 2928 DEC HL ; 2929 LD (HL),D ; 2930 2931 RET ; return. 2932 2933 ------------------------------------------------------------------------ 2934 2935 ; THE *'LIST'* AND 'LLIST' COMMAND ROUTINES 2936 ------------------------------------------------------------------------ 2937 2938 2939 mark_072C: 2940 *LLIST:* 2941 SET 1,(IY+FLAGS-RAMBASE) ; signal printer in use 2942 2943 mark_0730: 2944 *LIST:* 2945 CALL FIND_INT <#FIND_INT> 2946 2947 LD A,B ; fetch high byte of user-supplied line number. 2948 AND $3F ; and crudely limit to range 1-16383. 2949 2950 LD H,A ; 2951 LD L,C ; 2952 LD (E_PPC),HL ; 2953 CALL LINE_ADDR <#LINE_ADDR> 2954 2955 mark_073E: 2956 *LIST_PROG:* 2957 LD E,$00 ; 2958 2959 mark_0740: 2960 *UNTIL_END:* 2961 CALL OUT_LINE <#OUT_LINE> ; lists one line of BASIC 2962 ; making an early return when the screen is 2963 ; full or the end of program is reached. 2964 JR UNTIL_END <#UNTIL_END> ; loop back to UNTIL_END 2965 2966 ------------------------------------------------------------------------ 2967 2968 ; THE *'PRINT A BASIC LINE'* SUBROUTINE 2969 ------------------------------------------------------------------------ 2970 2971 2972 mark_0745: 2973 *OUT_LINE:* 2974 LD BC,(E_PPC) ; sv 2975 CALL CP_LINES <#CP_LINES> 2976 LD D,$92 ; 2977 JR Z,TEST_END <#TEST_END> 2978 2979 LD DE,$0000 ; 2980 RL E ; 2981 2982 mark_0755: 2983 *TEST_END:* 2984 LD (IY+BERG-RAMBASE),E 2985 LD A,(HL) ; 2986 CP $40 ; 2987 POP BC ; 2988 RET NC ; 2989 2990 PUSH BC ; 2991 CALL OUT_NO <#OUT_NO> 2992 INC HL ; 2993 LD A,D ; 2994 2995 RST _PRINT_A 2996 INC HL ; 2997 INC HL ; 2998 2999 mark_0766: 3000 *COPY_LINE:* 3001 LD (CH_ADD),HL ; 3002 SET 0,(IY+FLAGS-RAMBASE) ; Suppress leading space 3003 3004 mark_076D: 3005 *MORE_LINE:* 3006 LD BC,(X_PTR) ; 3007 LD HL,(CH_ADD) ; 3008 AND A ; 3009 SBC HL,BC ; 3010 JR NZ,TEST_NUM <#TEST_NUM> 3011 3012 LD A,ZX_INV_S ; $B8 ; 3013 3014 RST _PRINT_A 3015 3016 mark_077C: 3017 *TEST_NUM:* 3018 LD HL,(CH_ADD) ; 3019 LD A,(HL) ; 3020 INC HL ; 3021 CALL NUMBER <#NUMBER> 3022 LD (CH_ADD),HL ; 3023 JR Z,MORE_LINE <#MORE_LINE> 3024 3025 CP ZX_CURSOR ; 3026 JR Z,OUT_CURS <#OUT_CURS> 3027 3028 CP ZX_NEWLINE ; 3029 JR Z,OUT_CH <#OUT_CH> 3030 3031 BIT 6,A ; 3032 JR Z,NOT_TOKEN <#NOT_TOKEN> 3033 3034 CALL TOKENS <#TOKENS> 3035 JR MORE_LINE <#MORE_LINE> 3036 ; ___ 3037 3038 mark_079A: 3039 *NOT_TOKEN:* 3040 RST _PRINT_A 3041 JR MORE_LINE <#MORE_LINE> 3042 ; ___ 3043 3044 mark_079D: 3045 *OUT_CURS:* 3046 LD A,(MODE) ; Fetch value of system variable MODE 3047 LD B,$AB ; Prepare an inverse [F] for function cursor. 3048 3049 AND A ; Test for zero - 3050 JR NZ,FLAGS_2 <#FLAGS_2> ; forward if not to FLAGS_2 3051 3052 LD A,(FLAGS) ; Fetch system variable FLAGS. 3053 LD B,ZX_INV_K ; Prepare an inverse [K] for keyword cursor. 3054 3055 mark_07AA: 3056 *FLAGS_2:* 3057 RRA ; 00000?00 -> 000000?0 3058 RRA ; 000000?0 -> 0000000? 3059 AND $01 ; 0000000? 0000000x 3060 3061 ADD A,B ; Possibly [F] -> [G] or [K] -> [L] 3062 3063 CALL PRINT_SP <#PRINT_SP> 3064 JR MORE_LINE <#MORE_LINE> 3065 3066 ------------------------------------------------------------------------ 3067 3068 ; THE *'NUMBER'* SUBROUTINE 3069 ------------------------------------------------------------------------ 3070 3071 3072 mark_07B4: 3073 *NUMBER:* 3074 CP $7E ; 3075 RET NZ ; 3076 3077 INC HL ; 3078 INC HL ; 3079 INC HL ; 3080 INC HL ; 3081 INC HL ; 3082 RET ; 3083 3084 ------------------------------------------------------------------------ 3085 3086 ; THE *'KEYBOARD DECODE'* SUBROUTINE 3087 ------------------------------------------------------------------------ 3088 3089 3090 mark_07BD: 3091 *DECODE:* 3092 LD D,0 ; 3093 SRA B ; shift bit from B to Carry 3094 SBC A,A ; A = 0 - Carry 3095 OR $26 ; %00100110 3096 LD L,5 ; 3097 SUB L ; 3098 3099 mark_07C7: 3100 *KEY_LINE:* 3101 ADD A,L ; 3102 SCF ; Set Carry Flag 3103 RR C ; 3104 JR C,KEY_LINE <#KEY_LINE> 3105 3106 INC C ; 3107 RET NZ ; 3108 3109 LD C,B ; 3110 DEC L ; 3111 LD L,1 ; 3112 JR NZ,KEY_LINE <#KEY_LINE> 3113 3114 LD HL,$007D ; (expr reqd) 3115 LD E,A ; 3116 ADD HL,DE ; 3117 SCF ; Set Carry Flag 3118 RET ; 3119 3120 ------------------------------------------------------------------------ 3121 3122 ; THE *'PRINTING'* SUBROUTINE 3123 ------------------------------------------------------------------------ 3124 3125 3126 mark_07DC: 3127 *LEAD_SP:* 3128 LD A,E ; 3129 AND A ; 3130 RET M ; 3131 3132 JR PRINT_CH <#PRINT_CH> 3133 3134 ; ___ 3135 ; HL is typically -10000, -1000, -100, -10 3136 ; and repeatedly subtracted from BC 3137 ; i.e. it print 3138 ; 3139 ; 3140 mark_07E1: 3141 *OUT_DIGIT:* 3142 XOR A ; assume the digit is zero to begin with 3143 3144 mark_07E2: 3145 *DIGIT_INC:* 3146 ADD HL,BC ; HL += -ve number 3147 INC A ; 3148 JR C,DIGIT_INC <#DIGIT_INC> ; loop 3149 3150 SBC HL,BC ; undo last iteration 3151 DEC A ; undo last iteration 3152 JR Z,LEAD_SP <#LEAD_SP> ; leading zeros shown as spaces 3153 3154 mark_07EB: 3155 *OUT_CODE:* 3156 LD E,ZX_0 ; $1C 3157 ADD A,E ; 3158 3159 mark_07EE: 3160 *OUT_CH:* 3161 AND A ; 3162 JR Z,PRINT_SP <#PRINT_SP> 3163 3164 mark_07F1: 3165 *PRINT_CH:* 3166 RES 0,(IY+FLAGS-RAMBASE) ; signal leading space permitted 3167 3168 mark_07F5: 3169 *PRINT_SP:* 3170 EXX ; 3171 PUSH HL ; 3172 BIT 1,(IY+FLAGS-RAMBASE) ; is printer in use ? 3173 JR NZ,LPRINT_A <#LPRINT_A> 3174 3175 CALL ENTER_CH <#ENTER_CH> 3176 JR PRINT_EXX <#PRINT_EXX> 3177 3178 ; ___ 3179 3180 mark_0802: 3181 *LPRINT_A:* 3182 CALL LPRINT_CH <#LPRINT_CH> 3183 3184 mark_0805: 3185 *PRINT_EXX:* 3186 POP HL ; 3187 EXX ; 3188 RET ; 3189 3190 ; ___ 3191 3192 mark_0808: 3193 *ENTER_CH:* 3194 LD D,A ; 3195 LD BC,(S_POSN) ; 3196 LD A,C ; 3197 CP CHARS_HORIZONTAL+1 ; 3198 JR Z,TEST_LOW <#TEST_LOW> 3199 3200 mark_0812: 3201 *TEST_N_L:* 3202 LD A,ZX_NEWLINE ; 3203 CP D ; 3204 JR Z,WRITE_N_L <#WRITE_N_L> 3205 3206 LD HL,(DF_CC) ; 3207 CP (HL) ; 3208 LD A,D ; 3209 JR NZ,WRITE_CH <#WRITE_CH> 3210 3211 DEC C ; 3212 JR NZ,EXPAND_1 <#EXPAND_1> 3213 3214 INC HL ; 3215 LD (DF_CC),HL ; 3216 LD C,CHARS_HORIZONTAL+1 ; $21 = 33 normally 3217 DEC B ; 3218 LD (S_POSN),BC ; 3219 3220 mark_082C: 3221 *TEST_LOW:* 3222 LD A,B ; 3223 CP (IY+DF_SZ-RAMBASE) 3224 JR Z,REPORT_5 <#REPORT_5> 3225 3226 AND A ; 3227 JR NZ,TEST_N_L <#TEST_N_L> 3228 3229 mark_0835: 3230 *REPORT_5:* 3231 LD L,4 ; 'No more room on screen' 3232 JP ERROR_3 <#ERROR_3> 3233 3234 ; ___ 3235 3236 mark_083A: 3237 *EXPAND_1:* 3238 CALL ONE_SPACE <#ONE_SPACE> 3239 EX DE,HL ; 3240 3241 mark_083E: 3242 *WRITE_CH:* 3243 LD (HL),A ; 3244 INC HL ; 3245 LD (DF_CC),HL ; 3246 DEC (IY+S_POSN_x-RAMBASE) 3247 RET ; 3248 3249 ; ___ 3250 3251 mark_0847: 3252 *WRITE_N_L:* 3253 LD C,CHARS_HORIZONTAL+1 ; $21 = 33 3254 DEC B ; 3255 SET 0,(IY+FLAGS-RAMBASE) ; Suppress leading space 3256 JP LOC_ADDR <#LOC_ADDR> 3257 3258 ------------------------------------------------------------------------ 3259 3260 ; THE *'LPRINT_CH'* SUBROUTINE 3261 ------------------------------------------------------------------------ 3262 3263 ; This routine sends a character to the ZX-Printer placing the code for the 3264 ; character in the Printer Buffer. 3265 ; Note. PR_CC contains the low byte of the buffer address. The high order byte 3266 ; is always constant. 3267 3268 3269 mark_0851: 3270 *LPRINT_CH:* 3271 CP ZX_NEWLINE ; compare to NEWLINE. 3272 JR Z,COPY_BUFF <#COPY_BUFF> ; forward if so 3273 3274 LD C,A ; take a copy of the character in C. 3275 LD A,(PR_CC) ; fetch print location from PR_CC 3276 AND $7F ; ignore bit 7 to form true position. 3277 CP $5C ; compare to 33rd location 3278 3279 LD L,A ; form low-order byte. 3280 LD H,$40 ; the high-order byte is fixed. 3281 3282 CALL Z,COPY_BUFF <#COPY_BUFF> ; to send full buffer to 3283 ; the printer if first 32 bytes full. 3284 ; (this will reset HL to start.) 3285 3286 LD (HL),C ; place character at location. 3287 INC L ; increment - will not cross a 256 boundary. 3288 LD (IY+PR_CC-RAMBASE),L ; update system variable PR_CC 3289 ; automatically resetting bit 7 to show that 3290 ; the buffer is not empty. 3291 RET ; return. 3292 3293 ------------------------------------------------------------------------ 3294 3295 ; THE *'COPY'* COMMAND ROUTINE 3296 ------------------------------------------------------------------------ 3297 3298 ; The full character-mapped screen is copied to the ZX-Printer. 3299 ; All twenty-four text/graphic lines are printed. 3300 3301 mark_0869: 3302 *COPY:* 3303 ; 3304 ; check - is this $16==22 or 24? 3305 ; 3306 ;; LD D,$16 ; prepare to copy twenty four text lines. 3307 LD D,22 ; prepare to copy twenty four text lines. 3308 LD HL,(D_FILE) ; set HL to start of display file from D_FILE. 3309 INC HL ; 3310 JR COPY_D <#COPY_D> ; forward 3311 3312 ; ___ 3313 3314 ; A single character-mapped printer buffer is copied to the ZX-Printer. 3315 3316 mark_0871: 3317 *COPY_BUFF:* 3318 LD D,1 ; prepare to copy a single text line. 3319 LD HL,PRBUFF ; set HL to start of printer buffer PRBUFF. 3320 3321 ; both paths converge here. 3322 3323 mark_0876: 3324 *COPY_D:* 3325 CALL SET_FAST <#SET_FAST> 3326 3327 PUSH BC ; *** preserve BC throughout. 3328 ; a pending character may be present 3329 ; in C from LPRINT_CH 3330 3331 mark_087A: 3332 *COPY_LOOP:* 3333 PUSH HL ; save first character of line pointer. (*) 3334 XOR A ; clear accumulator. 3335 LD E,A ; set pixel line count, range 0-7, to zero. 3336 3337 ; this inner loop deals with each horizontal pixel line. 3338 3339 mark_087D: 3340 *COPY_TIME:* 3341 OUT (IO_PORT_PRINTER),A ; bit 2 reset starts the printer motor 3342 ; with an inactive stylus - bit 7 reset. 3343 POP HL ; pick up first character of line pointer (*) 3344 ; on inner loop. 3345 3346 mark_0880: 3347 *COPY_BRK:* 3348 CALL BREAK_1 <#BREAK_1> 3349 JR C,COPY_CONT <#COPY_CONT> ; forward with no keypress to COPY_CONT 3350 3351 ; else A will hold 11111111 0 3352 3353 RRA ; 0111 1111 3354 OUT (IO_PORT_PRINTER),A ; stop ZX printer motor, de-activate stylus. 3355 3356 mark_0888: 3357 *REPORT_D2:* 3358 RST _ERROR_1 3359 DEFB $0C ; Error Report: BREAK - CONT repeats 3360 3361 ; ___ 3362 3363 mark_088A: 3364 *COPY_CONT:* 3365 IN A,(IO_PORT_PRINTER) ; read from printer port. 3366 ADD A,A ; test bit 6 and 7 3367 JP M,COPY_END <#COPY_END> ; jump forward with no printer to COPY_END 3368 3369 JR NC,COPY_BRK <#COPY_BRK> ; back if stylus not in position to COPY_BRK 3370 3371 PUSH HL ; save first character of line pointer (*) 3372 PUSH DE ; ** preserve character line and pixel line. 3373 3374 LD A,D ; text line count to A? 3375 CP 2 ; sets carry if last line. 3376 SBC A,A ; now $FF if last line else zero. 3377 3378 ; now cleverly prepare a printer control mask setting bit 2 (later moved to 1) 3379 ; of D to slow printer for the last two pixel lines ( E = 6 and 7) 3380 3381 AND E ; and with pixel line offset 0-7 3382 RLCA ; shift to left. 3383 AND E ; and again. 3384 LD D,A ; store control mask in D. 3385 3386 mark_089C: 3387 *COPY_NEXT:* 3388 LD C,(HL) ; load character from screen or buffer. 3389 LD A,C ; save a copy in C for later inverse test. 3390 INC HL ; update pointer for next time. 3391 CP ZX_NEWLINE ; is character a NEWLINE ? 3392 JR Z,COPY_N_L <#COPY_N_L> ; forward, if so, to COPY_N_L 3393 3394 PUSH HL ; * else preserve the character pointer. 3395 3396 SLA A ; (?) multiply by two 3397 ADD A,A ; multiply by four 3398 ADD A,A ; multiply by eight 3399 3400 LD H,$0F ; load H with half the address of character set. 3401 RL H ; now $1E or $1F (with carry) 3402 ADD A,E ; add byte offset 0-7 3403 LD L,A ; now HL addresses character source byte 3404 3405 RL C ; test character, setting carry if inverse. 3406 SBC A,A ; accumulator now $00 if normal, $FF if inverse. 3407 3408 XOR (HL) ; combine with bit pattern at end or ROM. 3409 LD C,A ; transfer the byte to C. 3410 LD B,8 ; count eight bits to output. 3411 3412 mark_08B5: 3413 *COPY_BITS:* 3414 LD A,D ; fetch speed control mask from D. 3415 RLC C ; rotate a bit from output byte to carry. 3416 RRA ; pick up in bit 7, speed bit to bit 1 3417 LD H,A ; store aligned mask in H register. 3418 3419 mark_08BA: 3420 *COPY_WAIT:* 3421 IN A,(IO_PORT_PRINTER) ; read the printer port 3422 RRA ; test for alignment signal from encoder. 3423 JR NC,COPY_WAIT <#COPY_WAIT> ; loop if not present to COPY_WAIT 3424 3425 LD A,H ; control byte to A. 3426 OUT (IO_PORT_PRINTER),A ; and output to printer port. 3427 DJNZ COPY_BITS <#COPY_BITS> ; loop for all eight bits to COPY_BITS 3428 3429 POP HL ; * restore character pointer. 3430 JR COPY_NEXT <#COPY_NEXT> ; back for adjacent character line to COPY_NEXT 3431 3432 ; ___ 3433 3434 ; A NEWLINE has been encountered either following a text line or as the 3435 ; first character of the screen or printer line. 3436 3437 mark_08C7: 3438 *COPY_N_L:* 3439 IN A,(IO_PORT_PRINTER) ; read printer port. 3440 RRA ; wait for encoder signal. 3441 JR NC,COPY_N_L <#COPY_N_L> ; loop back if not to COPY_N_L 3442 3443 LD A,D ; transfer speed mask to A. 3444 RRCA ; rotate speed bit to bit 1. 3445 ; bit 7, stylus control is reset. 3446 OUT (IO_PORT_PRINTER),A ; set the printer speed. 3447 3448 POP DE ; ** restore character line and pixel line. 3449 INC E ; increment pixel line 0-7. 3450 BIT 3,E ; test if value eight reached. 3451 JR Z,COPY_TIME <#COPY_TIME> ; back if not 3452 3453 ; eight pixel lines, a text line have been completed. 3454 3455 POP BC ; lose the now redundant first character 3456 ; pointer 3457 DEC D ; decrease text line count. 3458 JR NZ,COPY_LOOP <#COPY_LOOP> ; back if not zero 3459 3460 LD A,$04 ; stop the already slowed printer motor. 3461 OUT (IO_PORT_PRINTER),A ; output to printer port. 3462 3463 mark_08DE: 3464 *COPY_END:* 3465 CALL SLOW_FAST <#SLOW_FAST> 3466 POP BC ; *** restore preserved BC. 3467 3468 ------------------------------------------------------------------------ 3469 3470 ; THE *'CLEAR PRINTER BUFFER'* SUBROUTINE 3471 ------------------------------------------------------------------------ 3472 3473 ; This subroutine sets 32 bytes of the printer buffer to zero (space) and 3474 ; the 33rd character is set to a NEWLINE. 3475 ; This occurs after the printer buffer is sent to the printer but in addition 3476 ; after the 24 lines of the screen are sent to the printer. 3477 ; Note. This is a logic error as the last operation does not involve the 3478 ; buffer at all. Logically one should be able to use 3479 ; 10 LPRINT "HELLO "; 3480 ; 20 COPY 3481 ; 30 LPRINT ; "WORLD" 3482 ; and expect to see the entire greeting emerge from the printer. 3483 ; Surprisingly this logic error was never discovered and although one can argue 3484 ; if the above is a bug, the repetition of this error on the Spectrum was most 3485 ; definitely a bug. 3486 ; Since the printer buffer is fixed at the end of the system variables, and 3487 ; the print position is in the range $3C - $5C, then bit 7 of the system 3488 ; variable is set to show the buffer is empty and automatically reset when 3489 ; the variable is updated with any print position - neat. 3490 3491 mark_08E2: 3492 *CLEAR_PRB:* 3493 LD HL,PRBUFF_END ; address fixed end of PRBUFF 3494 LD (HL),ZX_NEWLINE ; place a newline at last position. 3495 LD B,32 ; prepare to blank 32 preceding characters. 3496 ; 3497 ; NB the printer is fixed at 32 characters, maybe it can be tweaked ??? 3498 ; 3499 mark_08E9: 3500 *PRB_BYTES:* 3501 DEC HL ; decrement address - could be DEC L. 3502 LD (HL),0 ; place a zero byte. 3503 DJNZ PRB_BYTES <#PRB_BYTES> ; loop for all thirty-two 3504 3505 LD A,L ; fetch character print position. 3506 SET 7,A ; signal the printer buffer is clear. 3507 LD (PR_CC),A ; update one-byte system variable PR_CC 3508 RET ; return. 3509 3510 ------------------------------------------------------------------------ 3511 3512 ; THE *'PRINT AT'* SUBROUTINE 3513 ------------------------------------------------------------------------ 3514 3515 ; 3516 ; 3517 ; 3518 mark_08F5: 3519 *PRINT_AT:* 3520 3521 LD A,CHARS_VERTICAL-1 ; originally 23 3522 SUB B ; 3523 JR C,WRONG_VAL <#WRONG_VAL> 3524 3525 mark_08FA: 3526 *TEST_VAL:* 3527 CP (IY+DF_SZ-RAMBASE) 3528 JP C,REPORT_5 <#REPORT_5> 3529 3530 INC A ; 3531 LD B,A ; 3532 LD A,CHARS_HORIZONTAL-1 ; originally 31 3533 3534 SUB C ; 3535 3536 mark_0905: 3537 *WRONG_VAL:* 3538 JP C,REPORT_B <#REPORT_B> 3539 3540 ADD A,2 ; 3541 LD C,A ; 3542 3543 mark_090B: 3544 *SET_FIELD:* 3545 BIT 1,(IY+FLAGS-RAMBASE) ; Is printer in use? 3546 JR Z,LOC_ADDR <#LOC_ADDR> 3547 3548 LD A,$5D ; 3549 SUB C ; 3550 LD (PR_CC),A ; 3551 RET ; 3552 3553 ------------------------------------------------------------------------ 3554 3555 ; THE *'LOCATE ADDRESS'* ROUTINE 3556 ------------------------------------------------------------------------ 3557 3558 ; 3559 ; I'm guessing this locates the address of a character at X,Y 3560 ; on the screen, with 0,0 being on the bottom left? 3561 ; S_POSN_x equ $4039 3562 ; S_POSN_y equ $403A 3563 ; so when BC is stored there, B is Y and C is X 3564 ; 3565 mark_0918: 3566 *LOC_ADDR:* 3567 LD (S_POSN),BC ; 3568 LD HL,(VARS) ; 3569 LD D,C ; 3570 LD A,CHARS_HORIZONTAL+2 ; $22 == 34 originally. 3571 SUB C ; 3572 LD C,A ; 3573 LD A,ZX_NEWLINE ; 3574 INC B ; 3575 3576 mark_0927: 3577 *LOOK_BACK:* 3578 DEC HL ; 3579 CP (HL) ; 3580 JR NZ,LOOK_BACK <#LOOK_BACK> 3581 3582 DJNZ LOOK_BACK <#LOOK_BACK> 3583 3584 INC HL ; 3585 CPIR ; 3586 DEC HL ; 3587 LD (DF_CC),HL ; 3588 SCF ; Set Carry Flag 3589 RET PO ; 3590 3591 DEC D ; 3592 RET Z ; 3593 3594 PUSH BC ; 3595 CALL MAKE_ROOM <#MAKE_ROOM> 3596 POP BC ; 3597 LD B,C ; 3598 LD H,D ; HL := DE 3599 LD L,E ; 3600 3601 mark_0940: 3602 *EXPAND_2:* 3603 ; 3604 ; Writes B spaces to HL-- 3605 ; 3606 LD (HL),ZX_SPACE ; 3607 DEC HL ; 3608 DJNZ EXPAND_2 <#EXPAND_2> 3609 3610 EX DE,HL ; restore HL 3611 INC HL ; 3612 LD (DF_CC),HL ; 3613 RET ; 3614 3615 ------------------------------------------------------------------------ 3616 3617 ; THE *'EXPAND TOKENS'* SUBROUTINE 3618 ------------------------------------------------------------------------ 3619 3620 3621 mark_094B: 3622 *TOKENS:* 3623 PUSH AF ; 3624 CALL TOKEN_ADD <#TOKEN_ADD> 3625 JR NC,ALL_CHARS <#ALL_CHARS> 3626 3627 BIT 0,(IY+FLAGS-RAMBASE) ; Leading space if set 3628 JR NZ,ALL_CHARS <#ALL_CHARS> 3629 3630 XOR A ; A = 0 = ZX_SPACE 3631 3632 RST _PRINT_A 3633 3634 mark_0959: 3635 *ALL_CHARS:* 3636 LD A,(BC) ; 3637 AND $3F ; truncate to printable values ??? 3638 3639 RST _PRINT_A 3640 LD A,(BC) ; 3641 INC BC ; 3642 ADD A,A ; 3643 JR NC,ALL_CHARS <#ALL_CHARS> 3644 3645 POP BC ; 3646 BIT 7,B ; 3647 RET Z ; 3648 3649 CP ZX_COMMA ; $1A == 26 3650 JR Z,TRAIL_SP <#TRAIL_SP> 3651 3652 CP ZX_S ; $38 == 56 3653 RET C ; 3654 3655 mark_096D: 3656 *TRAIL_SP:* 3657 XOR A ; 3658 SET 0,(IY+FLAGS-RAMBASE) ; Suppress leading space 3659 JP PRINT_SP <#PRINT_SP> 3660 3661 ; ___ 3662 3663 mark_0975: 3664 *TOKEN_ADD:* 3665 PUSH HL ; 3666 LD HL,TOKEN_TABLE <#TOKEN_TABLE> 3667 BIT 7,A ; 3668 JR Z,TEST_HIGH <#TEST_HIGH> 3669 3670 AND $3F ; 3671 3672 mark_097F: 3673 *TEST_HIGH:* 3674 CP $43 ; 3675 JR NC,FOUND <#FOUND> 3676 3677 LD B,A ; 3678 INC B ; 3679 3680 mark_0985: 3681 *WORDS:* 3682 BIT 7,(HL) ; 3683 INC HL ; 3684 JR Z,WORDS <#WORDS> 3685 3686 DJNZ WORDS <#WORDS> 3687 3688 BIT 6,A ; 3689 JR NZ,COMP_FLAG <#COMP_FLAG> 3690 3691 CP $18 ; 3692 3693 mark_0992: 3694 *COMP_FLAG:* 3695 CCF ; Complement Carry Flag 3696 3697 mark_0993: 3698 *FOUND:* 3699 LD B,H ; 3700 LD C,L ; 3701 POP HL ; 3702 RET NC ; 3703 3704 LD A,(BC) ; 3705 ADD A,$E4 ; 3706 RET ; 3707 3708 ------------------------------------------------------------------------ 3709 3710 ; THE *'ONE_SPACE'* SUBROUTINE 3711 ------------------------------------------------------------------------ 3712 3713 3714 mark_099B: 3715 *ONE_SPACE:* 3716 LD BC,$0001 ; 3717 3718 ------------------------------------------------------------------------ 3719 3720 ; THE *'MAKE ROOM'* SUBROUTINE 3721 ------------------------------------------------------------------------ 3722 3723 ; 3724 ; 3725 3726 mark_099E: 3727 *MAKE_ROOM:* 3728 PUSH HL ; 3729 CALL TEST_ROOM <#TEST_ROOM> 3730 POP HL ; 3731 CALL POINTERS <#POINTERS> 3732 LD HL,(STKEND) ; 3733 EX DE,HL ; 3734 LDDR ; Copy Bytes 3735 RET ; 3736 3737 ------------------------------------------------------------------------ 3738 3739 ; THE *'POINTERS'* SUBROUTINE 3740 ------------------------------------------------------------------------ 3741 3742 3743 mark_09AD: 3744 *POINTERS:* 3745 PUSH AF ; 3746 PUSH HL ; 3747 LD HL,D_FILE ; 3748 LD A,$09 ; 3749 3750 mark_09B4: 3751 *NEXT_PTR:* 3752 LD E,(HL) ; 3753 INC HL ; 3754 LD D,(HL) ; 3755 EX (SP),HL ; 3756 AND A ; 3757 SBC HL,DE ; 3758 ADD HL,DE ; 3759 EX (SP),HL ; 3760 JR NC,PTR_DONE <#PTR_DONE> 3761 3762 PUSH DE ; 3763 EX DE,HL ; 3764 ADD HL,BC ; 3765 EX DE,HL ; 3766 LD (HL),D ; 3767 DEC HL ; 3768 LD (HL),E ; 3769 INC HL ; 3770 POP DE ; 3771 3772 mark_09C8: 3773 *PTR_DONE:* 3774 INC HL ; 3775 DEC A ; 3776 JR NZ,NEXT_PTR <#NEXT_PTR> 3777 3778 EX DE,HL ; 3779 POP DE ; 3780 POP AF ; 3781 AND A ; 3782 SBC HL,DE ; 3783 LD B,H ; 3784 LD C,L ; 3785 INC BC ; 3786 ADD HL,DE ; 3787 EX DE,HL ; 3788 RET ; 3789 3790 ------------------------------------------------------------------------ 3791 3792 ; THE *'LINE ADDRESS'* SUBROUTINE 3793 ------------------------------------------------------------------------ 3794 3795 3796 mark_09D8: 3797 *LINE_ADDR:* 3798 PUSH HL ; 3799 LD HL,USER_RAM ; 3800 LD D,H ; 3801 LD E,L ; 3802 3803 mark_09DE: 3804 *NEXT_TEST:* 3805 POP BC ; 3806 CALL CP_LINES <#CP_LINES> 3807 RET NC ; 3808 3809 PUSH BC ; 3810 CALL NEXT_ONE <#NEXT_ONE> 3811 EX DE,HL ; 3812 JR NEXT_TEST <#NEXT_TEST> 3813 3814 ------------------------------------------------------------------------ 3815 3816 ; THE *'COMPARE LINE NUMBERS'* SUBROUTINE 3817 ------------------------------------------------------------------------ 3818 3819 3820 mark_09EA: 3821 *CP_LINES:* 3822 LD A,(HL) ; 3823 CP B ; 3824 RET NZ ; 3825 3826 INC HL ; 3827 LD A,(HL) ; 3828 DEC HL ; 3829 CP C ; 3830 RET ; 3831 3832 ------------------------------------------------------------------------ 3833 3834 ; THE *'NEXT LINE OR VARIABLE'* SUBROUTINE 3835 ------------------------------------------------------------------------ 3836 3837 3838 mark_09F2: 3839 *NEXT_ONE:* 3840 PUSH HL ; 3841 LD A,(HL) ; 3842 CP $40 ; 3843 JR C,LINES <#LINES> 3844 3845 BIT 5,A ; 3846 JR Z,NEXT_0_4 <#NEXT_0_4> ; skip forward 3847 3848 ADD A,A ; 3849 JP M,NEXT_PLUS_FIVE <#NEXT_PLUS_FIVE> 3850 3851 CCF ; Complement Carry Flag 3852 3853 mark_0A01: 3854 *NEXT_PLUS_FIVE:* 3855 LD BC,$0005 ; 3856 JR NC,NEXT_LETT <#NEXT_LETT> 3857 3858 LD C,$11 ; 17 3859 3860 mark_0A08: 3861 *NEXT_LETT:* 3862 RLA ; 3863 INC HL ; 3864 LD A,(HL) ; 3865 JR NC,NEXT_LETT <#NEXT_LETT> ; loop 3866 3867 JR NEXT_ADD <#NEXT_ADD> 3868 ; ___ 3869 3870 mark_0A0F: 3871 *LINES:* 3872 INC HL ; 3873 3874 mark_0A10: 3875 *NEXT_0_4:* 3876 INC HL ; BC = word at HL++ 3877 LD C,(HL) ; 3878 INC HL ; 3879 LD B,(HL) ; 3880 INC HL ; 3881 3882 mark_0A15: 3883 *NEXT_ADD:* 3884 ADD HL,BC ; 3885 POP DE ; 3886 3887 ------------------------------------------------------------------------ 3888 3889 ; THE *'DIFFERENCE'* SUBROUTINE 3890 ------------------------------------------------------------------------ 3891 3892 3893 mark_0A17: 3894 *DIFFER:* 3895 AND A ; 3896 SBC HL,DE ; 3897 LD B,H ; BC := (HL-DE) 3898 LD C,L ; 3899 ADD HL,DE ; 3900 EX DE,HL ; DE := old HL ??? 3901 RET ; 3902 3903 ------------------------------------------------------------------------ 3904 3905 ; THE *'LINE_ENDS'* SUBROUTINE 3906 ------------------------------------------------------------------------ 3907 3908 3909 mark_0A1F: 3910 *LINE_ENDS:* 3911 LD B,(IY+DF_SZ-RAMBASE) 3912 PUSH BC ; 3913 CALL B_LINES <#B_LINES> 3914 POP BC ; 3915 DEC B ; 3916 JR B_LINES <#B_LINES> 3917 3918 ------------------------------------------------------------------------ 3919 3920 ; THE *'CLS'* COMMAND ROUTINE 3921 ------------------------------------------------------------------------ 3922 3923 3924 mark_0A2A: 3925 *CLS:* 3926 LD B,CHARS_VERTICAL ; number of lines to clear. $18 = 24 originally. 3927 3928 mark_0A2C: 3929 *B_LINES:* 3930 RES 1,(IY+FLAGS-RAMBASE) ; Signal printer not in use 3931 LD C,CHARS_HORIZONTAL+1 ; $21 ; extra 1 is for HALT opcode ? 3932 PUSH BC ; 3933 CALL LOC_ADDR <#LOC_ADDR> 3934 POP BC ; 3935 LD A,(RAMTOP+1) ; is RAMTOP_hi 3936 CP $4D ; 3937 JR C,COLLAPSED <#COLLAPSED> 3938 ; 3939 ; If RAMTOP less then 4D00, RAM less than D00 = 3.25 K, 3940 ; uses collapsed display. 3941 ; 3942 3943 SET 7,(IY+S_POSN_y-RAMBASE) 3944 3945 mark_0A42: 3946 *CLEAR_LOC:* 3947 XOR A ; prepare a space 3948 CALL PRINT_SP <#PRINT_SP> ; prints a space 3949 LD HL,(S_POSN) ; 3950 LD A,L ; 3951 OR H ; 3952 AND $7E ; 3953 JR NZ,CLEAR_LOC <#CLEAR_LOC> 3954 3955 JP LOC_ADDR <#LOC_ADDR> 3956 3957 ; ___ 3958 3959 mark_0A52: 3960 *COLLAPSED:* 3961 LD D,H ; DE := HL 3962 LD E,L ; 3963 DEC HL ; 3964 LD C,B ; 3965 LD B,0 ; Will loop 256 times 3966 LDIR ; Copy Bytes 3967 LD HL,(VARS) ; 3968 3969 ------------------------------------------------------------------------ 3970 3971 ; THE *'RECLAIMING'* SUBROUTINES 3972 ------------------------------------------------------------------------ 3973 3974 3975 mark_0A5D: 3976 *RECLAIM_1:* 3977 CALL DIFFER <#DIFFER> 3978 3979 mark_0A60: 3980 *RECLAIM_2:* 3981 PUSH BC ; 3982 LD A,B ; 3983 CPL ; 3984 LD B,A ; 3985 LD A,C ; 3986 CPL ; 3987 LD C,A ; 3988 INC BC ; 3989 CALL POINTERS <#POINTERS> 3990 EX DE,HL ; 3991 POP HL ; 3992 ADD HL,DE ; 3993 PUSH DE ; 3994 LDIR ; Copy Bytes 3995 POP HL ; 3996 RET ; 3997 3998 ------------------------------------------------------------------------ 3999 4000 ; THE *'E_LINE NUMBER'* SUBROUTINE 4001 ------------------------------------------------------------------------ 4002 4003 4004 mark_0A73: 4005 *E_LINE_NUM:* 4006 LD HL,(E_LINE) ; 4007 CALL TEMP_PTR2 <#TEMP_PTR2> 4008 4009 RST _GET_CHAR 4010 BIT 5,(IY+FLAGX-RAMBASE) 4011 RET NZ ; 4012 4013 LD HL,MEM_0_1st ; 4014 LD (STKEND),HL ; 4015 CALL INT_TO_FP <#INT_TO_FP> 4016 CALL FP_TO_BC <#FP_TO_BC> 4017 JR C,NO_NUMBER <#NO_NUMBER> ; to NO_NUMBER 4018 4019 LD HL,-10000 ; $D8F0 ; value '-10000' 4020 ADD HL,BC ; 4021 4022 mark_0A91: 4023 *NO_NUMBER:* 4024 JP C,REPORT_C <#REPORT_C> ; to REPORT_C 4025 4026 CP A ; 4027 JP SET_MIN <#SET_MIN> 4028 4029 ------------------------------------------------------------------------ 4030 4031 ; THE *'REPORT AND LINE NUMBER'* PRINTING SUBROUTINES 4032 ------------------------------------------------------------------------ 4033 4034 4035 mark_0A98: 4036 *OUT_NUM:* 4037 PUSH DE ; 4038 PUSH HL ; 4039 XOR A ; 4040 BIT 7,B ; 4041 JR NZ,UNITS <#UNITS> 4042 4043 LD H,B ; HL := BC 4044 LD L,C ; 4045 LD E,$FF ; 4046 JR THOUSAND <#THOUSAND> 4047 ; ___ 4048 4049 mark_0AA5: 4050 *OUT_NO:* 4051 PUSH DE ; 4052 LD D,(HL) ; 4053 INC HL ; 4054 LD E,(HL) ; 4055 PUSH HL ; 4056 EX DE,HL ; 4057 LD E,ZX_SPACE ; set E to leading space. 4058 4059 mark_0AAD: 4060 *THOUSAND:* 4061 LD BC,-1000 ; $FC18 ; 4062 CALL OUT_DIGIT <#OUT_DIGIT> 4063 LD BC,-100 ; $FF9C ; 4064 CALL OUT_DIGIT <#OUT_DIGIT> 4065 LD C,-10 ; $F6 ; B is already FF, so saves a byte. 4066 CALL OUT_DIGIT <#OUT_DIGIT> 4067 LD A,L ; 4068 4069 mark_0ABF: 4070 *UNITS:* 4071 CALL OUT_CODE <#OUT_CODE> 4072 POP HL ; 4073 POP DE ; 4074 RET ; 4075 4076 ------------------------------------------------------------------------ 4077 4078 ; THE *'UNSTACK_Z'* SUBROUTINE 4079 ------------------------------------------------------------------------ 4080 4081 4082 ; This subroutine is used to return early from a routine when checking syntax. 4083 ; On the ZX81 the same routines that execute commands also check the syntax 4084 ; on line entry. This enables precise placement of the error marker in a line 4085 ; that fails syntax. 4086 ; The sequence CALL SYNTAX_Z ; RET Z can be replaced by a call to this routine 4087 ; although it has not replaced every occurrence of the above two instructions. 4088 ; Even on the ZX80 this routine was not fully utilized. 4089 4090 mark_0AC5: 4091 *UNSTACK_Z:* 4092 CALL SYNTAX_Z <#SYNTAX_Z> ; resets the ZERO flag if 4093 ; checking syntax. 4094 POP HL ; drop the return address. 4095 RET Z ; return to previous calling routine if 4096 ; checking syntax. 4097 4098 JP (HL) ; else jump to the continuation address in 4099 ; the calling routine as RET would have done. 4100 4101 ------------------------------------------------------------------------ 4102 4103 ; THE *'LPRINT'* COMMAND ROUTINE 4104 ------------------------------------------------------------------------ 4105 4106 ; 4107 ; 4108 4109 mark_0ACB: 4110 *LPRINT:* 4111 SET 1,(IY+FLAGS-RAMBASE) ; Signal printer in use 4112 4113 ------------------------------------------------------------------------ 4114 4115 ; THE *'PRINT'* COMMAND ROUTINE 4116 ------------------------------------------------------------------------ 4117 4118 4119 mark_0ACF: 4120 *PRINT:* 4121 LD A,(HL) ; 4122 CP ZX_NEWLINE ; 4123 JP Z,PRINT_END <#PRINT_END> ; to PRINT_END 4124 4125 mark_0AD5: 4126 *PRINT_1:* 4127 SUB ZX_COMMA ; $1A == 26 4128 ADC A,$00 ; 4129 JR Z,SPACING <#SPACING> ; to SPACING 4130 ; 4131 ; Compare with AT, 4132 ; less comma recently subtracted. 4133 ; 4134 CP ZX_AT-ZX_COMMA ; $A7 == 167 4135 JR NZ,NOT_AT <#NOT_AT> ; 4136 4137 4138 RST _NEXT_CHAR 4139 CALL CLASS_6 <#CLASS_6> 4140 CP ZX_COMMA ; $1A = 26 4141 JP NZ,REPORT_C <#REPORT_C> ; 4142 4143 RST _NEXT_CHAR 4144 CALL CLASS_6 <#CLASS_6> 4145 CALL SYNTAX_ON <#SYNTAX_ON> 4146 4147 RST _FP_CALC ;; 4148 DEFB __exchange ;; 4149 DEFB __end_calc ;; 4150 4151 CALL STK_TO_BC <#STK_TO_BC> 4152 CALL PRINT_AT <#PRINT_AT> 4153 JR PRINT_ON <#PRINT_ON> 4154 ; ___ 4155 4156 mark_0AFA: 4157 *NOT_AT:* 4158 CP ZX_TAB-ZX_COMMA ; $A8 == 168 4159 JR NZ,NOT_TAB <#NOT_TAB> 4160 4161 4162 RST _NEXT_CHAR 4163 CALL CLASS_6 <#CLASS_6> 4164 CALL SYNTAX_ON <#SYNTAX_ON> 4165 CALL STK_TO_A <#STK_TO_A> 4166 JP NZ,REPORT_B <#REPORT_B> 4167 4168 AND $1F ; truncate to 0 to 31 characters ??? 4169 LD C,A ; 4170 BIT 1,(IY+FLAGS-RAMBASE) ; Is printer in use 4171 JR Z,TAB_TEST <#TAB_TEST> 4172 4173 SUB (IY+PR_CC-RAMBASE) 4174 SET 7,A ; 4175 ADD A,$3C ; 60 4176 CALL NC,COPY_BUFF <#COPY_BUFF> 4177 4178 mark_0B1E: 4179 *TAB_TEST:* 4180 ADD A,(IY+S_POSN_x-RAMBASE) ; screen position X 4181 CP CHARS_HORIZONTAL+1 ; 33 (characters horizontal plus newline ???) 4182 LD A,(S_POSN_y) ; screen position Y 4183 SBC A,1 ; 4184 CALL TEST_VAL <#TEST_VAL> 4185 SET 0,(IY+FLAGS-RAMBASE) ; sv FLAGS - Suppress leading space 4186 JR PRINT_ON <#PRINT_ON> 4187 ; ___ 4188 4189 mark_0B31: 4190 *NOT_TAB:* 4191 CALL SCANNING <#SCANNING> 4192 CALL PRINT_STK <#PRINT_STK> 4193 4194 mark_0B37: 4195 *PRINT_ON:* 4196 RST _GET_CHAR 4197 SUB ZX_COMMA ; $1A 4198 ADC A,0 ; 4199 JR Z,SPACING <#SPACING> 4200 4201 CALL CHECK_END <#CHECK_END> 4202 JP PRINT_END <#PRINT_END> 4203 ; ___ 4204 mark_0B44: 4205 *SPACING:* 4206 CALL NC,FIELD <#FIELD> 4207 4208 RST _NEXT_CHAR 4209 CP ZX_NEWLINE ; 4210 RET Z ; 4211 4212 JP PRINT_1 <#PRINT_1> 4213 ; ___ 4214 mark_0B4E: 4215 *SYNTAX_ON:* 4216 CALL SYNTAX_Z <#SYNTAX_Z> 4217 RET NZ ; 4218 4219 POP HL ; 4220 JR PRINT_ON <#PRINT_ON> 4221 ; ___ 4222 mark_0B55: 4223 *PRINT_STK:* 4224 CALL UNSTACK_Z <#UNSTACK_Z> 4225 BIT 6,(IY+FLAGS-RAMBASE) ; Numeric or string result? 4226 CALL Z,STK_FETCH <#STK_FETCH> 4227 JR Z,PR_STR_4 <#PR_STR_4> 4228 4229 JP PRINT_FP <#PRINT_FP> ; jump forward 4230 ; ___ 4231 4232 mark_0B64: 4233 *PR_STR_1:* 4234 LD A,ZX_QUOTE ; $0B 4235 4236 mark_0B66: 4237 *PR_STR_2:* 4238 RST _PRINT_A 4239 4240 mark_0B67: 4241 *PR_STR_3:* 4242 LD DE,(X_PTR) ; 4243 4244 mark_0B6B: 4245 *PR_STR_4:* 4246 LD A,B ; 4247 OR C ; 4248 DEC BC ; 4249 RET Z ; 4250 4251 LD A,(DE) ; 4252 INC DE ; 4253 LD (X_PTR),DE ; 4254 BIT 6,A ; 4255 JR Z,PR_STR_2 <#PR_STR_2> 4256 4257 CP $C0 ; 4258 JR Z,PR_STR_1 <#PR_STR_1> 4259 4260 PUSH BC ; 4261 CALL TOKENS <#TOKENS> 4262 POP BC ; 4263 JR PR_STR_3 <#PR_STR_3> 4264 4265 ; ___ 4266 4267 mark_0B84: 4268 *PRINT_END:* 4269 CALL UNSTACK_Z <#UNSTACK_Z> 4270 LD A,ZX_NEWLINE ; 4271 4272 RST _PRINT_A 4273 RET ; 4274 4275 ; ___ 4276 4277 mark_0B8B: 4278 *FIELD:* 4279 CALL UNSTACK_Z <#UNSTACK_Z> 4280 SET 0,(IY+FLAGS-RAMBASE) ; Suppress leading space 4281 XOR A ; 4282 4283 RST _PRINT_A 4284 LD BC,(S_POSN) ; 4285 LD A,C ; 4286 BIT 1,(IY+FLAGS-RAMBASE) ; Is printer in use 4287 JR Z,CENTRE <#CENTRE> 4288 4289 LD A,$5D ; 4290 SUB (IY+PR_CC-RAMBASE) 4291 4292 mark_0BA4: 4293 *CENTRE:* 4294 LD C,$11 ; 4295 CP C ; 4296 JR NC,RIGHT <#RIGHT> 4297 4298 LD C,$01 ; 4299 4300 mark_0BAB: 4301 *RIGHT:* 4302 CALL SET_FIELD <#SET_FIELD> 4303 RET ; 4304 4305 ------------------------------------------------------------------------ 4306 4307 ; THE *'PLOT AND UNPLOT'* COMMAND ROUTINES 4308 ------------------------------------------------------------------------ 4309 4310 4311 mark_0BAF: 4312 *PLOT_UNPLOT:* 4313 ; 4314 ; Of the 24 lines, only top 22 ar used for plotting. 4315 ; 4316 CALL STK_TO_BC <#STK_TO_BC> 4317 LD (COORDS_x),BC ; 4318 ;; LD A,$2B ; originally $2B == 32+11 = 43 = 2*22-1 4319 LD A,2*(CHARS_VERTICAL-2)-1 ; 4320 SUB B ; 4321 JP C,REPORT_B <#REPORT_B> 4322 4323 LD B,A ; 4324 LD A,$01 ; 4325 SRA B ; 4326 JR NC,COLUMNS <#COLUMNS> 4327 4328 LD A,$04 ; 4329 4330 mark_0BC5: 4331 *COLUMNS:* 4332 SRA C ; 4333 JR NC,FIND_ADDR <#FIND_ADDR> 4334 4335 RLCA ; 4336 4337 mark_0BCA: 4338 *FIND_ADDR:* 4339 PUSH AF ; 4340 CALL PRINT_AT <#PRINT_AT> 4341 LD A,(HL) ; 4342 RLCA ; 4343 CP ZX_BRACKET_LEFT ; $10 4344 JR NC,TABLE_PTR <#TABLE_PTR> 4345 4346 RRCA ; 4347 JR NC,SQ_SAVED <#SQ_SAVED> 4348 4349 XOR $8F ; 4350 4351 mark_0BD9: 4352 *SQ_SAVED:* 4353 LD B,A ; 4354 4355 mark_0BDA: 4356 *TABLE_PTR:* 4357 LD DE,P_UNPLOT <#P_UNPLOT> ; Address: P_UNPLOT 4358 LD A,(T_ADDR) ; get T_ADDR_lo 4359 SUB E ; 4360 JP M,PLOT <#PLOT> 4361 4362 POP AF ; 4363 CPL ; 4364 AND B ; 4365 JR UNPLOT <#UNPLOT> 4366 4367 ; ___ 4368 4369 mark_0BE9: 4370 *PLOT:* 4371 POP AF ; 4372 OR B ; 4373 4374 mark_0BEB: 4375 *UNPLOT:* 4376 CP 8 ; Only apply to graphic characters (0 to 7) 4377 JR C,PLOT_END <#PLOT_END> 4378 4379 XOR $8F ; binary 1000 1111 4380 4381 mark_0BF1: 4382 *PLOT_END:* 4383 EXX ; 4384 4385 RST _PRINT_A 4386 EXX ; 4387 RET ; 4388 4389 ------------------------------------------------------------------------ 4390 4391 ; THE *'STACK_TO_BC'* SUBROUTINE 4392 ------------------------------------------------------------------------ 4393 4394 mark_0BF5: 4395 *STK_TO_BC:* 4396 CALL STK_TO_A <#STK_TO_A> 4397 LD B,A ; 4398 PUSH BC ; 4399 CALL STK_TO_A <#STK_TO_A> 4400 LD E,C ; 4401 POP BC ; 4402 LD D,C ; 4403 LD C,A ; 4404 RET ; 4405 4406 ------------------------------------------------------------------------ 4407 4408 ; THE *'STACK_TO_A'* SUBROUTINE 4409 ------------------------------------------------------------------------ 4410 4411 4412 mark_0C02: 4413 *STK_TO_A:* 4414 CALL FP_TO_A <#FP_TO_A> 4415 JP C,REPORT_B <#REPORT_B> 4416 4417 LD C,$01 ; 4418 RET Z ; 4419 4420 LD C,$FF ; 4421 RET ; 4422 4423 ------------------------------------------------------------------------ 4424 4425 ; THE *'SCROLL'* SUBROUTINE 4426 ------------------------------------------------------------------------ 4427 4428 4429 mark_0C0E: 4430 *SCROLL:* 4431 LD B,(IY+DF_SZ-RAMBASE) 4432 LD C,CHARS_HORIZONTAL+1 ; 4433 CALL LOC_ADDR <#LOC_ADDR> 4434 CALL ONE_SPACE <#ONE_SPACE> 4435 LD A,(HL) ; 4436 LD (DE),A ; 4437 INC (IY+S_POSN_y-RAMBASE) 4438 LD HL,(D_FILE) ; 4439 INC HL ; 4440 LD D,H ; 4441 LD E,L ; 4442 CPIR ; 4443 JP RECLAIM_1 <#RECLAIM_1> 4444 4445 ------------------------------------------------------------------------ 4446 4447 ; THE *'SYNTAX'* TABLES 4448 ------------------------------------------------------------------------ 4449 4450 4451 ; i) The Offset table 4452 4453 mark_0C29: 4454 *offset_t:* 4455 DEFB P_LPRINT <#P_LPRINT> - $ ; 8B offset 4456 DEFB P_LLIST <#P_LLIST> - $ ; 8D offset 4457 DEFB P_STOP <#P_STOP> - $ ; 2D offset 4458 DEFB P_SLOW <#P_SLOW> - $ ; 7F offset 4459 DEFB P_FAST <#P_FAST> - $ ; 81 offset 4460 DEFB P_NEW <#P_NEW> - $ ; 49 offset 4461 DEFB P_SCROLL <#P_SCROLL> - $ ; 75 offset 4462 DEFB P_CONT <#P_CONT> - $ ; 5F offset 4463 DEFB P_DIM <#P_DIM> - $ ; 40 offset 4464 DEFB P_REM <#P_REM> - $ ; 42 offset 4465 DEFB P_FOR <#P_FOR> - $ ; 2B offset 4466 DEFB P_GOTO <#P_GOTO> - $ ; 17 offset 4467 DEFB P_GOSUB <#P_GOSUB> - $ ; 1F offset 4468 DEFB P_INPUT <#P_INPUT> - $ ; 37 offset 4469 DEFB P_LOAD <#P_LOAD> - $ ; 52 offset 4470 DEFB P_LIST <#P_LIST> - $ ; 45 offset 4471 DEFB P_LET <#P_LET> - $ ; 0F offset 4472 DEFB P_PAUSE <#P_PAUSE> - $ ; 6D offset 4473 DEFB P_NEXT <#P_NEXT> - $ ; 2B offset 4474 DEFB P_POKE <#P_POKE> - $ ; 44 offset 4475 DEFB P_PRINT <#P_PRINT> - $ ; 2D offset 4476 DEFB P_PLOT <#P_PLOT> - $ ; 5A offset 4477 DEFB P_RUN <#P_RUN> - $ ; 3B offset 4478 DEFB P_SAVE <#P_SAVE> - $ ; 4C offset 4479 DEFB P_RAND <#P_RAND> - $ ; 45 offset 4480 DEFB P_IF <#P_IF> - $ ; 0D offset 4481 DEFB P_CLS <#P_CLS> - $ ; 52 offset 4482 DEFB P_UNPLOT <#P_UNPLOT> - $ ; 5A offset 4483 DEFB P_CLEAR <#P_CLEAR> - $ ; 4D offset 4484 DEFB P_RETURN <#P_RETURN> - $ ; 15 offset 4485 DEFB P_COPY <#P_COPY> - $ ; 6A offset 4486 ------------------------------------------------------------------------ 4487 4488 ; ii) The parameter table. 4489 4490 mark_0C48: 4491 *P_LET:* 4492 DEFB _CLASS_01 ; A variable is required. 4493 DEFB ZX_EQUAL ; Separator: '=' 4494 DEFB _CLASS_02 ; An expression, numeric or string, 4495 ; must follow. 4496 4497 mark_0C4B: 4498 *P_GOTO:* 4499 DEFB _CLASS_06 ; A numeric expression must follow. 4500 DEFB _CLASS_00 ; No further operands. 4501 DEFW GOTO <#GOTO> 4502 4503 mark_0C4F: 4504 *P_IF:* 4505 DEFB _CLASS_06 ; A numeric expression must follow. 4506 DEFB ZX_THEN ; Separator: 'THEN' 4507 DEFB _CLASS_05 ; Variable syntax checked entirely 4508 ; by routine. 4509 DEFW IF <#IF> 4510 4511 mark_0C54: 4512 *P_GOSUB:* 4513 DEFB _CLASS_06 ; A numeric expression must follow. 4514 DEFB _CLASS_00 ; No further operands. 4515 DEFW GOSUB <#GOSUB> 4516 4517 mark_0C58: 4518 *P_STOP:* 4519 DEFB _CLASS_00 ; No further operands. 4520 DEFW STOP <#STOP> 4521 4522 mark_0C5B: 4523 *P_RETURN:* 4524 DEFB _CLASS_00 ; No further operands. 4525 DEFW RETURN <#RETURN> 4526 4527 mark_0C5E: 4528 *P_FOR:* 4529 DEFB _CLASS_04 ; A single character variable must 4530 ; follow. 4531 DEFB ZX_EQUAL ; Separator: '=' 4532 DEFB _CLASS_06 ; A numeric expression must follow. 4533 DEFB ZX_TO ; Separator: 'TO' 4534 DEFB _CLASS_06 ; A numeric expression must follow. 4535 DEFB _CLASS_05 ; Variable syntax checked entirely 4536 ; by routine. 4537 DEFW FOR <#FOR> 4538 4539 mark_0C66: 4540 *P_NEXT:* 4541 DEFB _CLASS_04 ; A single character variable must 4542 ; follow. 4543 DEFB _CLASS_00 ; No further operands. 4544 DEFW NEXT <#NEXT> 4545 4546 mark_0C6A: 4547 *P_PRINT:* 4548 DEFB _CLASS_05 ; Variable syntax checked entirely 4549 ; by routine. 4550 DEFW PRINT <#PRINT> ; not LPRINT ??? 4551 4552 mark_0C6D: 4553 *P_INPUT:* 4554 DEFB _CLASS_01 ; A variable is required. 4555 DEFB _CLASS_00 ; No further operands. 4556 DEFW INPUT <#INPUT> 4557 4558 mark_0C71: 4559 *P_DIM:* 4560 DEFB _CLASS_05 ; Variable syntax checked entirely 4561 ; by routine. 4562 DEFW DIM <#DIM> 4563 4564 mark_0C74: 4565 *P_REM:* 4566 DEFB _CLASS_05 ; Variable syntax checked entirely 4567 ; by routine. 4568 DEFW REM <#REM> 4569 4570 mark_0C77: 4571 *P_NEW:* 4572 DEFB _CLASS_00 ; No further operands. 4573 DEFW NEW <#NEW> 4574 4575 mark_0C7A: 4576 *P_RUN:* 4577 DEFB _CLASS_03 ; A numeric expression may follow 4578 ; else default to zero. 4579 DEFW RUN <#RUN> 4580 4581 mark_0C7D: 4582 *P_LIST:* 4583 DEFB _CLASS_03 ; A numeric expression may follow 4584 ; else default to zero. 4585 DEFW LIST <#LIST> 4586 4587 mark_0C80: 4588 *P_POKE:* 4589 DEFB _CLASS_06 ; A numeric expression must follow. 4590 DEFB ZX_COMMA ; Separator: ',' 4591 DEFB _CLASS_06 ; A numeric expression must follow. 4592 DEFB _CLASS_00 ; No further operands. 4593 DEFW POKE <#POKE> 4594 4595 mark_0C86: 4596 *P_RAND:* 4597 DEFB _CLASS_03 ; A numeric expression may follow 4598 ; else default to zero. 4599 DEFW RAND <#RAND> 4600 4601 mark_0C89: 4602 *P_LOAD:* 4603 DEFB _CLASS_05 ; Variable syntax checked entirely 4604 ; by routine. 4605 DEFW LOAD <#LOAD> 4606 4607 mark_0C8C: 4608 *P_SAVE:* 4609 DEFB _CLASS_05 ; Variable syntax checked entirely 4610 ; by routine. 4611 DEFW SAVE <#SAVE> 4612 4613 mark_0C8F: 4614 *P_CONT:* 4615 DEFB _CLASS_00 ; No further operands. 4616 DEFW CONT <#CONT> 4617 4618 mark_0C92: 4619 *P_CLEAR:* 4620 DEFB _CLASS_00 ; No further operands. 4621 DEFW CLEAR <#CLEAR> 4622 4623 mark_0C95: 4624 *P_CLS:* 4625 DEFB _CLASS_00 ; No further operands. 4626 DEFW CLS <#CLS> 4627 4628 mark_0C98: 4629 *P_PLOT:* 4630 DEFB _CLASS_06 ; A numeric expression must follow. 4631 DEFB ZX_COMMA ; Separator: ',' 4632 DEFB _CLASS_06 ; A numeric expression must follow. 4633 DEFB _CLASS_00 ; No further operands. 4634 DEFW PLOT_UNPLOT <#PLOT_UNPLOT> 4635 4636 mark_0C9E: 4637 *P_UNPLOT:* 4638 DEFB _CLASS_06 ; A numeric expression must follow. 4639 DEFB ZX_COMMA ; Separator: ',' 4640 DEFB _CLASS_06 ; A numeric expression must follow. 4641 DEFB _CLASS_00 ; No further operands. 4642 DEFW PLOT_UNPLOT <#PLOT_UNPLOT> 4643 4644 mark_0CA4: 4645 *P_SCROLL:* 4646 DEFB _CLASS_00 ; No further operands. 4647 DEFW SCROLL <#SCROLL> 4648 4649 mark_0CA7: 4650 *P_PAUSE:* 4651 DEFB _CLASS_06 ; A numeric expression must follow. 4652 DEFB _CLASS_00 ; No further operands. 4653 DEFW PAUSE <#PAUSE> 4654 4655 mark_0CAB: 4656 *P_SLOW:* 4657 DEFB _CLASS_00 ; No further operands. 4658 DEFW SLOW <#SLOW> 4659 4660 mark_0CAE: 4661 *P_FAST:* 4662 DEFB _CLASS_00 ; No further operands. 4663 DEFW FAST <#FAST> 4664 4665 mark_0CB1: 4666 *P_COPY:* 4667 DEFB _CLASS_00 ; No further operands. 4668 DEFW COPY <#COPY> 4669 4670 mark_0CB4: 4671 *P_LPRINT:* 4672 DEFB _CLASS_05 ; Variable syntax checked entirely 4673 ; by routine. 4674 DEFW LPRINT <#LPRINT> 4675 4676 mark_0CB7: 4677 *P_LLIST:* 4678 DEFB _CLASS_03 ; A numeric expression may follow 4679 ; else default to zero. 4680 DEFW LLIST <#LLIST> 4681 4682 4683 ------------------------------------------------------------------------ 4684 4685 ; THE *'LINE SCANNING'* ROUTINE 4686 ------------------------------------------------------------------------ 4687 4688 4689 mark_0CBA: 4690 *LINE_SCAN:* 4691 LD (IY+FLAGS-RAMBASE),1 4692 CALL E_LINE_NUM <#E_LINE_NUM> 4693 4694 mark_0CC1: 4695 *LINE_RUN:* 4696 CALL SET_MIN <#SET_MIN> 4697 LD HL,ERR_NR ; 4698 LD (HL),$FF ; 4699 LD HL,FLAGX ; 4700 BIT 5,(HL) ; 4701 JR Z,LINE_NULL <#LINE_NULL> 4702 4703 CP $E3 ; 'STOP' ? 4704 LD A,(HL) ; 4705 JP NZ,INPUT_REP <#INPUT_REP> 4706 4707 CALL SYNTAX_Z <#SYNTAX_Z> 4708 RET Z ; 4709 4710 4711 RST _ERROR_1 4712 DEFB $0C ; Error Report: BREAK - CONT repeats 4713 4714 4715 ------------------------------------------------------------------------ 4716 4717 ; THE *'STOP'* COMMAND ROUTINE 4718 ------------------------------------------------------------------------ 4719 4720 ; 4721 ; 4722 4723 mark_0CDC: 4724 *STOP:* 4725 RST _ERROR_1 4726 DEFB $08 ; Error Report: STOP statement 4727 ; ___ 4728 4729 ; the interpretation of a line continues with a check for just spaces 4730 ; followed by a carriage return. 4731 ; The IF command also branches here with a true value to execute the 4732 ; statement after the THEN but the statement can be null so 4733 ; 10 IF 1 = 1 THEN 4734 ; passes syntax (on all ZX computers). 4735 4736 mark_0CDE: 4737 *LINE_NULL:* 4738 RST _GET_CHAR 4739 LD B,$00 ; prepare to index - early. 4740 CP ZX_NEWLINE ; compare to NEWLINE. 4741 RET Z ; return if so. 4742 4743 4744 4745 4746 4747 LD C,A ; transfer character to C. 4748 4749 RST _NEXT_CHAR ; advances. 4750 LD A,C ; character to A 4751 SUB $E1 ; subtract 'LPRINT' - lowest command. 4752 JR C,REPORT_C2 <#REPORT_C2> ; forward if less 4753 4754 LD C,A ; reduced token to C 4755 LD HL,offset_t <#offset_t> ; set HL to address of offset table. 4756 ADD HL,BC ; index into offset table. 4757 LD C,(HL) ; fetch offset 4758 ADD HL,BC ; index into parameter table. 4759 JR GET_PARAM <#GET_PARAM> 4760 ; ___ 4761 4762 mark_0CF4: 4763 *SCAN_LOOP:* 4764 LD HL,(T_ADDR) ; 4765 4766 ; -> Entry Point to Scanning Loop 4767 4768 mark_0CF7: 4769 *GET_PARAM:* 4770 LD A,(HL) ; 4771 INC HL ; 4772 LD (T_ADDR),HL ; 4773 4774 LD BC,SCAN_LOOP <#SCAN_LOOP> 4775 PUSH BC ; is pushed on machine stack. 4776 4777 LD C,A ; 4778 CP ZX_QUOTE ; $0B 4779 JR NC,SEPARATOR <#SEPARATOR> 4780 4781 LD HL,class_tbl <#class_tbl> ; class_tbl - the address of the class table. 4782 LD B,$00 ; 4783 ADD HL,BC ; 4784 LD C,(HL) ; 4785 ADD HL,BC ; 4786 PUSH HL ; 4787 4788 RST _GET_CHAR 4789 RET ; indirect jump to class routine and 4790 ; by subsequent RET to SCAN_LOOP. 4791 4792 ------------------------------------------------------------------------ 4793 4794 ; THE *'SEPARATOR'* ROUTINE 4795 ------------------------------------------------------------------------ 4796 4797 4798 mark_0D10: 4799 *SEPARATOR:* 4800 RST _GET_CHAR 4801 CP C ; 4802 JR NZ,REPORT_C2 <#REPORT_C2> 4803 ; 'Nonsense in BASIC' 4804 4805 RST _NEXT_CHAR 4806 RET ; return 4807 4808 4809 ------------------------------------------------------------------------ 4810 4811 ; THE *'COMMAND CLASS'* TABLE 4812 ------------------------------------------------------------------------ 4813 4814 ; 4815 mark_0D16: 4816 *class_tbl:* 4817 DEFB CLASS_0 <#CLASS_0> - $ ; 17 offset to; Address: CLASS_0 4818 DEFB CLASS_1 <#CLASS_1> - $ ; 25 offset to; Address: CLASS_1 4819 DEFB CLASS_2 <#CLASS_2> - $ ; 53 offset to; Address: CLASS_2 4820 DEFB CLASS_3 <#CLASS_3> - $ ; 0F offset to; Address: CLASS_3 4821 DEFB CLASS_4 <#CLASS_4> - $ ; 6B offset to; Address: CLASS_4 4822 DEFB CLASS_5 <#CLASS_5> - $ ; 13 offset to; Address: CLASS_5 4823 DEFB CLASS_6 <#CLASS_6> - $ ; 76 offset to; Address: CLASS_6 4824 4825 ------------------------------------------------------------------------ 4826 4827 ; THE *'CHECK END'* SUBROUTINE 4828 ------------------------------------------------------------------------ 4829 4830 ; Check for end of statement and that no spurious characters occur after 4831 ; a correctly parsed statement. Since only one statement is allowed on each 4832 ; line, the only character that may follow a statement is a NEWLINE. 4833 ; 4834 mark_0D1D: 4835 *CHECK_END:* 4836 CALL SYNTAX_Z <#SYNTAX_Z> 4837 RET NZ ; return in runtime. 4838 4839 POP BC ; else drop return address. 4840 4841 mark_0D22: 4842 *CHECK_2:* 4843 LD A,(HL) ; fetch character. 4844 CP ZX_NEWLINE ; compare to NEWLINE. 4845 RET Z ; return if so. 4846 4847 mark_0D26: 4848 *REPORT_C2:* 4849 JR REPORT_C <#REPORT_C> 4850 ; 'Nonsense in BASIC' 4851 4852 ------------------------------------------------------------------------ 4853 4854 ; COMMAND CLASSES 03, 00, 05 4855 ------------------------------------------------------------------------ 4856 4857 4858 mark_0D28: 4859 *CLASS_3:* 4860 CP ZX_NEWLINE ; 4861 CALL NUMBER_TO_STK <#NUMBER_TO_STK> 4862 4863 mark_0D2D: 4864 *CLASS_0:* 4865 CP A ; 4866 4867 mark_0D2E: 4868 *CLASS_5:* 4869 POP BC ; 4870 CALL Z,CHECK_END <#CHECK_END> 4871 EX DE,HL ; 4872 LD HL,(T_ADDR) ; 4873 LD C,(HL) ; 4874 INC HL ; 4875 LD B,(HL) ; 4876 EX DE,HL ; 4877 4878 mark_0D3A: 4879 *CLASS_END:* 4880 PUSH BC ; 4881 RET ; 4882 4883 ------------------------------------------------------------------------ 4884 4885 ; COMMAND CLASSES 01, 02, 04, 06 4886 ------------------------------------------------------------------------ 4887 4888 4889 mark_0D3C: 4890 *CLASS_1:* 4891 CALL LOOK_VARS <#LOOK_VARS> 4892 4893 mark_0D3F: 4894 *CLASS_4_2:* 4895 LD (IY+FLAGX-RAMBASE),$00 4896 JR NC,SET_STK <#SET_STK> 4897 4898 SET 1,(IY+FLAGX-RAMBASE) 4899 JR NZ,SET_STRLN <#SET_STRLN> 4900 4901 4902 mark_0D4B: 4903 *REPORT_2:* 4904 RST _ERROR_1 4905 DEFB $01 ; Error Report: Variable not found 4906 ; ___ 4907 4908 mark_0D4D: 4909 *SET_STK:* 4910 CALL Z,STK_VAR <#STK_VAR> 4911 BIT 6,(IY+FLAGS-RAMBASE) ; Numeric or string result? 4912 JR NZ,SET_STRLN <#SET_STRLN> 4913 4914 XOR A ; 4915 CALL SYNTAX_Z <#SYNTAX_Z> 4916 CALL NZ,STK_FETCH <#STK_FETCH> 4917 LD HL,FLAGX ; 4918 OR (HL) ; 4919 LD (HL),A ; 4920 EX DE,HL ; 4921 4922 mark_0D63: 4923 *SET_STRLN:* 4924 LD (STRLEN),BC ; 4925 LD (DEST),HL ; 4926 4927 ; THE *'REM'* COMMAND ROUTINE 4928 4929 mark_0D6A: 4930 *REM:* 4931 RET ; 4932 4933 ; ___ 4934 4935 mark_0D6B: 4936 *CLASS_2:* 4937 POP BC ; 4938 LD A,(FLAGS) ; sv 4939 4940 mark_0D6F: 4941 *INPUT_REP:* 4942 PUSH AF ; 4943 CALL SCANNING <#SCANNING> 4944 POP AF ; 4945 LD BC,LET <#LET> ; Address: LET 4946 LD D,(IY+FLAGS-RAMBASE) 4947 XOR D ; 4948 AND $40 ; 4949 JR NZ,REPORT_C <#REPORT_C> ; to REPORT_C 4950 4951 BIT 7,D ; 4952 JR NZ,CLASS_END <#CLASS_END> ; to CLASS_END 4953 4954 JR CHECK_2 <#CHECK_2> ; to CHECK_2 4955 ; ___ 4956 4957 mark_0D85: 4958 *CLASS_4:* 4959 CALL LOOK_VARS <#LOOK_VARS> 4960 PUSH AF ; 4961 LD A,C ; 4962 OR $9F ; 4963 INC A ; 4964 JR NZ,REPORT_C <#REPORT_C> ; to REPORT_C 4965 4966 POP AF ; 4967 JR CLASS_4_2 <#CLASS_4_2> ; to CLASS_4_2 4968 4969 ; ___ 4970 4971 mark_0D92: 4972 *CLASS_6:* 4973 CALL SCANNING <#SCANNING> 4974 BIT 6,(IY+FLAGS-RAMBASE) ; Numeric or string result? 4975 RET NZ ; 4976 4977 4978 mark_0D9A: 4979 *REPORT_C:* 4980 RST _ERROR_1 4981 DEFB $0B ; Error Report: Nonsense in BASIC 4982 4983 ------------------------------------------------------------------------ 4984 4985 ; THE *'NUMBER TO STACK'* SUBROUTINE 4986 ------------------------------------------------------------------------ 4987 4988 ; 4989 ; 4990 4991 mark_0D9C: 4992 *NUMBER_TO_STK:* 4993 JR NZ,CLASS_6 <#CLASS_6> ; back to CLASS_6 with a non-zero number. 4994 4995 CALL SYNTAX_Z <#SYNTAX_Z> 4996 RET Z ; return if checking syntax. 4997 4998 ; in runtime a zero default is placed on the calculator stack. 4999 5000 RST _FP_CALC ;; 5001 DEFB __stk_zero ;; 5002 DEFB __end_calc ;; 5003 5004 RET ; return. 5005 5006 ------------------------------------------------------------------------ 5007 5008 ; THE *'SYNTAX_Z'* SUBROUTINE 5009 ------------------------------------------------------------------------ 5010 5011 ; This routine returns with zero flag set if checking syntax. 5012 ; Calling this routine uses three instruction bytes compared to four if the 5013 ; bit test is implemented inline. 5014 5015 mark_0DA6: 5016 *SYNTAX_Z:* 5017 BIT 7,(IY+FLAGS-RAMBASE) ; checking syntax only? 5018 RET ; return. 5019 5020 ------------------------------------------------------------------------ 5021 5022 ; THE *'IF'* COMMAND ROUTINE 5023 ------------------------------------------------------------------------ 5024 5025 ; In runtime, the class routines have evaluated the test expression and 5026 ; the result, true or false, is on the stack. 5027 5028 mark_0DAB: 5029 *IF:* 5030 CALL SYNTAX_Z <#SYNTAX_Z> 5031 JR Z,IF_END <#IF_END> ; forward if checking syntax 5032 5033 ; else delete the Boolean value on the calculator stack. 5034 5035 RST _FP_CALC ;; 5036 DEFB __delete ;; 5037 DEFB __end_calc ;; 5038 5039 ; register DE points to exponent of floating point value. 5040 5041 LD A,(DE) ; fetch exponent. 5042 AND A ; test for zero - FALSE. 5043 RET Z ; return if so. 5044 5045 mark_0DB6: 5046 *IF_END:* 5047 JP LINE_NULL <#LINE_NULL> ; jump back 5048 5049 ------------------------------------------------------------------------ 5050 5051 ; THE *'FOR'* COMMAND ROUTINE 5052 ------------------------------------------------------------------------ 5053 5054 ; 5055 ; 5056 5057 mark_0DB9: 5058 *FOR:* 5059 CP ZX_STEP ; is current character 'STEP' ? 5060 JR NZ,F_USE_ONE <#F_USE_ONE> ; forward if not 5061 5062 5063 RST _NEXT_CHAR 5064 CALL CLASS_6 <#CLASS_6> ; stacks the number 5065 CALL CHECK_END <#CHECK_END> 5066 JR F_REORDER <#F_REORDER> ; forward to F_REORDER 5067 ; ___ 5068 5069 mark_0DC6: 5070 *F_USE_ONE:* 5071 CALL CHECK_END <#CHECK_END> 5072 5073 RST _FP_CALC ;; 5074 DEFB __stk_one ;; 5075 DEFB __end_calc ;; 5076 5077 5078 5079 mark_0DCC: 5080 *F_REORDER:* 5081 RST _FP_CALC ;; v, l, s. 5082 DEFB __st_mem_0 ;; v, l, s. 5083 DEFB __delete ;; v, l. 5084 DEFB __exchange ;; l, v. 5085 DEFB __get_mem_0 ;; l, v, s. 5086 DEFB __exchange ;; l, s, v. 5087 DEFB __end_calc ;; l, s, v. 5088 5089 CALL LET <#LET> 5090 5091 LD (MEM),HL ; set MEM to address variable. 5092 DEC HL ; point to letter. 5093 LD A,(HL) ; 5094 SET 7,(HL) ; 5095 LD BC,$0006 ; 5096 ADD HL,BC ; 5097 RLCA ; 5098 JR C,F_LMT_STP <#F_LMT_STP> 5099 5100 SLA C ; 5101 CALL MAKE_ROOM <#MAKE_ROOM> 5102 INC HL ; 5103 5104 mark_0DEA: 5105 *F_LMT_STP:* 5106 PUSH HL ; 5107 5108 RST _FP_CALC ;; 5109 DEFB __delete ;; 5110 DEFB __delete ;; 5111 DEFB __end_calc ;; 5112 5113 POP HL ; 5114 EX DE,HL ; 5115 5116 LD C,$0A ; ten bytes to be moved. 5117 LDIR ; copy bytes 5118 5119 LD HL,(PPC) ; set HL to system variable PPC current line. 5120 EX DE,HL ; transfer to DE, variable pointer to HL. 5121 INC DE ; loop start will be this line + 1 at least. 5122 LD (HL),E ; 5123 INC HL ; 5124 LD (HL),D ; 5125 CALL NEXT_LOOP <#NEXT_LOOP> ; considers an initial pass. 5126 RET NC ; return if possible. 5127 5128 ; else program continues from point following matching NEXT. 5129 5130 BIT 7,(IY+PPC_hi-RAMBASE) 5131 RET NZ ; return if over 32767 ??? 5132 5133 LD B,(IY+STRLEN_lo-RAMBASE) ; fetch variable name from STRLEN_lo 5134 RES 6,B ; make a true letter. 5135 LD HL,(NXTLIN) ; set HL from NXTLIN 5136 5137 ; now enter a loop to look for matching next. 5138 5139 mark_0E0E: 5140 *NXTLIN_NO:* 5141 LD A,(HL) ; fetch high byte of line number. 5142 AND $C0 ; mask off low bits $3F 5143 JR NZ,FOR_END <#FOR_END> ; forward at end of program 5144 5145 PUSH BC ; save letter 5146 CALL NEXT_ONE <#NEXT_ONE> ; finds next line. 5147 POP BC ; restore letter 5148 5149 INC HL ; step past low byte 5150 INC HL ; past the 5151 INC HL ; line length. 5152 CALL TEMP_PTR1 <#TEMP_PTR1> ; sets CH_ADD 5153 5154 RST _GET_CHAR 5155 CP ZX_NEXT ; 5156 EX DE,HL ; next line to HL. 5157 JR NZ,NXTLIN_NO <#NXTLIN_NO> ; back with no match 5158 5159 ; 5160 5161 EX DE,HL ; restore pointer. 5162 5163 RST _NEXT_CHAR ; advances and gets letter in A. 5164 EX DE,HL ; save pointer 5165 CP B ; compare to variable name. 5166 JR NZ,NXTLIN_NO <#NXTLIN_NO> ; back with mismatch 5167 5168 mark_0E2A: 5169 *FOR_END:* 5170 LD (NXTLIN),HL ; update system variable NXTLIN 5171 RET ; return. 5172 5173 ------------------------------------------------------------------------ 5174 5175 ; THE *'NEXT'* COMMAND ROUTINE 5176 ------------------------------------------------------------------------ 5177 5178 ; 5179 ; 5180 5181 mark_0E2E: 5182 *NEXT:* 5183 BIT 1,(IY+FLAGX-RAMBASE) 5184 JP NZ,REPORT_2 <#REPORT_2> 5185 5186 LD HL,(DEST) 5187 BIT 7,(HL) 5188 JR Z,REPORT_1 <#REPORT_1> 5189 5190 INC HL ; 5191 LD (MEM),HL ; 5192 5193 RST _FP_CALC ;; 5194 DEFB __get_mem_0 ;; 5195 DEFB __get_mem_2 ;; 5196 DEFB __addition ;; 5197 DEFB __st_mem_0 ;; 5198 DEFB __delete ;; 5199 DEFB __end_calc ;; 5200 5201 CALL NEXT_LOOP <#NEXT_LOOP> 5202 RET C ; 5203 5204 LD HL,(MEM) ; 5205 LD DE,$000F ; 5206 ADD HL,DE ; 5207 LD E,(HL) ; 5208 INC HL ; 5209 LD D,(HL) ; 5210 EX DE,HL ; 5211 JR GOTO_2 <#GOTO_2> 5212 ; ___ 5213 5214 mark_0E58: 5215 *REPORT_1:* 5216 RST _ERROR_1 5217 DEFB $00 ; Error Report: NEXT without FOR 5218 5219 5220 ------------------------------------------------------------------------ 5221 5222 ; THE *'NEXT_LOOP'* SUBROUTINE 5223 ------------------------------------------------------------------------ 5224 5225 ; 5226 ; 5227 5228 mark_0E5A: 5229 *NEXT_LOOP:* 5230 RST _FP_CALC ;; 5231 DEFB __get_mem_1 ;; 5232 DEFB __get_mem_0 ;; 5233 DEFB __get_mem_2 ;; 5234 DEFB __less_0 ;; 5235 DEFB __jump_true ;; 5236 DEFB LMT_V_VAL <#LMT_V_VAL> - $ ;; 5237 5238 DEFB __exchange ;; 5239 5240 mark_0E62: 5241 *LMT_V_VAL:* 5242 DEFB __subtract ;; 5243 DEFB __greater_0 ;; 5244 DEFB __jump_true ;; 5245 DEFB IMPOSS <#IMPOSS> - $ ;; 5246 5247 DEFB __end_calc ;; 5248 5249 AND A ; clear carry flag 5250 RET ; return. 5251 ; ___ 5252 5253 mark_0E69: 5254 *IMPOSS:* 5255 DEFB __end_calc ;; 5256 5257 SCF ; set carry flag 5258 RET ; return. 5259 5260 ------------------------------------------------------------------------ 5261 5262 ; THE *'RAND'* COMMAND ROUTINE 5263 ------------------------------------------------------------------------ 5264 5265 ; The keyword was *'RANDOMISE'* on the ZX80, is 'RAND' here on the ZX81 and 5266 ; becomes 'RANDOMIZE' on the ZX Spectrum. 5267 ; In all invocations the procedure is the same - to set the SEED system variable 5268 ; with a supplied integer value or to use a time-based value if no number, or 5269 ; zero, is supplied. 5270 5271 mark_0E6C: 5272 *RAND:* 5273 CALL FIND_INT <#FIND_INT> 5274 LD A,B ; test value 5275 OR C ; for zero 5276 JR NZ,SET_SEED <#SET_SEED> ; forward if not zero 5277 5278 LD BC,(FRAMES) ; fetch value of FRAMES system variable. 5279 5280 mark_0E77: 5281 *SET_SEED:* 5282 LD (SEED),BC ; update the SEED system variable. 5283 RET ; return. 5284 5285 ------------------------------------------------------------------------ 5286 5287 ; THE *'CONT'* COMMAND ROUTINE 5288 ------------------------------------------------------------------------ 5289 5290 ; Another abbreviated command. ROM space was really tight. 5291 ; CONTINUE at the line number that was set when break was pressed. 5292 ; Sometimes the current line, sometimes the next line. 5293 5294 mark_0E7C: 5295 *CONT:* 5296 LD HL,(OLDPPC) ; set HL from system variable OLDPPC 5297 JR GOTO_2 <#GOTO_2> ; forward 5298 5299 ------------------------------------------------------------------------ 5300 5301 ; THE *'GOTO'* COMMAND ROUTINE 5302 ------------------------------------------------------------------------ 5303 5304 ; This token also suffered from the shortage of room and there is no space 5305 ; getween GO and TO as there is on the ZX80 and ZX Spectrum. The same also 5306 ; applies to the GOSUB keyword. 5307 5308 mark_0E81: 5309 *GOTO:* 5310 CALL FIND_INT <#FIND_INT> 5311 LD H,B ; 5312 LD L,C ; 5313 5314 mark_0E86: 5315 *GOTO_2:* 5316 LD A,H ; 5317 CP $F0 ; ZX_LIST ??? 5318 JR NC,REPORT_B <#REPORT_B> 5319 5320 CALL LINE_ADDR <#LINE_ADDR> 5321 LD (NXTLIN),HL ; sv 5322 RET ; 5323 5324 ------------------------------------------------------------------------ 5325 5326 ; THE *'POKE'* COMMAND ROUTINE 5327 ------------------------------------------------------------------------ 5328 5329 5330 mark_0E92: 5331 *POKE:* 5332 CALL FP_TO_A <#FP_TO_A> 5333 JR C,REPORT_B <#REPORT_B> ; forward, with overflow 5334 5335 JR Z,POKE_SAVE <#POKE_SAVE> ; forward, if positive 5336 5337 NEG ; negate 5338 5339 mark_0E9B: 5340 *POKE_SAVE:* 5341 PUSH AF ; preserve value. 5342 CALL FIND_INT <#FIND_INT> ; gets address in BC 5343 ; invoking the error routine with overflow 5344 ; or a negative number. 5345 POP AF ; restore value. 5346 5347 ; Note. the next two instructions are legacy code from the ZX80 and 5348 ; inappropriate here. 5349 5350 BIT 7,(IY+ERR_NR-RAMBASE) ; test ERR_NR - is it still $FF ? 5351 RET Z ; return with error. 5352 5353 LD (BC),A ; update the address contents. 5354 RET ; return. 5355 5356 ------------------------------------------------------------------------ 5357 5358 ; THE *'FIND INTEGER'* SUBROUTINE 5359 ------------------------------------------------------------------------ 5360 5361 5362 mark_0EA7: 5363 *FIND_INT:* 5364 CALL FP_TO_BC <#FP_TO_BC> 5365 JR C,REPORT_B <#REPORT_B> ; forward with overflow 5366 5367 RET Z ; return if positive (0-65535). 5368 5369 5370 mark_0EAD: 5371 *REPORT_B:* 5372 RST _ERROR_1 5373 DEFB $0A ; Error Report: Integer out of range 5374 ; 5375 ; Seems stupid, $0A is 10 but the ERROR_CODE_INTEGER_OUT_OF_RANGE is 11 5376 ; maybe gets incremented ??? 5377 5378 ------------------------------------------------------------------------ 5379 5380 ; THE *'RUN'* COMMAND ROUTINE 5381 ------------------------------------------------------------------------ 5382 5383 5384 mark_0EAF: 5385 *RUN:* 5386 CALL GOTO <#GOTO> 5387 JP CLEAR <#CLEAR> 5388 5389 ------------------------------------------------------------------------ 5390 5391 ; THE *'GOSUB'* COMMAND ROUTINE 5392 ------------------------------------------------------------------------ 5393 5394 5395 mark_0EB5: 5396 *GOSUB:* 5397 LD HL,(PPC) ; 5398 INC HL ; 5399 EX (SP),HL ; 5400 PUSH HL ; 5401 LD (ERR_SP),SP ; set the error stack pointer - ERR_SP 5402 CALL GOTO <#GOTO> 5403 LD BC,6 ; 5404 5405 ------------------------------------------------------------------------ 5406 5407 ; THE *'TEST ROOM'* SUBROUTINE 5408 ------------------------------------------------------------------------ 5409 5410 ; 5411 ; checks ther is room for 36 bytes on the stack 5412 ; 5413 mark_0EC5: 5414 *TEST_ROOM:* 5415 LD HL,(STKEND) ; 5416 ADD HL,BC ; HL = STKEND + BC 5417 JR C,REPORT_4 <#REPORT_4> 5418 5419 EX DE,HL ; DE = STKEND + BC 5420 LD HL,$0024 ; 36 decimal 5421 ADD HL,DE ; HL = 36 + STKEND + BC 5422 SBC HL,SP ; HL = 36 + STKEND + BC - SP 5423 RET C ; 5424 5425 mark_0ED3: 5426 *REPORT_4:* 5427 LD L,3 ; 5428 JP ERROR_3 <#ERROR_3> 5429 5430 ------------------------------------------------------------------------ 5431 5432 ; THE *'RETURN'* COMMAND ROUTINE 5433 ------------------------------------------------------------------------ 5434 5435 5436 mark_0ED8: 5437 *RETURN:* 5438 POP HL ; 5439 EX (SP),HL ; 5440 LD A,H ; 5441 CP $3E ; 5442 JR Z,REPORT_7 <#REPORT_7> 5443 5444 LD (ERR_SP),SP ; 5445 JR GOTO_2 <#GOTO_2> ; back 5446 ; ___ 5447 5448 mark_0EE5: 5449 *REPORT_7:* 5450 EX (SP),HL ; 5451 PUSH HL ; 5452 5453 RST _ERROR_1 5454 DEFB 6 ; Error Report: RETURN without GOSUB 5455 5456 ; 5457 ; Contradicts BASIC manual: 5458 ; 7 is ERROR_CODE_RETURN_WITHOUT_GOSUB 5459 ; 6 is ERROR_CODE_ARITHMETIC_OVERFLOW 5460 ; 5461 5462 ------------------------------------------------------------------------ 5463 5464 ; THE *'INPUT'* COMMAND ROUTINE 5465 ------------------------------------------------------------------------ 5466 5467 5468 mark_0EE9: 5469 *INPUT:* 5470 BIT 7,(IY+PPC_hi-RAMBASE) 5471 JR NZ,REPORT_8 <#REPORT_8> ; to REPORT_8 5472 5473 CALL X_TEMP <#X_TEMP> 5474 LD HL,FLAGX ; 5475 SET 5,(HL) ; 5476 RES 6,(HL) ; 5477 LD A,(FLAGS) ; 5478 AND $40 ; 64 5479 LD BC,2 ; 5480 JR NZ,PROMPT <#PROMPT> ; to PROMPT 5481 5482 LD C,$04 ; 5483 5484 mark_0F05: 5485 *PROMPT:* 5486 OR (HL) ; 5487 LD (HL),A ; 5488 5489 RST _BC_SPACES 5490 LD (HL),ZX_NEWLINE 5491 LD A,C ; 5492 RRCA ; 5493 RRCA ; 5494 JR C,ENTER_CUR <#ENTER_CUR> 5495 5496 LD A,$0B ; ZX_QUOTE ??? 5497 LD (DE),A ; 5498 DEC HL ; 5499 LD (HL),A ; 5500 5501 mark_0F14: 5502 *ENTER_CUR:* 5503 DEC HL ; 5504 LD (HL),ZX_CURSOR ; 5505 LD HL,(S_POSN) ; 5506 LD (T_ADDR),HL ; 5507 POP HL ; 5508 JP LOWER <#LOWER> 5509 5510 ; ___ 5511 5512 mark_0F21: 5513 *REPORT_8:* 5514 RST _ERROR_1 5515 DEFB 7 ; Error Report: End of file 5516 5517 ------------------------------------------------------------------------ 5518 5519 ; THE *'PAUSE'* COMMAND ROUTINE 5520 ------------------------------------------------------------------------ 5521 5522 5523 mark_0F23: 5524 *FAST:* 5525 CALL SET_FAST <#SET_FAST> 5526 RES 6,(IY+CDFLAG-RAMBASE) 5527 RET ; return. 5528 5529 ------------------------------------------------------------------------ 5530 5531 ; THE *'SLOW'* COMMAND ROUTINE 5532 ------------------------------------------------------------------------ 5533 5534 5535 mark_0F2B: 5536 *SLOW:* 5537 SET 6,(IY+CDFLAG-RAMBASE) 5538 JP SLOW_FAST <#SLOW_FAST> 5539 5540 ------------------------------------------------------------------------ 5541 5542 ; THE *'PAUSE'* COMMAND ROUTINE 5543 ------------------------------------------------------------------------ 5544 5545 5546 mark_0F32: 5547 *PAUSE:* 5548 CALL FIND_INT <#FIND_INT> 5549 CALL SET_FAST <#SET_FAST> 5550 LD H,B ; 5551 LD L,C ; 5552 CALL DISPLAY_P <#DISPLAY_P> 5553 5554 LD (IY+FRAMES_hi-RAMBASE),$FF 5555 5556 CALL SLOW_FAST <#SLOW_FAST> 5557 JR DEBOUNCE <#DEBOUNCE> 5558 5559 ------------------------------------------------------------------------ 5560 5561 ; THE *'BREAK'* SUBROUTINE 5562 ------------------------------------------------------------------------ 5563 5564 5565 mark_0F46: 5566 *BREAK_1:* 5567 LD A,$7F ; read port $7FFE - keys B,N,M,.,SPACE. 5568 IN A,(IO_PORT_KEYBOARD_RD) ; 5569 RRA ; carry will be set if space not pressed. 5570 5571 ------------------------------------------------------------------------ 5572 5573 ; THE *'DEBOUNCE'* SUBROUTINE 5574 ------------------------------------------------------------------------ 5575 5576 5577 mark_0F4B: 5578 *DEBOUNCE:* 5579 RES 0,(IY+CDFLAG-RAMBASE) ; update 5580 LD A,$FF ; 5581 LD (DEBOUNCE_VAR),A ; update 5582 RET ; return. 5583 5584 5585 ------------------------------------------------------------------------ 5586 5587 ; THE *'SCANNING'* SUBROUTINE 5588 ------------------------------------------------------------------------ 5589 5590 ; This recursive routine is where the ZX81 gets its power. 5591 ; Provided there is enough memory it can evaluate 5592 ; an expression of unlimited complexity. 5593 ; Note. there is no unary plus so, as on the ZX80, PRINT +1 gives a syntax error. 5594 ; PRINT +1 works on the Spectrum but so too does PRINT + "STRING". 5595 5596 mark_0F55: 5597 *SCANNING:* 5598 RST _GET_CHAR 5599 LD B,0 ; set B register to zero. 5600 PUSH BC ; stack zero as a priority end-marker. 5601 5602 mark_0F59: 5603 *S_LOOP_1:* 5604 CP ZX_RND 5605 JR NZ,S_TEST_PI <#S_TEST_PI> ; forward, if not, to S_TEST_PI 5606 5607 ------------------------------------------------------------------------ 5608 5609 ; THE *'RND'* FUNCTION 5610 ------------------------------------------------------------------------ 5611 5612 *RND:* 5613 5614 CALL SYNTAX_Z <#SYNTAX_Z> 5615 JR Z,S_JPI_END <#S_JPI_END> ; forward if checking syntax to S_JPI_END 5616 5617 LD BC,(SEED) ; sv 5618 CALL STACK_BC <#STACK_BC> 5619 5620 RST _FP_CALC ;; 5621 DEFB __stk_one ;; 5622 DEFB __addition ;; 5623 DEFB __stk_data ;; 5624 DEFB $37 ;;Exponent: $87, Bytes: 1 5625 DEFB $16 ;;(+00,+00,+00) 5626 DEFB __multiply ;; 5627 DEFB __stk_data ;; 5628 DEFB $80 ;;Bytes: 3 5629 DEFB $41 ;;Exponent $91 5630 DEFB $00,$00,$80 ;;(+00) 5631 DEFB __n_mod_m ;; 5632 DEFB __delete ;; 5633 DEFB __stk_one ;; 5634 DEFB __subtract ;; 5635 DEFB __duplicate ;; 5636 DEFB __end_calc ;; 5637 5638 CALL FP_TO_BC <#FP_TO_BC> 5639 LD (SEED),BC ; update the SEED system variable. 5640 LD A,(HL) ; HL addresses the exponent of the last value. 5641 AND A ; test for zero 5642 JR Z,S_JPI_END <#S_JPI_END> ; forward, if so 5643 5644 SUB $10 ; else reduce exponent by sixteen 5645 LD (HL),A ; thus dividing by 65536 for last value. 5646 5647 mark_0F8A: 5648 *S_JPI_END:* 5649 JR S_PI_END <#S_PI_END> ; forward 5650 5651 ; ___ 5652 5653 mark_0F8C: 5654 *S_TEST_PI:* 5655 CP ZX_PI ; the 'PI' character 5656 JR NZ,S_TST_INK <#S_TST_INK> ; forward, if not 5657 5658 ------------------------------------------------------------------------ 5659 5660 ; THE *'PI'* EVALUATION 5661 ------------------------------------------------------------------------ 5662 5663 5664 CALL SYNTAX_Z <#SYNTAX_Z> 5665 JR Z,S_PI_END <#S_PI_END> ; forward if checking syntax 5666 5667 5668 RST _FP_CALC ;; 5669 DEFB __stk_half_pi ;; 5670 DEFB __end_calc ;; 5671 5672 INC (HL) ; double the exponent giving PI on the stack. 5673 5674 mark_0F99: 5675 *S_PI_END:* 5676 RST _NEXT_CHAR ; advances character pointer. 5677 5678 JP S_NUMERIC <#S_NUMERIC> ; jump forward to set the flag 5679 ; to signal numeric result before advancing. 5680 5681 ; ___ 5682 5683 mark_0F9D: 5684 *S_TST_INK:* 5685 CP ZX_INKEY_STR ; 5686 JR NZ,S_ALPHANUM <#S_ALPHANUM> ; forward, if not 5687 5688 ------------------------------------------------------------------------ 5689 5690 ; THE *'INKEY$'* EVALUATION 5691 ------------------------------------------------------------------------ 5692 5693 5694 CALL KEYBOARD <#KEYBOARD> 5695 LD B,H ; 5696 LD C,L ; 5697 LD D,C ; 5698 INC D ; 5699 CALL NZ,DECODE <#DECODE> 5700 LD A,D ; 5701 ADC A,D ; 5702 LD B,D ; 5703 LD C,A ; 5704 EX DE,HL ; 5705 JR S_STRING <#S_STRING> ; forward 5706 5707 ; ___ 5708 5709 mark_0FB2: 5710 *S_ALPHANUM:* 5711 CALL ALPHANUM <#ALPHANUM> 5712 JR C,S_LTR_DGT <#S_LTR_DGT> ; forward, if alphanumeric 5713 5714 CP ZX_PERIOD ; is character a '.' ? 5715 JP Z,S_DECIMAL <#S_DECIMAL> ; jump forward if so 5716 5717 LD BC,$09D8 ; prepare priority 09, operation 'subtract' 5718 CP ZX_MINUS ; is character unary minus '-' ? 5719 JR Z,S_PUSH_PO <#S_PUSH_PO> ; forward, if so 5720 5721 CP ZX_BRACKET_LEFT ; is character a '(' ? 5722 JR NZ,S_QUOTE <#S_QUOTE> ; forward if not 5723 5724 CALL CH_ADD_PLUS_1 <#CH_ADD_PLUS_1> ; advances character pointer. 5725 5726 CALL SCANNING <#SCANNING> ; recursively call to evaluate the sub_expression. 5727 5728 CP ZX_BRACKET_RIGHT; is subsequent character a ')' ? 5729 JR NZ,S_RPT_C <#S_RPT_C> ; forward if not 5730 5731 5732 CALL CH_ADD_PLUS_1 <#CH_ADD_PLUS_1> ; advances. 5733 JR S_J_CONT_3 <#S_J_CONT_3> ; relative jump to S_JP_CONT3 and then S_CONT3 5734 5735 ; ___ 5736 5737 ; consider a quoted string e.g. PRINT "Hooray!" 5738 ; Note. quotes are not allowed within a string. 5739 5740 mark_0FD6: 5741 *S_QUOTE:* 5742 CP ZX_QUOTE ; is character a quote (") ? 5743 JR NZ,S_FUNCTION <#S_FUNCTION> ; forward, if not 5744 5745 CALL CH_ADD_PLUS_1 <#CH_ADD_PLUS_1> ; advances 5746 PUSH HL ; * save start of string. 5747 JR S_QUOTE_S <#S_QUOTE_S> ; forward 5748 5749 ; ___ 5750 5751 5752 mark_0FE0: 5753 *S_Q_AGAIN:* 5754 CALL CH_ADD_PLUS_1 <#CH_ADD_PLUS_1> 5755 5756 mark_0FE3: 5757 *S_QUOTE_S:* 5758 CP ZX_QUOTE ; is character a '"' ? 5759 JR NZ,S_Q_NL <#S_Q_NL> ; forward if not to S_Q_NL 5760 5761 POP DE ; * retrieve start of string 5762 AND A ; prepare to subtract. 5763 SBC HL,DE ; subtract start from current position. 5764 LD B,H ; transfer this length 5765 LD C,L ; to the BC register pair. 5766 5767 mark_0FED: 5768 *S_STRING:* 5769 LD HL,FLAGS ; address system variable FLAGS 5770 RES 6,(HL) ; signal string result 5771 BIT 7,(HL) ; test if checking syntax. 5772 5773 CALL NZ,STK_STO_STR <#STK_STO_STR> ; in run-time stacks the 5774 ; string descriptor - start DE, length BC. 5775 5776 RST _NEXT_CHAR ; advances pointer. 5777 5778 mark_0FF8: 5779 *S_J_CONT_3:* 5780 JP S_CONT_3 <#S_CONT_3> 5781 5782 ; ___ 5783 5784 ; A string with no terminating quote has to be considered. 5785 5786 mark_0FFB: 5787 *S_Q_NL:* 5788 CP ZX_NEWLINE 5789 JR NZ,S_Q_AGAIN <#S_Q_AGAIN> ; loop back if not 5790 5791 mark_0FFF: 5792 *S_RPT_C:* 5793 JP REPORT_C <#REPORT_C> 5794 ; ___ 5795 5796 mark_1002: 5797 *S_FUNCTION:* 5798 SUB $C4 ; subtract 'CODE' reducing codes 5799 ; CODE thru '<>' to range $00 - $XX 5800 JR C,S_RPT_C <#S_RPT_C> ; back, if less 5801 5802 ; test for NOT the last function in character set. 5803 5804 LD BC,$04EC ; prepare priority $04, operation 'not' 5805 CP $13 ; compare to 'NOT' ( - CODE) 5806 JR Z,S_PUSH_PO <#S_PUSH_PO> ; forward, if so 5807 5808 JR NC,S_RPT_C <#S_RPT_C> ; back with anything higher 5809 5810 ; else is a function 'CODE' thru 'CHR$' 5811 5812 LD B,$10 ; priority sixteen binds all functions to 5813 ; arguments removing the need for brackets. 5814 5815 ADD A,$D9 ; add $D9 to give range $D9 thru $EB 5816 ; bit 6 is set to show numeric argument. 5817 ; bit 7 is set to show numeric result. 5818 5819 ; now adjust these default argument/result indicators. 5820 5821 LD C,A ; save code in C 5822 5823 CP $DC ; separate 'CODE', 'VAL', 'LEN' 5824 JR NC,S_NUMBER_TO_STRING <#S_NUMBER_TO_STRING> ; skip forward if string operand 5825 5826 RES 6,C ; signal string operand. 5827 5828 mark_101A: 5829 *S_NUMBER_TO_STRING:* 5830 CP $EA ; isolate top of range 'STR$' and 'CHR$' 5831 JR C,S_PUSH_PO <#S_PUSH_PO> ; skip forward with others 5832 5833 RES 7,C ; signal string result. 5834 5835 mark_1020: 5836 *S_PUSH_PO:* 5837 PUSH BC ; push the priority/operation 5838 5839 RST _NEXT_CHAR 5840 JP S_LOOP_1 <#S_LOOP_1> ; jump back 5841 ; ___ 5842 5843 mark_1025: 5844 *S_LTR_DGT:* 5845 CP ZX_A ; compare to 'A'. 5846 JR C,S_DECIMAL <#S_DECIMAL> ; forward if less to S_DECIMAL 5847 5848 CALL LOOK_VARS <#LOOK_VARS> 5849 JP C,REPORT_2 <#REPORT_2> ; back if not found 5850 ; a variable is always 'found' when checking 5851 ; syntax. 5852 5853 CALL Z,STK_VAR <#STK_VAR> ; stacks string parameters or 5854 ; returns cell location if numeric. 5855 5856 LD A,(FLAGS) ; fetch FLAGS 5857 CP $C0 ; compare to numeric result/numeric operand 5858 JR C,S_CONT_2 <#S_CONT_2> ; forward if not numeric 5859 5860 INC HL ; address numeric contents of variable. 5861 LD DE,(STKEND) ; set destination to STKEND 5862 CALL MOVE_FP <#MOVE_FP> ; stacks the five bytes 5863 EX DE,HL ; transfer new free location from DE to HL. 5864 LD (STKEND),HL ; update STKEND system variable. 5865 JR S_CONT_2 <#S_CONT_2> ; forward 5866 ; ___ 5867 5868 ; The Scanning Decimal routine is invoked when a decimal point or digit is 5869 ; found in the expression. 5870 ; When checking syntax, then the 'hidden floating point' form is placed 5871 ; after the number in the BASIC line. 5872 ; In run-time, the digits are skipped and the floating point number is picked 5873 ; up. 5874 5875 mark_1047: 5876 *S_DECIMAL:* 5877 CALL SYNTAX_Z <#SYNTAX_Z> 5878 JR NZ,S_STK_DEC <#S_STK_DEC> ; forward in run-time 5879 5880 CALL DEC_TO_FP <#DEC_TO_FP> 5881 5882 RST _GET_CHAR ; advances HL past digits 5883 LD BC,$0006 ; six locations are required. 5884 CALL MAKE_ROOM <#MAKE_ROOM> 5885 INC HL ; point to first new location 5886 LD (HL),$7E ; insert the number marker 126 decimal. 5887 INC HL ; increment 5888 EX DE,HL ; transfer destination to DE. 5889 LD HL,(STKEND) ; set HL from STKEND which points to the 5890 ; first location after the 'last value' 5891 LD C,$05 ; five bytes to move. 5892 AND A ; clear carry. 5893 SBC HL,BC ; subtract five pointing to 'last value'. 5894 LD (STKEND),HL ; update STKEND thereby 'deleting the value. 5895 5896 LDIR ; copy the five value bytes. 5897 5898 EX DE,HL ; basic pointer to HL which may be white-space 5899 ; following the number. 5900 DEC HL ; now points to last of five bytes. 5901 CALL TEMP_PTR1 <#TEMP_PTR1> ; advances the character 5902 ; address skipping any white-space. 5903 JR S_NUMERIC <#S_NUMERIC> ; forward 5904 ; to signal a numeric result. 5905 ; ___ 5906 ; In run-time the branch is here when a digit or point is encountered. 5907 5908 mark_106F: 5909 *S_STK_DEC:* 5910 RST _NEXT_CHAR 5911 CP $7E ; compare to 'number marker' 5912 JR NZ,S_STK_DEC <#S_STK_DEC> ; loop back until found 5913 ; skipping all the digits. 5914 5915 INC HL ; point to first of five hidden bytes. 5916 LD DE,(STKEND) ; set destination from STKEND system variable 5917 CALL MOVE_FP <#MOVE_FP> ; stacks the number. 5918 LD (STKEND),DE ; update system variable STKEND. 5919 LD (CH_ADD),HL ; update system variable CH_ADD. 5920 5921 mark_1083: 5922 *S_NUMERIC:* 5923 SET 6,(IY+FLAGS-RAMBASE) ; Signal numeric result 5924 5925 mark_1087: 5926 *S_CONT_2:* 5927 RST _GET_CHAR 5928 5929 mark_1088: 5930 *S_CONT_3:* 5931 CP ZX_BRACKET_LEFT ; compare to opening bracket '(' 5932 JR NZ,S_OPERTR <#S_OPERTR> ; forward if not 5933 5934 BIT 6,(IY+FLAGS-RAMBASE) ; Numeric or string result? 5935 JR NZ,S_LOOP <#S_LOOP> ; forward if numeric 5936 5937 ; else is a string 5938 5939 CALL SLICING <#SLICING> 5940 5941 RST _NEXT_CHAR 5942 JR S_CONT_3 <#S_CONT_3> ; back 5943 ; ___ 5944 ; the character is now manipulated to form an equivalent in the table of 5945 ; calculator literals. This is quite cumbersome and in the ZX Spectrum a 5946 ; simple look-up table was introduced at this point. 5947 5948 mark_1098: 5949 *S_OPERTR:* 5950 LD BC,$00C3 ; prepare operator 'subtract' as default. 5951 ; also set B to zero for later indexing. 5952 5953 CP ZX_GREATER_THAN ; is character '>' ? 5954 JR C,S_LOOP <#S_LOOP> ; forward if less, as 5955 ; we have reached end of meaningful expression 5956 5957 SUB ZX_MINUS ; is character '-' ? 5958 JR NC,SUBMLTDIV <#SUBMLTDIV> ; forward with - * / and '**' '<>' 5959 5960 ADD A,13 ; increase others by thirteen 5961 ; $09 '>' thru $0C '+' 5962 JR GET_PRIO <#GET_PRIO> ; forward 5963 5964 ; ___ 5965 5966 mark_10A7: 5967 *SUBMLTDIV:* 5968 CP $03 ; isolate $00 '-', $01 '*', $02 '/' 5969 JR C,GET_PRIO <#GET_PRIO> ; forward if so 5970 5971 ; else possibly originally $D8 '**' thru $DD '<>' already reduced by $16 5972 5973 SUB $C2 ; giving range $00 to $05 5974 JR C,S_LOOP <#S_LOOP> ; forward if less 5975 5976 CP $06 ; test the upper limit for nonsense also 5977 JR NC,S_LOOP <#S_LOOP> ; forward if so 5978 5979 ADD A,$03 ; increase by 3 to give combined operators of 5980 5981 ; $00 '-' 5982 ; $01 '*' 5983 ; $02 '/' 5984 5985 ; $03 '**' 5986 ; $04 'OR' 5987 ; $05 'AND' 5988 ; $06 '<=' 5989 ; $07 '>=' 5990 ; $08 '<>' 5991 5992 ; $09 '>' 5993 ; $0A '<' 5994 ; $0B '=' 5995 ; $0C '+' 5996 5997 mark_10B5: 5998 *GET_PRIO:* 5999 ADD A,C ; add to default operation 'sub' ($C3) 6000 LD C,A ; and place in operator byte - C. 6001 6002 LD HL,tbl_pri <#tbl_pri> - $C3 ; theoretical base of the priorities table. 6003 ADD HL,BC ; add C ( B is zero) 6004 LD B,(HL) ; pick up the priority in B 6005 6006 mark_10BC: 6007 *S_LOOP:* 6008 POP DE ; restore previous 6009 LD A,D ; load A with priority. 6010 CP B ; is present priority higher 6011 JR C,S_TIGHTER <#S_TIGHTER> ; forward if so to S_TIGHTER 6012 6013 AND A ; are both priorities zero 6014 JP Z,GET_CHAR <#GET_CHAR> ; exit if zero via GET_CHAR 6015 6016 PUSH BC ; stack present values 6017 PUSH DE ; stack last values 6018 CALL SYNTAX_Z <#SYNTAX_Z> 6019 JR Z,S_SYNTEST <#S_SYNTEST> ; forward is checking syntax 6020 6021 LD A,E ; fetch last operation 6022 AND $3F ; mask off the indicator bits to give true 6023 ; calculator literal. 6024 LD B,A ; place in the B register for BERG 6025 6026 ; perform the single operation 6027 6028 RST _FP_CALC ;; 6029 DEFB __fp_calc_2 ;; 6030 DEFB __end_calc ;; 6031 6032 JR S_RUNTEST <#S_RUNTEST> ; forward 6033 6034 ; ___ 6035 6036 mark_10D5: 6037 *S_SYNTEST:* 6038 LD A,E ; transfer masked operator to A 6039 XOR (IY+FLAGS-RAMBASE) ; XOR with FLAGS like results will reset bit 6 6040 AND $40 ; test bit 6 6041 6042 mark_10DB: 6043 *S_RPORT_C:* 6044 JP NZ,REPORT_C <#REPORT_C> ; back if results do not agree. 6045 6046 ; ___ 6047 6048 ; in run-time impose bit 7 of the operator onto bit 6 of the FLAGS 6049 6050 mark_10DE: 6051 *S_RUNTEST:* 6052 POP DE ; restore last operation. 6053 LD HL,FLAGS ; address system variable FLAGS 6054 SET 6,(HL) ; presume a numeric result 6055 BIT 7,E ; test expected result in operation 6056 JR NZ,S_LOOPEND <#S_LOOPEND> ; forward if numeric 6057 6058 RES 6,(HL) ; reset to signal string result 6059 6060 mark_10EA: 6061 *S_LOOPEND:* 6062 POP BC ; restore present values 6063 JR S_LOOP <#S_LOOP> ; back 6064 6065 ; ___ 6066 6067 mark_10ED: 6068 *S_TIGHTER:* 6069 PUSH DE ; push last values and consider these 6070 6071 LD A,C ; get the present operator. 6072 BIT 6,(IY+FLAGS-RAMBASE) ; Numeric or string result? 6073 JR NZ,S_NEXT <#S_NEXT> ; forward if numeric to S_NEXT 6074 6075 AND $3F ; strip indicator bits to give clear literal. 6076 ADD A,$08 ; add eight - augmenting numeric to equivalent 6077 ; string literals. 6078 LD C,A ; place plain literal back in C. 6079 CP $10 ; compare to 'AND' 6080 JR NZ,S_NOT_AND <#S_NOT_AND> ; forward if not 6081 6082 SET 6,C ; set the numeric operand required for 'AND' 6083 JR S_NEXT <#S_NEXT> ; forward to S_NEXT 6084 6085 ; ___ 6086 6087 mark_1102: 6088 *S_NOT_AND:* 6089 JR C,S_RPORT_C <#S_RPORT_C> ; back if less than 'AND' 6090 ; Nonsense if '-', '*' etc. 6091 6092 CP __strs_add ; compare to 'strs_add' literal 6093 JR Z,S_NEXT <#S_NEXT> ; forward if so signaling string result 6094 6095 SET 7,C ; set bit to numeric (Boolean) for others. 6096 6097 mark_110A: 6098 *S_NEXT:* 6099 PUSH BC ; stack 'present' values 6100 6101 RST _NEXT_CHAR 6102 JP S_LOOP_1 <#S_LOOP_1> ; jump back 6103 6104 6105 6106 ------------------------------------------------------------------------ 6107 6108 ; THE *'TABLE OF PRIORITIES'* 6109 ------------------------------------------------------------------------ 6110 6111 6112 mark_110F: 6113 *tbl_pri:* 6114 DEFB 6 ; '-' 6115 DEFB 8 ; '*' 6116 DEFB 8 ; '/' 6117 DEFB 10 ; '**' 6118 DEFB 2 ; 'OR' 6119 DEFB 3 ; 'AND' 6120 DEFB 5 ; '<=' 6121 DEFB 5 ; '>=' 6122 DEFB 5 ; '<>' 6123 DEFB 5 ; '>' 6124 DEFB 5 ; '<' 6125 DEFB 5 ; '=' 6126 DEFB 6 ; '+' 6127 6128 ------------------------------------------------------------------------ 6129 6130 ; THE *'LOOK_VARS'* SUBROUTINE 6131 ------------------------------------------------------------------------ 6132 6133 6134 mark_111C: 6135 *LOOK_VARS:* 6136 SET 6,(IY+FLAGS-RAMBASE) ; Signal numeric result 6137 6138 RST _GET_CHAR 6139 CALL ALPHA <#ALPHA> 6140 JP NC,REPORT_C <#REPORT_C> ; to REPORT_C 6141 6142 PUSH HL ; 6143 LD C,A ; 6144 6145 RST _NEXT_CHAR 6146 PUSH HL ; 6147 RES 5,C ; 6148 CP $10 ; $10 6149 JR Z,V_RUN_SYN <#V_RUN_SYN> 6150 6151 SET 6,C ; 6152 CP ZX_DOLLAR ; $0D 6153 JR Z,V_STR_VAR <#V_STR_VAR> ; forward 6154 6155 SET 5,C ; 6156 6157 mark_1139: 6158 *V_CHAR:* 6159 CALL ALPHANUM <#ALPHANUM> 6160 JR NC,V_RUN_SYN <#V_RUN_SYN> ; forward when not 6161 6162 RES 6,C ; 6163 6164 RST _NEXT_CHAR 6165 JR V_CHAR <#V_CHAR> ; loop back 6166 6167 ; ___ 6168 6169 mark_1143: 6170 *V_STR_VAR:* 6171 RST _NEXT_CHAR 6172 RES 6,(IY+FLAGS-RAMBASE) ; Signal string result 6173 6174 mark_1148: 6175 *V_RUN_SYN:* 6176 LD B,C ; 6177 CALL SYNTAX_Z <#SYNTAX_Z> 6178 JR NZ,V_RUN <#V_RUN> ; forward 6179 6180 LD A,C ; 6181 AND $E0 ; 6182 SET 7,A ; 6183 LD C,A ; 6184 JR V_SYNTAX <#V_SYNTAX> ; forward 6185 6186 ; ___ 6187 6188 mark_1156: 6189 *V_RUN:* 6190 LD HL,(VARS) ; sv 6191 6192 mark_1159: 6193 *V_EACH:* 6194 LD A,(HL) ; 6195 AND $7F ; 6196 JR Z,V_80_BYTE <#V_80_BYTE> ; 6197 6198 CP C ; 6199 JR NZ,V_NEXT <#V_NEXT> ; 6200 6201 RLA ; 6202 ADD A,A ; 6203 JP P,V_FOUND_2 <#V_FOUND_2> 6204 6205 JR C,V_FOUND_2 <#V_FOUND_2> 6206 6207 POP DE ; 6208 PUSH DE ; 6209 PUSH HL ; 6210 6211 mark_116B: 6212 *V_MATCHES:* 6213 INC HL ; 6214 6215 mark_116C: 6216 *V_SPACES:* 6217 LD A,(DE) ; 6218 INC DE ; 6219 AND A ; 6220 JR Z,V_SPACES <#V_SPACES> ; back 6221 6222 CP (HL) ; 6223 JR Z,V_MATCHES <#V_MATCHES> ; back 6224 6225 OR $80 ; 6226 CP (HL) ; 6227 JR NZ,V_GET_PTR <#V_GET_PTR> ; forward 6228 6229 LD A,(DE) ; 6230 CALL ALPHANUM <#ALPHANUM> 6231 JR NC,V_FOUND_1 <#V_FOUND_1> ; forward 6232 6233 mark_117F: 6234 *V_GET_PTR:* 6235 POP HL ; 6236 6237 mark_1180: 6238 *V_NEXT:* 6239 PUSH BC ; 6240 CALL NEXT_ONE <#NEXT_ONE> 6241 EX DE,HL ; 6242 POP BC ; 6243 JR V_EACH <#V_EACH> ; back 6244 6245 ; ___ 6246 6247 mark_1188: 6248 *V_80_BYTE:* 6249 SET 7,B ; 6250 6251 mark_118A: 6252 *V_SYNTAX:* 6253 POP DE ; 6254 6255 RST _GET_CHAR 6256 CP $10 ; 6257 JR Z,V_PASS <#V_PASS> ; forward 6258 6259 SET 5,B ; 6260 JR V_END <#V_END> ; forward 6261 6262 ; ___ 6263 6264 mark_1194: 6265 *V_FOUND_1:* 6266 POP DE ; 6267 6268 mark_1195: 6269 *V_FOUND_2:* 6270 POP DE ; 6271 POP DE ; 6272 PUSH HL ; 6273 6274 RST _GET_CHAR 6275 6276 mark_1199: 6277 *V_PASS:* 6278 CALL ALPHANUM <#ALPHANUM> 6279 JR NC,V_END <#V_END> ; forward if not alphanumeric 6280 6281 6282 RST _NEXT_CHAR 6283 JR V_PASS <#V_PASS> ; back 6284 6285 ; ___ 6286 6287 mark_11A1: 6288 *V_END:* 6289 POP HL ; 6290 RL B ; 6291 BIT 6,B ; 6292 RET ; 6293 6294 ------------------------------------------------------------------------ 6295 6296 ; THE *'STK_VAR'* SUBROUTINE 6297 ------------------------------------------------------------------------ 6298 6299 6300 mark_11A7: 6301 *STK_VAR:* 6302 XOR A ; 6303 LD B,A ; 6304 BIT 7,C ; 6305 JR NZ,SV_COUNT <#SV_COUNT> ; forward 6306 6307 BIT 7,(HL) ; 6308 JR NZ,SV_ARRAYS <#SV_ARRAYS> ; forward 6309 6310 INC A ; 6311 6312 mark_11B2: 6313 *SV_SIMPLE_STR:* 6314 INC HL ; 6315 LD C,(HL) ; 6316 INC HL ; 6317 LD B,(HL) ; 6318 INC HL ; 6319 EX DE,HL ; 6320 CALL STK_STO_STR <#STK_STO_STR> 6321 6322 RST _GET_CHAR 6323 JP SV_SLICE_QUERY <#SV_SLICE_QUERY> ; jump forward 6324 6325 ; ___ 6326 6327 mark_11BF: 6328 *SV_ARRAYS:* 6329 INC HL ; 6330 INC HL ; 6331 INC HL ; 6332 LD B,(HL) ; 6333 BIT 6,C ; 6334 JR Z,SV_PTR <#SV_PTR> ; forward 6335 6336 DEC B ; 6337 JR Z,SV_SIMPLE_STR <#SV_SIMPLE_STR> ; forward 6338 6339 EX DE,HL ; 6340 6341 RST _GET_CHAR 6342 CP $10 ; 6343 JR NZ,REPORT_3 <#REPORT_3> ; forward 6344 6345 EX DE,HL ; 6346 6347 mark_11D1: 6348 *SV_PTR:* 6349 EX DE,HL ; 6350 JR SV_COUNT <#SV_COUNT> ; forward 6351 ; ___ 6352 mark_11D4: 6353 *SV_COMMA:* 6354 PUSH HL ; 6355 6356 RST _GET_CHAR 6357 POP HL ; 6358 CP ZX_COMMA ; $1A == 26 6359 JR Z,SV_LOOP <#SV_LOOP> ; forward 6360 6361 BIT 7,C ; 6362 JR Z,REPORT_3 <#REPORT_3> ; forward 6363 6364 BIT 6,C ; 6365 JR NZ,SV_CLOSE <#SV_CLOSE> ; forward 6366 6367 CP ZX_BRACKET_RIGHT ; $11 6368 JR NZ,SV_RPT_C <#SV_RPT_C> ; forward 6369 6370 6371 RST _NEXT_CHAR 6372 RET ; 6373 ; ___ 6374 mark_11E9: 6375 *SV_CLOSE:* 6376 CP ZX_BRACKET_RIGHT ; $11 6377 JR Z,SV_DIM <#SV_DIM> ; forward 6378 6379 CP $DF ; 6380 JR NZ,SV_RPT_C <#SV_RPT_C> ; forward 6381 6382 mark_11F1: 6383 *SV_CH_ADD:* 6384 RST _GET_CHAR 6385 DEC HL ; 6386 LD (CH_ADD),HL ; sv 6387 JR SV_SLICE <#SV_SLICE> ; forward 6388 6389 ; ___ 6390 6391 mark_11F8: 6392 *SV_COUNT:* 6393 LD HL,$0000 ; 6394 6395 mark_11FB: 6396 *SV_LOOP:* 6397 PUSH HL ; 6398 6399 RST _NEXT_CHAR 6400 POP HL ; 6401 LD A,C ; 6402 CP ZX_DOUBLE_QUOTE ; 6403 JR NZ,SV_MULT <#SV_MULT> ; forward 6404 6405 6406 RST _GET_CHAR 6407 CP ZX_BRACKET_RIGHT 6408 JR Z,SV_DIM <#SV_DIM> ; forward 6409 6410 CP ZX_TO ; 6411 JR Z,SV_CH_ADD <#SV_CH_ADD> ; back 6412 6413 mark_120C: 6414 *SV_MULT:* 6415 PUSH BC ; 6416 PUSH HL ; 6417 CALL DE_DE_PLUS_ONE <#DE_DE_PLUS_ONE> 6418 EX (SP),HL ; 6419 EX DE,HL ; 6420 CALL INT_EXP1 <#INT_EXP1> 6421 JR C,REPORT_3 <#REPORT_3> 6422 6423 DEC BC ; 6424 CALL GET_HL_TIMES_DE <#GET_HL_TIMES_DE> 6425 ADD HL,BC ; 6426 POP DE ; 6427 POP BC ; 6428 DJNZ SV_COMMA <#SV_COMMA> ; loop back 6429 6430 BIT 7,C ; 6431 6432 mark_1223: 6433 *SV_RPT_C:* 6434 JR NZ,SL_RPT_C <#SL_RPT_C> 6435 6436 PUSH HL ; 6437 BIT 6,C ; 6438 JR NZ,SV_ELEM_STR <#SV_ELEM_STR> 6439 6440 LD B,D ; 6441 LD C,E ; 6442 6443 RST _GET_CHAR 6444 CP ZX_BRACKET_RIGHT; is character a ')' ? 6445 JR Z,SV_NUMBER <#SV_NUMBER> ; skip forward 6446 6447 6448 mark_1231: 6449 *REPORT_3:* 6450 RST _ERROR_1 6451 DEFB $02 ; Error Report: Subscript wrong 6452 6453 6454 mark_1233: 6455 *SV_NUMBER:* 6456 RST _NEXT_CHAR 6457 POP HL ; 6458 LD DE,$0005 ; 6459 CALL GET_HL_TIMES_DE <#GET_HL_TIMES_DE> 6460 ADD HL,BC ; 6461 RET ; return >> 6462 6463 ; ___ 6464 6465 mark_123D: 6466 *SV_ELEM_STR:* 6467 CALL DE_DE_PLUS_ONE <#DE_DE_PLUS_ONE> 6468 EX (SP),HL ; 6469 CALL GET_HL_TIMES_DE <#GET_HL_TIMES_DE> 6470 POP BC ; 6471 ADD HL,BC ; 6472 INC HL ; 6473 LD B,D ; 6474 LD C,E ; 6475 EX DE,HL ; 6476 CALL STK_ST_0 <#STK_ST_0> 6477 6478 RST _GET_CHAR 6479 CP ZX_BRACKET_RIGHT ; is it ')' ? 6480 JR Z,SV_DIM <#SV_DIM> ; forward if so 6481 6482 CP ZX_COMMA ; $1A == 26 ; is it ',' ? 6483 JR NZ,REPORT_3 <#REPORT_3> ; back if not 6484 6485 mark_1256: 6486 *SV_SLICE:* 6487 CALL SLICING <#SLICING> 6488 6489 mark_1259: 6490 *SV_DIM:* 6491 RST _NEXT_CHAR 6492 6493 mark_125A: 6494 *SV_SLICE_QUERY:* 6495 CP $10 ; 6496 JR Z,SV_SLICE <#SV_SLICE> ; back 6497 6498 RES 6,(IY+FLAGS-RAMBASE) ; Signal string result 6499 RET ; return. 6500 6501 ------------------------------------------------------------------------ 6502 6503 ; THE *'SLICING'* SUBROUTINE 6504 ------------------------------------------------------------------------ 6505 6506 ; 6507 ; 6508 6509 mark_1263: 6510 *SLICING:* 6511 CALL SYNTAX_Z <#SYNTAX_Z> 6512 CALL NZ,STK_FETCH <#STK_FETCH> 6513 6514 RST _NEXT_CHAR 6515 CP ZX_BRACKET_RIGHT; is it ')' ? 6516 JR Z,SL_STORE <#SL_STORE> ; forward if so 6517 6518 PUSH DE ; 6519 XOR A ; 6520 PUSH AF ; 6521 PUSH BC ; 6522 LD DE,$0001 ; 6523 6524 RST _GET_CHAR 6525 POP HL ; 6526 CP ZX_TO ; is it 'TO' ? 6527 JR Z,SL_SECOND <#SL_SECOND> ; forward if so 6528 6529 POP AF ; 6530 CALL INT_EXP2 <#INT_EXP2> 6531 PUSH AF ; 6532 LD D,B ; 6533 LD E,C ; 6534 PUSH HL ; 6535 6536 RST _GET_CHAR 6537 POP HL ; 6538 CP ZX_TO ; is it 'TO' ? 6539 JR Z,SL_SECOND <#SL_SECOND> ; forward if so 6540 6541 CP ZX_BRACKET_RIGHT; $11 6542 6543 mark_128B: 6544 *SL_RPT_C:* 6545 JP NZ,REPORT_C <#REPORT_C> 6546 6547 LD H,D ; 6548 LD L,E ; 6549 JR SL_DEFINE <#SL_DEFINE> ; forward 6550 6551 ; ___ 6552 6553 mark_1292: 6554 *SL_SECOND:* 6555 PUSH HL ; 6556 6557 RST _NEXT_CHAR 6558 POP HL ; 6559 CP ZX_BRACKET_RIGHT; is it ')' ? 6560 JR Z,SL_DEFINE <#SL_DEFINE> ; forward if so 6561 6562 POP AF ; 6563 CALL INT_EXP2 <#INT_EXP2> 6564 PUSH AF ; 6565 6566 RST _GET_CHAR 6567 LD H,B ; 6568 LD L,C ; 6569 CP ZX_BRACKET_RIGHT; is it ')' ? 6570 JR NZ,SL_RPT_C <#SL_RPT_C> ; back if not 6571 6572 mark_12A5: 6573 *SL_DEFINE:* 6574 POP AF ; 6575 EX (SP),HL ; 6576 ADD HL,DE ; 6577 DEC HL ; 6578 EX (SP),HL ; 6579 AND A ; 6580 SBC HL,DE ; 6581 LD BC,$0000 ; 6582 JR C,SL_OVER <#SL_OVER> ; forward 6583 6584 INC HL ; 6585 AND A ; 6586 JP M,REPORT_3 <#REPORT_3> ; jump back 6587 6588 LD B,H ; 6589 LD C,L ; 6590 6591 mark_12B9: 6592 *SL_OVER:* 6593 POP DE ; 6594 RES 6,(IY+FLAGS-RAMBASE) ; Signal string result 6595 6596 mark_12BE: 6597 *SL_STORE:* 6598 CALL SYNTAX_Z <#SYNTAX_Z> 6599 RET Z ; return if checking syntax. 6600 6601 ------------------------------------------------------------------------ 6602 6603 ; THE *'STK_STORE'* SUBROUTINE 6604 ------------------------------------------------------------------------ 6605 6606 ; 6607 ; 6608 6609 mark_12C2: 6610 *STK_ST_0:* 6611 XOR A ; 6612 6613 mark_12C3: 6614 *STK_STO_STR:* 6615 PUSH BC ; 6616 CALL TEST_5_SP <#TEST_5_SP> 6617 POP BC ; 6618 LD HL,(STKEND) ; sv 6619 LD (HL),A ; 6620 INC HL ; 6621 LD (HL),E ; 6622 INC HL ; 6623 LD (HL),D ; 6624 INC HL ; 6625 LD (HL),C ; 6626 INC HL ; 6627 LD (HL),B ; 6628 INC HL ; 6629 LD (STKEND),HL ; sv 6630 RES 6,(IY+FLAGS-RAMBASE) ; Signal string result 6631 RET ; return. 6632 6633 ------------------------------------------------------------------------ 6634 6635 ; THE *'INT EXP'* SUBROUTINES 6636 ------------------------------------------------------------------------ 6637 6638 ; 6639 ; 6640 6641 mark_12DD: 6642 *INT_EXP1:* 6643 XOR A ; 6644 6645 mark_12DE: 6646 *INT_EXP2:* 6647 PUSH DE ; 6648 PUSH HL ; 6649 PUSH AF ; 6650 CALL CLASS_6 <#CLASS_6> 6651 POP AF ; 6652 CALL SYNTAX_Z <#SYNTAX_Z> 6653 JR Z,I_RESTORE <#I_RESTORE> ; forward if checking syntax 6654 6655 PUSH AF ; 6656 CALL FIND_INT <#FIND_INT> 6657 POP DE ; 6658 LD A,B ; 6659 OR C ; 6660 SCF ; Set Carry Flag 6661 JR Z,I_CARRY <#I_CARRY> ; forward 6662 6663 POP HL ; 6664 PUSH HL ; 6665 AND A ; 6666 SBC HL,BC ; 6667 6668 mark_12F9: 6669 *I_CARRY:* 6670 LD A,D ; 6671 SBC A,$00 ; 6672 6673 mark_12FC: 6674 *I_RESTORE:* 6675 POP HL ; 6676 POP DE ; 6677 RET ; 6678 6679 ------------------------------------------------------------------------ 6680 6681 ; THE *'DE,(DE+1)'* SUBROUTINE 6682 ------------------------------------------------------------------------ 6683 6684 ; INDEX and LOAD Z80 subroutine. 6685 ; This emulates the 6800 processor instruction LDX 1,X which loads a two_byte 6686 ; value from memory into the register indexing it. Often these are hardly worth 6687 ; the bother of writing as subroutines and this one doesn't save any time or 6688 ; memory. The timing and space overheads have to be offset against the ease of 6689 ; writing and the greater program readability from using such toolkit routines. 6690 6691 mark_12FF: 6692 *DE_DE_PLUS_ONE:* 6693 EX DE,HL ; move index address into HL. 6694 INC HL ; increment to address word. 6695 LD E,(HL) ; pick up word low_order byte. 6696 INC HL ; index high_order byte and 6697 LD D,(HL) ; pick it up. 6698 RET ; return with DE = word. 6699 6700 ------------------------------------------------------------------------ 6701 6702 ; THE *'GET_HL_TIMES_DE'* SUBROUTINE 6703 ------------------------------------------------------------------------ 6704 6705 ; 6706 6707 mark_1305: 6708 *GET_HL_TIMES_DE:* 6709 CALL SYNTAX_Z <#SYNTAX_Z> 6710 RET Z ; 6711 6712 PUSH BC ; 6713 LD B,$10 ; 6714 LD A,H ; 6715 LD C,L ; 6716 LD HL,$0000 ; 6717 6718 mark_1311: 6719 *HL_LOOP:* 6720 ADD HL,HL ; 6721 JR C,HL_END <#HL_END> ; forward with carry 6722 6723 RL C ; 6724 RLA ; 6725 JR NC,HL_AGAIN <#HL_AGAIN> ; forward with no carry 6726 6727 ADD HL,DE ; 6728 6729 mark_131A: 6730 *HL_END:* 6731 JP C,REPORT_4 <#REPORT_4> 6732 6733 mark_131D: 6734 *HL_AGAIN:* 6735 DJNZ HL_LOOP <#HL_LOOP> ; loop back 6736 6737 POP BC ; 6738 RET ; return. 6739 6740 ------------------------------------------------------------------------ 6741 6742 ; THE *'LET'* SUBROUTINE 6743 ------------------------------------------------------------------------ 6744 6745 ; 6746 ; 6747 6748 mark_1321: 6749 *LET:* 6750 LD HL,(DEST) 6751 BIT 1,(IY+FLAGX-RAMBASE) 6752 JR Z,L_EXISTS <#L_EXISTS> ; forward 6753 6754 LD BC,$0005 ; 6755 6756 mark_132D: 6757 *L_EACH_CH:* 6758 INC BC ; 6759 6760 ; check 6761 6762 mark_132E: 6763 *L_NO_SP:* 6764 INC HL ; 6765 LD A,(HL) ; 6766 AND A ; 6767 JR Z,L_NO_SP <#L_NO_SP> ; back 6768 6769 CALL ALPHANUM <#ALPHANUM> 6770 JR C,L_EACH_CH <#L_EACH_CH> ; back 6771 6772 CP ZX_DOLLAR ; is it '$' ? 6773 JP Z,L_NEW_STR <#L_NEW_STR> ; forward if so 6774 6775 6776 RST _BC_SPACES ; BC_SPACES 6777 PUSH DE ; 6778 LD HL,(DEST) ; 6779 DEC DE ; 6780 LD A,C ; 6781 SUB $06 ; 6782 LD B,A ; 6783 LD A,$40 ; 6784 JR Z,L_SINGLE <#L_SINGLE> 6785 6786 mark_134B: 6787 *L_CHAR:* 6788 INC HL ; 6789 LD A,(HL) ; 6790 AND A ; is it a space ? 6791 JR Z,L_CHAR <#L_CHAR> ; back 6792 6793 INC DE ; 6794 LD (DE),A ; 6795 DJNZ L_CHAR <#L_CHAR> ; loop back 6796 6797 OR $80 ; 6798 LD (DE),A ; 6799 LD A,$80 ; 6800 6801 mark_1359: 6802 *L_SINGLE:* 6803 LD HL,(DEST) ; 6804 XOR (HL) ; 6805 POP HL ; 6806 CALL L_FIRST <#L_FIRST> 6807 6808 mark_1361: 6809 *L_NUMERIC:* 6810 PUSH HL ; 6811 6812 RST _FP_CALC ;; 6813 DEFB __delete ;; 6814 DEFB __end_calc ;; 6815 6816 POP HL ; 6817 LD BC,$0005 ; 6818 AND A ; 6819 SBC HL,BC ; 6820 JR L_ENTER <#L_ENTER> ; forward 6821 6822 ; ___ 6823 6824 mark_136E: 6825 *L_EXISTS:* 6826 BIT 6,(IY+FLAGS-RAMBASE) ; Numeric or string result? 6827 JR Z,L_DELETE_STR <#L_DELETE_STR> ; forward 6828 6829 LD DE,$0006 ; 6830 ADD HL,DE ; 6831 JR L_NUMERIC <#L_NUMERIC> ; back 6832 6833 ; ___ 6834 6835 mark_137A: 6836 *L_DELETE_STR:* 6837 LD HL,(DEST) ; 6838 LD BC,(STRLEN) ; 6839 BIT 0,(IY+FLAGX-RAMBASE) 6840 JR NZ,L_ADD_STR <#L_ADD_STR> ; forward 6841 6842 LD A,B ; 6843 OR C ; 6844 RET Z ; 6845 6846 PUSH HL ; 6847 6848 RST _BC_SPACES 6849 PUSH DE ; 6850 PUSH BC ; 6851 LD D,H ; 6852 LD E,L ; 6853 INC HL ; 6854 LD (HL),$00 ; 6855 LDDR ; Copy Bytes 6856 PUSH HL ; 6857 CALL STK_FETCH <#STK_FETCH> 6858 POP HL ; 6859 EX (SP),HL ; 6860 AND A ; 6861 SBC HL,BC ; 6862 ADD HL,BC ; 6863 JR NC,L_LENGTH <#L_LENGTH> ; forward 6864 6865 LD B,H ; 6866 LD C,L ; 6867 6868 mark_13A3: 6869 *L_LENGTH:* 6870 EX (SP),HL ; 6871 EX DE,HL ; 6872 LD A,B ; 6873 OR C ; 6874 JR Z,L_IN_W_S <#L_IN_W_S> ; forward if zero 6875 6876 LDIR ; Copy Bytes 6877 6878 mark_13AB: 6879 *L_IN_W_S:* 6880 POP BC ; 6881 POP DE ; 6882 POP HL ; 6883 6884 ------------------------------------------------------------------------ 6885 6886 ; THE *'L_ENTER'* SUBROUTINE 6887 ; 6888 ; Part of the LET command contains a natural subroutine which is a 6889 ; conditional LDIR. The copy only occurs of BC is non-zero. 6890 ------------------------------------------------------------------------ 6891 6892 mark_13AE: 6893 *L_ENTER:* 6894 EX DE,HL ; 6895 #if ORIGINAL 6896 #else 6897 *COND_MV* 6898 #endif 6899 LD A,B ; 6900 OR C ; 6901 RET Z ; 6902 6903 PUSH DE ; 6904 LDIR ; Copy Bytes 6905 POP HL ; 6906 RET ; return. 6907 ------------------------------------------------------------------------ 6908 6909 mark_13B7: 6910 *L_ADD_STR:* 6911 DEC HL ; 6912 DEC HL ; 6913 DEC HL ; 6914 LD A,(HL) ; 6915 PUSH HL ; 6916 PUSH BC ; 6917 6918 CALL L_STRING <#L_STRING> 6919 6920 POP BC ; 6921 POP HL ; 6922 INC BC ; 6923 INC BC ; 6924 INC BC ; 6925 JP RECLAIM_2 <#RECLAIM_2> ; jump back to exit via RECLAIM_2 6926 6927 ; ___ 6928 6929 mark_13C8: 6930 *L_NEW_STR:* 6931 LD A,$60 ; prepare mask %01100000 6932 LD HL,(DEST) ; 6933 XOR (HL) ; 6934 6935 ------------------------------------------------------------------------ 6936 6937 ; THE *'L_STRING'* SUBROUTINE 6938 ------------------------------------------------------------------------ 6939 6940 ; 6941 6942 mark_13CE: 6943 *L_STRING:* 6944 PUSH AF ; 6945 CALL STK_FETCH <#STK_FETCH> 6946 EX DE,HL ; 6947 ADD HL,BC ; 6948 PUSH HL ; 6949 INC BC ; 6950 INC BC ; 6951 INC BC ; 6952 6953 RST _BC_SPACES 6954 EX DE,HL ; 6955 POP HL ; 6956 DEC BC ; 6957 DEC BC ; 6958 PUSH BC ; 6959 LDDR ; Copy Bytes 6960 EX DE,HL ; 6961 POP BC ; 6962 DEC BC ; 6963 LD (HL),B ; 6964 DEC HL ; 6965 LD (HL),C ; 6966 POP AF ; 6967 6968 mark_13E7: 6969 *L_FIRST:* 6970 PUSH AF ; 6971 CALL REC_V80 <#REC_V80> 6972 POP AF ; 6973 DEC HL ; 6974 LD (HL),A ; 6975 LD HL,(STKBOT) ; sv 6976 LD (E_LINE),HL ; sv 6977 DEC HL ; 6978 LD (HL),$80 ; 6979 RET ; 6980 6981 ------------------------------------------------------------------------ 6982 6983 ; THE *'STK_FETCH'* SUBROUTINE 6984 ------------------------------------------------------------------------ 6985 6986 ; This routine fetches a five-byte value from the calculator stack 6987 ; reducing the pointer to the end of the stack by five. 6988 ; For a floating-point number the exponent is in A and the mantissa 6989 ; is the thirty-two bits EDCB. 6990 ; For strings, the start of the string is in DE and the length in BC. 6991 ; A is unused. 6992 6993 mark_13F8: 6994 *STK_FETCH:* 6995 LD HL,(STKEND) ; load HL from system variable STKEND 6996 6997 DEC HL ; 6998 LD B,(HL) ; 6999 DEC HL ; 7000 LD C,(HL) ; 7001 DEC HL ; 7002 LD D,(HL) ; 7003 DEC HL ; 7004 LD E,(HL) ; 7005 DEC HL ; 7006 LD A,(HL) ; 7007 7008 LD (STKEND),HL ; set system variable STKEND to lower value. 7009 RET ; return. 7010 7011 ------------------------------------------------------------------------ 7012 7013 ; THE *'DIM'* COMMAND ROUTINE 7014 ------------------------------------------------------------------------ 7015 7016 ; An array is created and initialized to zeros which is also the space 7017 ; character on the ZX81. 7018 7019 mark_1409: 7020 *DIM:* 7021 CALL LOOK_VARS <#LOOK_VARS> 7022 7023 mark_140C: 7024 *D_RPORT_C:* 7025 JP NZ,REPORT_C <#REPORT_C> 7026 7027 CALL SYNTAX_Z <#SYNTAX_Z> 7028 JR NZ,D_RUN <#D_RUN> ; forward 7029 7030 RES 6,C ; 7031 CALL STK_VAR <#STK_VAR> 7032 CALL CHECK_END <#CHECK_END> 7033 7034 mark_141C: 7035 *D_RUN:* 7036 JR C,D_LETTER <#D_LETTER> ; forward 7037 7038 PUSH BC ; 7039 CALL NEXT_ONE <#NEXT_ONE> 7040 CALL RECLAIM_2 <#RECLAIM_2> 7041 POP BC ; 7042 7043 mark_1426: 7044 *D_LETTER:* 7045 SET 7,C ; 7046 LD B,$00 ; 7047 PUSH BC ; 7048 LD HL,$0001 ; 7049 BIT 6,C ; 7050 JR NZ,D_SIZE <#D_SIZE> ; forward 7051 7052 LD L,$05 ; 7053 7054 mark_1434: 7055 *D_SIZE:* 7056 EX DE,HL ; 7057 7058 mark_1435: 7059 *D_NO_LOOP:* 7060 RST _NEXT_CHAR 7061 LD H,$40 ; 7062 CALL INT_EXP1 <#INT_EXP1> 7063 JP C,REPORT_3 <#REPORT_3> 7064 7065 POP HL ; 7066 PUSH BC ; 7067 INC H ; 7068 PUSH HL ; 7069 LD H,B ; 7070 LD L,C ; 7071 CALL GET_HL_TIMES_DE <#GET_HL_TIMES_DE> 7072 EX DE,HL ; 7073 7074 RST _GET_CHAR 7075 CP ZX_COMMA ; $1A == 26 7076 JR Z,D_NO_LOOP <#D_NO_LOOP> ; back 7077 7078 CP ZX_BRACKET_RIGHT; is it ')' ? 7079 JR NZ,D_RPORT_C <#D_RPORT_C> ; back if not 7080 7081 7082 RST _NEXT_CHAR 7083 POP BC ; 7084 LD A,C ; 7085 LD L,B ; 7086 LD H,$00 ; 7087 INC HL ; 7088 INC HL ; 7089 ADD HL,HL ; 7090 ADD HL,DE ; 7091 JP C,REPORT_4 <#REPORT_4> 7092 7093 PUSH DE ; 7094 PUSH BC ; 7095 PUSH HL ; 7096 LD B,H ; 7097 LD C,L ; 7098 LD HL,(E_LINE) ; sv 7099 DEC HL ; 7100 CALL MAKE_ROOM <#MAKE_ROOM> 7101 INC HL ; 7102 LD (HL),A ; 7103 POP BC ; 7104 DEC BC ; 7105 DEC BC ; 7106 DEC BC ; 7107 INC HL ; 7108 LD (HL),C ; 7109 INC HL ; 7110 LD (HL),B ; 7111 POP AF ; 7112 INC HL ; 7113 LD (HL),A ; 7114 LD H,D ; 7115 LD L,E ; 7116 DEC DE ; 7117 LD (HL),0 ; 7118 POP BC ; 7119 LDDR ; Copy Bytes 7120 7121 mark_147F: 7122 *DIM_SIZES:* 7123 POP BC ; 7124 LD (HL),B ; 7125 DEC HL ; 7126 LD (HL),C ; 7127 DEC HL ; 7128 DEC A ; 7129 JR NZ,DIM_SIZES <#DIM_SIZES> ; back 7130 7131 RET ; return. 7132 7133 ------------------------------------------------------------------------ 7134 7135 ; THE *'RESERVE'* ROUTINE 7136 ------------------------------------------------------------------------ 7137 7138 ; 7139 ; 7140 7141 mark_1488: 7142 *RESERVE:* 7143 LD HL,(STKBOT) ; address STKBOT 7144 DEC HL ; now last byte of workspace 7145 CALL MAKE_ROOM <#MAKE_ROOM> 7146 INC HL ; 7147 INC HL ; 7148 POP BC ; 7149 LD (E_LINE),BC ; sv 7150 POP BC ; 7151 EX DE,HL ; 7152 INC HL ; 7153 RET ; 7154 7155 ------------------------------------------------------------------------ 7156 7157 ; THE *'CLEAR'* COMMAND ROUTINE 7158 ------------------------------------------------------------------------ 7159 7160 ; 7161 ; 7162 7163 mark_149A: 7164 *CLEAR:* 7165 LD HL,(VARS) ; sv 7166 LD (HL),$80 ; 7167 INC HL ; 7168 LD (E_LINE),HL ; sv 7169 7170 ------------------------------------------------------------------------ 7171 7172 ; THE *'X_TEMP'* SUBROUTINE 7173 ------------------------------------------------------------------------ 7174 7175 ; 7176 ; 7177 7178 mark_14A3: 7179 *X_TEMP:* 7180 LD HL,(E_LINE) ; sv 7181 7182 ------------------------------------------------------------------------ 7183 7184 ; THE *'SET_STK'* ROUTINES 7185 ------------------------------------------------------------------------ 7186 7187 ; 7188 ; 7189 7190 mark_14A6: 7191 *SET_STK_B:* 7192 LD (STKBOT),HL ; sv 7193 7194 ; 7195 7196 mark_14A9: 7197 *SET_STK_E:* 7198 LD (STKEND),HL ; sv 7199 RET ; 7200 7201 ------------------------------------------------------------------------ 7202 7203 ; THE *'CURSOR_IN'* ROUTINE 7204 ------------------------------------------------------------------------ 7205 7206 ; This routine is called to set the edit line to the minimum cursor/newline 7207 ; and to set STKEND, the start of free space, at the next position. 7208 7209 mark_14AD: 7210 *CURSOR_IN:* 7211 LD HL,(E_LINE) ; fetch start of edit line 7212 LD (HL),ZX_CURSOR ; insert cursor character 7213 7214 INC HL ; point to next location. 7215 LD (HL),ZX_NEWLINE ; insert NEWLINE character 7216 INC HL ; point to next free location. 7217 7218 LD (IY+DF_SZ-RAMBASE),2 ; set lower screen display file size 7219 7220 JR SET_STK_B <#SET_STK_B> ; exit via SET_STK_B above 7221 7222 ------------------------------------------------------------------------ 7223 7224 ; THE *'SET_MIN'* SUBROUTINE 7225 ------------------------------------------------------------------------ 7226 7227 ; 7228 ; 7229 7230 mark_14BC: 7231 *SET_MIN:* 7232 LD HL,$405D ; normal location of calculator's memory area 7233 LD (MEM),HL ; update system variable MEM 7234 LD HL,(STKBOT) ; 7235 JR SET_STK_E <#SET_STK_E> ; back 7236 7237 7238 ------------------------------------------------------------------------ 7239 7240 ; THE *'RECLAIM THE END_MARKER'* ROUTINE 7241 ------------------------------------------------------------------------ 7242 7243 7244 mark_14C7: 7245 *REC_V80:* 7246 LD DE,(E_LINE) ; sv 7247 JP RECLAIM_1 <#RECLAIM_1> 7248 7249 ------------------------------------------------------------------------ 7250 7251 ; THE *'ALPHA'* SUBROUTINE 7252 ------------------------------------------------------------------------ 7253 7254 7255 mark_14CE: 7256 *ALPHA:* 7257 CP ZX_A ; $26 7258 JR ALPHA_2 <#ALPHA_2> ; skip forward 7259 7260 7261 ------------------------------------------------------------------------ 7262 7263 ; THE *'ALPHANUM'* SUBROUTINE 7264 ------------------------------------------------------------------------ 7265 7266 7267 mark_14D2: 7268 *ALPHANUM:* 7269 CP ZX_0 ; 7270 7271 7272 mark_14D4: 7273 *ALPHA_2:* 7274 CCF ; Complement Carry Flag 7275 RET NC ; 7276 7277 CP $40 ; 7278 RET ; 7279 7280 7281 ------------------------------------------------------------------------ 7282 7283 ; THE *'DECIMAL TO FLOATING POINT'* SUBROUTINE 7284 ------------------------------------------------------------------------ 7285 7286 ; 7287 7288 mark_14D9: 7289 *DEC_TO_FP:* 7290 CALL INT_TO_FP <#INT_TO_FP> ; gets first part 7291 CP ZX_PERIOD ; is character a '.' ? 7292 JR NZ,E_FORMAT <#E_FORMAT> ; forward if not 7293 7294 7295 RST _FP_CALC ;; 7296 DEFB __stk_one ;; 7297 DEFB __st_mem_0 ;; 7298 DEFB __delete ;; 7299 DEFB __end_calc ;; 7300 7301 7302 mark_14E5: 7303 7304 *NXT_DGT_1:* 7305 RST _NEXT_CHAR 7306 CALL STK_DIGIT <#STK_DIGIT> 7307 JR C,E_FORMAT <#E_FORMAT> ; forward 7308 7309 7310 RST _FP_CALC ;; 7311 DEFB __get_mem_0 ;; 7312 DEFB __stk_ten ;; 7313 #if ORIGINAL 7314 DEFB __division ; 7315 DEFB $C0 ;;st-mem-0 7316 DEFB __multiply ;; 7317 #else 7318 DEFB $04 ;;+multiply 7319 DEFB $C0 ;;st-mem-0 7320 DEFB $05 ;;+division 7321 #endif 7322 DEFB __addition ;; 7323 DEFB __end_calc ;; 7324 7325 JR NXT_DGT_1 <#NXT_DGT_1> ; loop back till exhausted 7326 7327 ; ___ 7328 7329 mark_14F5: 7330 *E_FORMAT:* 7331 CP ZX_E ; is character 'E' ? 7332 RET NZ ; return if not 7333 7334 LD (IY+MEM_0_1st-RAMBASE),$FF ; initialize sv MEM_0_1st to $FF TRUE 7335 7336 RST _NEXT_CHAR 7337 CP ZX_PLUS ; is character a '+' ? 7338 JR Z,SIGN_DONE <#SIGN_DONE> ; forward if so 7339 7340 CP ZX_MINUS ; is it a '-' ? 7341 JR NZ,ST_E_PART <#ST_E_PART> ; forward if not 7342 7343 INC (IY+MEM_0_1st-RAMBASE) ; sv MEM_0_1st change to FALSE 7344 7345 mark_1508: 7346 *SIGN_DONE:* 7347 RST _NEXT_CHAR 7348 7349 mark_1509: 7350 *ST_E_PART:* 7351 CALL INT_TO_FP <#INT_TO_FP> 7352 7353 RST _FP_CALC ;; m, e. 7354 DEFB __get_mem_0 ;; m, e, (1/0) TRUE/FALSE 7355 DEFB __jump_true ;; 7356 DEFB E_POSTVE <#E_POSTVE> - $ ;; 7357 DEFB __negate ;; m, _e 7358 7359 mark_1511: 7360 *E_POSTVE:* 7361 DEFB __e_to_fp ;; x. 7362 DEFB __end_calc ;; x. 7363 7364 RET ; return. 7365 7366 7367 ------------------------------------------------------------------------ 7368 7369 ; THE *'STK_DIGIT'* SUBROUTINE 7370 ------------------------------------------------------------------------ 7371 7372 ; 7373 7374 mark_1514: 7375 *STK_DIGIT:* 7376 CP ZX_0 ; 7377 RET C ; 7378 7379 CP ZX_A ; $26 7380 CCF ; Complement Carry Flag 7381 RET C ; 7382 7383 SUB ZX_0 ; 7384 7385 ------------------------------------------------------------------------ 7386 7387 ; THE *'STACK_A'* SUBROUTINE 7388 ------------------------------------------------------------------------ 7389 7390 ; 7391 7392 7393 mark_151D: 7394 *STACK_A:* 7395 LD C,A ; 7396 LD B,0 ; 7397 7398 ------------------------------------------------------------------------ 7399 7400 ; THE *'STACK_BC'* SUBROUTINE 7401 ------------------------------------------------------------------------ 7402 7403 ; The ZX81 does not have an integer number format so the BC register contents 7404 ; must be converted to their full floating-point form. 7405 7406 mark_1520: 7407 *STACK_BC:* 7408 LD IY,ERR_NR ; re-initialize the system variables pointer. 7409 PUSH BC ; save the integer value. 7410 7411 ; now stack zero, five zero bytes as a starting point. 7412 7413 RST _FP_CALC ;; 7414 DEFB __stk_zero ;; 0. 7415 DEFB __end_calc ;; 7416 7417 POP BC ; restore integer value. 7418 7419 LD (HL),$91 ; place $91 in exponent 65536. 7420 ; this is the maximum possible value 7421 7422 LD A,B ; fetch hi-byte. 7423 AND A ; test for zero. 7424 JR NZ,STK_BC_2 <#STK_BC_2> ; forward if not zero 7425 7426 LD (HL),A ; else make exponent zero again 7427 OR C ; test lo-byte 7428 RET Z ; return if BC was zero - done. 7429 7430 ; else there has to be a set bit if only the value one. 7431 7432 LD B,C ; save C in B. 7433 LD C,(HL) ; fetch zero to C 7434 LD (HL),$89 ; make exponent $89 256. 7435 7436 mark_1536: 7437 *STK_BC_2:* 7438 DEC (HL) ; decrement exponent - halving number 7439 SLA C ; C<-76543210<-0 7440 RL B ; C<-76543210<-C 7441 JR NC,STK_BC_2 <#STK_BC_2> ; loop back if no carry 7442 7443 SRL B ; 0->76543210->C 7444 RR C ; C->76543210->C 7445 7446 INC HL ; address first byte of mantissa 7447 LD (HL),B ; insert B 7448 INC HL ; address second byte of mantissa 7449 LD (HL),C ; insert C 7450 7451 DEC HL ; point to the 7452 DEC HL ; exponent again 7453 RET ; return. 7454 7455 ------------------------------------------------------------------------ 7456 7457 ; THE *'INTEGER TO FLOATING POINT'* SUBROUTINE 7458 ------------------------------------------------------------------------ 7459 7460 ; 7461 ; 7462 7463 mark_1548: 7464 *INT_TO_FP:* 7465 PUSH AF ; 7466 7467 RST _FP_CALC ;; 7468 DEFB __stk_zero ;; 7469 DEFB __end_calc ;; 7470 7471 POP AF ; 7472 7473 mark_154D: 7474 *NXT_DGT_2:* 7475 CALL STK_DIGIT <#STK_DIGIT> 7476 RET C ; 7477 7478 RST _FP_CALC ;; 7479 DEFB __exchange ;; 7480 DEFB __stk_ten ;; 7481 DEFB __multiply ;; 7482 DEFB __addition ;; 7483 DEFB __end_calc ;; 7484 7485 RST _NEXT_CHAR 7486 JR NXT_DGT_2 <#NXT_DGT_2> 7487 7488 7489 ------------------------------------------------------------------------ 7490 7491 ; THE *'E_FORMAT TO FLOATING POINT'* SUBROUTINE 7492 ------------------------------------------------------------------------ 7493 7494 ; (Offset $38: 'e_to_fp') 7495 ; invoked from DEC_TO_FP and PRINT_FP. 7496 ; e.g. 2.3E4 is 23000. 7497 ; This subroutine evaluates xEm where m is a positive or negative integer. 7498 ; At a simple level x is multiplied by ten for every unit of m. 7499 ; If the decimal exponent m is negative then x is divided by ten for each unit. 7500 ; A short-cut is taken if the exponent is greater than seven and in this 7501 ; case the exponent is reduced by seven and the value is multiplied or divided 7502 ; by ten million. 7503 ; Note. for the ZX Spectrum an even cleverer method was adopted which involved 7504 ; shifting the bits out of the exponent so the result was achieved with six 7505 ; shifts at most. The routine below had to be completely re-written mostly 7506 ; in Z80 machine code. 7507 ; Although no longer operable, the calculator literal was retained for old 7508 ; times sake, the routine being invoked directly from a machine code CALL. 7509 ; 7510 ; On entry in the ZX81, m, the exponent, is the 'last value', and the 7511 ; floating-point decimal mantissa is beneath it. 7512 7513 7514 mark_155A: 7515 *e_to_fp:* 7516 RST _FP_CALC ;; x, m. 7517 DEFB __duplicate ;; x, m, m. 7518 DEFB __less_0 ;; x, m, (1/0). 7519 DEFB __st_mem_0 ;; x, m, (1/0). 7520 DEFB __delete ;; x, m. 7521 DEFB __abs ;; x, +m. 7522 7523 mark_1560: 7524 *E_LOOP:* 7525 DEFB __stk_one ;; x, m,1. 7526 DEFB __subtract ;; x, m-1. 7527 DEFB __duplicate ;; x, m-1,m-1. 7528 DEFB __less_0 ;; x, m-1, (1/0). 7529 DEFB __jump_true ;; x, m-1. 7530 DEFB E_END <#E_END> - $ ;; x, m-1. 7531 7532 DEFB __duplicate ;; x, m-1, m-1. 7533 DEFB __stk_data ;; 7534 DEFB $33 ;;Exponent: $83, Bytes: 1 7535 7536 DEFB $40 ;;(+00,+00,+00) x, m-1, m-1, 6. 7537 DEFB __subtract ;; x, m-1, m-7. 7538 DEFB __duplicate ;; x, m-1, m-7, m-7. 7539 DEFB __less_0 ;; x, m-1, m-7, (1/0). 7540 DEFB __jump_true ;; x, m-1, m-7. 7541 DEFB E_LOW <#E_LOW> - $ ;; 7542 7543 ; but if exponent m is higher than 7 do a bigger chunk. 7544 ; multiplying (or dividing if negative) by 10 million - 1e7. 7545 7546 DEFB __exchange ;; x, m-7, m-1. 7547 DEFB __delete ;; x, m-7. 7548 DEFB __exchange ;; m-7, x. 7549 DEFB __stk_data ;; 7550 DEFB $80 ;;Bytes: 3 7551 DEFB $48 ;;Exponent $98 7552 DEFB $18,$96,$80 ;;(+00) m-7, x, 10,000,000 (=f) 7553 DEFB __jump ;; 7554 DEFB E_CHUNK <#E_CHUNK> - $ ;; 7555 7556 ; ___ 7557 7558 mark_157A: 7559 *E_LOW:* 7560 DEFB __delete ;; x, m-1. 7561 DEFB __exchange ;; m-1, x. 7562 DEFB __stk_ten ;; m-1, x, 10 (=f). 7563 7564 mark_157D: 7565 *E_CHUNK:* 7566 DEFB __get_mem_0 ;; m-1, x, f, (1/0) 7567 DEFB __jump_true ;; m-1, x, f 7568 DEFB E_DIVSN <#E_DIVSN> - $ ;; 7569 7570 DEFB __multiply ;; m-1, x*f. 7571 DEFB __jump ;; 7572 DEFB E_SWAP <#E_SWAP> - $ ;; 7573 7574 ; ___ 7575 7576 mark_1583: 7577 *E_DIVSN:* 7578 DEFB __division ;; m-1, x/f (= new x). 7579 7580 mark_1584: 7581 *E_SWAP:* 7582 DEFB __exchange ;; x, m-1 (= new m). 7583 DEFB __jump ;; x, m. 7584 DEFB E_LOOP <#E_LOOP> - $ ;; 7585 7586 ; ___ 7587 7588 mark_1587: 7589 *E_END:* 7590 DEFB __delete ;; x. (-1) 7591 DEFB __end_calc ;; x. 7592 7593 RET ; return. 7594 7595 ------------------------------------------------------------------------ 7596 7597 ; THE *'FLOATING-POINT TO BC'* SUBROUTINE 7598 ------------------------------------------------------------------------ 7599 7600 ; The floating-point form on the calculator stack is compressed directly into 7601 ; the BC register rounding up if necessary. 7602 ; Valid range is 0 to 65535.4999 7603 7604 mark_158A: 7605 *FP_TO_BC:* 7606 CALL STK_FETCH <#STK_FETCH> ; exponent to A 7607 ; mantissa to EDCB. 7608 AND A ; test for value zero. 7609 JR NZ,FPBC_NZRO <#FPBC_NZRO> ; forward if not 7610 7611 ; else value is zero 7612 7613 LD B,A ; zero to B 7614 LD C,A ; also to C 7615 PUSH AF ; save the flags on machine stack 7616 JR FPBC_END <#FPBC_END> ; forward 7617 7618 ; ___ 7619 7620 ; EDCB => BCE 7621 7622 mark_1595: 7623 *FPBC_NZRO:* 7624 LD B,E ; transfer the mantissa from EDCB 7625 LD E,C ; to BCE. Bit 7 of E is the 17th bit which 7626 LD C,D ; will be significant for rounding if the 7627 ; number is already normalized. 7628 7629 SUB $91 ; subtract 65536 7630 CCF ; complement carry flag 7631 BIT 7,B ; test sign bit 7632 PUSH AF ; push the result 7633 7634 SET 7,B ; set the implied bit 7635 JR C,FPBC_END <#FPBC_END> ; forward with carry from SUB/CCF 7636 ; number is too big. 7637 7638 INC A ; increment the exponent and 7639 NEG ; negate to make range $00 - $0F 7640 7641 CP $08 ; test if one or two bytes 7642 JR C,BIG_INT <#BIG_INT> ; forward with two 7643 7644 LD E,C ; shift mantissa 7645 LD C,B ; 8 places right 7646 LD B,$00 ; insert a zero in B 7647 SUB $08 ; reduce exponent by eight 7648 7649 mark_15AF: 7650 *BIG_INT:* 7651 AND A ; test the exponent 7652 LD D,A ; save exponent in D. 7653 7654 LD A,E ; fractional bits to A 7655 RLCA ; rotate most significant bit to carry for 7656 ; rounding of an already normal number. 7657 7658 JR Z,EXP_ZERO <#EXP_ZERO> ; forward if exponent zero 7659 ; the number is normalized 7660 7661 mark_15B5: 7662 *FPBC_NORM:* 7663 SRL B ; 0->76543210->C 7664 RR C ; C->76543210->C 7665 7666 DEC D ; decrement exponent 7667 7668 JR NZ,FPBC_NORM <#FPBC_NORM> ; loop back till zero 7669 7670 mark_15BC: 7671 *EXP_ZERO:* 7672 JR NC,FPBC_END <#FPBC_END> ; forward without carry to NO_ROUND ??? 7673 7674 INC BC ; round up. 7675 LD A,B ; test result 7676 OR C ; for zero 7677 JR NZ,FPBC_END <#FPBC_END> ; forward if not to GRE_ZERO ??? 7678 7679 POP AF ; restore sign flag 7680 SCF ; set carry flag to indicate overflow 7681 PUSH AF ; save combined flags again 7682 7683 mark_15C6: 7684 *FPBC_END:* 7685 PUSH BC ; save BC value 7686 7687 ; set HL and DE to calculator stack pointers. 7688 7689 RST _FP_CALC ;; 7690 DEFB __end_calc ;; 7691 7692 7693 POP BC ; restore BC value 7694 POP AF ; restore flags 7695 LD A,C ; copy low byte to A also. 7696 RET ; return 7697 7698 ------------------------------------------------------------------------ 7699 7700 ; THE *'FLOATING-POINT TO A'* SUBROUTINE 7701 ------------------------------------------------------------------------ 7702 7703 ; 7704 ; 7705 7706 mark_15CD: 7707 *FP_TO_A:* 7708 CALL FP_TO_BC <#FP_TO_BC> 7709 RET C ; 7710 7711 PUSH AF ; 7712 DEC B ; 7713 INC B ; 7714 JR Z,FP_A_END <#FP_A_END> ; forward if in range 7715 7716 POP AF ; fetch result 7717 SCF ; set carry flag signaling overflow 7718 RET ; return 7719 7720 mark_15D9: 7721 *FP_A_END:* 7722 POP AF ; 7723 RET ; 7724 7725 7726 ------------------------------------------------------------------------ 7727 7728 ; THE *'PRINT A FLOATING-POINT NUMBER'* SUBROUTINE 7729 ------------------------------------------------------------------------ 7730 7731 ; prints 'last value' x on calculator stack. 7732 ; There are a wide variety of formats see Chapter 4. 7733 ; e.g. 7734 ; PI prints as 3.1415927 7735 ; .123 prints as 0.123 7736 ; .0123 prints as .0123 7737 ; 999999999999 prints as 1000000000000 7738 ; 9876543210123 prints as 9876543200000 7739 7740 ; Begin by isolating zero and just printing the '0' character 7741 ; for that case. For negative numbers print a leading '-' and 7742 ; then form the absolute value of x. 7743 7744 mark_15DB: 7745 *PRINT_FP:* 7746 RST _FP_CALC ;; x. 7747 DEFB __duplicate ;; x, x. 7748 DEFB __less_0 ;; x, (1/0). 7749 DEFB __jump_true ;; 7750 DEFB PF_NEGTVE <#PF_NEGTVE> - $ ;; x. 7751 7752 DEFB __duplicate ;; x, x 7753 DEFB __greater_0 ;; x, (1/0). 7754 DEFB __jump_true ;; 7755 DEFB PF_POSTVE <#PF_POSTVE> - $ ;; x. 7756 7757 DEFB __delete ;; . 7758 DEFB __end_calc ;; . 7759 7760 LD A,ZX_0 ; load accumulator with character '0' 7761 7762 RST _PRINT_A 7763 RET ; return. >> 7764 7765 ; ___ 7766 7767 mark_15EA: 7768 *PF_NEGTVE:* 7769 DEFB __abs ;; +x. 7770 DEFB __end_calc ;; x. 7771 7772 LD A,ZX_MINUS ; load accumulator with '-' 7773 7774 RST _PRINT_A 7775 7776 RST _FP_CALC ;; x. 7777 7778 mark_15F0: 7779 *PF_POSTVE:* 7780 DEFB __end_calc ;; x. 7781 7782 ; register HL addresses the exponent of the floating-point value. 7783 ; if positive, and point floats to left, then bit 7 is set. 7784 7785 LD A,(HL) ; pick up the exponent byte 7786 CALL STACK_A <#STACK_A> ; places on calculator stack. 7787 7788 ; now calculate roughly the number of digits, n, before the decimal point by 7789 ; subtracting a half from true exponent and multiplying by log to 7790 ; the base 10 of 2. 7791 ; The true number could be one higher than n, the integer result. 7792 7793 RST _FP_CALC ;; x, e. 7794 DEFB __stk_data ;; 7795 DEFB $78 ;;Exponent: $88, Bytes: 2 7796 DEFB $00,$80 ;;(+00,+00) x, e, 128.5. 7797 DEFB __subtract ;; x, e -.5. 7798 DEFB __stk_data ;; 7799 DEFB $EF ;;Exponent: $7F, Bytes: 4 7800 DEFB $1A,$20,$9A,$85 ;; .30103 (log10 2) 7801 DEFB __multiply ;; x, 7802 DEFB __int ;; 7803 DEFB __st_mem_1 ;; x, n. 7804 7805 7806 DEFB __stk_data ;; 7807 DEFB $34 ;;Exponent: $84, Bytes: 1 7808 DEFB $00 ;;(+00,+00,+00) x, n, 8. 7809 7810 DEFB __subtract ;; x, n-8. 7811 DEFB __negate ;; x, 8-n. 7812 DEFB __e_to_fp ;; x * (10^n) 7813 7814 ; finally the 8 or 9 digit decimal is rounded. 7815 ; a ten-digit integer can arise in the case of, say, 999999999.5 7816 ; which gives 1000000000. 7817 7818 DEFB __stk_half ;; 7819 DEFB __addition ;; 7820 DEFB __int ;; i. 7821 DEFB __end_calc ;; 7822 7823 ; If there were 8 digits then final rounding will take place on the calculator 7824 ; stack above and the next two instructions insert a masked zero so that 7825 ; no further rounding occurs. If the result is a 9 digit integer then 7826 ; rounding takes place within the buffer. 7827 7828 LD HL,$406B ; address system variable MEM_2_5th 7829 ; which could be the 'ninth' digit. 7830 LD (HL),$90 ; insert the value $90 10010000 7831 7832 ; now starting from lowest digit lay down the 8, 9 or 10 digit integer 7833 ; which represents the significant portion of the number 7834 ; e.g. PI will be the nine-digit integer 314159265 7835 7836 LD B,10 ; count is ten digits. 7837 7838 mark_1615: 7839 *PF_LOOP:* 7840 INC HL ; increase pointer 7841 7842 PUSH HL ; preserve buffer address. 7843 PUSH BC ; preserve counter. 7844 7845 RST _FP_CALC ;; i. 7846 DEFB __stk_ten ;; i, 10. 7847 DEFB __n_mod_m ;; i mod 10, i/10 7848 DEFB __exchange ;; i/10, remainder. 7849 DEFB __end_calc ;; 7850 7851 CALL FP_TO_A <#FP_TO_A> ; $00-$09 7852 7853 OR $90 ; make left hand nibble 9 7854 7855 POP BC ; restore counter 7856 POP HL ; restore buffer address. 7857 7858 LD (HL),A ; insert masked digit in buffer. 7859 DJNZ PF_LOOP <#PF_LOOP> ; loop back for all ten 7860 7861 ; the most significant digit will be last but if the number is exhausted then 7862 ; the last one or two positions will contain zero ($90). 7863 7864 ; e.g. for 'one' we have zero as estimate of leading digits. 7865 ; 1*10^8 100000000 as integer value 7866 ; 90 90 90 90 90 90 90 90 91 90 as buffer mem3/mem4 contents. 7867 7868 7869 INC HL ; advance pointer to one past buffer 7870 LD BC,$0008 ; set C to 8 ( B is already zero ) 7871 PUSH HL ; save pointer. 7872 7873 mark_162C: 7874 *PF_NULL:* 7875 DEC HL ; decrease pointer 7876 LD A,(HL) ; fetch masked digit 7877 CP $90 ; is it a leading zero ? 7878 JR Z,PF_NULL <#PF_NULL> ; loop back if so 7879 7880 ; at this point a significant digit has been found. carry is reset. 7881 7882 SBC HL,BC ; subtract eight from the address. 7883 PUSH HL ; ** save this pointer too 7884 LD A,(HL) ; fetch addressed byte 7885 ADD A,$6B ; add $6B - forcing a round up ripple 7886 ; if $95 or over. 7887 PUSH AF ; save the carry result. 7888 7889 ; now enter a loop to round the number. After rounding has been considered 7890 ; a zero that has arisen from rounding or that was present at that position 7891 ; originally is changed from $90 to $80. 7892 7893 mark_1639: 7894 *PF_RND_LP:* 7895 POP AF ; retrieve carry from machine stack. 7896 INC HL ; increment address 7897 LD A,(HL) ; fetch new byte 7898 ADC A,0 ; add in any carry 7899 7900 DAA ; decimal adjust accumulator 7901 ; carry will ripple through the '9' 7902 7903 PUSH AF ; save carry on machine stack. 7904 AND $0F ; isolate character 0 - 9 AND set zero flag 7905 ; if zero. 7906 LD (HL),A ; place back in location. 7907 SET 7,(HL) ; set bit 7 to show printable. 7908 ; but not if trailing zero after decimal point. 7909 JR Z,PF_RND_LP <#PF_RND_LP> ; back if a zero 7910 ; to consider further rounding and/or trailing 7911 ; zero identification. 7912 7913 POP AF ; balance stack 7914 POP HL ; ** retrieve lower pointer 7915 7916 ; now insert 6 trailing zeros which are printed if before the decimal point 7917 ; but mark the end of printing if after decimal point. 7918 ; e.g. 9876543210123 is printed as 9876543200000 7919 ; 123.456001 is printed as 123.456 7920 7921 LD B,6 ; the count is six. 7922 7923 mark_164B: 7924 *PF_ZERO_6:* 7925 LD (HL),$80 ; insert a masked zero 7926 DEC HL ; decrease pointer. 7927 DJNZ PF_ZERO_6 <#PF_ZERO_6> ; loop back for all six 7928 7929 ; n-mod-m reduced the number to zero and this is now deleted from the calculator 7930 ; stack before fetching the original estimate of leading digits. 7931 7932 7933 RST _FP_CALC ;; 0. 7934 DEFB __delete ;; . 7935 DEFB __get_mem_1 ;; n. 7936 DEFB __end_calc ;; n. 7937 7938 CALL FP_TO_A <#FP_TO_A> 7939 JR Z,PF_POS <#PF_POS> ; skip forward if positive 7940 7941 NEG ; negate makes positive 7942 7943 mark_165B: 7944 *PF_POS:* 7945 LD E,A ; transfer count of digits to E 7946 INC E ; increment twice 7947 INC E ; 7948 POP HL ; * retrieve pointer to one past buffer. 7949 7950 mark_165F: 7951 *GET_FIRST:* 7952 DEC HL ; decrement address. 7953 DEC E ; decrement digit counter. 7954 LD A,(HL) ; fetch masked byte. 7955 AND $0F ; isolate right-hand nibble. 7956 JR Z,GET_FIRST <#GET_FIRST> ; back with leading zero 7957 7958 ; now determine if E-format printing is needed 7959 7960 LD A,E ; transfer now accurate number count to A. 7961 SUB 5 ; subtract five 7962 CP 8 ; compare with 8 as maximum digits is 13. 7963 JP P,PF_E_FMT <#PF_E_FMT> ; forward if positive to PF_E_FMT 7964 7965 CP $F6 ; test for more than four zeros after point. 7966 JP M,PF_E_FMT <#PF_E_FMT> ; forward if so to PF_E_FMT 7967 7968 ADD A,6 ; test for zero leading digits, e.g. 0.5 7969 JR Z,PF_ZERO_1 <#PF_ZERO_1> ; forward if so to PF_ZERO_1 7970 7971 JP M,PF_ZEROS <#PF_ZEROS> ; forward if more than one zero to PF_ZEROS 7972 7973 ; else digits before the decimal point are to be printed 7974 7975 LD B,A ; count of leading characters to B. 7976 7977 mark_167B: 7978 *PF_NIB_LP:* 7979 CALL PF_NIBBLE <#PF_NIBBLE> 7980 DJNZ PF_NIB_LP <#PF_NIB_LP> ; loop back for counted numbers 7981 7982 JR PF_DC_OUT <#PF_DC_OUT> ; forward to consider decimal part to PF_DC_OUT 7983 7984 ; ___ 7985 7986 mark_1682: 7987 *PF_E_FMT:* 7988 LD B,E ; count to B 7989 CALL PF_NIBBLE <#PF_NIBBLE> ; prints one digit. 7990 CALL PF_DC_OUT <#PF_DC_OUT> ; considers fractional part. 7991 7992 LD A,ZX_E ; 7993 RST _PRINT_A 7994 7995 LD A,B ; transfer exponent to A 7996 AND A ; test the sign. 7997 JP P,PF_E_POS <#PF_E_POS> ; forward if positive to PF_E_POS 7998 7999 NEG ; negate the negative exponent. 8000 LD B,A ; save positive exponent in B. 8001 8002 LD A,ZX_MINUS ; 8003 JR PF_E_SIGN <#PF_E_SIGN> ; skip forward to PF_E_SIGN 8004 8005 ; ___ 8006 8007 mark_1698: 8008 *PF_E_POS:* 8009 LD A,ZX_PLUS ; 8010 8011 mark_169A: 8012 *PF_E_SIGN:* 8013 RST _PRINT_A 8014 8015 ; now convert the integer exponent in B to two characters. 8016 ; it will be less than 99. 8017 8018 LD A,B ; fetch positive exponent. 8019 LD B,$FF ; initialize left hand digit to minus one. 8020 8021 mark_169E: 8022 *PF_E_TENS:* 8023 INC B ; increment ten count 8024 SUB 10 ; subtract ten from exponent 8025 JR NC,PF_E_TENS <#PF_E_TENS> ; loop back if greater than ten 8026 8027 ADD A,10 ; reverse last subtraction 8028 LD C,A ; transfer remainder to C 8029 8030 LD A,B ; transfer ten value to A. 8031 AND A ; test for zero. 8032 JR Z,PF_E_LOW <#PF_E_LOW> ; skip forward if so to PF_E_LOW 8033 8034 CALL OUT_CODE <#OUT_CODE> ; prints as digit '1' - '9' 8035 8036 mark_16AD: 8037 *PF_E_LOW:* 8038 LD A,C ; low byte to A 8039 CALL OUT_CODE <#OUT_CODE> ; prints final digit of the 8040 ; exponent. 8041 RET ; return. >> 8042 8043 ------------------------------------------------------------------------ 8044 8045 ; THE *'FLOATING POINT PRINT ZEROS'* LOOP 8046 ; ------------------------------------- 8047 ; This branch deals with zeros after decimal point. 8048 ; e.g. .01 or .0000999 8049 ; Note. that printing to the ZX Printer destroys A and that A should be 8050 ; initialized to '0' at each stage of the loop. 8051 ; Originally LPRINT .00001 printed as .0XYZ1 8052 ------------------------------------------------------------------------ 8053 8054 mark_16B2: 8055 *PF_ZEROS:* 8056 NEG ; negate makes number positive 1 to 4. 8057 LD B,A ; zero count to B. 8058 8059 LD A,ZX_PERIOD ; prepare character '.' 8060 RST _PRINT_A 8061 8062 8063 #if ORIGINAL 8064 LD A,ZX_0 ; prepare a '0' 8065 *PFZROLP* 8066 RST _PRINT_A 8067 DJNZ PFZROLP <#PFZROLP> ; obsolete loop back to PFZROLP 8068 #else 8069 *PF_ZRO_LP* 8070 LD A,ZX_0 ; prepare a '0' in the accumulator each time. 8071 RST _PRINT_A 8072 DJNZ PF_ZRO_LP <#PF_ZRO_LP> ;+ New loop back to PF-ZRO-LP 8073 #endif 8074 8075 JR PF_FRAC_LP <#PF_FRAC_LP> ; forward 8076 8077 ; there is a need to print a leading zero e.g. 0.1 but not with .01 8078 8079 mark_16BF: 8080 *PF_ZERO_1:* 8081 LD A,ZX_0 ; prepare character '0'. 8082 RST _PRINT_A 8083 8084 ; this subroutine considers the decimal point and any trailing digits. 8085 ; if the next character is a marked zero, $80, then nothing more to print. 8086 8087 mark_16C2: 8088 *PF_DC_OUT:* 8089 DEC (HL) ; decrement addressed character 8090 INC (HL) ; increment it again 8091 RET PE ; return with overflow (was 128) >> 8092 ; as no fractional part 8093 8094 ; else there is a fractional part so print the decimal point. 8095 8096 LD A,ZX_PERIOD ; prepare character '.' 8097 RST _PRINT_A 8098 8099 ; now enter a loop to print trailing digits 8100 8101 mark_16C8: 8102 *PF_FRAC_LP:* 8103 DEC (HL) ; test for a marked zero. 8104 INC (HL) ; 8105 RET PE ; return when digits exhausted >> 8106 8107 CALL PF_NIBBLE <#PF_NIBBLE> 8108 JR PF_FRAC_LP <#PF_FRAC_LP> ; back for all fractional digits 8109 8110 ; ___ 8111 8112 ; subroutine to print right-hand nibble 8113 8114 mark_16D0: 8115 *PF_NIBBLE:* 8116 LD A,(HL) ; fetch addressed byte 8117 AND $0F ; mask off lower 4 bits 8118 CALL OUT_CODE <#OUT_CODE> 8119 DEC HL ; decrement pointer. 8120 RET ; return. 8121 8122 8123 ------------------------------------------------------------------------ 8124 8125 ; THE *'PREPARE TO ADD'* SUBROUTINE 8126 ------------------------------------------------------------------------ 8127 8128 ; This routine is called twice to prepare each floating point number for 8129 ; addition, in situ, on the calculator stack. 8130 ; The exponent is picked up from the first byte which is then cleared to act 8131 ; as a sign byte and accept any overflow. 8132 ; If the exponent is zero then the number is zero and an early return is made. 8133 ; The now redundant sign bit of the mantissa is set and if the number is 8134 ; negative then all five bytes of the number are twos-complemented to prepare 8135 ; the number for addition. 8136 ; On the second invocation the exponent of the first number is in B. 8137 8138 8139 mark_16D8: 8140 *PREP_ADD:* 8141 LD A,(HL) ; fetch exponent. 8142 LD (HL),0 ; make this byte zero to take any overflow and 8143 ; default to positive. 8144 AND A ; test stored exponent for zero. 8145 RET Z ; return with zero flag set if number is zero. 8146 8147 INC HL ; point to first byte of mantissa. 8148 BIT 7,(HL) ; test the sign bit. 8149 SET 7,(HL) ; set it to its implied state. 8150 DEC HL ; set pointer to first byte again. 8151 RET Z ; return if bit indicated number is positive.>> 8152 8153 ; if negative then all five bytes are twos complemented starting at LSB. 8154 8155 PUSH BC ; save B register contents. 8156 LD BC,$0005 ; set BC to five. 8157 ADD HL,BC ; point to location after 5th byte. 8158 LD B,C ; set the B counter to five. 8159 LD C,A ; store original exponent in C. 8160 SCF ; set carry flag so that one is added. 8161 8162 ; now enter a loop to twos_complement the number. 8163 ; The first of the five bytes becomes $FF to denote a negative number. 8164 8165 mark_16EC: 8166 *NEG_BYTE:* 8167 DEC HL ; point to first or more significant byte. 8168 LD A,(HL) ; fetch to accumulator. 8169 CPL ; complement. 8170 ADC A,0 ; add in initial carry or any subsequent carry. 8171 LD (HL),A ; place number back. 8172 DJNZ NEG_BYTE <#NEG_BYTE> ; loop back five times 8173 8174 LD A,C ; restore the exponent to accumulator. 8175 POP BC ; restore B register contents. 8176 8177 RET ; return. 8178 8179 ------------------------------------------------------------------------ 8180 8181 ; THE *'FETCH TWO NUMBERS'* SUBROUTINE 8182 ------------------------------------------------------------------------ 8183 8184 ; This routine is used by addition, multiplication and division to fetch 8185 ; the two five_byte numbers addressed by HL and DE from the calculator stack 8186 ; into the Z80 registers. 8187 ; The HL register may no longer point to the first of the two numbers. 8188 ; Since the 32-bit addition operation is accomplished using two Z80 16-bit 8189 ; instructions, it is important that the lower two bytes of each mantissa are 8190 ; in one set of registers and the other bytes all in the alternate set. 8191 ; 8192 ; In: HL = highest number, DE= lowest number 8193 ; 8194 ; : alt': 8195 ; : 8196 ; Out: 8197 ; :H,B-C:C,B: num1 8198 ; :L,D-E:D-E: num2 8199 8200 mark_16F7: 8201 *FETCH_TWO:* 8202 PUSH HL ; save HL 8203 PUSH AF ; save A - result sign when used from division. 8204 8205 LD C,(HL) ; 8206 INC HL ; 8207 LD B,(HL) ; 8208 LD (HL),A ; insert sign when used from multiplication. 8209 INC HL ; 8210 LD A,C ; m1 8211 LD C,(HL) ; 8212 PUSH BC ; PUSH m2 m3 8213 8214 INC HL ; 8215 LD C,(HL) ; m4 8216 INC HL ; 8217 LD B,(HL) ; m5 BC holds m5 m4 8218 8219 EX DE,HL ; make HL point to start of second number. 8220 8221 LD D,A ; m1 8222 LD E,(HL) ; 8223 PUSH DE ; PUSH m1 n1 8224 8225 INC HL ; 8226 LD D,(HL) ; 8227 INC HL ; 8228 LD E,(HL) ; 8229 PUSH DE ; PUSH n2 n3 8230 8231 EXX ; - - - - - - - 8232 8233 POP DE ; POP n2 n3 8234 POP HL ; POP m1 n1 8235 POP BC ; POP m2 m3 8236 8237 EXX ; - - - - - - - 8238 8239 INC HL ; 8240 LD D,(HL) ; 8241 INC HL ; 8242 LD E,(HL) ; DE holds n4 n5 8243 8244 POP AF ; restore saved 8245 POP HL ; registers. 8246 RET ; return. 8247 8248 ------------------------------------------------------------------------ 8249 8250 ; THE *'SHIFT ADDEND'* SUBROUTINE 8251 ------------------------------------------------------------------------ 8252 8253 ; The accumulator A contains the difference between the two exponents. 8254 ; This is the lowest of the two numbers to be added 8255 8256 mark_171A: 8257 *SHIFT_FP:* 8258 AND A ; test difference between exponents. 8259 RET Z ; return if zero. both normal. 8260 8261 CP 33 ; compare with 33 bits. 8262 JR NC,ADDEND_0 <#ADDEND_0> ; forward if greater than 32 8263 8264 PUSH BC ; preserve BC - part 8265 LD B,A ; shift counter to B. 8266 8267 ; Now perform B right shifts on the addend L'D'E'D E 8268 ; to bring it into line with the augend H'B'C'C B 8269 8270 mark_1722: 8271 *ONE_SHIFT:* 8272 EXX ; - - - 8273 SRA L ; 76543210->C bit 7 unchanged. 8274 RR D ; C->76543210->C 8275 RR E ; C->76543210->C 8276 EXX ; - - - 8277 RR D ; C->76543210->C 8278 RR E ; C->76543210->C 8279 DJNZ ONE_SHIFT <#ONE_SHIFT> ; loop back B times 8280 8281 POP BC ; restore BC 8282 RET NC ; return if last shift produced no carry. >> 8283 8284 ; if carry flag was set then accuracy is being lost so round up the addend. 8285 8286 CALL ADD_BACK <#ADD_BACK> 8287 RET NZ ; return if not FF 00 00 00 00 8288 8289 ; this branch makes all five bytes of the addend zero and is made during 8290 ; addition when the exponents are too far apart for the addend bits to 8291 ; affect the result. 8292 8293 mark_1736: 8294 *ADDEND_0:* 8295 EXX ; select alternate set for more significant 8296 ; bytes. 8297 XOR A ; clear accumulator. 8298 8299 8300 ; this entry point (from multiplication) sets four of the bytes to zero or if 8301 ; continuing from above, during addition, then all five bytes are set to zero. 8302 8303 mark_1738: 8304 *ZEROS_4_OR_5:* 8305 LD L,0 ; set byte 1 to zero. 8306 LD D,A ; set byte 2 to A. 8307 LD E,L ; set byte 3 to zero. 8308 EXX ; select main set 8309 LD DE,$0000 ; set lower bytes 4 and 5 to zero. 8310 RET ; return. 8311 8312 ------------------------------------------------------------------------ 8313 8314 ; THE *'ADD_BACK'* SUBROUTINE 8315 ------------------------------------------------------------------------ 8316 8317 ; Called from SHIFT_FP above during addition and after normalization from 8318 ; multiplication. 8319 ; This is really a 32_bit increment routine which sets the zero flag according 8320 ; to the 32-bit result. 8321 ; During addition, only negative numbers like FF FF FF FF FF, 8322 ; the twos-complement version of xx 80 00 00 01 say 8323 ; will result in a full ripple FF 00 00 00 00. 8324 ; FF FF FF FF FF when shifted right is unchanged by SHIFT_FP but sets the 8325 ; carry invoking this routine. 8326 8327 mark_1741: 8328 *ADD_BACK:* 8329 INC E ; 8330 RET NZ ; 8331 8332 INC D ; 8333 RET NZ ; 8334 8335 EXX ; 8336 INC E ; 8337 JR NZ,ALL_ADDED <#ALL_ADDED> ; forward if no overflow 8338 8339 INC D ; 8340 8341 mark_174A: 8342 *ALL_ADDED:* 8343 EXX ; 8344 RET ; return with zero flag set for zero mantissa. 8345 8346 8347 ------------------------------------------------------------------------ 8348 8349 ; THE *'SUBTRACTION'* OPERATION 8350 ------------------------------------------------------------------------ 8351 8352 ; just switch the sign of subtrahend and do an add. 8353 8354 mark_174C: 8355 *SUBTRACT:* 8356 LD A,(DE) ; fetch exponent byte of second number the 8357 ; subtrahend. 8358 AND A ; test for zero 8359 RET Z ; return if zero - first number is result. 8360 8361 INC DE ; address the first mantissa byte. 8362 LD A,(DE) ; fetch to accumulator. 8363 XOR $80 ; toggle the sign bit. 8364 LD (DE),A ; place back on calculator stack. 8365 DEC DE ; point to exponent byte. 8366 ; continue into addition routine. 8367 8368 ------------------------------------------------------------------------ 8369 8370 ; THE *'ADDITION'* OPERATION 8371 ------------------------------------------------------------------------ 8372 8373 ; The addition operation pulls out all the stops and uses most of the Z80's 8374 ; registers to add two floating-point numbers. 8375 ; This is a binary operation and on entry, HL points to the first number 8376 ; and DE to the second. 8377 8378 mark_1755: 8379 *ADDITION:* 8380 EXX ; - - - 8381 PUSH HL ; save the pointer to the next literal. 8382 EXX ; - - - 8383 8384 PUSH DE ; save pointer to second number 8385 PUSH HL ; save pointer to first number - will be the 8386 ; result pointer on calculator stack. 8387 8388 CALL PREP_ADD <#PREP_ADD> 8389 LD B,A ; save first exponent byte in B. 8390 EX DE,HL ; switch number pointers. 8391 CALL PREP_ADD <#PREP_ADD> 8392 LD C,A ; save second exponent byte in C. 8393 CP B ; compare the exponent bytes. 8394 JR NC,SHIFT_LEN <#SHIFT_LEN> ; forward if second higher 8395 8396 LD A,B ; else higher exponent to A 8397 LD B,C ; lower exponent to B 8398 EX DE,HL ; switch the number pointers. 8399 8400 mark_1769: 8401 *SHIFT_LEN:* 8402 PUSH AF ; save higher exponent 8403 SUB B ; subtract lower exponent 8404 8405 CALL FETCH_TWO <#FETCH_TWO> 8406 CALL SHIFT_FP <#SHIFT_FP> 8407 8408 POP AF ; restore higher exponent. 8409 POP HL ; restore result pointer. 8410 LD (HL),A ; insert exponent byte. 8411 PUSH HL ; save result pointer again. 8412 8413 ; now perform the 32-bit addition using two 16-bit Z80 add instructions. 8414 8415 LD L,B ; transfer low bytes of mantissa individually 8416 LD H,C ; to HL register 8417 8418 ADD HL,DE ; the actual binary addition of lower bytes 8419 8420 ; now the two higher byte pairs that are in the alternate register sets. 8421 8422 EXX ; switch in set 8423 EX DE,HL ; transfer high mantissa bytes to HL register. 8424 8425 ADC HL,BC ; the actual addition of higher bytes with 8426 ; any carry from first stage. 8427 8428 EX DE,HL ; result in DE, sign bytes ($FF or $00) to HL 8429 8430 ; now consider the two sign bytes 8431 8432 LD A,H ; fetch sign byte of num1 8433 8434 ADC A,L ; add including any carry from mantissa 8435 ; addition. 00 or 01 or FE or FF 8436 8437 LD L,A ; result in L. 8438 8439 ; possible outcomes of signs and overflow from mantissa are 8440 ; 8441 ; H + L + carry = L RRA XOR L RRA 8442 ------------------------------------------------------------------------ 8443 8444 ; 00 + 00 = 00 00 00 8445 ; 00 + 00 + carry = 01 00 01 carry 8446 ; FF + FF = FE C FF 01 carry 8447 ; FF + FF + carry = FF C FF 00 8448 ; FF + 00 = FF FF 00 8449 ; FF + 00 + carry = 00 C 80 80 8450 8451 RRA ; C->76543210->C 8452 XOR L ; set bit 0 if shifting required. 8453 8454 EXX ; switch back to main set 8455 EX DE,HL ; full mantissa result now in D'E'D E registers. 8456 POP HL ; restore pointer to result exponent on 8457 ; the calculator stack. 8458 8459 RRA ; has overflow occurred ? 8460 JR NC,TEST_NEG <#TEST_NEG> ; skip forward if not 8461 8462 ; if the addition of two positive mantissas produced overflow or if the 8463 ; addition of two negative mantissas did not then the result exponent has to 8464 ; be incremented and the mantissa shifted one place to the right. 8465 8466 LD A,1 ; one shift required. 8467 CALL SHIFT_FP <#SHIFT_FP> ; performs a single shift 8468 ; rounding any lost bit 8469 INC (HL) ; increment the exponent. 8470 JR Z,ADD_REP_6 <#ADD_REP_6> ; forward to ADD_REP_6 if the exponent 8471 ; wraps round from FF to zero as number is too 8472 ; big for the system. 8473 8474 ; at this stage the exponent on the calculator stack is correct. 8475 8476 mark_1790: 8477 *TEST_NEG:* 8478 EXX ; switch in the alternate set. 8479 LD A,L ; load result sign to accumulator. 8480 AND $80 ; isolate bit 7 from sign byte setting zero 8481 ; flag if positive. 8482 EXX ; back to main set. 8483 8484 INC HL ; point to first byte of mantissa 8485 LD (HL),A ; insert $00 positive or $80 negative at 8486 ; position on calculator stack. 8487 8488 DEC HL ; point to exponent again. 8489 JR Z,GO_NC_MLT <#GO_NC_MLT> ; forward if positive to GO_NC_MLT 8490 8491 ; a negative number has to be twos-complemented before being placed on stack. 8492 8493 LD A,E ; fetch lowest (rightmost) mantissa byte. 8494 NEG ; Negate 8495 CCF ; Complement Carry Flag 8496 LD E,A ; place back in register 8497 8498 LD A,D ; ditto 8499 CPL ; 8500 ADC A,0 ; 8501 LD D,A ; 8502 8503 EXX ; switch to higher (leftmost) 16 bits. 8504 8505 LD A,E ; ditto 8506 CPL ; 8507 ADC A,0 ; 8508 LD E,A ; 8509 8510 LD A,D ; ditto 8511 CPL ; 8512 ADC A,0 ; 8513 JR NC,END_COMPL <#END_COMPL> ; forward without overflow to END_COMPL 8514 8515 ; else entire mantissa is now zero. 00 00 00 00 8516 8517 RRA ; set mantissa to 80 00 00 00 8518 EXX ; switch. 8519 INC (HL) ; increment the exponent. 8520 8521 mark_17B3: 8522 *ADD_REP_6:* 8523 JP Z,REPORT_6 <#REPORT_6> ; jump forward if exponent now zero to REPORT_6 8524 ; 'Number too big' 8525 8526 EXX ; switch back to alternate set. 8527 8528 mark_17B7: 8529 *END_COMPL:* 8530 LD D,A ; put first byte of mantissa back in DE. 8531 EXX ; switch to main set. 8532 8533 mark_17B9: 8534 *GO_NC_MLT:* 8535 XOR A ; clear carry flag and 8536 ; clear accumulator so no extra bits carried 8537 ; forward as occurs in multiplication. 8538 8539 JR TEST_NORM <#TEST_NORM> ; forward to common code at TEST_NORM 8540 ; but should go straight to NORMALIZE. 8541 8542 8543 ------------------------------------------------------------------------ 8544 8545 ; THE *'PREPARE TO MULTIPLY OR DIVIDE'* SUBROUTINE 8546 ------------------------------------------------------------------------ 8547 8548 ; this routine is called twice from multiplication and twice from division 8549 ; to prepare each of the two numbers for the operation. 8550 ; Initially the accumulator holds zero and after the second invocation bit 7 8551 ; of the accumulator will be the sign bit of the result. 8552 8553 mark_17BC: 8554 *PREP_MULTIPLY_OR_DIVIDE:* 8555 SCF ; set carry flag to signal number is zero. 8556 DEC (HL) ; test exponent 8557 INC (HL) ; for zero. 8558 RET Z ; return if zero with carry flag set. 8559 8560 INC HL ; address first mantissa byte. 8561 XOR (HL) ; exclusive or the running sign bit. 8562 SET 7,(HL) ; set the implied bit. 8563 DEC HL ; point to exponent byte. 8564 RET ; return. 8565 8566 ------------------------------------------------------------------------ 8567 8568 ; THE *'MULTIPLICATION'* OPERATION 8569 ------------------------------------------------------------------------ 8570 8571 ; 8572 ; 8573 8574 mark_17C6: 8575 *MULTIPLY:* 8576 XOR A ; reset bit 7 of running sign flag. 8577 CALL PREP_MULTIPLY_OR_DIVIDE <#PREP_MULTIPLY_OR_DIVIDE> 8578 RET C ; return if number is zero. 8579 ; zero * anything = zero. 8580 8581 EXX ; - - - 8582 PUSH HL ; save pointer to 'next literal' 8583 EXX ; - - - 8584 8585 PUSH DE ; save pointer to second number 8586 8587 EX DE,HL ; make HL address second number. 8588 8589 CALL PREP_MULTIPLY_OR_DIVIDE <#PREP_MULTIPLY_OR_DIVIDE> 8590 8591 EX DE,HL ; HL first number, DE - second number 8592 JR C,ZERO_RESULT <#ZERO_RESULT> ; forward with carry to ZERO_RESULT 8593 ; anything * zero = zero. 8594 8595 PUSH HL ; save pointer to first number. 8596 8597 CALL FETCH_TWO <#FETCH_TWO> ; fetches two mantissas from 8598 ; calc stack to B'C'C,B D'E'D E 8599 ; (HL will be overwritten but the result sign 8600 ; in A is inserted on the calculator stack) 8601 8602 LD A,B ; transfer low mantissa byte of first number 8603 AND A ; clear carry. 8604 SBC HL,HL ; a short form of LD HL,$0000 to take lower 8605 ; two bytes of result. (2 program bytes) 8606 EXX ; switch in alternate set 8607 PUSH HL ; preserve HL 8608 SBC HL,HL ; set HL to zero also to take higher two bytes 8609 ; of the result and clear carry. 8610 EXX ; switch back. 8611 8612 LD B,33 ; register B can now be used to count 33 shifts. 8613 JR STRT_MLT <#STRT_MLT> ; forward to loop entry point STRT_MLT 8614 8615 ; ___ 8616 8617 ; The multiplication loop is entered at STRT_LOOP. 8618 8619 mark_17E7: 8620 *MLT_LOOP:* 8621 JR NC,NO_ADD <#NO_ADD> ; forward if no carry 8622 8623 ; else add in the multiplicand. 8624 8625 ADD HL,DE ; add the two low bytes to result 8626 EXX ; switch to more significant bytes. 8627 ADC HL,DE ; add high bytes of multiplicand and any carry. 8628 EXX ; switch to main set. 8629 8630 ; in either case shift result right into B'C'C A 8631 8632 mark_17EE: 8633 *NO_ADD:* 8634 EXX ; switch to alternate set 8635 RR H ; C > 76543210 > C 8636 RR L ; C > 76543210 > C 8637 EXX ; 8638 RR H ; C > 76543210 > C 8639 RR L ; C > 76543210 > C 8640 8641 mark_17F8: 8642 *STRT_MLT:* 8643 EXX ; switch in alternate set. 8644 RR B ; C > 76543210 > C 8645 RR C ; C > 76543210 > C 8646 EXX ; now main set 8647 RR C ; C > 76543210 > C 8648 RRA ; C > 76543210 > C 8649 DJNZ MLT_LOOP <#MLT_LOOP> ; loop back 33 timeS 8650 8651 ; 8652 8653 EX DE,HL ; 8654 EXX ; 8655 EX DE,HL ; 8656 EXX ; 8657 POP BC ; 8658 POP HL ; 8659 LD A,B ; 8660 ADD A,C ; 8661 JR NZ,MAKE_EXPT <#MAKE_EXPT> ; forward 8662 8663 AND A ; 8664 8665 mark_180E: 8666 *MAKE_EXPT:* 8667 DEC A ; 8668 CCF ; Complement Carry Flag 8669 8670 mark_1810: 8671 *DIVN_EXPT:* 8672 RLA ; 8673 CCF ; Complement Carry Flag 8674 RRA ; 8675 JP P,OFLW1_CLR <#OFLW1_CLR> 8676 8677 JR NC,REPORT_6 <#REPORT_6> 8678 8679 AND A ; 8680 8681 mark_1819: 8682 *OFLW1_CLR:* 8683 INC A ; 8684 JR NZ,OFLW2_CLR <#OFLW2_CLR> 8685 8686 JR C,OFLW2_CLR <#OFLW2_CLR> 8687 8688 EXX ; 8689 BIT 7,D ; 8690 EXX ; 8691 JR NZ,REPORT_6 <#REPORT_6> 8692 8693 mark_1824: 8694 *OFLW2_CLR:* 8695 LD (HL),A ; 8696 EXX ; 8697 LD A,B ; 8698 EXX ; 8699 8700 ; addition joins here with carry flag clear. 8701 8702 mark_1828: 8703 *TEST_NORM:* 8704 JR NC,NORMALIZE <#NORMALIZE> ; forward 8705 8706 LD A,(HL) ; 8707 AND A ; 8708 8709 mark_182C: 8710 *NEAR_ZERO:* 8711 LD A,$80 ; prepare to rescue the most significant bit 8712 ; of the mantissa if it is set. 8713 JR Z,SKIP_ZERO <#SKIP_ZERO> ; skip forward 8714 8715 mark_1830: 8716 *ZERO_RESULT:* 8717 XOR A ; make mask byte zero signaling set five 8718 ; bytes to zero. 8719 8720 mark_1831: 8721 *SKIP_ZERO:* 8722 EXX ; switch in alternate set 8723 AND D ; isolate most significant bit (if A is $80). 8724 8725 CALL ZEROS_4_OR_5 <#ZEROS_4_OR_5> ; sets mantissa without 8726 ; affecting any flags. 8727 8728 RLCA ; test if MSB set. bit 7 goes to bit 0. 8729 ; either $00 -> $00 or $80 -> $01 8730 LD (HL),A ; make exponent $01 (lowest) or $00 zero 8731 JR C,OFLOW_CLR <#OFLOW_CLR> ; forward if first case 8732 8733 INC HL ; address first mantissa byte on the 8734 ; calculator stack. 8735 LD (HL),A ; insert a zero for the sign bit. 8736 DEC HL ; point to zero exponent 8737 JR OFLOW_CLR <#OFLOW_CLR> ; forward 8738 8739 ; ___ 8740 8741 ; this branch is common to addition and multiplication with the mantissa 8742 ; result still in registers D'E'D E . 8743 8744 mark_183F: 8745 *NORMALIZE:* 8746 LD B,32 ; a maximum of thirty-two left shifts will be 8747 ; needed. 8748 8749 mark_1841: 8750 *SHIFT_ONE:* 8751 EXX ; address higher 16 bits. 8752 BIT 7,D ; test the leftmost bit 8753 EXX ; address lower 16 bits. 8754 8755 JR NZ,NORML_NOW <#NORML_NOW> ; forward if leftmost bit was set 8756 8757 RLCA ; this holds zero from addition, 33rd bit 8758 ; from multiplication. 8759 8760 RL E ; C < 76543210 < C 8761 RL D ; C < 76543210 < C 8762 8763 EXX ; address higher 16 bits. 8764 8765 RL E ; C < 76543210 < C 8766 RL D ; C < 76543210 < C 8767 8768 EXX ; switch to main set. 8769 8770 DEC (HL) ; decrement the exponent byte on the calculator 8771 ; stack. 8772 8773 JR Z,NEAR_ZERO <#NEAR_ZERO> ; back if exponent becomes zero 8774 ; it's just possible that the last rotation 8775 ; set bit 7 of D. We shall see. 8776 8777 DJNZ SHIFT_ONE <#SHIFT_ONE> ; loop back 8778 8779 ; if thirty-two left shifts were performed without setting the most significant 8780 ; bit then the result is zero. 8781 8782 JR ZERO_RESULT <#ZERO_RESULT> ; back 8783 8784 ; ___ 8785 8786 mark_1859: 8787 *NORML_NOW:* 8788 RLA ; for the addition path, A is always zero. 8789 ; for the mult path, ... 8790 8791 JR NC,OFLOW_CLR <#OFLOW_CLR> ; forward 8792 8793 ; this branch is taken only with multiplication. 8794 8795 CALL ADD_BACK <#ADD_BACK> 8796 8797 JR NZ,OFLOW_CLR <#OFLOW_CLR> ; forward 8798 8799 EXX ; 8800 LD D,$80 ; 8801 EXX ; 8802 INC (HL) ; 8803 JR Z,REPORT_6 <#REPORT_6> ; forward 8804 8805 ; now transfer the mantissa from the register sets to the calculator stack 8806 ; incorporating the sign bit already there. 8807 8808 mark_1868: 8809 *OFLOW_CLR:* 8810 PUSH HL ; save pointer to exponent on stack. 8811 INC HL ; address first byte of mantissa which was 8812 ; previously loaded with sign bit $00 or $80. 8813 8814 EXX ; - - - 8815 PUSH DE ; push the most significant two bytes. 8816 EXX ; - - - 8817 8818 POP BC ; pop - true mantissa is now BCDE. 8819 8820 ; now pick up the sign bit. 8821 8822 LD A,B ; first mantissa byte to A 8823 RLA ; rotate out bit 7 which is set 8824 RL (HL) ; rotate sign bit on stack into carry. 8825 RRA ; rotate sign bit into bit 7 of mantissa. 8826 8827 ; and transfer mantissa from main registers to calculator stack. 8828 8829 LD (HL),A ; 8830 INC HL ; 8831 LD (HL),C ; 8832 INC HL ; 8833 LD (HL),D ; 8834 INC HL ; 8835 LD (HL),E ; 8836 8837 POP HL ; restore pointer to num1 now result. 8838 POP DE ; restore pointer to num2 now STKEND. 8839 8840 EXX ; - - - 8841 POP HL ; restore pointer to next calculator literal. 8842 EXX ; - - - 8843 8844 RET ; return. 8845 8846 ; ___ 8847 8848 mark_1880: 8849 *REPORT_6:* 8850 RST _ERROR_1 8851 DEFB 5 ; Error Report: Arithmetic overflow. 8852 8853 ------------------------------------------------------------------------ 8854 8855 ; THE *'DIVISION'* OPERATION 8856 ------------------------------------------------------------------------ 8857 8858 ; "Of all the arithmetic subroutines, division is the most complicated and 8859 ; the least understood. It is particularly interesting to note that the 8860 ; Sinclair programmer himself has made a mistake in his programming ( or has 8861 ; copied over someone else's mistake!) for 8862 ; PRINT PEEK 6352 [ $18D0 ] ('unimproved' ROM, 6351 [ $18CF ] ) 8863 ; should give 218 not 225." 8864 ; - Dr. Ian Logan, Syntax magazine Jul/Aug 1982. 8865 ; [ i.e. the jump should be made to div-34th ] 8866 8867 ; First check for division by zero. 8868 8869 mark_1882: 8870 *DIVISION:* 8871 EX DE,HL ; consider the second number first. 8872 XOR A ; set the running sign flag. 8873 CALL PREP_MULTIPLY_OR_DIVIDE <#PREP_MULTIPLY_OR_DIVIDE> 8874 JR C,REPORT_6 <#REPORT_6> ; back if zero 8875 ; 'Arithmetic overflow' 8876 8877 EX DE,HL ; now prepare first number and check for zero. 8878 CALL PREP_MULTIPLY_OR_DIVIDE <#PREP_MULTIPLY_OR_DIVIDE> 8879 RET C ; return if zero, 0/anything is zero. 8880 8881 EXX ; - - - 8882 PUSH HL ; save pointer to the next calculator literal. 8883 EXX ; - - - 8884 8885 PUSH DE ; save pointer to divisor - will be STKEND. 8886 PUSH HL ; save pointer to dividend - will be result. 8887 8888 CALL FETCH_TWO <#FETCH_TWO> ; fetches the two numbers 8889 ; into the registers H'B'C'C B 8890 ; L'D'E'D E 8891 EXX ; - - - 8892 PUSH HL ; save the two exponents. 8893 8894 LD H,B ; transfer the dividend to H'L'H L 8895 LD L,C ; 8896 EXX ; 8897 LD H,C ; 8898 LD L,B ; 8899 8900 XOR A ; clear carry bit and accumulator. 8901 LD B,$DF ; count upwards from -33 decimal 8902 JR DIVISION_START <#DIVISION_START> ; forward to mid-loop entry point 8903 8904 ; ___ 8905 8906 mark_18A2: 8907 *DIV_LOOP:* 8908 RLA ; multiply partial quotient by two 8909 RL C ; setting result bit from carry. 8910 EXX ; 8911 RL C ; 8912 RL B ; 8913 EXX ; 8914 8915 mark_18AB: 8916 *DIV_34TH:* 8917 ADD HL,HL ; 8918 EXX ; 8919 ADC HL,HL ; 8920 EXX ; 8921 JR C,SUBN_ONLY <#SUBN_ONLY> ; forward 8922 8923 mark_18B2: 8924 *DIVISION_START:* 8925 SBC HL,DE ; subtract divisor part. 8926 EXX ; 8927 SBC HL,DE ; 8928 EXX ; 8929 JR NC,NUM_RESTORE <#NUM_RESTORE> ; forward if subtraction goes 8930 8931 ADD HL,DE ; else restore 8932 EXX ; 8933 ADC HL,DE ; 8934 EXX ; 8935 AND A ; clear carry 8936 JR COUNT_ONE <#COUNT_ONE> ; forward 8937 8938 ; ___ 8939 8940 mark_18C2: 8941 *SUBN_ONLY:* 8942 AND A ; 8943 SBC HL,DE ; 8944 EXX ; 8945 SBC HL,DE ; 8946 EXX ; 8947 8948 mark_18C9: 8949 *NUM_RESTORE:* 8950 SCF ; set carry flag 8951 8952 mark_18CA: 8953 *COUNT_ONE:* 8954 INC B ; increment the counter 8955 JP M,DIV_LOOP <#DIV_LOOP> ; back while still minus to DIV_LOOP 8956 8957 PUSH AF ; 8958 JR Z,DIVISION_START <#DIVISION_START> ; back to DIV_START 8959 8960 ; "This jump is made to the wrong place. No 34th bit will ever be obtained 8961 ; without first shifting the dividend. Hence important results like 1/10 and 8962 ; 1/1000 are not rounded up as they should be. Rounding up never occurs when 8963 ; it depends on the 34th bit. The jump should be made to div_34th above." 8964 ; - Dr. Frank O'Hara, "The Complete Spectrum ROM Disassembly", 1983, 8965 ; published by Melbourne House. 8966 ; (Note. on the ZX81 this would be JR Z,DIV_34TH) 8967 ; 8968 ; However if you make this change, then while (1/2=.5) will now evaluate as 8969 ; true, (.25=1/4), which did evaluate as true, no longer does. 8970 8971 LD E,A ; 8972 LD D,C ; 8973 EXX ; 8974 LD E,C ; 8975 LD D,B ; 8976 8977 POP AF ; 8978 RR B ; 8979 POP AF ; 8980 RR B ; 8981 8982 EXX ; 8983 POP BC ; 8984 POP HL ; 8985 LD A,B ; 8986 SUB C ; 8987 JP DIVN_EXPT <#DIVN_EXPT> ; jump back 8988 8989 ------------------------------------------------------------------------ 8990 8991 ; THE *'INTEGER TRUNCATION TOWARDS ZERO'* SUBROUTINE 8992 ------------------------------------------------------------------------ 8993 8994 ; 8995 8996 mark_18E4: 8997 *TRUNCATE:* 8998 LD A,(HL) ; fetch exponent 8999 CP $81 ; compare to +1 9000 JR NC,T_GR_ZERO <#T_GR_ZERO> ; forward, if 1 or more 9001 9002 ; else the number is smaller than plus or minus 1 and can be made zero. 9003 9004 LD (HL),$00 ; make exponent zero. 9005 LD A,$20 ; prepare to set 32 bits of mantissa to zero. 9006 JR NIL_BYTES <#NIL_BYTES> ; forward 9007 9008 ; ___ 9009 9010 mark_18EF: 9011 *T_GR_ZERO:* 9012 SUB $A0 ; subtract +32 from exponent 9013 RET P ; return if result is positive as all 32 bits 9014 ; of the mantissa relate to the integer part. 9015 ; The floating point is somewhere to the right 9016 ; of the mantissa 9017 9018 NEG ; else negate to form number of rightmost bits 9019 ; to be blanked. 9020 9021 ; for instance, disregarding the sign bit, the number 3.5 is held as 9022 ; exponent $82 mantissa .11100000 00000000 00000000 00000000 9023 ; we need to set $82 - $A0 = $E2 NEG = $1E (thirty) bits to zero to form the 9024 ; integer. 9025 ; The sign of the number is never considered as the first bit of the mantissa 9026 ; must be part of the integer. 9027 9028 mark_18F4: 9029 *NIL_BYTES:* 9030 PUSH DE ; save pointer to STKEND 9031 EX DE,HL ; HL points at STKEND 9032 DEC HL ; now at last byte of mantissa. 9033 LD B,A ; Transfer bit count to B register. 9034 SRL B ; divide by 9035 SRL B ; eight 9036 SRL B ; 9037 JR Z,BITS_ZERO <#BITS_ZERO> ; forward if zero 9038 9039 ; else the original count was eight or more and whole bytes can be blanked. 9040 9041 mark_1900: 9042 *BYTE_ZERO:* 9043 LD (HL),0 ; set eight bits to zero. 9044 DEC HL ; point to more significant byte of mantissa. 9045 DJNZ BYTE_ZERO <#BYTE_ZERO> ; loop back 9046 9047 ; now consider any residual bits. 9048 9049 mark_1905: 9050 *BITS_ZERO:* 9051 AND $07 ; isolate the remaining bits 9052 JR Z,IX_END <#IX_END> ; forward if none 9053 9054 LD B,A ; transfer bit count to B counter. 9055 LD A,$FF ; form a mask 11111111 9056 9057 mark_190C: 9058 *LESS_MASK:* 9059 SLA A ; 1 <- 76543210 <- o slide mask leftwards. 9060 DJNZ LESS_MASK <#LESS_MASK> ; loop back for bit count 9061 9062 AND (HL) ; lose the unwanted rightmost bits 9063 LD (HL),A ; and place in mantissa byte. 9064 9065 mark_1912: 9066 *IX_END:* 9067 EX DE,HL ; restore result pointer from DE. 9068 POP DE ; restore STKEND from stack. 9069 RET ; return. 9070 9071 ------------------------------------------------------------------------ 9072 9073 ; Up to this point all routine addresses have been maintained so that the 9074 ; modified ROM is compatible with any machine-code software that uses ROM 9075 ; routines. 9076 ; The final section does not maintain address entry points as the routines 9077 ; within are not generally called directly. 9078 ------------------------------------------------------------------------ 9079 9080 ;** FLOATING-POINT CALCULATOR ** 9081 ;******************************** 9082 ; As a general rule the calculator avoids using the IY register. 9083 ; Exceptions are val and str$. 9084 ; So an assembly language programmer who has disabled interrupts to use IY 9085 ; for other purposes can still use the calculator for mathematical 9086 ; purposes. 9087 ------------------------------------------------------------------------ 9088 9089 ; THE *'TABLE OF CONSTANTS'* 9090 ------------------------------------------------------------------------ 9091 9092 ; The ZX81 has only floating-point number representation. 9093 ; Both the ZX80 and the ZX Spectrum have integer numbers in some form. 9094 9095 9096 *TAB_CNST* 9097 9098 #if ORIGINAL 9099 mark_1915: 9100 ** ; 00 00 00 00 00 9101 stk_zero: 9102 DEFB $00 ;;Bytes: 1 9103 DEFB $B0 ;;Exponent $00 9104 DEFB $00 ;;(+00,+00,+00) 9105 9106 mark_1918: 9107 ** ; 81 00 00 00 00 9108 stk_one: 9109 DEFB $31 ;;Exponent $81, Bytes: 1 9110 DEFB $00 ;;(+00,+00,+00) 9111 9112 9113 mark_191A: 9114 ** ; 80 00 00 00 00 9115 stk_half: 9116 DEFB $30 ;;Exponent: $80, Bytes: 1 9117 DEFB $00 ;;(+00,+00,+00) 9118 9119 9120 mark_191C: 9121 ** ; 81 49 0F DA A2 9122 stk_half_pi: 9123 DEFB $F1 ;;Exponent: $81, Bytes: 4 9124 DEFB $49,$0F,$DA,$A2 ;; 9125 9126 mark_1921: 9127 ** ; 84 20 00 00 00 9128 stk_ten: 9129 DEFB $34 ;;Exponent: $84, Bytes: 1 9130 DEFB $20 ;;(+00,+00,+00) 9131 #else 9132 ; This table has been modified so that the constants are held in their 9133 ; uncompressed, ready-to-use, 5-byte form. 9134 9135 DEFB $00 ; the value zero. 9136 DEFB $00 ; 9137 DEFB $00 ; 9138 DEFB $00 ; 9139 DEFB $00 ; 9140 9141 DEFB $81 ; the floating point value 1. 9142 DEFB $00 ; 9143 DEFB $00 ; 9144 DEFB $00 ; 9145 DEFB $00 ; 9146 9147 DEFB $80 ; the floating point value 1/2. 9148 DEFB $00 ; 9149 DEFB $00 ; 9150 DEFB $00 ; 9151 DEFB $00 ; 9152 9153 DEFB $81 ; the floating point value pi/2. 9154 DEFB $49 ; 9155 DEFB $0F ; 9156 DEFB $DA ; 9157 DEFB $A2 ; 9158 9159 DEFB $84 ; the floating point value ten. 9160 DEFB $20 ; 9161 DEFB $00 ; 9162 DEFB $00 ; 9163 DEFB $00 ; 9164 #endif 9165 9166 ------------------------------------------------------------------------ 9167 9168 ; THE *'TABLE OF ADDRESSES'* 9169 ------------------------------------------------------------------------ 9170 9171 ; 9172 ; starts with binary operations which have two operands and one result. 9173 ; three pseudo binary operations first. 9174 9175 #if ORIGINAL 9176 mark_1923: 9177 #else 9178 #endif 9179 9180 *tbl_addrs:* 9181 9182 DEFW jump_true <#jump_true> ; $00 Address: $1C2F - jump_true 9183 DEFW exchange <#exchange> ; $01 Address: $1A72 - exchange 9184 DEFW delete <#delete> ; $02 Address: $19E3 - delete 9185 9186 ; true binary operations. 9187 9188 DEFW SUBTRACT <#SUBTRACT> ; $03 Address: $174C - subtract 9189 DEFW MULTIPLY <#MULTIPLY> ; $04 Address: $176C - multiply 9190 DEFW DIVISION <#DIVISION> ; $05 Address: $1882 - division 9191 DEFW to_power <#to_power> ; $06 Address: $1DE2 - to_power 9192 DEFW or <#or> ; $07 Address: $1AED - or 9193 9194 DEFW boolean_num_and_num <#boolean_num_and_num> ; $08 Address: $1AF3 - boolean_num_and_num 9195 DEFW num_l_eql <#num_l_eql> ; $09 Address: $1B03 - num_l_eql 9196 DEFW num_gr_eql <#num_gr_eql> ; $0A Address: $1B03 - num_gr_eql 9197 DEFW nums_neql <#nums_neql> ; $0B Address: $1B03 - nums_neql 9198 DEFW num_grtr <#num_grtr> ; $0C Address: $1B03 - num_grtr 9199 DEFW num_less <#num_less> ; $0D Address: $1B03 - num_less 9200 DEFW nums_eql <#nums_eql> ; $0E Address: $1B03 - nums_eql 9201 DEFW ADDITION <#ADDITION> ; $0F Address: $1755 - addition 9202 9203 DEFW strs_and_num <#strs_and_num> ; $10 Address: $1AF8 - str_and_num 9204 DEFW str_l_eql <#str_l_eql> ; $11 Address: $1B03 - str_l_eql 9205 DEFW str_gr_eql <#str_gr_eql> ; $12 Address: $1B03 - str_gr_eql 9206 DEFW strs_neql <#strs_neql> ; $13 Address: $1B03 - strs_neql 9207 DEFW str_grtr <#str_grtr> ; $14 Address: $1B03 - str_grtr 9208 DEFW str_less <#str_less> ; $15 Address: $1B03 - str_less 9209 DEFW strs_eql <#strs_eql> ; $16 Address: $1B03 - strs_eql 9210 DEFW strs_add <#strs_add> ; $17 Address: $1B62 - strs_add 9211 9212 ; unary follow 9213 9214 DEFW neg <#neg> ; $18 9215 DEFW code <#code> ; $19 9216 DEFW val <#val> ; $1A 9217 DEFW len <#len> ; $1B 9218 DEFW sin <#sin> ; $1C 9219 DEFW cos <#cos> ; $1D 9220 DEFW tan <#tan> ; $1E 9221 DEFW asn <#asn> ; $1F 9222 DEFW acs <#acs> ; $20 9223 DEFW atn <#atn> ; $21 9224 DEFW ln <#ln> ; $22 9225 DEFW exp <#exp> ; $23 9226 DEFW int <#int> ; $24 9227 DEFW sqr <#sqr> ; $25 9228 DEFW sgn <#sgn> ; $26 9229 DEFW abs <#abs> ; $27 9230 DEFW PEEK <#PEEK> ; $28 Address: $1A1B - peek !!!! 9231 DEFW usr_num <#usr_num> ; $29 9232 DEFW str_dollar <#str_dollar> ; $2A 9233 DEFW chr_dollar <#chr_dollar> ; $2B 9234 DEFW not <#not> ; $2C 9235 9236 ; end of true unary 9237 9238 DEFW duplicate <#duplicate> ; $2D 9239 DEFW n_mod_m <#n_mod_m> ; $2E 9240 9241 DEFW jump <#jump> ; $2F 9242 DEFW stk_data <#stk_data> ; $30 9243 9244 DEFW dec_jr_nz <#dec_jr_nz> ; $31 9245 DEFW less_0 <#less_0> ; $32 9246 DEFW greater_0 <#greater_0> ; $33 9247 DEFW end_calc <#end_calc> ; $34 9248 DEFW get_argt <#get_argt> ; $35 9249 DEFW TRUNCATE <#TRUNCATE> ; $36 9250 DEFW FP_CALC_2 <#FP_CALC_2> ; $37 9251 DEFW e_to_fp <#e_to_fp> ; $38 9252 9253 ; the following are just the next available slots for the 128 compound literals 9254 ; which are in range $80 - $FF. 9255 9256 DEFW series_xx <#series_xx> ; $39 : $80 - $9F. 9257 DEFW stk_const_xx <#stk_const_xx> ; $3A : $A0 - $BF. 9258 DEFW st_mem_xx <#st_mem_xx> ; $3B : $C0 - $DF. 9259 DEFW get_mem_xx <#get_mem_xx> ; $3C : $E0 - $FF. 9260 9261 ; Aside: 3D - 7F are therefore unused calculator literals. 9262 ; 39 - 7B would be available for expansion. 9263 9264 ------------------------------------------------------------------------ 9265 9266 ; THE *'FLOATING POINT CALCULATOR'* 9267 ------------------------------------------------------------------------ 9268 9269 ; 9270 ; 9271 9272 mark_199D: 9273 *CALCULATE:* 9274 CALL STACK_POINTERS <#STACK_POINTERS> ; is called to set up the 9275 ; calculator stack pointers for a default 9276 ; unary operation. HL = last value on stack. 9277 ; DE = STKEND first location after stack. 9278 9279 ; the calculate routine is called at this point by the series generator... 9280 9281 mark_19A0: 9282 *GEN_ENT_1:* 9283 LD A,B ; fetch the Z80 B register to A 9284 LD (BERG),A ; and store value in system variable BERG. 9285 ; this will be the counter for dec_jr_nz 9286 ; or if used from FP_CALC2 the calculator 9287 ; instruction. 9288 9289 ; ... and again later at this point 9290 9291 mark_19A4: 9292 *GEN_ENT_2:* 9293 EXX ; switch sets 9294 EX (SP),HL ; and store the address of next instruction, 9295 ; the return address, in H'L'. 9296 ; If this is a recursive call then the H'L' 9297 ; of the previous invocation goes on stack. 9298 ; c.f. end_calc. 9299 EXX ; switch back to main set. 9300 9301 ; this is the re-entry looping point when handling a string of literals. 9302 9303 mark_19A7: 9304 *RE_ENTRY:* 9305 LD (STKEND),DE ; save end of stack 9306 EXX ; switch to alt 9307 LD A,(HL) ; get next literal 9308 INC HL ; increase pointer' 9309 9310 ; single operation jumps back to here 9311 9312 mark_19AE: 9313 *SCAN_ENT:* 9314 PUSH HL ; save pointer on stack * 9315 AND A ; now test the literal 9316 JP P,FIRST_3D <#FIRST_3D> ; forward if in range $00 - $3D 9317 ; anything with bit 7 set will be one of 9318 ; 128 compound literals. 9319 9320 ; compound literals have the following format. 9321 ; bit 7 set indicates compound. 9322 ; bits 6-5 the subgroup 0-3. 9323 ; bits 4-0 the embedded parameter $00 - $1F. 9324 ; The subgroup 0-3 needs to be manipulated to form the next available four 9325 ; address places after the simple literals in the address table. 9326 9327 LD D,A ; save literal in D 9328 AND $60 ; and with 01100000 to isolate subgroup 9329 RRCA ; rotate bits 9330 RRCA ; 4 places to right 9331 RRCA ; not five as we need offset * 2 9332 RRCA ; 00000xx0 9333 ADD A,$72 ; add ($39 * 2) to give correct offset. 9334 ; alter above if you add more literals. 9335 LD L,A ; store in L for later indexing. 9336 LD A,D ; bring back compound literal 9337 AND $1F ; use mask to isolate parameter bits 9338 JR ENT_TABLE <#ENT_TABLE> ; forward 9339 9340 ; ___ 9341 9342 ; the branch was here with simple literals. 9343 9344 mark_19C2: 9345 *FIRST_3D:* 9346 CP $18 ; compare with first unary operations. 9347 JR NC,DOUBLE_A <#DOUBLE_A> ; with unary operations 9348 9349 ; it is binary so adjust pointers. 9350 9351 EXX ; 9352 LD BC,-5 9353 LD D,H ; transfer HL, the last value, to DE. 9354 LD E,L ; 9355 ADD HL,BC ; subtract 5 making HL point to second 9356 ; value. 9357 EXX ; 9358 9359 mark_19CE: 9360 *DOUBLE_A:* 9361 RLCA ; double the literal 9362 LD L,A ; and store in L for indexing 9363 9364 mark_19D0: 9365 *ENT_TABLE:* 9366 LD DE,tbl_addrs <#tbl_addrs> ; Address: tbl_addrs 9367 LD H,$00 ; prepare to index 9368 ADD HL,DE ; add to get address of routine 9369 LD E,(HL) ; low byte to E 9370 INC HL ; 9371 LD D,(HL) ; high byte to D 9372 9373 LD HL,RE_ENTRY <#RE_ENTRY> 9374 EX (SP),HL ; goes on machine stack 9375 ; address of next literal goes to HL. * 9376 9377 9378 PUSH DE ; now the address of routine is stacked. 9379 EXX ; back to main set 9380 ; avoid using IY register. 9381 LD BC,(STKEND+1) ; STKEND_hi 9382 ; nothing much goes to C but BERG to B 9383 ; and continue into next ret instruction 9384 ; which has a dual identity 9385 9386 9387 ------------------------------------------------------------------------ 9388 9389 ; THE *'DELETE'* SUBROUTINE 9390 ------------------------------------------------------------------------ 9391 9392 ; offset $02: 'delete' 9393 ; A simple return but when used as a calculator literal this 9394 ; deletes the last value from the calculator stack. 9395 ; On entry, as always with binary operations, 9396 ; HL=first number, DE=second number 9397 ; On exit, HL=result, DE=stkend. 9398 ; So nothing to do 9399 9400 mark_19E3: 9401 *delete:* 9402 RET ; return - indirect jump if from above. 9403 9404 ------------------------------------------------------------------------ 9405 9406 ; THE *'SINGLE OPERATION'* SUBROUTINE 9407 ------------------------------------------------------------------------ 9408 9409 ; offset $37: 'FP_CALC_2' 9410 ; this single operation is used, in the first instance, to evaluate most 9411 ; of the mathematical and string functions found in BASIC expressions. 9412 9413 mark_19E4: 9414 *FP_CALC_2:* 9415 POP AF ; drop return address. 9416 LD A,(BERG) ; load accumulator from system variable BERG 9417 ; value will be literal eg. 'tan' 9418 EXX ; switch to alt 9419 JR SCAN_ENT <#SCAN_ENT> ; back 9420 ; next literal will be end_calc in scanning 9421 9422 ------------------------------------------------------------------------ 9423 9424 ; THE *'TEST 5 SPACES'* SUBROUTINE 9425 ------------------------------------------------------------------------ 9426 9427 ; This routine is called from MOVE_FP, STK_CONST and STK_STORE to 9428 ; test that there is enough space between the calculator stack and the 9429 ; machine stack for another five_byte value. It returns with BC holding 9430 ; the value 5 ready for any subsequent LDIR. 9431 9432 mark_19EB: 9433 *TEST_5_SP:* 9434 PUSH DE ; save 9435 PUSH HL ; registers 9436 LD BC,5 ; an overhead of five bytes 9437 CALL TEST_ROOM <#TEST_ROOM> ; tests free RAM raising 9438 ; an error if not. 9439 POP HL ; else restore 9440 POP DE ; registers. 9441 RET ; return with BC set at 5. 9442 9443 9444 ------------------------------------------------------------------------ 9445 9446 ; THE *'MOVE A FLOATING POINT NUMBER'* SUBROUTINE 9447 ------------------------------------------------------------------------ 9448 9449 ; offset $2D: 'duplicate' 9450 ; This simple routine is a 5-byte LDIR instruction 9451 ; that incorporates a memory check. 9452 ; When used as a calculator literal it duplicates the last value on the 9453 ; calculator stack. 9454 ; Unary so on entry HL points to last value, DE to stkend 9455 9456 mark_19F6: 9457 *duplicate:* 9458 *MOVE_FP:* 9459 CALL TEST_5_SP <#TEST_5_SP> ; test free memory 9460 ; and sets BC to 5. 9461 LDIR ; copy the five bytes. 9462 RET ; return with DE addressing new STKEND 9463 ; and HL addressing new last value. 9464 9465 ------------------------------------------------------------------------ 9466 9467 ; THE *'STACK LITERALS'* SUBROUTINE 9468 ------------------------------------------------------------------------ 9469 9470 ; offset $30: 'stk_data' 9471 ; When a calculator subroutine needs to put a value on the calculator 9472 ; stack that is not a regular constant this routine is called with a 9473 ; variable number of following data bytes that convey to the routine 9474 ; the floating point form as succinctly as is possible. 9475 9476 mark_19FC: 9477 *stk_data:* 9478 LD H,D ; transfer STKEND 9479 LD L,E ; to HL for result. 9480 9481 mark_19FE: 9482 *STK_CONST:* 9483 CALL TEST_5_SP <#TEST_5_SP> ; tests that room exists 9484 ; and sets BC to $05. 9485 9486 EXX ; switch to alternate set 9487 PUSH HL ; save the pointer to next literal on stack 9488 EXX ; switch back to main set 9489 9490 EX (SP),HL ; pointer to HL, destination to stack. 9491 9492 #if ORIGINAL 9493 PUSH BC ; save BC - value 5 from test room ??. 9494 #else 9495 ;; PUSH BC ; save BC - value 5 from test room. No need. 9496 #endif 9497 LD A,(HL) ; fetch the byte following 'stk_data' 9498 AND $C0 ; isolate bits 7 and 6 9499 RLCA ; rotate 9500 RLCA ; to bits 1 and 0 range $00 - $03. 9501 LD C,A ; transfer to C 9502 INC C ; and increment to give number of bytes 9503 ; to read. $01 - $04 9504 LD A,(HL) ; reload the first byte 9505 AND $3F ; mask off to give possible exponent. 9506 JR NZ,FORM_EXP <#FORM_EXP> ; forward to FORM_EXP if it was possible to 9507 ; include the exponent. 9508 9509 ; else byte is just a byte count and exponent comes next. 9510 9511 INC HL ; address next byte and 9512 LD A,(HL) ; pick up the exponent ( - $50). 9513 9514 mark_1A14: 9515 *FORM_EXP:* 9516 ADD A,$50 ; now add $50 to form actual exponent 9517 LD (DE),A ; and load into first destination byte. 9518 LD A,$05 ; load accumulator with $05 and 9519 SUB C ; subtract C to give count of trailing 9520 ; zeros plus one. 9521 INC HL ; increment source 9522 INC DE ; increment destination 9523 9524 9525 #if ORIGINAL 9526 LD B,$00 ; prepare to copy. Note. B is zero. 9527 LDIR ; copy C bytes 9528 POP BC ; restore 5 counter to BC. 9529 #else 9530 LDIR ; copy C bytes 9531 #endif 9532 9533 EX (SP),HL ; put HL on stack as next literal pointer 9534 ; and the stack value - result pointer - 9535 ; to HL. 9536 9537 EXX ; switch to alternate set. 9538 POP HL ; restore next literal pointer from stack 9539 ; to H'L'. 9540 EXX ; switch back to main set. 9541 9542 LD B,A ; zero count to B 9543 XOR A ; clear accumulator 9544 9545 mark_1A27: 9546 *STK_ZEROS:* 9547 DEC B ; decrement B counter 9548 RET Z ; return if zero. >> 9549 ; DE points to new STKEND 9550 ; HL to new number. 9551 9552 LD (DE),A ; else load zero to destination 9553 INC DE ; increase destination 9554 JR STK_ZEROS <#STK_ZEROS> ; loop back until done. 9555 9556 ------------------------------------------------------------------------ 9557 9558 ; THE *'SKIP CONSTANTS'* SUBROUTINE 9559 ------------------------------------------------------------------------ 9560 9561 ; This routine traverses variable-length entries in the table of constants, 9562 ; stacking intermediate, unwanted constants onto a dummy calculator stack, 9563 ; in the first five bytes of the ZX81 ROM. 9564 9565 #if ORIGINAL 9566 mark_1A2D: 9567 *SKIP_CONS:* 9568 AND A ; test if initially zero. 9569 9570 mark_1A2E: 9571 *SKIP_NEXT:* 9572 RET Z ; return if zero. >> 9573 9574 PUSH AF ; save count. 9575 PUSH DE ; and normal STKEND 9576 9577 LD DE,$0000 ; dummy value for STKEND at start of ROM 9578 ; Note. not a fault but this has to be 9579 ; moved elsewhere when running in RAM. 9580 ; 9581 CALL STK_CONST <#STK_CONST> ; works through variable 9582 ; length records. 9583 9584 POP DE ; restore real STKEND 9585 POP AF ; restore count 9586 DEC A ; decrease 9587 JR SKIP_NEXT <#SKIP_NEXT> ; loop back 9588 #else 9589 ; Since the table now uses uncompressed values, some extra ROM space is 9590 ; required for the table but much more is released by getting rid of routines 9591 ; like this. 9592 #endif 9593 9594 ------------------------------------------------------------------------ 9595 9596 ; THE *'MEMORY LOCATION'* SUBROUTINE 9597 ------------------------------------------------------------------------ 9598 9599 ; This routine, when supplied with a base address in HL and an index in A, 9600 ; will calculate the address of the A'th entry, where each entry occupies 9601 ; five bytes. It is used for addressing floating-point numbers in the 9602 ; calculator's memory area. 9603 9604 mark_1A3C: 9605 *LOC_MEM:* 9606 LD C,A ; store the original number $00-$1F. 9607 RLCA ; double. 9608 RLCA ; quadruple. 9609 ADD A,C ; now add original value to multiply by five. 9610 9611 LD C,A ; place the result in C. 9612 LD B,$00 ; set B to 0. 9613 ADD HL,BC ; add to form address of start of number in HL. 9614 9615 RET ; return. 9616 9617 ------------------------------------------------------------------------ 9618 9619 ; THE *'GET FROM MEMORY AREA'* SUBROUTINE 9620 ------------------------------------------------------------------------ 9621 9622 ; offsets $E0 to $FF: 'get_mem_0', 'get_mem_1' etc. 9623 ; A holds $00-$1F offset. 9624 ; The calculator stack increases by 5 bytes. 9625 9626 mark_1A45: 9627 *get_mem_xx:* 9628 9629 #if ORIGINAL 9630 PUSH DE ; save STKEND 9631 LD HL,(MEM) ; MEM is base address of the memory cells. 9632 #else 9633 ; Note. first two instructions have been swapped to create a subroutine. 9634 LD HL,(MEM) ; MEM is base address of the memory cells. 9635 *INDEX_5* ; new label 9636 PUSH DE ; save STKEND 9637 #endif 9638 CALL LOC_MEM <#LOC_MEM> ; so that HL = first byte 9639 CALL MOVE_FP <#MOVE_FP> ; moves 5 bytes with memory 9640 ; check. 9641 ; DE now points to new STKEND. 9642 POP HL ; the original STKEND is now RESULT pointer. 9643 RET ; return. 9644 9645 ------------------------------------------------------------------------ 9646 9647 ; THE *'STACK A CONSTANT'* SUBROUTINE 9648 ------------------------------------------------------------------------ 9649 9650 9651 *stk_const_xx:* 9652 #if ORIGINAL 9653 9654 ; offset $A0: 'stk_zero' 9655 ; offset $A1: 'stk_one' 9656 ; offset $A2: 'stk_half' 9657 ; offset $A3: 'stk_half_pi' 9658 ; offset $A4: 'stk_ten' 9659 ; 9660 ; This routine allows a one-byte instruction to stack up to 32 constants 9661 ; held in short form in a table of constants. In fact only 5 constants are 9662 ; required. On entry the A register holds the literal ANDed with $1F. 9663 ; It isn't very efficient and it would have been better to hold the 9664 ; numbers in full, five byte form and stack them in a similar manner 9665 ; to that which would be used later for semi-tone table values. 9666 9667 mark_1A51: 9668 9669 LD H,D ; save STKEND - required for result 9670 LD L,E ; 9671 EXX ; swap 9672 PUSH HL ; save pointer to next literal 9673 LD HL,stk_zero <#stk_zero> ; Address: stk_zero - start of table of 9674 ; constants 9675 EXX ; 9676 CALL SKIP_CONS <#SKIP_CONS> 9677 CALL STK_CONST <#STK_CONST> 9678 EXX ; 9679 POP HL ; restore pointer to next literal. 9680 EXX ; 9681 RET ; return. 9682 #else 9683 *stk_con_x* 9684 LD HL,TAB_CNST ; Address: Table of constants. 9685 9686 JR INDEX_5 <#INDEX_5> ; and join subroutine above. 9687 #endif 9688 9689 9690 9691 ------------------------------------------------------------------------ 9692 9693 ; THE *'STORE IN A MEMORY AREA'* SUBROUTINE 9694 ------------------------------------------------------------------------ 9695 9696 ; Offsets $C0 to $DF: 'st_mem_0', 'st_mem_1' etc. 9697 ; Although 32 memory storage locations can be addressed, only six 9698 ; $C0 to $C5 are required by the ROM and only the thirty bytes (6*5) 9699 ; required for these are allocated. ZX81 programmers who wish to 9700 ; use the floating point routines from assembly language may wish to 9701 ; alter the system variable MEM to point to 160 bytes of RAM to have 9702 ; use the full range available. 9703 ; A holds derived offset $00-$1F. 9704 ; Unary so on entry HL points to last value, DE to STKEND. 9705 9706 mark_1A63: 9707 *st_mem_xx:* 9708 PUSH HL ; save the result pointer. 9709 EX DE,HL ; transfer to DE. 9710 LD HL,(MEM) ; fetch MEM the base of memory area. 9711 CALL LOC_MEM <#LOC_MEM> ; sets HL to the destination. 9712 EX DE,HL ; swap - HL is start, DE is destination. 9713 9714 #if ORIGINAL 9715 CALL MOVE_FP <#MOVE_FP> 9716 ; note. a short ld bc,5; ldir 9717 ; the embedded memory check is not required 9718 ; so these instructions would be faster! 9719 #else 9720 LD C,5 ;+ one extra byte but 9721 LDIR ;+ faster and no memory check. 9722 #endif 9723 9724 9725 EX DE,HL ; DE = STKEND 9726 POP HL ; restore original result pointer 9727 RET ; return. 9728 9729 ------------------------------------------------------------------------ 9730 9731 ; THE *'EXCHANGE'* SUBROUTINE 9732 ------------------------------------------------------------------------ 9733 9734 ; offset $01: 'exchange' 9735 ; This routine exchanges the last two values on the calculator stack 9736 ; On entry, as always with binary operations, 9737 ; HL=first number, DE=second number 9738 ; On exit, HL=result, DE=stkend. 9739 9740 mark_1A72: 9741 *exchange:* 9742 LD B,$05 ; there are five bytes to be swapped 9743 9744 ; start of loop. 9745 9746 mark_1A74: 9747 *SWAP_BYTE:* 9748 LD A,(DE) ; each byte of second 9749 #if ORIGINAL 9750 LD C,(HL) ; each byte of first 9751 EX DE,HL ; swap pointers 9752 #else 9753 LD C,A ;+ 9754 LD A,(HL) 9755 #endif 9756 LD (DE),A ; store each byte of first 9757 LD (HL),C ; store each byte of second 9758 INC HL ; advance both 9759 INC DE ; pointers. 9760 DJNZ SWAP_BYTE <#SWAP_BYTE> ; loop back until all 5 done. 9761 9762 #if ORIGINAL 9763 EX DE,HL ; even up the exchanges so that DE addresses STKEND. 9764 #else 9765 ; omit 9766 #endif 9767 RET ; return. 9768 9769 ------------------------------------------------------------------------ 9770 9771 ; THE *'SERIES GENERATOR'* SUBROUTINE 9772 ------------------------------------------------------------------------ 9773 9774 9775 ; The ZX81 uses Chebyshev polynomials to generate approximations for 9776 ; SIN, ATN, LN and EXP. These are named after the Russian mathematician 9777 ; Pafnuty Chebyshev, born in 1821, who did much pioneering work on numerical 9778 ; series. As far as calculators are concerned, Chebyshev polynomials have an 9779 ; advantage over other series, for example the Taylor series, as they can 9780 ; reach an approximation in just six iterations for SIN, eight for EXP and 9781 ; twelve for LN and ATN. The mechanics of the routine are interesting but 9782 ; for full treatment of how these are generated with demonstrations in 9783 ; Sinclair BASIC see "The Complete Spectrum ROM Disassembly" by Dr Ian Logan 9784 ; and Dr Frank O'Hara, published 1983 by Melbourne House. 9785 9786 mark_1A7F: 9787 *series_xx:* 9788 LD B,A ; parameter $00 - $1F to B counter 9789 CALL GEN_ENT_1 <#GEN_ENT_1> 9790 ; A recursive call to a special entry point 9791 ; in the calculator that puts the B register 9792 ; in the system variable BERG. The return 9793 ; address is the next location and where 9794 ; the calculator will expect its first 9795 ; instruction - now pointed to by HL'. 9796 ; The previous pointer to the series of 9797 ; five-byte numbers goes on the machine stack. 9798 9799 ; The initialization phase. 9800 9801 DEFB __duplicate ;; x,x 9802 DEFB __addition ;; x+x 9803 DEFB __st_mem_0 ;; x+x 9804 DEFB __delete ;; . 9805 DEFB __stk_zero ;; 0 9806 DEFB __st_mem_2 ;; 0 9807 9808 ; a loop is now entered to perform the algebraic calculation for each of 9809 ; the numbers in the series 9810 9811 mark_1A89: 9812 *G_LOOP:* 9813 DEFB __duplicate ;; v,v. 9814 DEFB __get_mem_0 ;; v,v,x+2 9815 DEFB __multiply ;; v,v*x+2 9816 DEFB __get_mem_2 ;; v,v*x+2,v 9817 DEFB __st_mem_1 ;; 9818 DEFB __subtract ;; 9819 DEFB __end_calc ;; 9820 9821 ; the previous pointer is fetched from the machine stack to H'L' where it 9822 ; addresses one of the numbers of the series following the series literal. 9823 9824 CALL stk_data <#stk_data> ; is called directly to 9825 ; push a value and advance H'L'. 9826 CALL GEN_ENT_2 <#GEN_ENT_2> ; recursively re-enters 9827 ; the calculator without disturbing 9828 ; system variable BERG 9829 ; H'L' value goes on the machine stack and is 9830 ; then loaded as usual with the next address. 9831 9832 DEFB __addition ;; 9833 DEFB __exchange ;; 9834 DEFB __st_mem_2 ;; 9835 DEFB __delete ;; 9836 9837 DEFB __dec_jr_nz ;; 9838 DEFB $EE ;;back to G_LOOP <#G_LOOP>, G_LOOP 9839 9840 ; when the counted loop is complete the final subtraction yields the result 9841 ; for example SIN X. 9842 9843 DEFB __get_mem_1 ;; 9844 DEFB __subtract ;; 9845 DEFB __end_calc ;; 9846 9847 RET ; return with H'L' pointing to location 9848 ; after last number in series. 9849 9850 ------------------------------------------------------------------------ 9851 9852 ; Handle unary minus (18) 9853 ------------------------------------------------------------------------ 9854 9855 ; Unary so on entry HL points to last value, DE to STKEND. 9856 9857 mark_1AA0: 9858 *mark_1AA0:* 9859 *neg:* 9860 LD A, (HL) ; fetch exponent of last value on the 9861 ; calculator stack. 9862 AND A ; test it. 9863 RET Z ; return if zero. 9864 9865 INC HL ; address the byte with the sign bit. 9866 LD A,(HL) ; fetch to accumulator. 9867 XOR $80 ; toggle the sign bit. 9868 LD (HL),A ; put it back. 9869 DEC HL ; point to last value again. 9870 RET ; return. 9871 9872 ------------------------------------------------------------------------ 9873 9874 ; Absolute magnitude (27) 9875 ------------------------------------------------------------------------ 9876 9877 ; This calculator literal finds the absolute value of the last value, 9878 ; floating point, on calculator stack. 9879 9880 mark_1AAA: 9881 *abs:* 9882 INC HL ; point to byte with sign bit. 9883 RES 7,(HL) ; make the sign positive. 9884 DEC HL ; point to last value again. 9885 RET ; return. 9886 9887 ------------------------------------------------------------------------ 9888 9889 ; Signum (26) 9890 ------------------------------------------------------------------------ 9891 9892 ; This routine replaces the last value on the calculator stack, 9893 ; which is in floating point form, with one if positive and with -minus one 9894 ; if negative. If it is zero then it is left as such. 9895 9896 mark_1AAF: 9897 *sgn:* 9898 INC HL ; point to first byte of 4-byte mantissa. 9899 LD A,(HL) ; pick up the byte with the sign bit. 9900 DEC HL ; point to exponent. 9901 DEC (HL) ; test the exponent for 9902 INC (HL) ; the value zero. 9903 9904 SCF ; set the carry flag. 9905 CALL NZ,FP_0_OR_1 <#FP_0_OR_1> ; replaces last value with one 9906 ; if exponent indicates the value is non-zero. 9907 ; in either case mantissa is now four zeros. 9908 9909 INC HL ; point to first byte of 4-byte mantissa. 9910 RLCA ; rotate original sign bit to carry. 9911 RR (HL) ; rotate the carry into sign. 9912 DEC HL ; point to last value. 9913 RET ; return. 9914 9915 9916 ------------------------------------------------------------------------ 9917 9918 ; Handle PEEK function (28) 9919 ------------------------------------------------------------------------ 9920 9921 ; This function returns the contents of a memory address. 9922 ; The entire address space can be peeked including the ROM. 9923 9924 mark_1ABE: 9925 *PEEK:* 9926 CALL FIND_INT <#FIND_INT> ; puts address in BC. 9927 LD A,(BC) ; load contents into A register. 9928 9929 mark_1AC2: 9930 *IN_PK_STK:* 9931 JP STACK_A <#STACK_A> ; exit via STACK_A to put value on the 9932 ; calculator stack. 9933 9934 ------------------------------------------------------------------------ 9935 9936 ; USR number (29) 9937 ------------------------------------------------------------------------ 9938 9939 ; The USR function followed by a number 0-65535 is the method by which 9940 ; the ZX81 invokes machine code programs. This function returns the 9941 ; contents of the BC register pair. 9942 ; Note. that STACK_BC re-initializes the IY register to ERR_NR if a user-written 9943 ; program has altered it. 9944 9945 mark_1AC5: 9946 *usr_num:* 9947 CALL FIND_INT <#FIND_INT> ; to fetch the 9948 ; supplied address into BC. 9949 9950 LD HL,STACK_BC <#STACK_BC> ; address: STACK_BC is 9951 PUSH HL ; pushed onto the machine stack. 9952 PUSH BC ; then the address of the machine code 9953 ; routine. 9954 9955 RET ; make an indirect jump to the routine 9956 ; and, hopefully, to STACK_BC also. 9957 9958 9959 ------------------------------------------------------------------------ 9960 9961 ; Greater than zero ($33) 9962 ------------------------------------------------------------------------ 9963 9964 ; Test if the last value on the calculator stack is greater than zero. 9965 ; This routine is also called directly from the end-tests of the comparison 9966 ; routine. 9967 9968 mark_1ACE: 9969 *greater_0:* 9970 LD A,(HL) ; fetch exponent. 9971 AND A ; test it for zero. 9972 RET Z ; return if so. 9973 9974 9975 LD A,$FF ; prepare XOR mask for sign bit 9976 JR SIGN_TO_C <#SIGN_TO_C> ; forward to SIGN_TO_C 9977 ; to put sign in carry 9978 ; (carry will become set if sign is positive) 9979 ; and then overwrite location with 1 or 0 9980 ; as appropriate. 9981 9982 ------------------------------------------------------------------------ 9983 9984 ; Handle NOT operator ($2C) 9985 ------------------------------------------------------------------------ 9986 9987 ; This overwrites the last value with 1 if it was zero else with zero 9988 ; if it was any other value. 9989 ; 9990 ; e.g. NOT 0 returns 1, NOT 1 returns 0, NOT -3 returns 0. 9991 ; 9992 ; The subroutine is also called directly from the end-tests of the comparison 9993 ; operator. 9994 9995 mark_1AD5: 9996 *not:* 9997 LD A,(HL) ; get exponent byte. 9998 NEG ; negate - sets carry if non-zero. 9999 CCF ; complement so carry set if zero, else reset. 10000 JR FP_0_OR_1 <#FP_0_OR_1> ; forward to FP_0_OR_1. 10001 10002 ------------------------------------------------------------------------ 10003 10004 ; Less than zero (32) 10005 ------------------------------------------------------------------------ 10006 10007 ; Destructively test if last value on calculator stack is less than zero. 10008 ; Bit 7 of second byte will be set if so. 10009 10010 mark_1ADB: 10011 *less_0:* 10012 XOR A ; set xor mask to zero 10013 ; (carry will become set if sign is negative). 10014 10015 ; transfer sign of mantissa to Carry Flag. 10016 10017 mark_1ADC: 10018 *SIGN_TO_C:* 10019 INC HL ; address 2nd byte. 10020 XOR (HL) ; bit 7 of HL will be set if number is negative. 10021 DEC HL ; address 1st byte again. 10022 RLCA ; rotate bit 7 of A to carry. 10023 10024 ------------------------------------------------------------------------ 10025 10026 ; Zero or one 10027 ------------------------------------------------------------------------ 10028 10029 ; This routine places an integer value zero or one at the addressed location 10030 ; of calculator stack or MEM area. The value one is written if carry is set on 10031 ; entry else zero. 10032 10033 mark_1AE0: 10034 *FP_0_OR_1:* 10035 PUSH HL ; save pointer to the first byte 10036 LD B,$05 ; five bytes to do. 10037 10038 mark_1AE3: 10039 *FP_loop:* 10040 LD (HL),$00 ; insert a zero. 10041 INC HL ; 10042 DJNZ FP_loop <#FP_loop> ; repeat. 10043 10044 POP HL ; 10045 RET NC ; 10046 10047 LD (HL),$81 ; make value 1 10048 RET ; return. 10049 10050 10051 ------------------------------------------------------------------------ 10052 10053 ; Handle OR operator (07) 10054 ------------------------------------------------------------------------ 10055 10056 ; The Boolean OR operator. eg. X OR Y 10057 ; The result is zero if both values are zero else a non-zero value. 10058 ; 10059 ; e.g. 0 OR 0 returns 0. 10060 ; -3 OR 0 returns -3. 10061 ; 0 OR -3 returns 1. 10062 ; -3 OR 2 returns 1. 10063 ; 10064 ; A binary operation. 10065 ; On entry HL points to first operand (X) and DE to second operand (Y). 10066 10067 mark_1AED: 10068 *or:* 10069 LD A,(DE) ; fetch exponent of second number 10070 AND A ; test it. 10071 RET Z ; return if zero. 10072 10073 SCF ; set carry flag 10074 JR FP_0_OR_1 <#FP_0_OR_1> ; back to FP_0_OR_1 to overwrite the first operand 10075 ; with the value 1. 10076 10077 10078 ------------------------------------------------------------------------ 10079 10080 ; Handle number AND number (08) 10081 ------------------------------------------------------------------------ 10082 10083 ; The Boolean AND operator. 10084 ; 10085 ; e.g. -3 AND 2 returns -3. 10086 ; -3 AND 0 returns 0. 10087 ; 0 and -2 returns 0. 10088 ; 0 and 0 returns 0. 10089 ; 10090 ; Compare with OR routine above. 10091 10092 *boolean_num_and_num:* 10093 LD A,(DE) ; fetch exponent of second number. 10094 AND A ; test it. 10095 RET NZ ; return if not zero. 10096 10097 JR FP_0_OR_1 <#FP_0_OR_1> ; back to FP_0_OR_1 to overwrite the first operand 10098 ; with zero for return value. 10099 10100 ------------------------------------------------------------------------ 10101 10102 ; Handle string AND number (10) 10103 ------------------------------------------------------------------------ 10104 10105 ; e.g. "YOU WIN" AND SCORE>99 will return the string if condition is true 10106 ; or the null string if false. 10107 10108 *strs_and_num:* 10109 LD A,(DE) ; fetch exponent of second number. 10110 AND A ; test it. 10111 RET NZ ; return if number was not zero - the string 10112 ; is the result. 10113 10114 ; if the number was zero (false) then the null string must be returned by 10115 ; altering the length of the string on the calculator stack to zero. 10116 10117 PUSH DE ; save pointer to the now obsolete number 10118 ; (which will become the new STKEND) 10119 10120 DEC DE ; point to the 5th byte of string descriptor. 10121 XOR A ; clear the accumulator. 10122 LD (DE),A ; place zero in high byte of length. 10123 DEC DE ; address low byte of length. 10124 LD (DE),A ; place zero there - now the null string. 10125 10126 POP DE ; restore pointer - new STKEND. 10127 RET ; return. 10128 10129 ------------------------------------------------------------------------ 10130 10131 ; Perform comparison ($09-$0E, $11-$16) 10132 ------------------------------------------------------------------------ 10133 10134 ; True binary operations. 10135 ; 10136 ; A single entry point is used to evaluate six numeric and six string 10137 ; comparisons. On entry, the calculator literal is in the B register and 10138 ; the two numeric values, or the two string parameters, are on the 10139 ; calculator stack. 10140 ; The individual bits of the literal are manipulated to group similar 10141 ; operations although the SUB 8 instruction does nothing useful and merely 10142 ; alters the string test bit. 10143 ; Numbers are compared by subtracting one from the other, strings are 10144 ; compared by comparing every character until a mismatch, or the end of one 10145 ; or both, is reached. 10146 ; 10147 ; Numeric Comparisons. 10148 ------------------------------------------------------------------------ 10149 10150 ; The *'x>y'* example is the easiest as it employs straight-thru logic. 10151 ; Number y is subtracted from x and the result tested for greater_0 yielding 10152 ; a final value 1 (true) or 0 (false). 10153 ; For 'x<y' the same logic is used but the two values are first swapped on the 10154 ; calculator stack. 10155 ; For 'x=y' NOT is applied to the subtraction result yielding true if the 10156 ; difference was zero and false with anything else. 10157 ; The first three numeric comparisons are just the opposite of the last three 10158 ; so the same processing steps are used and then a final NOT is applied. 10159 ; 10160 ; literal Test No sub 8 ExOrNot 1st RRCA exch sub ? End-Tests 10161 ; ========= ==== == ======== === ======== ======== ==== === = === === === 10162 ; num_l_eql x<=y 09 00000001 dec 00000000 00000000 ---- x-y ? --- >0? NOT 10163 ; num_gr_eql x>=y 0A 00000010 dec 00000001 10000000c swap y-x ? --- >0? NOT 10164 ; nums_neql x<>y 0B 00000011 dec 00000010 00000001 ---- x-y ? NOT --- NOT 10165 ; num_grtr x>y 0C 00000100 - 00000100 00000010 ---- x-y ? --- >0? --- 10166 ; num_less x<y 0D 00000101 - 00000101 10000010c swap y-x ? --- >0? --- 10167 ; nums_eql x=y 0E 00000110 - 00000110 00000011 ---- x-y ? NOT --- --- 10168 ; 10169 ; comp -> C/F 10170 ; ==== === 10171 ; str_l_eql x$<=y$ 11 00001001 dec 00001000 00000100 ---- x$y$ 0 !or >0? NOT 10172 ; str_gr_eql x$>=y$ 12 00001010 dec 00001001 10000100c swap y$x$ 0 !or >0? NOT 10173 ; strs_neql x$<>y$ 13 00001011 dec 00001010 00000101 ---- x$y$ 0 !or >0? NOT 10174 ; str_grtr x$>y$ 14 00001100 - 00001100 00000110 ---- x$y$ 0 !or >0? --- 10175 ; str_less x$<y$ 15 00001101 - 00001101 10000110c swap y$x$ 0 !or >0? --- 10176 ; strs_eql x$=y$ 16 00001110 - 00001110 00000111 ---- x$y$ 0 !or >0? --- 10177 ; 10178 ; String comparisons are a little different in that the eql/neql carry flag 10179 ; from the 2nd RRCA is, as before, fed into the first of the end tests but 10180 ; along the way it gets modified by the comparison process. The result on the 10181 ; stack always starts off as zero and the carry fed in determines if NOT is 10182 ; applied to it. So the only time the greater-0 test is applied is if the 10183 ; stack holds zero which is not very efficient as the test will always yield 10184 ; zero. The most likely explanation is that there were once separate end tests 10185 ; for numbers and strings. 10186 10187 ; $1B03 SAME ADDRESS FOR MULTIPLE ROUTINES ??? 10188 10189 *num_l_eql:* 10190 *num_gr_eql:* 10191 *nums_neql:* 10192 *num_grtr:* 10193 *num_less:* 10194 *nums_eql:* 10195 *str_l_eql:* 10196 *str_gr_eql:* 10197 *strs_neql:* 10198 *str_grtr:* 10199 *str_less:* 10200 *strs_eql:* 10201 *num_lt_eql:* 10202 #if ORIGINAL 10203 mark_1B03: 10204 LD A,B ; transfer literal to accumulator. 10205 SUB $08 ; subtract eight - which is not useful. 10206 #else 10207 LD A,B ; transfer literal to accumulator. 10208 ;; SUB $08 ; subtract eight - which is not useful. 10209 #endif 10210 BIT 2,A ; isolate '>', '<', '='. 10211 10212 JR NZ,EX_OR_NOT <#EX_OR_NOT> ; skip to EX_OR_NOT with these. 10213 10214 DEC A ; else make $00-$02, $08-$0A to match bits 0-2. 10215 10216 *EX_OR_NOT:* 10217 #if ORIGINAL 10218 mark_1B0B: 10219 #endif 10220 RRCA ; the first RRCA sets carry for a swap. 10221 JR NC,NUM_OR_STR <#NUM_OR_STR> ; forward to NUM_OR_STR with other 8 cases 10222 10223 ; for the other 4 cases the two values on the calculator stack are exchanged. 10224 10225 PUSH AF ; save A and carry. 10226 PUSH HL ; save HL - pointer to first operand. 10227 ; (DE points to second operand). 10228 10229 CALL exchange <#exchange> ; routine exchange swaps the two values. 10230 ; (HL = second operand, DE = STKEND) 10231 10232 POP DE ; DE = first operand 10233 EX DE,HL ; as we were. 10234 POP AF ; restore A and carry. 10235 10236 ; Note. it would be better if the 2nd RRCA preceded the string test. 10237 ; It would save two duplicate bytes and if we also got rid of that sub 8 10238 ; at the beginning we wouldn't have to alter which bit we test. 10239 10240 *NUM_OR_STR:* 10241 #if ORIGINAL 10242 mark_1B16: 10243 10244 BIT 2,A ; test if a string comparison. 10245 JR NZ,STRINGS <#STRINGS> ; forward to STRINGS if so. 10246 10247 ; continue with numeric comparisons. 10248 10249 RRCA ; 2nd RRCA causes eql/neql to set carry. 10250 PUSH AF ; save A and carry 10251 #else 10252 RRCA ;+ causes 'eql/neql' to set carry. 10253 PUSH AF ;+ save the carry flag. 10254 10255 BIT 2,A ; test if a string comparison. 10256 JR NZ,STRINGS <#STRINGS> ; forward to STRINGS if so. 10257 10258 #endif 10259 10260 CALL SUBTRACT <#SUBTRACT> ; leaves result on stack. 10261 JR END_TESTS <#END_TESTS> ; forward to END_TESTS 10262 10263 ; ___ 10264 10265 10266 *STRINGS:* 10267 #if ORIGINAL 10268 mark_1B21: 10269 RRCA ; 2nd RRCA causes eql/neql to set carry. 10270 PUSH AF ; save A and carry. 10271 #else 10272 ;; RRCA ; 2nd RRCA causes eql/neql to set carry. 10273 ;; PUSH AF ; save A and carry. 10274 #endif 10275 CALL STK_FETCH <#STK_FETCH> ; gets 2nd string params 10276 PUSH DE ; save start2 *. 10277 PUSH BC ; and the length. 10278 10279 CALL STK_FETCH <#STK_FETCH> ; gets 1st string 10280 ; parameters - start in DE, length in BC. 10281 POP HL ; restore length of second to HL. 10282 10283 ; A loop is now entered to compare, by subtraction, each corresponding character 10284 ; of the strings. For each successful match, the pointers are incremented and 10285 ; the lengths decreased and the branch taken back to here. If both string 10286 ; remainders become null at the same time, then an exact match exists. 10287 10288 #if ORIGINAL 10289 mark_1B2C: 10290 #endif 10291 *BYTE_COMP:* 10292 LD A,H ; test if the second string 10293 OR L ; is the null string and hold flags. 10294 10295 EX (SP),HL ; put length2 on stack, bring start2 to HL *. 10296 LD A,B ; hi byte of length1 to A 10297 10298 JR NZ,SEC_PLUS <#SEC_PLUS> ; forward to SEC_PLUS if second not null. 10299 10300 OR C ; test length of first string. 10301 10302 #if ORIGINAL 10303 mark_1B33: 10304 #endif 10305 10306 *SECOND_LOW:* 10307 POP BC ; pop the second length off stack. 10308 JR Z,BOTH_NULL <#BOTH_NULL> ; forward if first string is also 10309 ; of zero length. 10310 10311 ; the true condition - first is longer than second (SECOND_LESS) 10312 10313 POP AF ; restore carry (set if eql/neql) 10314 CCF ; complement carry flag. 10315 ; Note. equality becomes false. 10316 ; Inequality is true. By swapping or applying 10317 ; a terminal 'not', all comparisons have been 10318 ; manipulated so that this is success path. 10319 JR STR_TEST <#STR_TEST> ; forward to leave via STR_TEST 10320 10321 ; ___ 10322 ; the branch was here with a match 10323 10324 #if ORIGINAL 10325 mark_1B3A: 10326 #endif 10327 10328 *BOTH_NULL:* 10329 POP AF ; restore carry - set for eql/neql 10330 JR STR_TEST <#STR_TEST> ; forward to STR_TEST 10331 10332 ; ___ 10333 ; the branch was here when 2nd string not null and low byte of first is yet 10334 ; to be tested. 10335 10336 10337 mark_1B3D: 10338 *SEC_PLUS:* 10339 OR C ; test the length of first string. 10340 JR Z,FRST_LESS <#FRST_LESS> ; forward to FRST_LESS if length is zero. 10341 10342 ; both strings have at least one character left. 10343 10344 LD A,(DE) ; fetch character of first string. 10345 SUB (HL) ; subtract with that of 2nd string. 10346 JR C,FRST_LESS <#FRST_LESS> ; forward to FRST_LESS if carry set 10347 10348 JR NZ,SECOND_LOW <#SECOND_LOW> ; back to SECOND_LOW and then STR_TEST 10349 ; if not exact match. 10350 10351 DEC BC ; decrease length of 1st string. 10352 INC DE ; increment 1st string pointer. 10353 10354 INC HL ; increment 2nd string pointer. 10355 EX (SP),HL ; swap with length on stack 10356 DEC HL ; decrement 2nd string length 10357 JR BYTE_COMP <#BYTE_COMP> ; back to BYTE_COMP 10358 10359 ; ___ 10360 ; the false condition. 10361 10362 mark_1B4D: 10363 *FRST_LESS:* 10364 POP BC ; discard length 10365 POP AF ; pop A 10366 AND A ; clear the carry for false result. 10367 10368 ; ___ 10369 ; exact match and x$>y$ rejoin here 10370 10371 mark_1B50: 10372 *STR_TEST:* 10373 PUSH AF ; save A and carry 10374 10375 RST _FP_CALC ;; 10376 DEFB __stk_zero ;; an initial false value. 10377 DEFB __end_calc ;; 10378 10379 ; both numeric and string paths converge here. 10380 10381 mark_1B54: 10382 *END_TESTS:* 10383 POP AF ; pop carry - will be set if eql/neql 10384 PUSH AF ; save it again. 10385 10386 CALL C,not <#not> ; sets true(1) if equal(0) 10387 ; or, for strings, applies true result. 10388 CALL greater_0 <#greater_0> ; ?????????? 10389 10390 10391 POP AF ; pop A 10392 RRCA ; the third RRCA - test for '<=', '>=' or '<>'. 10393 CALL NC,not <#not> ; apply a terminal NOT if so. 10394 RET ; return. 10395 ------------------------------------------------------------------------ 10396 10397 ; String concatenation ($17) 10398 ------------------------------------------------------------------------ 10399 10400 ; This literal combines two strings into one e.g. LET A$ = B$ + C$ 10401 ; The two parameters of the two strings to be combined are on the stack. 10402 10403 mark_1B62: 10404 *strs_add:* 10405 CALL STK_FETCH <#STK_FETCH> ; fetches string parameters 10406 ; and deletes calculator stack entry. 10407 PUSH DE ; save start address. 10408 PUSH BC ; and length. 10409 10410 CALL STK_FETCH <#STK_FETCH> ; for first string 10411 POP HL ; re-fetch first length 10412 PUSH HL ; and save again 10413 PUSH DE ; save start of second string 10414 PUSH BC ; and its length. 10415 10416 ADD HL,BC ; add the two lengths. 10417 LD B,H ; transfer to BC 10418 LD C,L ; and create 10419 RST _BC_SPACES ; BC_SPACES in workspace. 10420 ; DE points to start of space. 10421 10422 CALL STK_STO_STR <#STK_STO_STR> ; stores parameters 10423 ; of new string updating STKEND. 10424 POP BC ; length of first 10425 POP HL ; address of start 10426 10427 #if ORIGINAL 10428 LD A,B ; test for 10429 OR C ; zero length. 10430 JR Z,OTHER_STR <#OTHER_STR> ; to OTHER_STR if null string 10431 LDIR ; copy string to workspace. 10432 #else 10433 CALL COND_MV <#COND_MV> ;+ a conditional (NZ) ldir routine. 10434 #endif 10435 10436 mark_1B7D: 10437 *OTHER_STR:* 10438 POP BC ; now second length 10439 POP HL ; and start of string 10440 #if ORIGINAL 10441 LD A,B ; test this one 10442 OR C ; for zero length 10443 JR Z,STACK_POINTERS <#STACK_POINTERS> ; skip forward to STACK_POINTERS if so as complete. 10444 10445 LDIR ; else copy the bytes. 10446 ; and continue into next routine which 10447 ; sets the calculator stack pointers. 10448 #else 10449 CALL COND_MV <#COND_MV> ;+ a conditional (NZ) ldir routine. 10450 #endif 10451 10452 ------------------------------------------------------------------------ 10453 10454 ; Check stack pointers 10455 ------------------------------------------------------------------------ 10456 10457 ; Register DE is set to STKEND and HL, the result pointer, is set to five 10458 ; locations below this. 10459 ; This routine is used when it is inconvenient to save these values at the 10460 ; time the calculator stack is manipulated due to other activity on the 10461 ; machine stack. 10462 ; This routine is also used to terminate the VAL routine for 10463 ; the same reason and to initialize the calculator stack at the start of 10464 ; the CALCULATE routine. 10465 10466 mark_1B85: 10467 *STACK_POINTERS:* 10468 LD HL,(STKEND) ; fetch STKEND value from system variable. 10469 LD DE,-5 10470 PUSH HL ; push STKEND value. 10471 10472 ADD HL,DE ; subtract 5 from HL. 10473 10474 POP DE ; pop STKEND to DE. 10475 RET ; return. 10476 10477 ------------------------------------------------------------------------ 10478 10479 ; Handle CHR$ (2B) 10480 ------------------------------------------------------------------------ 10481 10482 ; This function returns a single character string that is a result of 10483 ; converting a number in the range 0-255 to a string e.g. CHR$ 38 = "A". 10484 ; Note. the ZX81 does not have an ASCII character set. 10485 10486 mark_1B8F: 10487 *chr_dollar:* 10488 CALL FP_TO_A <#FP_TO_A> ; puts the number in A. 10489 10490 JR C,REPORT_Bd <#REPORT_Bd> ; forward if overflow 10491 JR NZ,REPORT_Bd <#REPORT_Bd> ; forward if negative 10492 #if ORIGINAL 10493 PUSH AF ; save the argument. 10494 #endif 10495 LD BC,1 ; one space required. 10496 RST _BC_SPACES ; BC_SPACES makes DE point to start 10497 #if ORIGINAL 10498 POP AF ; restore the number. 10499 #endif 10500 LD (DE),A ; and store in workspace 10501 10502 #if ORIGINAL 10503 CALL STK_STO_STR <#STK_STO_STR> ; stacks descriptor. 10504 10505 EX DE,HL ; make HL point to result and DE to STKEND. 10506 RET ; return. 10507 #else 10508 JR str_STK ;+ relative jump to similar sequence in str$. 10509 #endif 10510 ; ___ 10511 10512 mark_1BA2: 10513 *REPORT_Bd:* 10514 RST _ERROR_1 10515 DEFB $0A ; Error Report: Integer out of range 10516 10517 ------------------------------------------------------------------------ 10518 10519 ; Handle VAL ($1A) 10520 ------------------------------------------------------------------------ 10521 10522 ; VAL treats the characters in a string as a numeric expression. 10523 ; e.g. VAL "2.3" = 2.3, VAL "2+4" = 6, VAL ("2" + "4") = 24. 10524 10525 *val:* 10526 #if ORIGINAL 10527 mark_1BA4: 10528 LD HL,(CH_ADD) ; fetch value of system variable CH_ADD 10529 #else 10530 RST _GET_CHAR ;+ shorter way to fetch CH_ADD. 10531 #endif 10532 PUSH HL ; and save on the machine stack. 10533 10534 CALL STK_FETCH <#STK_FETCH> ; fetches the string operand 10535 ; from calculator stack. 10536 10537 PUSH DE ; save the address of the start of the string. 10538 INC BC ; increment the length for a carriage return. 10539 10540 RST _BC_SPACES ; BC_SPACES creates the space in workspace. 10541 POP HL ; restore start of string to HL. 10542 LD (CH_ADD),DE ; load CH_ADD with start DE in workspace. 10543 10544 PUSH DE ; save the start in workspace 10545 LDIR ; copy string from program or variables or 10546 ; workspace to the workspace area. 10547 EX DE,HL ; end of string + 1 to HL 10548 DEC HL ; decrement HL to point to end of new area. 10549 LD (HL),ZX_NEWLINE ; insert a carriage return at end. 10550 ; ZX81 has a non-ASCII character set 10551 RES 7,(IY+FLAGS-RAMBASE) ; signal checking syntax. 10552 CALL CLASS_6 <#CLASS_6> ; evaluates string 10553 ; expression and checks for integer result. 10554 10555 CALL CHECK_2 <#CHECK_2> ; checks for carriage return. 10556 10557 10558 POP HL ; restore start of string in workspace. 10559 10560 LD (CH_ADD),HL ; set CH_ADD to the start of the string again. 10561 SET 7,(IY+FLAGS-RAMBASE) ; signal running program. 10562 CALL SCANNING <#SCANNING> ; evaluates the string 10563 ; in full leaving result on calculator stack. 10564 10565 POP HL ; restore saved character address in program. 10566 LD (CH_ADD),HL ; and reset the system variable CH_ADD. 10567 10568 JR STACK_POINTERS <#STACK_POINTERS> ; back to exit via STACK_POINTERS. 10569 ; resetting the calculator stack pointers 10570 ; HL and DE from STKEND as it wasn't possible 10571 ; to preserve them during this routine. 10572 10573 ------------------------------------------------------------------------ 10574 10575 ; Handle STR$ (2A) 10576 ------------------------------------------------------------------------ 10577 10578 ; This function returns a string representation of a numeric argument. 10579 ; The method used is to trick the PRINT_FP routine into thinking it 10580 ; is writing to a collapsed display file when in fact it is writing to 10581 ; string workspace. 10582 ; If there is already a newline at the intended print position and the 10583 ; column count has not been reduced to zero then the print routine 10584 ; assumes that there is only 1K of RAM and the screen memory, like the rest 10585 ; of dynamic memory, expands as necessary using calls to the ONE_SPACE 10586 ; routine. The screen is character-mapped not bit-mapped. 10587 10588 mark_1BD5: 10589 *str_dollar:* 10590 LD BC,1 ; create an initial byte in workspace 10591 RST _BC_SPACES ; using BC_SPACES restart. 10592 10593 LD (HL),ZX_NEWLINE ; place a carriage return there. 10594 10595 LD HL,(S_POSN) ; fetch value of S_POSN column/line 10596 PUSH HL ; and preserve on stack. 10597 10598 LD L,$FF ; make column value high to create a 10599 ; contrived buffer of length 254. 10600 LD (S_POSN),HL ; and store in system variable S_POSN. 10601 10602 LD HL,(DF_CC) ; fetch value of DF_CC 10603 PUSH HL ; and preserve on stack also. 10604 10605 LD (DF_CC),DE ; now set DF_CC which normally addresses 10606 ; somewhere in the display file to the start 10607 ; of workspace. 10608 PUSH DE ; save the start of new string. 10609 10610 CALL PRINT_FP <#PRINT_FP> 10611 10612 POP DE ; retrieve start of string. 10613 10614 LD HL,(DF_CC) ; fetch end of string from DF_CC. 10615 AND A ; prepare for true subtraction. 10616 SBC HL,DE ; subtract to give length. 10617 10618 LD B,H ; and transfer to the BC 10619 LD C,L ; register. 10620 10621 POP HL ; restore original 10622 LD (DF_CC),HL ; DF_CC value 10623 10624 POP HL ; restore original 10625 LD (S_POSN),HL ; S_POSN values. 10626 10627 #if ORIGINAL 10628 #else 10629 str_STK: ; New entry-point to exploit similarities and save 3 bytes of code. 10630 #endif 10631 10632 CALL STK_STO_STR <#STK_STO_STR> ; stores the string 10633 ; descriptor on the calculator stack. 10634 10635 EX DE,HL ; HL = last value, DE = STKEND. 10636 RET ; return. 10637 10638 10639 ------------------------------------------------------------------------ 10640 10641 ; THE *'CODE'* FUNCTION 10642 ------------------------------------------------------------------------ 10643 10644 ; (offset $19: 'code') 10645 ; Returns the code of a character or first character of a string 10646 ; e.g. CODE "AARDVARK" = 38 (not 65 as the ZX81 does not have an ASCII 10647 ; character set). 10648 10649 10650 mark_1C06: 10651 *code:* 10652 CALL STK_FETCH <#STK_FETCH> ; fetch and delete the string parameters. 10653 ; DE points to the start, BC holds the length. 10654 LD A,B ; test length 10655 OR C ; of the string. 10656 JR Z,STK_CODE <#STK_CODE> ; skip with zero if the null string. 10657 10658 LD A,(DE) ; else fetch the first character. 10659 10660 mark_1C0E: 10661 *STK_CODE:* 10662 JP STACK_A <#STACK_A> ; jump back (with memory check) 10663 10664 ------------------------------------------------------------------------ 10665 10666 ; THE *'LEN'* SUBROUTINE 10667 ------------------------------------------------------------------------ 10668 10669 ; (offset $1b: 'len') 10670 ; Returns the length of a string. 10671 ; In Sinclair BASIC strings can be more than twenty thousand characters long 10672 ; so a sixteen-bit register is required to store the length 10673 10674 mark_1C11: 10675 *len:* 10676 CALL STK_FETCH <#STK_FETCH> ; fetch and delete the 10677 ; string parameters from the calculator stack. 10678 ; register BC now holds the length of string. 10679 10680 JP STACK_BC <#STACK_BC> ; jump back to save result on the 10681 ; calculator stack (with memory check). 10682 10683 ------------------------------------------------------------------------ 10684 10685 ; THE *'DECREASE THE COUNTER'* SUBROUTINE 10686 ------------------------------------------------------------------------ 10687 10688 ; (offset $31: 'dec_jr_nz') 10689 ; The calculator has an instruction that decrements a single-byte 10690 ; pseudo-register and makes consequential relative jumps just like 10691 ; the Z80's DJNZ instruction. 10692 10693 mark_1C17: 10694 *dec_jr_nz:* 10695 EXX ; switch in set that addresses code 10696 10697 PUSH HL ; save pointer to offset byte 10698 LD HL,BERG ; address BERG in system variables 10699 DEC (HL) ; decrement it 10700 POP HL ; restore pointer 10701 10702 JR NZ,JUMP_2 <#JUMP_2> ; to JUMP_2 if not zero 10703 10704 INC HL ; step past the jump length. 10705 EXX ; switch in the main set. 10706 RET ; return. 10707 10708 ; Note. as a general rule the calculator avoids using the IY register 10709 ; otherwise the cumbersome 4 instructions in the middle could be replaced by 10710 ; dec (iy+$xx) - using three instruction bytes instead of six. 10711 10712 10713 ------------------------------------------------------------------------ 10714 10715 ; THE *'JUMP'* SUBROUTINE 10716 ------------------------------------------------------------------------ 10717 10718 ; (Offset $2F; 'jump') 10719 ; This enables the calculator to perform relative jumps just like 10720 ; the Z80 chip's JR instruction. 10721 ; This is one of the few routines to be polished for the ZX Spectrum. 10722 ; See, without looking at the ZX Spectrum ROM, if you can get rid of the 10723 ; relative jump. 10724 10725 mark_1C23: 10726 *jump:* 10727 EXX ;switch in pointer set 10728 *JUMP_2:* 10729 LD E,(HL) ; the jump byte 0-127 forward, 128-255 back. 10730 10731 #if ORIGINAL 10732 mark_1C24: 10733 XOR A ; clear accumulator. 10734 BIT 7,E ; test if negative jump 10735 JR Z,JUMP_3 <#JUMP_3> ; skip, if positive 10736 CPL ; else change to $FF. 10737 #else 10738 ; Note. Elegance from the ZX Spectrum. 10739 LD A,E ;+ 10740 RLA ;+ 10741 SBC A,A ;+ 10742 #endif 10743 10744 mark_1C2B: 10745 *JUMP_3:* 10746 LD D,A ; transfer to high byte. 10747 ADD HL,DE ; advance calculator pointer forward or back. 10748 10749 EXX ; switch out pointer set. 10750 RET ; return. 10751 10752 ------------------------------------------------------------------------ 10753 10754 ; THE *'JUMP ON TRUE'* SUBROUTINE 10755 ------------------------------------------------------------------------ 10756 10757 ; (Offset $00; 'jump_true') 10758 ; This enables the calculator to perform conditional relative jumps 10759 ; dependent on whether the last test gave a true result 10760 ; On the ZX81, the exponent will be zero for zero or else $81 for one. 10761 10762 mark_1C2F: 10763 *jump_true:* 10764 LD A,(DE) ; collect exponent byte 10765 10766 AND A ; is result 0 or 1 ? 10767 JR NZ,jump <#jump> ; back to JUMP if true (1). 10768 10769 EXX ; else switch in the pointer set. 10770 INC HL ; step past the jump length. 10771 EXX ; switch in the main set. 10772 RET ; return. 10773 10774 10775 ------------------------------------------------------------------------ 10776 10777 ; THE *'MODULUS'* SUBROUTINE 10778 ------------------------------------------------------------------------ 10779 10780 ; ( Offset $2E: 'n_mod_m' ) 10781 ; ( i1, i2 -- i3, i4 ) 10782 ; The subroutine calculate N mod M where M is the positive integer, the 10783 ; 'last value' on the calculator stack and N is the integer beneath. 10784 ; The subroutine returns the integer quotient as the last value and the 10785 ; remainder as the value beneath. 10786 ; e.g. 17 MOD 3 = 5 remainder 2 10787 ; It is invoked during the calculation of a random number and also by 10788 ; the PRINT_FP routine. 10789 10790 mark_1C37: 10791 *n_mod_m:* 10792 RST _FP_CALC ;; 17, 3. 10793 DEFB __st_mem_0 ;; 17, 3. 10794 DEFB __delete ;; 17. 10795 DEFB __duplicate ;; 17, 17. 10796 DEFB __get_mem_0 ;; 17, 17, 3. 10797 DEFB __division ;; 17, 17/3. 10798 DEFB __int ;; 17, 5. 10799 DEFB __get_mem_0 ;; 17, 5, 3. 10800 DEFB __exchange ;; 17, 3, 5. 10801 DEFB __st_mem_0 ;; 17, 3, 5. 10802 DEFB __multiply ;; 17, 15. 10803 DEFB __subtract ;; 2. 10804 DEFB __get_mem_0 ;; 2, 5. 10805 DEFB __end_calc ;; 2, 5. 10806 10807 RET ; return. 10808 10809 10810 ------------------------------------------------------------------------ 10811 10812 ; THE *'INTEGER'* FUNCTION 10813 ------------------------------------------------------------------------ 10814 10815 ; (offset $24: 'int') 10816 ; This function returns the integer of x, which is just the same as truncate 10817 ; for positive numbers. The truncate literal truncates negative numbers 10818 ; upwards so that -3.4 gives -3 whereas the BASIC INT function has to 10819 ; truncate negative numbers down so that INT -3.4 is 4. 10820 ; It is best to work through using, say, plus or minus 3.4 as examples. 10821 10822 mark_1C46: 10823 *int:* 10824 RST _FP_CALC ;; x. (= 3.4 or -3.4). 10825 DEFB __duplicate ;; x, x. 10826 DEFB __less_0 ;; x, (1/0) 10827 DEFB __jump_true ;; x, (1/0) 10828 DEFB int <#int> - $ ;; X_NEG 10829 10830 DEFB __truncate ;; trunc 3.4 = 3. 10831 DEFB __end_calc ;; 3. 10832 10833 RET ; return with + int x on stack. 10834 10835 10836 mark_1C4E: 10837 *X_NEG:* 10838 DEFB __duplicate ;; -3.4, -3.4. 10839 DEFB __truncate ;; -3.4, -3. 10840 DEFB __st_mem_0 ;; -3.4, -3. 10841 DEFB __subtract ;; -.4 10842 DEFB __get_mem_0 ;; -.4, -3. 10843 DEFB __exchange ;; -3, -.4. 10844 DEFB __not ;; -3, (0). 10845 DEFB __jump_true ;; -3. 10846 DEFB EXIT <#EXIT> - $ ;; -3. 10847 10848 DEFB __stk_one ;; -3, 1. 10849 DEFB __subtract ;; -4. 10850 10851 mark_1C59: 10852 *EXIT:* 10853 DEFB __end_calc ;; -4. 10854 10855 RET ; return. 10856 10857 10858 ------------------------------------------------------------------------ 10859 10860 ; Exponential (23) 10861 ------------------------------------------------------------------------ 10862 10863 ; 10864 ; 10865 10866 mark_1C5B: 10867 *exp:* 10868 RST _FP_CALC ;; 10869 DEFB __stk_data ;; 10870 DEFB $F1 ;;Exponent: $81, Bytes: 4 10871 DEFB $38,$AA,$3B,$29 ;; 10872 DEFB __multiply ;; 10873 DEFB __duplicate ;; 10874 DEFB __int ;; 10875 DEFB $C3 ;;st_mem_3 10876 DEFB __subtract ;; 10877 DEFB __duplicate ;; 10878 DEFB __addition ;; 10879 DEFB __stk_one ;; 10880 DEFB __subtract ;; 10881 DEFB __series_08 ;; 10882 DEFB $13 ;;Exponent: $63, Bytes: 1 10883 DEFB $36 ;;(+00,+00,+00) 10884 DEFB $58 ;;Exponent: $68, Bytes: 2 10885 DEFB $65,$66 ;;(+00,+00) 10886 DEFB $9D ;;Exponent: $6D, Bytes: 3 10887 DEFB $78,$65,$40 ;;(+00) 10888 DEFB $A2 ;;Exponent: $72, Bytes: 3 10889 DEFB $60,$32,$C9 ;;(+00) 10890 DEFB $E7 ;;Exponent: $77, Bytes: 4 10891 DEFB $21,$F7,$AF,$24 ;; 10892 DEFB $EB ;;Exponent: $7B, Bytes: 4 10893 DEFB $2F,$B0,$B0,$14 ;; 10894 DEFB $EE ;;Exponent: $7E, Bytes: 4 10895 DEFB $7E,$BB,$94,$58 ;; 10896 DEFB $F1 ;;Exponent: $81, Bytes: 4 10897 DEFB $3A,$7E,$F8,$CF ;; 10898 DEFB $E3 ;;get_mem_3 10899 DEFB __end_calc ;; 10900 10901 CALL FP_TO_A <#FP_TO_A> 10902 JR NZ,N_NEGTV <#N_NEGTV> 10903 10904 JR C,REPORT_6b <#REPORT_6b> 10905 10906 ADD A,(HL) ; 10907 JR NC,RESULT_OK <#RESULT_OK> 10908 10909 10910 mark_1C99: 10911 *REPORT_6b:* 10912 RST _ERROR_1 10913 DEFB $05 ; Error Report: Number too big 10914 10915 mark_1C9B: 10916 *N_NEGTV:* 10917 JR C,RESULT_ZERO <#RESULT_ZERO> 10918 10919 SUB (HL) ; 10920 JR NC,RESULT_ZERO <#RESULT_ZERO> 10921 10922 NEG ; Negate 10923 10924 mark_1CA2: 10925 *RESULT_OK:* 10926 LD (HL),A ; 10927 RET ; return. 10928 10929 10930 mark_1CA4: 10931 *RESULT_ZERO:* 10932 RST _FP_CALC ;; 10933 DEFB __delete ;; 10934 DEFB __stk_zero ;; 10935 DEFB __end_calc ;; 10936 10937 RET ; return. 10938 10939 10940 ------------------------------------------------------------------------ 10941 10942 ; THE *'NATURAL LOGARITHM'* FUNCTION 10943 ------------------------------------------------------------------------ 10944 10945 ; (offset $22: 'ln') 10946 ; Like the ZX81 itself, 'natural' logarithms came from Scotland. 10947 ; They were devised in 1614 by well-traveled Scotsman John Napier who noted 10948 ; "Nothing doth more molest and hinder calculators than the multiplications, 10949 ; divisions, square and cubical extractions of great numbers". 10950 ; 10951 ; Napier's logarithms enabled the above operations to be accomplished by 10952 ; simple addition and subtraction simplifying the navigational and 10953 ; astronomical calculations which beset his age. 10954 ; Napier's logarithms were quickly overtaken by logarithms to the base 10 10955 ; devised, in conjunction with Napier, by Henry Briggs a Cambridge-educated 10956 ; professor of Geometry at Oxford University. These simplified the layout 10957 ; of the tables enabling humans to easily scale calculations. 10958 ; 10959 ; It is only recently with the introduction of pocket calculators and 10960 ; computers like the ZX81 that natural logarithms are once more at the fore, 10961 ; although some computers retain logarithms to the base ten. 10962 ; 'Natural' logarithms are powers to the base 'e', which like 'pi' is a 10963 ; naturally occurring number in branches of mathematics. 10964 ; Like 'pi' also, 'e' is an irrational number and starts 2.718281828... 10965 ; 10966 ; The tabular use of logarithms was that to multiply two numbers one looked 10967 ; up their two logarithms in the tables, added them together and then looked 10968 ; for the result in a table of antilogarithms to give the desired product. 10969 ; 10970 ; The EXP function is the BASIC equivalent of a calculator's 'antiln' function 10971 ; and by picking any two numbers, 1.72 and 6.89 say, 10972 ; 10 PRINT EXP ( LN 1.72 + LN 6.89 ) 10973 ; will give just the same result as 10974 ; 20 PRINT 1.72 * 6.89. 10975 ; Division is accomplished by subtracting the two logs. 10976 ; 10977 ; Napier also mentioned "square and cubicle extractions". 10978 ; To raise a number to the power 3, find its 'ln', multiply by 3 and find the 10979 ; 'antiln'. e.g. PRINT EXP( LN 4 * 3 ) gives 64. 10980 ; Similarly to find the n'th root divide the logarithm by 'n'. 10981 ; The ZX81 ROM used PRINT EXP ( LN 9 / 2 ) to find the square root of the 10982 ; number 9. The Napieran square root function is just a special case of 10983 ; the 'to_power' function. A cube root or indeed any root/power would be just 10984 ; as simple. 10985 10986 ; First test that the argument to LN is a positive, non-zero number. 10987 10988 mark_1CA9: 10989 *ln:* 10990 RST _FP_CALC ;; 10991 DEFB __duplicate ;; 10992 DEFB __greater_0 ;; 10993 DEFB __jump_true ;; 10994 DEFB VALID - $ ;;to VALID <#VALID> 10995 10996 DEFB __end_calc ;; 10997 10998 10999 mark_1CAF: 11000 *REPORT_Ab:* 11001 RST _ERROR_1 11002 DEFB $09 ; Error Report: Invalid argument 11003 11004 *VALID:* 11005 #if ORIGINAL 11006 mark_1CB1: 11007 DEFB __stk_zero ;; Note. not necessary. 11008 DEFB __delete ;; 11009 #endif 11010 DEFB __end_calc ;; 11011 LD A,(HL) ; 11012 11013 LD (HL),$80 ; 11014 CALL STACK_A <#STACK_A> 11015 11016 RST _FP_CALC ;; 11017 DEFB __stk_data ;; 11018 DEFB $38 ;;Exponent: $88, Bytes: 1 11019 DEFB $00 ;;(+00,+00,+00) 11020 DEFB __subtract ;; 11021 DEFB __exchange ;; 11022 DEFB __duplicate ;; 11023 DEFB __stk_data ;; 11024 DEFB $F0 ;;Exponent: $80, Bytes: 4 11025 DEFB $4C,$CC,$CC,$CD ;; 11026 DEFB __subtract ;; 11027 DEFB __greater_0 ;; 11028 DEFB __jump_true ;; 11029 DEFB GRE_8 <#GRE_8> - $ ;; 11030 11031 DEFB __exchange ;; 11032 DEFB __stk_one ;; 11033 DEFB __subtract ;; 11034 DEFB __exchange ;; 11035 DEFB __end_calc ;; 11036 11037 INC (HL) ; 11038 11039 RST _FP_CALC ;; 11040 11041 mark_1CD2: 11042 *GRE_8:* 11043 DEFB __exchange ;; 11044 DEFB __stk_data ;; 11045 DEFB $F0 ;;Exponent: $80, Bytes: 4 11046 DEFB $31,$72,$17,$F8 ;; 11047 DEFB __multiply ;; 11048 DEFB __exchange ;; 11049 DEFB __stk_half ;; 11050 DEFB __subtract ;; 11051 DEFB __stk_half ;; 11052 DEFB __subtract ;; 11053 DEFB __duplicate ;; 11054 DEFB __stk_data ;; 11055 DEFB $32 ;;Exponent: $82, Bytes: 1 11056 DEFB $20 ;;(+00,+00,+00) 11057 DEFB __multiply ;; 11058 DEFB __stk_half ;; 11059 DEFB __subtract ;; 11060 DEFB __series_0C ;; 11061 DEFB $11 ;;Exponent: $61, Bytes: 1 11062 DEFB $AC ;;(+00,+00,+00) 11063 DEFB $14 ;;Exponent: $64, Bytes: 1 11064 DEFB $09 ;;(+00,+00,+00) 11065 DEFB $56 ;;Exponent: $66, Bytes: 2 11066 DEFB $DA,$A5 ;;(+00,+00) 11067 DEFB $59 ;;Exponent: $69, Bytes: 2 11068 DEFB $30,$C5 ;;(+00,+00) 11069 DEFB $5C ;;Exponent: $6C, Bytes: 2 11070 DEFB $90,$AA ;;(+00,+00) 11071 DEFB $9E ;;Exponent: $6E, Bytes: 3 11072 DEFB $70,$6F,$61 ;;(+00) 11073 DEFB $A1 ;;Exponent: $71, Bytes: 3 11074 DEFB $CB,$DA,$96 ;;(+00) 11075 DEFB $A4 ;;Exponent: $74, Bytes: 3 11076 DEFB $31,$9F,$B4 ;;(+00) 11077 DEFB $E7 ;;Exponent: $77, Bytes: 4 11078 DEFB $A0,$FE,$5C,$FC ;; 11079 DEFB $EA ;;Exponent: $7A, Bytes: 4 11080 DEFB $1B,$43,$CA,$36 ;; 11081 DEFB $ED ;;Exponent: $7D, Bytes: 4 11082 DEFB $A7,$9C,$7E,$5E ;; 11083 DEFB $F0 ;;Exponent: $80, Bytes: 4 11084 DEFB $6E,$23,$80,$93 ;; 11085 DEFB __multiply ;; 11086 DEFB __addition ;; 11087 DEFB __end_calc ;; 11088 11089 RET ; return. 11090 ------------------------------------------------------------------------ 11091 11092 #if ORIGINAL 11093 #else 11094 ; ------------------------------ 11095 ; THE NEW *'SQUARE ROOT'* FUNCTION 11096 ; ------------------------------ 11097 ; (Offset $25: 'sqr') 11098 ; "If I have seen further, it is by standing on the shoulders of giants" - 11099 ; Sir Isaac Newton, Cambridge 1676. 11100 ; The sqr function has been re-written to use the Newton-Raphson method. 11101 ; Joseph Raphson was a student of Sir Isaac Newton at Cambridge University 11102 ; and helped publicize his work. 11103 ; Although Newton's method is centuries old, this routine, appropriately, is 11104 ; based on a FORTH word written by Steven Vickers in the Jupiter Ace manual. 11105 ; Whereas that method uses an initial guess of one, this one manipulates 11106 ; the exponent byte to obtain a better starting guess. 11107 ; First test for zero and return zero, if so, as the result. 11108 ; If the argument is negative, then produce an error. 11109 ; 11110 *sqr* RST _FP_CALC ;; x 11111 DEFB __st_mem_3 ;; x. (seed for guess) 11112 DEFB __end_calc ;; x. 11113 11114 ; HL now points to exponent of argument on calculator stack. 11115 11116 LD A,(HL) ; Test for zero argument 11117 AND A ; 11118 11119 RET Z ; Return with zero on the calculator stack. 11120 11121 ; Test for a positive argument 11122 11123 INC HL ; Address byte with sign bit. 11124 BIT 7,(HL) ; Test the bit. 11125 11126 JR NZ,REPORT_Ab <#REPORT_Ab> ; back to REPORT_A 11127 ; 'Invalid argument' 11128 11129 ; This guess is based on a Usenet discussion. 11130 ; Halve the exponent to achieve a good guess.(accurate with .25 16 64 etc.) 11131 11132 LD HL,$4071 ; Address first byte of mem-3 11133 11134 LD A,(HL) ; fetch exponent of mem-3 11135 XOR $80 ; toggle sign of exponent of mem-3 11136 SRA A ; shift right, bit 7 unchanged. 11137 INC A ; 11138 JR Z,ASIS <#ASIS> ; forward with say .25 -> .5 11139 JP P,ASIS <#ASIS> ; leave increment if value > .5 11140 DEC A ; restore to shift only. 11141 *ASIS* XOR $80 ; restore sign. 11142 LD (HL),A ; and put back 'halved' exponent. 11143 11144 ; Now re-enter the calculator. 11145 11146 RST 28H ;; FP-CALC x 11147 11148 *SLOOP* DEFB __duplicate ;; x,x. 11149 DEFB __get_mem_3 ;; x,x,guess 11150 DEFB __st_mem_4 ;; x,x,guess 11151 DEFB __division ;; x,x/guess. 11152 DEFB __get_mem_3 ;; x,x/guess,guess 11153 DEFB __addition ;; x,x/guess+guess 11154 DEFB __stk_half ;; x,x/guess+guess,.5 11155 DEFB __multiply ;; x,(x/guess+guess)*.5 11156 DEFB __st_mem_3 ;; x,newguess 11157 DEFB __get_mem_4 ;; x,newguess,oldguess 11158 DEFB __subtract ;; x,newguess-oldguess 11159 DEFB __abs ;; x,difference. 11160 DEFB __greater_0 ;; x,(0/1). 11161 DEFB __jump_true ;; x. 11162 11163 DEFB SLOOP <#SLOOP> - $ ;; x. 11164 11165 DEFB __delete ;; . 11166 DEFB __get_mem_3 ;; retrieve final guess. 11167 DEFB __end_calc ;; sqr x. 11168 11169 RET ; return with square root on stack 11170 11171 ; or in ZX81 BASIC 11172 ; 11173 ; 5 PRINT "NEWTON RAPHSON SQUARE ROOTS" 11174 ; 10 INPUT "NUMBER ";N 11175 ; 20 INPUT "GUESS ";G 11176 ; 30 PRINT " NUMBER "; N ;" GUESS "; G 11177 ; 40 FOR I = 1 TO 10 11178 ; 50 LET B = N/G 11179 ; 60 LET C = B+G 11180 ; 70 LET G = C/2 11181 ; 80 PRINT I; " VALUE "; G 11182 ; 90 NEXT I 11183 ; 100 PRINT "NAPIER METHOD"; SQR N 11184 #endif 11185 11186 ------------------------------------------------------------------------ 11187 11188 ; THE *'TRIGONOMETRIC'* FUNCTIONS 11189 ------------------------------------------------------------------------ 11190 11191 ; Trigonometry is rocket science. It is also used by carpenters and pyramid 11192 ; builders. 11193 ; Some uses can be quite abstract but the principles can be seen in simple 11194 ; right-angled triangles. Triangles have some special properties - 11195 ; 11196 ; 1) The sum of the three angles is always PI radians (180 degrees). 11197 ; Very helpful if you know two angles and wish to find the third. 11198 ; 2) In any right-angled triangle the sum of the squares of the two shorter 11199 ; sides is equal to the square of the longest side opposite the right-angle. 11200 ; Very useful if you know the length of two sides and wish to know the 11201 ; length of the third side. 11202 ; 3) Functions sine, cosine and tangent enable one to calculate the length 11203 ; of an unknown side when the length of one other side and an angle is 11204 ; known. 11205 ; 4) Functions arcsin, arccosine and arctan enable one to calculate an unknown 11206 ; angle when the length of two of the sides is known. 11207 11208 ------------------------------------------------------------------------ 11209 11210 ; THE *'REDUCE ARGUMENT'* SUBROUTINE 11211 ------------------------------------------------------------------------ 11212 11213 ; (offset $35: 'get_argt') 11214 ; 11215 ; This routine performs two functions on the angle, in radians, that forms 11216 ; the argument to the sine and cosine functions. 11217 ; First it ensures that the angle 'wraps round'. That if a ship turns through 11218 ; an angle of, say, 3*PI radians (540 degrees) then the net effect is to turn 11219 ; through an angle of PI radians (180 degrees). 11220 ; Secondly it converts the angle in radians to a fraction of a right angle, 11221 ; depending within which quadrant the angle lies, with the periodicity 11222 ; resembling that of the desired sine value. 11223 ; The result lies in the range -1 to +1. 11224 ; 11225 ; 90 deg. 11226 ; 11227 ; (pi/2) 11228 ; II +1 I 11229 ; | 11230 ; sin+ |\ | /| sin+ 11231 ; cos- | \ | / | cos+ 11232 ; tan- | \ | / | tan+ 11233 ; | \|/) | 11234 ; 180 deg. (pi) 0 |----+----|-- 0 (0) 0 degrees 11235 ; | /|\ | 11236 ; sin- | / | \ | sin- 11237 ; cos- | / | \ | cos+ 11238 ; tan+ |/ | \| tan- 11239 ; | 11240 ; III -1 IV 11241 ; (3pi/2) 11242 ; 11243 ; 270 deg. 11244 11245 mark_1D18: 11246 *get_argt:* 11247 RST _FP_CALC ;; X. 11248 DEFB __stk_data ;; 11249 DEFB $EE ;;Exponent: $7E, 11250 ;;Bytes: 4 11251 DEFB $22,$F9,$83,$6E ;; X, 1/(2*PI) 11252 DEFB __multiply ;; X/(2*PI) = fraction 11253 11254 DEFB __duplicate ;; 11255 DEFB __stk_half ;; 11256 DEFB __addition ;; 11257 DEFB __int ;; 11258 11259 DEFB __subtract ;; now range -.5 to .5 11260 11261 DEFB __duplicate ;; 11262 DEFB __addition ;; now range -1 to 1. 11263 DEFB __duplicate ;; 11264 DEFB __addition ;; now range -2 to 2. 11265 11266 ; quadrant I (0 to +1) and quadrant IV (-1 to 0) are now correct. 11267 ; quadrant II ranges +1 to +2. 11268 ; quadrant III ranges -2 to -1. 11269 11270 DEFB __duplicate ;; Y, Y. 11271 DEFB __abs ;; Y, abs(Y). range 1 to 2 11272 DEFB __stk_one ;; Y, abs(Y), 1. 11273 DEFB __subtract ;; Y, abs(Y)-1. range 0 to 1 11274 DEFB __duplicate ;; Y, Z, Z. 11275 DEFB __greater_0 ;; Y, Z, (1/0). 11276 11277 DEFB __st_mem_0 ;; store as possible sign 11278 ;; for cosine function. 11279 11280 DEFB __jump_true ;; 11281 DEFB Z_PLUS <#Z_PLUS> - $ ;; with quadrants II and III 11282 11283 ; else the angle lies in quadrant I or IV and value Y is already correct. 11284 11285 DEFB __delete ;; Y delete test value. 11286 DEFB __end_calc ;; Y. 11287 11288 RET ; return. with Q1 and Q4 >>> 11289 11290 ; The branch was here with quadrants II (0 to 1) and III (1 to 0). 11291 ; Y will hold -2 to -1 if this is quadrant III. 11292 11293 mark_1D35: 11294 *Z_PLUS:* 11295 DEFB __stk_one ;; Y, Z, 1 11296 DEFB __subtract ;; Y, Z-1. Q3 = 0 to -1 11297 DEFB __exchange ;; Z-1, Y. 11298 DEFB __less_0 ;; Z-1, (1/0). 11299 DEFB __jump_true ;; Z-1. 11300 DEFB YNEG <#YNEG> - $ ;; 11301 ;;if angle in quadrant III 11302 11303 ; else angle is within quadrant II (-1 to 0) 11304 11305 DEFB __negate ; range +1 to 0 11306 11307 11308 mark_1D3C: 11309 *YNEG:* 11310 DEFB __end_calc ;; quadrants II and III correct. 11311 11312 RET ; return. 11313 11314 11315 ------------------------------------------------------------------------ 11316 11317 ; THE *'COSINE'* FUNCTION 11318 ------------------------------------------------------------------------ 11319 11320 ; (offset $1D: 'cos') 11321 ; Cosines are calculated as the sine of the opposite angle rectifying the 11322 ; sign depending on the quadrant rules. 11323 ; 11324 ; 11325 ; /| 11326 ; h /y| 11327 ; / |o 11328 ; / x | 11329 ; /----| 11330 ; a 11331 ; 11332 ; The cosine of angle x is the adjacent side (a) divided by the hypotenuse 1. 11333 ; However if we examine angle y then a/h is the sine of that angle. 11334 ; Since angle x plus angle y equals a right-angle, we can find angle y by 11335 ; subtracting angle x from pi/2. 11336 ; However it's just as easy to reduce the argument first and subtract the 11337 ; reduced argument from the value 1 (a reduced right-angle). 11338 ; It's even easier to subtract 1 from the angle and rectify the sign. 11339 ; In fact, after reducing the argument, the absolute value of the argument 11340 ; is used and rectified using the test result stored in mem-0 by 'get-argt' 11341 ; for that purpose. 11342 11343 mark_1D3E: 11344 *cos:* 11345 RST _FP_CALC ;; angle in radians. 11346 DEFB __get_argt ;; X reduce -1 to +1 11347 11348 DEFB __abs ;; ABS X 0 to 1 11349 DEFB __stk_one ;; ABS X, 1. 11350 DEFB __subtract ;; now opposite angle 11351 ;; though negative sign. 11352 DEFB __get_mem_0 ;; fetch sign indicator. 11353 DEFB __jump_true ;; 11354 DEFB C_ENT <#C_ENT> - $ ;;fwd to C_ENT 11355 ;;forward to common code if in QII or QIII 11356 11357 11358 DEFB __negate ;; else make positive. 11359 DEFB __jump ;; 11360 DEFB C_ENT <#C_ENT> - $ ;;fwd to C_ENT 11361 ;;with quadrants QI and QIV 11362 11363 ------------------------------------------------------------------------ 11364 11365 ; THE *'SINE'* FUNCTION 11366 ------------------------------------------------------------------------ 11367 11368 ; (offset $1C: 'sin') 11369 ; This is a fundamental transcendental function from which others such as cos 11370 ; and tan are directly, or indirectly, derived. 11371 ; It uses the series generator to produce Chebyshev polynomials. 11372 ; 11373 ; 11374 ; /| 11375 ; 1 / | 11376 ; / |x 11377 ; /a | 11378 ; /----| 11379 ; y 11380 ; 11381 ; The 'get-argt' function is designed to modify the angle and its sign 11382 ; in line with the desired sine value and afterwards it can launch straight 11383 ; into common code. 11384 11385 mark_1D49: 11386 *sin:* 11387 RST _FP_CALC ;; angle in radians 11388 DEFB __get_argt ;; reduce - sign now correct. 11389 11390 mark_1D4B: 11391 *C_ENT:* 11392 DEFB __duplicate ;; 11393 DEFB __duplicate ;; 11394 DEFB __multiply ;; 11395 DEFB __duplicate ;; 11396 DEFB __addition ;; 11397 DEFB __stk_one ;; 11398 DEFB __subtract ;; 11399 11400 DEFB __series_06 ;; 11401 DEFB $14 ;;Exponent: $64, Bytes: 1 11402 DEFB $E6 ;;(+00,+00,+00) 11403 DEFB $5C ;;Exponent: $6C, Bytes: 2 11404 DEFB $1F,$0B ;;(+00,+00) 11405 DEFB $A3 ;;Exponent: $73, Bytes: 3 11406 DEFB $8F,$38,$EE ;;(+00) 11407 DEFB $E9 ;;Exponent: $79, Bytes: 4 11408 DEFB $15,$63,$BB,$23 ;; 11409 DEFB $EE ;;Exponent: $7E, Bytes: 4 11410 DEFB $92,$0D,$CD,$ED ;; 11411 DEFB $F1 ;;Exponent: $81, Bytes: 4 11412 DEFB $23,$5D,$1B,$EA ;; 11413 11414 DEFB __multiply ;; 11415 DEFB __end_calc ;; 11416 11417 RET ; return. 11418 11419 11420 ------------------------------------------------------------------------ 11421 11422 ; THE *'TANGENT'* FUNCTION 11423 ------------------------------------------------------------------------ 11424 11425 ; (offset $1E: 'tan') 11426 ; 11427 ; Evaluates tangent x as sin(x) / cos(x). 11428 ; 11429 ; 11430 ; /| 11431 ; h / | 11432 ; / |o 11433 ; /x | 11434 ; /----| 11435 ; a 11436 ; 11437 ; The tangent of angle x is the ratio of the length of the opposite side 11438 ; divided by the length of the adjacent side. As the opposite length can 11439 ; be calculates using sin(x) and the adjacent length using cos(x) then 11440 ; the tangent can be defined in terms of the previous two functions. 11441 11442 ; Error 6 if the argument, in radians, is too close to one like pi/2 11443 ; which has an infinite tangent. e.g. PRINT TAN (PI/2) evaluates as 1/0. 11444 ; Similarly PRINT TAN (3*PI/2), TAN (5*PI/2) etc. 11445 11446 mark_1D6E: 11447 *tan:* 11448 RST _FP_CALC ;; x. 11449 DEFB __duplicate ;; x, x. 11450 DEFB __sin ;; x, sin x. 11451 DEFB __exchange ;; sin x, x. 11452 DEFB __cos ;; sin x, cos x. 11453 DEFB __division ;; sin x/cos x (= tan x). 11454 DEFB __end_calc ;; tan x. 11455 11456 RET ; return. 11457 11458 ------------------------------------------------------------------------ 11459 11460 ; THE *'ARCTAN'* FUNCTION 11461 ------------------------------------------------------------------------ 11462 11463 ; (Offset $21: 'atn') 11464 ; The inverse tangent function with the result in radians. 11465 ; This is a fundamental transcendental function from which others such as 11466 ; asn and acs are directly, or indirectly, derived. 11467 ; It uses the series generator to produce Chebyshev polynomials. 11468 11469 mark_1D76: 11470 *atn:* 11471 LD A,(HL) ; fetch exponent 11472 CP $81 ; compare to that for 'one' 11473 JR C,SMALL <#SMALL> ; forward, if less 11474 11475 RST _FP_CALC ;; X. 11476 DEFB __stk_one ;; 11477 DEFB __negate ;; 11478 DEFB __exchange ;; 11479 DEFB __division ;; 11480 DEFB __duplicate ;; 11481 DEFB __less_0 ;; 11482 DEFB __stk_half_pi ;; 11483 DEFB __exchange ;; 11484 DEFB __jump_true ;; 11485 DEFB CASES <#CASES> - $ ;; 11486 11487 DEFB __negate ;; 11488 DEFB __jump ;; 11489 DEFB CASES <#CASES> - $ ;; 11490 11491 ; ___ 11492 11493 mark_1D89: 11494 *SMALL:* 11495 RST _FP_CALC ;; 11496 DEFB __stk_zero ;; 11497 11498 mark_1D8B: 11499 *CASES:* 11500 DEFB __exchange ;; 11501 DEFB __duplicate ;; 11502 DEFB __duplicate ;; 11503 DEFB __multiply ;; 11504 DEFB __duplicate ;; 11505 DEFB __addition ;; 11506 DEFB __stk_one ;; 11507 DEFB __subtract ;; 11508 11509 DEFB __series_0C ;; 11510 DEFB $10 ;;Exponent: $60, Bytes: 1 11511 DEFB $B2 ;;(+00,+00,+00) 11512 DEFB $13 ;;Exponent: $63, Bytes: 1 11513 DEFB $0E ;;(+00,+00,+00) 11514 DEFB $55 ;;Exponent: $65, Bytes: 2 11515 DEFB $E4,$8D ;;(+00,+00) 11516 DEFB $58 ;;Exponent: $68, Bytes: 2 11517 DEFB $39,$BC ;;(+00,+00) 11518 DEFB $5B ;;Exponent: $6B, Bytes: 2 11519 DEFB $98,$FD ;;(+00,+00) 11520 DEFB $9E ;;Exponent: $6E, Bytes: 3 11521 DEFB $00,$36,$75 ;;(+00) 11522 DEFB $A0 ;;Exponent: $70, Bytes: 3 11523 DEFB $DB,$E8,$B4 ;;(+00) 11524 DEFB $63 ;;Exponent: $73, Bytes: 2 11525 DEFB $42,$C4 ;;(+00,+00) 11526 DEFB $E6 ;;Exponent: $76, Bytes: 4 11527 DEFB $B5,$09,$36,$BE ;; 11528 DEFB $E9 ;;Exponent: $79, Bytes: 4 11529 DEFB $36,$73,$1B,$5D ;; 11530 DEFB $EC ;;Exponent: $7C, Bytes: 4 11531 DEFB $D8,$DE,$63,$BE ;; 11532 DEFB $F0 ;;Exponent: $80, Bytes: 4 11533 DEFB $61,$A1,$B3,$0C ;; 11534 11535 DEFB __multiply ;; 11536 DEFB __addition ;; 11537 DEFB __end_calc ;; 11538 11539 RET ; return. 11540 11541 11542 ------------------------------------------------------------------------ 11543 11544 ; THE *'ARCSIN'* FUNCTION 11545 ------------------------------------------------------------------------ 11546 11547 ; (Offset $1F: 'asn') 11548 ; The inverse sine function with result in radians. 11549 ; Derived from arctan function above. 11550 ; Error A unless the argument is between -1 and +1 inclusive. 11551 ; Uses an adaptation of the formula asn(x) = atn(x/sqr(1-x*x)) 11552 ; 11553 ; 11554 ; /| 11555 ; / | 11556 ; 1/ |x 11557 ; /a | 11558 ; /----| 11559 ; y 11560 ; 11561 ; e.g. We know the opposite side (x) and hypotenuse (1) 11562 ; and we wish to find angle a in radians. 11563 ; We can derive length y by Pythagoras and then use ATN instead. 11564 ; Since y*y + x*x = 1*1 (Pythagoras Theorem) then 11565 ; y=sqr(1-x*x) - no need to multiply 1 by itself. 11566 ; So, asn(a) = atn(x/y) 11567 ; or more fully, 11568 ; asn(a) = atn(x/sqr(1-x*x)) 11569 11570 ; Close but no cigar. 11571 11572 ; While PRINT ATN (x/SQR (1-x*x)) gives the same results as PRINT ASN x, 11573 ; it leads to division by zero when x is 1 or -1. 11574 ; To overcome this, 1 is added to y giving half the required angle and the 11575 ; result is then doubled. 11576 ; That is, PRINT ATN (x/(SQR (1-x*x) +1)) *2 11577 ; 11578 ; 11579 ; . /| 11580 ; . c/ | 11581 ; . /1 |x 11582 ; . c b /a | 11583 ; ---------/----| 11584 ; 1 y 11585 ; 11586 ; By creating an isosceles triangle with two equal sides of 1, angles c and 11587 ; c are also equal. If b+c+d = 180 degrees and b+a = 180 degrees then c=a/2. 11588 ; 11589 ; A value higher than 1 gives the required error as attempting to find the 11590 ; square root of a negative number generates an error in Sinclair BASIC. 11591 11592 mark_1DC4: 11593 *asn:* 11594 RST _FP_CALC ;; x. 11595 DEFB __duplicate ;; x, x. 11596 DEFB __duplicate ;; x, x, x. 11597 DEFB __multiply ;; x, x*x. 11598 DEFB __stk_one ;; x, x*x, 1. 11599 DEFB __subtract ;; x, x*x-1. 11600 DEFB __negate ;; x, 1-x*x. 11601 DEFB __sqr ;; x, sqr(1-x*x) = y. 11602 DEFB __stk_one ;; x, y, 1. 11603 DEFB __addition ;; x, y+1. 11604 DEFB __division ;; x/y+1. 11605 DEFB __atn ;; a/2 (half the angle) 11606 DEFB __duplicate ;; a/2, a/2. 11607 DEFB __addition ;; a. 11608 DEFB __end_calc ;; a. 11609 11610 RET ; return. 11611 11612 11613 ------------------------------------------------------------------------ 11614 11615 ; THE *'ARCCOS'* FUNCTION 11616 ------------------------------------------------------------------------ 11617 11618 ; (Offset $20: 'acs') 11619 ; The inverse cosine function with the result in radians. 11620 ; Error A unless the argument is between -1 and +1. 11621 ; Result in range 0 to pi. 11622 ; Derived from asn above which is in turn derived from the preceding atn. It 11623 ; could have been derived directly from atn using acs(x) = atn(sqr(1-x*x)/x). 11624 ; However, as sine and cosine are horizontal translations of each other, 11625 ; uses acs(x) = pi/2 - asn(x) 11626 11627 ; e.g. the arccosine of a known x value will give the required angle b in 11628 ; radians. 11629 ; We know, from above, how to calculate the angle a using asn(x). 11630 ; Since the three angles of any triangle add up to 180 degrees, or pi radians, 11631 ; and the largest angle in this case is a right-angle (pi/2 radians), then 11632 ; we can calculate angle b as pi/2 (both angles) minus asn(x) (angle a). 11633 ; 11634 ;; 11635 ; /| 11636 ; 1 /b| 11637 ; / |x 11638 ; /a | 11639 ; /----| 11640 ; y 11641 11642 mark_1DD4: 11643 *acs:* 11644 RST _FP_CALC ;; x. 11645 DEFB __asn ;; asn(x). 11646 DEFB __stk_half_pi ;; asn(x), pi/2. 11647 DEFB __subtract ;; asn(x) - pi/2. 11648 DEFB __negate ;; pi/2 - asn(x) = acs(x). 11649 DEFB __end_calc ;; acs(x) 11650 11651 RET ; return. 11652 11653 #if ORIGINAL 11654 ------------------------------------------------------------------------ 11655 11656 ; THE *'SQUARE ROOT'* FUNCTION 11657 ------------------------------------------------------------------------ 11658 11659 ; (Offset $25: 'sqr') 11660 ; Error A if argument is negative. 11661 ; This routine is remarkable for its brevity - 7 bytes. 11662 ; 11663 ; The ZX81 code was originally 9K and various techniques had to be 11664 ; used to shoe-horn it into an 8K Rom chip. 11665 11666 ; This routine uses Napier's method for calculating square roots which was 11667 ; devised in 1614 and calculates the value as EXP (LN 'x' * 0.5). 11668 ; 11669 ; This is a little on the slow side as it involves two polynomial series. 11670 ; A series of 12 for LN and a series of 8 for EXP. 11671 ; This was of no concern to John Napier since his tables were 'compiled forever'. 11672 11673 mark_1DDB: 11674 *sqr:* 11675 RST _FP_CALC ;; x. 11676 DEFB __duplicate ;; x, x. 11677 DEFB __not ;; x, 1/0 11678 DEFB __jump_true ;; x, (1/0). 11679 DEFB LAST <#LAST> - $ ;; exit if argument zero 11680 ;; with zero result. 11681 11682 ; else continue to calculate as x ** .5 11683 11684 DEFB __stk_half ;; x, .5. 11685 DEFB __end_calc ;; x, .5. 11686 11687 #endif 11688 11689 ------------------------------------------------------------------------ 11690 11691 ; THE *'EXPONENTIATION'* OPERATION 11692 ------------------------------------------------------------------------ 11693 11694 ; (Offset $06: 'to_power') 11695 ; This raises the first number X to the power of the second number Y. 11696 ; As with the ZX80, 11697 ; 0 ** 0 = 1 11698 ; 0 ** +n = 0 11699 ; 0 ** -n = arithmetic overflow. 11700 11701 mark_1DE2: 11702 *to_power:* 11703 RST _FP_CALC ;; X,Y. 11704 DEFB __exchange ;; Y,X. 11705 DEFB __duplicate ;; Y,X,X. 11706 DEFB __not ;; Y,X,(1/0). 11707 DEFB __jump_true ;; 11708 DEFB XISO <#XISO> - $ ;;forward to XISO if X is zero. 11709 11710 ; else X is non-zero. function 'ln' will catch a negative value of X. 11711 11712 DEFB __ln ;; Y, LN X. 11713 DEFB __multiply ;; Y * LN X 11714 DEFB __end_calc ;; 11715 11716 JP exp <#exp> ; jump back to EXP routine. -> 11717 11718 ; ___ 11719 11720 ; These routines form the three simple results when the number is zero. 11721 ; begin by deleting the known zero to leave Y the power factor. 11722 11723 mark_1DEE: 11724 *XISO:* 11725 DEFB __delete ;; Y. 11726 DEFB __duplicate ;; Y, Y. 11727 DEFB __not ;; Y, (1/0). 11728 DEFB __jump_true ;; 11729 DEFB ONE <#ONE> - $ ;; if Y is zero. 11730 11731 ; the power factor is not zero. If negative then an error exists. 11732 11733 DEFB __stk_zero ;; Y, 0. 11734 DEFB __exchange ;; 0, Y. 11735 DEFB __greater_0 ;; 0, (1/0). 11736 DEFB __jump_true ;; 0 11737 DEFB LAST <#LAST> - $ ;; if Y was any positive 11738 ;; number. 11739 11740 ; else force division by zero thereby raising an Arithmetic overflow error. 11741 ; There are some one and two-byte alternatives but perhaps the most formal 11742 ; might have been to use end_calc; rst 08; defb 05. 11743 11744 ; #if ORIGINAL 11745 11746 ; the SG ROM seems to want it the old way! 11747 #if 1 11748 DEFB __stk_one ;; 0, 1. 11749 DEFB __exchange ;; 1, 0. 11750 DEFB __division ;; 1/0 >> error 11751 #else 11752 DEFB $34 ;+ end-calc 11753 *REPORT_6c* 11754 RST 08H ;+ ERROR-1 11755 DEFB $05 ;+ Error Report: Number too big 11756 #endif 11757 11758 11759 ; ___ 11760 11761 mark_1DFB: 11762 *ONE:* 11763 DEFB __delete ;; . 11764 DEFB __stk_one ;; 1. 11765 11766 mark_1DFD: 11767 *LAST:* 11768 DEFB __end_calc ;; last value 1 or 0. 11769 11770 RET ; return. 11771 11772 ------------------------------------------------------------------------ 11773 11774 ; THE *'SPARE LOCATIONS'* 11775 ------------------------------------------------------------------------ 11776 11777 *SPARE:* 11778 11779 #if ORIGINAL 11780 mark_1DFF: 11781 DEFB $FF ; That's all folks. 11782 #else 11783 mark_1DFE: 11784 *L1DFE:* 11785 11786 ;; DEFB $FF, $FF ; Two spare bytes. 11787 DEFB $00, $00 ; Two spare bytes (as per the Shoulders of Giants ROM) 11788 #endif 11789 11790 11791 ------------------------------------------------------------------------ 11792 11793 ; THE *'ZX81 CHARACTER SET'* 11794 ------------------------------------------------------------------------ 11795 11796 11797 mark_1E00: 11798 *char_set* ; - begins with space character. 11799 11800 ; $00 - *Character: ' '* CHR$(0) 11801 11802 DEFB %00000000 11803 DEFB %00000000 11804 DEFB %00000000 11805 DEFB %00000000 11806 DEFB %00000000 11807 DEFB %00000000 11808 DEFB %00000000 11809 DEFB %00000000 11810 11811 ; $01 - *Character: mosaic* CHR$(1) 11812 11813 DEFB %*1111*0000 11814 DEFB %*1111*0000 11815 DEFB %*1111*0000 11816 DEFB %*1111*0000 11817 DEFB %00000000 11818 DEFB %00000000 11819 DEFB %00000000 11820 DEFB %00000000 11821 11822 11823 ; $02 - *Character: mosaic* CHR$(2) 11824 11825 DEFB %0000*1111* 11826 DEFB %0000*1111* 11827 DEFB %0000*1111* 11828 DEFB %0000*1111* 11829 DEFB %00000000 11830 DEFB %00000000 11831 DEFB %00000000 11832 DEFB %00000000 11833 11834 11835 ; $03 - *Character: mosaic* CHR$(3) 11836 11837 DEFB %*11111111* 11838 DEFB %*11111111* 11839 DEFB %*11111111* 11840 DEFB %*11111111* 11841 DEFB %00000000 11842 DEFB %00000000 11843 DEFB %00000000 11844 DEFB %00000000 11845 11846 ; $04 - *Character: mosaic* CHR$(4) 11847 11848 DEFB %00000000 11849 DEFB %00000000 11850 DEFB %00000000 11851 DEFB %00000000 11852 DEFB %*1111*0000 11853 DEFB %*1111*0000 11854 DEFB %*1111*0000 11855 DEFB %*1111*0000 11856 11857 ; $05 - *Character: mosaic* CHR$(5) 11858 11859 DEFB %*1111*0000 11860 DEFB %*1111*0000 11861 DEFB %*1111*0000 11862 DEFB %*1111*0000 11863 DEFB %*1111*0000 11864 DEFB %*1111*0000 11865 DEFB %*1111*0000 11866 DEFB %*1111*0000 11867 11868 ; $06 - *Character: mosaic* CHR$(6) 11869 11870 DEFB %0000*1111* 11871 DEFB %0000*1111* 11872 DEFB %0000*1111* 11873 DEFB %0000*1111* 11874 DEFB %*1111*0000 11875 DEFB %*1111*0000 11876 DEFB %*1111*0000 11877 DEFB %*1111*0000 11878 11879 ; $07 - *Character: mosaic* CHR$(7) 11880 11881 DEFB %*11111111* 11882 DEFB %*11111111* 11883 DEFB %*11111111* 11884 DEFB %*11111111* 11885 DEFB %*1111*0000 11886 DEFB %*1111*0000 11887 DEFB %*1111*0000 11888 DEFB %*1111*0000 11889 11890 ; $08 - *Character: mosaic* CHR$(8) 11891 11892 DEFB %*1*0*1*0*1*0*1*0 11893 DEFB %0*1*0*1*0*1*0*1* 11894 DEFB %*1*0*1*0*1*0*1*0 11895 DEFB %0*1*0*1*0*1*0*1* 11896 DEFB %*1*0*1*0*1*0*1*0 11897 DEFB %0*1*0*1*0*1*0*1* 11898 DEFB %*1*0*1*0*1*0*1*0 11899 DEFB %0*1*0*1*0*1*0*1* 11900 ; $09 - *Character: mosaic* CHR$(9) 11901 11902 DEFB %00000000 11903 DEFB %00000000 11904 DEFB %00000000 11905 DEFB %00000000 11906 DEFB %*1*0*1*0*1*0*1*0 11907 DEFB %0*1*0*1*0*1*0*1* 11908 DEFB %*1*0*1*0*1*0*1*0 11909 DEFB %0*1*0*1*0*1*0*1* 11910 ; $0A - *Character: mosaic* CHR$(10) 11911 11912 DEFB %*1*0*1*0*1*0*1*0 11913 DEFB %0*1*0*1*0*1*0*1* 11914 DEFB %*1*0*1*0*1*0*1*0 11915 DEFB %0*1*0*1*0*1*0*1* 11916 DEFB %00000000 11917 DEFB %00000000 11918 DEFB %00000000 11919 DEFB %00000000 11920 11921 ; $0B - *Character: '"'* CHR$(11) 11922 11923 DEFB %00000000 11924 DEFB %00*1*00*1*00 11925 DEFB %00*1*00*1*00 11926 DEFB %00000000 11927 DEFB %00000000 11928 DEFB %00000000 11929 DEFB %00000000 11930 DEFB %00000000 11931 11932 ; $0C - *Character:* £ CHR$(12) 11933 11934 DEFB %00000000 11935 DEFB %000*111*00 11936 DEFB %00*1*000*1*0 11937 DEFB %0*1111*000 11938 DEFB %00*1*00000 11939 DEFB %00*1*00000 11940 DEFB %0*111111*0 11941 DEFB %00000000 11942 11943 ; $0D - *Character: '$'* CHR$(13) 11944 11945 DEFB %00000000 11946 DEFB %0000*1*000 11947 DEFB %00*11111*0 11948 DEFB %00*1*0*1*000 11949 DEFB %00*11111*0 11950 DEFB %0000*1*0*1*0 11951 DEFB %00*11111*0 11952 DEFB %0000*1*000 11953 11954 ; $0E - *Character: ':'* CHR$(14) 11955 11956 DEFB %00000000 11957 DEFB %00000000 11958 DEFB %00000000 11959 DEFB %000*1*0000 11960 DEFB %00000000 11961 DEFB %00000000 11962 DEFB %000*1*0000 11963 DEFB %00000000 11964 11965 ; $0F - *Character: '?'* CHR$(15) 11966 11967 DEFB %00000000 11968 DEFB %00*1111*00 11969 DEFB %0*1*0000*1*0 11970 DEFB %00000*1*00 11971 DEFB %0000*1*000 11972 DEFB %00000000 11973 DEFB %0000*1*000 11974 DEFB %00000000 11975 11976 ; $10 - *Character: '('* CHR$(16) 11977 11978 DEFB %00000000 11979 DEFB %00000*1*00 11980 DEFB %0000*1*000 11981 DEFB %0000*1*000 11982 DEFB %0000*1*000 11983 DEFB %0000*1*000 11984 DEFB %00000*1*00 11985 DEFB %00000000 11986 11987 ; $11 - *Character: ')'* CHR$(17) 11988 11989 DEFB %00000000 11990 DEFB %00*1*00000 11991 DEFB %000*1*0000 11992 DEFB %000*1*0000 11993 DEFB %000*1*0000 11994 DEFB %000*1*0000 11995 DEFB %00*1*00000 11996 DEFB %00000000 11997 11998 ; $12 - *Character: '>'* CHR$(18) 11999 12000 DEFB %00000000 12001 DEFB %00000000 12002 DEFB %000*1*0000 12003 DEFB %0000*1*000 12004 DEFB %00000*1*00 12005 DEFB %0000*1*000 12006 DEFB %000*1*0000 12007 DEFB %00000000 12008 12009 ; $13 - *Character: '<'* CHR$(19) 12010 12011 DEFB %00000000 12012 DEFB %00000000 12013 DEFB %00000*1*00 12014 DEFB %0000*1*000 12015 DEFB %000*1*0000 12016 DEFB %0000*1*000 12017 DEFB %00000*1*00 12018 DEFB %00000000 12019 12020 ; $14 - *Character: '='* CHR$(20) 12021 12022 DEFB %00000000 12023 DEFB %00000000 12024 DEFB %00000000 12025 DEFB %00*11111*0 12026 DEFB %00000000 12027 DEFB %00*11111*0 12028 DEFB %00000000 12029 DEFB %00000000 12030 12031 ; $15 - *Character: '+'* CHR$(21) 12032 12033 DEFB %00000000 12034 DEFB %00000000 12035 DEFB %0000*1*000 12036 DEFB %0000*1*000 12037 DEFB %00*11111*0 12038 DEFB %0000*1*000 12039 DEFB %0000*1*000 12040 DEFB %00000000 12041 12042 ; $16 - *Character: '-'* CHR$(22) 12043 12044 DEFB %00000000 12045 DEFB %00000000 12046 DEFB %00000000 12047 DEFB %00000000 12048 DEFB %00*11111*0 12049 DEFB %00000000 12050 DEFB %00000000 12051 DEFB %00000000 12052 12053 ; $17 - *Character: '*'* CHR$(23) 12054 12055 DEFB %00000000 12056 DEFB %00000000 12057 DEFB %000*1*0*1*00 12058 DEFB %0000*1*000 12059 DEFB %00*11111*0 12060 DEFB %0000*1*000 12061 DEFB %000*1*0*1*00 12062 DEFB %00000000 12063 12064 ; $18 - *Character: '/'* CHR$(24) 12065 12066 DEFB %00000000 12067 DEFB %00000000 12068 DEFB %000000*1*0 12069 DEFB %00000*1*00 12070 DEFB %0000*1*000 12071 DEFB %000*1*0000 12072 DEFB %00*1*00000 12073 DEFB %00000000 12074 12075 ; $19 - *Character: ';'* CHR$(25) 12076 12077 DEFB %00000000 12078 DEFB %00000000 12079 DEFB %000*1*0000 12080 DEFB %00000000 12081 DEFB %00000000 12082 DEFB %000*1*0000 12083 DEFB %000*1*0000 12084 DEFB %00*1*00000 12085 12086 ; $1A - *Character: ','* CHR$(26) 12087 12088 DEFB %00000000 12089 DEFB %00000000 12090 DEFB %00000000 12091 DEFB %00000000 12092 DEFB %00000000 12093 DEFB %0000*1*000 12094 DEFB %0000*1*000 12095 DEFB %000*1*0000 12096 12097 ; $1B - *Character: '"'* CHR$(27) 12098 12099 DEFB %00000000 12100 DEFB %00000000 12101 DEFB %00000000 12102 DEFB %00000000 12103 DEFB %00000000 12104 DEFB %000*11*000 12105 DEFB %000*11*000 12106 DEFB %00000000 12107 12108 ; $1C - *Character: '0'* CHR$(28) 12109 12110 DEFB %00000000 12111 DEFB %00*1111*00 12112 DEFB %0*1*000*11*0 12113 DEFB %0*1*00*1*0*1*0 12114 DEFB %0*1*0*1*00*1*0 12115 DEFB %0*11*000*1*0 12116 DEFB %00*1111*00 12117 DEFB %00000000 12118 12119 ; $1D - *Character: '1'* CHR$(29) 12120 12121 DEFB %00000000 12122 DEFB %000*11*000 12123 DEFB %00*1*0*1*000 12124 DEFB %0000*1*000 12125 DEFB %0000*1*000 12126 DEFB %0000*1*000 12127 DEFB %00*11111*0 12128 DEFB %00000000 12129 12130 ; $1E - *Character: '2'* CHR$(30) 12131 12132 DEFB %00000000 12133 DEFB %00*1111*00 12134 DEFB %0*1*0000*1*0 12135 DEFB %000000*1*0 12136 DEFB %00*1111*00 12137 DEFB %0*1*000000 12138 DEFB %0*111111*0 12139 DEFB %00000000 12140 12141 ; $1F - *Character: '3'* CHR$(31) 12142 12143 DEFB %00000000 12144 DEFB %00*1111*00 12145 DEFB %0*1*0000*1*0 12146 DEFB %0000*11*00 12147 DEFB %000000*1*0 12148 DEFB %0*1*0000*1*0 12149 DEFB %00*1111*00 12150 DEFB %00000000 12151 12152 ; $20 - *Character: '4'* CHR$(32) 12153 12154 DEFB %00000000 12155 DEFB %0000*1*000 12156 DEFB %000*11*000 12157 DEFB %00*1*0*1*000 12158 DEFB %0*1*00*1*000 12159 DEFB %0*111111*0 12160 DEFB %0000*1*000 12161 DEFB %00000000 12162 12163 ; $21 - *Character: '5'* CHR$(33) 12164 12165 DEFB %00000000 12166 DEFB %0*111111*0 12167 DEFB %0*1*000000 12168 DEFB %0*11111*00 12169 DEFB %000000*1*0 12170 DEFB %0*1*0000*1*0 12171 DEFB %00*1111*00 12172 DEFB %00000000 12173 12174 ; $22 - *Character: '6'* CHR$(34) 12175 12176 DEFB %00000000 12177 DEFB %00*1111*00 12178 DEFB %0*1*000000 12179 DEFB %0*11111*00 12180 DEFB %0*1*0000*1*0 12181 DEFB %0*1*0000*1*0 12182 DEFB %00*1111*00 12183 DEFB %00000000 12184 12185 ; $23 - *Character: '7'* CHR$(35) 12186 12187 DEFB %00000000 12188 DEFB %0*111111*0 12189 DEFB %000000*1*0 12190 DEFB %00000*1*00 12191 DEFB %0000*1*000 12192 DEFB %000*1*0000 12193 DEFB %000*1*0000 12194 DEFB %00000000 12195 12196 ; $24 - *Character: '8'* CHR$(36) 12197 12198 DEFB %00000000 12199 DEFB %00*1111*00 12200 DEFB %0*1*0000*1*0 12201 DEFB %00*1111*00 12202 DEFB %0*1*0000*1*0 12203 DEFB %0*1*0000*1*0 12204 DEFB %00*1111*00 12205 DEFB %00000000 12206 12207 ; $25 - *Character: '9'* CHR$(37) 12208 12209 DEFB %00000000 12210 DEFB %00*1111*00 12211 DEFB %0*1*0000*1*0 12212 DEFB %0*1*0000*1*0 12213 DEFB %00*11111*0 12214 DEFB %000000*1*0 12215 DEFB %00*1111*00 12216 DEFB %00000000 12217 12218 ; $26 - *Character: 'A'* CHR$(38) 12219 12220 DEFB %00000000 12221 DEFB %00*1111*00 12222 DEFB %0*1*0000*1*0 12223 DEFB %0*1*0000*1*0 12224 DEFB %0*111111*0 12225 DEFB %0*1*0000*1*0 12226 DEFB %0*1*0000*1*0 12227 DEFB %00000000 12228 12229 ; $27 - *Character: 'B'* CHR$(39) 12230 12231 DEFB %00000000 12232 DEFB %0*11111*00 12233 DEFB %0*1*0000*1*0 12234 DEFB %0*11111*00 12235 DEFB %0*1*0000*1*0 12236 DEFB %0*1*0000*1*0 12237 DEFB %0*11111*00 12238 DEFB %00000000 12239 12240 ; $28 - *Character: 'C'* CHR$(40) 12241 12242 DEFB %00000000 12243 DEFB %00*1111*00 12244 DEFB %0*1*0000*1*0 12245 DEFB %0*1*000000 12246 DEFB %0*1*000000 12247 DEFB %0*1*0000*1*0 12248 DEFB %00*1111*00 12249 DEFB %00000000 12250 12251 ; $29 - *Character: 'D'* CHR$(41) 12252 12253 DEFB %00000000 12254 DEFB %0*1111*000 12255 DEFB %0*1*000*1*00 12256 DEFB %0*1*0000*1*0 12257 DEFB %0*1*0000*1*0 12258 DEFB %0*1*000*1*00 12259 DEFB %0*1111*000 12260 DEFB %00000000 12261 12262 ; $2A - *Character: 'E'* CHR$(42) 12263 12264 DEFB %00000000 12265 DEFB %0*111111*0 12266 DEFB %0*1*000000 12267 DEFB %0*11111*00 12268 DEFB %0*1*000000 12269 DEFB %0*1*000000 12270 DEFB %0*111111*0 12271 DEFB %00000000 12272 12273 ; $2B - *Character: 'F'* CHR$(43) 12274 12275 DEFB %00000000 12276 DEFB %0*111111*0 12277 DEFB %0*1*000000 12278 DEFB %0*11111*00 12279 DEFB %0*1*000000 12280 DEFB %0*1*000000 12281 DEFB %0*1*000000 12282 DEFB %00000000 12283 12284 ; $2C - *Character: 'G'* CHR$(44) 12285 12286 DEFB %00000000 12287 DEFB %00*1111*00 12288 DEFB %0*1*0000*1*0 12289 DEFB %0*1*000000 12290 DEFB %0*1*00*111*0 12291 DEFB %0*1*0000*1*0 12292 DEFB %00*1111*00 12293 DEFB %00000000 12294 12295 ; $2D - *Character: 'H'* CHR$(45) 12296 12297 DEFB %00000000 12298 DEFB %0*1*0000*1*0 12299 DEFB %0*1*0000*1*0 12300 DEFB %0*111111*0 12301 DEFB %0*1*0000*1*0 12302 DEFB %0*1*0000*1*0 12303 DEFB %0*1*0000*1*0 12304 DEFB %00000000 12305 12306 ; $2E - *Character: 'I'* CHR$(46) 12307 12308 DEFB %00000000 12309 DEFB %00*11111*0 12310 DEFB %0000*1*000 12311 DEFB %0000*1*000 12312 DEFB %0000*1*000 12313 DEFB %0000*1*000 12314 DEFB %00*11111*0 12315 DEFB %00000000 12316 12317 ; $2F - *Character: 'J'* CHR$(47) 12318 12319 DEFB %00000000 12320 DEFB %000000*1*0 12321 DEFB %000000*1*0 12322 DEFB %000000*1*0 12323 DEFB %0*1*0000*1*0 12324 DEFB %0*1*0000*1*0 12325 DEFB %00*1111*00 12326 DEFB %00000000 12327 12328 ; $30 - *Character: 'K'* CHR$(48) 12329 12330 DEFB %00000000 12331 DEFB %0*1*000*1*00 12332 DEFB %0*1*00*1*000 12333 DEFB %0*111*0000 12334 DEFB %0*1*00*1*000 12335 DEFB %0*1*000*1*00 12336 DEFB %0*1*0000*1*0 12337 DEFB %00000000 12338 12339 ; $31 - *Character: 'L'* CHR$(49) 12340 12341 DEFB %00000000 12342 DEFB %0*1*000000 12343 DEFB %0*1*000000 12344 DEFB %0*1*000000 12345 DEFB %0*1*000000 12346 DEFB %0*1*000000 12347 DEFB %0*111111*0 12348 DEFB %00000000 12349 12350 ; $32 - *Character: 'M'* CHR$(50) 12351 12352 DEFB %00000000 12353 DEFB %0*1*0000*1*0 12354 DEFB %0*11*00*11*0 12355 DEFB %0*1*0*11*0*1*0 12356 DEFB %0*1*0000*1*0 12357 DEFB %0*1*0000*1*0 12358 DEFB %0*1*0000*1*0 12359 DEFB %00000000 12360 12361 ; $33 - *Character: 'N'* CHR$(51) 12362 12363 DEFB %00000000 12364 DEFB %0*1*0000*1*0 12365 DEFB %0*11*000*1*0 12366 DEFB %0*1*0*1*00*1*0 12367 DEFB %0*1*00*1*0*1*0 12368 DEFB %0*1*000*11*0 12369 DEFB %0*1*0000*1*0 12370 DEFB %00000000 12371 12372 ; $34 - *Character: 'O'* CHR$(52) 12373 12374 DEFB %00000000 12375 DEFB %00*1111*00 12376 DEFB %0*1*0000*1*0 12377 DEFB %0*1*0000*1*0 12378 DEFB %0*1*0000*1*0 12379 DEFB %0*1*0000*1*0 12380 DEFB %00*1111*00 12381 DEFB %00000000 12382 12383 ; $35 - *Character: 'P'* CHR$(53) 12384 12385 DEFB %00000000 12386 DEFB %0*11111*00 12387 DEFB %0*1*0000*1*0 12388 DEFB %0*1*0000*1*0 12389 DEFB %0*11111*00 12390 DEFB %0*1*000000 12391 DEFB %0*1*000000 12392 DEFB %00000000 12393 12394 ; $36 - *Character: 'Q'* CHR$(54) 12395 12396 DEFB %00000000 12397 DEFB %00*1111*00 12398 DEFB %0*1*0000*1*0 12399 DEFB %0*1*0000*1*0 12400 DEFB %0*1*0*1*00*1*0 12401 DEFB %0*1*00*1*0*1*0 12402 DEFB %00*1111*00 12403 DEFB %00000000 12404 12405 ; $37 - *Character: 'R'* CHR$(55) 12406 12407 DEFB %00000000 12408 DEFB %0*11111*00 12409 DEFB %0*1*0000*1*0 12410 DEFB %0*1*0000*1*0 12411 DEFB %0*11111*00 12412 DEFB %0*1*000*1*00 12413 DEFB %0*1*0000*1*0 12414 DEFB %00000000 12415 12416 ; $38 - *Character: 'S'* CHR$(56) 12417 12418 DEFB %00000000 12419 DEFB %00*1111*00 12420 DEFB %0*1*000000 12421 DEFB %00*1111*00 12422 DEFB %000000*1*0 12423 DEFB %0*1*0000*1*0 12424 DEFB %00*1111*00 12425 DEFB %00000000 12426 12427 ; $39 - *Character: 'T'* CHR$(57) 12428 12429 DEFB %00000000 12430 DEFB %*1111111*0 12431 DEFB %000*1*0000 12432 DEFB %000*1*0000 12433 DEFB %000*1*0000 12434 DEFB %000*1*0000 12435 DEFB %000*1*0000 12436 DEFB %00000000 12437 12438 ; $3A - *Character: 'U'* CHR$(58) 12439 12440 DEFB %00000000 12441 DEFB %0*1*0000*1*0 12442 DEFB %0*1*0000*1*0 12443 DEFB %0*1*0000*1*0 12444 DEFB %0*1*0000*1*0 12445 DEFB %0*1*0000*1*0 12446 DEFB %00*1111*00 12447 DEFB %00000000 12448 12449 ; $3B - *Character: 'V'* CHR$(59) 12450 12451 DEFB %00000000 12452 DEFB %0*1*0000*1*0 12453 DEFB %0*1*0000*1*0 12454 DEFB %0*1*0000*1*0 12455 DEFB %0*1*0000*1*0 12456 DEFB %00*1*00*1*00 12457 DEFB %000*11*000 12458 DEFB %00000000 12459 12460 ; $3C - *Character: 'W'* CHR$(60) 12461 12462 DEFB %00000000 12463 DEFB %0*1*0000*1*0 12464 DEFB %0*1*0000*1*0 12465 DEFB %0*1*0000*1*0 12466 DEFB %0*1*0000*1*0 12467 DEFB %0*1*0*11*0*1*0 12468 DEFB %00*1*00*1*00 12469 DEFB %00000000 12470 12471 ; $3D - *Character: 'X'* CHR$(61) 12472 12473 DEFB %00000000 12474 DEFB %0*1*0000*1*0 12475 DEFB %00*1*00*1*00 12476 DEFB %000*11*000 12477 DEFB %000*11*000 12478 DEFB %00*1*00*1*00 12479 DEFB %0*1*0000*1*0 12480 DEFB %00000000 12481 12482 ; $3E - *Character: 'Y'* CHR$(62) 12483 12484 DEFB %00000000 12485 DEFB %*1*00000*1*0 12486 DEFB %0*1*000*1*00 12487 DEFB %00*1*0*1*000 12488 DEFB %000*1*0000 12489 DEFB %000*1*0000 12490 DEFB %000*1*0000 12491 DEFB %00000000 12492 12493 ; $3F - *Character: 'Z'* CHR$(63) 12494 12495 DEFB %00000000 12496 DEFB %0*111111*0 12497 DEFB %00000*1*00 12498 DEFB %0000*1*000 12499 DEFB %000*1*0000 12500 DEFB %00*1*00000 12501 DEFB %0*111111*0 12502 DEFB %00000000 12503 12504 12505 ; .END ;TASM assembler instruction. 12506 12507 12508 12509 ; 12510 ; This marks the end of the ZX81 ROM. 12511 ; 12512 ; As a bonus feature, I will now include the code for 12513 ; the G007 graphics board and 12514 ; the ZX81 monitor 12515 ; 12516 ; The 8K space divides into four 2K spaces like so: 12517 ; 12518 ; 2000 RAM (1K or 2K) remapped 12519 ; 2800 G007 ROM 12520 ; 3000 12521 ; 3800 ZX81 Monitor 12522 ; 12523 ; The G007 uses some RAM 12524 ; 2300 G007 RAM variables 12525 ; 12526 ; 2000 12527 #code $2000,$0800 12528 ; RAM_2K 12529 ; 2300 12530 ; xxxx data 4 ; reserves 4 bytes from the #data segment for variable "Toto" 12531 12532 #code $2800,$0800 12533 12534 #if 0 12535 ; 12536 ; just copy bytes. Provides a reference for comparing code output. 12537 ; 12538 ; G007 Graphics 12539 ; Start = 2800H 12540 ; End = 2FFFH 12541 mark_2800: DEFB $2A, $23, $23, $3A, $25, $23, $67, $EB 12542 mark_2808: DEFB $3A, $18, $23, $3D, $92, $57, $3E, $07 12543 mark_2810: DEFB $A3, $6F, $26, $2D, $7E, $2A, $08, $23 12544 mark_2818: DEFB $4A, $06, $00, $09, $09, $CB, $3A, $CB 12545 mark_2820: DEFB $1B, $CB, $3A, $CB, $1B, $CB, $3A, $CB 12546 mark_2828: DEFB $1B, $19, $47, $C9, $3A, $21, $23, $2A 12547 mark_2830: DEFB $27, $23, $ED, $5B, $23, $23, $D9, $2A 12548 mark_2838: DEFB $25, $23, $ED, $5B, $29, $23, $CB, $77 12549 mark_2840: DEFB $28, $1C, $CB, $7F, $C0, $3A, $21, $40 12550 mark_2848: DEFB $F5, $06, $08, $0F, $FD, $CB, $21, $16 12551 mark_2850: DEFB $10, $F9, $EB, $D9, $EB, $D9, $CD, $5E 12552 mark_2858: DEFB $28, $F1, $32, $21, $40, $C9, $01, $DE 12553 mark_2860: DEFB $FF, $3A, $18, $23, $3D, $93, $ED, $52 12554 mark_2868: DEFB $F2, $76, $28, $01, $22, $00, $7B, $D5 12555 mark_2870: DEFB $19, $EB, $B7, $ED, $52, $D1, $E5, $63 12556 mark_2878: DEFB $5F, $D9, $01, $FB, $28, $7D, $D9, $6F 12557 mark_2880: DEFB $D9, $B7, $ED, $52, $F2, $90, $28, $01 12558 mark_2888: DEFB $04, $29, $2F, $19, $EB, $B7, $ED, $52 12559 mark_2890: DEFB $ED, $43, $1A, $23, $D1, $B7, $ED, $52 12560 mark_2898: DEFB $19, $30, $09, $EB, $01, $F6, $28, $D9 12561 mark_28A0: DEFB $53, $5F, $7A, $D9, $ED, $43, $1C, $23 12562 mark_28A8: DEFB $D9, $57, $D5, $D9, $C1, $3A, $21, $23 12563 mark_28B0: DEFB $FE, $40, $30, $02, $45, $4B, $04, $0C 12564 mark_28B8: DEFB $CB, $3C, $38, $02, $28, $08, $CB, $1D 12565 mark_28C0: DEFB $CB, $3A, $CB, $1B, $18, $F2, $55, $CB 12566 mark_28C8: DEFB $3D, $D9, $C5, $CD, $07, $28, $D1, $3A 12567 mark_28D0: DEFB $1F, $23, $4F, $FD, $CB, $21, $06, $38 12568 mark_28D8: DEFB $08, $3A, $1E, $23, $AE, $B1, $A0, $AE 12569 mark_28E0: DEFB $77, $D9, $7D, $05, $C8, $93, $30, $0A 12570 mark_28E8: DEFB $0D, $C8, $82, $D9, $19, $D9, $2A, $1A 12571 mark_28F0: DEFB $23, $E9, $2A, $1C, $23, $E9, $6F, $D9 12572 mark_28F8: DEFB $19, $18, $D8, $6F, $D9, $CB, $00, $30 12573 mark_2900: DEFB $D2, $2B, $18, $CF, $6F, $D9, $CB, $08 12574 mark_2908: DEFB $30, $C9, $23, $18, $C6, $2A, $A8, $0E 12575 mark_2910: DEFB $E9, $CD, $0D, $29, $38, $0E, $21, $00 12576 mark_2918: DEFB $00, $28, $06, $ED, $42, $F8, $C8, $18 12577 mark_2920: DEFB $03, $ED, $4A, $F0, $E1, $C9, $CD, $11 12578 mark_2928: DEFB $29, $22, $25, $23, $CD, $11, $29, $E5 12579 mark_2930: DEFB $CD, $02, $0C, $C1, $ED, $5B, $25, $23 12580 mark_2938: DEFB $28, $0C, $3D, $C0, $21, $9C, $0C, $22 12581 mark_2940: DEFB $30, $40, $43, $C3, $B2, $0B 12582 ; The Plot Routine: 12583 ; A == the plot number N 12584 ; BC == screen X 12585 ; DE == screen Y 12586 mark_2946: DEFB $B7, $28 12587 mark_2948: DEFB $F9, $3D, $D5, $C5, $F5, $CD, $1F, $2E 12588 mark_2950: DEFB $F1, $D1, $C1, $FE, $81, $20, $0F, $ED 12589 mark_2958: DEFB $53, $30, $23, $ED, $43, $32, $23, $01 12590 mark_2960: DEFB $00, $00, $50, $58, $3E, $0B, $CB, $57 12591 mark_2968: DEFB $28, $09, $2A, $29, $23, $E5, $2A, $27 12592 mark_2970: DEFB $23, $18, $07, $2A, $32, $23, $E5, $2A 12593 mark_2978: DEFB $30, $23, $B7, $ED, $5A, $D1, $E8, $22 12594 mark_2980: DEFB $23, $23, $EB, $B7, $ED, $4A, $E8, $22 12595 mark_2988: DEFB $25, $23, $5F, $3E, $C0, $A4, $E0, $3E 12596 mark_2990: DEFB $C0, $A2, $E0, $D9, $E5, $D5, $C5, $CD 12597 mark_2998: DEFB $9F, $29, $C1, $D1, $E1, $D9, $C9, $D9 12598 mark_29A0: DEFB $7C, $B2, $37, $20, $05, $3A, $18, $23 12599 mark_29A8: DEFB $3D, $BD, $3A, $21, $23, $1F, $32, $21 12600 mark_29B0: DEFB $23, $7B, $CB, $7F, $28, $04, $2A, $10 12601 mark_29B8: DEFB $23, $E9, $F5, $E6, $03, $1F, $3D, $2F 12602 mark_29C0: DEFB $67, $9F, $6F, $22, $1E, $23, $E5, $CB 12603 mark_29C8: DEFB $5B, $20, $28, $3A, $20, $23, $AB, $E6 12604 mark_29D0: DEFB $FB, $28, $0F, $21, $34, $23, $7B, $07 12605 mark_29D8: DEFB $07, $07, $E6, $03, $85, $6F, $7E, $32 12606 mark_29E0: DEFB $21, $40, $CD, $2C, $28, $E1, $FD, $CB 12607 mark_29E8: DEFB $21, $0E, $38, $26, $7C, $A5, $28, $22 12608 mark_29F0: DEFB $2C, $5D, $E5, $3A, $21, $23, $CB, $6B 12609 mark_29F8: DEFB $20, $3D, $CB, $73, $20, $3E, $E1, $CB 12610 mark_2A00: DEFB $7F, $20, $0F, $E5, $CD, $00, $28, $A6 12611 mark_2A08: DEFB $32, $17, $23, $D1, $7E, $B2, $AB, $A0 12612 mark_2A10: DEFB $AE, $77, $F1, $32, $20, $23, $21, $2A 12613 mark_2A18: DEFB $23, $11, $2E, $23, $01, $08, $00, $CB 12614 mark_2A20: DEFB $67, $28, $11, $3A, $21, $23, $E6, $C0 12615 mark_2A28: DEFB $17, $30, $02, $CB, $F7, $32, $21, $23 12616 mark_2A30: DEFB $2E, $26, $0E, $04, $ED, $B8, $C9, $21 12617 mark_2A38: DEFB $FF, $FF, $18, $03, $2A, $0A, $23, $D9 12618 mark_2A40: DEFB $E6, $E0, $C2, $AD, $0E, $21, $21, $23 12619 mark_2A48: DEFB $FD, $36, $21, $55, $06, $03, $23, $23 12620 mark_2A50: DEFB $5E, $23, $23, $56, $D5, $10, $F7, $C1 12621 mark_2A58: DEFB $D1, $E1, $B7, $28, $02, $44, $4D, $78 12622 mark_2A60: DEFB $BC, $30, $03, $C5, $E3, $C1, $7C, $BA 12623 mark_2A68: DEFB $30, $01, $EB, $7A, $D9, $E6, $07, $3C 12624 mark_2A70: DEFB $47, $7C, $CB, $05, $07, $07, $07, $10 12625 mark_2A78: DEFB $F9, $67, $22, $38, $23, $D9, $7C, $B8 12626 mark_2A80: DEFB $3E, $07, $30, $03, $C5, $E3, $C1, $EB 12627 mark_2A88: DEFB $F5, $79, $D9, $67, $6F, $4F, $22, $1A 12628 mark_2A90: DEFB $23, $06, $FE, $D9, $93, $D9, $30, $04 12629 mark_2A98: DEFB $06, $00, $ED, $44, $57, $D9, $7A, $90 12630 mark_2AA0: DEFB $D9, $67, $BA, $30, $02, $EB, $04, $6C 12631 mark_2AA8: DEFB $2C, $5C, $CB, $3B, $F1, $0F, $30, $09 12632 mark_2AB0: DEFB $E5, $D5, $C5, $0F, $D9, $38, $CD, $18 12633 mark_2AB8: DEFB $CE, $D9, $60, $2E, $01, $C1, $D1, $E3 12634 mark_2AC0: DEFB $2D, $20, $16, $2A, $1A, $23, $79, $BC 12635 mark_2AC8: DEFB $38, $01, $67, $BD, $30, $01, $6F, $22 12636 mark_2AD0: DEFB $1A, $23, $E1, $2D, $28, $E7, $E5, $18 12637 mark_2AD8: DEFB $15, $7B, $92, $38, $0A, $5F, $CB, $40 12638 mark_2AE0: DEFB $28, $0C, $79, $80, $4F, $18, $D9, $84 12639 mark_2AE8: DEFB $5F, $3E, $01, $B0, $81, $4F, $79, $D9 12640 mark_2AF0: DEFB $FD, $CB, $21, $0E, $38, $CA, $E3, $D5 12641 mark_2AF8: DEFB $C5, $E5, $ED, $5B, $1A, $23, $47, $B9 12642 mark_2B00: DEFB $30, $02, $41, $4F, $ED, $43, $1A, $23 12643 mark_2B08: DEFB $79, $BB, $3C, $38, $01, $7B, $6F, $7A 12644 mark_2B10: DEFB $B8, $30, $02, $78, $3D, $95, $3C, $F5 12645 mark_2B18: DEFB $CD, $07, $28, $F1, $4F, $EB, $21, $39 12646 mark_2B20: DEFB $23, $7E, $07, $07, $07, $77, $2B, $CB 12647 mark_2B28: DEFB $06, $B6, $2A, $1E, $23, $AD, $2F, $6F 12648 mark_2B30: DEFB $EB, $7B, $AE, $B2, $A0, $AE, $77, $0D 12649 mark_2B38: DEFB $20, $14, $E1, $24, $CB, $7D, $28, $94 12650 mark_2B40: DEFB $E1, $E1, $E1, $E1, $7C, $A5, $CA, $12 12651 mark_2B48: DEFB $2A, $2C, $E5, $C3, $45, $2A, $CB, $18 12652 mark_2B50: DEFB $30, $DF, $23, $41, $79, $E6, $07, $4F 12653 mark_2B58: DEFB $CB, $38, $CB, $38, $CB, $38, $28, $08 12654 mark_2B60: DEFB $7B, $AE, $B2, $AE, $77, $23, $10, $F8 12655 mark_2B68: DEFB $37, $0C, $18, $CB, $2A, $13, $23, $2D 12656 mark_2B70: DEFB $B5, $C2, $09, $08, $25, $C2, $B8, $23 12657 mark_2B78: DEFB $3A, $21, $23, $17, $D8, $00, $00, $2A 12658 mark_2B80: DEFB $28, $23, $3A, $27, $23, $CB, $72, $20 12659 mark_2B88: DEFB $05, $6F, $C6, $08, $30, $0D, $7C, $D6 12660 mark_2B90: DEFB $08, $30, $04, $3A, $18, $23, $3D, $32 12661 mark_2B98: DEFB $29, $23, $AF, $32, $27, $23, $CB, $72 12662 mark_2BA0: DEFB $C0, $CD, $EF, $2E, $7D, $FE, $F9, $38 12663 mark_2BA8: DEFB $02, $1E, $02, $2F, $E6, $07, $3C, $57 12664 mark_2BB0: DEFB $7C, $3C, $D9, $57, $D9, $D5, $CD, $07 12665 mark_2BB8: DEFB $28, $D9, $79, $AE, $D9, $EB, $C1, $C5 12666 mark_2BC0: DEFB $6F, $26, $00, $29, $10, $FD, $EB, $06 12667 mark_2BC8: DEFB $02, $3A, $7B, $40, $AE, $FD, $B6, $7C 12668 mark_2BD0: DEFB $A2, $AE, $0D, $28, $01, $77, $53, $23 12669 mark_2BD8: DEFB $10, $EF, $0E, $20, $09, $D9, $23, $15 12670 mark_2BE0: DEFB $28, $02, $10, $D6, $E1, $C3, $9A, $29 12671 mark_2BE8: DEFB $ED, $57, $0F, $30, $08, $AF, $32, $22 12672 mark_2BF0: DEFB $40, $3C, $32, $13, $23, $CD, $CF, $0A 12673 mark_2BF8: DEFB $AF, $32, $13, $23, $FD, $36, $22, $02 12674 mark_2C00: DEFB $4F, $C9, $CD, $A0, $0C, $DA, $AD, $0E 12675 mark_2C08: DEFB $0E, $01, $C8, $0E, $FF, $C9, $FD, $46 12676 mark_2C10: DEFB $22, $0E, $21, $CD, $18, $09, $CD, $9B 12677 mark_2C18: DEFB $09, $7E, $12, $FD, $34, $3A, $2A, $0C 12678 mark_2C20: DEFB $40, $23, $54, $5D, $ED, $B1, $C3, $5D 12679 mark_2C28: DEFB $0A, $8B, $8D, $2D, $7F, $81, $49, $75 12680 mark_2C30: DEFB $5F, $40, $42, $2B, $17, $1F, $37, $52 12681 mark_2C38: DEFB $45, $0F, $6D, $2B, $44, $2D, $5A, $3B 12682 mark_2C40: DEFB $4C, $45, $0D, $52, $54, $4D, $15, $6A 12683 mark_2C48: DEFB $01, $14, $02, $06, $00, $81, $0E, $06 12684 mark_2C50: DEFB $DE, $05, $AB, $0D, $06, $00, $B5, $0E 12685 mark_2C58: DEFB $00, $DC, $0C, $00, $D8, $0E, $04, $14 12686 mark_2C60: DEFB $06, $DF, $06, $05, $B9, $0D, $04, $00 12687 mark_2C68: DEFB $2E, $0E, $05, $E8, $2B, $01, $00, $E9 12688 mark_2C70: DEFB $0E, $05, $A7, $2E, $05, $6A, $0D, $00 12689 mark_2C78: DEFB $C3, $03, $03, $AF, $0E, $03, $30, $07 12690 mark_2C80: DEFB $06, $1A, $06, $00, $92, $0E, $03, $6C 12691 mark_2C88: DEFB $0E, $05, $40, $03, $05, $4D, $2F, $00 12692 mark_2C90: DEFB $7C, $0E, $00, $B2, $0E, $03, $4E, $2E 12693 mark_2C98: DEFB $06, $1A, $06, $1A, $06, $00, $26, $29 12694 mark_2CA0: DEFB $2A, $A8, $0E, $E9, $00, $0E, $0C, $06 12695 mark_2CA8: DEFB $00, $AE, $2E, $03, $B2, $2E, $03, $B6 12696 mark_2CB0: DEFB $2E, $03, $53, $2F, $05, $CB, $0A, $03 12697 mark_2CB8: DEFB $2C, $07, $FD, $36, $01, $01, $CD, $73 12698 mark_2CC0: DEFB $0A, $CD, $95, $0A, $21, $00, $40, $36 12699 mark_2CC8: DEFB $FF, $21, $2D, $40, $CB, $6E, $28, $0E 12700 mark_2CD0: DEFB $FE, $E3, $7E, $C2, $6F, $0D, $CD, $A6 12701 mark_2CD8: DEFB $0D, $C8, $CF, $0C, $CF, $08, $DF, $06 12702 mark_2CE0: DEFB $00, $FE, $76, $C8, $4F, $E7, $79, $D6 12703 mark_2CE8: DEFB $E1, $38, $3B, $4F, $21, $29, $0C, $09 12704 mark_2CF0: DEFB $4E, $09, $18, $03, $2A, $30, $40, $7E 12705 mark_2CF8: DEFB $23, $22, $30, $40, $01, $F4, $0C, $C5 12706 ; 12707 ; bits shifting right within a byte: 12708 ; 12709 mark_2D00: DEFB $80, $40, $20, $10, $08, $04, $02, $01 12710 ; 12711 mark_2D08: DEFB $CD, $F7, $2B, $C3, $07, $02, $32, $28 12712 mark_2D10: DEFB $40, $EB, $21, $0A, $00, $39, $7E, $3C 12713 mark_2D18: DEFB $E6, $F0, $D6, $D0, $4F, $23, $7E, $D6 12714 mark_2D20: DEFB $04, $B1, $4F, $3A, $3B, $40, $07, $9F 12715 mark_2D28: DEFB $A1, $20, $10, $2A, $10, $40, $01, $DF 12716 mark_2D30: DEFB $FF, $09, $CB, $FC, $22, $04, $23, $3E 12717 mark_2D38: DEFB $01, $18, $0E, $2A, $0C, $40, $ED, $4B 12718 mark_2D40: DEFB $00, $23, $09, $CB, $FC, $22, $06, $23 12719 mark_2D48: DEFB $AF, $32, $19, $23, $2B, $7E, $EB, $C9 12720 mark_2D50: DEFB $3A, $19, $23, $3D, $C2, $73, $2D, $3E 12721 mark_2D58: DEFB $1E, $ED, $47, $ED, $6A, $2A, $04, $23 12722 mark_2D60: DEFB $01, $08, $01, $3E, $FE, $CD, $B5, $02 12723 mark_2D68: DEFB $3E, $1F, $ED, $47, $3A, $28, $40, $D6 12724 mark_2D70: DEFB $08, $18, $04, $2B, $3A, $28, $40, $4F 12725 mark_2D78: DEFB $DD, $E1, $FD, $CB, $3B, $7E, $C2, $9D 12726 mark_2D80: DEFB $02, $3E, $FE, $06, $01, $21, $9A, $2D 12727 mark_2D88: DEFB $CD, $95, $2D, $29, $00, $5F, $2A, $06 12728 mark_2D90: DEFB $23, $CB, $FC, $DD, $E9, $ED, $4F, $3E 12729 mark_2D98: DEFB $DD, $FB, $76, $21, $00, $22, $3E, $24 12730 mark_2DA0: DEFB $36, $01, $35, $28, $02, $CF, $1A, $23 12731 mark_2DA8: DEFB $BC, $20, $F5, $65, $11, $00, $20, $01 12732 mark_2DB0: DEFB $00, $01, $ED, $B0, $24, $14, $04, $ED 12733 mark_2DB8: DEFB $B0, $21, $F1, $07, $11, $A0, $23, $01 12734 mark_2DC0: DEFB $60, $00, $ED, $B0, $16, $20, $21, $B4 12735 mark_2DC8: DEFB $2F, $46, $18, $04, $5E, $23, $7E, $12 12736 mark_2DD0: DEFB $23, $10, $F9, $14, $CB, $52, $28, $F1 12737 mark_2DD8: DEFB $C9 12738 12739 ; Delete Display File: 12740 12741 mark_2DD9: DEFB $CD, $E7, $02, $21, $87, $3E, $CD 12742 mark_2DE0: DEFB $D8, $09, $C0, $EB, $2A, $29, $40, $CB 12743 mark_2DE8: DEFB $76, $28, $04, $ED, $53, $29, $40, $2A 12744 mark_2DF0: DEFB $0C, $40, $C3, $5D, $0A, $CD, $D9, $2D 12745 mark_2DF8: DEFB $01, $92, $19, $2A, $0C, $40, $2B, $CD 12746 mark_2E00: DEFB $9E, $09, $3E, $76, $12, $13, $12, $23 12747 mark_2E08: DEFB $23, $36, $3E, $23, $36, $87, $23, $36 12748 mark_2E10: DEFB $8D, $23, $36, $19, $23, $77, $23, $77 12749 mark_2E18: DEFB $CD, $07, $02, $3E, $01, $18, $37 12750 ; Check & Set Up Display File: 12751 mark_2E1F: DEFB $2A 12752 mark_2E20: DEFB $65, $22, $11, $D9, $BF, $19, $3A, $64 12753 mark_2E28: DEFB $22, $D6, $21, $B4, $B5, $C4, $9B, $2D 12754 mark_2E30: DEFB $2A, $0C, $40, $3E, $76, $2B, $2B, $BE 12755 mark_2E38: DEFB $C4, $F5, $2D, $2A, $0C, $40, $ED, $5B 12756 mark_2E40: DEFB $00, $23, $19, $22, $06, $23, $11, $09 12757 mark_2E48: DEFB $00, $19, $22, $08, $23, $C9, $CD, $02 12758 mark_2E50: DEFB $0C, $C0 12759 ; Clear The Screen: 12760 mark_2E52: DEFB $3D, $FA, $2A, $0A, $F5, $CD 12761 mark_2E58: DEFB $1F, $2E, $F1, $FE, $02, $ED, $4B, $18 12762 mark_2E60: DEFB $23, $2A, $0C, $40, $30, $30, $3D, $23 12763 mark_2E68: DEFB $22, $0E, $40, $2B, $2B, $2B, $1E, $00 12764 mark_2E70: DEFB $06, $10, $2B, $73, $2B, $73, $2B, $77 12765 mark_2E78: DEFB $2B, $77, $10, $FA, $0D, $20, $F1, $06 12766 mark_2E80: DEFB $09, $3E, $01, $2B, $73, $10, $FC, $21 12767 mark_2E88: DEFB $34, $23, $06, $14, $3D, $28, $F4, $21 12768 mark_2E90: DEFB $21, $18, $22, $39, $40, $C9, $C0, $2B 12769 mark_2E98: DEFB $2B, $06, $20, $2B, $2B, $2B, $7E, $2F 12770 mark_2EA0: DEFB $77, $10, $FA, $0D, $20, $F3, $C9, $2A 12771 mark_2EA8: DEFB $96, $0A, $3E, $4D, $18, $35, $3E, $DD 12772 mark_2EB0: DEFB $18, $2E, $3E, $D6, $18, $02, $3E, $CE 12773 mark_2EB8: DEFB $F5, $CD, $02, $0C, $06, $1E, $3D, $FE 12774 mark_2EC0: DEFB $06, $30, $19, $CB, $3F, $67, $28, $02 12775 mark_2EC8: DEFB $3E, $01, $F5, $9F, $6F, $CB, $8C, $25 12776 mark_2ED0: DEFB $22, $7B, $40, $CD, $1F, $2E, $06, $1F 12777 mark_2ED8: DEFB $F1, $32, $14, $23, $78, $ED, $47, $F1 12778 mark_2EE0: DEFB $2A, $71, $0D, $85, $6F, $E9, $57, $3A 12779 mark_2EE8: DEFB $39, $40, $E6, $80, $C3, $6C, $2B, $7A 12780 mark_2EF0: DEFB $D1, $D9, $E5, $D5, $C5, $2A, $0C, $23 12781 mark_2EF8: DEFB $87, $30, $0B, $2A, $0E, $23, $CB, $77 12782 mark_2F00: DEFB $28, $04, $2A, $15, $23, $3F, $EB, $6F 12783 mark_2F08: DEFB $26, $00, $9F, $4F, $3A, $7B, $40, $2F 12784 mark_2F10: DEFB $FD, $A6, $7C, $A9, $4F, $29, $29, $19 12785 mark_2F18: DEFB $06, $08, $D9, $D5, $C9, $FD, $35, $39 12786 mark_2F20: DEFB $3E, $18, $90, $47, $87, $87, $87, $6F 12787 mark_2F28: DEFB $3A, $18, $23, $95, $D8, $3E, $21, $91 12788 mark_2F30: DEFB $4F, $26, $00, $29, $09, $ED, $4B, $08 12789 mark_2F38: DEFB $23, $09, $CD, $EF, $2E, $01, $22, $00 12790 mark_2F40: DEFB $D9, $79, $AE, $D9, $77, $09, $D9, $23 12791 mark_2F48: DEFB $10, $F7, $C3, $9A, $29, $CD, $D9, $2D 12792 mark_2F50: DEFB $C3, $F6, $02, $CD, $02, $0C, $C0, $3D 12793 mark_2F58: DEFB $FA, $69, $08, $CD, $1F, $2E, $CD, $E7 12794 mark_2F60: DEFB $02, $3A, $18, $23, $47, $2A, $08, $23 12795 mark_2F68: DEFB $AF, $5F, $D3, $FB, $3E, $7F, $DB, $FE 12796 mark_2F70: DEFB $0F, $D2, $86, $08, $DB, $FB, $87, $FA 12797 mark_2F78: DEFB $AD, $2F, $30, $F0, $0E, $20, $C5, $4E 12798 mark_2F80: DEFB $06, $08, $CB, $01, $1F, $B3, $57, $DB 12799 mark_2F88: DEFB $FB, $1F, $30, $FB, $7A, $D3, $FB, $10 12800 mark_2F90: DEFB $F1, $23, $C1, $0D, $20, $E8, $23, $23 12801 mark_2F98: DEFB $3E, $03, $B8, $38, $02, $5F, $1D, $DB 12802 mark_2FA0: DEFB $FB, $1F, $30, $FB, $7B, $D3, $FB, $10 12803 mark_2FA8: DEFB $C3, $3E, $04, $D3, $FB, $C3, $07, $02 12804 mark_2FB0: DEFB $FB, $10, $C3, $3E, $0A, $12, $A0, $13 12805 mark_2FB8: DEFB $23, $15, $A4, $16, $23, $40, $C1, $60 12806 mark_2FC0: DEFB $08, $61, $2D, $75, $06, $76, $23, $01 12807 mark_2FC8: DEFB $0A, $54, $02, $85, $C1, $7F, $73, $80 12808 mark_2FD0: DEFB $2D, $8D, $50, $8E, $2D, $E3, $C3, $E4 12809 mark_2FD8: DEFB $0E, $E5, $2D, $13, $00, $75, $01, $E6 12810 mark_2FE0: DEFB $0A, $55, $0D, $1E, $0F, $1E, $16, $20 12811 mark_2FE8: DEFB $10, $07, $11, $08, $18, $C0, $35, $EE 12812 mark_2FF0: DEFB $36, $55, $37, $C6, $AD, $E6, $AE, $2E 12813 mark_2FF8: DEFB $F2, $C3, $F3, $1D, $F4, $2F, $ED, $00 12814 ; 12815 #else 12816 ; G007 source code, reverse engineered. 12817 ; 12818 ; The ZX81 labels will have been generated already. 12819 ; No need to include ZX definitions: 12820 ; 12821 12822 12823 ;=============================== 12824 ; G007 Hi-Res graphics board for the ZX81 12825 ; 12826 ; Source code partially reverse-engineered. 12827 ; A work in progress... 12828 ; 12829 ; 2011-05-15 Assembles to create correct ROM image. 12830 ; 12831 ; Verifed by comparing the hex files, 12832 ; the known-good reference generated by 12833 ; 2048 defb statements containing the original bytes. 12834 ; 12835 ; The source code below is not guaranteed to create the ROM image 12836 ; exactly the way the original author had in mind, 12837 ; as I'm not him and I don't have the original source code. 12838 ; 12839 ; This file was created from a disassembly generated by the 12840 ; impressive VB81 emulator program. 12841 ; 12842 ; It was already know that the G007 switched out pages of 12843 ; the ZX81 BASIC ROM and patched in replacements from 12844 ; the G007 ROM and the ZX81's internal 1K (or 2K) RAM. 12845 ; This is a thrifty use of RAM that expansion RAM packs 12846 ; usually just disabled. 12847 ; 12848 ; Memory map: 12849 ; 12850 ; 0000-0FFF 12851 ; 2000-23FF 1K RAM inside ZX81, remapped here. 12852 ; 2400-27FF 1K RAM more RAM if ZX81 has a 2K RAM chip 12853 ; 2800-2FFF 2K G007 12854 ; 3000-3FFF Empty 12855 ; 4000-7FFF External RAM pack 12856 ; 12857 ; Patching: 12858 ; 12859 ; 2C00-2CFF (ROM) also appears at 0C00-0CFF 12860 ; 2000-20FF (RAM) also appears at 0000-00FF 12861 ; 2200-22FF (RAM) also appears at 0200-02FF 12862 ; 12863 ; The ROM patching is active all the time. 12864 ; The RAM patching is active only in hi-res mode. 12865 ; 12866 ; The patches didn't cover every modification needed, 12867 ; so one routine is copied from ROM to RAM and 12868 ; then individual bytes are modified there 12869 ; by the initialisation routine which also 12870 ; initialises some variables. 12871 ; 12872 ; Graphics routines: 12873 ; 12874 ; These have not yet been analysed. 12875 ; Bresenham's algorithm will be there is some form. 12876 ; 12877 ; Triangle-filling is a sophisticated feature, 12878 ; using 8-bit maths for a practical speed. 12879 ; 12880 ; Future enhancements 12881 ; 12882 ; Programmers may like to try writing faster routines, 12883 ; or adding more commands now that memory is cheap. 12884 ; 12885 ; The bit-mask array at $2D00 looks like this: 12886 ; 10000000 12887 ; 01000000 12888 ; 00100000 12889 ; 00010000 12890 ; 00001000 12891 ; 00000100 12892 ; 00000010 12893 ; 00000001 12894 ; 12895 ; and suggests that pixels 12896 ; may be plotted one at a time. 12897 ; When I wrote a triangle-filling algorithm for the Atom, 12898 ; I made frequent use of horizontal lines. 12899 ; I optimised these by working out the partially-filled 12900 ; bytes at the left and right sides, and writing 12901 ; whole bytes (of 8 pixels) between the partial bytes. 12902 ; This used two overlapping tables like so: 12903 ; 12904 ; 10000000 ; BIT_MASK_R 12905 ; 11000000 12906 ; 11100000 12907 ; 11110000 12908 ; 11111000 12909 ; 11111100 12910 ; 11111110 12911 ; 11111111 ; BIT_MASK_L 12912 ; 01111111 12913 ; 00111111 12914 ; 00011111 12915 ; 00001111 12916 ; 00000111 12917 ; 00000011 12918 ; 00000001 12919 ; 12920 ; This technique might be able to increase the triangle filling speed. 12921 ; 12922 ; A proper ellipse algorithm would also be welcome, 12923 ; not one of those approximations using polygons! 12924 ; 12925 ;=============================== 12926 ; Assembly was done by a very handy online tool: 12927 ; http://k1.dyndns.org/cgi-bin/zasm.cgi 12928 ; which avoids the chore of installing it 12929 ; on one's own machine. 12930 ; The online tool is limited to one source file and 12931 ; one include file, but that's not a big deal 12932 ; for a tiny 2K ROM like this one. 12933 ; 12934 ;=============================== 12935 ; Problems 12936 ; The G007 ROM had several instances of opcdoes 12937 ; beginning with FD CB 12938 ; involving the Y register. 12939 ; VB81 disassembled them into statements 12940 ; that looked mangled and would not re-assemble. 12941 ; So I've just added them with defb statements. 12942 ; 12943 ; 12944 ;=============================== 12945 ; Global constants: 12946 ;=============================== 12947 FALSE equ 0 12948 NOT_G007 equ FALSE 12949 12950 12951 12952 ;=============================== 12953 ; ZX81 constants: 12954 ;=============================== 12955 ; ZX characters (not the same as ASCII) 12956 ;------------------------------- 12957 ZX_EQU equ $14 12958 ZX_COMMA equ $1A 12959 ZX_THEN equ $DE 12960 ZX_TO equ $DF 12961 ZX_INV_K equ $B0 12962 ZX_NEWLINE equ $76 12963 HRG_BYTES_PER_LINE equ 34 12964 ALL_BITS_SET equ -1 12965 ;------------------------------- 12966 ; tokens 12967 ;------------------------------- 12968 _CLASS_00 equ 0 12969 _CLASS_01 equ 1 12970 _CLASS_02 equ 2 12971 _CLASS_03 equ 3 12972 _CLASS_04 equ 4 12973 _CLASS_05 equ 5 12974 _CLASS_06 equ 6 12975 ;=============================== 12976 ; ZX81 I/O locations: 12977 ;=============================== 12978 IO_PORT_KEYBOARD_RD equ $FE ; A0 low 12979 ZX_NMI_GEN equ $FD ; A1 low 12980 ZX_PRINTER_PORT equ $FB ; A2 low 12981 ;=============================== 12982 ; ZX81 RAM variables 12983 ;=============================== 12984 RAMBASE equ $4000 12985 ERR_NR equ $4000 12986 FLAGS equ $4001 12987 ERR_SP equ $4002 12988 RAMTOP equ $4004 12989 MODE equ $4006 12990 PPC equ $4007 12991 VERSN equ $4009 12992 E_PPC equ $400A 12993 D_FILE equ $400C 12994 DF_CC equ $400E 12995 VARS equ $4010 12996 DEST equ $4012 12997 E_LINE equ $4014 12998 CH_ADD equ $4016 12999 X_PTR equ $4018 13000 STKBOT equ $401A 13001 STKEND equ $401C 13002 BERG equ $401E 13003 MEM equ $401F 13004 UNUSED_8 equ $4021 13005 G007_FLAG_Y equ UNUSED_8 ; 13006 13007 DF_SZ equ $4022 13008 S_TOP equ $4023 13009 LAST_K equ $4025 13010 DEBOUNCE equ $4027 13011 MARGIN equ $4028 13012 NXTLIN equ $4029 13013 NXT_LINE equ $4029 13014 OLDPPC equ $402B 13015 FLAGX equ $402D 13016 13017 STRLEN equ $402E 13018 T_ADDR equ $4030 13019 SEED equ $4032 13020 FRAMES equ $4034 13021 COORDS equ $4036 13022 PR_CC equ $4038 13023 S_POSN equ $4039 13024 S_POSN_hi equ S_POSN+1 13025 CDFLAG equ $403B 13026 PRBUFF equ $403C 13027 MEMBOT equ $407B 13028 PROGRAM equ $407D 13029 UNUSED_16 equ $407B 13030 UNUSED_16_hi equ UNUSED_16+1 13031 13032 G007_RESTART equ UNUSED_16 13033 13034 ; First byte after system variables: 13035 USER_RAM equ $407D 13036 MAX_RAM equ $7FFF 13037 13038 ;=============================== 13039 ; ZX BASIC ROM addresses 13040 ;=============================== 13041 ; restart constants 13042 START equ $0000 ; = 0 13043 ERROR_1 equ $0008 ; = 8 13044 PRINT_A equ $0010 ; = 16 13045 GET_CHAR equ $0018 ; = 24 13046 TEST_SP equ $001C ; = 28 13047 NEXT_CH equ $0020 ; = 32 13048 FP_CALC equ $0028 ; = 40 13049 ;------------------------------- 13050 L0108 equ $0108 13051 SLOW_FAST equ $0207 ; 13052 DISPLAY_5 equ $02B5 ; 13053 L029D equ $029D ; Inside the 'LOC_ADDR' subroutine 13054 SET_FAST equ $02E7 13055 LOAD equ $0340 13056 LIST equ $0730 13057 COPY equ $0869 13058 SAVE equ $02F6 13059 NEW equ $03C3 13060 LLIST equ $072C 13061 PRINT_CH equ $07F1 ; old, replaced 13062 L0809 equ $0809 13063 LOC_ADDR equ $0918 13064 ONE_SPACE equ $099B 13065 MAKE_ROOM equ $099E 13066 LINE_ADDR equ $09D8 13067 E_LINE_NO equ $0A73 13068 L0A95 equ $0A95 ; []*BIOS ROM*. Part way into 088A COPY_CONT 13069 PRINT equ $0ACF 13070 CLS equ $0A2A 13071 RECLAIM_1 equ $0A5D 13072 LPRINT equ $0ACB 13073 PRINT equ $0ACF 13074 PLOT_UNPLOT equ $0BAF 13075 L0BB2 equ $0BB2 ; 13076 STK_TO_A equ $0C02 13077 SCROLL equ $0C0E 13078 13079 ;------------------------------- 13080 ; Parameter table addresses: 13081 ; Checked in ROM disassembly book: 13082 ;------------------------------- 13083 P_LET equ $0C48 13084 P_GOTO equ $0C4B 13085 P_IF equ $0C4F 13086 P_GOSUB equ $0C54 13087 P_STOP equ $0C58 13088 P_RETURN equ $0C5B 13089 P_FOR equ $0C5E 13090 P_NEXT equ $0C66 13091 P_PRINT equ $0C6A 13092 P_INPUT equ $0C6D 13093 P_DIM equ $0C71 13094 P_REM equ $0C74 13095 P_NEW equ $0C77 13096 P_RUN equ $0C7A 13097 P_LIST equ $0C7D 13098 P_POKE equ $0C80 13099 P_RAND equ $0C86 13100 P_LOAD equ $0C89 13101 P_SAVE equ $0C8C 13102 P_CONT equ $0C8F 13103 P_CLEAR equ $0C92 13104 P_CLS equ $0C95 13105 13106 P_PLOT equ $0C98 ; redefined in G007 patch 13107 P_UNPLOT equ $0C9E ; redefined in G007 patch 13108 P_SCROLL equ $0CA4 13109 13110 P_PAUSE equ $0CA7 13111 ;P_SLOW equ $0CAB 13112 ;P_FAST equ $0CAE 13113 ;P_COPY equ $0CB1 13114 ;P_LPRINT equ $0CB4 13115 ;P_LLIST equ $0CB7 13116 ;------------------------------- 13117 13118 STOP equ $0CDC ; defined in this file 13119 13120 REM equ $0D6A 13121 INPUT_RE equ $0D6F 13122 13123 REPORT_C equ $0D9A ; according to the book 13124 REPORT_C_007 equ $0D26 ; seems the right one 13125 SYNTAX_Z equ $0DA6 13126 IF equ $0DAB 13127 FOR equ $0DB9 13128 13129 NEXT equ $0E2E 13130 RAND equ $0E6C 13131 CONT equ $0E7C 13132 GOTO equ $0E81 13133 POKE equ $0E92 13134 L0EA8 equ $0EA8 ; Inside the 'FIND_INT.' subroutine 13135 REPORT_B equ $0EAD 13136 ; check this!!! 13137 RUN equ $0EAF 13138 CLEAR_007 equ $0EB2 ; goes to JP CLEAR 13139 GOSUB equ $0EB5 13140 RETURN equ $0ED8 13141 INPUT equ $0EE9 13142 13143 FAST equ $0F23 13144 SLOW equ $0F2B 13145 PAUSE equ $0F32 13146 13147 DIM equ $1409 13148 CLEAR equ $149A 13149 SET_MEM equ $14BC 13150 13151 13152 ;=============================== 13153 ; G007 Memory patch addresses 13154 ;=============================== 13155 ; These patches only appear in hi-res mode 13156 ; 13157 RAM_PATCH_0000 equ $0000 13158 RAM_PATCH_0200 equ $0200 13159 ROM_PATCH_0C00 equ $0C00 13160 ; 13161 ; Their aliases are always present: 13162 ; 13163 RAM_PATCH_2000 equ $2000 13164 RAM_PATCH_2200 equ $2200 13165 ;=============================== 13166 ; G007 Plot number notes (a work in prgress) 13167 ;=============================== 13168 ; N-1 13169 ; 13170 ; 76543 210 13171 ; ..... .00 Line in white. 13172 ; ..... .01 Line black. 13173 ; ..... .10 Line inverting. 13174 ; ..... .11 Line inverting, omit last pixel. 13175 ; 13176 ; ..... 0.. Absolute co-ordinates 13177 ; ..... 1.. Relative co-ordinates 13178 ; 13179 ; ....0 ... Line 13180 ; ....1 ... Single pixel 13181 ; 13182 ; .0100 ... Coarse dotted line 13183 ; .0101 ... Add 40: triangle, plain 13184 ; .1001.... Add 72: triangle, textured (not available in invert mode) 13185 ; .1000 ... Add 64: fine dotted line 13186 ; .1100 ... Add 96: chain dotted line 13187 ; 13188 ; Note that PLOT 12 and PLOT 16 miss out the pixel, so simply move the PLOT position. 13189 ; 13190 13191 13192 13193 13194 13195 ;=============================== 13196 ; G007 Byte constants 13197 ;=============================== 13198 13199 13200 13201 13202 13203 G007_INT_REG_VALUE_FOR_HI_RES_GRAPHICS equ $1F 13204 G007_INT_REG_VALUE_FOR_LO_RES_GRAPHICS equ $1E 13205 13206 ; Dec. Hex. Bytes System Variables: G007 13207 13208 ; 8448 2100 Reserved for user defined characters 13209 ; 8703 21FF 13210 ; 13211 ; 8704 2200 Another page, possibly 13212 ; 8959 22FF 13213 13214 ;=============================== 13215 ; G007 Byte constants 13216 ;=============================== 13217 MEM_PATCH_SIZE equ $0100 13218 ;=============================== 13219 ; G007 RAM variables 13220 ;=============================== 13221 13222 V2265 equ $2265 13223 V2264 equ $2264 13224 13225 ; Dec. Hex. Bytes System Variables: G007 13226 ; 8960 2300 2 Offset of hi-res display file, less 9, from the D-FILE variable 13227 ; 8962 2302 2 Not used 13228 ; 8964 2304 2 Start address of last line of lo-res display file 13229 13230 G007_DISPLAY_OFFSET_FROM_DFILE_LESS_9 equ $2300 ; conflict! 13231 13232 G007_UNUSED_2302 equ $2302 13233 G007_DISPLAY_ADDRESS_LO_RES_LAST_LINE equ $2304 13234 G007_DISPLAY_ADDRESS_LESS_9 equ $2306 ; 8966 2306 2 Start address of hi-res display file, less 9 (used for video) 13235 G007_DISPLAY_ADDRESS equ $2308 ; 8968 2308 2 Start address of hi-res display file 13236 G007_TRIANGLE_TEXTURE equ $230A ; 8970 230A 2 Bytes defining triangle texture 13237 G007_CHAR_TABLE_ADDR_0_63 equ $230C ; 8972 230C 2 Character table address for CHR$0-63 13238 G007_CHAR_TABLE_ADDR_128_159 equ $230E ; 8974 230E 2 Character table address for CHR$128-159 13239 G007_PLOT_ROUTINES_VECTOR equ $2310 ; 8976 2310 2 Vector for additional plot routines 13240 G007_FLAG_0 equ $2312 ; 8978 2312 3 * Various flags 13241 G007_FLAG_1 equ $2313 13242 G007_FLAG_2 equ $2314 13243 G007_USR_DEF_CHR_TAB_LESS_256 equ $2315 ; 8981 2315 2 Address of user-defined character table, less 256 13244 G007_READ_POINT_BYTE equ $2317 ; 8983 2317 1 Read-point byte. Non-zero if pixel is set. 13245 G007_DISPLAY_HEIGHT equ $2318 ; 8984 2318 1 * Display height, normally 192 13246 G007_FLAG_3 equ $2319 ; 8985 2319 1 Flags 13247 13248 ;G007_TEMP_WORD_0 equ $231C ; 13249 G007_TEMP_BYTE_0 equ $231A ; 9886 231A 7 Temporary variables for PLOT routine. 13250 G007_TEMP_BYTE_1 equ $231B 13251 13252 G007_TEMP_WORD_1 equ $231C ; 13253 ;G007_TEMP_BYTE_2 equ $231C 13254 ;G007_TEMP_BYTE_3 equ $231D 13255 13256 G007_TEMP_WORD_2 equ $231E ; 13257 G007_TEMP_BYTE_4 equ $231E 13258 G007_TEMP_BYTE_5 equ $231F 13259 13260 G007_TEMP_BYTE_6 equ $2320 13261 G007_OUT_OF_RANGE_FLAGS equ $2321 ; 8993 2321 1 Plot out of range flags. Bit 7 = latest statement 13262 G007_UNUSED equ $2322 ; 8994 2322 1 Not used 13263 G007_PLOT_X equ $2323 ; 8995 2323 2 X co-ordinate for PLOT. Signed 16-bit 13264 G007_PLOT_Y equ $2325 ; 8997 2325 2 Y co-ordinate for PLOT. Signed 16-bit 13265 G007_PLOT_X_PREVIOUS_N1 equ $2327 ; 8999 2327 8 X and Y co-ordinates for previous two statements 13266 G007_PLOT_Y_PREVIOUS_N1 equ $2329 13267 G007_PLOT_X_PREVIOUS_N2 equ $232B 13268 G007_PLOT_Y_PREVIOUS_N2 equ $232D 13269 G007_FLAG_4 equ $232F ; 9007 232F 1 Flags 13270 G007_ORIGIN_Y equ $2330 ; 9008 2330 2 Y co-ordinate of graphics origin 13271 G007_ORIGIN_X equ $2332 ; 9010 2332 2 X co-ordinate of graphics origin 13272 G007_LINE_TYPE equ $2334 ; 9012 2334 4 Bytes defining four line types 13273 G007_TEMP_BYTE_7 equ $2338 ; 9016 2338 2 Temporary variable for PLOT 13274 G007_TEMP_BYTE_8 equ $2339 ; 13275 G007_V23A0 equ $23A0 13276 ;=============================== 13277 ; G007 RAM routines 13278 ;=============================== 13279 ; Yes, there is such a thing! 13280 L23B8 equ $23B8 13281 ;=============================== 13282 ; G007 ROM routines 13283 ;=============================== 13284 L2BF7 equ $2BF7 ; invalid opcode address 13285 SLOW_FAST_007 equ $2D08 ; new! 13286 ;=============================== 13287 ; Needed by zasm: 13288 #target rom ; declare target file format 13289 #code $2800,$0800 ; declare code segment start and size 13290 ; 13291 ;=============================== 13292 ; G007 ROM assembly code 13293 ;=============================== 13294 ; Start of ROM contents; 13295 ; 10240/12287 : 2800/2FFF 13296 ;=============================== 13297 G007_GET_PIXEL_ADDRESS_AND_MASK: ; 13298 LD HL,(G007_PLOT_X) ; X co-ordinate for PLOT. Signed 16-bit. Fetch 16 bits 13299 L2803: 13300 LD A,(G007_PLOT_Y) ; Y co-ordinate for PLOT. Signed 16-bit. Fetch 8 bits 13301 LD H,A ; and store in H 13302 L2807: 13303 EX DE,HL ; then swap it into D 13304 LD A,(G007_DISPLAY_HEIGHT) 13305 DEC A; 13306 SUB D ; 13307 LD D,A 13308 LD A,7 ; A must be 0 to 7 13309 AND A,E ; E is the LS byte of the X co-ordinate 13310 LD L,A ; L = A = selects bit-mask 13311 LD H,$2D ; bit-mask array is at $2D00 13312 LD A,(HL) ; get byte with bit set at appropriate position 13313 13314 LD HL,(G007_DISPLAY_ADDRESS) ; Start address of hi-res display file 13315 ;------------------------------- 13316 ; Add two bytes for every line 13317 ; 13318 LD C,D ; BC = Y coordinate 13319 LD B,0 13320 ADD HL,BC ; HL += BC*2 13321 ADD HL,BC 13322 ;------------------------------- 13323 ; DE /= 8 gets byte offset from left of screen 13324 ; 13325 SRL D ; shift DE right 13326 RR E 13327 SRL D ; shift DE right 13328 RR E 13329 SRL D ; shift DE right 13330 RR E 13331 13332 ADD HL,DE ; HL = G007_DISPLAY_ADDRESS + byte offset of XY-co-ordinates 13333 LD B,A ; A and B hold the bitmask 13334 RET ; return 13335 ;=============================== 13336 L282C: 13337 LD A,(G007_OUT_OF_RANGE_FLAGS) ; Plot out of range flags. Bit 7 = latest statement 13338 13339 LD HL,(G007_PLOT_X_PREVIOUS_N1) 13340 LD DE,(G007_PLOT_X) ; X co-ordinate for PLOT. Signed 16-bit 13341 13342 EXX 13343 13344 LD HL,(G007_PLOT_Y) 13345 LD DE,(G007_PLOT_Y_PREVIOUS_N1) 13346 13347 ; test two most recent out-of-range flag bits: 13348 BIT 6,A 13349 JR Z,L285E 13350 BIT 7,A 13351 RET NZ 13352 13353 LD A,(G007_FLAG_Y); 13354 PUSH AF 13355 LD B,8 13356 ;------------------------------- 13357 loop_284B: 13358 RRCA 13359 13360 ;284C FD;CB;21;16 LD C,SLA (IY+CH_ADD-RAMBASE) output from VB81 disassembler 13361 13362 #if 1 13363 RL (IY+G007_FLAG_Y-RAMBASE) ; makes FD CB 21 16 - correct! 13364 #else ; force bytes 13365 defb $FD 13366 defb $CB 13367 defb $21 13368 defb $16 13369 #endif 13370 DJNZ loop_284B 13371 ;------------------------------- 13372 EX DE,HL 13373 EXX 13374 EX DE,HL 13375 EXX 13376 CALL L285E 13377 POP AF 13378 LD (G007_FLAG_Y),A; 13379 RET 13380 ;=============================== 13381 L285E: 13382 LD BC,-HRG_BYTES_PER_LINE ; NB negative number = $FFDE 13383 LD A,(G007_DISPLAY_HEIGHT) 13384 DEC A 13385 SUB E 13386 SBC HL,DE 13387 JP P,L2876 13388 ;------------------------------- 13389 LD BC,HRG_BYTES_PER_LINE 13390 LD A,E 13391 13392 PUSH DE 13393 ADD HL,DE 13394 EX DE,HL 13395 OR A,A 13396 SBC HL,DE 13397 POP DE 13398 ;------------------------------- 13399 L2876: 13400 PUSH HL 13401 LD H,E 13402 LD E,A 13403 EXX 13404 13405 LD BC,L28FB 13406 LD A,L 13407 EXX 13408 LD L,A 13409 EXX 13410 OR A,A 13411 SBC HL,DE 13412 JP P,L2890 ; [10384] 13413 ;------------------------------- 13414 LD BC,L2904 13415 CPL 13416 ADD HL,DE 13417 EX DE,HL 13418 OR A,A 13419 SBC HL,DE 13420 L2890: 13421 LD (G007_TEMP_BYTE_0),BC ; Temporary variables for PLOT routine. 13422 POP DE 13423 OR A,A 13424 SBC HL,DE 13425 ADD HL,DE 13426 JR NC,L28A4 13427 ;------------------------------- 13428 EX DE,HL 13429 13430 LD BC,L28F6 13431 EXX 13432 LD D,E 13433 LD E,A 13434 LD A,D 13435 EXX 13436 L28A4: 13437 LD (G007_TEMP_WORD_1),BC 13438 EXX 13439 LD D,A 13440 ;------------------------------- 13441 PUSH DE 13442 EXX 13443 POP BC 13444 ;------------------------------- 13445 LD A,(G007_OUT_OF_RANGE_FLAGS) ; Plot out of range flags. Bit 7 = latest statement 13446 CP $40 13447 JR NC,L28B6 13448 ;------------------------------- 13449 LD B,L ; BC = LE 13450 LD C,E 13451 ;------------------------------- 13452 L28B6: 13453 INC B 13454 INC C 13455 ;------------------------------- 13456 L28B8: 13457 SRL H 13458 JR C,L28BE 13459 13460 JR Z,L28C6 13461 ;------------------------------- 13462 L28BE: 13463 RR L 13464 SRL D 13465 RR E 13466 JR L28B8 13467 ;------------------------------- 13468 L28C6: 13469 LD D,L 13470 SRL L 13471 EXX 13472 PUSH BC 13473 CALL L2807 13474 POP DE 13475 LD A,(G007_TEMP_BYTE_5) 13476 LD C,A 13477 ;------------------------------- 13478 L28D3: 13479 ; Bytes from disassembler: 13480 ;28D3 FD;CB;21;06 LD C,SLA (IY+6) 13481 #if 1 13482 RLC (IY+G007_FLAG_Y-RAMBASE) ; makes FD CB 21 06 13483 #else 13484 ; force bytes 13485 defb $FD 13486 defb $CB 13487 defb $21 13488 defb $06 13489 #endif 13490 13491 JR C,L28E1 13492 ;------------------------------- 13493 LD A,(G007_TEMP_BYTE_4) 13494 XOR A,(HL) 13495 OR A,C 13496 AND A,B 13497 XOR A,(HL) 13498 LD (HL),A 13499 ;------------------------------- 13500 L28E1: 13501 EXX 13502 13503 LD A,L 13504 DEC B 13505 RET Z 13506 ;------------------------------- 13507 SUB E 13508 JR NC,L28F2 13509 ;------------------------------- 13510 DEC C 13511 RET Z 13512 ;------------------------------- 13513 ADD A,D 13514 EXX 13515 ADD HL,DE 13516 EXX 13517 LD HL,(G007_TEMP_BYTE_0) ; Temporary variables for PLOT routine. 13518 JP (HL) 13519 ;------------------------------- 13520 L28F2: 13521 LD HL,(G007_TEMP_WORD_1) 13522 JP (HL) 13523 ;------------------------------- 13524 L28F6: 13525 LD L,A 13526 EXX 13527 ADD HL,DE 13528 JR L28D3 13529 ;------------------------------- 13530 L28FB: 13531 LD L,A 13532 EXX 13533 RLC B 13534 JR NC,L28D3 13535 ;------------------------------- 13536 DEC HL 13537 JR L28D3 13538 ;------------------------------- 13539 L2904: 13540 LD L,A 13541 EXX 13542 13543 RRC B 13544 JR NC,L28D3 13545 ;------------------------------- 13546 INC HL 13547 JR L28D3 13548 ;------------------------------- 13549 G007_INTEGER_FROM_STACK_TO_BC: 13550 LD HL,(L0EA8) ; Inside the 'FIND_INT.' subroutine 13551 ; 0EA7 FIND_INT CALL 158A,FP_TO_BC 13552 ; so 0EA8 should contain $158A, pointing to the FP_TO_BC routine 13553 JP (HL) ; exit 13554 ;=============================== 13555 G007_INTEGER_FROM_STACK_TO_HL: 13556 CALL G007_INTEGER_FROM_STACK_TO_BC ; get an integer 13557 JR C,L2924 13558 ;------------------------------- 13559 LD HL,0 13560 JR Z,L2921 13561 ;------------------------------- 13562 SBC HL,BC ; HL = 0 - BC 13563 RET M 13564 RET Z 13565 ;------------------------------- 13566 JR L2924 13567 ;------------------------------- 13568 L2921: 13569 ADC HL,BC 13570 RET P 13571 ;------------------------------- 13572 L2924: 13573 POP HL 13574 RET 13575 ;=============================== 13576 ; 13577 G007_PLOT_UNPLOT_N_X_Y: ; takes parameters from the stack 13578 ; 13579 CALL G007_INTEGER_FROM_STACK_TO_HL ; get Y 13580 LD (G007_PLOT_Y),HL 13581 CALL G007_INTEGER_FROM_STACK_TO_HL ; get X 13582 PUSH HL 13583 CALL STK_TO_A ; get N 13584 ; 13585 POP BC ; BC = X 13586 LD DE,(G007_PLOT_Y) ; DE = Y 13587 JR Z,G007_PLOT ; 13588 DEC A ; if (N-1) is zero 13589 RET NZ 13590 ;------------------------------- 13591 LD HL,L0C9C ; then T_ADDR = HL = L0C9C 13592 LD (T_ADDR),HL ; 13593 ;------------------------------- 13594 L2942: 13595 LD B,E 13596 JP L0BB2 ; []*BIOS ROM* 13597 ;=============================== 13598 ; The Plot Routine: 13599 ; A == the plot number N 13600 ; BC == screen X 13601 ; DE == screen Y 13602 ;------------------------------- 13603 G007_PLOT: 13604 OR A,A 13605 JR Z,L2942 13606 ;------------------------------- 13607 DEC A ; when PLOT N value is decremented, bits make more sense 13608 ;------------------------------- 13609 PUSH DE ; push screen Y 13610 PUSH BC ; push screen X 13611 PUSH AF ; push plot number-1 13612 13613 CALL G007_CHECK_AND_SET_UP_DISPLAY_FILE 13614 13615 POP AF 13616 POP DE 13617 POP BC ; NB BC and DE are swapped 13618 ;------------------------------- 13619 CP $81 ; Was A=129 (PLOT 130 sets graphics origin) 13620 JR NZ,G007_PLOT_XY_TO_HISTORY 13621 13622 ;------------------------------- 13623 G007_ORIGIN_SET: 13624 ; 13625 LD (G007_ORIGIN_Y),DE ; Y co-ordinate of graphics origin 13626 LD (G007_ORIGIN_X),BC ; X co-ordinate of graphics origin 13627 LD BC,$0000 ; BC = 0 13628 LD D,B ; DE = BC = 0 13629 LD E,B 13630 LD A,$0B 13631 13632 ;------------------------------- 13633 G007_PLOT_XY_TO_HISTORY: 13634 ; 13635 BIT 2,A; ; the (PLOT_N -1) 13636 JR Z,G007_PLOT_ABSOLUTE 13637 13638 ;------------------------------- 13639 G007_PLOT_RELATIVE: ; 13640 LD HL,(G007_PLOT_Y_PREVIOUS_N1) 13641 PUSH HL 13642 LD HL,(G007_PLOT_X_PREVIOUS_N1) 13643 JR G007_PLOT_ABSOLUTE_OR_RELATIVE 13644 ;=============================== 13645 G007_PLOT_ABSOLUTE: 13646 LD HL,(G007_ORIGIN_X) ; X co-ordinate of graphics origin 13647 PUSH HL 13648 LD HL,(G007_ORIGIN_Y) ; Y co-ordinate of graphics origin 13649 ;------------------------------- ; 13650 ; 13651 G007_PLOT_ABSOLUTE_OR_RELATIVE: ; 13652 OR A,A ; update flags 13653 ADC HL,DE ; HL = G007_PLOT_Y + G007_ORIGIN_Y 13654 POP DE ; DE = G007_PLOT_X co-ordinate of graphics origin 13655 RET PE 13656 ;------------------------------- 13657 LD (G007_PLOT_X),HL ; record plot X 13658 EX DE,HL 13659 OR A,A ; restore Flags 13660 ADC HL,BC ; HL = G007_PLOT_X + G007_ORIGIN_X 13661 RET PE 13662 ;------------------------------- 13663 LD (G007_PLOT_Y),HL ; record plot Y 13664 LD E,A 13665 LD A,%11000000 ; $C0 13666 AND A,H ; 13667 RET PO; 13668 ;------------------------------- 13669 LD A,%11000000 ; $C0 13670 AND A,D 13671 RET PO 13672 ;------------------------------- ; push alternate HL,DE,BC 13673 EXX 13674 PUSH HL 13675 PUSH DE 13676 PUSH BC 13677 CALL G007_RANGE_CHECK 13678 ;------------------------------- ; pop alternate BC,DE,HL 13679 L299A: 13680 POP BC 13681 POP DE 13682 POP HL 13683 EXX 13684 RET 13685 ;=============================== 13686 G007_RANGE_CHECK: 13687 EXX 13688 LD A,H ; A = H OR D 13689 OR A,D 13690 SCF 13691 JR NZ,G007_RANGE_CHECK_UPDATE ; if not zero, out of range already so ignore display height 13692 ;------------------------------- 13693 LD A,(G007_DISPLAY_HEIGHT) ; check Y coordinate 13694 DEC A ; if (G007_DISPLAY_HEIGHT - Y ) is less than zero, 13695 CP L ; set the Carry flag 13696 ;------------------------------- 13697 G007_RANGE_CHECK_UPDATE: ; latest flag in Carry is shifted into history flags 13698 LD A,(G007_OUT_OF_RANGE_FLAGS) ; 13699 RRA ; shift bits right. Bit 7 = latest statement 13700 LD (G007_OUT_OF_RANGE_FLAGS),A ; 13701 LD A,E ; E bit 7 13702 BIT 7,A 13703 JR Z,L29BA 13704 ;------------------------------- ; gets here if PLOT_N is over 130 13705 LD HL,(G007_PLOT_ROUTINES_VECTOR) ; Vector for additional plot routines 13706 JP (HL) ; This looks very promising, 13707 ; makes it easy to bolt-on extra graphics routines 13708 ;=============================== 13709 L29BA: 13710 PUSH AF 13711 AND 3 13712 RRA 13713 DEC A 13714 CPL 13715 LD H,A 13716 SBC A,A 13717 LD L,A 13718 LD (G007_TEMP_WORD_2),HL 13719 PUSH HL 13720 BIT 3,E 13721 JR NZ,L29F3 13722 ;------------------------------- 13723 LD A,(G007_TEMP_BYTE_6) 13724 XOR A,E 13725 AND %11111011 ; $FB. Bit 2 ignored 13726 JR Z,L29E2 13727 ;------------------------------- 13728 LD HL,G007_LINE_TYPE 13729 LD A,E 13730 ;------------------------------- ; A *= 8 13731 RLCA 13732 RLCA 13733 RLCA 13734 ;------------------------------- 13735 AND $03 13736 ADD A,L 13737 LD L,A 13738 LD A,(HL) 13739 LD (G007_FLAG_Y),A; 13740 ;------------------------------- 13741 L29E2: 13742 CALL L282C; 13743 POP HL 13744 13745 ;------------------------------- 13746 ; Bytes from disassembler: 29E6 FD;CB;21;0E LD C,SLA (IY+14) 13747 13748 RRC (IY+G007_FLAG_Y-RAMBASE) ; makes FD CB 21 0E 13749 JR C,L2A12 13750 ;=============================== 13751 LD A,H ; A = H and L 13752 AND A,L 13753 JR Z,L2A12 13754 ;------------------------------- 13755 INC L 13756 LD E,L 13757 PUSH HL 13758 ;------------------------------- 13759 L29F3: 13760 LD A,(G007_OUT_OF_RANGE_FLAGS) ; Bit 7 = latest statement 13761 BIT 5,E 13762 JR NZ,G007_TRIANGLE_PLAIN 13763 ;------------------------------- 13764 BIT 6,E 13765 JR NZ,G007_TRIANGLE_TEXTURED 13766 ;------------------------------- 13767 POP HL 13768 BIT 7,A 13769 JR NZ,L2A12 13770 ;------------------------------- 13771 PUSH HL 13772 CALL G007_GET_PIXEL_ADDRESS_AND_MASK 13773 AND A,(HL) 13774 LD (G007_READ_POINT_BYTE),A ; "Read-point" byte. Non-zero if pixel is set. 13775 POP DE 13776 LD A,(HL) 13777 OR A,D 13778 XOR A,E 13779 AND A,B 13780 XOR A,(HL) 13781 LD (HL),A 13782 ;------------------------------- 13783 L2A12: 13784 POP AF 13785 LD (G007_TEMP_BYTE_6),A 13786 LD HL,G007_PLOT_Y_PREVIOUS_N1+1 13787 LD DE,G007_PLOT_Y_PREVIOUS_N2+1 13788 LD BC,8 13789 BIT 4,A 13790 JR Z,L2A34 13791 ;------------------------------- 13792 LD A,(G007_OUT_OF_RANGE_FLAGS) ; Plot out of range flags. Bit 7 = latest statement 13793 AND $C0 ; only want most recent two bits 13794 RLA 13795 JR NC,L2A2D 13796 SET 6,A ; carry flag into bit 6 of A 13797 ;------------------------------- 13798 L2A2D: 13799 LD (G007_OUT_OF_RANGE_FLAGS),A 13800 LD L,$26 13801 LD C,4 13802 ;------------------------------- 13803 L2A34: 13804 LDDR ; (DE--)=(HL--); BC-- UNTIL BC IS ZERO 13805 RET 13806 ;=============================== 13807 G007_TRIANGLE_PLAIN: 13808 LD HL,ALL_BITS_SET 13809 JR G007_TRIANGLE_TEXTURED_BY_HL 13810 ;=============================== 13811 G007_TRIANGLE_TEXTURED: 13812 LD HL,(G007_TRIANGLE_TEXTURE) ; Bytes defining triangle texture 13813 ;------------------------------- 13814 G007_TRIANGLE_TEXTURED_BY_HL: 13815 EXX 13816 AND $E0 ; = 224 13817 JP NZ,REPORT_B; 13818 ;------------------------------- 13819 L2A45: 13820 LD HL,G007_OUT_OF_RANGE_FLAGS 13821 LD (IY+G007_FLAG_Y-RAMBASE),$55 13822 LD B,3 13823 ;------------------------------- 13824 loop_2A4E: 13825 INC HL ; HL+=2 13826 INC HL 13827 LD E,(HL) 13828 INC HL ; HL+=2 13829 INC HL 13830 LD D,(HL) 13831 PUSH DE 13832 DJNZ loop_2A4E ; BC-- 13833 ;------------------------------- 13834 POP BC ; restore register pairs 13835 POP DE 13836 POP HL 13837 ;------------------------------- 13838 OR A,A 13839 JR Z,L2A5F 13840 ;------------------------------- 13841 LD B,H ; BC=HL 13842 LD C,L 13843 ;------------------------------- 13844 L2A5F: 13845 LD A,B 13846 CP H 13847 JR NC,L2A66 13848 ;------------------------------- 13849 PUSH BC 13850 EX (SP),HL 13851 POP BC 13852 ;------------------------------- 13853 L2A66: 13854 LD A,H 13855 CP D 13856 JR NC,L2A6B 13857 ;------------------------------- 13858 EX DE,HL 13859 ;------------------------------- 13860 L2A6B: 13861 LD A,D 13862 EXX 13863 AND 7 13864 INC A 13865 LD B,A 13866 LD A,H 13867 ;------------------------------- 13868 loop_2A72: 13869 RLC L ; L *= 2 13870 ;------------------------------- 13871 RLCA ; A *= 8 13872 RLCA 13873 RLCA 13874 ;------------------------------- 13875 DJNZ loop_2A72 ; loop while BC-- is not zero 13876 ;------------------------------- 13877 LD H,A 13878 LD (G007_TEMP_BYTE_7),HL ; Temporary variable for PLOT 13879 EXX 13880 ;------------------------------- 13881 LD A,H 13882 CP B 13883 LD A,7 13884 JR NC,L2A87 13885 ;------------------------------- 13886 loop_2A84: 13887 PUSH BC 13888 EX (SP),HL 13889 POP BC 13890 ;------------------------------- 13891 L2A87: 13892 EX DE,HL 13893 PUSH AF 13894 LD A,C 13895 EXX 13896 LD H,A 13897 LD L,A 13898 LD C,A 13899 LD (G007_TEMP_BYTE_0),HL ; Temporary variables for PLOT routine. 13900 LD B,$FE 13901 EXX 13902 SUB E 13903 EXX 13904 ;------------------------------- 13905 JR NC,skip_2A9C 13906 LD B,$00 13907 NEG 13908 skip_2A9C: 13909 ;------------------------------- 13910 LD D,A 13911 EXX 13912 LD A,D 13913 SUB B 13914 EXX 13915 LD H,A 13916 ;------------------------------- 13917 CP D 13918 JR NC,skip_2AA7 13919 EX DE,HL 13920 INC B 13921 skip_2AA7: 13922 ;------------------------------- 13923 LD L,H 13924 INC L 13925 LD E,H 13926 SRL E 13927 13928 POP AF 13929 RRCA 13930 JR NC,L2AB9 13931 ;------------------------------- 13932 PUSH HL 13933 ;------------------------------- 13934 PUSH DE 13935 PUSH BC 13936 ;------------------------------- 13937 RRCA 13938 EXX 13939 ;------------------------------- 13940 JR C,loop_2A84 13941 JR L2A87 13942 ;=============================== 13943 L2AB9: 13944 EXX 13945 LD H,B 13946 LD L,1 13947 ;------------------------------- 13948 loop_2ABD: 13949 POP BC 13950 POP DE 13951 ;------------------------------- 13952 EX (SP),HL 13953 ;------------------------------- 13954 L2AC0: 13955 DEC L 13956 JR NZ,L2AD9 13957 ;------------------------------- 13958 LD HL,(G007_TEMP_BYTE_0) ; Temporary variables for PLOT routine. 13959 LD A,C 13960 ;------------------------------- 13961 CP H 13962 JR C,skip_2ACB 13963 LD H,A 13964 skip_2ACB: 13965 ;------------------------------- 13966 CP L 13967 JR NC,skip_2ACF 13968 LD L,A 13969 skip_2ACF: 13970 ;------------------------------- 13971 LD (G007_TEMP_BYTE_0),HL ; Temporary variables for PLOT routine. 13972 POP HL 13973 DEC L 13974 ;------------------------------- 13975 L2AD4: 13976 13977 JR Z,loop_2ABD 13978 13979 PUSH HL 13980 JR L2AEE 13981 ;------------------------------- 13982 L2AD9: 13983 LD A,E 13984 SUB D 13985 JR C,L2AE7 13986 ;------------------------------- 13987 LD E,A 13988 BIT 0,B 13989 JR Z,L2AEE 13990 ;------------------------------- 13991 LD A,C 13992 ADD A,B 13993 LD C,A 13994 JR L2AC0 13995 ;------------------------------- 13996 L2AE7: 13997 ADD A,H 13998 LD E,A 13999 LD A,1 14000 OR A,B 14001 ADD A,C 14002 LD C,A 14003 ;------------------------------- 14004 L2AEE: 14005 LD A,C 14006 EXX 14007 ;------------------------------- 14008 RRC (IY+G007_FLAG_Y-RAMBASE) ; makes FD CB 21 0E 14009 14010 JR C,L2AC0 ; if 14011 ;------------------------------- 14012 EX (SP),HL 14013 ;------------------------------- 14014 PUSH DE 14015 PUSH BC 14016 PUSH HL 14017 ;------------------------------- 14018 LD DE,(G007_TEMP_BYTE_0) 14019 LD B,A 14020 ;------------------------------- 14021 CP C 14022 JR NC,skip_2B04 14023 LD B,C 14024 LD C,A 14025 skip_2B04: 14026 ;------------------------------- 14027 LD (G007_TEMP_BYTE_0),BC 14028 LD A,C 14029 ;------------------------------- 14030 CP E 14031 INC A 14032 JR C,skip_2B0E 14033 LD A,E 14034 skip_2B0E: 14035 ;------------------------------- 14036 LD L,A 14037 LD A,D 14038 ;------------------------------- 14039 CP B 14040 JR NC,skip_2B15 14041 LD A,B 14042 DEC A 14043 skip_2B15: 14044 ;------------------------------- 14045 SUB L 14046 INC A 14047 PUSH AF 14048 CALL L2807 14049 14050 POP AF 14051 LD C,A 14052 EX DE,HL 14053 LD HL,G007_TEMP_BYTE_8 14054 LD A,(HL) 14055 ;------------------------------- 14056 RLCA 14057 RLCA 14058 RLCA 14059 ;------------------------------- 14060 LD (HL),A 14061 DEC HL 14062 RLC (HL) 14063 OR A,(HL) 14064 LD HL,(G007_TEMP_WORD_2) 14065 XOR A,L 14066 CPL 14067 LD L,A 14068 EX DE,HL 14069 ;------------------------------- 14070 loop_2B31: 14071 LD A,E 14072 XOR A,(HL) 14073 OR A,D 14074 AND A,B 14075 XOR A,(HL) 14076 LD (HL),A 14077 ;------------------------------- 14078 loop_2B37: 14079 DEC C 14080 JR NZ,L2B4E 14081 ;------------------------------- 14082 POP HL 14083 INC H 14084 BIT 7,L 14085 JR Z,L2AD4 14086 ;------------------------------- ; discard 3 words from stack 14087 POP HL 14088 POP HL 14089 POP HL 14090 ;------------------------------- 14091 POP HL 14092 LD A,H 14093 AND A,L 14094 JP Z,L2A12 14095 ;------------------------------- 14096 INC L 14097 PUSH HL 14098 JP L2A45 14099 ;------------------------------- 14100 L2B4E: 14101 RR B 14102 JR NC,loop_2B31 14103 ;------------------------------- 14104 INC HL 14105 LD B,C 14106 LD A,C 14107 AND $07 14108 LD C,A 14109 ;------------------------------- 14110 SRL B ; B *= 8 14111 SRL B 14112 SRL B 14113 ;------------------------------- 14114 JR Z,L2B68 14115 ;------------------------------- 14116 loop_2B60: 14117 LD A,E 14118 XOR A,(HL) 14119 OR A,D 14120 XOR A,(HL) 14121 LD (HL),A 14122 INC HL 14123 DJNZ loop_2B60 14124 ;------------------------------- 14125 L2B68: 14126 SCF 14127 INC C 14128 JR loop_2B37 14129 ;------------------------------- 14130 L2B6C: 14131 LD HL,(G007_FLAG_1) 14132 DEC L 14133 OR A,L 14134 JP NZ,L0809 ; iii) Testing S-POSN: 0808 ENTER-CH LD D,A 14135 ; G007 skips that first instruction though. 14136 ;------------------------------- 14137 14138 DEC H ; if --H, 14139 JP NZ,L23B8 ; then jump to modified copy of a ZX81 routine, in RAM. 14140 ;------------------------------- ; 14141 LD A,(G007_OUT_OF_RANGE_FLAGS) ; Plot out of range flags. Bit 7 = latest statement 14142 RLA 14143 RET C 14144 ;------------------------------- 14145 NOP 14146 NOP 14147 LD HL,(G007_PLOT_X_PREVIOUS_N1+1) 14148 LD A, (G007_PLOT_X_PREVIOUS_N1) 14149 BIT 6,D 14150 ;------------------------------- 14151 mark_2B87: 14152 JR NZ,L2B8E ; 20;05 14153 14154 LD L,A 14155 ADD A,8 14156 JR NC,L2B9B 14157 ;------------------------------- 14158 L2B8E: 14159 LD A,H 14160 ;------------------------------- 14161 SUB 8 14162 JR NC,skip_2B97 14163 LD A,(G007_DISPLAY_HEIGHT) 14164 DEC A 14165 skip_2B97: 14166 ;------------------------------- 14167 LD (G007_PLOT_Y_PREVIOUS_N1),A; 14168 XOR A,A ; A = 0 14169 ;------------------------------- 14170 L2B9B: 14171 LD (G007_PLOT_X_PREVIOUS_N1),A 14172 BIT 6,D 14173 RET NZ 14174 ;------------------------------- 14175 CALL L2EEF 14176 14177 LD A,L 14178 ;------------------------------- 14179 CP $F9 14180 JR C,skip_2BAB 14181 LD E,2 14182 skip_2BAB: 14183 ;------------------------------- 14184 CPL 14185 AND 7 14186 INC A 14187 LD D,A 14188 LD A,H 14189 INC A 14190 EXX 14191 14192 LD D,A 14193 EXX 14194 PUSH DE 14195 CALL L2807 14196 EXX 14197 ;------------------------------- 14198 L2BBA: 14199 LD A,C 14200 XOR A,(HL) 14201 EXX 14202 EX DE,HL 14203 LXXX: 14204 POP BC 14205 PUSH BC 14206 LD L,A 14207 LD H,$00 14208 ;------------------------------- 14209 loop_2BC3: 14210 ADD HL,HL 14211 DJNZ loop_2BC3 14212 ;------------------------------- 14213 EX DE,HL 14214 LD B,2 14215 ;------------------------------- 14216 L2BC9: 14217 LD A,(G007_RESTART); 14218 XOR A,(HL) 14219 OR A,(IY+G007_RESTART+1-RAMBASE) 14220 AND A,D 14221 XOR A,(HL) 14222 ;------------------------------- 14223 DEC C 14224 JR Z,skip_2BD6 14225 LD (HL),A 14226 skip_2BD6: 14227 ;------------------------------- 14228 LD D,E 14229 INC HL 14230 DJNZ L2BC9 14231 ;------------------------------- 14232 LD C,$20 14233 ADD HL,BC 14234 EXX 14235 INC HL 14236 ;------------------------------- 14237 DEC D 14238 JR Z,skip_2BE4 14239 ;------------------------------- 14240 DJNZ L2BBA 14241 ;------------------------------- 14242 skip_2BE4: 14243 ;------------------------------- 14244 POP HL 14245 JP L299A 14246 ;=============================== 14247 PRINT_007: 14248 LD A,I ; read graphics mode 14249 RRCA 14250 ;------------------------------- 14251 JR NC,skip_2BF5 14252 XOR A,A ; A = 0 14253 LD (DF_SZ),A ; SET DF_SZ 14254 INC A 14255 LD (G007_FLAG_1),A 14256 skip_2BF5: 14257 ;------------------------------- 14258 CALL PRINT ; [PRINT] 14259 XOR A,A ; A = 0 14260 LD (G007_FLAG_1),A 14261 LD (IY+DF_SZ-RAMBASE),2 ; The lines above have no return or jump statements 14262 ; They will fall into copy of the end of the STK_TO_BC routine 14263 ; Perhaps a cunning trick to save two bytes? :-) 14264 ;=============================== 14265 ;=============================== 14266 ;=============================== 14267 14268 org ROM_PATCH_0C00 14269 ; 14270 ; 256-byte block patched in to ZX81 BASIC at 0C00 hex 14271 ; This cleverly alters the language syntax, 14272 ; adding parameters and/or pointing to new routines. 14273 ; 14274 LD C,A ; from the end of the STK_TO_BC routine 14275 RET 14276 ;=============================== 14277 ; THE 'STK_TO_A' SUBROUTINE (duplicated for the paged ROM) 14278 14279 ; This subroutine 'loads' the A register with the floating point number held at the top of the calculator stack. The number must be in the range 00-FF. 14280 ;------------------------------- 14281 STK_TO_A: 14282 14283 #if NOT_G007 14284 ; CALL 15CD,FP_TO_A ; This is what the disassembly book says 14285 #else 14286 CALL L0CA0 ; new in G007 14287 #endif 14288 JP C,REPORT_B 14289 ;------------------------------- 14290 LD C,$01 14291 RET Z 14292 LD C,$FF 14293 RET 14294 ;=============================== 14295 14296 ; THE 'SCROLL' COMMAND ROUTINE (duplicated for the paged ROM) 14297 14298 ; The first part of the routine sets the correct values of DF_CC and S_POSN to allow for the next printing to occur at the start of the bottom line + 1. 14299 14300 ; Next the end address of the first line in the display file is identified and the whole of the display file moved to overwrite this line. 14301 ;------------------------------- 14302 14303 SCROLL: 14304 mark_0C0E: 14305 LD B,(IY+DF_SZ-RAMBASE) ; ??? Disassembly book says LD B,(DF_SZ) 14306 LD C,CHARS_HORIZONTAL + 1 ;change here, $21 originally 14307 CALL LOC_ADDR 14308 CALL ONE_SPACE 14309 LD A,(HL) 14310 LD (DE),A 14311 14312 INC (IY+S_POSN_hi-RAMBASE) ; 14313 14314 LD HL,(D_FILE); 14315 INC HL 14316 LD D,H 14317 LD E,L 14318 CPIR 14319 JP RECLAIM_1 14320 ;=============================== 14321 ; 14322 ; THE SYNTAX TABLES 14323 ; 14324 ; i) The offset table 14325 ; 14326 ; There is an offset value for each of the BASIC commands and by 14327 ; adding this offset to the value of the address where it is found, 14328 ; the correct address for the command in the parameter table is 14329 ; obtained. 14330 14331 ; 2C29: 8B 8D 2D 7F 81 49 75 14332 14333 mark_0C29: 14334 offset_t: 14335 14336 ; expression address byte offset expected 14337 defb P_LPRINT-$ ; 0CB4 $8B 14338 defb P_LLIST-$ ; 0CB1 ; $8D ; 14339 defb P_STOP-$ ; 0C58 ; $2D ; 14340 defb P_SLOW-$ ; 0CAB ; $7F ; 14341 defb P_FAST-$ ; 0CAE ; $81 ; 14342 defb P_NEW-$ ; 0C77 ; $49 ; 14343 defb P_SCROLL_007-$ ; 0CA4 ; $75 ; 14344 ; 2C30: 5F 40 42 2B 17 1F 37 52 14345 defb P_CONT-$ ; 0CBF ; $5F ; 14346 defb P_DIM-$ ; 0C71 ; $40 ; 14347 defb P_REM-$ ; 0C74 ; $42 ; 14348 defb P_FOR-$ ; 0C5E ; $2B ; 14349 defb P_GOTO-$ ; 0C4B ; $17 ; 14350 defb P_GOSUB-$ ; 0C54 ; $1F ; 14351 defb P_INPUT-$ ; 0C6D ; $37 ; 14352 defb P_LOAD-$ ; 0C89 ; $52 ; 14353 ; 2C38: 45 0F 6D 2B 44 2D 5A 3B 14354 defb P_LIST-$ ; 0C7D ; $45 ; 14355 defb P_LET-$ ; 0C48 ; $0F ; 14356 defb P_PAUSE-$ ; 0CA7 ; $6D ; 14357 defb P_NEXT-$ ; 0C66 ; $2B ; 14358 defb P_POKE-$ ; 0C80 ; $44 ; 14359 defb P_PRINT-$ ; 0C6A ; $2D ; Same as normal ZX81 14360 defb P_PLOT_007-$ ; 0C98 ; $5A ; 14361 defb P_RUN-$ ; 0C7A ; $3B ; 14362 ; 2C40: 4C 45 0D 52 54 4D 15 6A 14363 defb P_SAVE-$ ; 0C8C ; $4C ; 14364 defb P_RAND-$ ; 0C86 ; $45 ; 14365 defb P_IF-$ ; 0C4F ; $0D ; 14366 defb P_CLS-$ ; 0C95 ; $52 ; 14367 defb P_UNPLOT_007-$ ; 0C98 ; $54 ; This byte is 5A, an offset to 0C9E, in normal ZX81 14368 ; NB same address as PLOT 14369 defb P_CLEAR-$ ; 0C92 ; $4D ; 14370 defb P_RETURN-$ ; 0C5B ; $15 ; 14371 defb P_COPY-$ ; 0CB1 ; $6A ; 14372 ; 14373 ; ii) The parameter table. 14374 ; 14375 ; For each of the BASIC commands there are between 3 and 8 14376 ; entries in the parameter table. The command classes for each of 14377 ; the commands are given, together with the required separators and 14378 ; these are followed by the address of the appropriate routine. 14379 14380 14381 ; 2C48: 01 14 02 14382 mark_0C48: 14383 P_LET: 14384 defb _CLASS_01 ; A variable is required. 14385 defb ZX_EQU ; Separator: '=' 14386 defb _CLASS_02 ; An expression, numeric or string, 14387 ; must follow. 14388 14389 ; 244B: 06 00 81 0E 06 14390 14391 P_GOTO: 14392 mark_0C4B: 14393 defb _CLASS_06 ; A numeric expression must follow. 14394 defb _CLASS_00 ; No further operands. 14395 defw GOTO 14396 14397 14398 P_IF: 14399 mark_0C4F: 14400 defb _CLASS_06 ; A numeric expression must follow. 14401 mark_0C50 ; 2C50: DE 05 AB 0D 14402 defb ZX_THEN ; Separator: 'THEN' 14403 defb _CLASS_05 ; Variable syntax checked entirely 14404 ; by routine. 14405 defw IF 14406 14407 14408 P_GOSUB: ; mark_0C54: 14409 defb _CLASS_06 ; A numeric expression must follow. 14410 defb _CLASS_00 ; No further operands. 14411 defw GOSUB ; 0EB5 14412 14413 ; 2C58: 00 DC 0C 14414 14415 P_STOP: ; mark_0C58: 14416 ; 2C54: 06 00 B5 0E 14417 defb _CLASS_00 ; No further operands. 14418 defw STOP 14419 14420 ; 2c5B: 00 D8 0E 14421 14422 P_RETURN 14423 defb _CLASS_00 ; No further operands. 14424 defw RETURN 14425 14426 14427 ; 2c5e: 04 14 14428 14429 14430 P_FOR: 14431 #if 0 14432 mark_0C5E: 14433 #else 14434 #endif 14435 defb _CLASS_04 ; A single character variable must 14436 ; follow. 14437 defb ZX_EQU ; Separator: '=' 14438 defb _CLASS_06 ; A numeric expression must follow. 14439 defb ZX_TO ; Separator: 'TO' 14440 defb _CLASS_06 ; A numeric expression must follow. 14441 defb _CLASS_05 ; Variable syntax checked entirely 14442 ; by routine. 14443 defw FOR 14444 14445 ; 0C66: 04 00 2E 0E 14446 14447 P_NEXT: ; at $0C66: 14448 14449 defb _CLASS_04 ; A single character variable must follow. 14450 defb _CLASS_00 ; No further operands. 14451 defw NEXT 14452 14453 14454 ; 2C6A: 05 E8 2B 14455 14456 P_PRINT: 14457 14458 mark_0C6A: 14459 14460 14461 14462 defb _CLASS_05 ; Variable syntax checked entirely 14463 ; by routine. 14464 #if NOT_G007 14465 defw PRINT ; This is the original routine 14466 #else 14467 defw PRINT_007 ; 2BE8 This is the new routine! 14468 #endif 14469 14470 ; ; 2C6D: 01 00 E9 0E 14471 14472 14473 mark_0C6D: 14474 14475 14476 P_INPUT: 14477 defb _CLASS_01 ; A variable is required. 14478 defb _CLASS_00 ; No further operands. 14479 defw INPUT 14480 14481 P_DIM: 14482 mark_0C71: 14483 defb _CLASS_05 ; Variable syntax checked entirely 14484 ; by routine. 14485 #if NOT_G007 14486 defw DIM ; 1409 Original ZX81 replaced by 14487 #else 14488 defw DIM_007 ; 2EA7 new routine 14489 #endif 14490 ; 14491 ; ; 2c74: 05 6A 0D 14492 ; 14493 mark_0C74: 14494 P_REM: 14495 14496 defb _CLASS_05 ; Variable syntax checked entirely by routine. 14497 defw REM 14498 14499 mark_0C77: 14500 P_NEW: 14501 defb _CLASS_00 ; No further operands. 14502 defw NEW 14503 14504 P_RUN: 14505 mark_0C7A: 14506 14507 P_RUN: 14508 defb _CLASS_03 ; A numeric expression may follow 14509 ; else default to zero. 14510 defw RUN 14511 14512 P_LIST: 14513 #if 0 14514 mark_0C7D: 14515 #else 14516 #endif 14517 defb _CLASS_03 ; A numeric expression may follow 14518 ; else default to zero. 14519 defw LIST 14520 14521 P_POKE: ; mark_0C80: 14522 defb _CLASS_06 ; A numeric expression must follow. 14523 defb ZX_COMMA ; Separator: ',' 14524 defb _CLASS_06 ; A numeric expression must follow. 14525 defb _CLASS_00 ; No further operands. 14526 defw POKE 14527 14528 P_RAND: ; mark_0C86: 14529 defb _CLASS_03 ; A numeric expression may follow 14530 ; else default to zero. 14531 defw RAND 14532 14533 P_LOAD: ; mark_0C89: 14534 defb _CLASS_05 ; Variable syntax checked entirely 14535 ; by routine. 14536 defw LOAD 14537 14538 P_SAVE: ; mark_0C8C: 14539 defb _CLASS_05 ; Variable syntax checked entirely 14540 ; by routine. 14541 #if NOT_G007 14542 defw SAVE ; 02F6 original 14543 #else 14544 defw SAVE_007 ; 2F4D new! 14545 #endif 14546 ; 14547 P_CONT: 14548 #if 0 14549 #else 14550 #endif 14551 mark_0C8F: 14552 defb _CLASS_00 ; No further operands. 14553 defw CONT ; 0E7C 14554 ; 14555 P_CLEAR: ; mark_0C92: 14556 defb _CLASS_00 14557 #if NOT_G007 14558 defw CLEAR ; 149A original 14559 #else 14560 defw CLEAR_007 ; 0EB2 new. this points outside the G007 ROM 14561 #endif 14562 14563 14564 P_CLS: ; mark_0C95: 14565 #if NOT_G007 14566 defb _CLASS_00 ; No further operands. 14567 ;; defw CLS ; original 14568 #else 14569 defb _CLASS_03 ; A numeric expression may follow 14570 ; else default to zero. 14571 defw G007_CLS_N ; 2E4E new! 14572 #endif 14573 ; 14574 ; 14575 ; 14576 mark_0C98: 14577 14578 #if NOT_G007 14579 ; originally the ZX81 does this: 14580 P_PLOT: ; original: plot X,Y 14581 defb _CLASS_06 ; A numeric expression must follow. X 14582 defb ZX_COMMA ; Separator: ',' 14583 defb _CLASS_06 ; A numeric expression must follow. Y 14584 defb _CLASS_00 ; No further operands. 14585 defw PLOT_UNPLOT ; 0BAF 14586 14587 P_UNPLOT: ; original: plot X,Y 14588 defb _CLASS_06 ; A numeric expression must follow. X 14589 defb ZX_COMMA ; Separator: ',' 14590 defb _CLASS_06 ; A numeric expression must follow. Y 14591 defb _CLASS_00 ; No further operands. 14592 defw PLOT_UNPLOT ; 0BAF 14593 14594 ; These are identical, so they could overlap 14595 #else 14596 ; The G007 saves bytes by having these 14597 ; identical parameter table entries overlapping: 14598 ; 0C98 / 2C98: 06 1A 06 1A 06 00 26 29 14599 P_PLOT_007: 14600 P_UNPLOT_007: 14601 ; new: plot N,X,Y 14602 defb _CLASS_06 ; A numeric expression must follow. N 14603 defb ZX_COMMA ; Separator: ',' 14604 defb _CLASS_06 ; A numeric expression must follow. X 14605 defb ZX_COMMA ; Separator: ',' 14606 L0C9C: 14607 defb _CLASS_06 ; A numeric expression must follow. Y 14608 defb _CLASS_00 ; No further operands. 14609 defw G007_PLOT_UNPLOT_N_X_Y ; 2926 new! 14610 ; 14611 ; by saving those bytes, can put a tiny routine here: 14612 L0CA0: 14613 LD HL,(L0EA8) ; Inside the 'FIND_INT.' subroutine 14614 JP (HL) 14615 #endif 14616 ; 14617 ; Now back to the table! 14618 ; 14619 P_SCROLL_007 14620 mark_0CA4: 14621 defb _CLASS_00 14622 defw SCROLL ; 0C0E 14623 14624 14625 14626 P_PAUSE: 14627 defb _CLASS_06 14628 defb _CLASS_00 14629 #if NOT_G007 14630 mark_0CA9: 14631 ; 2CA9: 0F 32 14632 defw PAUSE ; 0F32 original 14633 #else 14634 mark_0CA9: 14635 ; 2CA9: AE 2E 14636 ; 0CA7 14637 defw PAUSE_007 ; 2EAE new! 14638 #endif 14639 ; 14640 ; 2CAB: 03 B2 2E 14641 ; 0CAB 14642 14643 14644 14645 P_SLOW: 14646 mark_0CAB: 14647 #if NOT_G007 14648 defb _CLASS_00 ; No further operands. 14649 defw SLOW ; 2B 0F SLOW,0F2B original 14650 #else 14651 defb _CLASS_03 ; new! Extra parameter sets graphic mode 14652 defw SLOW_007 ; 2EB2 new! 14653 #endif 14654 14655 14656 P_FAST: 14657 mark_0CAE: 14658 #if NOT_G007 14659 defb _CLASS_00 ; No further operands. 14660 defw FAST ; 23 0F FAST,0F23 original 14661 #else 14662 defb _CLASS_03 ; new! Extra parameter sets graphic mode 14663 defw FAST_007 ; 2EB6 new! 14664 #endif 14665 14666 14667 14668 14669 14670 14671 14672 14673 ; 14674 ; 2CB1: 03 53 2F 14675 ; 14676 ; 0CB1 14677 14678 P_COPY: 14679 #if NOT_G007 14680 defb _CLASS_00 ; original 14681 defw COPY ; 0869 original 14682 #else 14683 defb _CLASS_03 ; new! Extra parameter sets graphic mode 14684 ;;; defw COPY_007 ; 2EB6 new but wrong ???! 14685 defw L2F53 ; what the disassembler said 14686 #endif 14687 14688 mark_0CB4: 14689 14690 14691 P_LPRINT: 14692 14693 defb _CLASS_05 14694 defw LPRINT ; 0ACB 14695 ; 14696 ; ; 2CB7: 03 2C 07 14697 ; 0CB7 14698 P_LLIST: 14699 defb _CLASS_03 14700 defw LLIST ; 072C 14701 ; 14702 ; 14703 ; the rest of this page is just a copy of the usual ZX81 code 14704 14705 LINE_SCAN: 14706 L0CBA: 14707 ; 2CBA: FD 36 01 01 CD 73 14708 ; 2CC0: 0A CD 95 0A 21 00 40 36 14709 ; 2CC8: FF 21 2D 40 CB 6E 28 0E 14710 ; 2CD0: FE E3 7E C2 6F 0D CD A6 14711 ; 2CD8: 0D C8 CF 0C CF 08 DF 06 14712 ; 2CE0: 00 FE 76 C8 4F E7 79 D6 14713 ; 2CE8: E1 38 3B 4F 21 29 0C 09 14714 ; 2CF0: 4E 09 18 03 2A 30 40 7E 14715 ; 2CF8: 23 22 30 40 01 F4 0C C5 14716 ; 14717 ; which is described as follows in the ZX81 disassembly book: 14718 ; 14719 ; THE 'LINE SCANNING' ROUTINE 14720 ; 14721 ; The BASIC interpreter scans each line for BASIC commands and as each one is found 14722 ; the appropriate command routine is followed. 14723 ; The different parts of the routine are: 14724 ;------------------------------- 14725 ; i) The LINE_SCAN entry point leads to the line number being checked for validity. 14726 14727 LD (IY+FLAGS-RAMBASE),$01 ; FLAGS = 1 14728 CALL E_LINE_NO ; 14729 ;------------------------------- 14730 ; ii) The LINE_RUN entry point is used when replying to an INPUT prompt 14731 ; and this fact has be identified. 14732 ;------------------------------- 14733 LINE_RUN 14734 #if NOT_G007 14735 CALL SET_MEM ; at $14BC 14736 #else 14737 CALL L0A95 ; JP 14BC,SET_MEM then return 14738 ; why it does this I do not know - KH 14739 #endif 14740 LD HL,ERR_NR 14741 LD (HL),$FF 14742 LD HL,FLAGX 14743 BIT 5,(HL) 14744 JR Z,LINE_NULL 14745 ;------------------------------- 14746 ; iii) The INPUT reply is tested to see if STOP was entered. 14747 14748 CP $E3 14749 LD A,(HL) 14750 JP NZ,INPUT_RE 14751 CALL SYNTAX_Z 14752 RET Z 14753 14754 ; iv) If appropriate, report D is given. 14755 14756 RST ERROR_1 14757 defb $0C 14758 ;------------------------------- 14759 ; THE 'STOP' COMMAND ROUTINE 14760 ; The only action is to give report 9. 14761 ;------------------------------- 14762 STOP 14763 RST ERROR_1 14764 defb 8 14765 ;------------------------------- 14766 ; v) A return is made if the line is 'null'. 14767 ;------------------------------- 14768 LINE_NULL: 14769 14770 mark_0CDE: 14771 14772 ; old software from disassembly book: 14773 14774 RST GET_CHAR 14775 LD B,0 14776 CP ZX_NEWLINE 14777 RET Z 14778 14779 ; vi) The first character is tested so as to check that it is a command. 14780 14781 LD C,A 14782 RST NEXT_CH 14783 LD A,C 14784 SUB $E1 14785 #if NOT_G007 14786 JR C,REPORT_C ; $0D9A as per the book 14787 #else 14788 JR C,REPORT_C_007 ; $0D26 in G007 systems 14789 #endif 14790 ;------------------------------- 14791 ; vii) The offset for the command is found from the offset table. 14792 14793 LD C,A 14794 LD HL,offset_t ; $0C29 14795 ADD HL,BC 14796 LD C,(HL) 14797 ADD HL,BC 14798 JR GET_PARAM 14799 14800 ; viii) The parameters are fetched in turn by a loc that returns to 0CF4. 14801 ; The separators are identitied by the test against +0B. 14802 ;------------------------------- 14803 mark_0CF4: 14804 14805 SCAN_LOOP: 14806 LD HL,(T_ADDR) 14807 GET_PARAM: 14808 LD A,(HL) 14809 INC HL 14810 LD (T_ADDR),HL 14811 LD BC,SCAN_LOOP 14812 PUSH BC 14813 14814 ; 14815 ; there is more to this routine but the patch ends here 14816 ; 14817 ; end of patch 14818 ;------------------------------- 14819 org $2D00 14820 14821 14822 ; bits shifting right within a byte: 14823 ; 14824 defb %10000000 ; $80 14825 defb %01000000 ; $40 14826 defb %00100000 ; $20 14827 defb %00010000 ; $10 14828 defb %00001000 ; $08 14829 defb %00000100 ; $04 14830 defb %00000010 ; $02 14831 defb %00000001 ; $01 14832 ;------------------------------- 14833 L2D08: 14834 14835 SLOW_FAST_007: ; at $2D08 14836 14837 CALL L2BF7 ; ??? not a valid opcode address? 14838 JP SLOW_FAST ; old routine 14839 ;------------------------------- 14840 L2D0E: 14841 LD (MARGIN),A ; 14842 EX DE,HL 14843 LD HL,10 14844 ADD HL,SP 14845 LD A,(HL) 14846 INC A 14847 AND $F0 14848 SUB $D0 14849 LD C,A 14850 INC HL 14851 LD A,(HL) 14852 SUB 4 14853 OR A,C 14854 LD C,A 14855 LD A,(CDFLAG) ; 14856 RLCA 14857 SBC A,A 14858 AND A,C 14859 JR NZ,L2D3B 14860 ;------------------------------- 14861 LD HL,(VARS) ; 14862 LD BC,-(CHARS_HORIZONTAL+1) ; $FFDF 14863 ADD HL,BC 14864 SET 7,H 14865 LD (G007_DISPLAY_ADDRESS_LO_RES_LAST_LINE),HL 14866 LD A,1 14867 JR L2D49 14868 ;------------------------------- 14869 L2D3B: 14870 LD HL,(D_FILE) ; GET D_FILE 14871 LD BC,(G007_DISPLAY_OFFSET_FROM_DFILE_LESS_9) 14872 ADD HL,BC 14873 SET 7,H 14874 LD (G007_DISPLAY_ADDRESS_LESS_9),HL 14875 XOR A,A ; A = 0 14876 ;------------------------------- 14877 L2D49: 14878 LD (G007_FLAG_3),A 14879 DEC HL 14880 LD A,(HL) 14881 EX DE,HL 14882 RET 14883 ;------------------------------- 14884 LD A,(G007_FLAG_3) 14885 DEC A 14886 JP NZ,L2D73 ; [11635] 14887 ;------------------------------- 14888 LD A,G007_INT_REG_VALUE_FOR_LO_RES_GRAPHICS 14889 LD I,A ; Interrupt register = 0x1E sets low res mode 14890 ADC HL,HL 14891 LD HL,(G007_DISPLAY_ADDRESS_LO_RES_LAST_LINE) 14892 14893 LD BC,$0108 14894 LD A,$FE 14895 CALL DISPLAY_5; 14896 LD A,G007_INT_REG_VALUE_FOR_HI_RES_GRAPHICS 14897 LD I,A ; Interrupt register = 0x1F sets high res mode 14898 LD A,(MARGIN) ; GET MARGIN 14899 SUB 8 14900 JR L2D77 14901 ;------------------------------- 14902 L2D73: 14903 DEC HL 14904 LD A,(MARGIN) ; GET MARGIN 14905 ;------------------------------- 14906 L2D77: 14907 LD C,A 14908 POP IX 14909 ;------------------------------- 14910 BIT 7,(IY+CDFLAG-RAMBASE) ; makes FD CB 3B 7E 14911 JP NZ,L029D ; []*BIOS ROM* 14912 ;------------------------------- 14913 14914 ; This jumps into the middle of the DISPLAY_3, where it meets this code: 14915 ;029D 79 LD A,C 14916 ;029E ED;44 NEG 14917 ;02A0 3C INC A 14918 ;02A1 08 EX AF,AF' 14919 ;02A2 D3;FE OUT (IO_PORT_KEYBOARD_RD),A ; ZX81 NMI GENERATOR on, for SLOW mode 14920 ;02A4 E1 POP HL ; restore registers 14921 ;02A5 D1 POP DE 14922 ;02A6 C1 POP BC 14923 ;02A7 F1 POP AF 14924 ;02A8 C9 RET 14925 ;------------------------------- 14926 LD A,$FE 14927 LD B,$01 14928 LD HL,HALT_AT_2D9A 14929 CALL LOAD_R_AND_WAIT_FOR_INT 14930 ADD HL,HL ; double HL 14931 NOP 14932 LD E,A 14933 LD HL,(G007_DISPLAY_ADDRESS_LESS_9) 14934 SET 7,H 14935 JP (IX) 14936 ;=============================== 14937 LOAD_R_AND_WAIT_FOR_INT ; mark_2D95 14938 ; Sets up the refresh register and waits for an interrupt: 14939 LD R,A ; Refresh row counter := accumulator 14940 LD A,221 ; 221 = $DD 14941 EI ; Enable interrupts, then drop into HALT 14942 ;------------------------------- 14943 HALT_AT_2D9A: 14944 14945 HALT 14946 ;=============================== 14947 ; Copy two pages of ZX81 BASIC ROM to RAM patch areas, 14948 ; then modify bytes as controlled by a table of offsets and values 14949 ; This uses less memory than two whole pages of ROM 14950 ; If the RAM patches are not changed thereafter, 14951 ; one might be able to use a 16K ROM to hold two different versions of the ZX81 BASIC space, 14952 ; one with the 'RAM' patch and one without. 14953 ; The RAM testing would have to be disabled, because the ROM would cause it to fail. 14954 ;------------------------------- 14955 #if NOT_G007 14956 ZX81_COPY: 14957 #else 14958 G007_COPY: 14959 #endif 14960 ;------------------------------- 14961 ; First check RAM by loading 512 bytes RAM from $2200 to $23FF with value 1, 14962 ; and decrement them to zero to test they are working RAM 14963 ; 14964 LD HL,RAM_PATCH_2200 ; destination RAM patch 2 14965 LD A,$24 14966 ;------------------------------- 14967 mark_2DA0: 14968 G007_COPY_LOOP: 14969 LD (HL),1 ; try writing the value 1 to a byte in RAM patch 2 14970 DEC (HL) ; try decrementing it to zero 14971 JR Z,G007_COPY_SKIP ; if result is zero, skip error code report 14972 ;------------------------------- 14973 RST $08 14974 defb $1A ; RST8 Arg ; Error Code:'R' (ZX81 on-board 1K/2K RAM not found) 14975 ;------------------------------- 14976 G007_COPY_SKIP 14977 mark_2DA7: 14978 INC HL ; next address 14979 CP H ; has HL reached $2400 (yet? 14980 JR NZ,G007_COPY_LOOP ; no, repeat. 14981 ;------------------------------- 14982 ; HL is now $2400 14983 ; Copy 256 bytes from BASIC ROM to RAM patch 1: 14984 LD H,L ; HL is now $0000 (data source is start of ZX81 BASIC ROM) 14985 LD DE,RAM_PATCH_2000 ; data destination 14986 LD BC,$0100 ; 256 bytes 14987 LDIR ; (HL) -> (DE) 256 times 14988 ;------------------------------- 14989 ; HL is now $0100 14990 ; DE is now $2100 14991 ; BC is now $0000 14992 ;------------------------------- 14993 INC H ; HL is now $0200 14994 INC D ; DE is now $2200 14995 INC B ; BC is now $0100 14996 LDIR ; copy another 256 bytes to RAM patch 2 14997 ;------------------------------- 14998 LD HL,PRINT_CH ; src = the original ZX81 print character routine 14999 LD DE,G007_V23A0 ; dst = 15000 LD BC,$0060 ; 60hex = 96 bytes, so stops just before 0851 (the 'LPRINT_CH routine) 15001 LDIR ; move 15002 ; BC is now $0000 15003 LD D,$20 ; DE is now $20?? 15004 LD HL,TABLE_ONE ; copy data from this table: 15005 LOOP_2DC9: 15006 LD B,(HL) ; BC is now $0A00 (seems way too many bytes) 15007 JR G007_TABLE_END_TEST ; branch to end-of-table test 15008 ;------------------------------- 15009 G007_TABLE_ONE_LOOP: 15010 LD E,(HL) ; Get the offset 15011 INC HL ; next byte is data 15012 LD A,(HL) ; Get the data byte 15013 LD (DE),A ; ($2000+offset) = data byte 15014 ;------------------------------- 15015 G007_TABLE_END_TEST: 15016 mark_2DD0: 15017 INC HL ; next offset 15018 DJNZ G007_TABLE_ONE_LOOP ; repeat until BC is zero 15019 ;------------------------------- 15020 INC D ; D becomes $21 15021 BIT 2,D ; test bit 2 (has D incremented to $23 ?) 15022 JR Z,LOOP_2DC9 15023 15024 RET 15025 ;=============================== 15026 ; Delete Display File: 15027 ; 15028 G007_DELETE_DISPLAY_FILE: 15029 CALL SET_FAST; 15030 LD HL,$3E87 15031 CALL LINE_ADDR; 15032 RET NZ 15033 ;------------------------------- 15034 EX DE,HL 15035 LD HL,(NXT_LINE) ; 15036 BIT 6,(HL) 15037 JR Z,L2DEF 15038 ;------------------------------- 15039 LD (NXT_LINE),DE ; 15040 ;------------------------------- 15041 L2DEF: 15042 LD HL,(D_FILE) ; 15043 JP RECLAIM_1 ; exit 15044 ;------------------------------- 15045 L2DF5: 15046 CALL G007_DELETE_DISPLAY_FILE 15047 LD BC,$1992 ; 6546 decimal = 15048 LD HL,(D_FILE) ; 15049 DEC HL 15050 CALL MAKE_ROOM 15051 15052 LD A,ZX_NEWLINE 15053 LD (DE),A ; to DE 15054 INC DE 15055 LD (DE),A ; and DE+1 15056 15057 INC HL ; HL += 2 15058 INC HL 15059 15060 LD (HL),$3E ; (HL++) = $3E 'Y' 15061 INC HL 15062 LD (HL),$87 ; (HL++) = $87 15063 INC HL 15064 LD (HL),$8D ; (HL++) = $8D 15065 INC HL 15066 LD (HL),$19 ; (HL++) = $19 ';' 15067 INC HL 15068 LD (HL),A ; (HL++) = ZX_NEWLINE 15069 INC HL 15070 LD (HL),A ; (HL++) = ZX_NEWLINE 15071 ;------------------------------- 15072 L2E18: 15073 CALL SLOW_FAST ; 15074 LD A,1 15075 JR G007_CLS_HI_RES 15076 ;------------------------------- 15077 G007_CHECK_AND_SET_UP_DISPLAY_FILE: 15078 ; 15079 LD HL,(V2265) ; in the RAM page 2 area ! Usually $4027 15080 LD DE,$BFD9 ; 3FD9 + 32K, or -16423 = 16K - 39 bytes 15081 ADD HL,DE 15082 15083 LD A,(V2264) 15084 SUB CHARS_HORIZONTAL+1 ; bytes per screen line 15085 15086 OR A,H 15087 OR A,L 15088 15089 CALL NZ,G007_COPY 15090 LD HL,(D_FILE) ; GET D_FILE 15091 LD A,ZX_NEWLINE 15092 15093 DEC HL 15094 DEC HL 15095 CP (HL) ; pointing to a HALT? 15096 15097 CALL NZ,L2DF5 ; no, 15098 ; else yes 15099 LD HL,(D_FILE) ; GET D_FILE 15100 LD DE,(G007_DISPLAY_OFFSET_FROM_DFILE_LESS_9) 15101 ADD HL,DE 15102 LD (G007_DISPLAY_ADDRESS_LESS_9),HL 15103 15104 LD DE,9 ; HL += 9 15105 ADD HL,DE 15106 15107 LD (G007_DISPLAY_ADDRESS),HL 15108 RET 15109 ;------------------------------- 15110 G007_CLS_N: 15111 ; 15112 CALL STK_TO_A 15113 RET NZ ; drop through if zero flag set 15114 ;------------------------------- 15115 ; Clear The Screen: 15116 ; 15117 G007_CLS_A: 15118 DEC A 15119 JP M,CLS ; if A was zero 15120 ;------------------------------- 15121 G007_CLS_HI_RES: 15122 PUSH AF 15123 CALL G007_CHECK_AND_SET_UP_DISPLAY_FILE 15124 POP AF 15125 ;------------------------------- 15126 CP 2 15127 LD BC,(G007_DISPLAY_HEIGHT) 15128 LD HL,(D_FILE) 15129 JR NC,L2E96 15130 ;------------------------------- 15131 DEC A 15132 15133 INC HL 15134 LD (DF_CC),HL ; Addr. for PRINT AT position 15135 DEC HL 15136 15137 DEC HL 15138 DEC HL 15139 15140 LD E,0 ; E = 0 is byte to fill screen 15141 ;------------------------------- 15142 loop_2E70: 15143 LD B,16 ; 16 15144 DEC HL 15145 LD (HL),E ; but writes 2 bytes for each loop 15146 DEC HL 15147 LD (HL),E ; perhaps to reduce loop overhead? 15148 ;------------------------------- 15149 loop_2E76: 15150 DEC HL 15151 LD (HL),A ; writes A twice over 15152 DEC HL 15153 LD (HL),A 15154 DJNZ loop_2E76 15155 ;------------------------------- 15156 DEC C 15157 JR NZ,loop_2E70 15158 ;------------------------------- ; C is now zero 15159 LD B,9 ; BC is now $0900 15160 LD A,1 15161 ;------------------------------- 15162 loop_2E83: 15163 DEC HL 15164 LD (HL),E ; (--HL) = E while --BC 15165 DJNZ loop_2E83 15166 ;------------------------------- ; BC is now zero 15167 LD HL,G007_LINE_TYPE 15168 LD B,20 ; decimal 20 15169 DEC A 15170 JR Z,loop_2E83 15171 ;------------------------------- 15172 LD HL,256*CHARS_VERTICAL + CHARS_HORIZONTAL + 1 15173 LD (S_POSN),HL ; SET S_POSN 15174 RET 15175 ;=============================== 15176 L2E96: 15177 RET NZ 15178 15179 DEC HL ; HL -= 2 15180 DEC HL 15181 ;------------------------------- outer loop 15182 loop_2E99: 15183 LD B,32 ; 32 bytes to invert 15184 DEC HL ; HL -= 2 15185 DEC HL ; skips past 2 HALT characters 15186 15187 ;------------------------------- inner loop 15188 loop_2E9D: 15189 DEC HL 15190 15191 LD A,(HL) ; read 15192 CPL ; invert (one's complement) 15193 LD (HL),A ; write 15194 15195 DJNZ loop_2E9D 15196 ;------------------------------- 15197 DEC C ; C is obviously the number of horizontal lines to invert 15198 JR NZ,loop_2E99 15199 ;------------------------------- 15200 RET 15201 ;------------------------------- 15202 mark_2EA7: 15203 DIM_007: ; 2EA7 15204 LD HL,($0A96) 15205 LD A,$4D 15206 JR L2EE3 15207 ;------------------------------- 15208 PAUSE_007: 15209 LD A,$DD 15210 JR skip_2EE0 15211 ;------------------------------- 15212 SLOW_007: ; 2EB2 15213 LD A,$D6 15214 JR skip_2EB8 15215 ;------------------------------- 15216 FAST_007: ; 2EB6 15217 LD A,$CE 15218 ;------------------------------- 15219 skip_2EB8: 15220 PUSH AF 15221 15222 CALL STK_TO_A 15223 LD B,$1E 15224 DEC A 15225 CP 6 15226 JR NC,skip_2EDC 15227 ;------------------------------- 15228 SRL A 15229 LD H,A 15230 ;------------------------------- 15231 JR Z,skip_2ECA 15232 LD A,1 15233 skip_2ECA: 15234 ;------------------------------- 15235 PUSH AF 15236 SBC A,A 15237 LD L,A 15238 RES 1,H 15239 DEC H 15240 LD (G007_RESTART),HL 15241 CALL G007_CHECK_AND_SET_UP_DISPLAY_FILE 15242 LD B,G007_INT_REG_VALUE_FOR_HI_RES_GRAPHICS 15243 POP AF 15244 15245 LD (G007_FLAG_2),A 15246 ;------------------------------- 15247 skip_2EDC: 15248 LD A,B ; 15249 LD I,A ; I = B = G007_INT_REG_VALUE_FOR_HI_RES_GRAPHICS = set video mode 15250 POP AF 15251 ;------------------------------- 15252 skip_2EE0: 15253 LD HL,($0D71) ; inside the 'COMMAND CLASS 2' routine of the ZX BASIC ROM 15254 ;------------------------------- 15255 L2EE3: 15256 ADD A,L 15257 LD L,A 15258 JP (HL) 15259 15260 LD D,A 15261 LD A,(S_POSN) ; 15262 AND $80 15263 JP L2B6C 15264 ;=============================== 15265 L2EEF: ; print a character on high-res screen perhaps? 15266 LD A,D 15267 POP DE 15268 15269 EXX 15270 ;------------------------------- 15271 PUSH HL 15272 PUSH DE 15273 PUSH BC 15274 ;------------------------------- 15275 LD HL,(G007_CHAR_TABLE_ADDR_0_63) 15276 ADD A,A ; if (A < 128) goto 15277 JR NC,skip_2F06 15278 ;------------------------------- ; 15279 LD HL,(G007_CHAR_TABLE_ADDR_128_159) 15280 BIT 6,A 15281 JR Z,skip_2F06 15282 ;------------------------------- 15283 LD HL,(G007_USR_DEF_CHR_TAB_LESS_256) 15284 CCF 15285 ;------------------------------- 15286 skip_2F06: 15287 EX DE,HL ; DE now points to the selected charater table 15288 15289 LD L,A ; HL = A 15290 LD H,0 15291 15292 SBC A,A ; A = carry 15293 LD C,A ; 15294 ;------------------------------- 15295 LD A,(G007_RESTART) ; invert this variable 15296 CPL 15297 AND A,(IY+G007_RESTART+1-RAMBASE) 15298 ;------------------------------- 15299 XOR A,C 15300 LD C,A 15301 15302 ADD HL,HL ; HL *= 4 15303 ADD HL,HL 15304 ADD HL,DE ; HD += DE 15305 15306 LD B,8 15307 15308 EXX 15309 PUSH DE 15310 RET 15311 ;=============================== 15312 L2F1D: ; The copied and modified PRINT_CH / WRITE_CH jumps here from $23FF 15313 DEC (IY+S_POSN-RAMBASE) ; Line and Column for PRINT AT 15314 LD A,24 ; 24 character rows per screen 15315 SUB B 15316 LD B,A 15317 ; 15318 ADD A,A 15319 ADD A,A 15320 ADD A,A 15321 LD L,A ; L = A * 8 15322 ; 15323 LD A,(G007_DISPLAY_HEIGHT) 15324 SUB L ; A = G007_DISPLAY_HEIGHT - something 15325 RET C ; return if beyond limit 15326 ;------------------------------- 15327 LD A,CHARS_HORIZONTAL+1 ; 32 video bytes plus HALT ? 15328 SUB C 15329 LD C,A 15330 ;------------------------------- 15331 LD H,0 15332 ADD HL,HL 15333 ADD HL,BC 15334 LD BC,(G007_DISPLAY_ADDRESS) 15335 ADD HL,BC ; HL = L*2 + BC + G007_DISPLAY_ADDRESS: 15336 ;------------------------------- 15337 CALL L2EEF 15338 LD BC,$0022 ; B = 0, C = 34 15339 EXX 15340 ;------------------------------- 15341 COPY_007: 15342 loop_2F41: ; 15343 LD A,C 15344 XOR A,(HL) 15345 EXX 15346 LD (HL),A 15347 ADD HL,BC 15348 EXX 15349 INC HL 15350 DJNZ loop_2F41 15351 ;------------------------------- 15352 JP L299A 15353 ;------------------------------- 15354 SAVE_007: ; 2F4D 15355 CALL G007_DELETE_DISPLAY_FILE 15356 JP SAVE 15357 ;------------------------------- 15358 L2F53: 15359 CALL STK_TO_A 15360 RET NZ 15361 15362 DEC A 15363 JP M,COPY ; A was zero, jump to low-res copy-to-printer 15364 ;------------------------------- 15365 CALL G007_CHECK_AND_SET_UP_DISPLAY_FILE ; check we have a display 15366 CALL SET_FAST ; print in FAST mode! 15367 LD A,(G007_DISPLAY_HEIGHT) 15368 LD B,A ; B = (G007_DISPLAY_HEIGHT) 15369 LD HL,(G007_DISPLAY_ADDRESS) 15370 XOR A,A ; A = 0 15371 LD E,A ; E = 0 15372 OUT (ZX_PRINTER_PORT),A 15373 ;------------------------------- 15374 loop_2F6C: 15375 LD A,$7F ; looks pointless 15376 IN A,(IO_PORT_KEYBOARD_RD) 15377 RRCA 15378 JP NC,$0886 ; []*BIOS ROM* between 0880 COPY-BRK and 0888 REPORT-D2 15379 IN A,(ZX_PRINTER_PORT) 15380 ;------------------------------- 15381 loop_2F76: 15382 ADD A,A 15383 JP M,L2FAD 15384 ;------------------------------- 15385 JR NC,loop_2F6C 15386 ;------------------------------- 15387 LD C,$20 ; 32 15388 ;------------------------------- 15389 loop_2F7E: 15390 PUSH BC 15391 LD C,(HL) 15392 LD B,8 15393 ;------------------------------- ; outer loop 15394 loop_2F82: 15395 RLC C 15396 RRA 15397 OR A,E 15398 LD D,A 15399 ;------------------------------- ; inner loop 15400 loop_2F87: 15401 IN A,(ZX_PRINTER_PORT) ; read printer port bit 0 into carry flag 15402 RRA 15403 JR NC,loop_2F87 ; repeat while bit is zero 15404 ;------------------------------- 15405 LD A,D 15406 OUT (ZX_PRINTER_PORT),A ; D register to printer 15407 DJNZ loop_2F82 15408 ;------------------------------- 15409 INC HL 15410 POP BC 15411 DEC C 15412 JR NZ,loop_2F7E 15413 ;------------------------------- 15414 INC HL 15415 INC HL 15416 LD A,3 15417 ;------------------------------- 15418 CP B 15419 JR C,skip_2F9F 15420 ;------------------------------- 15421 LD E,A 15422 DEC E 15423 skip_2F9F: 15424 ;------------------------------- 15425 loop_2F9F: 15426 IN A,(ZX_PRINTER_PORT) ; read printer port bit 0 into carry flag 15427 RRA 15428 JR NC,loop_2F9F ; repeat while bit is zero 15429 ;------------------------------- 15430 LD A,E 15431 OUT (ZX_PRINTER_PORT),A ; E register to printer 15432 DJNZ loop_2F6C 15433 ;------------------------------- 15434 LD A,4 15435 OUT (ZX_PRINTER_PORT),A 15436 ;------------------------------- 15437 L2FAD: 15438 JP SLOW_FAST ; normal 15439 EI 15440 DJNZ loop_2F76 15441 ;------------------------------- 15442 defb $3E ; something to do with the table below? 15443 ;------------------------------- 15444 TABLE_ONE: 15445 ; 15446 ; this table is copied to offsets from $2000, $2200, and $2300 15447 ;------------------------------- 15448 ; Modify 9 bytes in page 20xx / 00xx: 15449 ;------------------------------- 15450 L2FB4 : 15451 defb (9+1) ; Modify 9 bytes in page 20xx / 00xx: 15452 ;------------------------------- 15453 ; Original routine Modifications made in page 00xx 15454 ; 15455 L2FB5: 15456 ; 0011 C2;F1;07 JP NZ,PRINT_CH ; old 15457 ; 0011 C2;A0;23 JP NZ,L23A0 ; new, jump somewhere in RAM ??? 15458 15459 defb $12 15460 defb $A0 15461 defb $13 15462 defb $23 15463 ;------------------------------- 15464 L2FB9 15465 ; 0014 F5 07 JP PRINT_SP ; $07F5 15466 ; 2014 A4 23 JP L23A4 ; new, jumps to somewhere in RAM 15467 15468 defb $15 15469 defb $A4 15470 defb $16 15471 defb $23 15472 ;------------------------------- 15473 ; 003F CB;D9 SET 3,C ; old 15474 ; 003F CB;C1 SET 0,C ; new 15475 15476 L2FBD: defb $40 15477 L2FBE: defb $C1 15478 ;------------------------------- 15479 ; 005F CD;07;02 CALL SLOW_FAST ; 0207 is old 15480 ; 005F CD;08;2D CALL SLOW_FAST_007 ; 2D08 is new 15481 15482 L2FBF: defb $60 15483 L2FC0: defb $08 15484 L2FC1: defb $61 15485 L2FC2: defb $2D 15486 ;------------------------------- 15487 ; 0074 2A;0C;40 LD HL,(D_FILE) 15488 ; 0074 2A;06:23 LD HL,(G007_DISPLAY_ADDRESS_LESS_9) ; new 15489 15490 L2FC3: defb $75 15491 L2FC4: defb $06 15492 defb $76 15493 L2FC6: defb $23 15494 ;------------------------------- 15495 ; Modifications made in page 02xx 15496 ;------------------------------- 15497 L2FC7: defb $01 15498 defb $0A 15499 15500 ; 0253 06;0B LD B,$0B 15501 ; 2253 06;02 LD B,$02 15502 15503 L2FC9 defb $54 15504 defb $02 15505 ;------------------------------- 15506 ; 0283 01;01;19 LD BC,$1901 15507 ; 2283 01;01;C1 LD BC,$C101 15508 L2FCB: defb $85 15509 defb $C1 15510 ;------------------------------- 15511 ; 027E CD;92;02 CALL DISPLAY_3 15512 ; 227E CD;73;2D CALL L2D73 15513 ; 15514 L2FCD: defb $7F 15515 defb $73 15516 L2FCF: defb $80 15517 defb $2D 15518 ;------------------------------- 15519 ; 028C CD;92;02 CALL $0292 ; [DISPLAY-3] 15520 ; 228C CD;50;2D CALL $2D50 15521 L2FD1: defb $8D 15522 L2FD2: defb $50 15523 L2FD3: defb $8E 15524 L2FD4: defb $2D 15525 ;------------------------------- 15526 ; 02E3 32;28;40 LD ($4028),A ; SET MARGIN 15527 ; 22E3 C3;0E;2D JP L2D0E 15528 L2FD5: defb $E3 15529 L2FD6: defb $C3 15530 defb $E4 15531 defb $0E 15532 L2FD9: defb $E5 15533 L2FDA: defb $2D 15534 ;------------------------------- 15535 L2FDB: defb $13 ; some kind of marker? 15536 ;------------------------------- 15537 ; 15538 ; Original routine Modifications made to the copy of the PRINT-CH routines: 15539 ; 15540 ; 15541 ; Variables in the sparsely populated G007 RAM areas 15542 ; 15543 ; Initialise 18 (decimal, = 12 in hex)RAM variables at $23xx: 15544 ; 15545 ; 2FE0 E6 0A ; 23E6 0A 15546 ; 2FE2 55 0D ; 2355 0D 15547 ; 2FE4 1E 0F ; 231E 0F 15548 ; 2FE6 16 20 ; 2316 20 15549 ; 2FE8 10 07 ; 2310 07 15550 ; 2FEA 11 08 ; 2311 08 15551 ; 2FEC 18 C0 ; 2318 C0 15552 ; 15553 ;------------------ ; G007_DISPLAY_OFFSET_FROM_DFILE_LESS_9 = E675 (6675 echoed in top 32K ???) 15554 L2FDC: defb $00 ; 2300 75 15555 defb $75 15556 ;------------------ 15557 L2FDE: defb $01 ; 2301 E6 15558 defb $E6 15559 ;------------------ 15560 L2FE0: defb $0A 15561 ;------------------ 15562 L2FE1: defb $55 ; 2355 0D 15563 L2FE2: defb $0D 15564 ;------------------ 15565 L2FE3: defb $1E ; 231E 0F 15566 L2FE4: defb $0F 15567 ;------------------ 15568 defb $1E ; some kind of marker? 15569 ;------------------ 15570 L2FE6: defb $16 ; 2316 20 15571 defb $20 15572 ;------------------ ; G007_PLOT_ROUTINES_VECTOR = G007_PLOT_ROUTINES_VECTOR_DEFAULT = $0807 15573 L2FE8: defb $10 ; 2310 07 15574 defb $07 15575 ;------------------ 15576 L2FEA: defb $11 ; 2311 08 15577 defb $08 15578 ;------------------ 15579 L2FEC: defb $18 ; 2318 C0 15580 defb $C0 15581 ;------------------ 15582 L2FEE: defb $35 ; 2335 EE 15583 defb $EE 15584 ;------------------ 15585 L2FF0: defb $36 ; 2336 55 15586 defb $55 15587 ;------------------ 15588 L2FF2: defb $37 ; 2337 C6 15589 defb $C6 15590 ;------------------ 15591 ; The values below were seen in RAM but are not initialised from this table: 15592 ; 15593 ; 2306 84 4084 G007_DISPLAY_ADDRESS_LESS_9 15594 ; 2307 40 15595 ; 2308 8D 408D G007_DISPLAY_ADDRESS 15596 ; 2309 40 15597 ; 230A 55 00 55,00 G007_TRIANGLE_TEXTURE 15598 ; 230C 00 1E00 Character table address for CHR$0-63 15599 ; 230D 1E 15600 ; 230E 00 1E00 Character table address for CHR$128-159 15601 ; 230F 1E 15602 ;------------------ 15603 ; Modding offsets in copied code: 15604 ;------------------ 15605 ; 07FD CD 08 08 CALL $0808 ; [ENTER-CH] 15606 ; 23AC CD E6 2E CALL $2EE6 15607 ; 15608 L2FF4: defb $AD 15609 defb $E6 15610 defb $AE 15611 defb $2E 15612 ;------------------ 15613 ; 0843 FD 35 39 DEC (IY+SPOSN-RAMBASE) 15614 ; 23F2 C3 1D 2F JP $2F1D 15615 ; 15616 L2FF8: defb $F2 15617 defb $C3 15618 15619 defb $F3 15620 defb $1D 15621 15622 defb $F4 15623 defb $2F 15624 ;------------------ 15625 ; 15626 ; 083E 77 LD (HL),A ; WRITE-CH 15627 ; 23ED 00 NOP ; WRITE-CH modified! 15628 ; 15629 L2FFE: defb $ED 15630 defb $00 15631 ;------------------ 15632 15633 15634 15635 15636 15637 15638 15639 15640 15641 15642 15643 15644 15645 15646 15647 15648 15649 15650 15651 15652 15653 15654 15655 ; end of g007 stuff 15656 ; 15657 #endif 15658 15659 15660 15661 #code $3800,$0800 15662 15663 15664 15665 15666 #if 1 15667 15668 mark_3800: DEFB $21, $00, $38 ; ld hl,Source 15669 mark_3803: DEFB $11, $00, $78 ; ld de,Destination 15670 mark_3806: DEFB $01, $00, $08 ; ld bc,MonitorSize 15671 mark_3809: DEFB $ED, $B0 ; ldir 15672 mark_380B: DEFB $3E, $74 ; ld a,74 15673 mark_380D: DEFB $32, $05, $40 ; ld (RamtopHi),a 15674 mark_3810: DEFB $CD, $C3, $03 ; call New 15675 15676 mark_3813: DEFB $3E, $01 ; ld a,01 15677 mark_3815: DEFB $01, $93, $7B ; ld bc,Input_Prompt_Data 15678 mark_3818: DEFB $CD, $02, $79 ; call Get_A_addresses 15679 mark_381B: DEFB $CD, $2A, $0A ; call Cls 15680 mark_381E: DEFB $ED, $6B, $F8, $7F ; ld hl,Next_Address 15681 mark_3822: DEFB $E9 ; jp (hl) 15682 15683 ; Routine 0 the disassembler 15684 mark_3823: DEFB $CD, $FD, $78, $CD, $09 15685 mark_3828: DEFB $79, $18, $05, $16, $13, $CD, $53, $7B 15686 mark_3830: DEFB $CD, $81, $7B, $30, $05, $AF, $32, $21 15687 mark_3838: DEFB $40, $C9 15688 mark_383A: DEFB $21, $7B, $40, $36, $30, $23 15689 mark_3840: DEFB $36, $78, $CD, $2E, $7A, $CD, $72, $7A 15690 mark_3848: DEFB $78, $FE, $76, $20, $08, $21, $F5, $7C 15691 mark_3850: DEFB $CD, $A4, $7B, $18, $D6, $FE, $CB, $28 15692 mark_3858: DEFB $32, $FE, $ED, $28, $38, $FE, $DD, $28 15693 mark_3860: DEFB $44, $FE, $FD, $28, $44, $CD, $4F, $7A 15694 mark_3868: DEFB $2E, $24, $FE, $00, $28, $11, $2E, $2C 15695 mark_3870: DEFB $FE, $01, $28, $0E, $2C, $FE, $02, $28 15696 mark_3878: DEFB $09, $3E, $5E, $32, $42, $7D, $2C, $7D 15697 mark_3880: DEFB $81, $6F, $26, $7D, $6E, $EB, $CD, $D4 15698 mark_3888: DEFB $7A, $18, $A0, $CD, $72, $7A, $CD, $4F 15699 mark_3890: DEFB $7A, $C6, $36, $18, $EC, $CD, $72, $7A 15700 mark_3898: DEFB $CD, $4F, $7A, $2E, $18, $FE, $01, $28 15701 mark_38A0: DEFB $DE, $2E, $20, $18, $DA, $3E, $0B, $18 15702 mark_38A8: DEFB $02, $3E, $0D, $32, $41, $7D, $3E, $12 15703 mark_38B0: DEFB $32, $40, $7D, $2A, $F8, $7F, $23, $7E 15704 mark_38B8: DEFB $21, $16, $7D, $CD, $89, $7A, $23, $CB 15705 mark_38C0: DEFB $BE, $CD, $72, $7A, $78, $FE, $CB, $20 15706 mark_38C8: DEFB $05, $CD, $72, $7A, $18, $BD, $CD, $4F 15707 mark_38D0: DEFB $7A, $FE, $03, $28, $93, $F5, $C5, $FE 15708 mark_38D8: DEFB $00, $20, $05, $3E, $06, $B8, $20, $03 15709 mark_38E0: DEFB $CD, $72, $7A, $C1, $F1, $18, $81 15710 15711 ; Spare bytes 15712 mark_38E7: DEFB $00 15713 mark_38E8: DEFB $00, $00, $00, $00, $00, $00, $00, $00 15714 mark_38F0: DEFB $00, $00, $00, $00, $00, $00, $00, $00 15715 mark_38F8: DEFB $00, $00, $00, $00, $00 15716 15717 ; Start/Finish Addresses 15718 ; prints request for input then calls input address routine 15719 mark_38FD: DEFB $01, $93, $7B 15720 mark_3900: DEFB $3E, $02 15721 15722 ; Get_A_addresses 15723 mark_3902: DEFB $11, $F8, $7F, $CD, $14, $7A, $C9 15724 15725 ; Check printer 15726 mark_3909: DEFB $11, $E1, $10, $CD, $3B, $7B, $2B 15727 mark_3910: DEFB $7E, $21, $21, $40, $36, $83, $FD, $CB 15728 mark_3918: DEFB $01, $CE, $FE, $1D, $C4, $2A, $0A, $C9 15729 15730 ; routine 1: DEFB hex dump 15731 mark_3920: DEFB $CD, $FD, $78, $CD, $09, $79, $21, $F9 15732 mark_3928: DEFB $7C, $CD, $9F, $7B, $21, $7B, $40, $36 15733 mark_3930: DEFB $33, $23, $36, $79, $CD, $81, $7B, $F8 15734 mark_3938: DEFB $CD, $3D, $7A, $0E, $08, $CD, $72, $7A 15735 mark_3940: DEFB $0D, $28, $0B, $CD, $81, $7B, $30, $F5 15736 mark_3948: DEFB $16, $0B, $CD, $53, $7B, $C9 15737 mark_394E: DEFB $CD, $48, $79, $18, $E1 15738 15739 ; routine 2: DEFB write 15740 mark_3953: DEFB $3E, $01, $01, $93, $7B 15741 mark_3958: DEFB $CD, $02, $79, $CD, $2A, $0A, $CD, $0E 15742 mark_3960: DEFB $0C, $CD, $3D, $7A, $11, $E8, $1C, $CD 15743 mark_3968: DEFB $A5, $7F, $CB, $45, $28, $05, $CD, $AD 15744 mark_3970: DEFB $7F, $18, $F7, $ED, $5B, $F8, $7F, $CD 15745 mark_3978: DEFB $0B, $7B, $ED, $53, $F8, $7F, $3E, $76 15746 mark_3980: DEFB $D7, $18, $DB 15747 15748 ; prints data associated with RST 08 or RST 28 15749 mark_3983: DEFB $0D, $20, $24, $0E, $04 15750 mark_3988: DEFB $16, $13, $CD, $53, $7B, $18, $18, $78 15751 mark_3990: DEFB $FE, $01, $20, $1A, $21, $7B, $40, $36 15752 mark_3998: DEFB $62, $23, $36, $7A, $16, $13, $CD, $53 15753 mark_39A0: DEFB $7B, $21, $F9, $7C, $CD, $9F, $7B, $CD 15754 mark_39A8: DEFB $3D, $7A, $CD, $72, $7A, $C9 15755 mark_39AE: DEFB $FE, $05 15756 mark_39B0: DEFB $C0, $21, $7B, $40, $36, $68, $23, $36 15757 mark_39B8: DEFB $7A, $0E, $04, $CD, $9C, $79, $78, $FE 15758 mark_39C0: DEFB $34, $C8, $CD, $83, $79, $18, $F7 15759 15760 ; Data Calculates absolute address for JR instructions 15761 ; and adds number and addresses to mnemonic 15762 mark_39C7: DEFB $CD 15763 mark_39C8: DEFB $72, $7A, $AF, $CB, $78, $28, $01, $2F 15764 mark_39D0: DEFB $48, $47, $2A, $F8, $7F, $09, $EB, $21 15765 mark_39D8: DEFB $00, $7D, $7B, $CD, $89, $7A, $2B, $7A 15766 mark_39E0: DEFB $CD, $89, $7A, $23, $CB, $BE, $2B, $18 15767 mark_39E8: DEFB $1B, $CD, $72, $7A, $2B, $18, $15, $CD 15768 mark_39F0: DEFB $07, $7A, $18, $10, $CD, $72, $7A, $2B 15769 mark_39F8: DEFB $18, $03, $CD, $07, $7A, $2B, $CD, $A4 15770 mark_3A00: DEFB $7B, $21, $0D, $7C, $C3, $A4, $7B, $21 15771 mark_3A08: DEFB $00, $7D, $CD, $75, $7A, $CD, $72, $7A 15772 mark_3A10: DEFB $CB, $BE, $2B, $C9 15773 15774 ; Input_Address 15775 mark_3A14: DEFB $F5, $D5, $11, $E4 15776 mark_3A18: DEFB $10, $CD, $3B, $7B, $7D, $BB, $28, $05 15777 mark_3A20: DEFB $CD, $AD, $7F, $18, $F7, $D1, $CD, $21 15778 mark_3A28: DEFB $7B, $F1, $3D, $20, $E7, $C9 15779 15780 ; Initial 15781 mark_3A2E: DEFB $21, $42 15782 mark_3A30: DEFB $7D, $36, $5C, $2B, $36, $09, $2B, $36 15783 mark_3A38: DEFB $0F, $2B, $2B, $36, $E0 15784 15785 ; Next_Address 15786 mark_3A3D: DEFB $11, $F9, $7F 15787 mark_3A40: DEFB $21, $FE, $7C, $1A, $CD, $7F, $7A, $1B 15788 mark_3A48: DEFB $1A, $CD, $7F, $7A, $AF, $D7, $C9 15789 15790 ; Octal 15791 mark_3A4F: DEFB $78 15792 mark_3A50: DEFB $E6, $07, $4F, $78, $F5, $E6, $38, $0F 15793 mark_3A58: DEFB $0F, $0F, $47, $F1, $E6, $C0, $07, $CB 15794 mark_3A60: DEFB $07, $C9 15795 15796 ; Cont, $RST 15797 mark_3A62: DEFB $CD, $A1, $79, $C3, $2B, $78 15798 mark_3A68: DEFB $0E, $04, $CD, $A1, $79, $CD, $BE, $79 15799 mark_3A70: DEFB $18, $F3 15800 15801 ; Next_Byte 15802 mark_3A72: DEFB $21, $FE, $7C, $ED, $5B, $F8 15803 mark_3A78: DEFB $7F, $1A, $13, $ED, $53, $F8, $7F, $CD 15804 mark_3A80: DEFB $89, $7A, $D7, $23, $7E, $CB, $BF, $D7 15805 mark_3A88: DEFB $C9 15806 mark_3A89: DEFB $47, $E6, $0F, $C6, $1C, $CB, $FF 15807 mark_3A90: DEFB $77, $2B, $78, $E6, $F0, $1F, $1F, $1F 15808 mark_3A98: DEFB $1F, $C6, $1C, $77, $C9 15809 15810 ; Offsets 15811 mark_3A9D: DEFB $CB, $40, $20 15812 mark_3AA0: DEFB $19, $CD, $B3, $7A, $13, $C9 15813 mark_3AA6: DEFB $3E, $01 15814 mark_3AA8: DEFB $CB, $40, $20, $1E, $18, $05, $CB, $40 15815 mark_3AB0: DEFB $28, $0F, $13, $AF, $18, $14, $CB, $40 15816 mark_3AB8: DEFB $28, $07, $13, $78, $CB, $87, $0F, $18 15817 mark_3AC0: DEFB $09, $CD, $BB, $7A, $13, $C9 15818 mark_3AC7: DEFB $78, $18 15819 mark_3AC8: DEFB $01, $79, $13, $62, $6B, $6E, $26, $7C 15820 mark_3AD0: DEFB $CD, $A5, $7B, $C9 15821 15822 ; Control 15823 mark_3AD4: DEFB $1A, $F5, $E6, $07 15824 mark_3AD8: DEFB $21, $DD, $7A, $18, $1E, $F1, $F5, $CB 15825 mark_3AE0: DEFB $77, $28, $0D, $2A, $3E, $7D, $CB, $55 15826 mark_3AE8: DEFB $36, $00, $23, $28, $F9, $22, $3E, $7D 15827 mark_3AF0: DEFB $E6, $38, $0F, $0F, $CB, $0F, $28, $0C 15828 mark_3AF8: DEFB $21, $04, $7B, $E5, $3C, $26, $7D, $6F 15829 mark_3B00: DEFB $6E, $26, $7A, $E9, $F1, $CB, $7F, $C0 15830 mark_3B08: DEFB $13, $18, $C9 15831 15832 ; Transfer 15833 mark_3B0B: DEFB $C5, $7D, $2E, $E0, $95 15834 mark_3B10: DEFB $0F, $47, $7E, $CD, $8C, $7B, $23, $86 15835 mark_3B18: DEFB $D6, $1C, $12, $13, $23, $10, $F3, $C1 15836 mark_3B20: DEFB $C9 15837 mark_3B21: DEFB $C5, $06, $02, $2B, $4E, $2B, $7E 15838 mark_3B28: DEFB $CD, $8C, $7B, $81, $D6, $1C, $12, $13 15839 mark_3B30: DEFB $10, $F2, $C1, $3E, $76, $D7, $D7, $C9 15840 15841 mark_3B38: DEFB $11, $EF, $10, $CD, $33, $78, $26, $7E 15842 mark_3B40: DEFB $0A, $6F, $CD, $9F, $7B, $03, $0A, $6F 15843 mark_3B48: DEFB $03, $CD, $A4, $7B, $CD, $53, $7B, $CD 15844 mark_3B50: DEFB $A5, $7F, $C9 15845 15846 ; Print_String 15847 mark_3B53: DEFB $C5, $D5, $E5, $FD, $CB 15848 mark_3B58: DEFB $21, $46, $28, $08, $ED, $4B, $39, $40 15849 mark_3B60: DEFB $4A, $CD, $0B, $09, $11, $E0, $7F, $ED 15850 mark_3B68: DEFB $4B, $3E, $7D, $06, $00, $79, $D6, $E0 15851 mark_3B70: DEFB $4F, $CD, $6B, $0B, $FD, $CB, $21, $4E 15852 mark_3B78: DEFB $28, $03, $3E, $76, $D7, $E1, $D1, $C1 15853 mark_3B80: DEFB $C9 15854 15855 ; Check_Finish 15856 mark_3B81: DEFB $2A, $FA, $7F, $ED, $5B, $F8, $7F 15857 mark_3B88: DEFB $A7, $ED, $52, $C9 15858 mark_3B8C: DEFB $D6, $1C, $07, $07 15859 mark_3B90: DEFB $07, $07, $C9 15860 15861 ; data for input prompt messages 15862 mark_3B93: DEFB $DD, $E3, $EB, $E3, $F2 15863 mark_3B98: DEFB $F8, $D5, $DC, $30, $E3, $D0, $E3 15864 15865 ; Add_String, for building mnemonic 15866 mark_3B9F: DEFB $3E 15867 mark_3BA0: DEFB $E0, $32, $3E, $7D, $AF, $C5, $D5, $A7 15868 mark_3BA8: DEFB $28, $0B, $CB, $7E, $20, $03, $23, $18 15869 mark_3BB0: DEFB $F9, $3D, $23, $18, $F2, $CD, $BB, $7B 15870 mark_3BB8: DEFB $D1, $C1, $C9 15871 mark_3BBB: DEFB $ED, $5B, $3E, $7D, $7E 15872 mark_3BC0: DEFB $CB, $7F, $20, $05, $CD, $CB, $7B, $18 15873 mark_3BC8: DEFB $F2, $CB, $BF, $FE, $40, $30, $08, $12 15874 mark_3BD0: DEFB $13, $ED, $53, $3E, $7D, $23, $C9 15875 mark_3BD7: DEFB $23 15876 mark_3BD8: DEFB $ED, $53, $3E, $7D, $E5, $FE, $43, $30 15877 mark_3BE0: DEFB $06, $26, $7D, $6F, $6E, $18, $14, $FE 15878 mark_3BE8: DEFB $64, $30, $05, $26, $7D, $6F, $18, $0B 15879 mark_3BF0: DEFB $21, $FE, $7B, $E5, $26, $7D, $6F, $6E 15880 mark_3BF8: DEFB $26, $79, $E9, $CD, $BB, $7B, $E1, $C9 15881 ; 15882 ; data for mnemonics 15883 ; lower case are ZX inverse characters 15884 ; 15885 mark_3C00: DEFB $A7, $A8, $A9, $AA, $AD, $B1, $C0, $A6 15886 mark_3C08: DEFB $A6, $C1, $A6, $10, $43, $91, $10, $45 15887 mark_3C10: DEFB $91, $E7, $E7, $C3, $C5, $C1, $C2, $62 15888 mark_3C18: DEFB $A8, $45, $A8, $47, $D6, $49, $D6, $47 15889 mark_3C20: DEFB $A6, $49, $A6, $29, $26, $A6, $28, $35 15890 mark_3C28: DEFB $B1, $38, $28, $AB, $28, $28, $AB, $9C 15891 mark_3C30: DEFB $9D, $9E, $9F, $A0, $A1, $A2, $A3, $35 15892 mark_3C38: DEFB $3A, $38, $AD, $56, $31, $B1, $37, $2A 15893 mark_3C40: DEFB $B9, $4B, $BD, $2F, $B5, $CD, $58, $A9 15894 mark_3C48: DEFB $58, $A8, $38, $3A, $A7, $38, $C3, $26 15895 mark_3C50: DEFB $33, $A9, $3D, $34, $B7, $34, $B7, $28 15896 mark_3C58: DEFB $B5, $35, $34, $B5, $37, $38, $B9, $2F 15897 mark_3C60: DEFB $B5, $80, $D3, $E2, $CB, $CB, $29, $AE 15898 mark_3C68: DEFB $2A, $AE, $E5, $E8, $66, $1A, $A6, $4F 15899 mark_3C70: DEFB $E6, $10, $5C, $11, $DA, $45, $DA, $80 15900 mark_3C78: DEFB $80, $10, $41, $91, $5C, $DA, $CF, $CF 15901 mark_3C80: DEFB $80, $CF, $80, $80, $80, $80, $33, $BF 15902 mark_3C88: DEFB $BF, $33, $A8, $A8, $35, $B4, $35, $AA 15903 mark_3C90: DEFB $B5, $B2, $47, $A8, $49, $A8, $C7, $C9 15904 mark_3C98: DEFB $38, $31, $A6, $38, $37, $A6, $E4, $38 15905 mark_3CA0: DEFB $C7, $27, $2E, $B9, $37, $2A, $B8, $38 15906 mark_3CA8: DEFB $2A, $B9, $10, $28, $91, $33, $2A, $AC 15907 mark_3CB0: DEFB $B3, $AE, $38, $C3, $58, $A8, $2E, $B2 15908 mark_3CB8: DEFB $9C, $A4, $9D, $9E, $CD, $CD, $CD, $CD 15909 mark_3CC0: DEFB $49, $A9, $47, $A9, $2E, $9A, $37, $9A 15910 mark_3CC8: DEFB $CF, $CF, $80, $80, $5E, $1A, $DE, $E9 15911 mark_3CD0: DEFB $E9, $E0, $E0, $E0, $E0, $A6, $A6, $AE 15912 mark_3CD8: DEFB $B7, $80, $80, $AE, $A9, $2E, $B7, $29 15913 mark_3CE0: DEFB $B7, $CD, $28, $B5, $E2, $D3, $34, $B9 15914 mark_3CE8: DEFB $33, $34, $B5, $CB, $29, $2F, $33, $BF 15915 mark_3CF0: DEFB $D1, $D1, $D1, $D1, $D1, $2D, $26, $31 15916 mark_3CF8: DEFB $B9, $45, $2B, $A7, $10, $1D, $A9, $27 15917 ; 15918 ; data and data pointers for disassembler 15919 ; 15920 mark_3D00: DEFB $9F, $A6, $C9, $B3, $AE, $BB, $9D, $B6 15921 mark_3D08: DEFB $C6, $2D, $B1, $2E, $BD, $2E, $BE, $10 15922 mark_3D10: DEFB $41, $91, $10, $41, $15, $2A, $27, $91 15923 mark_3D18: DEFB $CD, $D3, $D9, $DF, $3C, $E8, $EB, $EE 15924 mark_3D20: DEFB $F3, $F3, $F3, $F5, $91, $81, $89, $6D 15925 mark_3D28: DEFB $6A, $F9, $7B, $3A, $70, $9C, $A1, $76 15926 mark_3D30: DEFB $A4, $AA, $AD, $FC, $B3, $96, $B8, $BB 15927 mark_3D38: DEFB $C1, $C7, $87, $1B, $81, $A1, $E4, $7F 15928 mark_3D40: DEFB $0F, $09, $5C, $27, $A8, $29, $AA, $37 15929 mark_3D48: DEFB $B1, $37, $B7, $2A, $BD, $31, $A9, $26 15930 mark_3D50: DEFB $9A, $2F, $B7, $34, $3A, $B9, $28, $A6 15931 mark_3D58: DEFB $26, $A9, $1A, $C1, $38, $B5, $26, $AB 15932 mark_3D60: DEFB $1A, $E9, $2E, $B3, $E9, $EF, $F4, $FA 15933 mark_3D68: DEFB $8F, $C7, $FA, $17, $00, $E0, $17, $13 15934 mark_3D70: DEFB $7A, $45, $00, $8A, $C5, $00, $F5, $59 15935 mark_3D78: DEFB $3E, $13, $77, $7A, $45, $00, $92, $C5 15936 mark_3D80: DEFB $9E, $58, $45, $13, $15, $AA, $C5, $6A 15937 mark_3D88: DEFB $13, $72, $45, $0B, $07, $B2, $C5, $07 15938 mark_3D90: DEFB $0B, $7F, $E8, $82, $87, $CB, $62, $5C 15939 mark_3D98: DEFB $2F, $90, $B8, $6B, $7F, $46, $7E, $81 15940 mark_3DA0: DEFB $00, $FA, $3E, $86, $7A, $43, $86, $92 15941 mark_3DA8: DEFB $C5, $6A, $FF, $5F, $6A, $7A, $3B, $86 15942 mark_3DB0: DEFB $92, $C5, $6A, $7F, $46, $7E, $82, $9E 15943 mark_3DB8: DEFB $CF, $92, $00, $7A, $A1, $2F, $8A, $C5 15944 mark_3DC0: DEFB $00, $7A, $A4, $2F, $8A, $C5, $00, $7A 15945 mark_3DC8: DEFB $A7, $2F, $8A, $C5, $00, $7A, $63, $00 15946 mark_3DD0: DEFB $92, $C5, $AA, $52, $62, $AA, $BA, $C5 15947 mark_3DD8: DEFB $00, $50, $B2, $15, $A2, $C5, $13, $6A 15948 mark_3DE0: DEFB $45, $11, $13, $9A, $C5, $13, $11, $00 15949 mark_3DE8: DEFB $BA, $3E, $B0, $FA, $B6, $B8, $7F, $BC 15950 mark_3DF0: DEFB $C4, $87, $D5, $B9, $E1, $D7, $BC, $E2 15951 mark_3DF8: DEFB $D7, $FA, $19, $00, $D8, $37, $13, $6A 15952 ; 15953 ; print data for menu & routines 15954 ; 15955 mark_3E00: DEFB $00, $00, $00, $00, $32, $2A, $33, $BA 15956 mark_3E08: DEFB $00, $00, $00, $00, $14, $14, $14, $94 15957 mark_3E10: DEFB $1C, $00, $35, $37, $2E, $33, $39, $00 15958 mark_3E18: DEFB $28, $34, $29, $AA, $1D, $00, $2D, $2A 15959 mark_3E20: DEFB $3D, $00, $29, $3A, $32, $B5, $1E, $00 15960 mark_3E28: DEFB $3C, $37, $2E, $39, $AA, $1F, $00, $2E 15961 mark_3E30: DEFB $33, $38, $2A, $37, $B9, $20, $00, $29 15962 mark_3E38: DEFB $2A, $31, $2A, $39, $AA, $21, $00, $39 15963 mark_3E40: DEFB $37, $26, $33, $38, $2B, $2A, $B7, $22 15964 mark_3E48: DEFB $00, $38, $2A, $26, $37, $28, $AD, $23 15965 mark_3E50: DEFB $00, $37, $2A, $35, $31, $26, $28, $AA 15966 mark_3E58: DEFB $24, $00, $26, $38, $38, $2A, $32, $27 15967 mark_3E60: DEFB $31, $2A, $B7, $25, $00, $37, $3A, $33 15968 mark_3E68: DEFB $00, $28, $34, $29, $AA, $26, $00, $28 15969 mark_3E70: DEFB $26, $31, $28, $3A, $31, $26, $39, $34 15970 mark_3E78: DEFB $B7, $27, $00, $28, $2D, $37, $0D, $00 15971 mark_3E80: DEFB $29, $3A, $32, $B5, $28, $00, $26, $38 15972 mark_3E88: DEFB $28, $2E, $2E, $00, $29, $3A, $32, $B5 15973 mark_3E90: DEFB $29, $00, $37, $2A, $33, $3A, $32, $27 15974 mark_3E98: DEFB $2A, $B7, $2A, $00, $2E, $32, $26, $2C 15975 mark_3EA0: DEFB $2A, $B7, $2B, $00, $32, $2A, $33, $3A 15976 mark_3EA8: DEFB $00, $9E, $80, $80, $00, $00, $00, $00 15977 mark_3EB0: DEFB $00, $00, $00, $00, $00, $00, $00, $00 15978 mark_3EB8: DEFB $00, $00, $00, $00, $00, $00, $00, $00 15979 mark_3EC0: DEFB $00, $00, $00, $00, $00, $00, $00, $00 15980 mark_3EC8: DEFB $00, $00, $00, $00, $00, $00, $00, $00 15981 mark_3ED0: DEFB $31, $2E, $32, $2E, $B9, $37, $34, $3A 15982 mark_3ED8: DEFB $39, $2E, $33, $2A, $80, $38, $39, $26 15983 mark_3EE0: DEFB $37, $39, $80, $26, $29, $29, $37, $2A 15984 mark_3EE8: DEFB $38, $38, $80, $2B, $2E, $33, $2E, $38 15985 mark_3EF0: DEFB $2D, $80, $1D, $00, $2B, $34, $37, $80 15986 mark_3EF8: DEFB $35, $37, $2E, $33, $39, $2A, $37, $80 15987 15988 ; addresses of routines 15989 mark_3F00: DEFB $23, $78 ;, $.dw, $7823 15990 mark_3F02: DEFB $20, $79 ; , $.dw, $7902 15991 mark_3F04: DEFB $53, $79 ;, $.dw, $7953 15992 mark_3F06: DEFB $FF, $FF 15993 mark_3F08: DEFB $FF, $FF 15994 mark_3F0A: DEFB $FF, $FF 15995 mark_3F0C: DEFB $FF, $FF 15996 mark_3F0E: DEFB $FF, $FF 15997 mark_3F10: DEFB $FF, $FF 15998 mark_3F12: DEFB $13, $38 ;, $.dw, $3813 15999 mark_3F14: DEFB $FF, $FF 16000 mark_3F16: DEFB $FF, $FF 16001 mark_3F18: DEFB $FF, $FF 16002 mark_3F1A: DEFB $FF, $FF 16003 mark_3F1C: DEFB $FF, $FF 16004 mark_3F1E: DEFB $FF, $FF 16005 16006 ; Read_Keyboard 16007 mark_3F20: DEFB $D5, $C5, $E5, $2A, $25, $40, $E5, $ED 16008 mark_3F28: DEFB $4B, $25, $40, $E1, $C5, $A7, $ED, $42 16009 mark_3F30: DEFB $28, $F5, $79, $3C, $28, $F1, $E1, $CD 16010 mark_3F38: DEFB $BD, $07, $7E, $E1, $C1, $D1, $FE, $76 16011 mark_3F40: DEFB $C8, $FE, $77, $C8, $FE, $00, $20, $05 16012 mark_3F48: DEFB $CD, $2A, $0A, $CF, $0C, $FE, $1C, $38 16013 mark_3F50: DEFB $CF, $FE, $2C, $30, $CB, $C9 16014 ; 16015 ; Menu 16016 ; 16017 mark_3F56: DEFB $21, $21 16018 mark_3F58: DEFB $40, $CB, $7E, $28, $04, $2A, $7B, $40 16019 mark_3F60: DEFB $E9, $21, $00, $7E, $06, $14, $3E, $03 16020 mark_3F68: DEFB $32, $21, $40, $11, $E1, $18, $CD, $9F 16021 mark_3F70: DEFB $7B, $CD, $53, $7B, $10, $F8, $01, $99 16022 mark_3F78: DEFB $7B, $CD, $3B, $7B, $2B, $7E, $D6, $1C 16023 mark_3F80: DEFB $47, $07, $6F, $26, $7F, $7E, $23, $66 16024 mark_3F88: DEFB $6F, $E5, $C5, $CD, $2A, $0A, $C1, $3E 16025 mark_3F90: DEFB $E0, $32, $3E, $7D, $78, $21, $10, $7E 16026 mark_3F98: DEFB $CD, $A5, $7B, $16, $1A, $CD, $53, $7B 16027 mark_3FA0: DEFB $3E, $76, $D7, $D7, $C9 16028 ; 16029 ; InputString, the heart of all routines 16030 ; 16031 mark_3FA5: DEFB $3E, $01, $32 16032 mark_3FA8: DEFB $21, $40, $21, $E0, $7F, $36, $17, $CD 16033 mark_3FB0: DEFB $C0, $7F, $CD, $20, $7F, $FE, $76, $20 16034 mark_3FB8: DEFB $10, $3E, $E0, $BD, $28, $F4, $36, $00 16035 mark_3FC0: DEFB $23, $22, $3E, $7D, $CD, $53, $7B, $2B 16036 mark_3FC8: DEFB $C9 16037 mark_3FC9: DEFB $FE, $77, $20, $0B, $3E, $E0, $BD 16038 mark_3FD0: DEFB $28, $DB, $CD, $BE, $7F, $2B, $18, $D5 16039 mark_3FD8: DEFB $77, $7B, $BD, $28, $D0, $23, $18, $CD 16040 ; 16041 ; mnemonic string, ram area for mnemonic to be built up 16042 ; 16043 mark_3FE0: DEFB $00, $00, $00, $00, $00, $00, $00, $00 16044 mark_3FE8: DEFB $00, $00, $00, $00, $00, $00, $00, $00 16045 ; 16046 ; spare bytes 16047 ; 16048 mark_3FF0: DEFB $00, $00, $00, $00, $00, $00, $00, $00 16049 ; 16050 ; next address for routine 16051 ; 16052 mark_3FF8: DEFB $00, $00 16053 ; 16054 ; finish address for routine 16055 ; 16056 mark_3FFA: DEFB $00, $00 16057 ; 16058 ; spare bytes 16059 ; 16060 mark_3FFC: DEFB $00, $00, $00 16061 mark_3FFF: DEFB $C9 ; ret 16062 16063 16064 #else 16065 ; 16066 ; 16067 ; 16068 Input_Prompt_Data equ $7B93 16069 Get_A_addresses equ $7902 16070 Next_Address equ $7FFB 16071 #endif 16072 16073 16074 16075 16076 16077 16078 16079 16080 #end ; required by zasm 16081 16082