sg81.html (139466B)
1 <HTML> 2 <HEAD> 3 <TITLE> 4 Assembly Listing of the Shoulders of Giants ZX81 ROM. 5 </TITLE> 6 </HEAD> 7 <BODY> 8 <font face = "Courier"> </font> 9 <PRE> 10 ; ========================================================= 11 ; An Assembly Listing of the "Shoulders of Giants" ZX81 ROM 12 ; ========================================================= 13 ; ------------------------- 14 ; Last updated: 23-OCT-2003 15 ; ------------------------- 16 ; 17 ; The "Shoulders of Giants" ZX81 ROM. 18 ; This file shows the altered sections of the ZX81/TS1000 ROM that produced 19 ; the customized sg81.rom. 20 ; The main feature is the inclusion of Newton Raphson square roots. 21 ; The square roots are executed 3 times faster than those in the 22 ; standard ROM. They are more accurate also and 23 ; 24 ; PRINT SQR 100 = INT SQR 100 gives the result 1 (true) not 0 (false) 25 ; 26 ; The input and storage of fractional numbers is improved 27 ; 28 ; PRINT 1/2 = .5 gives the result 1 (true) and not 0 (false) 29 ; 30 ; The output of fractional numbers to the ZX Printer is corrected 31 ; 32 ; LPRINT .00001 gives the output .00001 and not .0XYZ1 33 ; 34 ; Other alterations have been made to create the space required by the 35 ; new square root routine and some are obscure and would not otherwise have 36 ; been made. 37 ; Using uncompressed constants rectifies a logic error and improves speed. 38 39 #define DEFB .BYTE ; TASM cross-assembler definitions 40 #define DEFW .WORD 41 #define EQU .EQU 42 #define ORG .ORG 43 44 45 ; the backward references 46 47 <a name="subtract"></a><b>subtract</b> EQU $174C ; SUBTRACT 48 <a name="multiply"></a><b>multiply</b> EQU $176C ; multiply 49 <a name="division"></a><b>division</b> EQU $1882 ; division 50 <a name="addition"></a><b>addition</b> EQU $1755 ; addition 51 <a name="truncate"></a><b>truncate</b> EQU $18E4 ; truncate 52 <a name="e_to_fp"></a><b>e_to_fp</b> EQU $155A ; e-to-fp 53 <a name="TEST_ROOM"></a><b>TEST_ROOM</b> EQU $0EC5 ; TEST-ROOM 54 <a name="FIND_INT"></a><b>FIND_INT</b> EQU $0EA7 ; FIND-INT 55 <a name="STACK_A"></a><b>STACK_A</b> EQU $151D ; STACK-A 56 <a name="STACK_BC"></a><b>STACK_BC</b> EQU $1520 ; STACK-BC 57 <a name="STK_FETCH"></a><b>STK_FETCH</b> EQU $13F8 ; STK-FETCH 58 <a name="STK_STO_s"></a><b>STK_STO_s</b> EQU $12C3 ; STK-STO-$ 59 <a name="FP_TO_A"></a><b>FP_TO_A</b> EQU $15CD ; FP-TO-A 60 <a name="CLASS_06"></a><b>CLASS_06</b> EQU $0D92 ; CLASS-06 61 <a name="CHECK_2"></a><b>CHECK_2</b> EQU $0D22 ; CHECK-2 62 <a name="SCANNING"></a><b>SCANNING</b> EQU $0F55 ; SCANNING 63 <a name="PRINT_FP"></a><b>PRINT_FP</b> EQU $15DB ; PRINT-FP 64 65 ; ----------------------------------------------------------------------------- 66 67 <a name="ORG"></a><b>ORG</b> $0010 68 69 ;-------------------------------- 70 ; THE <b><font color=#333388>'PRINT A CHARACTER'</font></b> RESTART 71 ;-------------------------------- 72 ; This restart prints the character in the accumulator using the alternate 73 ; register set so there is no requirement to save the main registers. 74 ; There is sufficient room available to separate a space (zero) from other 75 ; characters as leading spaces need not be considered with a space. 76 ; <font color=#9900FF>Note.</font> the accumulator is preserved only when printing to the screen. 77 78 <a name="PRINT_A"></a><b>PRINT_A</b> AND A ; test for zero - space. 79 JP NZ,<A href="#PRINT_CH">PRINT_CH</a> ; jump forward if not to PRINT-CH. 80 81 JP <A href="#PRINT_SP">PRINT_SP</a> ; jump forward to PRINT-SP. 82 83 ; --- 84 85 <font color=#3333FF> DEFB $01 ;+ unused location. Version. PRINT PEEK 23</font> 86 87 ; ----------------------------------------------------------------------------- 88 89 <a name="ORG"></a><b>ORG</b> $0028 90 91 92 ; ----------------------- 93 ; THE <b><font color=#333388>'CALCULATE'</font></b> RESTART 94 ; ----------------------- 95 ; An immediate jump is made to the CALCULATE routine the address of which 96 ; has changed. 97 98 <a name="FP_CALC"></a><b>FP_CALC</b> <font color=#3333FF> JP <A href="#CALCULATE">CALCULATE</a> ;+ jump to the NEW calculate routine address.</font> 99 100 <a name="end_calc"></a><b>end_calc</b> POP AF ; drop the calculator return address RE-ENTRY 101 EXX ; switch to the other set. 102 103 EX (SP),HL ; transfer H'L' to machine stack for the 104 ; return address. 105 ; when exiting recursion then the previous 106 ; pointer is transferred to H'L'. 107 108 EXX ; back to main set. 109 RET ; return. 110 111 ; ----------------------------------------------------------------------------- 112 113 <a name="ORG"></a><b>ORG</b> $13AE 114 115 ; ------------------------ 116 ; THE <b><font color=#333388>'L-ENTER'</font></b> SUBROUTINE 117 ; ------------------------ 118 ; Part of the LET command contains a natural subroutine which is a 119 ; conditional LDIR. The copy only occurs of BC is non-zero. 120 121 <a name="L_ENTER"></a><b>L_ENTER</b> EX DE,HL ; 122 123 124 <a name="COND_MV"></a><b>COND_MV</b> LD A,B ; 125 OR C ; 126 RET Z ; 127 128 PUSH DE ; 129 130 LDIR ; Copy Bytes 131 132 POP HL ; 133 RET ; Return. 134 135 ; ----------------------------------------------------------------------------- 136 137 <a name="ORG"></a><b>ORG</b> $14E5 138 139 ; --------------------- 140 ; THE <b><font color=#333388>'NEXT DIGIT'</font></b> LOOP 141 ; --------------------- 142 ; Within the 'DECIMAL TO FLOATING POINT' routine, swapping the multiply and 143 ; divide literals preserves accuracy and ensures that .5 is evaluated 144 ; as 5/10 and not as .1 * 5. 145 146 <a name="NXT_DGT_1"></a><b>NXT_DGT_1</b> RST 20H ; NEXT-CHAR 147 CALL $1514 ; routine STK-DIGIT 148 JR C,$14F5 ; forward to E-FORMAT 149 150 151 RST 28H ;; FP-CALC 152 DEFB $E0 ;;get-mem-0 153 DEFB $A4 ;;stk-ten 154 <font color=#FF3333>;;; DEFB $05 ;;division</font> 155 <font color=#3333FF> DEFB $04 ;;+multiply</font> 156 DEFB $C0 ;;st-mem-0 157 <font color=#FF3333>;;; DEFB $04 ;;multiply</font> 158 <font color=#3333FF> DEFB $05 ;;+division</font> 159 DEFB $0F ;;addition 160 DEFB $34 ;;end-calc 161 162 JR NXT_DGT_1 ; loop back till exhausted to NXT-DGT-1 163 164 ; ----------------------------------------------------------------------------- 165 166 <a name="ORG"></a><b>ORG</b> $16B2 167 168 ; ------------------------------------- 169 ; THE <b><font color=#333388>'FLOATING POINT PRINT ZEROS'</font></b> LOOP 170 ; ------------------------------------- 171 172 ; This branch deals with zeros after decimal point. 173 ; e.g. .01 or .0000999 174 ; <font color=#9900FF>Note.</font> that printing to the ZX Printer destroys A and that A should be 175 ; initialized to '0' at each stage of the loop. 176 ; Originally LPRINT .00001 printed as .0XYZ1 177 178 <a name="PF_ZEROS"></a><b>PF_ZEROS</b> NEG ; negate makes number positive 1 to 4. 179 LD B,A ; zero count to B. 180 181 LD A,$1B ; prepare character '.' 182 RST 10H ; PRINT-A 183 184 <a name="PF_ZRO_LP"></a><b>PF_ZRO_LP</b> LD A,$1C ; prepare a '0' in the accumulator each time. 185 186 <a name="PFZROLP"></a><b>PFZROLP</b> RST 10H ; PRINT-A 187 188 <font color=#3333FF> DJNZ <A href="#PF_ZRO_LP">PF_ZRO_LP</a> ;+ New loop back to PF-ZRO-LP</font> 189 190 <font color=#FF3333>;;; DJNZ <A href="#PFZROLP">PFZROLP</a> ; obsolete loop back to PFZROLP</font> 191 192 193 ; and continue with trailing fractional digits... 194 195 ; ----------------------------------------------------------------------------- 196 197 <a name="ORG"></a><b>ORG</b> $1915 198 199 200 ; Up to this point all routine addresses have been maintained so that the 201 ; modified ROM is compatible with any machine-code software that uses ROM 202 ; routines. 203 ; The final section does not maintain address entry points as the routines 204 ; within are not generally called directly. 205 206 ;******************************** 207 ;** FLOATING-POINT CALCULATOR ** 208 ;******************************** 209 210 ; As a general rule the calculator avoids using the IY register. 211 ; The exception is the 'val' function. 212 ; So an assembly language programmer who has disabled interrupts to use IY 213 ; for other purposes can still use the calculator for mathematical 214 ; purposes. 215 216 217 ; ------------------------ 218 ; THE <b><font color=#333388>'TABLE OF CONSTANTS'</font></b> 219 ; ------------------------ 220 ; The ZX81 has only floating-point number representation. 221 ; Both the ZX80 and the ZX Spectrum have integer numbers in some form. 222 ; This table has been modified so that the constants are held in their 223 ; uncompressed, ready-to-party, 5-byte form. 224 225 <font color=#FF3333>;;; L1915: DEFB $00 ;;Bytes: 1</font> 226 <font color=#FF3333>;;; DEFB $B0 ;;Exponent $00</font> 227 <font color=#FF3333>;;; DEFB $00 ;;(+00,+00,+00)</font> 228 <font color=#FF3333>;;; L1918: DEFB $31 ;;Exponent $81, Bytes: 1</font> 229 <font color=#FF3333>;;; DEFB $00 ;;(+00,+00,+00)</font> 230 <font color=#FF3333>;;; L191A: DEFB $30 ;;Exponent: $80, Bytes: 1</font> 231 <font color=#FF3333>;;; DEFB $00 ;;(+00,+00,+00)</font> 232 <font color=#FF3333>;;; L191C: DEFB $F1 ;;Exponent: $81, Bytes: 4</font> 233 <font color=#FF3333>;;; DEFB $49,$0F,$DA,$A2 ;;</font> 234 <font color=#FF3333>;;; L1921: DEFB $34 ;;Exponent: $84, Bytes: 1</font> 235 <font color=#FF3333>;;; DEFB $20 ;;(+00,+00,+00)</font> 236 237 <a name="TAB_CNST"></a><b>TAB_CNST</b> DEFB $00 ; the value zero. 238 DEFB $00 ; 239 DEFB $00 ; 240 DEFB $00 ; 241 DEFB $00 ; 242 243 DEFB $81 ; the floating point value 1. 244 DEFB $00 ; 245 DEFB $00 ; 246 DEFB $00 ; 247 DEFB $00 ; 248 249 DEFB $80 ; the floating point value 1/2. 250 DEFB $00 ; 251 DEFB $00 ; 252 DEFB $00 ; 253 DEFB $00 ; 254 255 DEFB $81 ; the floating point value pi/2. 256 DEFB $49 ; 257 DEFB $0F ; 258 DEFB $DA ; 259 DEFB $A2 ; 260 261 DEFB $84 ; the floating point value ten. 262 DEFB $20 ; 263 DEFB $00 ; 264 DEFB $00 ; 265 DEFB $00 ; 266 267 ; ------------------------ 268 ; THE <b><font color=#333388>'TABLE OF ADDRESSES'</font></b> 269 ; ------------------------ 270 ; 271 ; Starts with binary operations which have two operands and one result. 272 ; three pseudo binary operations first. 273 274 <a name="tbl_addrs"></a><b>tbl_addrs</b> DEFW jump_true ; $00 Address: $1C2F - jump-true 275 DEFW exchange ; $01 Address: $1A72 - exchange 276 DEFW delete ; $02 Address: $19E3 - delete 277 278 ; true binary operations. 279 280 DEFW subtract ; $03 Address: $174C - subtract 281 DEFW multiply ; $04 Address: $176C - multiply 282 DEFW division ; $05 Address: $1882 - division 283 DEFW to_power ; $06 Address: $1DE2 - to-power 284 DEFW or ; $07 Address: $1AED - or 285 286 DEFW no_v_no ; $08 Address: $1B03 - no-&-no 287 DEFW no_l_eql ; $09 Address: $1B03 - no-l-eql 288 DEFW no_l_eql ; $0A Address: $1B03 - no-gr-eql 289 DEFW no_l_eql ; $0B Address: $1B03 - nos-neql 290 DEFW no_l_eql ; $0C Address: $1B03 - no-grtr 291 DEFW no_l_eql ; $0D Address: $1B03 - no-less 292 DEFW no_l_eql ; $0E Address: $1B03 - nos-eql 293 DEFW addition ; $0F Address: $1755 - addition 294 295 DEFW str_v_no ; $10 Address: $1AF8 - str-&-no 296 DEFW no_l_eql ; $11 Address: $1B03 - str-l-eql 297 DEFW no_l_eql ; $12 Address: $1B03 - str-gr-eql 298 DEFW no_l_eql ; $13 Address: $1B03 - strs-neql 299 DEFW no_l_eql ; $14 Address: $1B03 - str-grtr 300 DEFW no_l_eql ; $15 Address: $1B03 - str-less 301 DEFW no_l_eql ; $16 Address: $1B03 - strs-eql 302 DEFW strs_add ; $17 Address: $1B62 - strs-add 303 304 ; unary follow 305 306 DEFW negate ; $18 Address: $1AA0 - neg 307 308 DEFW code ; $19 Address: $1C06 - code 309 DEFW val ; $1A Address: $1BA4 - val 310 DEFW len ; $1B Address: $1C11 - len 311 DEFW sin ; $1C Address: $1D49 - sin 312 DEFW cos ; $1D Address: $1D3E - cos 313 DEFW tan ; $1E Address: $1D6E - tan 314 DEFW asn ; $1F Address: $1DC4 - asn 315 DEFW acs ; $20 Address: $1DD4 - acs 316 DEFW atn ; $21 Address: $1D76 - atn 317 DEFW ln ; $22 Address: $1CA9 - ln 318 DEFW exp ; $23 Address: $1C5B - exp 319 DEFW int ; $24 Address: $1C46 - int 320 DEFW sqr ; $25 Address: $1DDB - sqr 321 DEFW sgn ; $26 Address: $1AAF - sgn 322 DEFW abs ; $27 Address: $1AAA - abs 323 DEFW peek ; $28 Address: $1A1B - peek 324 DEFW usr_no ; $29 Address: $1AC5 - usr-no 325 DEFW strS ; $2A Address: $1BD5 - str$ 326 DEFW chrS ; $2B Address: $1B8F - chrs 327 DEFW not ; $2C Address: $1AD5 - not 328 329 ; end of true unary 330 331 DEFW MOVE_FP ; $2D Address: $19F6 - duplicate 332 DEFW n_mod_m ; $2E Address: $1C37 - n-mod-m 333 334 DEFW JUMP ; $2F Address: $1C23 - jump 335 DEFW stk_data ; $30 Address: $19FC - stk-data 336 337 DEFW dec_jr_nz ; $31 Address: $1C17 - dec-jr-nz 338 DEFW less_0 ; $32 Address: $1ADB - less-0 339 DEFW greater_0 ; $33 Address: $1ACE - greater-0 340 DEFW end_calc ; $34 Address: $002B - end-calc 341 DEFW get_argt ; $35 Address: $1D18 - get-argt 342 DEFW truncate ; $36 Address: $18E4 - truncate 343 DEFW fp_calc_2 ; $37 Address: $19E4 - fp-calc-2 344 DEFW e_to_fp ; $38 Address: $155A - e-to-fp 345 346 ; the following are just the next available slots for the 128 compound 347 ; literals which are in range $80 - $FF. 348 349 DEFW seriesg_x ; $39 Address: $1A7F - series-xx $80 - $9F. 350 DEFW stk_con_x ; $3A Address: $1A51 - stk-const-xx $A0 - $BF. 351 DEFW sto_mem_x ; $3B Address: $1A63 - st-mem-xx $C0 - $DF. 352 DEFW get_mem_x ; $3C Address: $1A45 - get-mem-xx $E0 - $FF. 353 354 ; ------------------------------- 355 ; THE <b><font color=#333388>'FLOATING POINT CALCULATOR'</font></b> 356 ; ------------------------------- 357 ; 358 ; 359 360 <a name="CALCULATE"></a><b>CALCULATE</b> CALL <A href="#STK_PNTRS">STK_PNTRS</a> ; routine STK-PNTRS is called to set up the 361 ; calculator stack pointers for a default 362 ; unary operation. HL = last value on stack. 363 ; DE = STKEND first location after stack. 364 365 ; the calculate routine is called at this point by the series generator... 366 367 <a name="GEN_ENT_1"></a><b>GEN_ENT_1</b> LD A,B ; fetch the Z80 B register to A 368 LD ($401E),A ; and store value in system variable BREG. 369 ; this will be the counter for dec-jr-nz 370 ; or if used from fp-calc2 the calculator 371 ; instruction. 372 373 ; ... and again later at this point 374 375 <a name="GEN_ENT_2"></a><b>GEN_ENT_2</b> EXX ; switch sets 376 EX (SP),HL ; and store the address of next instruction, 377 ; the return address, in H'L'. 378 ; If this is a recursive call then the H'L' 379 ; of the previous invocation goes on stack. 380 ; c.f. end-calc. 381 EXX ; switch back to main set. 382 383 ; this is the re-entry looping point when handling a string of literals. 384 385 <a name="RE_ENTRY"></a><b>RE_ENTRY</b> LD ($401C),DE ; save end of stack in system variable STKEND 386 EXX ; switch to alt 387 LD A,(HL) ; get next literal 388 INC HL ; increase pointer' 389 390 ; single operation jumps back to here 391 392 <a name="SCAN_ENT"></a><b>SCAN_ENT</b> PUSH HL ; save pointer on stack * 393 AND A ; now test the literal 394 JP P,<A href="#FIRST_3D">FIRST_3D</a> ; forward to FIRST-3D if in range $00 - $3D 395 ; anything with bit 7 set will be one of 396 ; 128 compound literals. 397 398 ; Compound literals have the following format. 399 ; bit 7 set indicates compound. 400 ; bits 6-5 the subgroup 0-3. 401 ; bits 4-0 the embedded parameter $00 - $1F. 402 ; The subgroup 0-3 needs to be manipulated to form the next available four 403 ; address places after the simple literals in the address table. 404 405 LD D,A ; save literal in D 406 AND $60 ; and with 01100000 to isolate subgroup 407 RRCA ; rotate bits 408 RRCA ; 4 places to right 409 RRCA ; not five as we need offset * 2 410 RRCA ; 00000xx0 411 ADD A,$72 ; add ($39 * 2) to give correct offset. 412 ; alter above if you add more literals. 413 LD L,A ; store in L for later indexing. 414 LD A,D ; bring back compound literal 415 AND $1F ; use mask to isolate parameter bits 416 JR <A href="#ENT_TABLE">ENT_TABLE</a> ; forward to ENT-TABLE 417 418 ; --- 419 420 ; the branch was here with simple literals. 421 422 <a name="FIRST_3D"></a><b>FIRST_3D</b> CP $18 ; compare with first unary operations. 423 JR NC,<A href="#DOUBLE_A">DOUBLE_A</a> ; to DOUBLE-A with unary operations 424 425 ; it is binary so adjust pointers. 426 427 EXX ; 428 LD BC,$FFFB ; the value -5 429 LD D,H ; transfer HL, the last value, to DE. 430 LD E,L ; 431 ADD HL,BC ; subtract 5 making HL point to second 432 ; value. 433 EXX ; 434 435 <a name="DOUBLE_A"></a><b>DOUBLE_A</b> RLCA ; double the literal 436 LD L,A ; and store in L for indexing 437 438 <a name="ENT_TABLE"></a><b>ENT_TABLE</b> LD DE,tbl_addrs ; Address: tbl-addrs 439 LD H,$00 ; prepare to index 440 ADD HL,DE ; add to get address of routine 441 LD E,(HL) ; low byte to E 442 INC HL ; 443 LD D,(HL) ; high byte to D 444 445 LD HL,RE_ENTRY ; Address: RE-ENTRY 446 EX (SP),HL ; goes on machine stack 447 ; address of next literal goes to HL. * 448 449 450 PUSH DE ; now the address of routine is stacked. 451 EXX ; back to main set 452 ; avoid using IY register. 453 LD BC,($401D) ; STKEND_hi 454 ; nothing much goes to C but BREG to B 455 ; and continue into next ret instruction 456 ; which has a dual identity 457 458 459 ; ----------------------- 460 ; THE <b><font color=#333388>'DELETE'</font></b> SUBROUTINE 461 ; ----------------------- 462 ; <font color=#339933>(offset $02: 'delete')</font> 463 ; A simple return but when used as a calculator literal this 464 ; deletes the last value from the calculator stack. 465 ; On entry, as always with binary operations, 466 ; HL=first number, DE=second number 467 ; On exit, HL=result, DE=stkend. 468 ; So nothing to do 469 470 <a name="delete"></a><b>delete</b> RET ; return - indirect jump if from above. 471 472 ; --------------------------------- 473 ; THE <b><font color=#333388>'SINGLE OPERATION'</font></b> SUBROUTINE 474 ; --------------------------------- 475 ; offset $37: 'fp-calc-2' 476 ; this single operation is used, in the first instance, to evaluate most 477 ; of the mathematical and string functions found in BASIC expressions. 478 479 <a name="fp_calc_2"></a><b>fp_calc_2</b> POP AF ; drop return address. 480 LD A,($401E) ; load accumulator from system variable BREG 481 ; value will be literal eg. 'tan' 482 EXX ; switch to alt 483 JR <A href="#SCAN_ENT">SCAN_ENT</a> ; back to SCAN-ENT 484 ; next literal will be end-calc in scanning 485 486 ; ------------------------------ 487 ; THE <b><font color=#333388>'TEST 5 SPACES'</font></b> SUBROUTINE 488 ; ------------------------------ 489 ; This routine is called from MOVE-FP, STK-CONST and STK-STORE to 490 ; test that there is enough space between the calculator stack and the 491 ; machine stack for another five-byte value. It returns with BC holding 492 ; the value 5 ready for any subsequent LDIR. 493 494 <a name="TEST_5_SP"></a><b>TEST_5_SP</b> PUSH DE ; save 495 PUSH HL ; registers 496 LD BC,$0005 ; an overhead of five bytes 497 CALL <A href="#TEST_ROOM">TEST_ROOM</a> ; routine TEST-ROOM tests free RAM raising 498 ; an error if not. 499 POP HL ; else restore 500 POP DE ; registers. 501 RET ; return with BC set at 5. 502 503 504 ; --------------------------------------------- 505 ; THE <b><font color=#333388>'MOVE A FLOATING POINT NUMBER'</font></b> SUBROUTINE 506 ; --------------------------------------------- 507 ; offset $2D: 'duplicate' 508 ; This simple routine is a 5-byte LDIR instruction 509 ; that incorporates a memory check. 510 ; When used as a calculator literal it duplicates the last value on the 511 ; calculator stack. 512 ; Unary so on entry HL points to last value, DE to stkend 513 514 <a name="MOVE_FP"></a><b>MOVE_FP</b> CALL <A href="#TEST_5_SP">TEST_5_SP</a> ; routine TEST-5-SP test free memory 515 ; and sets BC to 5. 516 517 LDIR ; copy the five bytes. 518 RET ; return with DE addressing new STKEND 519 ; and HL addressing new last value. 520 521 ; ------------------------------- 522 ; THE <b><font color=#333388>'STACK LITERALS'</font></b> SUBROUTINE 523 ; ------------------------------- 524 ; offset $30: 'stk-data' 525 ; When a calculator subroutine needs to put a value on the calculator 526 ; stack that is not a regular constant this routine is called with a 527 ; variable number of following data bytes that convey to the routine 528 ; the floating point form as succinctly as is possible. 529 530 <a name="stk_data"></a><b>stk_data</b> LD H,D ; transfer STKEND 531 LD L,E ; to HL for result. 532 533 <a name="STK_CONST"></a><b>STK_CONST</b> CALL <A href="#TEST_5_SP">TEST_5_SP</a> ; routine TEST-5-SP tests that room exists 534 ; and sets BC to $05. 535 536 EXX ; switch to alternate set 537 PUSH HL ; save the pointer to next literal on stack 538 EXX ; switch back to main set 539 540 EX (SP),HL ; pointer to HL, destination to stack. 541 542 <font color=#FF3333>;;; PUSH BC ; save BC - value 5 from test room. No need.</font> 543 544 LD A,(HL) ; fetch the byte following 'stk-data' 545 AND $C0 ; isolate bits 7 and 6 546 RLCA ; rotate 547 RLCA ; to bits 1 and 0 range $00 - $03. 548 LD C,A ; transfer to C 549 INC C ; and increment to give number of bytes 550 ; to read. $01 - $04 551 LD A,(HL) ; reload the first byte 552 AND $3F ; mask off to give possible exponent. 553 JR NZ,<A href="#FORM_EXP">FORM_EXP</a> ; forward to FORM-EXP if it was possible to 554 ; include the exponent. 555 556 ; else byte is just a byte count and exponent comes next. 557 558 INC HL ; address next byte and 559 LD A,(HL) ; pick up the exponent ( - $50). 560 561 <a name="FORM_EXP"></a><b>FORM_EXP</b> ADD A,$50 ; now add $50 to form actual exponent 562 LD (DE),A ; and load into first destination byte. 563 LD A,$05 ; load accumulator with $05 and 564 SUB C ; subtract C to give count of trailing 565 ; zeros plus one. 566 INC HL ; increment source 567 INC DE ; increment destination 568 <font color=#FF3333>;;; LD B,$00 ; prepare to copy. <font color=#9900FF>Note.</font> B is zero.</font> 569 LDIR ; copy C bytes 570 571 <font color=#FF3333>;;; POP BC ; restore 5 counter to BC.</font> 572 573 EX (SP),HL ; put HL on stack as next literal pointer 574 ; and the stack value - result pointer - 575 ; to HL. 576 577 EXX ; switch to alternate set. 578 POP HL ; restore next literal pointer from stack 579 ; to H'L'. 580 EXX ; switch back to main set. 581 582 LD B,A ; zero count to B 583 XOR A ; clear accumulator 584 585 <a name="STK_ZEROS"></a><b>STK_ZEROS</b> DEC B ; decrement B counter 586 RET Z ; return if zero. >> 587 ; DE points to new STKEND 588 ; HL to new number. 589 590 LD (DE),A ; else load zero to destination 591 INC DE ; increase destination 592 JR <A href="#STK_ZEROS">STK_ZEROS</a> ; loop back to STK-ZEROS until done. 593 594 ; ------------------------------- 595 ; THE <b><font color=#333388>'SKIP CONSTANTS'</font></b> SUBROUTINE 596 ; ------------------------------- 597 ; This routine traversed variable-length entries in the table of constants, 598 ; stacking intermediate, unwanted constants onto a dummy calculator stack, 599 ; in the first five bytes of the ZX81 ROM. 600 ; Since the table now uses uncompressed values, some extra ROM space is 601 ; required for the table but much more is released by getting rid of routines 602 ; like this. 603 604 <font color=#FF3333>;;; L1A2D: AND A ; test if initially zero.</font> 605 <font color=#FF3333>;;; L1A2E: RET Z ; return if zero. >></font> 606 <font color=#FF3333>;;; PUSH AF ; save count.</font> 607 <font color=#FF3333>;;; PUSH DE ; and normal STKEND</font> 608 <font color=#FF3333>;;; LD DE,$0000 ; dummy value for STKEND at start of ROM</font> 609 <font color=#FF3333>;;; CALL STK_CONST ; routine STK-CONST works through variable</font> 610 <font color=#FF3333>;;; ; length records.</font> 611 <font color=#FF3333>;;; POP DE ; restore real STKEND</font> 612 <font color=#FF3333>;;; POP AF ; restore count</font> 613 <font color=#FF3333>;;; DEC A ; decrease</font> 614 <font color=#FF3333>;;; JR L1A2E ; loop back to SKIP-NEXT</font> 615 616 ; -------------------------------- 617 ; THE <b><font color=#333388>'MEMORY LOCATION'</font></b> SUBROUTINE 618 ; -------------------------------- 619 ; This routine, when supplied with a base address in HL and an index in A, 620 ; will calculate the address of the A'th entry, where each entry occupies 621 ; five bytes. It is used for addressing floating-point numbers in the 622 ; calculator's memory area. 623 624 <a name="LOC_MEM"></a><b>LOC_MEM</b> LD C,A ; store the original number $00-$1F. 625 RLCA ; double. 626 RLCA ; quadruple. 627 ADD A,C ; now add original value to multiply by five. 628 629 LD C,A ; place the result in C. 630 LD B,$00 ; set B to 0. 631 ADD HL,BC ; add to form address of start of number in HL. 632 633 RET ; return. 634 635 ; ------------------------------------- 636 ; THE <b><font color=#333388>'GET FROM MEMORY AREA'</font></b> SUBROUTINE 637 ; ------------------------------------- 638 ; offsets $E0 to $FF: 'get-mem-0', 'get-mem-1' etc. 639 ; A holds $00-$1F offset. 640 ; The calculator stack increases by 5 bytes. 641 ; <font color=#9900FF>Note.</font> first two instructions have been swapped to create a subroutine. 642 643 <a name="get_mem_x"></a><b>get_mem_x</b> LD HL,($401F) ; MEM is base address of the memory cells. 644 645 <a name="INDEX_5"></a><b>INDEX_5</b> PUSH DE ; save STKEND 646 647 CALL <A href="#LOC_MEM">LOC_MEM</a> ; routine LOC-MEM so that HL = first byte 648 CALL <A href="#MOVE_FP">MOVE_FP</a> ; routine MOVE-FP moves 5 bytes with memory 649 ; check. 650 ; DE now points to new STKEND. 651 POP HL ; the original STKEND is now RESULT pointer. 652 RET ; return. 653 654 ; --------------------------------- 655 ; THE <b><font color=#333388>'STACK A CONSTANT'</font></b> SUBROUTINE 656 ; --------------------------------- 657 ; <font color=#339933>(offset $A0: 'stk-zero')</font> 658 ; <font color=#339933>(offset $A1: 'stk-one')</font> 659 ; <font color=#339933>(offset $A2: 'stk-half')</font> 660 ; <font color=#339933>(offset $A3: 'stk-pi/2')</font> 661 ; <font color=#339933>(offset $A4: 'stk-ten')</font> 662 ; This routine allows a one-byte instruction to stack up to 32 constants 663 ; held in short form in a table of constants. In fact only 5 constants are 664 ; required. On entry the A register holds the literal ANDed with $1F. 665 ; 666 ; It wasn't very efficient and it is better to hold the 667 ; numbers in full, five byte form and stack them in a similar manner 668 ; to that which which is used by the above routine. 669 670 <a name="stk_con_x"></a><b>stk_con_x</b> LD HL,TAB_CNST ; Address: Table of constants. 671 672 JR <A href="#INDEX_5">INDEX_5</a> ; and join subsroutine above. 673 674 ; --- 675 676 <font color=#FF3333>;;; LD H,D ; save STKEND - required for result</font> 677 <font color=#FF3333>;;; LD L,E ;</font> 678 <font color=#FF3333>;;; EXX ; swap</font> 679 <font color=#FF3333>;;; PUSH HL ; save pointer to next literal</font> 680 <font color=#FF3333>;;; LD HL,L1515 ; Address: stk-zero - start of table of</font> 681 <font color=#FF3333>;;; ; constants</font> 682 <font color=#FF3333>;;; EXX ;</font> 683 <font color=#FF3333>;;; CALL SKIP_CONS ; routine SKIP-CONS</font> 684 <font color=#FF3333>;;; CALL STK_CONST ; routine STK-CONST</font> 685 <font color=#FF3333>;;; EXX ;</font> 686 <font color=#FF3333>;;; POP HL ; restore pointer to next literal.</font> 687 <font color=#FF3333>;;; EXX ;</font> 688 <font color=#FF3333>;;; RET ; return.</font> 689 690 ; --------------------------------------- 691 ; THE <b><font color=#333388>'STORE IN A MEMORY AREA'</font></b> SUBROUTINE 692 ; --------------------------------------- 693 ; Offsets $C0 to $DF: 'st-mem-0', 'st-mem-1' etc. 694 ; Although 32 memory storage locations can be addressed, only six 695 ; $C0 to $C5 are required by the ROM and only the thirty bytes (6*5) 696 ; required for these are allocated. ZX81 programmers who wish to 697 ; use the floating point routines from assembly language may wish to 698 ; alter the system variable MEM to point to 160 bytes of RAM to have 699 ; use the full range available. 700 ; A holds derived offset $00-$1F. 701 ; Unary so on entry HL points to last value, DE to STKEND. 702 703 <a name="sto_mem_x"></a><b>sto_mem_x</b> PUSH HL ; save the result pointer. 704 EX DE,HL ; transfer to DE. 705 LD HL,($401F) ; fetch MEM the base of memory area. 706 CALL <A href="#LOC_MEM">LOC_MEM</a> ; routine LOC-MEM sets HL to the destination. 707 EX DE,HL ; swap - HL is start, DE is destination. 708 709 <font color=#FF3333>;;; CALL <A href="#MOVE_FP">MOVE_FP</a> ; routine MOVE-FP.</font> 710 <font color=#FF3333>;;; ; <font color=#9900FF>Note.</font> a short ld bc,5; ldir</font> 711 <font color=#FF3333>;;; ; the embedded memory check is not required</font> 712 <font color=#FF3333>;;; ; so these instructions would be faster!</font> 713 714 <font color=#3333FF> LD C,$05 ;+ one extra byte but </font> 715 <font color=#3333FF> LDIR ;+ faster and no memory check.</font> 716 717 EX DE,HL ; DE = STKEND 718 POP HL ; restore original result pointer 719 RET ; return. 720 721 ; ------------------------- 722 ; THE <b><font color=#333388>'EXCHANGE'</font></b> SUBROUTINE 723 ; ------------------------- 724 ; offset $01: 'exchange' 725 ; This routine exchanges the last two values on the calculator stack 726 ; On entry, as always with binary operations, 727 ; HL=first number, DE=second number 728 ; On exit, HL=result, DE=stkend. 729 730 <a name="exchange"></a><b>exchange</b> LD B,$05 ; there are five bytes to be swapped 731 732 ; start of loop. 733 734 <a name="SWAP_BYTE"></a><b>SWAP_BYTE</b> LD A,(DE) ; each byte of second 735 <font color=#FF3333>;;; LD C,(HL) ; each byte of first</font> 736 <font color=#FF3333>;;; EX DE,HL ; swap pointers</font> 737 <font color=#3333FF> ld c,a ;+</font> 738 <font color=#3333FF> ld a,(hl) ;+</font> 739 LD (DE),A ; store each byte of first 740 LD (HL),C ; store each byte of second 741 INC HL ; advance both 742 INC DE ; pointers. 743 DJNZ <A href="#SWAP_BYTE">SWAP_BYTE</a> ; loop back to SWAP-BYTE until all 5 done. 744 745 <font color=#FF3333>;;; EX DE,HL ; even up the exchanges (one byte saved)</font> 746 747 RET ; return. 748 749 ; --------------------------------- 750 ; THE <b><font color=#333388>'SERIES GENERATOR'</font></b> SUBROUTINE 751 ; --------------------------------- 752 ; offset $86: 'series-06' 753 ; offset $88: 'series-08' 754 ; offset $8C: 'series-0C' 755 ; The ZX81 uses Chebyshev polynomials to generate approximations for 756 ; SIN, ATN, LN and EXP. These are named after the Russian mathematician 757 ; Pafnuty Chebyshev, born in 1821, who did much pioneering work on numerical 758 ; series. As far as calculators are concerned, Chebyshev polynomials have an 759 ; advantage over other series, for example the Taylor series, as they can 760 ; reach an approximation in just six iterations for SIN, eight for EXP and 761 ; twelve for LN and ATN. The mechanics of the routine are interesting but 762 ; for full treatment of how these are generated with demonstrations in 763 ; Sinclair BASIC see "The Complete Spectrum ROM Disassembly" by Dr Ian Logan 764 ; and Dr Frank O'Hara, published 1983 by Melbourne House. 765 766 <a name="seriesg_x"></a><b>seriesg_x</b> LD B,A ; parameter $00 - $1F to B counter 767 CALL <A href="#GEN_ENT_1">GEN_ENT_1</a> ; routine GEN-ENT-1 is called. 768 ; A recursive call to a special entry point 769 ; in the calculator that puts the B register 770 ; in the system variable BREG. The return 771 ; address is the next location and where 772 ; the calculator will expect its first 773 ; instruction - now pointed to by HL'. 774 ; The previous pointer to the series of 775 ; five-byte numbers goes on the machine stack. 776 777 ; The initialization phase. 778 779 DEFB $2D ;;duplicate x,x 780 DEFB $0F ;;addition x+x 781 DEFB $C0 ;;st-mem-0 x+x 782 DEFB $02 ;;delete . 783 DEFB $A0 ;;stk-zero 0 784 DEFB $C2 ;;st-mem-2 0 785 786 ; a loop is now entered to perform the algebraic calculation for each of 787 ; the numbers in the series 788 789 <a name="G_LOOP"></a><b>G_LOOP</b> DEFB $2D ;;duplicate v,v. 790 DEFB $E0 ;;get-mem-0 v,v,x+2 791 DEFB $04 ;;multiply v,v*x+2 792 DEFB $E2 ;;get-mem-2 v,v*x+2,v 793 DEFB $C1 ;;st-mem-1 794 DEFB $03 ;;subtract 795 DEFB $34 ;;end-calc 796 797 ; the previous pointer is fetched from the machine stack to H'L' where it 798 ; addresses one of the numbers of the series following the series literal. 799 800 CALL stk_data ; routine STK-DATA is called directly to 801 ; push a value and advance H'L'. 802 CALL <A href="#GEN_ENT_2">GEN_ENT_2</a> ; routine GEN-ENT-2 recursively re-enters 803 ; the calculator without disturbing 804 ; system variable BREG 805 ; H'L' value goes on the machine stack and is 806 ; then loaded as usual with the next address. 807 808 DEFB $0F ;;addition 809 DEFB $01 ;;exchange 810 DEFB $C2 ;;st-mem-2 811 DEFB $02 ;;delete 812 813 DEFB $31 ;;dec-jr-nz 814 DEFB G_LOOP - $ ;;back to L1A89, G-LOOP 815 816 ; when the counted loop is complete the final subtraction yields the result 817 ; for example SIN X. 818 819 DEFB $E1 ;;get-mem-1 820 DEFB $03 ;;subtract 821 DEFB $34 ;;end-calc 822 823 RET ; return with H'L' pointing to location 824 ; after last number in series. 825 826 ; ----------------------- 827 ; Handle unary minus (18) 828 ; ----------------------- 829 ; Unary so on entry HL points to last value, DE to STKEND. 830 831 <a name="negate"></a><b>negate</b> LD A,(HL) ; fetch exponent of last value on the 832 ; calculator stack. 833 AND A ; test it. 834 RET Z ; return if zero. 835 836 INC HL ; address the byte with the sign bit. 837 LD A,(HL) ; fetch to accumulator. 838 XOR $80 ; toggle the sign bit. 839 LD (HL),A ; put it back. 840 DEC HL ; point to last value again. 841 RET ; return. 842 843 ; ----------------------- 844 ; Absolute magnitude (27) 845 ; ----------------------- 846 ; This calculator literal finds the absolute value of the last value, 847 ; floating point, on calculator stack. 848 849 <a name="abs"></a><b>abs</b> INC HL ; point to byte with sign bit. 850 RES 7,(HL) ; make the sign positive. 851 DEC HL ; point to last value again. 852 RET ; return. 853 854 ; ----------- 855 ; Signum (26) 856 ; ----------- 857 ; This routine replaces the last value on the calculator stack, 858 ; (which is in floating point form), with one if positive and with minus one 859 ; if it is negative. If it is zero then it is left unchanged. 860 861 <a name="sgn"></a><b>sgn</b> INC HL ; point to first byte of 4-byte mantissa. 862 LD A,(HL) ; pick up the byte with the sign bit. 863 DEC HL ; point to exponent. 864 DEC (HL) ; test the exponent for 865 INC (HL) ; the value zero. 866 867 SCF ; Set the carry flag. 868 CALL NZ,<A href="#FP_0_1">FP_0_1</a> ; Routine FP-0/1 replaces last value with one 869 ; if exponent indicates the value is non-zero. 870 ; In either case mantissa is now four zeros. 871 872 INC HL ; Point to first byte of 4-byte mantissa. 873 RLCA ; Rotate original sign bit to carry. 874 RR (HL) ; Rotate the carry into sign. 875 DEC HL ; Point to last value. 876 RET ; Return. 877 878 879 ; ------------------------- 880 ; Handle PEEK function (28) 881 ; ------------------------- 882 ; This function returns the contents of a memory address. 883 ; The entire address space can be peeked including the ROM. 884 885 <a name="peek"></a><b>peek</b> CALL <A href="#FIND_INT">FIND_INT</a> ; routine FIND-INT puts address in BC. 886 LD A,(BC) ; load contents into A register. 887 888 <a name="IN_PK_STK"></a><b>IN_PK_STK</b> JP <A href="#STACK_A">STACK_A</a> ; exit via STACK-A to put value on the 889 ; calculator stack. 890 891 ; --------------- 892 ; USR number (29) 893 ; --------------- 894 ; The USR function followed by a number 0-65535 is the method by which 895 ; the ZX81 invokes machine code programs. This function returns the 896 ; contents of the BC register pair. 897 ; <font color=#9900FF>Note.</font> that STACK-BC re-initializes the IY register to $4000 if a user-written 898 ; program has altered it. 899 900 <a name="usr_no"></a><b>usr_no</b> CALL <A href="#FIND_INT">FIND_INT</a> ; routine FIND-INT to fetch the 901 ; supplied address into BC. 902 903 LD HL,STACK_BC ; address: STACK-BC is 904 PUSH HL ; pushed onto the machine stack. 905 PUSH BC ; then the address of the machine code 906 ; routine. 907 908 RET ; make an indirect jump to the user's routine 909 ; and, hopefully, to STACK-BC also. 910 911 912 ; ----------------------- 913 ; Greater than zero ($33) 914 ; ----------------------- 915 ; Test if the last value on the calculator stack is greater than zero. 916 ; This routine is also called directly from the end-tests of the comparison 917 ; routine. 918 919 <a name="greater_0"></a><b>greater_0</b> LD A,(HL) ; fetch exponent. 920 AND A ; test it for zero. 921 RET Z ; return if so. 922 923 924 LD A,$FF ; prepare XOR mask for sign bit 925 JR <A href="#SIGN_TO_C">SIGN_TO_C</a> ; forward to SIGN-TO-C 926 ; to put sign in carry 927 ; (carry will become set if sign is positive) 928 ; and then overwrite location with 1 or 0 929 ; as appropriate. 930 931 ; ------------------------ 932 ; Handle NOT operator ($2C) 933 ; ------------------------ 934 ; This overwrites the last value with 1 if it was zero else with zero 935 ; if it was any other value. 936 ; 937 ; e.g. NOT 0 returns 1, NOT 1 returns 0, NOT -3 returns 0. 938 ; 939 ; The subroutine is also called directly from the end-tests of the comparison 940 ; operator. 941 942 <a name="not"></a><b>not</b> LD A,(HL) ; get exponent byte. 943 NEG ; negate - sets carry if non-zero. 944 CCF ; complement so carry set if zero, else reset. 945 JR <A href="#FP_0_1">FP_0_1</a> ; forward to FP-0/1. 946 947 ; ------------------- 948 ; Less than zero (32) 949 ; ------------------- 950 ; Destructively test if last value on calculator stack is less than zero. 951 ; Bit 7 of second byte will be set if so. 952 953 <a name="less_0"></a><b>less_0</b> XOR A ; set xor mask to zero 954 ; (carry will become set if sign is negative). 955 956 ; transfer sign of mantissa to Carry Flag. 957 958 <a name="SIGN_TO_C"></a><b>SIGN_TO_C</b> INC HL ; address 2nd byte. 959 XOR (HL) ; bit 7 of HL will be set if number is negative. 960 DEC HL ; address 1st byte again. 961 RLCA ; rotate bit 7 of A to carry. 962 963 ; ----------- 964 ; Zero or one 965 ; ----------- 966 ; This routine places an integer value zero or one at the addressed location 967 ; of calculator stack or MEM area. The value one is written if carry is set on 968 ; entry else zero. 969 970 <a name="FP_0_1"></a><b>FP_0_1</b> PUSH HL ; save pointer to the first byte 971 LD B,$05 ; five bytes to do. 972 973 <a name="FP_loop"></a><b>FP_loop</b> LD (HL),$00 ; insert a zero. 974 INC HL ; 975 DJNZ <A href="#FP_loop">FP_loop</a> ; repeat. 976 977 POP HL ; 978 RET NC ; 979 980 LD (HL),$81 ; make value 1 981 RET ; return. 982 983 984 ; ----------------------- 985 ; Handle OR operator (07) 986 ; ----------------------- 987 ; The Boolean OR operator. eg. X OR Y 988 ; The result is zero if both values are zero else a non-zero value. 989 ; 990 ; e.g. 0 OR 0 returns 0. 991 ; -3 OR 0 returns -3. 992 ; 0 OR -3 returns 1. 993 ; -3 OR 2 returns 1. 994 ; 995 ; A binary operation. 996 ; On entry HL points to first operand (X) and DE to second operand (Y). 997 998 <a name="or"></a><b>or</b> LD A,(DE) ; fetch exponent of second number 999 AND A ; test it. 1000 RET Z ; return if zero. 1001 1002 SCF ; set carry flag 1003 JR <A href="#FP_0_1">FP_0_1</a> ; back to FP-0/1 to overwrite the first operand 1004 ; with the value 1. 1005 1006 1007 ; ----------------------------- 1008 ; Handle number AND number (08) 1009 ; ----------------------------- 1010 ; The Boolean AND operator. 1011 ; 1012 ; e.g. -3 AND 2 returns -3. 1013 ; -3 AND 0 returns 0. 1014 ; 0 and -2 returns 0. 1015 ; 0 and 0 returns 0. 1016 ; 1017 ; Compare with OR routine above. 1018 1019 <a name="no_v_no"></a><b>no_v_no</b> LD A,(DE) ; fetch exponent of second number. 1020 AND A ; test it. 1021 RET NZ ; return if not zero. 1022 1023 JR <A href="#FP_0_1">FP_0_1</a> ; back to FP-0/1 to overwrite the first operand 1024 ; with zero for return value. 1025 1026 ; ----------------------------- 1027 ; Handle string AND number (10) 1028 ; ----------------------------- 1029 ; e.g. "YOU WIN" AND SCORE>99 will return the string if condition is true 1030 ; or the null string if false. 1031 1032 <a name="str_v_no"></a><b>str_v_no</b> LD A,(DE) ; fetch exponent of second number. 1033 AND A ; test it. 1034 RET NZ ; return if number was not zero - the string 1035 ; is the result. 1036 1037 ; if the number was zero (false) then the null string must be returned by 1038 ; altering the length of the string on the calculator stack to zero. 1039 1040 PUSH DE ; save pointer to the now obsolete number 1041 ; (which will become the new STKEND) 1042 1043 DEC DE ; point to the 5th byte of string descriptor. 1044 XOR A ; clear the accumulator. 1045 LD (DE),A ; place zero in high byte of length. 1046 DEC DE ; address low byte of length. 1047 LD (DE),A ; place zero there - now the null string. 1048 1049 POP DE ; restore pointer - new STKEND. 1050 RET ; return. 1051 1052 ; ------------------------------------- 1053 ; Perform comparison ($09-$0E, $11-$16) 1054 ; ------------------------------------- 1055 ; True binary operations. 1056 ; 1057 ; A single entry point is used to evaluate six numeric and six string 1058 ; comparisons. On entry, the calculator literal is in the B register and 1059 ; the two numeric values, or the two string parameters, are on the 1060 ; calculator stack. 1061 ; The individual bits of the literal are manipulated to group similar 1062 ; operations although the SUB 8 instruction does nothing useful and merely 1063 ; alters the string test bit. 1064 ; Numbers are compared by subtracting one from the other, strings are 1065 ; compared by comparing every character until a mismatch, or the end of one 1066 ; or both, is reached. 1067 ; 1068 ; Numeric Comparisons. 1069 ; -------------------- 1070 ; The <b><font color=#333388>'x>y'</font></b> example is the easiest as it employs straight-thru logic. 1071 ; Number y is subtracted from x and the result tested for greater-0 yielding 1072 ; a final value 1 (true) or 0 (false). 1073 ; For 'x<y' the same logic is used but the two values are first swapped on the 1074 ; calculator stack. 1075 ; For 'x=y' NOT is applied to the subtraction result yielding true if the 1076 ; difference was zero and false with anything else. 1077 ; The first three numeric comparisons are just the opposite of the last three 1078 ; so the same processing steps are used and then a final NOT is applied. 1079 ; 1080 ; literal Test No sub 8 ExOrNot 1st RRCA exch sub ? End-Tests 1081 ; ========= ==== == ======== === ======== ======== ==== === = === === === 1082 ; no-l-eql x<=y 09 00000001 dec 00000000 00000000 ---- x-y ? --- >0? NOT 1083 ; no-gr-eql x>=y 0A 00000010 dec 00000001 10000000c swap y-x ? --- >0? NOT 1084 ; nos-neql x<>y 0B 00000011 dec 00000010 00000001 ---- x-y ? NOT --- NOT 1085 ; no-grtr x>y 0C 00000100 - 00000100 00000010 ---- x-y ? --- >0? --- 1086 ; no-less x<y 0D 00000101 - 00000101 10000010c swap y-x ? --- >0? --- 1087 ; nos-eql x=y 0E 00000110 - 00000110 00000011 ---- x-y ? NOT --- --- 1088 ; 1089 ; comp -> C/F 1090 ; ==== === 1091 ; str-l-eql x$<=y$ 11 00001001 dec 00001000 00000100 ---- x$y$ 0 !or >0? NOT 1092 ; str-gr-eql x$>=y$ 12 00001010 dec 00001001 10000100c swap y$x$ 0 !or >0? NOT 1093 ; strs-neql x$<>y$ 13 00001011 dec 00001010 00000101 ---- x$y$ 0 !or >0? NOT 1094 ; str-grtr x$>y$ 14 00001100 - 00001100 00000110 ---- x$y$ 0 !or >0? --- 1095 ; str-less x$<y$ 15 00001101 - 00001101 10000110c swap y$x$ 0 !or >0? --- 1096 ; strs-eql x$=y$ 16 00001110 - 00001110 00000111 ---- x$y$ 0 !or >0? --- 1097 ; 1098 ; String comparisons are a little different in that the eql/neql carry flag 1099 ; from the 2nd RRCA is, as before, fed into the first of the end tests but 1100 ; along the way it gets modified by the comparison process. The result on the 1101 ; stack always starts off as zero and the carry fed in determines if NOT is 1102 ; applied to it. So the only time the greater-0 test is applied is if the 1103 ; stack holds zero which is not very efficient as the test will always yield 1104 ; zero. The most likely explanation is that there were once separate end tests 1105 ; for numbers and strings. 1106 1107 <a name="no_l_eql"></a><b>no_l_eql</b> LD A,B ; transfer literal to accumulator. 1108 1109 <font color=#FF3333>;;; SUB $08 ; subtract eight - which is not useful.</font> 1110 1111 BIT 2,A ; isolate '>', '<', '='. 1112 1113 JR NZ,<A href="#EX_OR_NOT">EX_OR_NOT</a> ; skip to EX-OR-NOT with these. 1114 1115 DEC A ; else make $00-$02, $08-$0A to match bits 0-2. 1116 1117 <a name="EX_OR_NOT"></a><b>EX_OR_NOT</b> RRCA ; the first RRCA sets carry for a swap. 1118 JR NC,<A href="#NU_OR_STR">NU_OR_STR</a> ; forward to NU-OR-STR with other 8 cases 1119 1120 ; for the other 4 cases the two values on the calculator stack are exchanged. 1121 1122 PUSH AF ; save A and carry. 1123 PUSH HL ; save HL - pointer to first operand. 1124 ; (DE points to second operand). 1125 1126 CALL exchange ; routine exchange swaps the two values. 1127 ; (HL = second operand, DE = STKEND) 1128 1129 POP DE ; DE = first operand 1130 EX DE,HL ; as we were. 1131 POP AF ; restore A and carry. 1132 1133 ; <font color=#9900FF>Note.</font> it would be better if the 2nd RRCA preceded the string test. 1134 ; It would save two duplicate bytes and if we also got rid of that sub 8 1135 ; at the beginning we wouldn't have to alter which bit we test. 1136 1137 <a name="NU_OR_STR"></a><b>NU_OR_STR</b> <font color=#3333FF>RRCA ;+ causes 'eql/neql' to set carry.</font> 1138 <font color=#3333FF> PUSH AF ;+ save the carry flag.</font> 1139 BIT 2,A ; test if a string comparison. 1140 JR NZ,<A href="#STRINGS">STRINGS</a> ; forward to STRINGS if so. 1141 1142 ; continue with numeric comparisons. 1143 1144 <font color=#FF3333>;;; RRCA ; 2nd RRCA causes eql/neql to set carry.</font> 1145 <font color=#FF3333>;;; PUSH AF ; save A and carry</font> 1146 1147 CALL subtract ; routine subtract leaves result on stack. 1148 JR <A href="#END_TESTS">END_TESTS</a> ; forward to END-TESTS 1149 1150 ; --- 1151 1152 <a name="STRINGS"></a><b>STRINGS</b> 1153 <font color=#FF3333>;;; RRCA ; 2nd RRCA causes eql/neql to set carry.</font> 1154 <font color=#FF3333>;;; PUSH AF ; save A and carry.</font> 1155 1156 CALL <A href="#STK_FETCH">STK_FETCH</a> ; routine STK-FETCH gets 2nd string params 1157 PUSH DE ; save start2 *. 1158 PUSH BC ; and the length. 1159 1160 CALL <A href="#STK_FETCH">STK_FETCH</a> ; routine STK-FETCH gets 1st string 1161 ; parameters - start in DE, length in BC. 1162 POP HL ; restore length of second to HL. 1163 1164 ; A loop is now entered to compare, by subtraction, each corresponding character 1165 ; of the strings. For each successful match, the pointers are incremented and 1166 ; the lengths decreased and the branch taken back to here. If both string 1167 ; remainders become null at the same time, then an exact match exists. 1168 1169 <a name="BYTE_COMP"></a><b>BYTE_COMP</b> LD A,H ; test if the second string 1170 OR L ; is the null string and hold flags. 1171 1172 EX (SP),HL ; put length2 on stack, bring start2 to HL *. 1173 LD A,B ; hi byte of length1 to A 1174 1175 JR NZ,<A href="#SEC_PLUS">SEC_PLUS</a> ; forward to SEC-PLUS if second not null. 1176 1177 OR C ; test length of first string. 1178 1179 <a name="SECND_LOW"></a><b>SECND_LOW</b> POP BC ; pop the second length off stack. 1180 JR Z,<A href="#BOTH_NULL">BOTH_NULL</a> ; forward to BOTH-NULL if first string is also 1181 ; of zero length. 1182 1183 ; the true condition - first is longer than second (SECND-LESS) 1184 1185 POP AF ; restore carry (set if eql/neql) 1186 CCF ; complement carry flag. 1187 ; <font color=#9900FF>Note.</font> equality becomes false. 1188 ; Inequality is true. By swapping or applying 1189 ; a terminal 'not', all comparisons have been 1190 ; manipulated so that this is success path. 1191 JR <A href="#STR_TEST">STR_TEST</a> ; forward to leave via STR-TEST 1192 1193 ; --- 1194 ; the branch was here with a match 1195 1196 <a name="BOTH_NULL"></a><b>BOTH_NULL</b> POP AF ; restore carry - set for eql/neql 1197 JR <A href="#STR_TEST">STR_TEST</a> ; forward to STR-TEST 1198 1199 ; --- 1200 ; the branch was here when 2nd string not null and low byte of first is yet 1201 ; to be tested. 1202 1203 1204 <a name="SEC_PLUS"></a><b>SEC_PLUS</b> OR C ; test the length of first string. 1205 JR Z,<A href="#FRST_LESS">FRST_LESS</a> ; forward to FRST-LESS if length is zero. 1206 1207 ; both strings have at least one character left. 1208 1209 LD A,(DE) ; fetch character of first string. 1210 SUB (HL) ; subtract with that of 2nd string. 1211 JR C,<A href="#FRST_LESS">FRST_LESS</a> ; forward to FRST-LESS if carry set 1212 1213 JR NZ,<A href="#SECND_LOW">SECND_LOW</a> ; back to SECND-LOW and then STR-TEST 1214 ; if not exact match. 1215 1216 DEC BC ; decrease length of 1st string. 1217 INC DE ; increment 1st string pointer. 1218 1219 INC HL ; increment 2nd string pointer. 1220 EX (SP),HL ; swap with length on stack 1221 DEC HL ; decrement 2nd string length 1222 JR <A href="#BYTE_COMP">BYTE_COMP</a> ; back to BYTE-COMP 1223 1224 ; --- 1225 ; the false condition. 1226 1227 <a name="FRST_LESS"></a><b>FRST_LESS</b> POP BC ; discard length 1228 POP AF ; pop A 1229 AND A ; clear the carry for false result. 1230 1231 ; --- 1232 ; exact match and x$>y$ rejoin here 1233 1234 <a name="STR_TEST"></a><b>STR_TEST</b> PUSH AF ; save A and carry 1235 1236 RST 28H ;; FP-CALC 1237 DEFB $A0 ;;stk-zero an initial false value. 1238 DEFB $34 ;;end-calc 1239 1240 ; both numeric and string paths converge here. 1241 1242 <a name="END_TESTS"></a><b>END_TESTS</b> POP AF ; pop carry - will be set if eql/neql 1243 PUSH AF ; save it again. 1244 1245 CALL C,not ; routine NOT sets true(1) if equal(0) 1246 ; or, for strings, applies true result. 1247 CALL greater_0 ; greater-0 1248 1249 1250 POP AF ; pop A 1251 RRCA ; the third RRCA - test for '<=', '>=' or '<>'. 1252 CALL NC,not ; apply a terminal NOT if so. 1253 RET ; return. 1254 1255 ; ----------------------------------- 1256 ; THE <b><font color=#333388>'STRING CONCATENATION'</font></b> OPERATOR 1257 ; ----------------------------------- 1258 ; <font color=#339933>(offset $17: 'strs_add')</font> 1259 ; This literal combines two strings into one e.g. LET A$ = B$ + C$ 1260 ; The two parameters of the two strings to be combined are on the stack. 1261 1262 <a name="strs_add"></a><b>strs_add</b> 1263 CALL <A href="#STK_FETCH">STK_FETCH</a> ; routine STK-FETCH fetches string parameters 1264 ; and deletes calculator stack entry. 1265 PUSH DE ; save start address. 1266 PUSH BC ; and length. 1267 1268 CALL <A href="#STK_FETCH">STK_FETCH</a> ; routine STK-FETCH for first string 1269 POP HL ; re-fetch first length 1270 PUSH HL ; and save again 1271 PUSH DE ; save start of second string 1272 PUSH BC ; and its length. 1273 1274 ADD HL,BC ; add the two lengths. 1275 LD B,H ; transfer to BC 1276 LD C,L ; and create 1277 RST 30H ; BC-SPACES in workspace. 1278 ; DE points to start of space. 1279 1280 CALL <A href="#STK_STO_s">STK_STO_s</a> ; routine STK-STO-$ stores parameters 1281 ; of new string updating STKEND. 1282 1283 POP BC ; length of first 1284 POP HL ; address of start 1285 1286 <font color=#FF3333>;;; LD A,B ; test for</font> 1287 <font color=#FF3333>;;; OR C ; zero length.</font> 1288 <font color=#FF3333>;;; JR Z,OTHER_STR ; to OTHER-STR if null string</font> 1289 <font color=#FF3333>;;; LDIR ; copy string to workspace.</font> 1290 1291 <font color=#3333FF> CALL <A href="#COND_MV">COND_MV</a> ;+ a conditional (NZ) ldir routine. </font> 1292 1293 <a name="OTHER_STR"></a><b>OTHER_STR</b> POP BC ; now second length 1294 POP HL ; and start of string 1295 1296 <font color=#FF3333>;;; LD A,B ; test this one</font> 1297 <font color=#FF3333>;;; OR C ; for zero length</font> 1298 <font color=#FF3333>;;; JR Z,<A href="#STK_PNTRS">STK_PNTRS</a> ; skip forward to STK-PNTRS if so as complete.</font> 1299 <font color=#FF3333>;;; LDIR ; else copy the bytes.</font> 1300 1301 <font color=#3333FF> CALL <A href="#COND_MV">COND_MV</a> ;+ a conditional (NZ) ldir routine. </font> 1302 1303 ; Continue into next routine which sets the calculator stack pointers. 1304 1305 ; ---------------------------- 1306 ; THE <b><font color=#333388>'STACK POINTERS'</font></b> ROUTINE 1307 ; ---------------------------- 1308 ; Register DE is set to STKEND and HL, the result pointer, is set to five 1309 ; locations below this - the 'last value'. 1310 ; This routine is used when it is inconvenient to save these values at the 1311 ; time the calculator stack is manipulated due to other activity on the 1312 ; machine stack. 1313 ; This routine is also used to terminate the VAL routine for 1314 ; the same reason and to initialize the calculator stack at the start of 1315 ; the CALCULATE routine. 1316 1317 <a name="STK_PNTRS"></a><b>STK_PNTRS</b> LD HL,($401C) ; fetch STKEND value from system variable. 1318 LD DE,$FFFB ; the value -5 1319 PUSH HL ; push STKEND value. 1320 1321 ADD HL,DE ; subtract 5 from HL. 1322 1323 POP DE ; pop STKEND to DE. 1324 RET ; return. 1325 1326 ; ------------------- 1327 ; THE <b><font color=#333388>'CHR$'</font></b> FUNCTION 1328 ; ------------------- 1329 ; <font color=#339933>(offset $2B: 'chr$')</font> 1330 ; This function returns a single character string that is a result of 1331 ; converting a number in the range 0-255 to a string e.g. CHR$ 38 = "A". 1332 ; <font color=#9900FF>Note.</font> the ZX81 does not have an ASCII character set. 1333 1334 <a name="chrS"></a><b>chrS</b> CALL <A href="#FP_TO_A">FP_TO_A</a> ; routine FP-TO-A puts the number in A. 1335 1336 JR C,<A href="#REPORT_Bd">REPORT_Bd</a> ; forward to REPORT-Bd if overflow 1337 JR NZ,<A href="#REPORT_Bd">REPORT_Bd</a> ; forward to REPORT-Bd if negative 1338 1339 <font color=#FF3333>;;; PUSH AF ; save the argument.</font> 1340 1341 LD BC,$0001 ; one space required. 1342 RST 30H ; BC-SPACES makes DE point to start 1343 1344 <font color=#FF3333>;;; POP AF ; restore the number.</font> 1345 1346 LD (DE),A ; and store in workspace 1347 1348 <font color=#3333FF> JR str_STK ;+ relative jump to similar sequence in str$.</font> 1349 1350 <font color=#FF3333>;;; CALL <A href="#STK_STO_s">STK_STO_s</a> ; routine STK-STO-$ stacks descriptor.</font> 1351 <font color=#FF3333>;;; EX DE,HL ; make HL point to result and DE to STKEND.</font> 1352 <font color=#FF3333>;;; RET ; return.</font> 1353 1354 ; --- 1355 1356 <a name="REPORT_Bd"></a><b>REPORT_Bd</b> RST 08H ; ERROR-1 1357 DEFB $0A ; Error Report: Integer out of range 1358 1359 ; ------------------ 1360 ; THE <b><font color=#333388>'VAL'</font></b> FUNCTION 1361 ; ------------------ 1362 ; <font color=#339933>(offset $1A: 'val')</font> 1363 ; VAL treats the characters in a string as a numeric expression. 1364 ; e.g. VAL "2.3" = 2.3, VAL "2+4" = 6, VAL ("2" + "4") = 24. 1365 1366 <a name="val"></a><b>val</b> <font color=#3333FF> RST 18H ;+ shorter way to fetch CH_ADD.</font> 1367 1368 <font color=#FF3333>;;; LD HL,($4016) ; fetch value of system variable CH_ADD</font> 1369 PUSH HL ; and save on the machine stack. 1370 1371 CALL <A href="#STK_FETCH">STK_FETCH</a> ; routine STK-FETCH fetches the string operand 1372 ; from calculator stack. 1373 1374 PUSH DE ; save the address of the start of the string. 1375 INC BC ; increment the length for a carriage return. 1376 1377 RST 30H ; BC-SPACES creates the space in workspace. 1378 POP HL ; restore start of string to HL. 1379 LD ($4016),DE ; load CH_ADD with start DE in workspace. 1380 1381 PUSH DE ; save the start in workspace 1382 LDIR ; copy string from program or variables or 1383 ; workspace to the workspace area. 1384 EX DE,HL ; end of string + 1 to HL 1385 DEC HL ; decrement HL to point to end of new area. 1386 LD (HL),$76 ; insert a carriage return at end. 1387 ; ZX81 has a non-ASCII character set 1388 RES 7,(IY+$01) ; update FLAGS - signal checking syntax. 1389 CALL <A href="#CLASS_06">CLASS_06</a> ; routine CLASS-06 - SCANNING evaluates string 1390 ; expression and checks for integer result. 1391 1392 CALL <A href="#CHECK_2">CHECK_2</a> ; routine CHECK-2 checks for carriage return. 1393 1394 1395 POP HL ; restore start of string in workspace. 1396 1397 LD ($4016),HL ; set CH_ADD to the start of the string again. 1398 SET 7,(IY+$01) ; update FLAGS - signal running program. 1399 CALL <A href="#SCANNING">SCANNING</a> ; routine SCANNING evaluates the string 1400 ; in full leaving result on calculator stack. 1401 1402 POP HL ; restore saved character address in program. 1403 LD ($4016),HL ; and reset the system variable CH_ADD. 1404 1405 JR <A href="#STK_PNTRS">STK_PNTRS</a> ; back to exit via STK-PNTRS. 1406 ; resetting the calculator stack pointers 1407 ; HL and DE from STKEND as it wasn't possible 1408 ; to preserve them during this routine. 1409 1410 ; ------------------- 1411 ; THE <b><font color=#333388>'STR$'</font></b> FUNCTION 1412 ; ------------------- 1413 ; <font color=#339933>(offset $2A: 'str$')</font> 1414 ; This function returns a string representation of a numeric argument. 1415 ; The method used is to trick the PRINT-FP routine into thinking it 1416 ; is writing to a collapsed display file when in fact it is writing to 1417 ; string workspace. 1418 ; If there is already a newline at the intended print position and the 1419 ; column count has not been reduced to zero then the print routine 1420 ; assumes that there is only 1K of RAM and the screen memory, like the rest 1421 ; of dynamic memory, expands as necessary using calls to the ONE-SPACE 1422 ; routine. The screen is character-mapped not bit-mapped. 1423 1424 <a name="strS"></a><b>strS</b> LD BC,$0001 ; create an initial byte in workspace 1425 RST 30H ; using BC-SPACES restart. 1426 1427 LD (HL),$76 ; place a carriage return there. 1428 1429 LD HL,($4039) ; fetch value of S_POSN column/line 1430 PUSH HL ; and preserve on stack. 1431 1432 LD L,$FF ; make column value high to create a 1433 ; contrived buffer of length 254. 1434 LD ($4039),HL ; and store in system variable S_POSN. 1435 1436 LD HL,($400E) ; fetch value of DF_CC 1437 PUSH HL ; and preserve on stack also. 1438 1439 LD ($400E),DE ; now set DF_CC which normally addresses 1440 ; somewhere in the display file to the start 1441 ; of workspace. 1442 PUSH DE ; save the start of new string. 1443 1444 CALL <A href="#PRINT_FP">PRINT_FP</a> ; routine PRINT-FP. 1445 1446 POP DE ; retrieve start of string. 1447 1448 LD HL,($400E) ; fetch end of string from DF_CC. 1449 AND A ; prepare for true subtraction. 1450 SBC HL,DE ; subtract to give length. 1451 1452 LD B,H ; and transfer to the BC 1453 LD C,L ; register. 1454 1455 POP HL ; restore original 1456 LD ($400E),HL ; DF_CC value 1457 1458 POP HL ; restore original 1459 LD ($4039),HL ; S_POSN values. 1460 1461 ; New entry-point to exploit similarities and save 3 bytes of code. 1462 1463 <a name="str_STK"></a><b>str_STK</b> CALL STK_STO_s ; routine STK-STO-$ stores the string 1464 ; descriptor on the calculator stack. 1465 1466 EX DE,HL ; HL = last value, DE = STKEND. 1467 RET ; return. 1468 1469 1470 ; ------------------- 1471 ; THE <b><font color=#333388>'CODE'</font></b> FUNCTION 1472 ; ------------------- 1473 ; <font color=#339933>(offset $19: 'code')</font> 1474 ; Returns the code of a character or first character of a string 1475 ; e.g. CODE "AARDVARK" = 38 (not 65 as the ZX81 does not have an ASCII 1476 ; character set). 1477 1478 1479 <a name="code"></a><b>code</b> CALL <A href="#STK_FETCH">STK_FETCH</a> ; routine STK-FETCH to fetch and delete the 1480 ; string parameters. 1481 ; DE points to the start, BC holds the length. 1482 LD A,B ; test length 1483 OR C ; of the string. 1484 JR Z,<A href="#STK_CODE">STK_CODE</a> ; skip to STK-CODE with zero if the null string. 1485 1486 LD A,(DE) ; else fetch the first character. 1487 1488 <a name="STK_CODE"></a><b>STK_CODE</b> JP <A href="#STACK_A">STACK_A</a> ; jump back to STACK-A (with memory check) 1489 1490 ; -------------------- 1491 ; THE <b><font color=#333388>'LEN'</font></b> SUBROUTINE 1492 ; -------------------- 1493 ; <font color=#339933>(offset $1b: 'len')</font> 1494 ; Returns the length of a string. 1495 ; In Sinclair BASIC strings can be more than twenty thousand characters long 1496 ; so a sixteen-bit register is required to store the length 1497 1498 <a name="len"></a><b>len</b> CALL <A href="#STK_FETCH">STK_FETCH</a> ; routine STK-FETCH to fetch and delete the 1499 ; string parameters from the calculator stack. 1500 ; register BC now holds the length of string. 1501 1502 JP <A href="#STACK_BC">STACK_BC</a> ; jump back to STACK-BC to save result on the 1503 ; calculator stack (with memory check). 1504 1505 ; ------------------------------------- 1506 ; THE <b><font color=#333388>'DECREASE THE COUNTER'</font></b> SUBROUTINE 1507 ; ------------------------------------- 1508 ; <font color=#339933>(offset $31: 'dec-jr-nz')</font> 1509 ; The calculator has an instruction that decrements a single-byte 1510 ; pseudo-register and makes consequential relative jumps just like 1511 ; the Z80's DJNZ instruction. 1512 1513 <a name="dec_jr_nz"></a><b>dec_jr_nz</b> EXX ; switch in set that addresses code 1514 1515 PUSH HL ; save pointer to offset byte 1516 LD HL,$401E ; address BREG in system variables 1517 DEC (HL) ; decrement it 1518 POP HL ; restore pointer 1519 1520 JR NZ,<A href="#JUMP_2">JUMP_2</a> ; to JUMP-2 if not zero 1521 1522 INC HL ; step past the jump length. 1523 EXX ; switch in the main set. 1524 RET ; return. 1525 1526 ; <font color=#9900FF>Note.</font> as a general rule the calculator avoids using the IY register 1527 ; otherwise the cumbersome 4 instructions in the middle could be replaced by 1528 ; dec (iy+$xx) - using three instruction bytes instead of six. 1529 1530 1531 ; --------------------- 1532 ; THE <b><font color=#333388>'JUMP'</font></b> SUBROUTINE 1533 ; --------------------- 1534 ; <font color=#339933>(Offset $2F; 'jump')</font> 1535 ; This enables the calculator to perform relative jumps just like 1536 ; the Z80 chip's JR instruction. 1537 ; This is one of the few routines that was polished for the ZX Spectrum. 1538 1539 <a name="JUMP"></a><b>JUMP</b> EXX ;switch in pointer set 1540 1541 <a name="JUMP_2"></a><b>JUMP_2</b> LD E,(HL) ; the jump byte 0-127 forward, 128-255 back. 1542 1543 ; <font color=#9900FF>Note.</font> Elegance from the ZX Spectrum. 1544 1545 <font color=#3333FF> LD A,E ;+</font> 1546 <font color=#3333FF> RLA ;+</font> 1547 <font color=#3333FF> SBC A,A ;+</font> 1548 1549 ; The original ZX81 code. 1550 1551 <font color=#FF3333>;;; XOR A ; clear accumulator.</font> 1552 <font color=#FF3333>;;; BIT 7,E ; test if negative jump</font> 1553 <font color=#FF3333>;;; JR Z,<A href="#JUMP_3">JUMP_3</a> ; skip, if positive, to JUMP-3.</font> 1554 <font color=#FF3333>;;; CPL ; else change to $FF.</font> 1555 1556 <a name="JUMP_3"></a><b>JUMP_3</b> LD D,A ; transfer to high byte. 1557 ADD HL,DE ; advance calculator pointer forward or back. 1558 1559 EXX ; switch out pointer set. 1560 RET ; return. 1561 1562 ; ----------------------------- 1563 ; THE <b><font color=#333388>'JUMP ON TRUE'</font></b> SUBROUTINE 1564 ; ----------------------------- 1565 ; <font color=#339933>(Offset $00; 'jump-true')</font> 1566 ; This enables the calculator to perform conditional relative jumps 1567 ; dependent on whether the last test gave a true result 1568 ; On the ZX81, the exponent will be zero for zero or else $81 for one. 1569 1570 <a name="jump_true"></a><b>jump_true</b> LD A,(DE) ; collect exponent byte 1571 1572 AND A ; is result 0 or 1 ? 1573 JR NZ,<A href="#JUMP">JUMP</a> ; back to JUMP if true (1). 1574 1575 EXX ; else switch in the pointer set. 1576 INC HL ; step past the jump length. 1577 EXX ; switch in the main set. 1578 RET ; return. 1579 1580 1581 ; ------------------------ 1582 ; THE <b><font color=#333388>'MODULUS'</font></b> SUBROUTINE 1583 ; ------------------------ 1584 ; ( Offset $2E: 'n-mod-m' ) 1585 ; <font color=#CC00FF>( i1, i2 -- i3, i4 )</font> 1586 ; The subroutine calculate N mod M where M is the positive integer, the 1587 ; 'last value' on the calculator stack and N is the integer beneath. 1588 ; The subroutine returns the integer quotient as the last value and the 1589 ; remainder as the value beneath. 1590 ; e.g. 17 MOD 3 = 5 remainder 2 1591 ; It is invoked during the calculation of a random number and also by 1592 ; the PRINT-FP routine. 1593 1594 <a name="n_mod_m"></a><b>n_mod_m</b> RST 28H ;; FP-CALC 17, 3. 1595 DEFB $C0 ;;st-mem-0 17, 3. 1596 DEFB $02 ;;delete 17. 1597 DEFB $2D ;;duplicate 17, 17. 1598 DEFB $E0 ;;get-mem-0 17, 17, 3. 1599 DEFB $05 ;;division 17, 17/3. 1600 DEFB $24 ;;int 17, 5. 1601 DEFB $E0 ;;get-mem-0 17, 5, 3. 1602 DEFB $01 ;;exchange 17, 3, 5. 1603 DEFB $C0 ;;st-mem-0 17, 3, 5. 1604 DEFB $04 ;;multiply 17, 15. 1605 DEFB $03 ;;subtract 2. 1606 DEFB $E0 ;;get-mem-0 2, 5. 1607 DEFB $34 ;;end-calc 2, 5. 1608 1609 RET ; return. 1610 1611 1612 ; ---------------------- 1613 ; THE <b><font color=#333388>'INTEGER'</font></b> FUNCTION 1614 ; ---------------------- 1615 ; <font color=#339933>(offset $24: 'int')</font> 1616 ; This function returns the integer of x, which is just the same as truncate 1617 ; for positive numbers. The truncate literal truncates negative numbers 1618 ; upwards so that -3.4 gives -3 whereas the BASIC INT function has to 1619 ; truncate negative numbers down so that INT -3.4 is 4. 1620 ; It is best to work through using, say, plus and minus 3.4 as examples. 1621 1622 <a name="int"></a><b>int</b> RST 28H ;; FP-CALC x. (= 3.4 or -3.4). 1623 DEFB $2D ;;duplicate x, x. 1624 DEFB $32 ;;less-0 x, (1/0) 1625 DEFB $00 ;;jump-true x, (1/0) 1626 DEFB $04 ;;to L1C46, X-NEG 1627 1628 DEFB $36 ;;truncate trunc 3.4 = 3. 1629 DEFB $34 ;;end-calc 3. 1630 1631 RET ; return with + int x on stack. 1632 1633 1634 <a name="X_NEG"></a><b>X_NEG</b> DEFB $2D ;;duplicate -3.4, -3.4. 1635 DEFB $36 ;;truncate -3.4, -3. 1636 DEFB $C0 ;;st-mem-0 -3.4, -3. 1637 DEFB $03 ;;subtract -.4 1638 DEFB $E0 ;;get-mem-0 -.4, -3. 1639 DEFB $01 ;;exchange -3, -.4. 1640 DEFB $2C ;;not -3, (0). 1641 DEFB $00 ;;jump-true -3. 1642 DEFB $03 ;;to L1C59, EXIT -3. 1643 1644 DEFB $A1 ;;stk-one -3, 1. 1645 DEFB $03 ;;subtract -4. 1646 1647 <a name="EXIT"></a><b>EXIT</b> DEFB $34 ;;end-calc -4. 1648 1649 RET ; return. 1650 1651 1652 ; -------------------------- 1653 ; THE <b><font color=#333388>'EXPONENTIAL'</font></b> FUNCTION 1654 ; -------------------------- 1655 ; <font color=#339933>(Offset $23: 'exp')</font> 1656 ; The exponential function returns the exponential of the argument, or the 1657 ; value of 'e' (2.7182818...) raised to the power of the argument. 1658 ; PRINT EXP 1 gives 2.7182818 1659 ; 1660 ; EXP is the opposite of the LN function (see below) and is equivalent to 1661 ; the 'antiln' function found on pocket calculators or the 'Inverse ln' 1662 ; function found on the Windows scientific calculator. 1663 ; So PRINT EXP LN 5.3 will give 5.3 as will PRINT LN EXP 5.3 or indeed 1664 ; any number e.g. PRINT EXP LN PI. 1665 ; 1666 ; The applications of the exponential function are in areas where exponential 1667 ; growth is experienced, calculus, population growth and compound interest. 1668 ; 1669 ; Error 6 if the argument is above 88. 1670 1671 <a name="exp"></a><b>exp</b> RST 28H ;; FP-CALC 1672 DEFB $30 ;;stk-data 1/LN 2 1673 DEFB $F1 ;;Exponent: $81, Bytes: 4 1674 DEFB $38,$AA,$3B,$29 ;; 1675 DEFB $04 ;;multiply 1676 DEFB $2D ;;duplicate 1677 DEFB $24 ;;int 1678 DEFB $C3 ;;st-mem-3 1679 DEFB $03 ;;subtract 1680 DEFB $2D ;;duplicate 1681 DEFB $0F ;;addition 1682 DEFB $A1 ;;stk-one 1683 DEFB $03 ;;subtract 1684 DEFB $88 ;;series-08 1685 DEFB $13 ;;Exponent: $63, Bytes: 1 1686 DEFB $36 ;;(+00,+00,+00) 1687 DEFB $58 ;;Exponent: $68, Bytes: 2 1688 DEFB $65,$66 ;;(+00,+00) 1689 DEFB $9D ;;Exponent: $6D, Bytes: 3 1690 DEFB $78,$65,$40 ;;(+00) 1691 DEFB $A2 ;;Exponent: $72, Bytes: 3 1692 DEFB $60,$32,$C9 ;;(+00) 1693 DEFB $E7 ;;Exponent: $77, Bytes: 4 1694 DEFB $21,$F7,$AF,$24 ;; 1695 DEFB $EB ;;Exponent: $7B, Bytes: 4 1696 DEFB $2F,$B0,$B0,$14 ;; 1697 DEFB $EE ;;Exponent: $7E, Bytes: 4 1698 DEFB $7E,$BB,$94,$58 ;; 1699 DEFB $F1 ;;Exponent: $81, Bytes: 4 1700 DEFB $3A,$7E,$F8,$CF ;; 1701 DEFB $E3 ;;get-mem-3 1702 DEFB $34 ;;end-calc 1703 1704 CALL <A href="#FP_TO_A">FP_TO_A</a> ; routine FP-TO-A 1705 JR NZ,<A href="#N_NEGTV">N_NEGTV</a> ; to N-NEGTV 1706 1707 JR C,<A href="#REPORT_6b">REPORT_6b</a> ; to REPORT-6b 1708 1709 ADD A,(HL) ; 1710 JR NC,<A href="#RESULT_OK">RESULT_OK</a> ; to RESULT-OK 1711 1712 1713 <a name="REPORT_6b"></a><b>REPORT_6b</b> RST 08H ; ERROR-1 1714 DEFB $05 ; Error Report: Number too big 1715 1716 <a name="N_NEGTV"></a><b>N_NEGTV</b> JR C,<A href="#RSLT_ZERO">RSLT_ZERO</a> ; to RSLT-ZERO 1717 1718 SUB (HL) ; 1719 JR NC,<A href="#RSLT_ZERO">RSLT_ZERO</a> ; to RSLT-ZERO 1720 1721 NEG ; Negate 1722 1723 <a name="RESULT_OK"></a><b>RESULT_OK</b> LD (HL),A ; 1724 RET ; return. 1725 1726 1727 <a name="RSLT_ZERO"></a><b>RSLT_ZERO</b> RST 28H ;; FP-CALC 1728 DEFB $02 ;;delete 1729 DEFB $A0 ;;stk-zero 1730 DEFB $34 ;;end-calc 1731 1732 RET ; return. 1733 1734 1735 ; -------------------------------- 1736 ; THE <b><font color=#333388>'NATURAL LOGARITHM'</font></b> FUNCTION 1737 ; -------------------------------- 1738 ; <font color=#339933>(offset $22: 'ln')</font> 1739 ; Like the ZX81 itself, 'natural' logarithms came from Scotland. 1740 ; They were devised in 1614 by well-traveled Scotsman John Napier who noted 1741 ; "Nothing doth more molest and hinder calculators than the multiplications, 1742 ; divisions, square and cubical extractions of great numbers". 1743 ; Napier's logarithms enabled the above operations to be accomplished by 1744 ; simple addition and subtraction simplifying the navigational and 1745 ; astronomical calculations which beset his age. 1746 ; Napier's logarithms were quickly overtaken by logarithms to the base 10 1747 ; devised, in conjunction with Napier, by Henry Briggs a Cambridge-educated 1748 ; professor of Geometry at Oxford University. These simplified the layout 1749 ; of the tables enabling humans to easily scale calculations. 1750 ; 1751 ; It is only recently with the introduction of pocket calculators and 1752 ; computers like the ZX81 that natural logarithms are once more at the fore, 1753 ; although some computers retain logarithms to the base ten. 1754 ; 'Natural' logarithms are powers to the base 'e', which like 'pi' is a 1755 ; naturally occurring number in branches of mathematics. 1756 ; Like 'pi' also, 'e' is an irrational number and starts 2.718281828... 1757 ; 1758 ; The tabular use of logarithms was that to multiply two numbers one looked 1759 ; up their two logarithms in the tables, added them together and then looked 1760 ; for the result in a table of antilogarithms to give the desired product. 1761 ; 1762 ; The EXP function is the BASIC equivalent of a calculator's 'antiln' function 1763 ; and by picking any two numbers, 1.72 and 6.89 say, 1764 ; 10 PRINT EXP ( LN 1.72 + LN 6.89 ) 1765 ; will give just the same result as 1766 ; 20 PRINT 1.72 * 6.89. 1767 ; Division is accomplished by subtracting the two logs. 1768 ; 1769 ; Napier also mentioned "square and cubicle extractions". 1770 ; To raise a number to the power 3, find its 'ln', multiply by 3 and find the 1771 ; 'antiln'. e.g. PRINT EXP( LN 4 * 3 ) gives 64. 1772 ; Similarly to find the n'th root divide the logarithm by 'n'. 1773 ; The ZX81 ROM used PRINT EXP ( LN 9 / 2 ) to find the square root of the 1774 ; number 9. The Napieran square root function is just a special case of 1775 ; the 'to_power' function. A cube root or indeed any root/power would be just 1776 ; as simple. 1777 1778 ; First test that the argument to LN is a positive, non-zero number. 1779 1780 1781 <a name="ln"></a><b>ln</b> RST 28H ;; FP-CALC x. 1782 DEFB $2D ;;duplicate x,x. 1783 DEFB $33 ;;greater-0 x,(0/1). 1784 DEFB $00 ;;jump-true x. 1785 DEFB $04 ;;to L1CB1, VALID 1786 1787 DEFB $34 ;;end-calc x. 1788 1789 1790 <a name="REPORT_Ab"></a><b>REPORT_Ab</b> RST 08H ; ERROR-1 1791 DEFB $09 ; Error Report: Invalid argument 1792 1793 <a name="VALID"></a><b>VALID</b> 1794 <font color=#FF3333>;;; DEFB $A0 ;;stk-zero </font> 1795 <font color=#FF3333>;;; DEFB $02 ;;delete</font> 1796 DEFB $34 ;;end-calc x. 1797 1798 ; Register HL addresses the 'last value' x. 1799 1800 LD A,(HL) ; Fetch exponent to A. 1801 1802 LD (HL),$80 ; Insert 'plus zero' as exponent. 1803 CALL <A href="#STACK_A">STACK_A</a> ; routine STACK-A stacks true binary exponent. 1804 1805 RST 28H ;; FP-CALC 1806 DEFB $30 ;;stk-data 1807 DEFB $38 ;;Exponent: $88, Bytes: 1 1808 DEFB $00 ;;(+00,+00,+00) 1809 DEFB $03 ;;subtract 1810 DEFB $01 ;;exchange 1811 DEFB $2D ;;duplicate 1812 DEFB $30 ;;stk-data 1813 DEFB $F0 ;;Exponent: $80, Bytes: 4 1814 DEFB $4C,$CC,$CC,$CD ;; 1815 DEFB $03 ;;subtract 1816 DEFB $33 ;;greater-0 1817 DEFB $00 ;;jump-true 1818 DEFB $08 ;;to L1CD2, GRE.8 1819 1820 DEFB $01 ;;exchange 1821 DEFB $A1 ;;stk-one 1822 DEFB $03 ;;subtract 1823 DEFB $01 ;;exchange 1824 DEFB $34 ;;end-calc 1825 1826 INC (HL) ; 1827 1828 RST 28H ;; FP-CALC 1829 1830 <a name="GRE_8"></a><b>GRE_8</b> DEFB $01 ;;exchange 1831 DEFB $30 ;;stk-data LN 2 1832 DEFB $F0 ;;Exponent: $80, Bytes: 4 1833 DEFB $31,$72,$17,$F8 ;; 1834 DEFB $04 ;;multiply 1835 DEFB $01 ;;exchange 1836 DEFB $A2 ;;stk-half 1837 DEFB $03 ;;subtract 1838 DEFB $A2 ;;stk-half 1839 DEFB $03 ;;subtract 1840 DEFB $2D ;;duplicate 1841 DEFB $30 ;;stk-data 1842 DEFB $32 ;;Exponent: $82, Bytes: 1 1843 DEFB $20 ;;(+00,+00,+00) 1844 DEFB $04 ;;multiply 1845 DEFB $A2 ;;stk-half 1846 DEFB $03 ;;subtract 1847 DEFB $8C ;;series-0C 1848 DEFB $11 ;;Exponent: $61, Bytes: 1 1849 DEFB $AC ;;(+00,+00,+00) 1850 DEFB $14 ;;Exponent: $64, Bytes: 1 1851 DEFB $09 ;;(+00,+00,+00) 1852 DEFB $56 ;;Exponent: $66, Bytes: 2 1853 DEFB $DA,$A5 ;;(+00,+00) 1854 DEFB $59 ;;Exponent: $69, Bytes: 2 1855 DEFB $30,$C5 ;;(+00,+00) 1856 DEFB $5C ;;Exponent: $6C, Bytes: 2 1857 DEFB $90,$AA ;;(+00,+00) 1858 DEFB $9E ;;Exponent: $6E, Bytes: 3 1859 DEFB $70,$6F,$61 ;;(+00) 1860 DEFB $A1 ;;Exponent: $71, Bytes: 3 1861 DEFB $CB,$DA,$96 ;;(+00) 1862 DEFB $A4 ;;Exponent: $74, Bytes: 3 1863 DEFB $31,$9F,$B4 ;;(+00) 1864 DEFB $E7 ;;Exponent: $77, Bytes: 4 1865 DEFB $A0,$FE,$5C,$FC ;; 1866 DEFB $EA ;;Exponent: $7A, Bytes: 4 1867 DEFB $1B,$43,$CA,$36 ;; 1868 DEFB $ED ;;Exponent: $7D, Bytes: 4 1869 DEFB $A7,$9C,$7E,$5E ;; 1870 DEFB $F0 ;;Exponent: $80, Bytes: 4 1871 DEFB $6E,$23,$80,$93 ;; 1872 DEFB $04 ;;multiply 1873 DEFB $0F ;;addition 1874 DEFB $34 ;;end-calc 1875 1876 RET ; return. 1877 1878 ; ------------------------------ 1879 ; THE NEW <b><font color=#333388>'SQUARE ROOT'</font></b> FUNCTION 1880 ; ------------------------------ 1881 ; <font color=#339933>(Offset $25: 'sqr')</font> 1882 ; "If I have seen further, it is by standing on the shoulders of giants" - 1883 ; Sir Isaac Newton, Cambridge 1676. 1884 ; The sqr function has been re-written to use the Newton-Raphson method. 1885 ; Joseph Raphson was a student of Sir Isaac Newton at Cambridge University 1886 ; and helped publicize his work. 1887 ; Although Newton's method is centuries old, this routine, appropriately, is 1888 ; based on a FORTH word written by Steven Vickers in the Jupiter Ace manual. 1889 ; Whereas that method uses an initial guess of one, this one manipulates 1890 ; the exponent byte to obtain a better starting guess. 1891 ; First test for zero and return zero, if so, as the result. 1892 ; If the argument is negative, then produce an error. 1893 1894 <a name="sqr"></a><b>sqr</b> RST 28H ;; FP-CALC x 1895 DEFB $C3 ;;st-mem-3 x. (seed for guess) 1896 DEFB $34 ;;end-calc x. 1897 1898 ; HL now points to exponent of argument on calculator stack. 1899 1900 LD A,(HL) ; Test for zero argument 1901 AND A ; 1902 1903 RET Z ; Return with zero on the calculator stack. 1904 1905 ; Test for a positive argument 1906 1907 INC HL ; Address byte with sign bit. 1908 BIT 7,(HL) ; Test the bit. 1909 1910 JR NZ,<A href="#REPORT_Ab">REPORT_Ab</a> ; back to REPORT_A 1911 ; 'Invalid argument' 1912 1913 ; This guess is based on a Usenet discussion. 1914 ; Halve the exponent to achieve a good guess.(accurate with .25 16 64 etc.) 1915 1916 LD HL,$4071 ; Address first byte of mem-3 1917 1918 LD A,(HL) ; fetch exponent of mem-3 1919 XOR $80 ; toggle sign of exponent of mem-3 1920 SRA A ; shift right, bit 7 unchanged. 1921 INC A ; 1922 JR Z,<A href="#ASIS">ASIS</a> ; forward with say .25 -> .5 1923 JP P,<A href="#ASIS">ASIS</a> ; leave increment if value > .5 1924 DEC A ; restore to shift only. 1925 <a name="ASIS"></a><b>ASIS</b> XOR $80 ; restore sign. 1926 LD (HL),A ; and put back 'halved' exponent. 1927 1928 ; Now re-enter the calculator. 1929 1930 RST 28H ;; FP-CALC x 1931 1932 <a name="SLOOP"></a><b>SLOOP</b> DEFB $2D ;;duplicate x,x. 1933 DEFB $E3 ;;get-mem-3 x,x,guess 1934 DEFB $C4 ;;st-mem-4 x,x,guess 1935 DEFB $05 ;;div x,x/guess. 1936 DEFB $E3 ;;get-mem-3 x,x/guess,guess 1937 DEFB $0F ;;addition x,x/guess+guess 1938 DEFB $A2 ;;stk-half x,x/guess+guess,.5 1939 DEFB $04 ;;multiply x,(x/guess+guess)*.5 1940 DEFB $C3 ;;st-mem-3 x,newguess 1941 DEFB $E4 ;;get-mem-4 x,newguess,oldguess 1942 DEFB $03 ;;subtract x,newguess-oldguess 1943 DEFB $27 ;;abs x,difference. 1944 DEFB $33 ;;greater-0 x,(0/1). 1945 DEFB $00 ;;jump-true x. 1946 1947 DEFB SLOOP - $ ;;to sloop x. 1948 1949 DEFB $02 ;;delete . 1950 DEFB $E3 ;;get-mem-3 retrieve final guess. 1951 DEFB $34 ;;end-calc sqr x. 1952 1953 RET ; return with square root on stack 1954 1955 ; or in ZX81 BASIC 1956 ; 1957 ; 5 PRINT "NEWTON RAPHSON SQUARE ROOTS" 1958 ; 10 INPUT "NUMBER ";N 1959 ; 20 INPUT "GUESS ";G 1960 ; 30 PRINT " NUMBER "; N ;" GUESS "; G 1961 ; 40 FOR I = 1 TO 10 1962 ; 50 LET B = N/G 1963 ; 60 LET C = B+G 1964 ; 70 LET G = C/2 1965 ; 80 PRINT I; " VALUE "; G 1966 ; 90 NEXT I 1967 ; 100 PRINT "NAPIER METHOD"; SQR N 1968 1969 ; ----------------------------- 1970 ; THE <b><font color=#333388>'TRIGONOMETRIC'</font></b> FUNCTIONS 1971 ; ----------------------------- 1972 ; Trigonometry is rocket science. It is also used by carpenters and pyramid 1973 ; builders. 1974 ; Some uses can be quite abstract but the principles can be seen in simple 1975 ; right-angled triangles. Triangles have some special properties - 1976 ; 1977 ; 1) The sum of the three angles is always PI radians (180 degrees). 1978 ; Very helpful if you know two angles and wish to find the third. 1979 ; 2) In any right-angled triangle the sum of the squares of the two shorter 1980 ; sides is equal to the square of the longest side opposite the right-angle. 1981 ; Very useful if you know the length of two sides and wish to know the 1982 ; length of the third side. 1983 ; 3) Functions sine, cosine and tangent enable one to calculate the length 1984 ; of an unknown side when the length of one other side and an angle is 1985 ; known. 1986 ; 4) Functions arcsin, arccosine and arctan enable one to calculate an unknown 1987 ; angle when the length of two of the sides is known. 1988 1989 ; -------------------------------- 1990 ; THE <b><font color=#333388>'REDUCE ARGUMENT'</font></b> SUBROUTINE 1991 ; -------------------------------- 1992 ; <font color=#339933>(offset $35: 'get-argt')</font> 1993 ; 1994 ; This routine performs two functions on the angle, in radians, that forms 1995 ; the argument to the sine and cosine functions. 1996 ; First it ensures that the angle 'wraps round'. That if a ship turns through 1997 ; an angle of, say, 3*PI radians (540 degrees) then the net effect is to turn 1998 ; through an angle of PI radians (180 degrees). 1999 ; Secondly it converts the angle in radians to a fraction of a right angle, 2000 ; depending within which quadrant the angle lies, with the periodicity 2001 ; resembling that of the desired sine value. 2002 ; The result lies in the range -1 to +1. 2003 ; 2004 ; 90 deg. 2005 ; 2006 ; (pi/2) 2007 ; II +1 I 2008 ; | 2009 ;<font color=#339933> sin+ |\ | /| sin+</font> 2010 ;<font color=#339933> cos- | \ | / | cos+</font> 2011 ;<font color=#339933> tan- | \ | / | tan+</font> 2012 ;<font color=#339933> | \|/) | </font> 2013 ;<font color=#339933> 180 deg. (pi) 0 -|----+----|-- 0 (0) 0 degrees</font> 2014 ;<font color=#339933> | /|\ |</font> 2015 ;<font color=#339933> sin- | / | \ | sin-</font> 2016 ;<font color=#339933> cos- | / | \ | cos+</font> 2017 ;<font color=#339933> tan+ |/ | \| tan-</font> 2018 ;<font color=#339933> |</font> 2019 ;<font color=#339933> III -1 IV</font> 2020 ;<font color=#339933> (3pi/2)</font> 2021 ;<font color=#339933></font> 2022 ; 270 deg. 2023 2024 2025 <a name="get_argt"></a><b>get_argt</b> RST 28H ;; FP-CALC X. 2026 DEFB $30 ;;stk-data 2027 DEFB $EE ;;Exponent: $7E, 2028 ;;Bytes: 4 2029 DEFB $22,$F9,$83,$6E ;; X, 1/(2*PI) 2030 DEFB $04 ;;multiply X/(2*PI) = fraction 2031 2032 DEFB $2D ;;duplicate 2033 DEFB $A2 ;;stk-half 2034 DEFB $0F ;;addition 2035 DEFB $24 ;;int 2036 2037 DEFB $03 ;;subtract now range -.5 to .5 2038 2039 DEFB $2D ;;duplicate 2040 DEFB $0F ;;addition now range -1 to 1. 2041 DEFB $2D ;;duplicate 2042 DEFB $0F ;;addition now range -2 to 2. 2043 2044 ; quadrant I (0 to +1) and quadrant IV (-1 to 0) are now correct. 2045 ; quadrant II ranges +1 to +2. 2046 ; quadrant III ranges -2 to -1. 2047 2048 DEFB $2D ;;duplicate Y, Y. 2049 DEFB $27 ;;abs Y, abs(Y). range 1 to 2 2050 DEFB $A1 ;;stk-one Y, abs(Y), 1. 2051 DEFB $03 ;;subtract Y, abs(Y)-1. range 0 to 1 2052 DEFB $2D ;;duplicate Y, Z, Z. 2053 DEFB $33 ;;greater-0 Y, Z, (1/0). 2054 2055 DEFB $C0 ;;st-mem-0 store as possible sign 2056 ;; for cosine function. 2057 2058 DEFB $00 ;;jump-true 2059 DEFB $04 ;;to L1D35, ZPLUS with quadrants II and III 2060 2061 ; else the angle lies in quadrant I or IV and value Y is already correct. 2062 2063 DEFB $02 ;;delete Y delete test value. 2064 DEFB $34 ;;end-calc Y. 2065 2066 RET ; return. with Q1 and Q4 >>> 2067 2068 ; The branch was here with quadrants II (0 to 1) and III (1 to 0). 2069 ; Y will hold -2 to -1 if this is quadrant III. 2070 2071 <a name="ZPLUS"></a><b>ZPLUS</b> DEFB $A1 ;;stk-one Y, Z, 1 2072 DEFB $03 ;;subtract Y, Z-1. Q3 = 0 to -1 2073 DEFB $01 ;;exchange Z-1, Y. 2074 DEFB $32 ;;less-0 Z-1, (1/0). 2075 DEFB $00 ;;jump-true Z-1. 2076 DEFB $02 ;;to L1D3C, YNEG 2077 ;;if angle in quadrant III 2078 2079 ; else angle is within quadrant II (-1 to 0) 2080 2081 DEFB $18 ;;negate range +1 to 0 2082 2083 2084 <a name="YNEG"></a><b>YNEG</b> DEFB $34 ;;end-calc quadrants II and III correct. 2085 2086 RET ; return. 2087 2088 2089 ; --------------------- 2090 ; THE <b><font color=#333388>'COSINE'</font></b> FUNCTION 2091 ; --------------------- 2092 ; <font color=#339933>(offset $1D: 'cos')</font> 2093 ; Cosines are calculated as the sine of the opposite angle rectifying the 2094 ; sign depending on the quadrant rules. 2095 ; 2096 ; 2097 ;<font color=#339933> /|</font> 2098 ;<font color=#339933> h /y|</font> 2099 ;<font color=#339933> / |o</font> 2100 ;<font color=#339933> /x |</font> 2101 ;<font color=#339933> /----| </font> 2102 ;<font color=#339933> a</font> 2103 ;<font color=#339933></font> 2104 ; The cosine of angle x is the adjacent side (a) divided by the hypotenuse 1. 2105 ; However if we examine angle y then a/h is the sine of that angle. 2106 ; Since angle x plus angle y equals a right-angle, we can find angle y by 2107 ; subtracting angle x from pi/2. 2108 ; However it's just as easy to reduce the argument first and subtract the 2109 ; reduced argument from the value 1 (a reduced right-angle). 2110 ; It's even easier to subtract 1 from the angle and rectify the sign. 2111 ; In fact, after reducing the argument, the absolute value of the argument 2112 ; is used and rectified using the test result stored in mem-0 by 'get-argt' 2113 ; for that purpose. 2114 2115 <a name="cos"></a><b>cos</b> RST 28H ;; FP-CALC angle in radians. 2116 DEFB $35 ;;get-argt X reduce -1 to +1 2117 2118 DEFB $27 ;;abs ABS X 0 to 1 2119 DEFB $A1 ;;stk-one ABS X, 1. 2120 DEFB $03 ;;subtract now opposite angle 2121 ;; though negative sign. 2122 DEFB $E0 ;;get-mem-0 fetch sign indicator. 2123 DEFB $00 ;;jump-true 2124 DEFB $06 ;;fwd to L1D4B, C-ENT 2125 ;;forward to common code if in QII or QIII 2126 2127 2128 DEFB $18 ;;negate else make positive. 2129 DEFB $2F ;;jump 2130 DEFB $03 ;;fwd to L1D4B, C-ENT 2131 ;;with quadrants QI and QIV 2132 2133 ; ------------------- 2134 ; THE <b><font color=#333388>'SINE'</font></b> FUNCTION 2135 ; ------------------- 2136 ; <font color=#339933>(offset $1C: 'sin')</font> 2137 ; This is a fundamental transcendental function from which others such as cos 2138 ; and tan are directly, or indirectly, derived. 2139 ; It uses the series generator to produce Chebyshev polynomials. 2140 ; 2141 ; 2142 ;<font color=#339933> /|</font> 2143 ;<font color=#339933> 1 / |</font> 2144 ;<font color=#339933> / |x</font> 2145 ;<font color=#339933> /a |</font> 2146 ;<font color=#339933> /----| </font> 2147 ;<font color=#339933> y</font> 2148 ;<font color=#339933></font> 2149 ; The 'get-argt' function is designed to modify the angle and its sign 2150 ; in line with the desired sine value and afterwards it can launch straight 2151 ; into common code. 2152 2153 <a name="sin"></a><b>sin</b> RST 28H ;; FP-CALC angle in radians 2154 DEFB $35 ;;get-argt reduce - sign now correct. 2155 2156 <a name="C_ENT"></a><b>C_ENT</b> DEFB $2D ;;duplicate 2157 DEFB $2D ;;duplicate 2158 DEFB $04 ;;multiply 2159 DEFB $2D ;;duplicate 2160 DEFB $0F ;;addition 2161 DEFB $A1 ;;stk-one 2162 DEFB $03 ;;subtract 2163 2164 DEFB $86 ;;series-06 2165 DEFB $14 ;;Exponent: $64, Bytes: 1 2166 DEFB $E6 ;;(+00,+00,+00) 2167 DEFB $5C ;;Exponent: $6C, Bytes: 2 2168 DEFB $1F,$0B ;;(+00,+00) 2169 DEFB $A3 ;;Exponent: $73, Bytes: 3 2170 DEFB $8F,$38,$EE ;;(+00) 2171 DEFB $E9 ;;Exponent: $79, Bytes: 4 2172 DEFB $15,$63,$BB,$23 ;; 2173 DEFB $EE ;;Exponent: $7E, Bytes: 4 2174 DEFB $92,$0D,$CD,$ED ;; 2175 DEFB $F1 ;;Exponent: $81, Bytes: 4 2176 DEFB $23,$5D,$1B,$EA ;; 2177 2178 DEFB $04 ;;multiply 2179 DEFB $34 ;;end-calc 2180 2181 RET ; return. 2182 2183 2184 ; ---------------------- 2185 ; THE <b><font color=#333388>'TANGENT'</font></b> FUNCTION 2186 ; ---------------------- 2187 ; <font color=#339933>(offset $1E: 'tan')</font> 2188 ; 2189 ; Evaluates tangent x as sin(x) / cos(x). 2190 ; 2191 ; 2192 ;<font color=#339933> /|</font> 2193 ;<font color=#339933> h / |</font> 2194 ;<font color=#339933> / |o</font> 2195 ;<font color=#339933> /x |</font> 2196 ;<font color=#339933> /----| </font> 2197 ;<font color=#339933> a</font> 2198 ;<font color=#339933></font> 2199 ; The tangent of angle x is the ratio of the length of the opposite side 2200 ; divided by the length of the adjacent side. As the opposite length can 2201 ; be calculates using sin(x) and the adjacent length using cos(x) then 2202 ; the tangent can be defined in terms of the previous two functions. 2203 2204 ; Error 6 if the argument, in radians, is too close to one like pi/2 2205 ; which has an infinite tangent. e.g. PRINT TAN (PI/2) evaluates as 1/0. 2206 ; Similarly PRINT TAN (3*PI/2), TAN (5*PI/2) etc. 2207 2208 <a name="tan"></a><b>tan</b> RST 28H ;; FP-CALC x. 2209 DEFB $2D ;;duplicate x, x. 2210 DEFB $1C ;;sin x, sin x. 2211 DEFB $01 ;;exchange sin x, x. 2212 DEFB $1D ;;cos sin x, cos x. 2213 DEFB $05 ;;division sin x/cos x (= tan x). 2214 DEFB $34 ;;end-calc tan x. 2215 2216 RET ; return. 2217 2218 ; --------------------- 2219 ; THE <b><font color=#333388>'ARCTAN'</font></b> FUNCTION 2220 ; --------------------- 2221 ; <font color=#339933>(Offset $21: 'atn')</font> 2222 ; The inverse tangent function with the result in radians. 2223 ; This is a fundamental transcendental function from which others such as asn 2224 ; and acs are directly, or indirectly, derived. 2225 ; It uses the series generator to produce Chebyshev polynomials. 2226 2227 <a name="atn"></a><b>atn</b> LD A,(HL) ; fetch exponent 2228 CP $81 ; compare to that for 'one' 2229 JR C,<A href="#SMALL">SMALL</a> ; forward, if less, to SMALL 2230 2231 RST 28H ;; FP-CALC X. 2232 DEFB $A1 ;;stk-one 2233 DEFB $18 ;;negate 2234 DEFB $01 ;;exchange 2235 DEFB $05 ;;division 2236 DEFB $2D ;;duplicate 2237 DEFB $32 ;;less-0 2238 DEFB $A3 ;;stk-pi/2 2239 DEFB $01 ;;exchange 2240 DEFB $00 ;;jump-true 2241 DEFB $06 ;;to L1D8B, CASES 2242 2243 DEFB $18 ;;negate 2244 DEFB $2F ;;jump 2245 DEFB $03 ;;to L1D8B, CASES 2246 2247 ; --- 2248 2249 <a name="SMALL"></a><b>SMALL</b> RST 28H ;; FP-CALC 2250 DEFB $A0 ;;stk-zero 2251 2252 <a name="CASES"></a><b>CASES</b> DEFB $01 ;;exchange 2253 DEFB $2D ;;duplicate 2254 DEFB $2D ;;duplicate 2255 DEFB $04 ;;multiply 2256 DEFB $2D ;;duplicate 2257 DEFB $0F ;;addition 2258 DEFB $A1 ;;stk-one 2259 DEFB $03 ;;subtract 2260 2261 DEFB $8C ;;series-0C 2262 DEFB $10 ;;Exponent: $60, Bytes: 1 2263 DEFB $B2 ;;(+00,+00,+00) 2264 DEFB $13 ;;Exponent: $63, Bytes: 1 2265 DEFB $0E ;;(+00,+00,+00) 2266 DEFB $55 ;;Exponent: $65, Bytes: 2 2267 DEFB $E4,$8D ;;(+00,+00) 2268 DEFB $58 ;;Exponent: $68, Bytes: 2 2269 DEFB $39,$BC ;;(+00,+00) 2270 DEFB $5B ;;Exponent: $6B, Bytes: 2 2271 DEFB $98,$FD ;;(+00,+00) 2272 DEFB $9E ;;Exponent: $6E, Bytes: 3 2273 DEFB $00,$36,$75 ;;(+00) 2274 DEFB $A0 ;;Exponent: $70, Bytes: 3 2275 DEFB $DB,$E8,$B4 ;;(+00) 2276 DEFB $63 ;;Exponent: $73, Bytes: 2 2277 DEFB $42,$C4 ;;(+00,+00) 2278 DEFB $E6 ;;Exponent: $76, Bytes: 4 2279 DEFB $B5,$09,$36,$BE ;; 2280 DEFB $E9 ;;Exponent: $79, Bytes: 4 2281 DEFB $36,$73,$1B,$5D ;; 2282 DEFB $EC ;;Exponent: $7C, Bytes: 4 2283 DEFB $D8,$DE,$63,$BE ;; 2284 DEFB $F0 ;;Exponent: $80, Bytes: 4 2285 DEFB $61,$A1,$B3,$0C ;; 2286 2287 DEFB $04 ;;multiply 2288 DEFB $0F ;;addition 2289 DEFB $34 ;;end-calc 2290 2291 RET ; return. 2292 2293 2294 ; --------------------- 2295 ; THE <b><font color=#333388>'ARCSIN'</font></b> FUNCTION 2296 ; --------------------- 2297 ; <font color=#339933>(Offset $1F: 'asn')</font> 2298 ; The inverse sine function with result in radians. 2299 ; Derived from arctan function above. 2300 ; Error A unless the argument is between -1 and +1 inclusive. 2301 ; Uses an adaptation of the formula asn(x) = atn(x/sqr(1-x*x)) 2302 ; 2303 ; 2304 ;<font color=#339933> /|</font> 2305 ;<font color=#339933> / |</font> 2306 ;<font color=#339933> 1/ |x</font> 2307 ;<font color=#339933> /a |</font> 2308 ;<font color=#339933> /----| </font> 2309 ;<font color=#339933> y</font> 2310 ;<font color=#339933></font> 2311 ; e.g. We know the opposite side (x) and hypotenuse (1) 2312 ; and we wish to find angle a in radians. 2313 ; We can derive length y by Pythagoras and then use ATN instead. 2314 ; Since y*y + x*x = 1*1 (Pythagoras Theorem) then 2315 ; y=sqr(1-x*x) - no need to multiply 1 by itself. 2316 ; So, asn(a) = atn(x/y) 2317 ; or more fully, 2318 ; asn(a) = atn(x/sqr(1-x*x)) 2319 2320 ; Close but no cigar. 2321 2322 ; While PRINT ATN (x/SQR (1-x*x)) gives the same results as PRINT ASN x, 2323 ; it leads to division by zero when x is 1 or -1. 2324 ; To overcome this, 1 is added to y giving half the required angle and the 2325 ; result is then doubled. 2326 ; That is, PRINT ATN (x/(SQR (1-x*x) +1)) *2 2327 ; 2328 ; 2329 ;<font color=#339933> . /|</font> 2330 ;<font color=#339933> . c/ |</font> 2331 ;<font color=#339933> . /1 |x</font> 2332 ;<font color=#339933> . c b /a |</font> 2333 ;<font color=#339933> ---------/----| </font> 2334 ;<font color=#339933> 1 y</font> 2335 ;<font color=#339933></font> 2336 ; By creating an isosceles triangle with two equal sides of 1, angles c and 2337 ; c are also equal. If b+c+c = 180 degrees and b+a = 180 degress then c=a/2. 2338 ; 2339 ; A value higher than 1 gives the required error as attempting to find the 2340 ; square root of a negative number generates an error in Sinclair BASIC. 2341 2342 <a name="asn"></a><b>asn</b> RST 28H ;; FP-CALC x. 2343 DEFB $2D ;;duplicate x, x. 2344 DEFB $2D ;;duplicate x, x, x. 2345 DEFB $04 ;;multiply x, x*x. 2346 DEFB $A1 ;;stk-one x, x*x, 1. 2347 DEFB $03 ;;subtract x, x*x-1. 2348 DEFB $18 ;;negate x, 1-x*x. 2349 DEFB $25 ;;sqr x, sqr(1-x*x) = y. 2350 DEFB $A1 ;;stk-one x, y, 1. 2351 DEFB $0F ;;addition x, y+1. 2352 DEFB $05 ;;division x/y+1. 2353 DEFB $21 ;;atn a/2 (half the angle) 2354 DEFB $2D ;;duplicate a/2, a/2. 2355 DEFB $0F ;;addition a. 2356 DEFB $34 ;;end-calc a. 2357 2358 RET ; return. 2359 2360 2361 ; ------------------------ 2362 ; THE <b><font color=#333388>'ARCCOS'</font></b> FUNCTION 2363 ; ------------------------ 2364 ; <font color=#339933>(Offset $20: 'acs')</font> 2365 ; the inverse cosine function with the result in radians. 2366 ; Error A unless the argument is between -1 and +1. 2367 ; Result in range 0 to pi. 2368 ; Derived from asn above which is in turn derived from the preceding atn. 2369 ; It could have been derived directly from atn using acs(x) = atn(sqr(1-x*x)/x). 2370 ; However, as sine and cosine are horizontal translations of each other, 2371 ; uses acs(x) = pi/2 - asn(x) 2372 2373 ; e.g. the arccosine of a known x value will give the required angle b in 2374 ; radians. 2375 ; We know, from above, how to calculate the angle a using asn(x). 2376 ; Since the three angles of any triangle add up to 180 degrees, or pi radians, 2377 ; and the largest angle in this case is a right-angle (pi/2 radians), then 2378 ; we can calculate angle b as pi/2 (both angles) minus asn(x) (angle a). 2379 ; 2380 ; 2381 ;<font color=#339933> /|</font> 2382 ;<font color=#339933> 1 /b|</font> 2383 ;<font color=#339933> / |x</font> 2384 ;<font color=#339933> /a |</font> 2385 ;<font color=#339933> /----| </font> 2386 ;<font color=#339933> y</font> 2387 ;<font color=#339933></font> 2388 2389 <a name="acs"></a><b>acs</b> RST 28H ;; FP-CALC x. 2390 DEFB $1F ;;asn asn(x). 2391 DEFB $A3 ;;stk-pi/2 asn(x), pi/2. 2392 DEFB $03 ;;subtract asn(x) - pi/2. 2393 DEFB $18 ;;negate pi/2 - asn(x) = acs(x). 2394 DEFB $34 ;;end-calc acs(x) 2395 2396 RET ; return. 2397 2398 2399 ; -------------------------- 2400 ; THE OLD <b><font color=#333388>'SQUARE ROOT'</font></b> FUNCTION 2401 ; -------------------------- 2402 ; <font color=#339933>(Offset $25: 'sqr')</font> 2403 ; Error A if argument is negative. 2404 ; This routine is remarkable for its brevity - 7 bytes. 2405 ; This routine uses Napier's method for calculating square roots which was 2406 ; devised in 1614 and calculates the value as EXP (LN 'x' * 0.5). 2407 ; 2408 ; This is a little on the slow side as it involves two polynomial series. 2409 ; A series of 12 for LN and a series of 8 for EXP. This was of no concern 2410 ; to John Napier since his tables were 'compiled forever'. 2411 ; 2412 <font color=#FF3333>;;; L1DDB: RST 28H ;; FP-CALC x.</font> 2413 <font color=#FF3333>;;; DEFB $2D ;;duplicate x, x.</font> 2414 <font color=#FF3333>;;; DEFB $2C ;;not x, 1/0</font> 2415 <font color=#FF3333>;;; DEFB $00 ;;jump-true x, (1/0).</font> 2416 <font color=#FF3333>;;; DEFB $1E ;;to L1DFD, LAST exit if argument zero</font> 2417 <font color=#FF3333>;;; ;; with zero result.</font> 2418 ;;; 2419 <font color=#FF3333>;;; else continue to calculate as x ** .5</font> 2420 ;;; 2421 <font color=#FF3333>;;; DEFB $A2 ;;stk-half x, .5.</font> 2422 <font color=#FF3333>;;; DEFB $34 ;;end-calc x, .5.</font> 2423 2424 2425 ; ------------------------ 2426 ; THE <b><font color=#333388>'TO POWER'</font></b> OPERATION 2427 ; ------------------------ 2428 ; <font color=#339933>(Offset $06: 'to-power')</font> 2429 ; The 'Exponential' operation. 2430 ; This raises the first number X to the power of the second number Y. 2431 ; e.g. PRINT 2 ** 3 gives the result 8 2432 ; As with the ZX80, 2433 ; 0 ** 0 = 1 2434 ; 0 ** +n = 0 2435 ; 0 ** -n = arithmetic overflow. 2436 2437 <a name="to_power"></a><b>to_power</b> RST 28H ;; FP-CALC X,Y. 2438 DEFB $01 ;;exchange Y,X. 2439 DEFB $2D ;;duplicate Y,X,X. 2440 DEFB $2C ;;not Y,X,(1/0). 2441 DEFB $00 ;;jump-true 2442 DEFB $07 ;;forward to L1DEE, XISO if X is zero. 2443 2444 ; else X is non-zero. function 'ln' will catch a negative value of X. 2445 2446 DEFB $22 ;;ln Y, LN X. 2447 2448 ; Multiply the power by the logarithm of the argument. 2449 2450 DEFB $04 ;;multiply Y * LN X 2451 DEFB $34 ;;end-calc 2452 2453 JP exp ; jump back to EXP routine ->> 2454 ; to find the 'antiln' 2455 2456 ; --- 2457 2458 ; these routines form the three simple results when the number is zero. 2459 ; begin by deleting the known zero to leave Y the power factor. 2460 2461 <a name="XISO"></a><b>XISO</b> DEFB $02 ;;delete Y. 2462 DEFB $2D ;;duplicate Y, Y. 2463 DEFB $2C ;;not Y, (1/0). 2464 DEFB $00 ;;jump-true 2465 DEFB $09 ;;forward to L1DFB, ONE if Y is zero. 2466 2467 ; the power factor is not zero. If negative then an error exists. 2468 2469 DEFB $A0 ;;stk-zero Y, 0. 2470 DEFB $01 ;;exchange 0, Y. 2471 DEFB $33 ;;greater-0 0, (1/0). 2472 DEFB $00 ;;jump-true 0 2473 DEFB $06 ;;to L1DFD, LAST if Y was any positive 2474 ;; number. 2475 2476 ; else force division by zero thereby raising an Arithmetic overflow error. 2477 ; As an alternative, this now raises an error directly. 2478 2479 <font color=#FF3333>;;; DEFB $A1 ;;stk-one 0, 1.</font> 2480 <font color=#FF3333>;;; DEFB $01 ;;exchange 1, 0.</font> 2481 <font color=#FF3333>;;; DEFB $05 ;;division 1/0 >> error </font> 2482 2483 <font color=#3333FF> DEFB $34 ;+ end-calc</font> 2484 <a name="REPORT_6c"></a><b>REPORT_6c</b> <font color=#3333FF>RST 08H ;+ ERROR-1</font> 2485 <font color=#3333FF> DEFB $05 ;+ Error Report: Number too big</font> 2486 2487 ; --- 2488 2489 <a name="ONE"></a><b>ONE</b> DEFB $02 ;;delete . 2490 DEFB $A1 ;;stk-one 1. 2491 2492 <a name="LAST"></a><b>LAST</b> DEFB $34 ;;end-calc last value 1 or 0. 2493 2494 RET ; return. 2495 2496 ; --------------------- 2497 ; THE <b><font color=#333388>'SPARE LOCATIONS'</font></b> 2498 ; --------------------- 2499 2500 <a name="L1DFE:"></a><b>L1DFE:</b> 2501 2502 DEFB $FF, $FF ; Two spare bytes. 2503 2504 2505 <a name="ORG"></a><b>ORG</b> $1E00 2506 2507 ; ------------------------ 2508 ; THE <b><font color=#333388>'ZX81 CHARACTER SET'</font></b> 2509 ; ------------------------ 2510 2511 2512 ; $00 - <b>Character: ' ' </b>CHR$(0) 2513 2514 <a name="char_set"></a><b>char_set</b> DEFB %00000000 2515 DEFB %00000000 2516 DEFB %00000000 2517 DEFB %00000000 2518 DEFB %00000000 2519 DEFB %00000000 2520 DEFB %00000000 2521 DEFB %00000000 2522 2523 ; $01 - <b>Character: mosaic </b>CHR$(1) 2524 2525 DEFB %<B>1</B><B>1</B><B>1</B><B>1</B>0000 2526 DEFB %<B>1</B><B>1</B><B>1</B><B>1</B>0000 2527 DEFB %<B>1</B><B>1</B><B>1</B><B>1</B>0000 2528 DEFB %<B>1</B><B>1</B><B>1</B><B>1</B>0000 2529 DEFB %00000000 2530 DEFB %00000000 2531 DEFB %00000000 2532 DEFB %00000000 2533 2534 2535 ; $02 - <b>Character: mosaic </b>CHR$(2) 2536 2537 DEFB %0000<B>1</B><B>1</B><B>1</B><B>1</B> 2538 DEFB %0000<B>1</B><B>1</B><B>1</B><B>1</B> 2539 DEFB %0000<B>1</B><B>1</B><B>1</B><B>1</B> 2540 DEFB %0000<B>1</B><B>1</B><B>1</B><B>1</B> 2541 DEFB %00000000 2542 DEFB %00000000 2543 DEFB %00000000 2544 DEFB %00000000 2545 2546 2547 ; $03 - <b>Character: mosaic </b>CHR$(3) 2548 2549 DEFB %<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B> 2550 DEFB %<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B> 2551 DEFB %<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B> 2552 DEFB %<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B> 2553 DEFB %00000000 2554 DEFB %00000000 2555 DEFB %00000000 2556 DEFB %00000000 2557 2558 ; $04 - <b>Character: mosaic </b>CHR$(4) 2559 2560 DEFB %00000000 2561 DEFB %00000000 2562 DEFB %00000000 2563 DEFB %00000000 2564 DEFB %<B>1</B><B>1</B><B>1</B><B>1</B>0000 2565 DEFB %<B>1</B><B>1</B><B>1</B><B>1</B>0000 2566 DEFB %<B>1</B><B>1</B><B>1</B><B>1</B>0000 2567 DEFB %<B>1</B><B>1</B><B>1</B><B>1</B>0000 2568 2569 ; $05 - <b>Character: mosaic </b>CHR$(1) 2570 2571 DEFB %<B>1</B><B>1</B><B>1</B><B>1</B>0000 2572 DEFB %<B>1</B><B>1</B><B>1</B><B>1</B>0000 2573 DEFB %<B>1</B><B>1</B><B>1</B><B>1</B>0000 2574 DEFB %<B>1</B><B>1</B><B>1</B><B>1</B>0000 2575 DEFB %<B>1</B><B>1</B><B>1</B><B>1</B>0000 2576 DEFB %<B>1</B><B>1</B><B>1</B><B>1</B>0000 2577 DEFB %<B>1</B><B>1</B><B>1</B><B>1</B>0000 2578 DEFB %<B>1</B><B>1</B><B>1</B><B>1</B>0000 2579 2580 ; $06 - <b>Character: mosaic </b>CHR$(1) 2581 2582 DEFB %0000<B>1</B><B>1</B><B>1</B><B>1</B> 2583 DEFB %0000<B>1</B><B>1</B><B>1</B><B>1</B> 2584 DEFB %0000<B>1</B><B>1</B><B>1</B><B>1</B> 2585 DEFB %0000<B>1</B><B>1</B><B>1</B><B>1</B> 2586 DEFB %<B>1</B><B>1</B><B>1</B><B>1</B>0000 2587 DEFB %<B>1</B><B>1</B><B>1</B><B>1</B>0000 2588 DEFB %<B>1</B><B>1</B><B>1</B><B>1</B>0000 2589 DEFB %<B>1</B><B>1</B><B>1</B><B>1</B>0000 2590 2591 ; $07 - <b>Character: mosaic </b>CHR$(1) 2592 2593 DEFB %<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B> 2594 DEFB %<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B> 2595 DEFB %<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B> 2596 DEFB %<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B> 2597 DEFB %<B>1</B><B>1</B><B>1</B><B>1</B>0000 2598 DEFB %<B>1</B><B>1</B><B>1</B><B>1</B>0000 2599 DEFB %<B>1</B><B>1</B><B>1</B><B>1</B>0000 2600 DEFB %<B>1</B><B>1</B><B>1</B><B>1</B>0000 2601 2602 ; $08 - <b>Character: mosaic </b>CHR$(1) 2603 2604 DEFB %<B>1</B>0<B>1</B>0<B>1</B>0<B>1</B>0 2605 DEFB %0<B>1</B>0<B>1</B>0<B>1</B>0<B>1</B> 2606 DEFB %<B>1</B>0<B>1</B>0<B>1</B>0<B>1</B>0 2607 DEFB %0<B>1</B>0<B>1</B>0<B>1</B>0<B>1</B> 2608 DEFB %<B>1</B>0<B>1</B>0<B>1</B>0<B>1</B>0 2609 DEFB %0<B>1</B>0<B>1</B>0<B>1</B>0<B>1</B> 2610 DEFB %<B>1</B>0<B>1</B>0<B>1</B>0<B>1</B>0 2611 DEFB %0<B>1</B>0<B>1</B>0<B>1</B>0<B>1</B> 2612 2613 ; $09 - <b>Character: mosaic </b>CHR$(1) 2614 2615 DEFB %00000000 2616 DEFB %00000000 2617 DEFB %00000000 2618 DEFB %00000000 2619 DEFB %<B>1</B>0<B>1</B>0<B>1</B>0<B>1</B>0 2620 DEFB %0<B>1</B>0<B>1</B>0<B>1</B>0<B>1</B> 2621 DEFB %<B>1</B>0<B>1</B>0<B>1</B>0<B>1</B>0 2622 DEFB %0<B>1</B>0<B>1</B>0<B>1</B>0<B>1</B> 2623 2624 ; $0A - <b>Character: mosaic </b>CHR$(10) 2625 2626 DEFB %<B>1</B>0<B>1</B>0<B>1</B>0<B>1</B>0 2627 DEFB %0<B>1</B>0<B>1</B>0<B>1</B>0<B>1</B> 2628 DEFB %<B>1</B>0<B>1</B>0<B>1</B>0<B>1</B>0 2629 DEFB %0<B>1</B>0<B>1</B>0<B>1</B>0<B>1</B> 2630 DEFB %00000000 2631 DEFB %00000000 2632 DEFB %00000000 2633 DEFB %00000000 2634 2635 ; $0B - <b>Character: '"' </b>CHR$(11) 2636 2637 DEFB %00000000 2638 DEFB %00<B>1</B>00<B>1</B>00 2639 DEFB %00<B>1</B>00<B>1</B>00 2640 DEFB %00000000 2641 DEFB %00000000 2642 DEFB %00000000 2643 DEFB %00000000 2644 DEFB %00000000 2645 2646 ; $0B - <b>Character: 'œ' </b>CHR$(12) 2647 2648 DEFB %00000000 2649 DEFB %000<B>1</B><B>1</B><B>1</B>00 2650 DEFB %00<B>1</B>000<B>1</B>0 2651 DEFB %0<B>1</B><B>1</B><B>1</B><B>1</B>000 2652 DEFB %00<B>1</B>00000 2653 DEFB %00<B>1</B>00000 2654 DEFB %0<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>0 2655 DEFB %00000000 2656 2657 ; $0B - <b>Character: '$' </b>CHR$(13) 2658 2659 DEFB %00000000 2660 DEFB %0000<B>1</B>000 2661 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>0 2662 DEFB %00<B>1</B>0<B>1</B>000 2663 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>0 2664 DEFB %0000<B>1</B>0<B>1</B>0 2665 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>0 2666 DEFB %0000<B>1</B>000 2667 2668 ; $0B - <b>Character: ':' </b>CHR$(14) 2669 2670 DEFB %00000000 2671 DEFB %00000000 2672 DEFB %00000000 2673 DEFB %000<B>1</B>0000 2674 DEFB %00000000 2675 DEFB %00000000 2676 DEFB %000<B>1</B>0000 2677 DEFB %00000000 2678 2679 ; $0B - <b>Character: '?' </b>CHR$(15) 2680 2681 DEFB %00000000 2682 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B>00 2683 DEFB %0<B>1</B>0000<B>1</B>0 2684 DEFB %00000<B>1</B>00 2685 DEFB %0000<B>1</B>000 2686 DEFB %00000000 2687 DEFB %0000<B>1</B>000 2688 DEFB %00000000 2689 2690 ; $10 - <b>Character: '(' </b>CHR$(16) 2691 2692 DEFB %00000000 2693 DEFB %00000<B>1</B>00 2694 DEFB %0000<B>1</B>000 2695 DEFB %0000<B>1</B>000 2696 DEFB %0000<B>1</B>000 2697 DEFB %0000<B>1</B>000 2698 DEFB %00000<B>1</B>00 2699 DEFB %00000000 2700 2701 ; $11 - <b>Character: ')' </b>CHR$(17) 2702 2703 DEFB %00000000 2704 DEFB %00<B>1</B>00000 2705 DEFB %000<B>1</B>0000 2706 DEFB %000<B>1</B>0000 2707 DEFB %000<B>1</B>0000 2708 DEFB %000<B>1</B>0000 2709 DEFB %00<B>1</B>00000 2710 DEFB %00000000 2711 2712 ; $12 - <b>Character: '>' </b>CHR$(18) 2713 2714 DEFB %00000000 2715 DEFB %00000000 2716 DEFB %000<B>1</B>0000 2717 DEFB %0000<B>1</B>000 2718 DEFB %00000<B>1</B>00 2719 DEFB %0000<B>1</B>000 2720 DEFB %000<B>1</B>0000 2721 DEFB %00000000 2722 2723 ; $13 - <b>Character: '<' </b>CHR$(19) 2724 2725 DEFB %00000000 2726 DEFB %00000000 2727 DEFB %00000<B>1</B>00 2728 DEFB %0000<B>1</B>000 2729 DEFB %000<B>1</B>0000 2730 DEFB %0000<B>1</B>000 2731 DEFB %00000<B>1</B>00 2732 DEFB %00000000 2733 2734 ; $14 - <b>Character: '=' </b>CHR$(20) 2735 2736 DEFB %00000000 2737 DEFB %00000000 2738 DEFB %00000000 2739 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>0 2740 DEFB %00000000 2741 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>0 2742 DEFB %00000000 2743 DEFB %00000000 2744 2745 ; $15 - <b>Character: '+' </b>CHR$(21) 2746 2747 DEFB %00000000 2748 DEFB %00000000 2749 DEFB %0000<B>1</B>000 2750 DEFB %0000<B>1</B>000 2751 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>0 2752 DEFB %0000<B>1</B>000 2753 DEFB %0000<B>1</B>000 2754 DEFB %00000000 2755 2756 ; $16 - <b>Character: '-' </b>CHR$(22) 2757 2758 DEFB %00000000 2759 DEFB %00000000 2760 DEFB %00000000 2761 DEFB %00000000 2762 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>0 2763 DEFB %00000000 2764 DEFB %00000000 2765 DEFB %00000000 2766 2767 ; $17 - <b>Character: '*' </b>CHR$(23) 2768 2769 DEFB %00000000 2770 DEFB %00000000 2771 DEFB %000<B>1</B>0<B>1</B>00 2772 DEFB %0000<B>1</B>000 2773 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>0 2774 DEFB %0000<B>1</B>000 2775 DEFB %000<B>1</B>0<B>1</B>00 2776 DEFB %00000000 2777 2778 ; $18 - <b>Character: '/' </b>CHR$(24) 2779 2780 DEFB %00000000 2781 DEFB %00000000 2782 DEFB %000000<B>1</B>0 2783 DEFB %00000<B>1</B>00 2784 DEFB %0000<B>1</B>000 2785 DEFB %000<B>1</B>0000 2786 DEFB %00<B>1</B>00000 2787 DEFB %00000000 2788 2789 ; $19 - <b>Character: ';' </b>CHR$(25) 2790 2791 DEFB %00000000 2792 DEFB %00000000 2793 DEFB %000<B>1</B>0000 2794 DEFB %00000000 2795 DEFB %00000000 2796 DEFB %000<B>1</B>0000 2797 DEFB %000<B>1</B>0000 2798 DEFB %00<B>1</B>00000 2799 2800 ; $1A - <b>Character: ',' </b>CHR$(26) 2801 2802 DEFB %00000000 2803 DEFB %00000000 2804 DEFB %00000000 2805 DEFB %00000000 2806 DEFB %00000000 2807 DEFB %0000<B>1</B>000 2808 DEFB %0000<B>1</B>000 2809 DEFB %000<B>1</B>0000 2810 2811 ; $1B - <b>Character: '"' </b>CHR$(27) 2812 2813 DEFB %00000000 2814 DEFB %00000000 2815 DEFB %00000000 2816 DEFB %00000000 2817 DEFB %00000000 2818 DEFB %000<B>1</B><B>1</B>000 2819 DEFB %000<B>1</B><B>1</B>000 2820 DEFB %00000000 2821 2822 ; $1C - <b>Character: '0' </b>CHR$(28) 2823 2824 DEFB %00000000 2825 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B>00 2826 DEFB %0<B>1</B>000<B>1</B><B>1</B>0 2827 DEFB %0<B>1</B>00<B>1</B>0<B>1</B>0 2828 DEFB %0<B>1</B>0<B>1</B>00<B>1</B>0 2829 DEFB %0<B>1</B><B>1</B>000<B>1</B>0 2830 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B>00 2831 DEFB %00000000 2832 2833 ; $1D - <b>Character: '1' </b>CHR$(29) 2834 2835 DEFB %00000000 2836 DEFB %000<B>1</B><B>1</B>000 2837 DEFB %00<B>1</B>0<B>1</B>000 2838 DEFB %0000<B>1</B>000 2839 DEFB %0000<B>1</B>000 2840 DEFB %0000<B>1</B>000 2841 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>0 2842 DEFB %00000000 2843 2844 ; $1E - <b>Character: '2' </b>CHR$(30) 2845 2846 DEFB %00000000 2847 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B>00 2848 DEFB %0<B>1</B>0000<B>1</B>0 2849 DEFB %000000<B>1</B>0 2850 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B>00 2851 DEFB %0<B>1</B>000000 2852 DEFB %0<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>0 2853 DEFB %00000000 2854 2855 ; $1F - <b>Character: '3' </b>CHR$(31) 2856 2857 DEFB %00000000 2858 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B>00 2859 DEFB %0<B>1</B>0000<B>1</B>0 2860 DEFB %0000<B>1</B><B>1</B>00 2861 DEFB %000000<B>1</B>0 2862 DEFB %0<B>1</B>0000<B>1</B>0 2863 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B>00 2864 DEFB %00000000 2865 2866 ; $20 - <b>Character: '4' </b>CHR$(32) 2867 2868 DEFB %00000000 2869 DEFB %0000<B>1</B>000 2870 DEFB %000<B>1</B><B>1</B>000 2871 DEFB %00<B>1</B>0<B>1</B>000 2872 DEFB %0<B>1</B>00<B>1</B>000 2873 DEFB %0<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>0 2874 DEFB %0000<B>1</B>000 2875 DEFB %00000000 2876 2877 ; $21 - <b>Character: '5' </b>CHR$(33) 2878 2879 DEFB %00000000 2880 DEFB %0<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>0 2881 DEFB %0<B>1</B>000000 2882 DEFB %0<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>00 2883 DEFB %000000<B>1</B>0 2884 DEFB %0<B>1</B>0000<B>1</B>0 2885 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B>00 2886 DEFB %00000000 2887 2888 ; $22 - <b>Character: '6' </b>CHR$(34) 2889 2890 DEFB %00000000 2891 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B>00 2892 DEFB %0<B>1</B>000000 2893 DEFB %0<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>00 2894 DEFB %0<B>1</B>0000<B>1</B>0 2895 DEFB %0<B>1</B>0000<B>1</B>0 2896 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B>00 2897 DEFB %00000000 2898 2899 ; $23 - <b>Character: '7' </b>CHR$(35) 2900 2901 DEFB %00000000 2902 DEFB %0<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>0 2903 DEFB %000000<B>1</B>0 2904 DEFB %00000<B>1</B>00 2905 DEFB %0000<B>1</B>000 2906 DEFB %000<B>1</B>0000 2907 DEFB %000<B>1</B>0000 2908 DEFB %00000000 2909 2910 ; $24 - <b>Character: '8' </b>CHR$(36) 2911 2912 DEFB %00000000 2913 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B>00 2914 DEFB %0<B>1</B>0000<B>1</B>0 2915 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B>00 2916 DEFB %0<B>1</B>0000<B>1</B>0 2917 DEFB %0<B>1</B>0000<B>1</B>0 2918 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B>00 2919 DEFB %00000000 2920 2921 ; $25 - <b>Character: '9' </b>CHR$(37) 2922 2923 DEFB %00000000 2924 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B>00 2925 DEFB %0<B>1</B>0000<B>1</B>0 2926 DEFB %0<B>1</B>0000<B>1</B>0 2927 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>0 2928 DEFB %000000<B>1</B>0 2929 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B>00 2930 DEFB %00000000 2931 2932 ; $26 - <b>Character: 'A' </b>CHR$(38) 2933 2934 DEFB %00000000 2935 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B>00 2936 DEFB %0<B>1</B>0000<B>1</B>0 2937 DEFB %0<B>1</B>0000<B>1</B>0 2938 DEFB %0<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>0 2939 DEFB %0<B>1</B>0000<B>1</B>0 2940 DEFB %0<B>1</B>0000<B>1</B>0 2941 DEFB %00000000 2942 2943 ; $27 - <b>Character: 'B' </b>CHR$(39) 2944 2945 DEFB %00000000 2946 DEFB %0<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>00 2947 DEFB %0<B>1</B>0000<B>1</B>0 2948 DEFB %0<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>00 2949 DEFB %0<B>1</B>0000<B>1</B>0 2950 DEFB %0<B>1</B>0000<B>1</B>0 2951 DEFB %0<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>00 2952 DEFB %00000000 2953 2954 ; $28 - <b>Character: 'C' </b>CHR$(40) 2955 2956 DEFB %00000000 2957 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B>00 2958 DEFB %0<B>1</B>0000<B>1</B>0 2959 DEFB %0<B>1</B>000000 2960 DEFB %0<B>1</B>000000 2961 DEFB %0<B>1</B>0000<B>1</B>0 2962 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B>00 2963 DEFB %00000000 2964 2965 ; $29 - <b>Character: 'D' </b>CHR$(41) 2966 2967 DEFB %00000000 2968 DEFB %0<B>1</B><B>1</B><B>1</B><B>1</B>000 2969 DEFB %0<B>1</B>000<B>1</B>00 2970 DEFB %0<B>1</B>0000<B>1</B>0 2971 DEFB %0<B>1</B>0000<B>1</B>0 2972 DEFB %0<B>1</B>000<B>1</B>00 2973 DEFB %0<B>1</B><B>1</B><B>1</B><B>1</B>000 2974 DEFB %00000000 2975 2976 ; $2A - <b>Character: 'E' </b>CHR$(42) 2977 2978 DEFB %00000000 2979 DEFB %0<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>0 2980 DEFB %0<B>1</B>000000 2981 DEFB %0<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>00 2982 DEFB %0<B>1</B>000000 2983 DEFB %0<B>1</B>000000 2984 DEFB %0<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>0 2985 DEFB %00000000 2986 2987 ; $2B - <b>Character: 'F' </b>CHR$(43) 2988 2989 DEFB %00000000 2990 DEFB %0<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>0 2991 DEFB %0<B>1</B>000000 2992 DEFB %0<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>00 2993 DEFB %0<B>1</B>000000 2994 DEFB %0<B>1</B>000000 2995 DEFB %0<B>1</B>000000 2996 DEFB %00000000 2997 2998 ; $2C - <b>Character: 'G' </b>CHR$(44) 2999 3000 DEFB %00000000 3001 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B>00 3002 DEFB %0<B>1</B>0000<B>1</B>0 3003 DEFB %0<B>1</B>000000 3004 DEFB %0<B>1</B>00<B>1</B><B>1</B><B>1</B>0 3005 DEFB %0<B>1</B>0000<B>1</B>0 3006 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B>00 3007 DEFB %00000000 3008 3009 ; $2D - <b>Character: 'H' </b>CHR$(45) 3010 3011 DEFB %00000000 3012 DEFB %0<B>1</B>0000<B>1</B>0 3013 DEFB %0<B>1</B>0000<B>1</B>0 3014 DEFB %0<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>0 3015 DEFB %0<B>1</B>0000<B>1</B>0 3016 DEFB %0<B>1</B>0000<B>1</B>0 3017 DEFB %0<B>1</B>0000<B>1</B>0 3018 DEFB %00000000 3019 3020 ; $2E - <b>Character: 'I' </b>CHR$(46) 3021 3022 DEFB %00000000 3023 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>0 3024 DEFB %0000<B>1</B>000 3025 DEFB %0000<B>1</B>000 3026 DEFB %0000<B>1</B>000 3027 DEFB %0000<B>1</B>000 3028 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>0 3029 DEFB %00000000 3030 3031 ; $2F - <b>Character: 'J' </b>CHR$(47) 3032 3033 DEFB %00000000 3034 DEFB %000000<B>1</B>0 3035 DEFB %000000<B>1</B>0 3036 DEFB %000000<B>1</B>0 3037 DEFB %0<B>1</B>0000<B>1</B>0 3038 DEFB %0<B>1</B>0000<B>1</B>0 3039 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B>00 3040 DEFB %00000000 3041 3042 ; $30 - <b>Character: 'K' </b>CHR$(48) 3043 3044 DEFB %00000000 3045 DEFB %0<B>1</B>000<B>1</B>00 3046 DEFB %0<B>1</B>00<B>1</B>000 3047 DEFB %0<B>1</B><B>1</B><B>1</B>0000 3048 DEFB %0<B>1</B>00<B>1</B>000 3049 DEFB %0<B>1</B>000<B>1</B>00 3050 DEFB %0<B>1</B>0000<B>1</B>0 3051 DEFB %00000000 3052 3053 ; $31 - <b>Character: 'L' </b>CHR$(49) 3054 3055 DEFB %00000000 3056 DEFB %0<B>1</B>000000 3057 DEFB %0<B>1</B>000000 3058 DEFB %0<B>1</B>000000 3059 DEFB %0<B>1</B>000000 3060 DEFB %0<B>1</B>000000 3061 DEFB %0<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>0 3062 DEFB %00000000 3063 3064 ; $32 - <b>Character: 'M' </b>CHR$(50) 3065 3066 DEFB %00000000 3067 DEFB %0<B>1</B>0000<B>1</B>0 3068 DEFB %0<B>1</B><B>1</B>00<B>1</B><B>1</B>0 3069 DEFB %0<B>1</B>0<B>1</B><B>1</B>0<B>1</B>0 3070 DEFB %0<B>1</B>0000<B>1</B>0 3071 DEFB %0<B>1</B>0000<B>1</B>0 3072 DEFB %0<B>1</B>0000<B>1</B>0 3073 DEFB %00000000 3074 3075 ; $33 - <b>Character: 'N' </b>CHR$(51) 3076 3077 DEFB %00000000 3078 DEFB %0<B>1</B>0000<B>1</B>0 3079 DEFB %0<B>1</B><B>1</B>000<B>1</B>0 3080 DEFB %0<B>1</B>0<B>1</B>00<B>1</B>0 3081 DEFB %0<B>1</B>00<B>1</B>0<B>1</B>0 3082 DEFB %0<B>1</B>000<B>1</B><B>1</B>0 3083 DEFB %0<B>1</B>0000<B>1</B>0 3084 DEFB %00000000 3085 3086 ; $34 - <b>Character: 'O' </b>CHR$(52) 3087 3088 DEFB %00000000 3089 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B>00 3090 DEFB %0<B>1</B>0000<B>1</B>0 3091 DEFB %0<B>1</B>0000<B>1</B>0 3092 DEFB %0<B>1</B>0000<B>1</B>0 3093 DEFB %0<B>1</B>0000<B>1</B>0 3094 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B>00 3095 DEFB %00000000 3096 3097 ; $35 - <b>Character: 'P' </b>CHR$(53) 3098 3099 DEFB %00000000 3100 DEFB %0<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>00 3101 DEFB %0<B>1</B>0000<B>1</B>0 3102 DEFB %0<B>1</B>0000<B>1</B>0 3103 DEFB %0<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>00 3104 DEFB %0<B>1</B>000000 3105 DEFB %0<B>1</B>000000 3106 DEFB %00000000 3107 3108 ; $36 - <b>Character: 'Q' </b>CHR$(54) 3109 3110 DEFB %00000000 3111 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B>00 3112 DEFB %0<B>1</B>0000<B>1</B>0 3113 DEFB %0<B>1</B>0000<B>1</B>0 3114 DEFB %0<B>1</B>0<B>1</B>00<B>1</B>0 3115 DEFB %0<B>1</B>00<B>1</B>0<B>1</B>0 3116 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B>00 3117 DEFB %00000000 3118 3119 ; $37 - <b>Character: 'R' </b>CHR$(55) 3120 3121 DEFB %00000000 3122 DEFB %0<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>00 3123 DEFB %0<B>1</B>0000<B>1</B>0 3124 DEFB %0<B>1</B>0000<B>1</B>0 3125 DEFB %0<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>00 3126 DEFB %0<B>1</B>000<B>1</B>00 3127 DEFB %0<B>1</B>0000<B>1</B>0 3128 DEFB %00000000 3129 3130 ; $38 - <b>Character: 'S' </b>CHR$(56) 3131 3132 DEFB %00000000 3133 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B>00 3134 DEFB %0<B>1</B>000000 3135 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B>00 3136 DEFB %000000<B>1</B>0 3137 DEFB %0<B>1</B>0000<B>1</B>0 3138 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B>00 3139 DEFB %00000000 3140 3141 ; $39 - <b>Character: 'T' </b>CHR$(57) 3142 3143 DEFB %00000000 3144 DEFB %<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>0 3145 DEFB %000<B>1</B>0000 3146 DEFB %000<B>1</B>0000 3147 DEFB %000<B>1</B>0000 3148 DEFB %000<B>1</B>0000 3149 DEFB %000<B>1</B>0000 3150 DEFB %00000000 3151 3152 ; $3A - <b>Character: 'U' </b>CHR$(58) 3153 3154 DEFB %00000000 3155 DEFB %0<B>1</B>0000<B>1</B>0 3156 DEFB %0<B>1</B>0000<B>1</B>0 3157 DEFB %0<B>1</B>0000<B>1</B>0 3158 DEFB %0<B>1</B>0000<B>1</B>0 3159 DEFB %0<B>1</B>0000<B>1</B>0 3160 DEFB %00<B>1</B><B>1</B><B>1</B><B>1</B>00 3161 DEFB %00000000 3162 3163 ; $3B - <b>Character: 'V' </b>CHR$(59) 3164 3165 DEFB %00000000 3166 DEFB %0<B>1</B>0000<B>1</B>0 3167 DEFB %0<B>1</B>0000<B>1</B>0 3168 DEFB %0<B>1</B>0000<B>1</B>0 3169 DEFB %0<B>1</B>0000<B>1</B>0 3170 DEFB %00<B>1</B>00<B>1</B>00 3171 DEFB %000<B>1</B><B>1</B>000 3172 DEFB %00000000 3173 3174 ; $3C - <b>Character: 'W' </b>CHR$(60) 3175 3176 DEFB %00000000 3177 DEFB %0<B>1</B>0000<B>1</B>0 3178 DEFB %0<B>1</B>0000<B>1</B>0 3179 DEFB %0<B>1</B>0000<B>1</B>0 3180 DEFB %0<B>1</B>0000<B>1</B>0 3181 DEFB %0<B>1</B>0<B>1</B><B>1</B>0<B>1</B>0 3182 DEFB %00<B>1</B>00<B>1</B>00 3183 DEFB %00000000 3184 3185 ; $3D - <b>Character: 'X' </b>CHR$(61) 3186 3187 DEFB %00000000 3188 DEFB %0<B>1</B>0000<B>1</B>0 3189 DEFB %00<B>1</B>00<B>1</B>00 3190 DEFB %000<B>1</B><B>1</B>000 3191 DEFB %000<B>1</B><B>1</B>000 3192 DEFB %00<B>1</B>00<B>1</B>00 3193 DEFB %0<B>1</B>0000<B>1</B>0 3194 DEFB %00000000 3195 3196 ; $3E - <b>Character: 'Y' </b>CHR$(62) 3197 3198 DEFB %00000000 3199 DEFB %<B>1</B>00000<B>1</B>0 3200 DEFB %0<B>1</B>000<B>1</B>00 3201 DEFB %00<B>1</B>0<B>1</B>000 3202 DEFB %000<B>1</B>0000 3203 DEFB %000<B>1</B>0000 3204 DEFB %000<B>1</B>0000 3205 DEFB %00000000 3206 3207 ; $3F - <b>Character: 'Z' </b>CHR$(63) 3208 3209 DEFB %00000000 3210 DEFB %0<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>0 3211 DEFB %00000<B>1</B>00 3212 DEFB %0000<B>1</B>000 3213 DEFB %000<B>1</B>0000 3214 DEFB %00<B>1</B>00000 3215 DEFB %0<B>1</B><B>1</B><B>1</B><B>1</B><B>1</B><B>1</B>0 3216 DEFB %00000000 3217 3218 .END ;TASM assembler instruction. 3219 3220 3221 3222 </PRE> 3223 </BODY> 3224 </HTML>