zx81-rom

ZX81 rom source mirror
git clone http://frotz.net/git/zx81-rom.git
Log | Files | Refs

zx81plus.asm (246238B)


      1 ; ===========================================================
      2 ; An Assembly Listing of the Operating System of the ZX81 ROM
      3 ; ===========================================================
      4 
      5 ; Last updated: 13-DEC-2004
      6 ; 2011		Updated to remove -, +, /, *, &, 
      7 ;		characters from labels (which confuse assemblers)
      8 ;
      9 ; 2011		Updated for conditional assembly of ORIGINAL or "Shoulders of Giants" ROM
     10 ;
     11 ; 2014-08-01	Updated to add CHARS_PER_LINE_WINDOW  which is normally 32.
     12 ;
     13 ;	The ideal pixel rates for square pixels on a PAL system are
     14 ;	14.75  MHz (interlaced) and
     15 ;	 7.375 MHz (non-interlaced, which the ZX80/ZX81 are).
     16 ;	These are not commonly available but fortunately one can buy
     17 ;	baud-rate generator frequencies such as
     18 ;	14.7456 and 7.3728 MHz that are only 0.03% low
     19 ;	which is more than close enough.
     20 ;
     21 ;	ZX video normally has 6.5 MHz pixel rate,
     22 ;	so 32 characters take 256 pixels in 39.4 microseconds.
     23 ;	A 7.3728 MHz clock and 40 characters produces 
     24 ;	320 pixels in 43.4 microseconds.
     25 ;
     26 ;	ZX80 video generation is software defined so it is
     27 ;	easy to get square pixels simply by subtracting 8 from the bytes
     28 ;	at hex addresses 287, 2AA and 2B8.
     29 ;	The video will appear to the left of the screen but
     30 ;	the characters will be square and a diagonal graphic line
     31 ;	will be at 45 degrees.
     32 ;
     33 ;	ZX81 video generation in fast mode exactly the same as the ZX80.
     34 ;
     35 ;	ZX81 video generation in slow mode is problematic, in that
     36 ;	the NMI generator expects a 3.25 MHz CPU clock 
     37 ;	(3.25MHz / 208 = 15.625 kHz = 64 microsecond line period)
     38 ;	It is inside the ULA where it cannot be modified.
     39 ;
     40 ;	Simply fitting a 7.3728 MHz crystal would reduce the line period to
     41 ;	57.3 microseconds. Slow mode would require the CPU clock to be
     42 ;	divided by 236.
     43 ;
     44 ;	Square pixels on NTSC requires 11+3/11 = 11.272... MHz (interlaced)
     45 ;	or 5.63.. non-interlaced which is slower than the original 6.5 MHz.
     46 ;	The NTSC line period is still 64 microseconds, so 256 pixels
     47 ;	stretch over 45 microseconds, and 320 pixels over 56 microseconds.
     48 ;	Thus it is possible to get square pixels on an NTSC display,
     49 ;	it is not possible to get 40 column text as well.
     50 ;	That would require the PAL clock, but pixels would not be square.
     51 ;
     52 ;	The ZX printer is fixed in hardware.
     53 ;	It will not work in 40-column mode.
     54 ;
     55 ;
     56 ;
     57 ;	PIXEL_CLOCK:	equ	7372500
     58 ;
     59 ; on-line assembler complains about the line above
     60 ;
     61 ; CHARS_PER_LINE_WINDOW always 32 for 6.5   MHz pixel rate
     62 ;                       always 40 for 7.375 MHz PAL square pixel rate
     63 ;
     64 ;CHARS_PER_LINE_WINDOW:	equ	40	; 32	originally
     65 CHARS_PER_LINE_WINDOW:	equ	32
     66 ;
     67 ; CHARS_PER_LINE always 32 for 6.5 MHz pixel rate
     68 ;                but 32 or 40 if using PAL square pixel rate
     69 ;
     70 ;CHARS_HORIZONTAL:	equ	40	; 32	originally
     71 CHARS_HORIZONTAL:	equ	32
     72 CHARS_VERTICAL:		equ	24
     73 ;
     74 ; 2014-08-01
     75 ; Largely working but some bugs remain.
     76 ; Working:
     77 ; You can type text and it takes 40 characters before new line.
     78 ; 40 characters are nicely centred in the screen.
     79 ; PLOT X,Y accepts X from 0 to 79.
     80 ; Faulty:
     81 ; System crashing in an authentic ZX81 fashion,
     82 ; I don't know if this is due to software bugs
     83 ; or socket joint disturbance from key presses.
     84 ; 
     85 ;
     86 ; 2018-01-09 add org
     87 ; Assembles using on-line assembler "zasm" at:
     88 ;
     89 ; http://k1.spdns.de/cgi-bin/zasm.cgi
     90 ;
     91 	org	0
     92 	
     93 FALSE:		equ	0
     94 
     95 ORIGINAL:	equ	1
     96 NOT_BODGED:	equ	1
     97 
     98 ; 2018-02-09 CHARS_HORIZONTAL placed in SCROLL routine.
     99 ;		Thanks to Adam Klotblixt for testing code and spotting this bug.
    100 ;	Also added to some G007 routines.
    101 ;
    102 
    103 
    104 ;
    105 ; Work in progress.
    106 ; This file will cross-assemble an original version of the "Improved"
    107 ; ZX81 ROM.
    108 ; The file can be modified to change the behaviour of the ROM
    109 ; when used in emulators although there is no spare space available.
    110 ;
    111 ; The documentation is incomplete and if you can find a copy
    112 ; of "The Complete Spectrum ROM Disassembly" then many routines
    113 ; such as POINTERS and most of the mathematical routines are
    114 ; similar and often identical.
    115 ;
    116 ; I've used the labels from the above book in this file and also
    117 ; some from the more elusive Complete ZX81 ROM Disassembly
    118 ; by the same publishers, Melbourne House.
    119 
    120 ; define stuff sensibly:
    121 ;
    122 ; I/O locations:
    123 ;
    124 IO_PORT_TAPE:		equ	$FF	; write
    125 IO_PORT_SCREEN:		equ	$FF	; write
    126 
    127 IO_PORT_KEYBOARD_RD:	equ	$FE	; A0 low
    128 IO_PORT_NMI_GEN_ON:	equ	$FE	; A0 low
    129 IO_PORT_NMI_GEN_OFF:	equ	$FD	; A1 low
    130 IO_PORT_PRINTER:		equ	$FB	; A2 low
    131 
    132 ;
    133 ; System variables:
    134 ;
    135 RAMBASE:		equ	$4000
    136 ERR_NR:		equ	$4000		; The report code. Incremented before printing.
    137 FLAGS:		equ	$4001		; Bit 0: Suppression of leading space.
    138 					; Bit 1: Control Flag for the printer.
    139 					; Bit 2: Selects K or F mode; or, F or G
    140 					; Bit 6: FP no. or string parameters.
    141 					; Bit 7: Reset during syntax checking."
    142 ERR_SP:		equ	$4002		; Pointer to the GOSUB stack.
    143 RAMTOP:		equ	$4004		; The top of available RAM, or as specified.
    144 MODE:		equ	$4006		; Holds the code for K or F
    145 PPC:		equ	$4007		; Line number of the current statement.
    146 PPC_hi:		equ	PPC+1
    147 VERSN:		equ	$4009		; Marks the start of the RAM that is saved.
    148 E_PPC:		equ	$400A		; The BASIC line with the cursor
    149 D_FILE:		equ	$400C		; Pointer to Display file
    150 DF_CC:		equ	$400E		; Address for PRINT AT position
    151 VARS:		equ	$4010		; Pointer to variable area
    152 DEST:		equ	$4012		; Address of current variable in program area
    153 E_LINE:		equ	$4014		; Pointer to workspace
    154 E_LINE_hi:	equ	E_LINE+1
    155 CH_ADD:		equ	$4016		; Pointer for scanning a line, in program or workspace
    156 X_PTR:		equ	$4018		; Pointer to syntax error.
    157 X_PTR_lo:	equ	X_PTR
    158 X_PTR_hi:	equ	X_PTR+1
    159 STKBOT:		equ	$401A		; Pointer to calculator stack bottom.
    160 STKEND:		equ	$401C		; Pointer to calculator stack end.
    161 BERG:		equ	$401E		; Used for many different counting purposes
    162 MEM:		equ	$401F		; Pointer to base of table of fp. nos, either in calc. stack or variable area.
    163 ;					; Unused by ZX BASIC. Or FLAG Y for G007
    164 DF_SZ:		equ	$4022		; Number of lines in the lower screen
    165 S_TOP:		equ	$4023		; Current line number of automatic listing
    166 LAST_K:		equ	$4025		; Last Key pressed
    167 DEBOUNCE_VAR:	equ	$4027		; The de-bounce status
    168 MARGIN:		equ	$4028		; Adjusts for differing TV standards
    169 NXTLIN:		equ	$4029		; Next BASIC line to be interpreted
    170 OLDPPC:		equ	$402B		; Last line number, in case needed.
    171 FLAGX:		equ	$402D		; Bit 0: Reset indicates an arrayed variable
    172 					; Bit 1: Reset indicates a given variable exists
    173 					; Bit 5: Set during INPUT mode
    174 					; Bit 7: Set when INPUT is to be numeric
    175 STRLEN:		equ	$402E		; Length of a string, or a BASIC line
    176 STRLEN_lo:	equ	STRLEN		; 
    177 T_ADDR:		equ	$4030		; Pointer to parameter table. & distinguishes between PLOT & UNPLOT
    178 SEED:		equ	$4032		; For RANDOM function
    179 FRAMES:		equ	$4034		; Frame counter
    180 FRAMES_hi:	equ	FRAMES+1	; 
    181 COORDS:		equ	$4036		; X & Y for PLOT
    182 COORDS_x:	equ	COORDS		; 
    183 PR_CC:		equ	$4038		; Print buffer counter
    184 S_POSN:		equ	$4039		; Line & Column for PRINT AT
    185 S_POSN_x:	equ	$4039		; 
    186 S_POSN_y:	equ	$403A		; 
    187 CDFLAG:		equ	$403B		; Bit 6 = the true fast/slow flag
    188 					; Bit 7 = copy of the fast/slow flag. RESET when FAST needed
    189 PRBUFF:		equ	$403C		; Printer buffer
    190 PRBUFF_END:	equ	$405C		; 
    191 MEM_0_1st:	equ	$405D		; room for 5 floating point numbers (meme_0 to mem_ 5???)
    192 ;			$407B		; unused. Or RESTART to G007
    193 ;			$407D		; The BASIC program starts here
    194 ;:		equ	$40
    195 ;:		equ	$40
    196 ;:		equ	$40
    197 ; First byte after system variables:
    198 USER_RAM:	equ	$407D
    199 MAX_RAM:		equ	$7FFF
    200 
    201 ;===============================
    202 ; ZX81 constants:
    203 ;===============================
    204 ; ZX characters (not the same as ASCII)
    205 ;-------------------------------
    206 ZX_SPACE:	equ	$00
    207 ;	ZX_graphic:		equ	$01
    208 ;	ZX_graphic:		equ	$02
    209 ;	ZX_graphic:		equ	$03
    210 ;	ZX_graphic:		equ	$04
    211 ;	ZX_graphic:		equ	$05
    212 ;	ZX_graphic:		equ	$06
    213 ;	ZX_graphic:		equ	$07
    214 ;	ZX_graphic:		equ	$08
    215 ;	ZX_graphic:		equ	$09
    216 ;	ZX_graphic:		equ	$0A
    217 ZX_QUOTE:		equ	$0B
    218 ZX_POUND:		equ	$0C
    219 ZX_DOLLAR:		equ	$0D
    220 ZX_COLON:		equ	$0E
    221 ZX_QUERY:		equ	$0F
    222 ZX_BRACKET_LEFT:		equ	$10
    223 ZX_BRACKET_RIGHT:	equ	$11
    224 ZX_GREATER_THAN:		equ	$12
    225 ZX_LESS_THAN:		equ	$13
    226 ZX_EQUAL:		equ	$14
    227 ZX_PLUS:			equ	$15
    228 ZX_MINUS:		equ	$16
    229 ZX_STAR:			equ	$17
    230 ZX_SLASH:		equ	$18
    231 ZX_SEMICOLON:		equ	$19
    232 ZX_COMMA:		equ	$1A
    233 ZX_PERIOD:		equ	$1B
    234 ZX_0:		equ	$1C
    235 ZX_1:		equ	$1D
    236 ZX_2:		equ	$1E
    237 ZX_3:		equ	$1F
    238 ZX_4:		equ	$20
    239 ZX_5:		equ	$21
    240 ZX_6:		equ	$22
    241 ZX_7:		equ	$23
    242 ZX_8:		equ	$24
    243 ZX_9:		equ	$25
    244 ZX_A:		equ	$26
    245 ZX_B:		equ	$27
    246 ZX_C:		equ	$28
    247 ZX_D:		equ	$29
    248 ZX_E:		equ	$2A
    249 ZX_F:		equ	$2B
    250 ZX_G:		equ	$2C
    251 ZX_H:		equ	$2D
    252 ZX_I:		equ	$2E
    253 ZX_J:		equ	$2F
    254 ZX_K:		equ	$30
    255 ZX_L:		equ	$31
    256 ZX_M:		equ	$32
    257 ZX_N:		equ	$33
    258 ZX_O:		equ	$34
    259 ZX_P:		equ	$35
    260 ZX_Q:		equ	$36
    261 ZX_R:		equ	$37
    262 ZX_S:		equ	$38
    263 ZX_T:		equ	$39
    264 ZX_U:		equ	$3A
    265 ZX_V:		equ	$3B
    266 ZX_W:		equ	$3C
    267 ZX_X:		equ	$3D
    268 ZX_Y:		equ	$3E
    269 ZX_Z:		equ	$3F
    270 ZX_RND:			equ	$40
    271 ZX_INKEY_STR:		equ	$41
    272 ZX_PI:			equ	$42
    273 ;
    274 ; $43 to $6F not used
    275 ;
    276 ZX_cursor_up:		equ	$70
    277 ZX_cursor_down:		equ	$71
    278 ZX_cursor_left:		equ	$72
    279 ZX_cursor_right:		equ	$73
    280 
    281 ZX_GRAPHICS:		equ	$74
    282 ZX_EDIT:			equ	$75
    283 ZX_NEWLINE:		equ	$76
    284 ZX_RUBOUT:		equ	$77
    285 ZX_KL:			equ	$78
    286 ZX_FUNCTION:		equ	$79
    287 ;
    288 ; $7A to $7F not used
    289 ;
    290 ZX_CURSOR:		equ	$7F
    291 ;
    292 ; $80 to $BF are inverses of $00 to $3F
    293 ;
    294 ;	ZX_graphic:		equ	$80	 ; inverse space
    295 ;	ZX_graphic:		equ	$81
    296 ;	ZX_graphic:		equ	$82
    297 ;	ZX_graphic:		equ	$83
    298 ;	ZX_graphic:		equ	$84
    299 ;	ZX_graphic:		equ	$85
    300 ;	ZX_graphic:		equ	$86
    301 ;	ZX_graphic:		equ	$87
    302 ;	ZX_graphic:		equ	$88
    303 ;	ZX_graphic:		equ	$89
    304 ;	ZX_graphic:		equ	$8A
    305 ZX_INV_QUOTE:		equ	$8B
    306 ZX_INV_POUND:		equ	$8C
    307 ZX_INV_DOLLAR:		equ	$8D
    308 ZX_INV_COLON:		equ	$8E
    309 ZX_INV_QUERY:		equ	$8F
    310 ZX_INV_BRACKET_RIGHT:	equ	$90
    311 ZX_INV_BRACKET_LEFT:	equ	$91
    312 ZX_INV_GT:		equ	$92
    313 
    314 ZX_INV_PLUS:		equ	$95
    315 ZX_INV_MINUS:		equ	$96
    316 
    317 ZX_INV_K:		equ	$B0
    318 ZX_INV_S:		equ	$B8
    319 
    320 ZX_DOUBLE_QUOTE:		equ	$C0
    321 ZX_AT:			equ	$C1
    322 ZX_TAB:			equ	$C2
    323 ; not used:		equ	$C3
    324 ZX_CODE:			equ	$C4
    325 ZX_VAL:			equ	$C5
    326 ZX_LEN:			equ	$C6
    327 ZX_SIN:			equ	$C7
    328 ZX_COS:			equ	$C8
    329 ZX_TAN:			equ	$C9
    330 ZX_ASN:			equ	$CA
    331 ZX_ACS:			equ	$CB
    332 ZX_ATN:			equ	$CC
    333 ZX_LN:			equ	$CD
    334 ZX_EXP:			equ	$CE
    335 ZX_INT:			equ	$CF
    336 
    337 ZX_SQR:			equ	$D0
    338 ZX_SGN:			equ	$D1
    339 ZX_ABS:			equ	$D2
    340 ZX_PEEK:			equ	$D3
    341 ZX_USR:			equ	$D4
    342 ZX_STR_STR:		equ	$D5		; STR$
    343 ZX_CHR_STR:		equ	$D6		; CHR$
    344 ZX_NOT:			equ	$D7
    345 ZX_POWER:		equ	$D8
    346 ZX_OR:			equ	$D9
    347 ZX_AND:			equ	$DA
    348 ZX_LESS_OR_EQUAL:	equ	$DB
    349 ZX_GREATER_OR_EQUAL:	equ	$DC
    350 ZX_NOT_EQUAL:		equ	$DD
    351 ZX_THEN:			equ	$DE
    352 ZX_TO:			equ	$DF
    353 
    354 ZX_STEP:			equ	$E0
    355 ZX_LPRINT:		equ	$E1
    356 ZX_LLIST:		equ	$E2
    357 ZX_STOP:			equ	$E3
    358 ZX_SLOW:			equ	$E4
    359 ZX_FAST:			equ	$E5
    360 ZX_NEW:			equ	$E6
    361 ZX_SCROLL:		equ	$E7
    362 ZX_CONT:			equ	$E8
    363 ZX_DIM:			equ	$E9
    364 ZX_REM:			equ	$EA
    365 ZX_FOR:			equ	$EB
    366 ZX_GOTO:			equ	$EC
    367 ZX_GOSUB:		equ	$ED
    368 ZX_INPUT:		equ	$EE
    369 ZX_LOAD:			equ	$EF
    370 
    371 ZX_LIST:			equ	$F0
    372 ZX_LET:			equ	$F1
    373 ZX_PAUSE:		equ	$F2
    374 ZX_NEXT:			equ	$F3
    375 ZX_POKE:			equ	$F4
    376 ZX_PRINT:		equ	$F5
    377 ZX_PLOT:			equ	$F6
    378 ZX_RUN:			equ	$F7
    379 ZX_SAVE:			equ	$F8
    380 ZX_RAND:			equ	$F9
    381 ZX_IF:			equ	$FA
    382 ZX_CLS:			equ	$FB
    383 ZX_UNPLOT:		equ	$FC
    384 ZX_CLEAR:		equ	$FD
    385 ZX_RETURN:		equ	$FE
    386 ZX_COPY:			equ	$FF
    387 
    388 
    389 ;
    390 _CLASS_00:	equ	0
    391 _CLASS_01:	equ	1
    392 _CLASS_02:	equ	2
    393 _CLASS_03:	equ	3
    394 _CLASS_04:	equ	4
    395 _CLASS_05:	equ	5
    396 _CLASS_06:	equ	6
    397 
    398 
    399 
    400 ; These values taken from BASIC manual
    401 ; 
    402 ;
    403 ERROR_CODE_SUCCESS:			equ	0
    404 ERROR_CODE_CONTROL_VARIABLE:		equ	1
    405 ERROR_CODE_UNDEFINED_VARIABLE:		equ	2
    406 ERROR_CODE_SUBSCRIPT_OUT_OF_RANGE:	equ	3
    407 ERROR_CODE_NOT_ENOUGH_MEMORY:		equ	4
    408 ERROR_CODE_NO_ROOM_ON_SCREEN:		equ	5
    409 ERROR_CODE_ARITHMETIC_OVERFLOW:		equ	6
    410 ERROR_CODE_RETURN_WITHOUT_GOSUB:		equ	7
    411 ERROR_CODE_INPUT_AS_A_COMMAND:		equ	8
    412 ERROR_CODE_STOP:				equ	9
    413 ERROR_CODE_INVALID_ARGUMENT:		equ	10
    414 
    415 ERROR_CODE_INTEGER_OUT_OF_RANGE:		equ	11
    416 ERROR_CODE_VAL_STRING_INVALID:		equ	12
    417 ERROR_CODE_BREAK:			equ	13
    418 
    419 ERROR_CODE_EMPTY_PROGRAM_NAME:		equ	15
    420 
    421 ;
    422 ; codes for Forth-like calculator
    423 ;
    424 __jump_true:		equ	$00
    425 __exchange:		equ	$01
    426 __delete:		equ	$02
    427 __subtract:		equ	$03
    428 __multiply:		equ	$04
    429 __division:		equ	$05
    430 __to_power:		equ	$06
    431 __or:			equ	$07
    432 __boolean_num_and_num:	equ	$08
    433 __num_l_eql:		equ	$09
    434 __num_gr_eql:		equ	$0A
    435 __nums_neql:		equ	$0B
    436 __num_grtr:		equ	$0C
    437 __num_less:		equ	$0D
    438 __nums_eql:		equ	$0E
    439 __addition:		equ	$0F
    440 __strs_and_num:		equ	$10
    441 __str_l_eql:		equ	$11
    442 __str_gr_eql:		equ	$12
    443 __strs_neql:		equ	$13
    444 __str_grtr:		equ	$14
    445 __str_less:		equ	$15
    446 __strs_eql:		equ	$16
    447 __strs_add:		equ	$17
    448 __negate:		equ	$18
    449 __code:			equ	$19
    450 __val:			equ	$1A 
    451 __len:			equ	$1B 
    452 __sin:			equ	$1C
    453 __cos:			equ	$1D
    454 __tan:			equ	$1E
    455 __asn:			equ	$1F
    456 __acs:			equ	$20
    457 __atn:			equ	$21
    458 __ln:			equ	$22
    459 __exp:			equ	$23
    460 __int:			equ	$24
    461 __sqr:			equ	$25
    462 __sgn:			equ	$26
    463 __abs:			equ	$27
    464 __peek:			equ	$28
    465 __usr_num:		equ	$29
    466 __str_dollar:		equ	$2A
    467 __chr_dollar:		equ	$2B
    468 __not:			equ	$2C
    469 __duplicate:		equ	$2D
    470 __n_mod_m:		equ	$2E
    471 __jump:			equ	$2F
    472 __stk_data:		equ	$30
    473 __dec_jr_nz:		equ	$31
    474 __less_0:		equ	$32
    475 __greater_0:		equ	$33
    476 __end_calc:		equ	$34
    477 __get_argt:		equ	$35
    478 __truncate:		equ	$36
    479 __fp_calc_2:		equ	$37
    480 __e_to_fp:		equ	$38
    481 
    482 ;
    483 ; __series_xx:			equ	$39 : $80__$9F.
    484 ; tells the stack machine to push 
    485 ; 0 to 31 floating-point values on the stack.
    486 ;
    487 __series_06:		equ	$86
    488 __series_08:		equ	$88
    489 __series_0C:		equ	$8C
    490 ;	__stk_const_xx:			equ	$3A : $A0__$BF.
    491 ;	__st_mem_xx:			equ	$3B : $C0__$DF.
    492 ;	__get_mem_xx:			equ	$3C : $E0__$FF.
    493 
    494 __st_mem_0:			equ	$C0
    495 __st_mem_1:			equ	$C1
    496 __st_mem_2:			equ	$C2
    497 __st_mem_3:			equ	$C3
    498 __st_mem_4:			equ	$C4
    499 __st_mem_5:			equ	$C5
    500 __st_mem_6:			equ	$C6
    501 __st_mem_7:			equ	$C7
    502 
    503 
    504 __get_mem_0:			equ	$E0
    505 __get_mem_1:			equ	$E1
    506 __get_mem_2:			equ	$E2
    507 __get_mem_3:			equ	$E3
    508 __get_mem_4:			equ	$E4
    509 
    510 
    511 __stk_zero:			equ	$A0
    512 __stk_one:			equ	$A1
    513 __stk_half:			equ	$A2
    514 __stk_half_pi:			equ	$A3
    515 __stk_ten:			equ	$A4
    516 
    517 ;*****************************************
    518 ;** Part 1. RESTART ROUTINES AND TABLES **
    519 ;*****************************************
    520 
    521 
    522 ; THE 'START'
    523 
    524 ; All Z80 chips start at location zero.
    525 ; At start-up the Interrupt Mode is 0, ZX computers use Interrupt Mode 1.
    526 ; Interrupts are disabled .
    527 
    528 mark_0000:
    529 START:
    530 	OUT	(IO_PORT_NMI_GEN_OFF),A	; Turn off the NMI generator if this ROM is 
    531 				; running in ZX81 hardware. This does nothing 
    532 				; if this ROM is running within an upgraded
    533 				; ZX80.
    534 	LD	BC,MAX_RAM	; Set BC to the top of possible RAM.
    535 				; The higher unpopulated addresses are used for
    536 				; video generation.
    537 	JP	RAM_CHECK	; Jump forward to RAM_CHECK.
    538 
    539 
    540 ; THE 'ERROR' RESTART
    541 
    542 ; The error restart deals immediately with an error.
    543 ; ZX computers execute the same code in runtime as when checking syntax.
    544 ; If the error occurred while running a program
    545 ; then a brief report is produced.
    546 ; If the error occurred while entering a BASIC line or in input etc., 
    547 ; then the error marker indicates the exact point at which the error lies.
    548 
    549 mark_0008:
    550 ERROR_1:
    551 	LD	HL,(CH_ADD)	; fetch character address from CH_ADD.
    552 	LD	(X_PTR),HL	; and set the error pointer X_PTR.
    553 	JR	ERROR_2		; forward to continue at ERROR_2.
    554 
    555 
    556 ; THE 'PRINT A CHARACTER' RESTART
    557 
    558 ; This restart prints the character in the accumulator using the alternate
    559 ; register set so there is no requirement to save the main registers.
    560 ; There is sufficient room available to separate a space (zero) from other
    561 ; characters as leading spaces need not be considered with a space.
    562 
    563 mark_0010:
    564 PRINT_A:
    565 	AND	A		; test for zero - space.
    566 	JP	NZ,PRINT_CH	; jump forward if not to PRINT_CH.
    567 
    568 	JP	PRINT_SP	; jump forward to PRINT_SP.
    569 
    570 ; ___
    571 if ORIGINAL
    572 	DEFB	$FF		; unused location.
    573 else
    574 	DEFB	$01		;+ unused location. Version. PRINT PEEK 23
    575 endif
    576 
    577 
    578 ; THE 'COLLECT A CHARACTER' RESTART
    579 
    580 ; The character addressed by the system variable CH_ADD is fetched and if it
    581 ; is a non-space, non-cursor character it is returned else CH_ADD is 
    582 ; incremented and the new addressed character tested until it is not a space.
    583 
    584 mark_0018:
    585 GET_CHAR:
    586 	LD	HL,(CH_ADD)	; set HL to character address CH_ADD.
    587 	LD	A,(HL)		; fetch addressed character to A.
    588 
    589 TEST_SP:
    590 	AND	A		; test for space.
    591 	RET	NZ		; return if not a space
    592 
    593 	NOP			; else trickle through
    594 	NOP			; to the next routine.
    595 
    596 
    597 ; THE 'COLLECT NEXT CHARACTER' RESTART
    598 
    599 ; The character address is incremented and the new addressed character is 
    600 ; returned if not a space, or cursor, else the process is repeated.
    601 
    602 mark_0020:
    603 NEXT_CHAR:
    604 	CALL	CH_ADD_PLUS_1	; gets next immediate
    605 				; character.
    606 	JR	TEST_SP		; back
    607 ; ___
    608 
    609 	DEFB	$FF, $FF, $FF	; unused locations.
    610 
    611 
    612 ; THE 'FLOATING POINT CALCULATOR' RESTART
    613 
    614 ; this restart jumps to the recursive floating-point calculator.
    615 ; the ZX81's internal, FORTH-like, stack-based language.
    616 ;
    617 ; In the five remaining bytes there is, appropriately, enough room for the
    618 ; end-calc literal - the instruction which exits the calculator.
    619 
    620 mark_0028:
    621 FP_CALC:
    622 if ORIGINAL
    623 	JP	CALCULATE	; jump immediately to the CALCULATE routine.
    624 else
    625 
    626 	JP	CALCULATE	;+ jump to the NEW calculate routine address.
    627 endif
    628 
    629 mark_002B:
    630 end_calc:
    631 	POP	AF		; drop the calculator return address RE_ENTRY
    632 	EXX			; switch to the other set.
    633 
    634 	EX	(SP),HL		; transfer H'L' to machine stack for the
    635 				; return address.
    636 				; when exiting recursion then the previous
    637 				; pointer is transferred to H'L'.
    638 
    639 	EXX			; back to main set.
    640 	RET			; return.
    641 
    642 
    643 
    644 ; THE 'MAKE BC SPACES' RESTART
    645 
    646 ; This restart is used eight times to create, in workspace, the number of
    647 ; spaces passed in the BC register.
    648 
    649 mark_0030:
    650 BC_SPACES:
    651 	PUSH	BC		; push number of spaces on stack.
    652 	LD	HL,(E_LINE)	; fetch edit line location from E_LINE.
    653 	PUSH	HL		; save this value on stack.
    654 	JP	RESERVE		; jump forward to continue at RESERVE.
    655 
    656 
    657 
    658 _START:		equ	$00
    659 _ERROR_1:	equ	$08
    660 _PRINT_A:	equ	$10
    661 _GET_CHAR:	equ	$18
    662 _NEXT_CHAR:	equ	$20
    663 _FP_CALC:	equ	$28
    664 _BC_SPACES:	equ	$30
    665 
    666 ; THE 'INTERRUPT' RESTART
    667 
    668 ;	The Mode 1 Interrupt routine is concerned solely with generating the central
    669 ;	television picture.
    670 ;	On the ZX81 interrupts are enabled only during the interrupt routine, 
    671 ;	although the interrupt 
    672 ;
    673 ;	This Interrupt Service Routine automatically disables interrupts at the 
    674 ;	outset and the last interrupt in a cascade exits before the interrupts are
    675 ;	enabled.
    676 ;
    677 ;	There is no DI instruction in the ZX81 ROM.
    678 ;
    679 ;	A maskable interrupt is triggered when bit 6 of the Z80's Refresh register
    680 ;	changes from set to reset.
    681 ;
    682 ;	The Z80 will always be executing a HALT (NEWLINE) when the interrupt occurs.
    683 ;	A HALT instruction repeatedly executes NOPS but the seven lower bits
    684 ;	of the Refresh register are incremented each time as they are when any 
    685 ;	simple instruction is executed. (The lower 7 bits are incremented twice for
    686 ;	a prefixed instruction)
    687 ;
    688 ;	This is controlled by the Sinclair Computer Logic Chip - manufactured from 
    689 ;	a Ferranti Uncommitted Logic Array.
    690 ;
    691 ;	When a Mode 1 Interrupt occurs the Program Counter, which is the address in
    692 ;	the upper echo display following the NEWLINE/HALT instruction, goes on the 
    693 ;	machine stack.	193 interrupts are required to generate the last part of
    694 ;	the 56th border line and then the 192 lines of the central TV picture and, 
    695 ;	although each interrupt interrupts the previous one, there are no stack 
    696 ;	problems as the 'return address' is discarded each time.
    697 ;
    698 ;	The scan line counter in C counts down from 8 to 1 within the generation of
    699 ;	each text line. For the first interrupt in a cascade the initial value of 
    700 ;	C is set to 1 for the last border line.
    701 ;	Timing is of the utmost importance as the RH border, horizontal retrace
    702 ;	and LH border are mostly generated in the 58 clock cycles this routine 
    703 ;	takes .
    704 
    705 
    706 
    707 MARK_0038:
    708 INTERRUPT:
    709 	DEC	C		; (4)	decrement C - the scan line counter.
    710 	JP	NZ,SCAN_LINE	; (10/10) JUMP forward if not zero to SCAN_LINE
    711 
    712 	POP	HL		; (10) point to start of next row in display 
    713 				;	file.
    714 
    715 	DEC	B		; (4)	decrement the row counter. (4)
    716 	RET	Z		; (11/5) return when picture complete to R_IX_1_LAST_NEWLINE
    717 				;	with interrupts disabled.
    718 
    719 	SET	3,C		; (8)	Load the scan line counter with eight.
    720 				;	Note. LD C,$08 is 7 clock cycles which 
    721 				;	is way too fast.
    722 
    723 ; ->
    724 
    725 mark_0041:
    726 WAIT_INT:
    727 ;
    728 ; NB $DD is for 32-column display
    729 ;
    730 	LD	R,A		; (9) Load R with initial rising value $DD.
    731 
    732 	EI			; (4) Enable Interrupts.	[ R is now $DE ].
    733 
    734 	JP	(HL)		; (4) jump to the echo display file in upper
    735 				;	memory and execute characters $00 - $3F 
    736 				;	as NOP instructions.	The video hardware 
    737 				;	is able to read these characters and, 
    738 				;	with the I register is able to convert 
    739 				;	the character bitmaps in this ROM into a 
    740 				;	line of bytes. Eventually the NEWLINE/HALT
    741 				;	will be encountered before R reaches $FF. 
    742 				;	It is however the transition from $FF to 
    743 				;	$80 that triggers the next interrupt.
    744 				;	[ The Refresh register is now $DF ]
    745 
    746 ; ___
    747 
    748 mark_0045:
    749 SCAN_LINE:
    750 	POP	DE		; (10) discard the address after NEWLINE as the 
    751 				;	same text line has to be done again
    752 				;	eight times. 
    753 
    754 	RET	Z		; (5)	Harmless Nonsensical Timing.
    755 				;	(condition never met)
    756 
    757 	JR	WAIT_INT	; (12) back to WAIT_INT
    758 
    759 ;	Note. that a computer with less than 4K or RAM will have a collapsed
    760 ;	display file and the above mechanism deals with both types of display.
    761 ;
    762 ;	With a full display, the 32 characters in the line are treated as NOPS
    763 ;	and the Refresh register rises from $E0 to $FF and, at the next instruction 
    764 ;	- HALT, the interrupt occurs.
    765 ;	With a collapsed display and an initial NEWLINE/HALT, it is the NOPs 
    766 ;	generated by the HALT that cause the Refresh value to rise from $E0 to $FF,
    767 ;	triggering an Interrupt on the next transition.
    768 ;	This works happily for all display lines between these extremes and the 
    769 ;	generation of the 32 character, 1 pixel high, line will always take 128 
    770 ;	clock cycles.
    771 
    772 
    773 ; THE 'INCREMENT CH_ADD' SUBROUTINE
    774 
    775 ; This is the subroutine that increments the character address system variable
    776 ; and returns if it is not the cursor character. The ZX81 has an actual 
    777 ; character at the cursor position rather than a pointer system variable
    778 ; as is the case with prior and subsequent ZX computers.
    779 
    780 mark_0049:
    781 CH_ADD_PLUS_1:
    782 	LD	HL,(CH_ADD)	; fetch character address to CH_ADD.
    783 
    784 mark_004C:
    785 TEMP_PTR1:
    786 	INC	HL		; address next immediate location.
    787 
    788 mark_004D:
    789 TEMP_PTR2:
    790 	LD	(CH_ADD),HL	; update system variable CH_ADD.
    791 
    792 	LD	A,(HL)		; fetch the character.
    793 	CP	ZX_CURSOR	; compare to cursor character.
    794 	RET	NZ		; return if not the cursor.
    795 
    796 	JR	TEMP_PTR1	; back for next character to TEMP_PTR1.
    797 
    798 
    799 ; THE 'ERROR_2' BRANCH
    800 
    801 ; This is a continuation of the error restart.
    802 ; If the error occurred in runtime then the error stack pointer will probably
    803 ; lead to an error report being printed unless it occurred during input.
    804 ; If the error occurred when checking syntax then the error stack pointer
    805 ; will be an editing routine and the position of the error will be shown
    806 ; when the lower screen is reprinted.
    807 
    808 mark_0056:
    809 ERROR_2:
    810 	POP	HL		; pop the return address which points to the
    811 				; DEFB, error code, after the RST 08.
    812 	LD	L,(HL)		; load L with the error code. HL is not needed
    813 				; anymore.
    814 
    815 mark_0058:
    816 ERROR_3:
    817 	LD	(IY+ERR_NR-RAMBASE),L	; place error code in system variable ERR_NR
    818 	LD	SP,(ERR_SP)	; set the stack pointer from ERR_SP
    819 	CALL	SLOW_FAST	; selects slow mode.
    820 	JP	SET_MIN		; exit to address on stack via routine SET_MIN.
    821 
    822 ; ___
    823 
    824 	DEFB	$FF		; unused.
    825 
    826 
    827 ; THE 'NON MASKABLE INTERRUPT' ROUTINE
    828 
    829 ;	Jim Westwood's technical dodge using Non-Maskable Interrupts solved the
    830 ;	flicker problem of the ZX80 and gave the ZX81 a multi-tasking SLOW mode 
    831 ;	with a steady display.	Note that the AF' register is reserved for this 
    832 ;	function and its interaction with the display routines.	When counting 
    833 ;	TV lines, the NMI makes no use of the main registers.
    834 ;	The circuitry for the NMI generator is contained within the SCL (Sinclair 
    835 ;	Computer Logic) chip. 
    836 ;	( It takes 32 clock cycles while incrementing towards zero ). 
    837 
    838 mark_0066:
    839 NMI:
    840 	EX	AF,AF'		; (4) switch in the NMI's copy of the 
    841 				;	accumulator.
    842 	INC	A		; (4) increment.
    843 	JP	M,NMI_RET	; (10/10) jump, if minus, to NMI_RET as this is
    844 				;	part of a test to see if the NMI 
    845 				;	generation is working or an intermediate 
    846 				;	value for the ascending negated blank 
    847 				;	line counter.
    848 
    849 	JR	Z,NMI_CONT	; (12) forward to NMI_CONT
    850 				;	when line count has incremented to zero.
    851 
    852 ; Note. the synchronizing NMI when A increments from zero to one takes this
    853 ; 7 clock cycle route making 39 clock cycles in all.
    854 
    855 mark_006D:
    856 NMI_RET:
    857 	EX	AF,AF'		; (4)	switch out the incremented line counter
    858 				;	or test result $80
    859 	RET			; (10) return to User application for a while.
    860 
    861 ; ___
    862 
    863 ;	This branch is taken when the 55 (or 31) lines have been drawn.
    864 
    865 mark_006F:
    866 NMI_CONT:
    867 	EX	AF,AF'		; (4) restore the main accumulator.
    868 
    869 	PUSH	AF		; (11) *		Save Main Registers
    870 	PUSH	BC		; (11) **
    871 	PUSH	DE		; (11) ***
    872 	PUSH	HL		; (11) ****
    873 
    874 ;	the next set-up procedure is only really applicable when the top set of 
    875 ;	blank lines have been generated.
    876 
    877 	LD	HL,(D_FILE)	; (16) fetch start of Display File from D_FILE
    878 				;      points to the HALT at beginning.
    879 	SET	7,H		; (8)  point to upper 32K 'echo display file'
    880 
    881 	HALT			; (1)  HALT synchronizes with NMI.
    882 				;      Used with special hardware connected to the
    883 				;      Z80 HALT and WAIT lines to take 1 clock cycle.
    884 
    885 
    886 ;	the NMI has been generated - start counting.
    887 ;	The cathode ray is at the RH side of the TV.
    888 ;
    889 ;	First the NMI servicing, similar to CALL		=	17 clock cycles.
    890 ;	Then the time taken by the NMI for zero-to-one path	=	39 cycles
    891 ;	The HALT above						=	01 cycles.
    892 ;	The two instructions below				=	19 cycles.
    893 ;	The code at R_IX_1 up to and including the CALL		=	43 cycles.
    894 ;	The Called routine at DISPLAY_5				=	24 cycles.
    895 ;	--------------------------------------				---
    896 ;	Total Z80 instructions					=	143 cycles.
    897 ;
    898 ;	Meanwhile in TV world,
    899 ;	Horizontal retrace					=	15 cycles.
    900 ;	Left blanking border 8 character positions		=	32 cycles
    901 ;	Generation of 75% scanline from the first NEWLINE	=	96 cycles
    902 ;	---------------------------------------				---
    903 ;								=	143 cycles
    904 ;
    905 ;	Since at the time the first JP (HL) is encountered to execute the echo
    906 ;	display another 8 character positions have to be put out, then the
    907 ;	Refresh register need to hold $F8. Working back and counteracting 
    908 ;	the fact that every instruction increments the Refresh register then
    909 ;	the value that is loaded into R needs to be $F5.	:-)
    910 ;
    911 ;
    912 	OUT	(IO_PORT_NMI_GEN_OFF),A		; (11) Stop the NMI generator.
    913 
    914 	JP	(IX)				; (8) forward to R_IX_1 (after top) or R_IX_2
    915 
    916 ; ****************
    917 ; ** KEY TABLES **
    918 ; ****************
    919 
    920 
    921 ; THE 'UNSHIFTED' CHARACTER CODES
    922 
    923 
    924 mark_007E:
    925 K_UNSHIFT:
    926 	DEFB	ZX_Z
    927 	DEFB	ZX_X
    928 	DEFB	ZX_C
    929 	DEFB	ZX_V
    930 
    931 	DEFB	ZX_A
    932 	DEFB	ZX_S
    933 	DEFB	ZX_D
    934 	DEFB	ZX_F
    935 	DEFB	ZX_G
    936 
    937 	DEFB	ZX_Q
    938 	DEFB	ZX_W
    939 	DEFB	ZX_E
    940 	DEFB	ZX_R
    941 	DEFB	ZX_T
    942 
    943 	DEFB	ZX_1
    944 	DEFB	ZX_2
    945 	DEFB	ZX_3
    946 	DEFB	ZX_4
    947 	DEFB	ZX_5
    948 
    949 	DEFB	ZX_0
    950 	DEFB	ZX_9
    951 	DEFB	ZX_8
    952 	DEFB	ZX_7
    953 	DEFB	ZX_6
    954 
    955 	DEFB	ZX_P
    956 	DEFB	ZX_O
    957 	DEFB	ZX_I
    958 	DEFB	ZX_U
    959 	DEFB	ZX_Y
    960 
    961 	DEFB	ZX_NEWLINE
    962 	DEFB	ZX_L
    963 	DEFB	ZX_K
    964 	DEFB	ZX_J
    965 	DEFB	ZX_H
    966 
    967 	DEFB	ZX_SPACE
    968 	DEFB	ZX_PERIOD
    969 	DEFB	ZX_M
    970 	DEFB	ZX_N
    971 	DEFB	ZX_B
    972 
    973 
    974 
    975 ; THE 'SHIFTED' CHARACTER CODES
    976 
    977 
    978 
    979 mark_00A5:
    980 K_SHIFT:
    981 	DEFB	ZX_COLON	; :
    982 	DEFB	ZX_SEMICOLON	; ;
    983 	DEFB	ZX_QUERY	; ?
    984 	DEFB	ZX_SLASH	; /
    985 	DEFB	ZX_STOP
    986 	DEFB	ZX_LPRINT
    987 	DEFB	ZX_SLOW
    988 	DEFB	ZX_FAST
    989 	DEFB	ZX_LLIST
    990 	DEFB	$C0		; ""
    991 	DEFB	ZX_OR
    992 	DEFB	ZX_STEP
    993 	DEFB	$DB		; <=
    994 	DEFB	$DD		; <>
    995 	DEFB	ZX_EDIT
    996 	DEFB	ZX_AND
    997 	DEFB	ZX_THEN
    998 	DEFB	ZX_TO
    999 	DEFB	$72		; cursor-left
   1000 	DEFB	ZX_RUBOUT
   1001 	DEFB	ZX_GRAPHICS
   1002 	DEFB	$73		; cursor-right
   1003 	DEFB	$70		; cursor-up
   1004 	DEFB	$71		; cursor-down
   1005 	DEFB	ZX_QUOTE	; "
   1006 	DEFB	$11		; )
   1007 	DEFB	$10		; (
   1008 	DEFB	ZX_DOLLAR	; $
   1009 	DEFB	$DC		; >=
   1010 	DEFB	ZX_FUNCTION
   1011 	DEFB	ZX_EQUAL
   1012 	DEFB	ZX_PLUS
   1013 	DEFB	ZX_MINUS
   1014 	DEFB	ZX_POWER	; **
   1015 	DEFB	ZX_POUND	; � 
   1016 	DEFB	ZX_COMMA	; ,
   1017 	DEFB	ZX_GREATER_THAN	; >
   1018 	DEFB	ZX_LESS_THAN	; <
   1019 	DEFB	ZX_STAR		; *
   1020 
   1021 
   1022 ; THE 'FUNCTION' CHARACTER CODES
   1023 
   1024 
   1025 
   1026 mark_00CC:
   1027 K_FUNCT:
   1028 	DEFB	ZX_LN
   1029 	DEFB	ZX_EXP
   1030 	DEFB	ZX_AT
   1031 	DEFB	ZX_KL
   1032 	DEFB	ZX_ASN
   1033 	DEFB	ZX_ACS
   1034 	DEFB	ZX_ATN
   1035 	DEFB	ZX_SGN
   1036 	DEFB	ZX_ABS
   1037 	DEFB	ZX_SIN
   1038 	DEFB	ZX_COS
   1039 	DEFB	ZX_TAN
   1040 	DEFB	ZX_INT
   1041 	DEFB	ZX_RND
   1042 	DEFB	ZX_KL
   1043 	DEFB	ZX_KL
   1044 	DEFB	ZX_KL
   1045 	DEFB	ZX_KL
   1046 	DEFB	ZX_KL
   1047 	DEFB	ZX_KL
   1048 	DEFB	ZX_KL
   1049 	DEFB	ZX_KL
   1050 	DEFB	ZX_KL
   1051 	DEFB	ZX_KL
   1052 	DEFB	ZX_TAB
   1053 	DEFB	ZX_PEEK
   1054 	DEFB	ZX_CODE
   1055 	DEFB	ZX_CHR_STR	;	CHR$
   1056 	DEFB	ZX_STR_STR	;	STR$
   1057 	DEFB	ZX_KL
   1058 	DEFB	ZX_USR
   1059 	DEFB	ZX_LEN
   1060 	DEFB	ZX_VAL
   1061 	DEFB	ZX_SQR
   1062 	DEFB	ZX_KL
   1063 	DEFB	ZX_KL
   1064 	DEFB	ZX_PI
   1065 	DEFB	ZX_NOT
   1066 	DEFB	ZX_INKEY_STR
   1067 
   1068 
   1069 
   1070 ; THE 'GRAPHIC' CHARACTER CODES
   1071 
   1072 
   1073 
   1074 mark_00F3:
   1075 K_GRAPH:
   1076 	DEFB	$08		; graphic
   1077 	DEFB	$0A		; graphic
   1078 	DEFB	$09		; graphic
   1079 	DEFB	$8A		; graphic
   1080 	DEFB	$89		; graphic
   1081 
   1082 	DEFB	$81		; graphic
   1083 	DEFB	$82		; graphic
   1084 	DEFB	$07		; graphic
   1085 	DEFB	$84		; graphic
   1086 	DEFB	$06		; graphic
   1087 
   1088 	DEFB	$01		; graphic
   1089 	DEFB	$02		; graphic
   1090 	DEFB	$87		; graphic
   1091 	DEFB	$04		; graphic
   1092 	DEFB	$05		; graphic
   1093 
   1094 	DEFB	ZX_RUBOUT
   1095 	DEFB	ZX_KL
   1096 	DEFB	$85		; graphic
   1097 	DEFB	$03		; graphic
   1098 	DEFB	$83		; graphic
   1099 
   1100 	DEFB	$8B		; graphic
   1101 	DEFB	$91		; inverse )
   1102 	DEFB	$90		; inverse (
   1103 	DEFB	$8D		; inverse $
   1104 	DEFB	$86		; graphic
   1105 
   1106 	DEFB	ZX_KL
   1107 	DEFB	$92		; inverse >
   1108 	DEFB	$95		; inverse +
   1109 	DEFB	$96		; inverse -
   1110 	DEFB	$88		; graphic
   1111 
   1112 
   1113 ; THE 'TOKEN' TABLES
   1114 
   1115 
   1116 
   1117 mark_0111:
   1118 TOKEN_TABLE:
   1119 	DEFB	ZX_QUERY						+$80; '?'
   1120 	DEFB	ZX_QUOTE,	ZX_QUOTE				+$80; ""
   1121 	DEFB	ZX_A,	ZX_T						+$80; AT
   1122 	DEFB	ZX_T,	ZX_A,	ZX_B					+$80; TAB
   1123 	DEFB	ZX_QUERY						+$80; '?'
   1124 	DEFB	ZX_C,	ZX_O,	ZX_D,	ZX_E				+$80; CODE
   1125 	DEFB	ZX_V,	ZX_A,	ZX_L					+$80; VAL
   1126 	DEFB	ZX_L,	ZX_E,	ZX_N					+$80; LEN
   1127 	DEFB	ZX_S,	ZX_I,	ZX_N					+$80; SIN
   1128 	DEFB	ZX_C,	ZX_O,	ZX_S					+$80; COS
   1129 	DEFB	ZX_T,	ZX_A,	ZX_N					+$80; TAN
   1130 	DEFB	ZX_A,	ZX_S,	ZX_N					+$80; ASN
   1131 	DEFB	ZX_A,	ZX_C,	ZX_S					+$80; ACS
   1132 	DEFB	ZX_A,	ZX_T,	ZX_N					+$80; ATN
   1133 	DEFB	ZX_L,	ZX_N						+$80; LN
   1134 	DEFB	ZX_E,	ZX_X,	ZX_P					+$80; EXP
   1135 	DEFB	ZX_I,	ZX_N,	ZX_T					+$80; INT
   1136 	DEFB	ZX_S,	ZX_Q,	ZX_R					+$80; SQR
   1137 	DEFB	ZX_S,	ZX_G,	ZX_N					+$80; SGN
   1138 	DEFB	ZX_A,	ZX_B,	ZX_S					+$80; ABS
   1139 	DEFB	ZX_P,	ZX_E,	ZX_E,	ZX_K				+$80; PEEK
   1140 	DEFB	ZX_U,	ZX_S,	ZX_R					+$80; USR
   1141 	DEFB	ZX_S,	ZX_T,	ZX_R,	ZX_DOLLAR			+$80; STR$
   1142 	DEFB	ZX_C,	ZX_H,	ZX_R,	ZX_DOLLAR			+$80; CHR$
   1143 	DEFB	ZX_N,	ZX_O,	ZX_T					+$80; NOT
   1144 	DEFB	ZX_STAR,	ZX_STAR					+$80; **
   1145 	DEFB	ZX_O,	ZX_R						+$80; OR
   1146 	DEFB	ZX_A,	ZX_N,	ZX_D					+$80; AND
   1147 	DEFB	ZX_LESS_THAN,		ZX_EQUAL			+$80; >=
   1148 	DEFB	ZX_GREATER_THAN,	ZX_EQUAL			+$80; <=
   1149 	DEFB	ZX_LESS_THAN,		ZX_GREATER_THAN			+$80; ><
   1150 	DEFB	ZX_T,	ZX_H,	ZX_E,	ZX_N				+$80; THEN
   1151 	DEFB	ZX_T,	ZX_O						+$80; TO
   1152 	DEFB	ZX_S,	ZX_T,	ZX_E,	ZX_P				+$80; STEP
   1153 	DEFB	ZX_L,	ZX_P,	ZX_R,	ZX_I,	ZX_N,	ZX_T		+$80; LPRINT
   1154 	DEFB	ZX_L,	ZX_L,	ZX_I,	ZX_S,	ZX_T			+$80; LLIST
   1155 	DEFB	ZX_S,	ZX_T,	ZX_O,	ZX_P				+$80; STOP
   1156 	DEFB	ZX_S,	ZX_L,	ZX_O,	ZX_W				+$80; SLOW
   1157 	DEFB	ZX_F,	ZX_A,	ZX_S,	ZX_T				+$80; FAST
   1158 	DEFB	ZX_N,	ZX_E,	ZX_W					+$80; NEW
   1159 	DEFB	ZX_S,	ZX_C,	ZX_R,	ZX_O,	ZX_L,	ZX_L		+$80; SCROLL
   1160 	DEFB	ZX_C,	ZX_O,	ZX_N,	ZX_T				+$80; CONT
   1161 	DEFB	ZX_D,	ZX_I,	ZX_M					+$80; DIM
   1162 	DEFB	ZX_R,	ZX_E,	ZX_M					+$80; REM
   1163 	DEFB	ZX_F,	ZX_O,	ZX_R					+$80; FOR
   1164 	DEFB	ZX_G,	ZX_O,	ZX_T,	ZX_O				+$80; GOTO
   1165 	DEFB	ZX_G,	ZX_O,	ZX_S,	ZX_U,	ZX_B			+$80; GOSUB
   1166 	DEFB	ZX_I,	ZX_N,	ZX_P,	ZX_U,	ZX_T			+$80; INPUT
   1167 	DEFB	ZX_L,	ZX_O,	ZX_A,	ZX_D				+$80; LOAD
   1168 	DEFB	ZX_L,	ZX_I,	ZX_S,	ZX_T				+$80; LIST
   1169 	DEFB	ZX_L,	ZX_E,	ZX_T					+$80; LET
   1170 	DEFB	ZX_P,	ZX_A,	ZX_U,	ZX_S,	ZX_E			+$80; PAUSE
   1171 	DEFB	ZX_N,	ZX_E,	ZX_X,	ZX_T				+$80; NEXT
   1172 	DEFB	ZX_P,	ZX_O,	ZX_K,	ZX_E				+$80; POKE
   1173 	DEFB	ZX_P,	ZX_R,	ZX_I,	ZX_N,	ZX_T			+$80; PRINT
   1174 	DEFB	ZX_P,	ZX_L,	ZX_O,	ZX_T				+$80; PLOT
   1175 	DEFB	ZX_R,	ZX_U,	ZX_N					+$80; RUN
   1176 	DEFB	ZX_S,	ZX_A,	ZX_V,	ZX_E				+$80; SAVE
   1177 	DEFB	ZX_R,	ZX_A,	ZX_N,	ZX_D				+$80; RAND
   1178 	DEFB	ZX_I,	ZX_F						+$80; IF
   1179 	DEFB	ZX_C,	ZX_L,	ZX_S					+$80; CLS
   1180 	DEFB	ZX_U,	ZX_N,	ZX_P,	ZX_L,	ZX_O,	ZX_T		+$80; UNPLOT
   1181 	DEFB	ZX_C,	ZX_L,	ZX_E,	ZX_A,	ZX_R			+$80; CLEAR
   1182 	DEFB	ZX_R,	ZX_E,	ZX_T,	ZX_U,	ZX_R,	ZX_N		+$80; RETURN
   1183 	DEFB	ZX_C,	ZX_O,	ZX_P,	ZX_Y				+$80; COPY
   1184 	DEFB	ZX_R,	ZX_N,	ZX_D					+$80; RND
   1185 	DEFB	ZX_I,	ZX_N,	ZX_K,	ZX_E,	ZX_Y,	ZX_DOLLAR	+$80; INKEY$
   1186 	DEFB	ZX_P,	ZX_I						+$80; PI
   1187 
   1188 
   1189 ; THE 'LOAD_SAVE UPDATE' ROUTINE
   1190 
   1191 ;
   1192 ;
   1193 
   1194 mark_01FC:
   1195 LOAD_SAVE:
   1196 	INC	HL		;
   1197 	EX	DE,HL		;
   1198 	LD	HL,(E_LINE)	; system variable edit line E_LINE.
   1199 	SCF			; set carry flag
   1200 	SBC	HL,DE		;
   1201 	EX	DE,HL		;
   1202 	RET	NC		; return if more bytes to LOAD_SAVE.
   1203 
   1204 	POP	HL		; else drop return address
   1205 
   1206 
   1207 ; THE 'DISPLAY' ROUTINES
   1208 
   1209 ;
   1210 ;
   1211 
   1212 mark_0207:
   1213 SLOW_FAST:
   1214 	LD	HL,CDFLAG	; Address the system variable CDFLAG.
   1215 	LD	A,(HL)		; Load value to the accumulator.
   1216 	RLA			; rotate bit 6 to position 7.
   1217 	XOR	(HL)		; exclusive or with original bit 7.
   1218 	RLA			; rotate result out to carry.
   1219 	RET	NC		; return if both bits were the same.
   1220 
   1221 ;	Now test if this really is a ZX81 or a ZX80 running the upgraded ROM.
   1222 ;	The standard ZX80 did not have an NMI generator.
   1223 
   1224 	LD	A,$7F		; Load accumulator with %011111111
   1225 	EX	AF,AF'		; save in AF'
   1226 
   1227 	LD	B,17		; A counter within which an NMI should occur
   1228 				; if this is a ZX81.
   1229 	OUT	(IO_PORT_NMI_GEN_ON),A	; start the NMI generator.
   1230 
   1231 ;	Note that if this is a ZX81 then the NMI will increment AF'.
   1232 
   1233 mark_0216:
   1234 LOOP_11:
   1235 
   1236 	DJNZ	LOOP_11		; self loop to give the NMI a chance to kick in.
   1237 				; = 16*13 clock cycles + 8 = 216 clock cycles.
   1238 
   1239 	OUT	(IO_PORT_NMI_GEN_OFF),A	; Turn off the NMI generator.
   1240 	EX	AF,AF'		; bring back the AF' value.
   1241 	RLA			; test bit 7.
   1242 	JR	NC,NO_SLOW	; forward, if bit 7 is still reset, to NO_SLOW.
   1243 
   1244 ;	If the AF' was incremented then the NMI generator works and SLOW mode can
   1245 ;	be set.
   1246 
   1247 	SET	7,(HL)		; Indicate SLOW mode - Compute and Display.
   1248 
   1249 	PUSH	AF		; *		Save Main Registers
   1250 	PUSH	BC		; **
   1251 	PUSH	DE		; ***
   1252 	PUSH	HL		; ****
   1253 
   1254 	JR	DISPLAY_1	; skip forward - to DISPLAY_1.
   1255 
   1256 ; ___
   1257 
   1258 mark_0226:
   1259 NO_SLOW:
   1260 	RES	6,(HL)		; reset bit 6 of CDFLAG.
   1261 	RET			; return.
   1262 
   1263 
   1264 ; THE 'MAIN DISPLAY' LOOP
   1265 
   1266 ; This routine is executed once for every frame displayed.
   1267 
   1268 mark_0229:
   1269 DISPLAY_1:
   1270 
   1271 	LD	HL,(FRAMES)	; fetch two-byte system variable FRAMES.
   1272 	DEC	HL		; decrement frames counter.
   1273 mark_022D:
   1274 DISPLAY_P:
   1275 	LD	A,$7F		; prepare a mask
   1276 	AND	H		; pick up bits 6-0 of H.
   1277 	OR	L		; and any bits of L.
   1278 	LD	A,H		; reload A with all bits of H for PAUSE test.
   1279 
   1280 ;	Note both branches must take the same time.
   1281 
   1282 	JR	NZ,ANOTHER	; (12/7) forward if bits 14-0 are not zero 
   1283 				; to ANOTHER
   1284 
   1285 	RLA			; (4) test bit 15 of FRAMES.
   1286 	JR	OVER_NC		; (12) forward with result to OVER_NC
   1287 
   1288 ; ___
   1289 
   1290 mark_0237:
   1291 ANOTHER:
   1292 	LD	B,(HL)		; (7) Note. Harmless Nonsensical Timing weight.
   1293 	SCF			; (4) Set Carry Flag.
   1294 
   1295 ; Note. the branch to here takes either (12)(7)(4) cyles or (7)(4)(12) cycles.
   1296 
   1297 mark_0239:
   1298 OVER_NC:
   1299 	LD	H,A		; (4)	set H to zero
   1300 	LD	(FRAMES),HL	; (16) update system variable FRAMES 
   1301 	RET	NC		; (11/5) return if FRAMES is in use by PAUSE 
   1302 				; command.
   1303 
   1304 mark_023E:
   1305 DISPLAY_2:
   1306 	CALL	KEYBOARD	; gets the key row in H and the column in L. 
   1307 				; Reading the ports also starts
   1308 				; the TV frame synchronization pulse. (VSYNC)
   1309 
   1310 	LD	BC,(LAST_K)	; fetch the last key values
   1311 	LD	(LAST_K),HL	; update LAST_K with new values.
   1312 
   1313 	LD	A,B		; load A with previous column - will be $FF if
   1314 				; there was no key.
   1315 	ADD	A,2		; adding two will set carry if no previous key.
   1316 
   1317 	SBC	HL,BC		; subtract with the carry the two key values.
   1318 
   1319 ; If the same key value has been returned twice then HL will be zero.
   1320 
   1321 	LD	A,(DEBOUNCE_VAR)
   1322 	OR	H		; and OR with both bytes of the difference
   1323 	OR	L		; setting the zero flag for the upcoming branch.
   1324 
   1325 	LD	E,B		; transfer the column value to E
   1326 	LD	B,11		; and load B with eleven 
   1327 
   1328 	LD	HL,CDFLAG	; address system variable CDFLAG
   1329 	RES	0,(HL)		; reset the rightmost bit of CDFLAG
   1330 	JR	NZ,NO_KEY	; skip forward if debounce/diff >0 to NO_KEY
   1331 
   1332 	BIT	7,(HL)		; test compute and display bit of CDFLAG
   1333 	SET	0,(HL)		; set the rightmost bit of CDFLAG.
   1334 	RET	Z		; return if bit 7 indicated fast mode.
   1335 
   1336 	DEC	B		; (4) decrement the counter.
   1337 	NOP			; (4) Timing - 4 clock cycles. ??
   1338 	SCF			; (4) Set Carry Flag
   1339 
   1340 mark_0264:
   1341 NO_KEY:
   1342 
   1343 	LD	HL,DEBOUNCE_VAR	;
   1344 	CCF			; Complement Carry Flag
   1345 	RL	B		; rotate left B picking up carry
   1346 				;	C<-76543210<-C
   1347 
   1348 
   1349 
   1350 
   1351 
   1352 
   1353 mark_026A:
   1354 LOOP_B:
   1355 
   1356 	DJNZ	LOOP_B		; self-loop while B>0 to LOOP_B
   1357 
   1358 	LD	B,(HL)		; fetch value of DEBOUNCE_VAR to B
   1359 	LD	A,E		; transfer column value
   1360 	CP	$FE		;
   1361 	SBC	A,A		; A = A-A-C = 0-Carry
   1362 if 1
   1363 ; I think this truncating DEBOUNCE_VAR 
   1364 ; which would explain why the VSYNC time didn't match
   1365 ; my calculations that assumed debouncing for 255 loops.
   1366 ;
   1367 ;
   1368 	LD	B,$1F		; binary 000 11111
   1369 	OR	(HL)		;
   1370 	AND	B		; truncate column, 0 to 31
   1371 endif
   1372 	RRA			;
   1373 	LD	(HL),A		;
   1374 
   1375 	OUT	(IO_PORT_SCREEN),A	; end the TV frame synchronization pulse.
   1376 
   1377 	LD	HL,(D_FILE)	; (12) set HL to the Display File from D_FILE
   1378 	SET	7,H		; (8) set bit 15 to address the echo display.
   1379 
   1380 	CALL	DISPLAY_3	; (17) routine DISPLAY_3 displays the top set 
   1381 				; of blank lines.
   1382 
   1383 
   1384 ; THE 'VIDEO_1' ROUTINE
   1385 
   1386 
   1387 mark_0281:
   1388 R_IX_1:
   1389 	LD	A,R		; (9)	Harmless Nonsensical Timing
   1390 				;	or something very clever?
   1391 	LD	BC,25*256+1	; (10)	25 lines, 1 scanline in first. ($1901)
   1392 
   1393 ; 32 characters, use $F5 (i.e. minus 11)
   1394 ; 40 characters, use $ED (i.e. minus 19)
   1395 ;
   1396 
   1397 mark_0286:
   1398 	LD	A,277-CHARS_PER_LINE_WINDOW	; $F5 for 6.5MHz clocked machines
   1399 				; (7)	This value will be loaded into R and 
   1400 				; ensures that the cycle starts at the right 
   1401 				; part of the display	- after last character 
   1402 				; position.
   1403 
   1404 	CALL	DISPLAY_5	; (17) routine DISPLAY_5 completes the current 
   1405 				; blank line and then generates the display of 
   1406 				; the live picture using INT interrupts
   1407 				; The final interrupt returns to the next 
   1408 				; address.
   1409 R_IX_1_LAST_NEWLINE:
   1410 	DEC	HL		; point HL to the last NEWLINE/HALT.
   1411 
   1412 	CALL	DISPLAY_3	; displays the bottom set of blank lines.
   1413 
   1414 ; ___
   1415 
   1416 mark_028F:
   1417 R_IX_2:
   1418 	JP	DISPLAY_1	; JUMP back to DISPLAY_1
   1419 
   1420 
   1421 ; THE 'DISPLAY BLANK LINES' ROUTINE 
   1422 
   1423 ;	This subroutine is called twice (see above) to generate first the blank 
   1424 ;	lines at the top of the television display and then the blank lines at the
   1425 ;	bottom of the display. 
   1426 ;
   1427 ;	It is actually pretty bad.
   1428 ;	PAL or NTSC = 312 or 
   1429 ;   1 to   5 = 5 long and 5 short sync
   1430 ;   6 to  23 = blank
   1431 ;  24 to 309 = image
   1432 ; 310 to 312 = 6 short sync
   1433 ;
   1434 ; The ZX80 generates either 62 or 110 blank lines
   1435 ;
   1436 ; 262 - 31 - 31 = 200
   1437 ; 312 - 55 - 55 = 202
   1438 ;
   1439 ; This does not include 'VSYNC' line periods.
   1440 ;
   1441 
   1442 mark_0292:
   1443 DISPLAY_3:
   1444 	POP	IX		; pop the return address to IX register.
   1445 				; will be either R_IX_1 or R_IX_2 - see above.
   1446 
   1447 	LD	C,(IY+MARGIN-RAMBASE)	; load C with value of system constant MARGIN.
   1448 	BIT	7,(IY+CDFLAG-RAMBASE)	; test CDFLAG for compute and display.
   1449 	JR	Z,DISPLAY_4	; forward, with FAST mode, to DISPLAY_4
   1450 
   1451 	LD	A,C		; move MARGIN to A	- 31d or 55d.
   1452 	NEG			; Negate
   1453 	INC	A		;
   1454 	EX	AF,AF'		; place negative count of blank lines in A'
   1455 
   1456 	OUT	(IO_PORT_NMI_GEN_ON),A	; enable the NMI generator.
   1457 
   1458 	POP	HL		; ****
   1459 	POP	DE		; ***
   1460 	POP	BC		; **
   1461 	POP	AF		; *		Restore Main Registers
   1462 
   1463 	RET			; return - end of interrupt.	Return is to 
   1464 				; user's program - BASIC or machine code.
   1465 				; which will be interrupted by every NMI.
   1466 
   1467 
   1468 ; THE 'FAST MODE' ROUTINES
   1469 
   1470 
   1471 mark_02A9:
   1472 
   1473 DISPLAY_4:
   1474 
   1475 	LD	A,284-CHARS_PER_LINE_WINDOW	; $FC for 6.5MHz clocked machines
   1476 				; (7)	load A with first R delay value
   1477 
   1478 	LD	B,1		; (7)	one row only.
   1479 
   1480 	CALL	DISPLAY_5	; (17) routine DISPLAY_5
   1481 
   1482 	DEC	HL		; (6)	point back to the HALT.
   1483 	EX	(SP),HL		; (19) Harmless Nonsensical Timing if paired.
   1484 	EX	(SP),HL		; (19) Harmless Nonsensical Timing.
   1485 	JP	(IX)		; (8)	to R_IX_1 or R_IX_2
   1486 
   1487 
   1488 ; THE 'DISPLAY_5' SUBROUTINE
   1489 
   1490 ;	This subroutine is called from SLOW mode and FAST mode to generate the 
   1491 ;	central TV picture. With SLOW mode the R register is incremented, with
   1492 ;	each instruction, to $F7 by the time it completes.	With fast mode, the 
   1493 ;	final R value will be $FF and an interrupt will occur as soon as the 
   1494 ;	Program Counter reaches the HALT.	(24 clock cycles)
   1495 
   1496 mark_02B5:
   1497 DISPLAY_5:
   1498 	LD	R,A		; (9) Load R from A.	R = slow: $F5 fast: $FC
   1499 
   1500 ;; Original, for 32 column display:
   1501 ;;
   1502 ;;	LD	A,$DD		; (7) load future R value.	$F6	$FD
   1503 ;;
   1504 ;; For other display widths,
   1505 ;; need to count down three instructions then the number of characters
   1506 ;;
   1507 	LD	A,256-3-CHARS_PER_LINE_WINDOW	; (7) load future R value.	$F6	$FD
   1508 
   1509 	EI			; (4) Enable Interrupts		$F7	$FE
   1510 
   1511 	JP	(HL)		; (4) jump to the echo display.	$F8	$FF
   1512 
   1513 
   1514 ; THE 'KEYBOARD SCANNING' SUBROUTINE
   1515 
   1516 ; The keyboard is read during the vertical sync interval while no video is 
   1517 ; being displayed.	Reading a port with address bit 0 low i.e. $FE starts the 
   1518 ; vertical sync pulse.
   1519 
   1520 mark_02BB:
   1521 KEYBOARD:
   1522 	LD	HL,$FFFF	; (16) prepare a buffer to take key.
   1523 	LD	BC,$FEFE	; (20) set BC to port $FEFE. The B register, 
   1524 				;	with its single reset bit also acts as 
   1525 				;	an 8-counter.
   1526 	IN	A,(C)		; (11) read the port - all 16 bits are put on 
   1527 				;	the address bus.	Start VSYNC pulse.
   1528 	OR	$01		; (7)	set the rightmost bit so as to ignore 
   1529 				;	the SHIFT key.
   1530 
   1531 mark_02C5:
   1532 EACH_LINE:
   1533 	OR	$E0		; [7] OR %11100000
   1534 	LD	D,A		; [4] transfer to D.
   1535 	CPL			; [4] complement - only bits 4-0 meaningful now.
   1536 	CP	1		; [7] sets carry if A is zero.
   1537 	SBC	A,A		; [4] $FF if $00 else zero.
   1538 	OR	B		; [7] $FF or port FE,FD,FB....
   1539 	AND	L		; [4] unless more than one key, L will still be 
   1540 				;	$FF. if more than one key is pressed then A is 
   1541 				;	now invalid.
   1542 	LD	L,A		; [4] transfer to L.
   1543 
   1544 ; now consider the column identifier.
   1545 
   1546 	LD	A,H		; [4] will be $FF if no previous keys.
   1547 	AND	D		; [4] 111xxxxx
   1548 	LD	H,A		; [4] transfer A to H
   1549 
   1550 ; since only one key may be pressed, H will, if valid, be one of
   1551 ; 11111110, 11111101, 11111011, 11110111, 11101111
   1552 ; reading from the outer column, say Q, to the inner column, say T.
   1553 
   1554 	RLC	B		; [8]	rotate the 8-counter/port address.
   1555 				;	sets carry if more to do.
   1556 	IN	A,(C)		; [10] read another half-row.
   1557 				;	all five bits this time.
   1558 
   1559 	JR	C,EACH_LINE	; [12](7) loop back, until done, to EACH_LINE
   1560 
   1561 ;	The last row read is SHIFT,Z,X,C,V	for the second time.
   1562 
   1563 	RRA			; (4) test the shift key - carry will be reset
   1564 				;	if the key is pressed.
   1565 	RL	H		; (8) rotate left H picking up the carry giving
   1566 				;	column values -
   1567 				;	$FD, $FB, $F7, $EF, $DF.
   1568 				;	or $FC, $FA, $F6, $EE, $DE if shifted.
   1569 
   1570 ;	We now have H identifying the column and L identifying the row in the
   1571 ;	keyboard matrix.
   1572 
   1573 ;	This is a good time to test if this is an American or British machine.
   1574 ;	The US machine has an extra diode that causes bit 6 of a byte read from
   1575 ;	a port to be reset.
   1576 
   1577 	RLA			; (4) compensate for the shift test.
   1578 	RLA			; (4) rotate bit 7 out.
   1579 	RLA			; (4) test bit 6.
   1580 
   1581 	SBC	A,A		; (4)		$FF or 0 {USA}
   1582 	AND	$18		; (7)		24 or 0
   1583 	ADD	A,31		; (7)		55 or 31
   1584 
   1585 ;	result is either 31 (USA) or 55 (UK) blank lines above and below the TV 
   1586 ;	picture.
   1587 
   1588 	LD	(MARGIN),A	; (13) update system variable MARGIN
   1589 
   1590 	RET			; (10) return
   1591 
   1592 
   1593 ; THE 'SET FAST MODE' SUBROUTINE
   1594 
   1595 ;
   1596 ;
   1597 
   1598 mark_02E7:
   1599 SET_FAST:
   1600 	BIT	7,(IY+CDFLAG-RAMBASE)
   1601 	RET	Z		;
   1602 
   1603 	HALT			; Wait for Interrupt
   1604 	OUT	(IO_PORT_NMI_GEN_OFF),A	;
   1605 	RES	7,(IY+CDFLAG-RAMBASE)
   1606 	RET			; return.
   1607 
   1608 
   1609 
   1610 ; THE 'REPORT_F'
   1611 
   1612 
   1613 mark_02F4:
   1614 REPORT_F:
   1615 	RST	_ERROR_1
   1616 	DEFB	$0E		; Error Report: No Program Name supplied.
   1617 
   1618 
   1619 ; THE 'SAVE COMMAND' ROUTINE
   1620 
   1621 ;
   1622 ;
   1623 
   1624 mark_02F6:
   1625 SAVE:
   1626 	CALL	NAME
   1627 	JR	C,REPORT_F	; back with null name
   1628 
   1629 	EX	DE,HL		;
   1630 
   1631 
   1632 
   1633 
   1634 ;
   1635 ; The next 6 bytes differ
   1636 ;
   1637 if NOT_BODGED
   1638 ; what ZASM assembled:
   1639 ; 02FC: 11CB12
   1640 	LD	DE,$12CB	; five seconds timing value (4811 decimal)
   1641 ; 02FF: CD460F
   1642 mark_02FF:
   1643 HEADER:
   1644 	CALL	BREAK_1
   1645 
   1646 else
   1647 ; what the SG ROM disassembled to:
   1648 ;	02FC   ED;FD
   1649 			LDIR			; Patch tape SAVE
   1650 ;	02FE   C3;07;02
   1651 			JP	SLOW_FAST	; to $0207
   1652 ;	0301   0F
   1653 			RRCA
   1654 endif
   1655 
   1656 
   1657 mark_0302:
   1658 	JR	NC,BREAK_2
   1659 
   1660 mark_0304:
   1661 DELAY_1:
   1662 	DJNZ	DELAY_1
   1663 
   1664 	DEC	DE		;
   1665 	LD	A,D		;
   1666 	OR	E		;
   1667 	JR	NZ,HEADER	; back for delay to HEADER
   1668 
   1669 mark_030B:
   1670 OUT_NAME:
   1671 	CALL	OUT_BYTE
   1672 	BIT	7,(HL)		; test for inverted bit.
   1673 	INC	HL		; address next character of name.
   1674 	JR	Z,OUT_NAME	; back if not inverted to OUT_NAME
   1675 
   1676 ; now start saving the system variables onwards.
   1677 
   1678 	LD	HL,VERSN	; set start of area to VERSN thereby
   1679 				; preserving RAMTOP etc.
   1680 
   1681 mark_0316:
   1682 OUT_PROG:
   1683 	CALL	OUT_BYTE
   1684 
   1685 	CALL	LOAD_SAVE	; 			>>
   1686 	JR	OUT_PROG	; loop back
   1687 
   1688 
   1689 ; THE 'OUT_BYTE' SUBROUTINE
   1690 
   1691 ; This subroutine outputs a byte a bit at a time to a domestic tape recorder.
   1692 
   1693 mark_031E:
   1694 OUT_BYTE:
   1695 	LD	E,(HL)		; fetch byte to be saved.
   1696 	SCF			; set carry flag - as a marker.
   1697 
   1698 mark_0320:
   1699 EACH_BIT:
   1700 	RL	E		; C < 76543210 < C
   1701 	RET	Z		; return when the marker bit has passed 
   1702 				; right through.			>>
   1703 
   1704 	SBC	A,A		; $FF if set bit or $00 with no carry.
   1705 	AND	$05		; $05 "  "   "   "  $00
   1706 	ADD	A,$04		; $09 "  "   "   "  $04
   1707 	LD	C,A		; transfer timer to C. a set bit has a longer
   1708 				; pulse than a reset bit.
   1709 
   1710 mark_0329:
   1711 PULSES:
   1712 	OUT	(IO_PORT_TAPE),A	; pulse to cassette.
   1713 	LD	B,$23		; set timing constant
   1714 
   1715 mark_032D:
   1716 DELAY_2:
   1717 	DJNZ	DELAY_2		; self-loop
   1718 
   1719 	CALL	BREAK_1		; test for BREAK key.
   1720 
   1721 mark_0332:
   1722 BREAK_2:
   1723 	JR	NC,REPORT_D	; forward with break to REPORT_D
   1724 
   1725 	LD	B,$1E		; set timing value.
   1726 
   1727 mark_0336:
   1728 DELAY_3:
   1729 
   1730 	DJNZ	DELAY_3		; self-loop
   1731 
   1732 	DEC	C		; decrement counter
   1733 	JR	NZ,PULSES	; loop back
   1734 
   1735 mark_033B:
   1736 DELAY_4:
   1737 	AND	A		; clear carry for next bit test.
   1738 	DJNZ	DELAY_4		; self loop (B is zero - 256)
   1739 
   1740 	JR	EACH_BIT	; loop back
   1741 
   1742 
   1743 ; THE 'LOAD COMMAND' ROUTINE
   1744 
   1745 
   1746 mark_0340:
   1747 LOAD:
   1748 	CALL	NAME
   1749 
   1750 ; DE points to start of name in RAM.
   1751 
   1752 	RL	D		; pick up carry 
   1753 	RRC	D		; carry now in bit 7.
   1754 
   1755 mark_0347:
   1756 
   1757 
   1758 
   1759 if NOT_BODGED
   1760 
   1761 LNEXT_PROG:
   1762 	CALL	IN_BYTE
   1763 	JR	LNEXT_PROG	; loop
   1764 
   1765 
   1766 ; THE 'IN_BYTE' SUBROUTINE
   1767 
   1768 
   1769 mark_034C:
   1770 IN_BYTE:
   1771 	LD	C,$01		; prepare an eight counter 00000001.
   1772 
   1773 mark_034E:
   1774 NEXT_BIT:
   1775 	LD	B,$00		; set counter to 256
   1776 
   1777 else
   1778 ; what the SG ROM has:
   1779 ;0347   EB
   1780 			EX DE,HL            ; NEXT-PROG
   1781 ;0348   ED;FC
   1782 			LDIR                ; Patch tape LOAD
   1783 ;034A   C3;07;02
   1784 			JP SLOW_FAST
   1785 ;034D   01;06;00
   1786 			LD BC,6          
   1787 endif
   1788 
   1789 
   1790 
   1791 
   1792 mark_0350:
   1793 BREAK_3:
   1794 	LD	A,$7F		; read the keyboard row 
   1795 	IN	A,(IO_PORT_KEYBOARD_RD)	; with the SPACE key.
   1796 
   1797 	OUT	(IO_PORT_SCREEN),A	; output signal to screen.
   1798 
   1799 	RRA			; test for SPACE pressed.
   1800 	JR	NC,BREAK_4	; forward if so to BREAK_4
   1801 
   1802 	RLA			; reverse above rotation
   1803 	RLA			; test tape bit.
   1804 	JR	C,GET_BIT	; forward if set to GET_BIT
   1805 
   1806 	DJNZ	BREAK_3		; loop back
   1807 
   1808 	POP	AF		; drop the return address.
   1809 	CP	D		; ugh.
   1810 
   1811 mark_0361:
   1812 RESTART:
   1813 	JP	NC,INITIAL	; jump forward to INITIAL if D is zero 
   1814 				; to reset the system
   1815 				; if the tape signal has timed out for example
   1816 				; if the tape is stopped. Not just a simple 
   1817 				; report as some system variables will have
   1818 				; been overwritten.
   1819 
   1820 	LD	H,D		; else transfer the start of name
   1821 	LD	L,E		; to the HL register
   1822 
   1823 mark_0366:
   1824 IN_NAME:
   1825 	CALL	IN_BYTE		; is sort of recursion for name
   1826 				; part. received byte in C.
   1827 	BIT	7,D		; is name the null string ?
   1828 	LD	A,C		; transfer byte to A.
   1829 	JR	NZ,MATCHING	; forward with null string
   1830 
   1831 	CP	(HL)		; else compare with string in memory.
   1832 	JR	NZ,LNEXT_PROG	; back with mis-match
   1833 				; (seemingly out of subroutine but return 
   1834 				; address has been dropped).
   1835 
   1836 
   1837 mark_0371:
   1838 MATCHING:
   1839 	INC	HL		; address next character of name
   1840 	RLA			; test for inverted bit.
   1841 	JR	NC,IN_NAME	; back if not
   1842 
   1843 ; the name has been matched in full. 
   1844 ; proceed to load the data but first increment the high byte of E_LINE, which
   1845 ; is one of the system variables to be loaded in. Since the low byte is loaded
   1846 ; before the high byte, it is possible that, at the in-between stage, a false
   1847 ; value could cause the load to end prematurely - see	LOAD_SAVE check.
   1848 
   1849 	INC	(IY+E_LINE_hi-RAMBASE)	; increment E_LINE_hi.
   1850 	LD	HL,VERSN	; start loading at VERSN.
   1851 
   1852 mark_037B:
   1853 IN_PROG:
   1854 	LD	D,B		; set D to zero as indicator.
   1855 	CALL	IN_BYTE		; loads a byte
   1856 	LD	(HL),C		; insert assembled byte in memory.
   1857 	CALL	LOAD_SAVE		; 		>>
   1858 	JR	IN_PROG		; loop back
   1859 
   1860 ; ___
   1861 
   1862 ; this branch assembles a full byte before exiting normally
   1863 ; from the IN_BYTE subroutine.
   1864 
   1865 mark_0385:
   1866 GET_BIT:
   1867 	PUSH	DE		; save the 
   1868 	LD	E,$94		; timing value.
   1869 
   1870 mark_0388:
   1871 TRAILER:
   1872 	LD	B,26		; counter to twenty six.
   1873 
   1874 mark_038A:
   1875 COUNTER:
   1876 	DEC	E		; decrement the measuring timer.
   1877 	IN	A,(IO_PORT_KEYBOARD_RD)	; read the tape input
   1878 	RLA			;
   1879 	BIT	7,E		;
   1880 	LD	A,E		;
   1881 	JR	C,TRAILER	; loop back with carry to TRAILER
   1882 
   1883 	DJNZ	COUNTER
   1884 
   1885 	POP	DE		;
   1886 	JR	NZ,BIT_DONE
   1887 
   1888 	CP	$56		;
   1889 	JR	NC,NEXT_BIT
   1890 
   1891 mark_039C:
   1892 BIT_DONE:
   1893 	CCF			; complement carry flag
   1894 	RL	C		;
   1895 	JR	NC,NEXT_BIT
   1896 
   1897 	RET			; return with full byte.
   1898 
   1899 ; ___
   1900 
   1901 ; if break is pressed while loading data then perform a reset.
   1902 ; if break pressed while waiting for program on tape then OK to break.
   1903 
   1904 mark_03A2:
   1905 BREAK_4:
   1906 	LD	A,D		; transfer indicator to A.
   1907 	AND	A		; test for zero.
   1908 	JR	Z,RESTART	; back if so
   1909 
   1910 
   1911 mark_03A6:
   1912 REPORT_D:
   1913 	RST	_ERROR_1
   1914 	DEFB	$0C		; Error Report: BREAK - CONT repeats
   1915 
   1916 
   1917 ; THE 'PROGRAM NAME' SUBROUTINE
   1918 
   1919 
   1920 mark_03A8:
   1921 NAME:
   1922 	CALL	SCANNING
   1923 	LD	A,(FLAGS)	; sv
   1924 	ADD	A,A		;
   1925 	JP	M,REPORT_C
   1926 
   1927 	POP	HL		;
   1928 	RET	NC		;
   1929 
   1930 	PUSH	HL		;
   1931 	CALL	SET_FAST
   1932 	CALL	STK_FETCH
   1933 	LD	H,D		;
   1934 	LD	L,E		;
   1935 	DEC	C		;
   1936 	RET	M		;
   1937 
   1938 	ADD	HL,BC		;
   1939 	SET	7,(HL)		;
   1940 	RET			;
   1941 
   1942 
   1943 ; THE 'NEW' COMMAND ROUTINE
   1944 
   1945 
   1946 mark_03C3:
   1947 NEW:
   1948 	CALL	SET_FAST
   1949 	LD	BC,(RAMTOP)	; fetch value of system variable RAMTOP
   1950 	DEC	BC		; point to last system byte.
   1951 
   1952 
   1953 ; THE 'RAM CHECK' ROUTINE
   1954 
   1955 
   1956 mark_03CB:
   1957 RAM_CHECK:
   1958 	LD	H,B		;
   1959 	LD	L,C		;
   1960 	LD	A,$3F		;
   1961 
   1962 mark_03CF:
   1963 RAM_FILL:
   1964 	LD	(HL),$02	;
   1965 	DEC	HL		;
   1966 	CP	H		;
   1967 	JR	NZ,RAM_FILL
   1968 
   1969 mark_03D5:
   1970 RAM_READ:
   1971 	AND	A		;
   1972 	SBC	HL,BC		;
   1973 	ADD	HL,BC		;
   1974 	INC	HL		;
   1975 	JR	NC,SET_TOP
   1976 
   1977 	DEC	(HL)		;
   1978 	JR	Z,SET_TOP
   1979 
   1980 	DEC	(HL)		;
   1981 	JR	Z,RAM_READ
   1982 
   1983 mark_03E2:
   1984 SET_TOP:
   1985 	LD	(RAMTOP),HL	; set system variable RAMTOP to first byte 
   1986 				; above the BASIC system area.
   1987 
   1988 
   1989 ; THE 'INITIALIZATION' ROUTINE
   1990 
   1991 
   1992 mark_03E5:
   1993 INITIAL:
   1994 	LD	HL,(RAMTOP)	; fetch system variable RAMTOP.
   1995 	DEC	HL		; point to last system byte.
   1996 	LD	(HL),$3E	; make GO SUB end-marker $3E - too high for
   1997 				; high order byte of line number.
   1998 				; (was $3F on ZX80)
   1999 	DEC	HL		; point to unimportant low-order byte.
   2000 	LD	SP,HL		; and initialize the stack-pointer to this
   2001 				; location.
   2002 	DEC	HL		; point to first location on the machine stack
   2003 	DEC	HL		; which will be filled by next CALL/PUSH.
   2004 	LD	(ERR_SP),HL	; set the error stack pointer ERR_SP to
   2005 				; the base of the now empty machine stack.
   2006 
   2007 ; Now set the I register so that the video hardware knows where to find the
   2008 ; character set. This ROM only uses the character set when printing to 
   2009 ; the ZX Printer. The TV picture is formed by the external video hardware. 
   2010 ; Consider also, that this 8K ROM can be retro-fitted to the ZX80 instead of 
   2011 ; its original 4K ROM so the video hardware could be on the ZX80.
   2012 
   2013 	LD	A,$1E		; address for this ROM is $1E00.
   2014 	LD	I,A		; set I register from A.
   2015 	IM	1		; select Z80 Interrupt Mode 1.
   2016 
   2017 	LD	IY,ERR_NR	; set IY to the start of RAM so that the 
   2018 				; system variables can be indexed.
   2019 
   2020 	LD	(IY+CDFLAG-RAMBASE),%01000000
   2021 				; Bit 6 indicates Compute and Display required.
   2022 
   2023 	LD	HL,USER_RAM	; The first location after System Variables -
   2024 				; 16509 decimal.
   2025 	LD	(D_FILE),HL	; set system variable D_FILE to this value.
   2026 	LD	B,$19		; prepare minimal screen of 24 NEWLINEs
   2027 				; following an initial NEWLINE.
   2028 
   2029 mark_0408:
   2030 LINE:
   2031 	LD	(HL),ZX_NEWLINE	; insert NEWLINE (HALT instruction)
   2032 	INC	HL		; point to next location.
   2033 	DJNZ	LINE		; loop back for all twenty five to LINE
   2034 
   2035 	LD	(VARS),HL	; set system variable VARS to next location
   2036 
   2037 	CALL	CLEAR		; sets $80 end-marker and the 
   2038 				; dynamic memory pointers E_LINE, STKBOT and
   2039 				; STKEND.
   2040 
   2041 mark_0413:
   2042 N_L_ONLY:
   2043 	CALL	CURSOR_IN	; inserts the cursor and 
   2044 				; end-marker in the Edit Line also setting
   2045 				; size of lower display to two lines.
   2046 
   2047 	CALL	SLOW_FAST	; selects COMPUTE and DISPLAY
   2048 
   2049 
   2050 ; THE 'BASIC LISTING' SECTION
   2051 
   2052 
   2053 mark_0419:
   2054 UPPER:
   2055 	CALL	CLS
   2056 	LD	HL,(E_PPC)	; sv
   2057 	LD	DE,(S_TOP)	; sv
   2058 	AND	A		;
   2059 	SBC	HL,DE		;
   2060 	EX	DE,HL		;
   2061 	JR	NC,ADDR_TOP
   2062 
   2063 	ADD	HL,DE		;
   2064 	LD	(S_TOP),HL	; sv
   2065 
   2066 mark_042D:
   2067 ADDR_TOP:
   2068 	CALL	LINE_ADDR
   2069 	JR	Z,LIST_TOP
   2070 
   2071 	EX	DE,HL		;
   2072 
   2073 mark_0433:
   2074 LIST_TOP:
   2075 	CALL	LIST_PROG
   2076 	DEC	(IY+BERG-RAMBASE)
   2077 	JR	NZ,LOWER
   2078 
   2079 	LD	HL,(E_PPC)	; sv
   2080 	CALL	LINE_ADDR
   2081 	LD	HL,(CH_ADD)	; sv
   2082 	SCF			; Set Carry Flag
   2083 	SBC	HL,DE		;
   2084 	LD	HL,S_TOP	; sv
   2085 	JR	NC,INC_LINE
   2086 
   2087 	EX	DE,HL		;
   2088 	LD	A,(HL)		;
   2089 	INC	HL		;
   2090 	LDI			;
   2091 	LD	(DE),A		;
   2092 	JR	UPPER
   2093 ; ___
   2094 
   2095 mark_0454:
   2096 DOWN_KEY:
   2097 
   2098 	LD	HL,E_PPC	; sv
   2099 
   2100 mark_0457:
   2101 INC_LINE:
   2102 	LD	E,(HL)		;
   2103 	INC	HL		;
   2104 	LD	D,(HL)		;
   2105 	PUSH	HL		;
   2106 	EX	DE,HL		;
   2107 	INC	HL		;
   2108 	CALL	LINE_ADDR
   2109 	CALL	LINE_NUM
   2110 	POP	HL		;
   2111 
   2112 mark_0464:
   2113 KEY_INPUT:
   2114 	BIT	5,(IY+FLAGX-RAMBASE)
   2115 	JR	NZ,LOWER	; forward
   2116 
   2117 	LD	(HL),D		;
   2118 	DEC	HL		;
   2119 	LD	(HL),E		;
   2120 	JR	UPPER
   2121 
   2122 
   2123 ; THE 'EDIT LINE COPY' SECTION
   2124 
   2125 ; This routine sets the edit line to just the cursor when
   2126 ; 1) There is not enough memory to edit a BASIC line.
   2127 ; 2) The edit key is used during input.
   2128 ; The entry point LOWER
   2129 
   2130 
   2131 mark_046F:
   2132 EDIT_INP:
   2133 	CALL	CURSOR_IN	; sets cursor only edit line.
   2134 
   2135 ; ->
   2136 
   2137 mark_0472:
   2138 LOWER:
   2139 	LD	HL,(E_LINE)	; fetch edit line start from E_LINE.
   2140 
   2141 mark_0475:
   2142 EACH_CHAR:
   2143 	LD	A,(HL)		; fetch a character from edit line.
   2144 	CP	$7E		; compare to the number marker.
   2145 	JR	NZ,END_LINE	; forward if not
   2146 
   2147 	LD	BC,6		; else six invisible bytes to be removed.
   2148 	CALL	RECLAIM_2
   2149 	JR	EACH_CHAR	; back
   2150 ; ___
   2151 
   2152 mark_0482:
   2153 END_LINE:
   2154 	CP	ZX_NEWLINE		;
   2155 	INC	HL		;
   2156 	JR	NZ,EACH_CHAR
   2157 
   2158 mark_0487:
   2159 EDIT_LINE:
   2160 	CALL	CURSOR		; sets cursor K or L.
   2161 
   2162 mark_048A:
   2163 EDIT_ROOM:
   2164 	CALL	LINE_ENDS
   2165 	LD	HL,(E_LINE)	; sv
   2166 	LD	(IY+ERR_NR-RAMBASE),$FF
   2167 	CALL	COPY_LINE
   2168 	BIT	7,(IY+ERR_NR-RAMBASE)
   2169 	JR	NZ,DISPLAY_6
   2170 
   2171 	LD	A,(DF_SZ)	; 
   2172 	CP	CHARS_VERTICAL	; $18 = 24
   2173 	JR	NC,DISPLAY_6
   2174 
   2175 	INC	A		;
   2176 	LD	(DF_SZ),A	; 
   2177 	LD	B,A		;
   2178 	LD	C,1		;
   2179 	CALL	LOC_ADDR
   2180 	LD	D,H		;
   2181 	LD	E,L		;
   2182 	LD	A,(HL)		;
   2183 
   2184 mark_04B1:
   2185 FREE_LINE:
   2186 	DEC	HL		;
   2187 	CP	(HL)		;
   2188 	JR	NZ,FREE_LINE
   2189 
   2190 	INC	HL		;
   2191 	EX	DE,HL		;
   2192 	LD	A,(RAMTOP+1)	; sv RAMTOP_hi
   2193 	CP	$4D		;
   2194 	CALL	C,RECLAIM_1
   2195 	JR	EDIT_ROOM
   2196 
   2197 
   2198 ; THE 'WAIT FOR KEY' SECTION
   2199 
   2200 
   2201 mark_04C1:
   2202 DISPLAY_6:
   2203 	LD	HL,$0000	;
   2204 	LD	(X_PTR),HL	; sv
   2205 
   2206 	LD	HL,CDFLAG	; system variable CDFLAG
   2207 
   2208 
   2209 
   2210 
   2211 if NOT_BODGED
   2212 	BIT	7,(HL)		;
   2213 
   2214 	CALL	Z,DISPLAY_1
   2215 
   2216 mark_04CF:
   2217 SLOW_DISP:
   2218 	BIT	0,(HL)		;
   2219 	JR	Z,SLOW_DISP
   2220 
   2221 else
   2222 ;	04CA   D3;00
   2223 			OUT ($00),A         ; PORT 0
   2224 ;	04CC   CB;46
   2225 L04CC:
   2226 			BIT 0,(HL)           
   2227 ;	04CE   28;FC
   2228 			JR Z,L04CC
   2229 ;	04D0   D3;01
   2230 			OUT ($01),A         ; PORT 1
   2231 ;	04D2   00
   2232 			NOP
   2233 
   2234 
   2235 endif
   2236 
   2237 
   2238 
   2239 
   2240 	LD	BC,(LAST_K)	; sv
   2241 	CALL	DEBOUNCE
   2242 	CALL	DECODE
   2243 
   2244 	JR	NC,LOWER	; back
   2245 
   2246 
   2247 ; THE 'KEYBOARD DECODING' SECTION
   2248 
   2249 ;	The decoded key value is in E and HL points to the position in the 
   2250 ;	key table. D contains zero.
   2251 
   2252 mark_04DF:
   2253 K_DECODE:
   2254 	LD	A,(MODE)	; Fetch value of system variable MODE
   2255 	DEC	A		; test the three values together
   2256 
   2257 	JP	M,FETCH_2	; forward, if was zero
   2258 
   2259 	JR	NZ,FETCH_1	; forward, if was 2
   2260 
   2261 ;	The original value was one and is now zero.
   2262 
   2263 	LD	(MODE),A	; update the system variable MODE
   2264 
   2265 	DEC	E		; reduce E to range $00 - $7F
   2266 	LD	A,E		; place in A
   2267 	SUB	39		; subtract 39 setting carry if range 00 - 38
   2268 	JR	C,FUNC_BASE	; forward, if so
   2269 
   2270 	LD	E,A		; else set E to reduced value
   2271 
   2272 mark_04F2:
   2273 FUNC_BASE:
   2274 	LD	HL,K_FUNCT	; address of K_FUNCT table for function keys.
   2275 	JR	TABLE_ADD	; forward
   2276 ; ___
   2277 mark_04F7:
   2278 FETCH_1:
   2279 	LD	A,(HL)		;
   2280 	CP	ZX_NEWLINE	;
   2281 	JR	Z,K_L_KEY
   2282 
   2283 	CP	ZX_RND		; $40
   2284 	SET	7,A		;
   2285 	JR	C,ENTER
   2286 
   2287 	LD	HL,$00C7	; (expr reqd)
   2288 
   2289 mark_0505:
   2290 TABLE_ADD:
   2291 	ADD	HL,DE		;
   2292 	JR	FETCH_3
   2293 
   2294 ; ___
   2295 
   2296 mark_0508:
   2297 FETCH_2:
   2298 	LD	A,(HL)		;
   2299 	BIT	2,(IY+FLAGS-RAMBASE)	; K or L mode ?
   2300 	JR	NZ,TEST_CURS
   2301 
   2302 	ADD	A,$C0		;
   2303 	CP	$E6		;
   2304 	JR	NC,TEST_CURS
   2305 
   2306 mark_0515:
   2307 FETCH_3:
   2308 	LD	A,(HL)		;
   2309 
   2310 mark_0516:
   2311 TEST_CURS:
   2312 	CP	$F0		;
   2313 	JP	PE,KEY_SORT
   2314 
   2315 mark_051B:
   2316 ENTER:
   2317 	LD	E,A		;
   2318 	CALL	CURSOR
   2319 
   2320 	LD	A,E		;
   2321 	CALL	ADD_CHAR
   2322 
   2323 mark_0523:
   2324 BACK_NEXT:
   2325 	JP	LOWER		; back
   2326 
   2327 
   2328 ; THE 'ADD CHARACTER' SUBROUTINE
   2329 
   2330 mark_0526:
   2331 ADD_CHAR:
   2332 	CALL	ONE_SPACE
   2333 	LD	(DE),A		;
   2334 	RET			;
   2335 
   2336 
   2337 ; THE 'CURSOR KEYS' ROUTINE
   2338 
   2339 mark_052B:
   2340 K_L_KEY:
   2341 	LD	A,ZX_KL		;
   2342 
   2343 mark_052D:
   2344 KEY_SORT:
   2345 	LD	E,A		;
   2346 	LD	HL,$0482	; base address of ED_KEYS (exp reqd)
   2347 	ADD	HL,DE		;
   2348 	ADD	HL,DE		;
   2349 	LD	C,(HL)		;
   2350 	INC	HL		;
   2351 	LD	B,(HL)		;
   2352 	PUSH	BC		;
   2353 
   2354 mark_0537:
   2355 CURSOR:
   2356 	LD	HL,(E_LINE)	; sv
   2357 	BIT	5,(IY+FLAGX-RAMBASE)
   2358 	JR	NZ,L_MODE
   2359 
   2360 mark_0540:
   2361 K_MODE:
   2362 	RES	2,(IY+FLAGS-RAMBASE)	; Signal use K mode
   2363 
   2364 mark_0544:
   2365 TEST_CHAR:
   2366 	LD	A,(HL)		;
   2367 	CP	ZX_CURSOR	;
   2368 	RET	Z		; return
   2369 
   2370 	INC	HL		;
   2371 	CALL	NUMBER
   2372 	JR	Z,TEST_CHAR
   2373 
   2374 	CP	ZX_A		; $26
   2375 	JR	C,TEST_CHAR
   2376 
   2377 	CP	$DE		; ZX_THEN ??
   2378 	JR	Z,K_MODE
   2379 
   2380 mark_0556:
   2381 L_MODE:
   2382 	SET	2,(IY+FLAGS-RAMBASE)	; Signal use L mode
   2383 	JR	TEST_CHAR
   2384 
   2385 
   2386 ; THE 'CLEAR_ONE' SUBROUTINE
   2387 
   2388 mark_055C:
   2389 CLEAR_ONE:
   2390 	LD	BC,$0001	;
   2391 	JP	RECLAIM_2
   2392 
   2393 
   2394 ; THE 'EDITING KEYS' TABLE
   2395 
   2396 mark_0562:
   2397 ED_KEYS:
   2398 	DEFW	UP_KEY
   2399 	DEFW	DOWN_KEY
   2400 	DEFW	LEFT_KEY
   2401 	DEFW	RIGHT_KEY
   2402 	DEFW	FUNCTION
   2403 	DEFW	EDIT_KEY
   2404 	DEFW	N_L_KEY
   2405 	DEFW	RUBOUT
   2406 	DEFW	FUNCTION
   2407 	DEFW	FUNCTION
   2408 
   2409 
   2410 
   2411 ; THE 'CURSOR LEFT' ROUTINE
   2412 
   2413 ;
   2414 ;
   2415 
   2416 mark_LEFT_KEY:
   2417 LEFT_KEY:
   2418 	CALL	LEFT_EDGE
   2419 	LD	A,(HL)		;
   2420 	LD	(HL),ZX_CURSOR	;
   2421 	INC	HL		;
   2422 	JR	GET_CODE
   2423 
   2424 
   2425 ; THE 'CURSOR RIGHT' ROUTINE
   2426 
   2427 
   2428 mark_RIGHT_KEY:
   2429 RIGHT_KEY:
   2430 	INC	HL		;
   2431 	LD	A,(HL)		;
   2432 	CP	ZX_NEWLINE		;
   2433 	JR	Z,ENDED_2
   2434 
   2435 	LD	(HL),ZX_CURSOR	;
   2436 	DEC	HL		;
   2437 
   2438 mark_0588:
   2439 GET_CODE:
   2440 	LD	(HL),A		;
   2441 
   2442 mark_0589:
   2443 ENDED_1:
   2444 	JR	BACK_NEXT
   2445 
   2446 
   2447 ; THE 'RUBOUT' ROUTINE
   2448 
   2449 
   2450 mark_058B:
   2451 RUBOUT:
   2452 	CALL	LEFT_EDGE
   2453 	CALL	CLEAR_ONE
   2454 	JR	ENDED_1
   2455 
   2456 
   2457 ; THE 'ED_EDGE' SUBROUTINE
   2458 
   2459 ;
   2460 ;
   2461 
   2462 mark_0593:
   2463 LEFT_EDGE:
   2464 	DEC	HL		;
   2465 	LD	DE,(E_LINE)	; sv
   2466 	LD	A,(DE)		;
   2467 	CP	ZX_CURSOR	;
   2468 	RET	NZ		;
   2469 
   2470 	POP	DE		;
   2471 
   2472 mark_059D:
   2473 ENDED_2:
   2474 	JR	ENDED_1
   2475 
   2476 
   2477 ; THE 'CURSOR UP' ROUTINE
   2478 
   2479 ;
   2480 ;
   2481 
   2482 mark_059F:
   2483 UP_KEY:
   2484 	LD	HL,(E_PPC)	; sv
   2485 	CALL	LINE_ADDR
   2486 	EX	DE,HL		;
   2487 	CALL	LINE_NUM
   2488 	LD	HL,E_PPC+1	; point to system variable E_PPC_hi
   2489 	JP	KEY_INPUT	; jump back
   2490 
   2491 
   2492 ; THE 'FUNCTION KEY' ROUTINE
   2493 
   2494 ;
   2495 ;
   2496 
   2497 mark_FUNCTION:
   2498 FUNCTION:
   2499 	LD	A,E		;
   2500 	AND	$07		;
   2501 	LD	(MODE),A	; sv
   2502 	JR	ENDED_2		; back
   2503 
   2504 
   2505 ; THE 'COLLECT LINE NUMBER' SUBROUTINE
   2506 
   2507 mark_05B7:
   2508 ZERO_DE:
   2509 	EX	DE,HL		;
   2510 	LD	DE,DISPLAY_6 + 1	; $04C2 - a location addressing two zeros.
   2511 
   2512 ; ->
   2513 
   2514 mark_05BB:
   2515 LINE_NUM:
   2516 	LD	A,(HL)		;
   2517 	AND	$C0		;
   2518 	JR	NZ,ZERO_DE
   2519 
   2520 	LD	D,(HL)		;
   2521 	INC	HL		;
   2522 	LD	E,(HL)		;
   2523 	RET			;
   2524 
   2525 
   2526 ; THE 'EDIT KEY' ROUTINE
   2527 
   2528 
   2529 mark_EDIT_KEY:
   2530 EDIT_KEY:
   2531 	CALL	LINE_ENDS	; clears lower display.
   2532 
   2533 	LD	HL,EDIT_INP	; Address: EDIT_INP
   2534 	PUSH	HL		; ** is pushed as an error looping address.
   2535 
   2536 	BIT	5,(IY+FLAGX-RAMBASE)	; test FLAGX
   2537 	RET	NZ		; indirect jump if in input mode
   2538 				; to EDIT_INP (begin again).
   2539 
   2540 ;
   2541 
   2542 	LD	HL,(E_LINE)	; fetch E_LINE
   2543 	LD	(DF_CC),HL	; and use to update the screen cursor DF_CC
   2544 
   2545 ; so now RST $10 will print the line numbers to the edit line instead of screen.
   2546 ; first make sure that no newline/out of screen can occur while sprinting the
   2547 ; line numbers to the edit line.
   2548 
   2549 				; prepare line 0, column 0.
   2550 
   2551 	LD	HL,256*CHARS_VERTICAL + CHARS_HORIZONTAL + 1
   2552 ;
   2553 	LD	(S_POSN),HL	; update S_POSN with these dummy values.
   2554 
   2555 	LD	HL,(E_PPC)	; fetch current line from E_PPC may be a 
   2556 				; non-existent line e.g. last line deleted.
   2557 	CALL	LINE_ADDR	; gets address or that of
   2558 				; the following line.
   2559 	CALL	LINE_NUM	; gets line number if any in DE
   2560 				; leaving HL pointing at second low byte.
   2561 
   2562 	LD	A,D		; test the line number for zero.
   2563 	OR	E		;
   2564 	RET	Z		; return if no line number - no program to edit.
   2565 
   2566 	DEC	HL		; point to high byte.
   2567 	CALL	OUT_NO		; writes number to edit line.
   2568 
   2569 	INC	HL		; point to length bytes.
   2570 	LD	C,(HL)		; low byte to C.
   2571 	INC	HL		;
   2572 	LD	B,(HL)		; high byte to B.
   2573 
   2574 	INC	HL		; point to first character in line.
   2575 	LD	DE,(DF_CC)	; fetch display file cursor DF_CC
   2576 
   2577 	LD	A,ZX_CURSOR	; prepare the cursor character.
   2578 	LD	(DE),A		; and insert in edit line.
   2579 	INC	DE		; increment intended destination.
   2580 
   2581 	PUSH	HL		; * save start of BASIC.
   2582 
   2583 	LD	HL,29		; set an overhead of 29 bytes.
   2584 	ADD	HL,DE		; add in the address of cursor.
   2585 	ADD	HL,BC		; add the length of the line.
   2586 	SBC	HL,SP		; subtract the stack pointer.
   2587 
   2588 	POP	HL		; * restore pointer to start of BASIC.
   2589 
   2590 	RET	NC		; return if not enough room to EDIT_INP EDIT_INP.
   2591 				; the edit key appears not to work.
   2592 
   2593 	LDIR			; else copy bytes from program to edit line.
   2594 				; Note. hidden floating point forms are also
   2595 				; copied to edit line.
   2596 
   2597 	EX	DE,HL		; transfer free location pointer to HL
   2598 
   2599 	POP	DE		; ** remove address EDIT_INP from stack.
   2600 
   2601 	CALL	SET_STK_B	; sets STKEND from HL.
   2602 
   2603 	JR	ENDED_2		; back to ENDED_2 and after 3 more jumps
   2604 				; to LOWER, LOWER.
   2605 				; Note. The LOWER routine removes the hidden 
   2606 				; floating-point numbers from the edit line.
   2607 
   2608 
   2609 ; THE 'NEWLINE KEY' ROUTINE
   2610 
   2611 
   2612 mark_060C:
   2613 N_L_KEY:
   2614 	CALL	LINE_ENDS
   2615 
   2616 	LD	HL,LOWER	; prepare address: LOWER
   2617 
   2618 	BIT	5,(IY+FLAGX-RAMBASE)
   2619 	JR	NZ,NOW_SCAN
   2620 
   2621 	LD	HL,(E_LINE)	; sv
   2622 	LD	A,(HL)		;
   2623 	CP	$FF		;
   2624 	JR	Z,STK_UPPER
   2625 
   2626 	CALL	CLEAR_PRB
   2627 	CALL	CLS
   2628 
   2629 mark_0626:
   2630 STK_UPPER:
   2631 	LD	HL,UPPER	; Address: UPPER
   2632 
   2633 mark_0629:
   2634 NOW_SCAN:
   2635 	PUSH	HL		; push routine address (LOWER or UPPER).
   2636 	CALL	LINE_SCAN
   2637 	POP	HL		;
   2638 	CALL	CURSOR
   2639 	CALL	CLEAR_ONE
   2640 	CALL	E_LINE_NUM
   2641 	JR	NZ,N_L_INP
   2642 
   2643 	LD	A,B		;
   2644 	OR	C		;
   2645 	JP	NZ,N_L_LINE
   2646 
   2647 	DEC	BC		;
   2648 	DEC	BC		;
   2649 	LD	(PPC),BC	; sv
   2650 	LD	(IY+DF_SZ-RAMBASE),2
   2651 	LD	DE,(D_FILE)	; sv
   2652 
   2653 	JR	TEST_NULL	; forward
   2654 
   2655 ; ___
   2656 
   2657 mark_064E:
   2658 N_L_INP:
   2659 	CP	ZX_NEWLINE	;
   2660 	JR	Z,N_L_NULL
   2661 
   2662 	LD	BC,(T_ADDR)	; 
   2663 	CALL	LOC_ADDR
   2664 	LD	DE,(NXTLIN)	; 
   2665 	LD	(IY+DF_SZ-RAMBASE),2
   2666 
   2667 mark_0661:
   2668 TEST_NULL:
   2669 	RST	_GET_CHAR
   2670 	CP	ZX_NEWLINE	;
   2671 
   2672 mark_0664:
   2673 N_L_NULL:
   2674 	JP	Z,N_L_ONLY
   2675 
   2676 	LD	(IY+FLAGS-RAMBASE),$80
   2677 	EX	DE,HL		;
   2678 
   2679 mark_066C:
   2680 NEXT_LINE:
   2681 	LD	(NXTLIN),HL	; 
   2682 	EX	DE,HL		;
   2683 	CALL	TEMP_PTR2
   2684 	CALL	LINE_RUN
   2685 	RES	1,(IY+FLAGS-RAMBASE)	; Signal printer not in use
   2686 	LD	A,$C0		;
   2687 ;;	LD	(IY+X_PTR_lo-RAMBASE),A		;; ERROR IN htm SOURCE! IY+$19 is X_PTR_hi
   2688 	LD	(IY+X_PTR_hi-RAMBASE),A
   2689 	CALL	X_TEMP
   2690 	RES	5,(IY+FLAGX-RAMBASE)
   2691 	BIT	7,(IY+ERR_NR-RAMBASE)
   2692 	JR	Z,STOP_LINE
   2693 
   2694 	LD	HL,(NXTLIN)	;
   2695 	AND	(HL)		;
   2696 	JR	NZ,STOP_LINE
   2697 
   2698 	LD	D,(HL)		;
   2699 	INC	HL		;
   2700 	LD	E,(HL)		;
   2701 	LD	(PPC),DE	;
   2702 	INC	HL		;
   2703 	LD	E,(HL)		;
   2704 	INC	HL		;
   2705 	LD	D,(HL)		;
   2706 	INC	HL		;
   2707 	EX	DE,HL		;
   2708 	ADD	HL,DE		;
   2709 	CALL	BREAK_1
   2710 	JR	C,NEXT_LINE
   2711 
   2712 	LD	HL,ERR_NR
   2713 	BIT	7,(HL)
   2714 	JR	Z,STOP_LINE
   2715 
   2716 	LD	(HL),$0C
   2717 
   2718 mark_06AE:
   2719 STOP_LINE:
   2720 	BIT	7,(IY+PR_CC-RAMBASE)
   2721 	CALL	Z,COPY_BUFF
   2722 ;
   2723 if 0
   2724 	LD	BC,$0121	;
   2725 else
   2726 	LD	BC,256*1 + CHARS_HORIZONTAL + 1
   2727 endif
   2728 ;
   2729 ;
   2730 	CALL	LOC_ADDR
   2731 	LD	A,(ERR_NR)
   2732 	LD	BC,(PPC)
   2733 	INC	A
   2734 	JR	Z,REPORT
   2735 
   2736 	CP	$09
   2737 	JR	NZ,CONTINUE
   2738 
   2739 	INC	BC
   2740 
   2741 mark_06CA:
   2742 CONTINUE:
   2743 	LD	(OLDPPC),BC	;
   2744 	JR	NZ,REPORT
   2745 
   2746 	DEC	BC		;
   2747 
   2748 mark_06D1:
   2749 REPORT:
   2750 	CALL	OUT_CODE
   2751 	LD	A,ZX_SLASH
   2752 
   2753 	RST	_PRINT_A
   2754 	CALL	OUT_NUM
   2755 	CALL	CURSOR_IN
   2756 	JP	DISPLAY_6
   2757 
   2758 ; ___
   2759 
   2760 mark_06E0:
   2761 N_L_LINE:
   2762 	LD	(E_PPC),BC	;
   2763 	LD	HL,(CH_ADD)	;
   2764 	EX	DE,HL		;
   2765 	LD	HL,N_L_ONLY
   2766 	PUSH	HL		;
   2767 	LD	HL,(STKBOT)	;
   2768 	SBC	HL,DE		;
   2769 	PUSH	HL		;
   2770 	PUSH	BC		;
   2771 	CALL	SET_FAST
   2772 	CALL	CLS
   2773 	POP	HL		;
   2774 	CALL	LINE_ADDR
   2775 	JR	NZ,COPY_OVER
   2776 
   2777 	CALL	NEXT_ONE
   2778 	CALL	RECLAIM_2
   2779 
   2780 mark_0705:
   2781 COPY_OVER:
   2782 	POP	BC		;
   2783 	LD	A,C		;
   2784 	DEC	A		;
   2785 	OR	B		;
   2786 	RET	Z		;
   2787 
   2788 	PUSH	BC		;
   2789 	INC	BC		;
   2790 	INC	BC		;
   2791 	INC	BC		;
   2792 	INC	BC		;
   2793 	DEC	HL		;
   2794 	CALL	MAKE_ROOM
   2795 	CALL	SLOW_FAST
   2796 	POP	BC		;
   2797 	PUSH	BC		;
   2798 	INC	DE		;
   2799 	LD	HL,(STKBOT)	;
   2800 	DEC	HL		;
   2801 	LDDR			; copy bytes
   2802 	LD	HL,(E_PPC)	;
   2803 	EX	DE,HL		;
   2804 	POP	BC		;
   2805 	LD	(HL),B		;
   2806 	DEC	HL		;
   2807 	LD	(HL),C		;
   2808 	DEC	HL		;
   2809 	LD	(HL),E		;
   2810 	DEC	HL		;
   2811 	LD	(HL),D		;
   2812 
   2813 	RET			; return.
   2814 
   2815 
   2816 ; THE 'LIST' AND 'LLIST' COMMAND ROUTINES
   2817 
   2818 
   2819 mark_072C:
   2820 LLIST:
   2821 	SET	1,(IY+FLAGS-RAMBASE)	; signal printer in use
   2822 
   2823 mark_0730:
   2824 LIST:
   2825 	CALL	FIND_INT
   2826 
   2827 	LD	A,B		; fetch high byte of user-supplied line number.
   2828 	AND	$3F		; and crudely limit to range 1-16383.
   2829 
   2830 	LD	H,A		;
   2831 	LD	L,C		;
   2832 	LD	(E_PPC),HL	;
   2833 	CALL	LINE_ADDR
   2834 
   2835 mark_073E:
   2836 LIST_PROG:
   2837 	LD	E,$00		;
   2838 
   2839 mark_0740:
   2840 UNTIL_END:
   2841 	CALL	OUT_LINE	; lists one line of BASIC
   2842 				; making an early return when the screen is
   2843 				; full or the end of program is reached.
   2844 	JR	UNTIL_END	; loop back to UNTIL_END
   2845 
   2846 
   2847 ; THE 'PRINT A BASIC LINE' SUBROUTINE
   2848 
   2849 
   2850 mark_0745:
   2851 OUT_LINE:
   2852 	LD	BC,(E_PPC)	; sv
   2853 	CALL	CP_LINES
   2854 	LD	D,$92		;
   2855 	JR	Z,TEST_END
   2856 
   2857 	LD	DE,$0000	;
   2858 	RL	E		;
   2859 
   2860 mark_0755:
   2861 TEST_END:
   2862 	LD	(IY+BERG-RAMBASE),E
   2863 	LD	A,(HL)		;
   2864 	CP	$40		;
   2865 	POP	BC		;
   2866 	RET	NC		;
   2867 
   2868 	PUSH	BC		;
   2869 	CALL	OUT_NO
   2870 	INC	HL		;
   2871 	LD	A,D		;
   2872 
   2873 	RST	_PRINT_A
   2874 	INC	HL		;
   2875 	INC	HL		;
   2876 
   2877 mark_0766:
   2878 COPY_LINE:
   2879 	LD	(CH_ADD),HL	;
   2880 	SET	0,(IY+FLAGS-RAMBASE)	; Suppress leading space
   2881 
   2882 mark_076D:
   2883 MORE_LINE:
   2884 	LD	BC,(X_PTR)	;
   2885 	LD	HL,(CH_ADD)	;
   2886 	AND	A		;
   2887 	SBC	HL,BC		;
   2888 	JR	NZ,TEST_NUM
   2889 
   2890 	LD	A,ZX_INV_S	; $B8	; 
   2891 
   2892 	RST	_PRINT_A
   2893 
   2894 mark_077C:
   2895 TEST_NUM:
   2896 	LD	HL,(CH_ADD)	;
   2897 	LD	A,(HL)		;
   2898 	INC	HL		;
   2899 	CALL	NUMBER
   2900 	LD	(CH_ADD),HL	;
   2901 	JR	Z,MORE_LINE
   2902 
   2903 	CP	ZX_CURSOR	;
   2904 	JR	Z,OUT_CURS
   2905 
   2906 	CP	ZX_NEWLINE		;
   2907 	JR	Z,OUT_CH
   2908 
   2909 	BIT	6,A		;
   2910 	JR	Z,NOT_TOKEN
   2911 
   2912 	CALL	TOKENS
   2913 	JR	MORE_LINE
   2914 ; ___
   2915 
   2916 mark_079A:
   2917 NOT_TOKEN:
   2918 	RST	_PRINT_A
   2919 	JR	MORE_LINE
   2920 ; ___
   2921 
   2922 mark_079D:
   2923 OUT_CURS:
   2924 	LD	A,(MODE)	; Fetch value of system variable MODE
   2925 	LD	B,$AB		; Prepare an inverse [F] for function cursor.
   2926 
   2927 	AND	A		; Test for zero -
   2928 	JR	NZ,FLAGS_2	; forward if not to FLAGS_2
   2929 
   2930 	LD	A,(FLAGS)	; Fetch system variable FLAGS.
   2931 	LD	B,ZX_INV_K	; Prepare an inverse [K] for keyword cursor.
   2932 
   2933 mark_07AA:
   2934 FLAGS_2:
   2935 	RRA			; 00000?00 -> 000000?0
   2936 	RRA			; 000000?0 -> 0000000?
   2937 	AND	$01		; 0000000?	0000000x
   2938 
   2939 	ADD	A,B		; Possibly [F] -> [G]	or	[K] -> [L]
   2940 
   2941 	CALL	PRINT_SP
   2942 	JR	MORE_LINE
   2943 
   2944 
   2945 ; THE 'NUMBER' SUBROUTINE
   2946 
   2947 
   2948 mark_07B4:
   2949 NUMBER:
   2950 	CP	$7E		;
   2951 	RET	NZ		;
   2952 
   2953 	INC	HL		;
   2954 	INC	HL		;
   2955 	INC	HL		;
   2956 	INC	HL		;
   2957 	INC	HL		;
   2958 	RET			;
   2959 
   2960 
   2961 ; THE 'KEYBOARD DECODE' SUBROUTINE
   2962 
   2963 
   2964 mark_07BD:
   2965 DECODE:
   2966 	LD	D,0		;
   2967 	SRA	B		; shift bit from B to Carry
   2968 	SBC	A,A		; A = 0 - Carry
   2969 	OR	$26		; %00100110
   2970 	LD	L,5		;
   2971 	SUB	L		;
   2972 
   2973 mark_07C7:
   2974 KEY_LINE:
   2975 	ADD	A,L		;
   2976 	SCF			; Set Carry Flag
   2977 	RR	C		;
   2978 	JR	C,KEY_LINE
   2979 
   2980 	INC	C		;
   2981 	RET	NZ		;
   2982 
   2983 	LD	C,B		;
   2984 	DEC	L		;
   2985 	LD	L,1		;
   2986 	JR	NZ,KEY_LINE
   2987 
   2988 	LD	HL,$007D	; (expr reqd)
   2989 	LD	E,A		;
   2990 	ADD	HL,DE		;
   2991 	SCF			; Set Carry Flag
   2992 	RET			;
   2993 
   2994 
   2995 ; THE 'PRINTING' SUBROUTINE
   2996 
   2997 
   2998 mark_07DC:
   2999 LEAD_SP:
   3000 	LD	A,E		;
   3001 	AND	A		;
   3002 	RET	M		;
   3003 
   3004 	JR	PRINT_CH
   3005 
   3006 ; ___
   3007 ; HL is typically -10000, -1000, -100, -10 
   3008 ; and repeatedly subtracted from BC
   3009 ; i.e. it print
   3010 ;
   3011 ;
   3012 mark_07E1:
   3013 OUT_DIGIT:
   3014 	XOR	A		; assume the digit is zero to begin with
   3015 
   3016 mark_07E2:
   3017 DIGIT_INC:
   3018 	ADD	HL,BC		; HL += -ve number
   3019 	INC	A		;
   3020 	JR	C,DIGIT_INC	; loop
   3021 
   3022 	SBC	HL,BC		; undo last iteration
   3023 	DEC	A		; undo last iteration
   3024 	JR	Z,LEAD_SP	; leading zeros shown as spaces
   3025 
   3026 mark_07EB:
   3027 OUT_CODE:
   3028 	LD	E,ZX_0		; $1C
   3029 	ADD	A,E		;
   3030 
   3031 mark_07EE:
   3032 OUT_CH:
   3033 	AND	A		;
   3034 	JR	Z,PRINT_SP
   3035 
   3036 mark_07F1:
   3037 PRINT_CH:
   3038 	RES	0,(IY+FLAGS-RAMBASE)	; signal leading space permitted
   3039 
   3040 mark_07F5:
   3041 PRINT_SP:
   3042 	EXX			;
   3043 	PUSH	HL		;
   3044 	BIT	1,(IY+FLAGS-RAMBASE)	; is printer in use ?
   3045 	JR	NZ,LPRINT_A
   3046 
   3047 	CALL	ENTER_CH
   3048 	JR	PRINT_EXX
   3049 
   3050 ; ___
   3051 
   3052 mark_0802:
   3053 LPRINT_A:
   3054 	CALL	LPRINT_CH
   3055 
   3056 mark_0805:
   3057 PRINT_EXX:
   3058 	POP	HL		;
   3059 	EXX			;
   3060 	RET			;
   3061 
   3062 ; ___
   3063 
   3064 mark_0808:
   3065 ENTER_CH:
   3066 	LD	D,A		;
   3067 	LD	BC,(S_POSN)	;
   3068 	LD	A,C		;
   3069 	CP	CHARS_HORIZONTAL+1	;
   3070 	JR	Z,TEST_LOW
   3071 
   3072 mark_0812:
   3073 TEST_N_L:
   3074 	LD	A,ZX_NEWLINE		;
   3075 	CP	D		;
   3076 	JR	Z,WRITE_N_L
   3077 
   3078 	LD	HL,(DF_CC)	;
   3079 	CP	(HL)		;
   3080 	LD	A,D		;
   3081 	JR	NZ,WRITE_CH
   3082 
   3083 	DEC	C		;
   3084 	JR	NZ,EXPAND_1
   3085 
   3086 	INC	HL			;
   3087 	LD	(DF_CC),HL		;
   3088 	LD	C,CHARS_HORIZONTAL+1	; $21 = 33 normally
   3089 	DEC	B			;
   3090 	LD	(S_POSN),BC		;
   3091 
   3092 mark_082C:
   3093 TEST_LOW:
   3094 	LD	A,B		;
   3095 	CP	(IY+DF_SZ-RAMBASE)
   3096 	JR	Z,REPORT_5
   3097 
   3098 	AND	A		;
   3099 	JR	NZ,TEST_N_L
   3100 
   3101 mark_0835:
   3102 REPORT_5:
   3103 	LD	L,4		; 'No more room on screen'
   3104 	JP	ERROR_3
   3105 
   3106 ; ___
   3107 
   3108 mark_083A:
   3109 EXPAND_1:
   3110 	CALL	ONE_SPACE
   3111 	EX	DE,HL		;
   3112 
   3113 mark_083E:
   3114 WRITE_CH:
   3115 	LD	(HL),A		;
   3116 	INC	HL		;
   3117 	LD	(DF_CC),HL	;
   3118 	DEC	(IY+S_POSN_x-RAMBASE)
   3119 	RET			;
   3120 
   3121 ; ___
   3122 
   3123 mark_0847:
   3124 WRITE_N_L:
   3125 	LD	C,CHARS_HORIZONTAL+1	; $21 = 33
   3126 	DEC	B		;
   3127 	SET	0,(IY+FLAGS-RAMBASE)	; Suppress leading space
   3128 	JP	LOC_ADDR
   3129 
   3130 
   3131 ; THE 'LPRINT_CH' SUBROUTINE
   3132 
   3133 ; This routine sends a character to the ZX-Printer placing the code for the
   3134 ; character in the Printer Buffer.
   3135 ; Note. PR_CC contains the low byte of the buffer address. The high order byte 
   3136 ; is always constant. 
   3137 
   3138 
   3139 mark_0851:
   3140 LPRINT_CH:
   3141 	CP	ZX_NEWLINE	; compare to NEWLINE.
   3142 	JR	Z,COPY_BUFF	; forward if so
   3143 
   3144 	LD	C,A		; take a copy of the character in C.
   3145 	LD	A,(PR_CC)	; fetch print location from PR_CC
   3146 	AND	$7F		; ignore bit 7 to form true position.
   3147 	CP	$5C		; compare to 33rd location
   3148 
   3149 	LD	L,A		; form low-order byte.
   3150 	LD	H,$40		; the high-order byte is fixed.
   3151 
   3152 	CALL	Z,COPY_BUFF	; to send full buffer to 
   3153 				; the printer if first 32 bytes full.
   3154 				; (this will reset HL to start.)
   3155 
   3156 	LD	(HL),C		; place character at location.
   3157 	INC	L		; increment - will not cross a 256 boundary.
   3158 	LD	(IY+PR_CC-RAMBASE),L	; update system variable PR_CC
   3159 				; automatically resetting bit 7 to show that
   3160 				; the buffer is not empty.
   3161 	RET			; return.
   3162 
   3163 
   3164 ; THE 'COPY' COMMAND ROUTINE
   3165 
   3166 ; The full character-mapped screen is copied to the ZX-Printer.
   3167 ; All twenty-four text/graphic lines are printed.
   3168 
   3169 mark_0869:
   3170 COPY:
   3171 ;
   3172 ; check - is this $16==22 or 24?
   3173 ;
   3174 ;;	LD	D,$16		; prepare to copy twenty four text lines.
   3175 	LD	D,22		; prepare to copy twenty four text lines.
   3176 	LD	HL,(D_FILE)	; set HL to start of display file from D_FILE.
   3177 	INC	HL		; 
   3178 	JR	COPY_D		; forward
   3179 
   3180 ; ___
   3181 
   3182 ; A single character-mapped printer buffer is copied to the ZX-Printer.
   3183 
   3184 mark_0871:
   3185 COPY_BUFF:
   3186 	LD	D,1		; prepare to copy a single text line.
   3187 	LD	HL,PRBUFF	; set HL to start of printer buffer PRBUFF.
   3188 
   3189 ; both paths converge here.
   3190 
   3191 mark_0876:
   3192 COPY_D:
   3193 	CALL	SET_FAST
   3194 
   3195 	PUSH	BC		; *** preserve BC throughout.
   3196 				; a pending character may be present 
   3197 				; in C from LPRINT_CH
   3198 
   3199 mark_087A:
   3200 COPY_LOOP:
   3201 	PUSH	HL		; save first character of line pointer. (*)
   3202 	XOR	A		; clear accumulator.
   3203 	LD	E,A		; set pixel line count, range 0-7, to zero.
   3204 
   3205 ; this inner loop deals with each horizontal pixel line.
   3206 
   3207 mark_087D:
   3208 COPY_TIME:
   3209 	OUT	(IO_PORT_PRINTER),A	; bit 2 reset starts the printer motor
   3210 				; with an inactive stylus - bit 7 reset.
   3211 	POP	HL		; pick up first character of line pointer (*)
   3212 				; on inner loop.
   3213 
   3214 mark_0880:
   3215 COPY_BRK:
   3216 	CALL	BREAK_1
   3217 	JR	C,COPY_CONT	; forward with no keypress to COPY_CONT
   3218 
   3219 ; else A will hold 11111111 0
   3220 
   3221 	RRA			; 0111 1111
   3222 	OUT	(IO_PORT_PRINTER),A	; stop ZX printer motor, de-activate stylus.
   3223 
   3224 mark_0888:
   3225 REPORT_D2:
   3226 	RST	_ERROR_1
   3227 	DEFB	$0C		; Error Report: BREAK - CONT repeats
   3228 
   3229 ; ___
   3230 
   3231 mark_088A:
   3232 COPY_CONT:
   3233 	IN	A,(IO_PORT_PRINTER)	; read from printer port.
   3234 	ADD	A,A		; test bit 6 and 7
   3235 	JP	M,COPY_END	; jump forward with no printer to COPY_END
   3236 
   3237 	JR	NC,COPY_BRK	; back if stylus not in position to COPY_BRK
   3238 
   3239 	PUSH	HL		; save first character of line pointer (*)
   3240 	PUSH	DE		; ** preserve character line and pixel line.
   3241 
   3242 	LD	A,D		; text line count to A?
   3243 	CP	2		; sets carry if last line.
   3244 	SBC	A,A		; now $FF if last line else zero.
   3245 
   3246 ; now cleverly prepare a printer control mask setting bit 2 (later moved to 1)
   3247 ; of D to slow printer for the last two pixel lines ( E = 6 and 7)
   3248 
   3249 	AND	E		; and with pixel line offset 0-7
   3250 	RLCA			; shift to left.
   3251 	AND	E		; and again.
   3252 	LD	D,A		; store control mask in D.
   3253 
   3254 mark_089C:
   3255 COPY_NEXT:
   3256 	LD	C,(HL)		; load character from screen or buffer.
   3257 	LD	A,C		; save a copy in C for later inverse test.
   3258 	INC	HL		; update pointer for next time.
   3259 	CP	ZX_NEWLINE	; is character a NEWLINE ?
   3260 	JR	Z,COPY_N_L	; forward, if so, to COPY_N_L
   3261 
   3262 	PUSH	HL		; * else preserve the character pointer.
   3263 
   3264 	SLA	A		; (?) multiply by two
   3265 	ADD	A,A		; multiply by four
   3266 	ADD	A,A		; multiply by eight
   3267 
   3268 	LD	H,$0F		; load H with half the address of character set.
   3269 	RL	H		; now $1E or $1F (with carry)
   3270 	ADD	A,E		; add byte offset 0-7
   3271 	LD	L,A		; now HL addresses character source byte
   3272 
   3273 	RL	C		; test character, setting carry if inverse.
   3274 	SBC	A,A		; accumulator now $00 if normal, $FF if inverse.
   3275 
   3276 	XOR	(HL)		; combine with bit pattern at end or ROM.
   3277 	LD	C,A		; transfer the byte to C.
   3278 	LD	B,8		; count eight bits to output.
   3279 
   3280 mark_08B5:
   3281 COPY_BITS:
   3282 	LD	A,D		; fetch speed control mask from D.
   3283 	RLC	C		; rotate a bit from output byte to carry.
   3284 	RRA			; pick up in bit 7, speed bit to bit 1
   3285 	LD	H,A		; store aligned mask in H register.
   3286 
   3287 mark_08BA:
   3288 COPY_WAIT:
   3289 	IN	A,(IO_PORT_PRINTER)	; read the printer port
   3290 	RRA				; test for alignment signal from encoder.
   3291 	JR	NC,COPY_WAIT		; loop if not present to COPY_WAIT
   3292 
   3293 	LD	A,H			; control byte to A.
   3294 	OUT	(IO_PORT_PRINTER),A	; and output to printer port.
   3295 	DJNZ	COPY_BITS		; loop for all eight bits to COPY_BITS
   3296 
   3297 	POP	HL			; * restore character pointer.
   3298 	JR	COPY_NEXT		; back for adjacent character line to COPY_NEXT
   3299 
   3300 ; ___
   3301 
   3302 ; A NEWLINE has been encountered either following a text line or as the 
   3303 ; first character of the screen or printer line.
   3304 
   3305 mark_08C7:
   3306 COPY_N_L:
   3307 	IN	A,(IO_PORT_PRINTER)	; read printer port.
   3308 	RRA			; wait for encoder signal.
   3309 	JR	NC,COPY_N_L	; loop back if not to COPY_N_L
   3310 
   3311 	LD	A,D		; transfer speed mask to A.
   3312 	RRCA			; rotate speed bit to bit 1. 
   3313 				; bit 7, stylus control is reset.
   3314 	OUT	(IO_PORT_PRINTER),A	; set the printer speed.
   3315 
   3316 	POP	DE		; ** restore character line and pixel line.
   3317 	INC	E		; increment pixel line 0-7.
   3318 	BIT	3,E		; test if value eight reached.
   3319 	JR	Z,COPY_TIME	; back if not
   3320 
   3321 ; eight pixel lines, a text line have been completed.
   3322 
   3323 	POP	BC		; lose the now redundant first character 
   3324 				; pointer
   3325 	DEC	D		; decrease text line count.
   3326 	JR	NZ,COPY_LOOP	; back if not zero
   3327 
   3328 	LD	A,$04			; stop the already slowed printer motor.
   3329 	OUT	(IO_PORT_PRINTER),A	; output to printer port.
   3330 
   3331 mark_08DE:
   3332 COPY_END:
   3333 	CALL	SLOW_FAST
   3334 	POP	BC		; *** restore preserved BC.
   3335 
   3336 
   3337 ; THE 'CLEAR PRINTER BUFFER' SUBROUTINE
   3338 
   3339 ; This subroutine sets 32 bytes of the printer buffer to zero (space) and
   3340 ; the 33rd character is set to a NEWLINE.
   3341 ; This occurs after the printer buffer is sent to the printer but in addition
   3342 ; after the 24 lines of the screen are sent to the printer. 
   3343 ; Note. This is a logic error as the last operation does not involve the 
   3344 ; buffer at all. Logically one should be able to use 
   3345 ; 10 LPRINT "HELLO ";
   3346 ; 20 COPY
   3347 ; 30 LPRINT ; "WORLD"
   3348 ; and expect to see the entire greeting emerge from the printer.
   3349 ; Surprisingly this logic error was never discovered and although one can argue
   3350 ; if the above is a bug, the repetition of this error on the Spectrum was most
   3351 ; definitely a bug.
   3352 ; Since the printer buffer is fixed at the end of the system variables, and
   3353 ; the print position is in the range $3C - $5C, then bit 7 of the system
   3354 ; variable is set to show the buffer is empty and automatically reset when
   3355 ; the variable is updated with any print position - neat.
   3356 
   3357 mark_08E2:
   3358 CLEAR_PRB:
   3359 	LD	HL,PRBUFF_END	; address fixed end of PRBUFF
   3360 	LD	(HL),ZX_NEWLINE	; place a newline at last position.
   3361 	LD	B,32		; prepare to blank 32 preceding characters. 
   3362 ;
   3363 ; NB the printer is fixed at 32 characters, maybe it can be tweaked ???
   3364 ;
   3365 mark_08E9:
   3366 PRB_BYTES:
   3367 	DEC	HL		; decrement address - could be DEC L.
   3368 	LD	(HL),0		; place a zero byte.
   3369 	DJNZ	PRB_BYTES	; loop for all thirty-two
   3370 
   3371 	LD	A,L		; fetch character print position.
   3372 	SET	7,A		; signal the printer buffer is clear.
   3373 	LD	(PR_CC),A	; update one-byte system variable PR_CC
   3374 	RET			; return.
   3375 
   3376 
   3377 ; THE 'PRINT AT' SUBROUTINE
   3378 
   3379 ;
   3380 ;
   3381 ;
   3382 mark_08F5:
   3383 PRINT_AT:
   3384 
   3385 	LD	A,CHARS_VERTICAL-1	; originally 23
   3386 	SUB	B		;
   3387 	JR	C,WRONG_VAL
   3388 
   3389 mark_08FA:
   3390 TEST_VAL:
   3391 	CP	(IY+DF_SZ-RAMBASE)
   3392 	JP	C,REPORT_5
   3393 
   3394 	INC	A		;
   3395 	LD	B,A		;
   3396 	LD	A,CHARS_HORIZONTAL-1	; originally 31
   3397 
   3398 	SUB	C		;
   3399 
   3400 mark_0905:
   3401 WRONG_VAL:
   3402 	JP	C,REPORT_B
   3403 
   3404 	ADD	A,2		;
   3405 	LD	C,A		;
   3406 
   3407 mark_090B:
   3408 SET_FIELD:
   3409 	BIT	1,(IY+FLAGS-RAMBASE)	; Is printer in use?
   3410 	JR	Z,LOC_ADDR
   3411 
   3412 	LD	A,$5D		;
   3413 	SUB	C		;
   3414 	LD	(PR_CC),A	;
   3415 	RET			;
   3416 
   3417 
   3418 ; THE 'LOCATE ADDRESS' ROUTINE
   3419 
   3420 ;
   3421 ; I'm guessing this locates the address of a character at X,Y 
   3422 ; on the screen, with 0,0 being on the bottom left?
   3423 ; S_POSN_x:    equ $4039
   3424 ; S_POSN_y:    equ $403A
   3425 ; so when BC is stored there, B is Y and C is X
   3426 ;
   3427 mark_0918:
   3428 LOC_ADDR:
   3429 	LD	(S_POSN),BC	;
   3430 	LD	HL,(VARS)	;
   3431 	LD	D,C		;
   3432 	LD	A,CHARS_HORIZONTAL+2	; $22 == 34 originally.
   3433 	SUB	C		;
   3434 	LD	C,A		;
   3435 	LD	A,ZX_NEWLINE	;
   3436 	INC	B		;
   3437 
   3438 mark_0927:
   3439 LOOK_BACK:
   3440 	DEC	HL		;
   3441 	CP	(HL)		;
   3442 	JR	NZ,LOOK_BACK
   3443 
   3444 	DJNZ	LOOK_BACK
   3445 
   3446 	INC	HL		;
   3447 	CPIR			;
   3448 	DEC	HL		;
   3449 	LD	(DF_CC),HL	;
   3450 	SCF			; Set Carry Flag
   3451 	RET	PO		;
   3452 
   3453 	DEC	D		;
   3454 	RET	Z		;
   3455 
   3456 	PUSH	BC		;
   3457 	CALL	MAKE_ROOM
   3458 	POP	BC		;
   3459 	LD	B,C		;
   3460 	LD	H,D		; HL := DE
   3461 	LD	L,E		;
   3462 
   3463 mark_0940:
   3464 EXPAND_2:
   3465 ;
   3466 ; Writes B spaces to HL--
   3467 ;
   3468 	LD	(HL),ZX_SPACE	;
   3469 	DEC	HL		;
   3470 	DJNZ	EXPAND_2
   3471 
   3472 	EX	DE,HL		; restore HL
   3473 	INC	HL		;
   3474 	LD	(DF_CC),HL	;
   3475 	RET			;
   3476 
   3477 
   3478 ; THE 'EXPAND TOKENS' SUBROUTINE
   3479 
   3480 
   3481 mark_094B:
   3482 TOKENS:
   3483 	PUSH	AF		;
   3484 	CALL	TOKEN_ADD
   3485 	JR	NC,ALL_CHARS
   3486 
   3487 	BIT	0,(IY+FLAGS-RAMBASE)	; Leading space if set
   3488 	JR	NZ,ALL_CHARS
   3489 
   3490 	XOR	A		; A = 0 = ZX_SPACE
   3491 
   3492 	RST	_PRINT_A
   3493 
   3494 mark_0959:
   3495 ALL_CHARS:
   3496 	LD	A,(BC)		;
   3497 	AND	$3F		; truncate to printable values ???
   3498 
   3499 	RST	_PRINT_A
   3500 	LD	A,(BC)		;
   3501 	INC	BC		;
   3502 	ADD	A,A		;
   3503 	JR	NC,ALL_CHARS
   3504 
   3505 	POP	BC		;
   3506 	BIT	7,B		;
   3507 	RET	Z		;
   3508 
   3509 	CP	ZX_COMMA	; $1A == 26
   3510 	JR	Z,TRAIL_SP
   3511 
   3512 	CP	ZX_S		; $38 == 56
   3513 	RET	C		;
   3514 
   3515 mark_096D:
   3516 TRAIL_SP:
   3517 	XOR	A		;
   3518 	SET	0,(IY+FLAGS-RAMBASE)	; Suppress leading space
   3519 	JP	PRINT_SP
   3520 
   3521 ; ___
   3522 
   3523 mark_0975:
   3524 TOKEN_ADD:
   3525 	PUSH	HL		;
   3526 	LD	HL,TOKEN_TABLE
   3527 	BIT	7,A		;
   3528 	JR	Z,TEST_HIGH
   3529 
   3530 	AND	$3F		;
   3531 
   3532 mark_097F:
   3533 TEST_HIGH:
   3534 	CP	$43		;
   3535 	JR	NC,FOUND
   3536 
   3537 	LD	B,A		;
   3538 	INC	B		;
   3539 
   3540 mark_0985:
   3541 WORDS:
   3542 	BIT	7,(HL)		;
   3543 	INC	HL		;
   3544 	JR	Z,WORDS
   3545 
   3546 	DJNZ	WORDS
   3547 
   3548 	BIT	6,A		;
   3549 	JR	NZ,COMP_FLAG
   3550 
   3551 	CP	$18		;
   3552 
   3553 mark_0992:
   3554 COMP_FLAG:
   3555 	CCF			; Complement Carry Flag
   3556 
   3557 mark_0993:
   3558 FOUND:
   3559 	LD	B,H		;
   3560 	LD	C,L		;
   3561 	POP	HL		;
   3562 	RET	NC		;
   3563 
   3564 	LD	A,(BC)		;
   3565 	ADD	A,$E4		;
   3566 	RET			;
   3567 
   3568 
   3569 ; THE 'ONE_SPACE' SUBROUTINE
   3570 
   3571 
   3572 mark_099B:
   3573 ONE_SPACE:
   3574 	LD	BC,$0001	;
   3575 
   3576 
   3577 ; THE 'MAKE ROOM' SUBROUTINE
   3578 
   3579 ;
   3580 ;
   3581 
   3582 mark_099E:
   3583 MAKE_ROOM:
   3584 	PUSH	HL		;
   3585 	CALL	TEST_ROOM
   3586 	POP	HL		;
   3587 	CALL	POINTERS
   3588 	LD	HL,(STKEND)	;
   3589 	EX	DE,HL		;
   3590 	LDDR			; Copy Bytes
   3591 	RET			;
   3592 
   3593 
   3594 ; THE 'POINTERS' SUBROUTINE
   3595 
   3596 
   3597 mark_09AD:
   3598 POINTERS:
   3599 	PUSH	AF		;
   3600 	PUSH	HL		;
   3601 	LD	HL,D_FILE	;
   3602 	LD	A,$09		;
   3603 
   3604 mark_09B4:
   3605 NEXT_PTR:
   3606 	LD	E,(HL)		;
   3607 	INC	HL		;
   3608 	LD	D,(HL)		;
   3609 	EX	(SP),HL	;
   3610 	AND	A		;
   3611 	SBC	HL,DE		;
   3612 	ADD	HL,DE		;
   3613 	EX	(SP),HL	;
   3614 	JR	NC,PTR_DONE
   3615 
   3616 	PUSH	DE		;
   3617 	EX	DE,HL		;
   3618 	ADD	HL,BC		;
   3619 	EX	DE,HL		;
   3620 	LD	(HL),D		;
   3621 	DEC	HL		;
   3622 	LD	(HL),E		;
   3623 	INC	HL		;
   3624 	POP	DE		;
   3625 
   3626 mark_09C8:
   3627 PTR_DONE:
   3628 	INC	HL		;
   3629 	DEC	A		;
   3630 	JR	NZ,NEXT_PTR
   3631 
   3632 	EX	DE,HL		;
   3633 	POP	DE		;
   3634 	POP	AF		;
   3635 	AND	A		;
   3636 	SBC	HL,DE		;
   3637 	LD	B,H		;
   3638 	LD	C,L		;
   3639 	INC	BC		;
   3640 	ADD	HL,DE		;
   3641 	EX	DE,HL		;
   3642 	RET			;
   3643 
   3644 
   3645 ; THE 'LINE ADDRESS' SUBROUTINE
   3646 
   3647 
   3648 mark_09D8:
   3649 LINE_ADDR:
   3650 	PUSH	HL		;
   3651 	LD	HL,USER_RAM	;
   3652 	LD	D,H		;
   3653 	LD	E,L		;
   3654 
   3655 mark_09DE:
   3656 NEXT_TEST:
   3657 	POP	BC		;
   3658 	CALL	CP_LINES
   3659 	RET	NC		;
   3660 
   3661 	PUSH	BC		;
   3662 	CALL	NEXT_ONE
   3663 	EX	DE,HL		;
   3664 	JR	NEXT_TEST
   3665 
   3666 
   3667 ; THE 'COMPARE LINE NUMBERS' SUBROUTINE
   3668 
   3669 
   3670 mark_09EA:
   3671 CP_LINES:
   3672 	LD	A,(HL)		;
   3673 	CP	B		;
   3674 	RET	NZ		;
   3675 
   3676 	INC	HL		;
   3677 	LD	A,(HL)		;
   3678 	DEC	HL		;
   3679 	CP	C		;
   3680 	RET			;
   3681 
   3682 
   3683 ; THE 'NEXT LINE OR VARIABLE' SUBROUTINE
   3684 
   3685 
   3686 mark_09F2:
   3687 NEXT_ONE:
   3688 	PUSH	HL		;
   3689 	LD	A,(HL)		;
   3690 	CP	$40		;
   3691 	JR	C,LINES
   3692 
   3693 	BIT	5,A		;
   3694 	JR	Z,NEXT_0_4	; skip forward
   3695 
   3696 	ADD	A,A		;
   3697 	JP	M,NEXT_PLUS_FIVE
   3698 
   3699 	CCF			; Complement Carry Flag
   3700 
   3701 mark_0A01:
   3702 NEXT_PLUS_FIVE:
   3703 	LD	BC,$0005	;
   3704 	JR	NC,NEXT_LETT
   3705 
   3706 	LD	C,$11		; 17
   3707 
   3708 mark_0A08:
   3709 NEXT_LETT:
   3710 	RLA			;
   3711 	INC	HL		;
   3712 	LD	A,(HL)		;
   3713 	JR	NC,NEXT_LETT	; loop 
   3714 
   3715 	JR	NEXT_ADD
   3716 ; ___
   3717 
   3718 mark_0A0F:
   3719 LINES:
   3720 	INC	HL		;
   3721 
   3722 mark_0A10:
   3723 NEXT_0_4:
   3724 	INC	HL		; BC = word at HL++
   3725 	LD	C,(HL)		;
   3726 	INC	HL		;
   3727 	LD	B,(HL)		;
   3728 	INC	HL		;
   3729 
   3730 mark_0A15:
   3731 NEXT_ADD:
   3732 	ADD	HL,BC		;
   3733 	POP	DE		;
   3734 
   3735 
   3736 ; THE 'DIFFERENCE' SUBROUTINE
   3737 
   3738 
   3739 mark_0A17:
   3740 DIFFER:
   3741 	AND	A		;
   3742 	SBC	HL,DE		;
   3743 	LD	B,H		; BC := (HL-DE)
   3744 	LD	C,L		;
   3745 	ADD	HL,DE		;
   3746 	EX	DE,HL		; DE := old HL ???
   3747 	RET			;
   3748 
   3749 
   3750 ; THE 'LINE_ENDS' SUBROUTINE
   3751 
   3752 
   3753 mark_0A1F:
   3754 LINE_ENDS:
   3755 	LD	B,(IY+DF_SZ-RAMBASE)
   3756 	PUSH	BC		;
   3757 	CALL	B_LINES
   3758 	POP	BC		;
   3759 	DEC	B		;
   3760 	JR	B_LINES
   3761 
   3762 
   3763 ; THE 'CLS' COMMAND ROUTINE
   3764 
   3765 
   3766 mark_0A2A:
   3767 CLS:
   3768 	LD	B,CHARS_VERTICAL	; number of lines to clear. $18 = 24 originally.
   3769 
   3770 mark_0A2C:
   3771 B_LINES:
   3772 	RES	1,(IY+FLAGS-RAMBASE)	; Signal printer not in use
   3773 	LD	C,CHARS_HORIZONTAL+1	; $21		; extra 1 is for HALT opcode ?
   3774 	PUSH	BC		;
   3775 	CALL	LOC_ADDR
   3776 	POP	BC		;
   3777 	LD	A,(RAMTOP+1)	; is RAMTOP_hi
   3778 	CP	$4D		;
   3779 	JR	C,COLLAPSED
   3780 ;
   3781 ; If RAMTOP less then 4D00, RAM less than D00 = 3.25 K, 
   3782 ; uses collapsed display.
   3783 ;
   3784 
   3785 	SET	7,(IY+S_POSN_y-RAMBASE)
   3786 
   3787 mark_0A42:
   3788 CLEAR_LOC:
   3789 	XOR	A		; prepare a space
   3790 	CALL	PRINT_SP	; prints a space
   3791 	LD	HL,(S_POSN)	;
   3792 	LD	A,L		;
   3793 	OR	H		;
   3794 	AND	$7E		; 
   3795 	JR	NZ,CLEAR_LOC
   3796 
   3797 	JP	LOC_ADDR
   3798 
   3799 ; ___
   3800 
   3801 mark_0A52:
   3802 COLLAPSED:
   3803 	LD	D,H		; DE := HL
   3804 	LD	E,L		;
   3805 	DEC	HL		;
   3806 	LD	C,B		;
   3807 	LD	B,0		; Will loop 256 times
   3808 	LDIR			; Copy Bytes
   3809 	LD	HL,(VARS)	;
   3810 
   3811 
   3812 ; THE 'RECLAIMING' SUBROUTINES
   3813 
   3814 
   3815 mark_0A5D:
   3816 RECLAIM_1:
   3817 	CALL	DIFFER
   3818 
   3819 mark_0A60:
   3820 RECLAIM_2:
   3821 	PUSH	BC		;
   3822 	LD	A,B		;
   3823 	CPL			;
   3824 	LD	B,A		;
   3825 	LD	A,C		;
   3826 	CPL			;
   3827 	LD	C,A		;
   3828 	INC	BC		;
   3829 	CALL	POINTERS
   3830 	EX	DE,HL		;
   3831 	POP	HL		;
   3832 	ADD	HL,DE		;
   3833 	PUSH	DE		;
   3834 	LDIR			; Copy Bytes
   3835 	POP	HL		;
   3836 	RET			;
   3837 
   3838 
   3839 ; THE 'E_LINE NUMBER' SUBROUTINE
   3840 
   3841 
   3842 mark_0A73:
   3843 E_LINE_NUM:
   3844 	LD	HL,(E_LINE)	;
   3845 	CALL	TEMP_PTR2
   3846 
   3847 	RST	_GET_CHAR
   3848 	BIT	5,(IY+FLAGX-RAMBASE)
   3849 	RET	NZ		;
   3850 
   3851 	LD	HL,MEM_0_1st	;
   3852 	LD	(STKEND),HL	;
   3853 	CALL	INT_TO_FP
   3854 	CALL	FP_TO_BC
   3855 	JR	C,NO_NUMBER	; to NO_NUMBER
   3856 
   3857 	LD	HL,-10000	; $D8F0	; value '-10000'
   3858 	ADD	HL,BC		;
   3859 
   3860 mark_0A91:
   3861 NO_NUMBER:
   3862 	JP	C,REPORT_C	; to REPORT_C
   3863 
   3864 	CP	A		;
   3865 	JP	SET_MIN
   3866 
   3867 
   3868 ; THE 'REPORT AND LINE NUMBER' PRINTING SUBROUTINES
   3869 
   3870 
   3871 mark_0A98:
   3872 OUT_NUM:
   3873 	PUSH	DE		;
   3874 	PUSH	HL		;
   3875 	XOR	A		;
   3876 	BIT	7,B		;
   3877 	JR	NZ,UNITS
   3878 
   3879 	LD	H,B		; HL := BC
   3880 	LD	L,C		;
   3881 	LD	E,$FF		;
   3882 	JR	THOUSAND
   3883 ; ___
   3884 
   3885 mark_0AA5:
   3886 OUT_NO:
   3887 	PUSH	DE		;
   3888 	LD	D,(HL)		;
   3889 	INC	HL		;
   3890 	LD	E,(HL)		;
   3891 	PUSH	HL		;
   3892 	EX	DE,HL		;
   3893 	LD	E,ZX_SPACE	; set E to leading space.
   3894 
   3895 mark_0AAD:
   3896 THOUSAND:
   3897 	LD	BC,-1000	; $FC18	;
   3898 	CALL	OUT_DIGIT
   3899 	LD	BC,-100		; $FF9C	;
   3900 	CALL	OUT_DIGIT
   3901 	LD	C,-10		; $F6		; B is already FF, so saves a byte.
   3902 	CALL	OUT_DIGIT
   3903 	LD	A,L		;
   3904 
   3905 mark_0ABF:
   3906 UNITS:
   3907 	CALL	OUT_CODE
   3908 	POP	HL		;
   3909 	POP	DE		;
   3910 	RET			;
   3911 
   3912 
   3913 ; THE 'UNSTACK_Z' SUBROUTINE
   3914 
   3915 
   3916 ; This subroutine is used to return early from a routine when checking syntax.
   3917 ; On the ZX81 the same routines that execute commands also check the syntax
   3918 ; on line entry. This enables precise placement of the error marker in a line
   3919 ; that fails syntax.
   3920 ; The sequence CALL SYNTAX_Z ; RET Z can be replaced by a call to this routine
   3921 ; although it has not replaced every occurrence of the above two instructions.
   3922 ; Even on the ZX80 this routine was not fully utilized.
   3923 
   3924 mark_0AC5:
   3925 UNSTACK_Z:
   3926 	CALL	SYNTAX_Z		; resets the ZERO flag if
   3927 				; checking syntax.
   3928 	POP	HL		; drop the return address.
   3929 	RET	Z		; return to previous calling routine if 
   3930 				; checking syntax.
   3931 
   3932 	JP	(HL)		; else jump to the continuation address in
   3933 				; the calling routine as RET would have done.
   3934 
   3935 
   3936 ; THE 'LPRINT' COMMAND ROUTINE
   3937 
   3938 ;
   3939 ;
   3940 
   3941 mark_0ACB:
   3942 LPRINT:
   3943 	SET	1,(IY+FLAGS-RAMBASE)	; Signal printer in use
   3944 
   3945 
   3946 ; THE 'PRINT' COMMAND ROUTINE
   3947 
   3948 
   3949 mark_0ACF:
   3950 PRINT:
   3951 	LD	A,(HL)		;
   3952 	CP	ZX_NEWLINE		;
   3953 	JP	Z,PRINT_END	; to PRINT_END
   3954 
   3955 mark_0AD5:
   3956 PRINT_1:
   3957 	SUB	ZX_COMMA	; $1A == 26
   3958 	ADC	A,$00		; 
   3959 	JR	Z,SPACING	; to SPACING
   3960 				; 
   3961 				; Compare with AT, 
   3962 				; less comma recently subtracted.
   3963 				; 
   3964 	CP	ZX_AT-ZX_COMMA	; $A7 == 167
   3965 	JR	NZ,NOT_AT	;
   3966 
   3967 
   3968 	RST	_NEXT_CHAR
   3969 	CALL	CLASS_6
   3970 	CP	ZX_COMMA	; $1A = 26
   3971 	JP	NZ,REPORT_C	;
   3972 
   3973 	RST	_NEXT_CHAR
   3974 	CALL	CLASS_6
   3975 	CALL	SYNTAX_ON
   3976 
   3977 	RST	_FP_CALC	;;
   3978 	DEFB	__exchange	;;
   3979 	DEFB	__end_calc	;;
   3980 
   3981 	CALL	STK_TO_BC
   3982 	CALL	PRINT_AT
   3983 	JR	PRINT_ON
   3984 ; ___
   3985 
   3986 mark_0AFA:
   3987 NOT_AT:
   3988 	CP	ZX_TAB-ZX_COMMA	; $A8 == 168
   3989 	JR	NZ,NOT_TAB
   3990 
   3991 
   3992 	RST	_NEXT_CHAR
   3993 	CALL	CLASS_6
   3994 	CALL	SYNTAX_ON
   3995 	CALL	STK_TO_A
   3996 	JP	NZ,REPORT_B
   3997 
   3998 	AND	$1F		; truncate to 0 to 31 characters ???
   3999 	LD	C,A		;
   4000 	BIT	1,(IY+FLAGS-RAMBASE)	; Is printer in use
   4001 	JR	Z,TAB_TEST
   4002 
   4003 	SUB	(IY+PR_CC-RAMBASE)
   4004 	SET	7,A		;
   4005 	ADD	A,$3C		; 60
   4006 	CALL	NC,COPY_BUFF
   4007 
   4008 mark_0B1E:
   4009 TAB_TEST:
   4010 	ADD	A,(IY+S_POSN_x-RAMBASE)	; screen position X
   4011 	CP	CHARS_HORIZONTAL+1	; 33 (characters horizontal plus newline ???)
   4012 	LD	A,(S_POSN_y)		; screen position Y
   4013 	SBC	A,1			;
   4014 	CALL	TEST_VAL
   4015 	SET	0,(IY+FLAGS-RAMBASE)	; sv FLAGS	- Suppress leading space
   4016 	JR	PRINT_ON
   4017 ; ___
   4018 
   4019 mark_0B31:
   4020 NOT_TAB:
   4021 	CALL	SCANNING
   4022 	CALL	PRINT_STK
   4023 
   4024 mark_0B37:
   4025 PRINT_ON:
   4026 	RST	_GET_CHAR
   4027 	SUB	ZX_COMMA	;  $1A
   4028 	ADC	A,0		;
   4029 	JR	Z,SPACING
   4030 
   4031 	CALL	CHECK_END
   4032 	JP	PRINT_END
   4033 ; ___
   4034 mark_0B44:
   4035 SPACING:
   4036 	CALL	NC,FIELD
   4037 
   4038 	RST	_NEXT_CHAR
   4039 	CP	ZX_NEWLINE	;
   4040 	RET	Z		;
   4041 
   4042 	JP	PRINT_1
   4043 ; ___
   4044 mark_0B4E:
   4045 SYNTAX_ON:
   4046 	CALL	SYNTAX_Z
   4047 	RET	NZ		;
   4048 
   4049 	POP	HL		;
   4050 	JR	PRINT_ON
   4051 ; ___
   4052 mark_0B55:
   4053 PRINT_STK:
   4054 	CALL	UNSTACK_Z
   4055 	BIT	6,(IY+FLAGS-RAMBASE)	; Numeric or string result?
   4056 	CALL	Z,STK_FETCH
   4057 	JR	Z,PR_STR_4
   4058 
   4059 	JP	PRINT_FP		; jump forward
   4060 ; ___
   4061 
   4062 mark_0B64:
   4063 PR_STR_1:
   4064 	LD	A,ZX_QUOTE	; $0B
   4065 
   4066 mark_0B66:
   4067 PR_STR_2:
   4068 	RST	_PRINT_A
   4069 
   4070 mark_0B67:
   4071 PR_STR_3:
   4072 	LD	DE,(X_PTR)	;
   4073 
   4074 mark_0B6B:
   4075 PR_STR_4:
   4076 	LD	A,B		;
   4077 	OR	C		;
   4078 	DEC	BC		;
   4079 	RET	Z		;
   4080 
   4081 	LD	A,(DE)		;
   4082 	INC	DE		;
   4083 	LD	(X_PTR),DE	;
   4084 	BIT	6,A		;
   4085 	JR	Z,PR_STR_2
   4086 
   4087 	CP	$C0		;
   4088 	JR	Z,PR_STR_1
   4089 
   4090 	PUSH	BC		;
   4091 	CALL	TOKENS
   4092 	POP	BC		;
   4093 	JR	PR_STR_3
   4094 
   4095 ; ___
   4096 
   4097 mark_0B84:
   4098 PRINT_END:
   4099 	CALL	UNSTACK_Z
   4100 	LD	A,ZX_NEWLINE		;
   4101 
   4102 	RST	_PRINT_A
   4103 	RET			;
   4104 
   4105 ; ___
   4106 
   4107 mark_0B8B:
   4108 FIELD:
   4109 	CALL	UNSTACK_Z
   4110 	SET	0,(IY+FLAGS-RAMBASE)	; Suppress leading space
   4111 	XOR	A		;
   4112 
   4113 	RST	_PRINT_A
   4114 	LD	BC,(S_POSN)	;
   4115 	LD	A,C		;
   4116 	BIT	1,(IY+FLAGS-RAMBASE)	; Is printer in use
   4117 	JR	Z,CENTRE
   4118 
   4119 	LD	A,$5D		;
   4120 	SUB	(IY+PR_CC-RAMBASE)
   4121 
   4122 mark_0BA4:
   4123 CENTRE:
   4124 	LD	C,$11		;
   4125 	CP	C		;
   4126 	JR	NC,RIGHT
   4127 
   4128 	LD	C,$01		;
   4129 
   4130 mark_0BAB:
   4131 RIGHT:
   4132 	CALL	SET_FIELD
   4133 	RET			;
   4134 
   4135 
   4136 ; THE 'PLOT AND UNPLOT' COMMAND ROUTINES
   4137 
   4138 
   4139 mark_0BAF:
   4140 PLOT_UNPLOT:
   4141 ;
   4142 ; Of the 24 lines, only top 22 ar used for plotting.
   4143 ;
   4144 	CALL	STK_TO_BC
   4145 	LD	(COORDS_x),BC	;
   4146 ;;	LD	A,$2B		; originally $2B == 32+11 = 43 = 2*22-1
   4147 	LD	A,2*(CHARS_VERTICAL-2)-1	; 
   4148 	SUB	B		;
   4149 	JP	C,REPORT_B
   4150 
   4151 	LD	B,A		;
   4152 	LD	A,$01		;
   4153 	SRA	B		;
   4154 	JR	NC,COLUMNS
   4155 
   4156 	LD	A,$04		;
   4157 
   4158 mark_0BC5:
   4159 COLUMNS:
   4160 	SRA	C		;
   4161 	JR	NC,FIND_ADDR
   4162 
   4163 	RLCA			;
   4164 
   4165 mark_0BCA:
   4166 FIND_ADDR:
   4167 	PUSH	AF		;
   4168 	CALL	PRINT_AT
   4169 	LD	A,(HL)		;
   4170 	RLCA			;
   4171 	CP	ZX_BRACKET_LEFT	; $10
   4172 	JR	NC,TABLE_PTR
   4173 
   4174 	RRCA			;
   4175 	JR	NC,SQ_SAVED
   4176 
   4177 	XOR	$8F		;
   4178 
   4179 mark_0BD9:
   4180 SQ_SAVED:
   4181 	LD	B,A		;
   4182 
   4183 mark_0BDA:
   4184 TABLE_PTR:
   4185 	LD	DE,P_UNPLOT	; Address: P_UNPLOT
   4186 	LD	A,(T_ADDR)	; get T_ADDR_lo
   4187 	SUB	E		;
   4188 	JP	M,PLOT
   4189 
   4190 	POP	AF		;
   4191 	CPL			;
   4192 	AND	B		;
   4193 	JR	UNPLOT
   4194 
   4195 ; ___
   4196 
   4197 mark_0BE9:
   4198 PLOT:
   4199 	POP	AF		;
   4200 	OR	B		;
   4201 
   4202 mark_0BEB:
   4203 UNPLOT:
   4204 	CP	8		; Only apply to graphic characters (0 to 7)
   4205 	JR	C,PLOT_END
   4206 
   4207 	XOR	$8F		; binary 1000 1111
   4208 
   4209 mark_0BF1:
   4210 PLOT_END:
   4211 	EXX			;
   4212 
   4213 	RST	_PRINT_A
   4214 	EXX			;
   4215 	RET			;
   4216 
   4217 
   4218 ; THE 'STACK_TO_BC' SUBROUTINE
   4219 
   4220 mark_0BF5:
   4221 STK_TO_BC:
   4222 	CALL	STK_TO_A
   4223 	LD	B,A		;
   4224 	PUSH	BC		;
   4225 	CALL	STK_TO_A
   4226 	LD	E,C		;
   4227 	POP	BC		;
   4228 	LD	D,C		;
   4229 	LD	C,A		;
   4230 	RET			;
   4231 
   4232 
   4233 ; THE 'STACK_TO_A' SUBROUTINE
   4234 
   4235 
   4236 mark_0C02:
   4237 STK_TO_A:
   4238 	CALL	FP_TO_A
   4239 	JP	C,REPORT_B
   4240 
   4241 	LD	C,$01		; 
   4242 	RET	Z		;
   4243 
   4244 	LD	C,$FF		;
   4245 	RET			;
   4246 
   4247 
   4248 ; THE 'SCROLL' SUBROUTINE
   4249 
   4250 
   4251 mark_0C0E:
   4252 SCROLL:
   4253 	LD	B,(IY+DF_SZ-RAMBASE)
   4254 	LD	C,CHARS_HORIZONTAL+1		;
   4255 	CALL	LOC_ADDR
   4256 	CALL	ONE_SPACE
   4257 	LD	A,(HL)		;
   4258 	LD	(DE),A		;
   4259 	INC	(IY+S_POSN_y-RAMBASE)
   4260 	LD	HL,(D_FILE)	;
   4261 	INC	HL		;
   4262 	LD	D,H		;
   4263 	LD	E,L		;
   4264 	CPIR			;
   4265 	JP	RECLAIM_1
   4266 
   4267 
   4268 ; THE 'SYNTAX' TABLES
   4269 
   4270 
   4271 ; i) The Offset table
   4272 
   4273 mark_0C29:
   4274 offset_t:
   4275 	DEFB	P_LPRINT - $	; 8B offset
   4276 	DEFB	P_LLIST - $	; 8D offset
   4277 	DEFB	P_STOP - $	; 2D offset
   4278 	DEFB	P_SLOW - $	; 7F offset
   4279 	DEFB	P_FAST - $	; 81 offset
   4280 	DEFB	P_NEW - $	; 49 offset
   4281 	DEFB	P_SCROLL - $	; 75 offset
   4282 	DEFB	P_CONT - $	; 5F offset
   4283 	DEFB	P_DIM - $	; 40 offset
   4284 	DEFB	P_REM - $	; 42 offset
   4285 	DEFB	P_FOR - $	; 2B offset
   4286 	DEFB	P_GOTO - $	; 17 offset
   4287 	DEFB	P_GOSUB - $	; 1F offset
   4288 	DEFB	P_INPUT - $	; 37 offset
   4289 	DEFB	P_LOAD - $	; 52 offset
   4290 	DEFB	P_LIST - $	; 45 offset
   4291 	DEFB	P_LET - $	; 0F offset
   4292 	DEFB	P_PAUSE - $	; 6D offset
   4293 	DEFB	P_NEXT - $	; 2B offset
   4294 	DEFB	P_POKE - $	; 44 offset
   4295 	DEFB	P_PRINT - $	; 2D offset
   4296 	DEFB	P_PLOT - $	; 5A offset
   4297 	DEFB	P_RUN - $	; 3B offset
   4298 	DEFB	P_SAVE - $	; 4C offset
   4299 	DEFB	P_RAND - $	; 45 offset
   4300 	DEFB	P_IF - $	; 0D offset
   4301 	DEFB	P_CLS - $	; 52 offset
   4302 	DEFB	P_UNPLOT - $	; 5A offset
   4303 	DEFB	P_CLEAR - $	; 4D offset
   4304 	DEFB	P_RETURN - $	; 15 offset
   4305 	DEFB	P_COPY - $	; 6A offset
   4306 
   4307 ; ii) The parameter table.
   4308 
   4309 mark_0C48:
   4310 P_LET:
   4311 	DEFB	_CLASS_01	; A variable is required.
   4312 	DEFB	ZX_EQUAL	; Separator:	'='
   4313 	DEFB	_CLASS_02	; An expression, numeric or string,
   4314 				; must follow.
   4315 
   4316 mark_0C4B:
   4317 P_GOTO:
   4318 	DEFB	_CLASS_06	; A numeric expression must follow.
   4319 	DEFB	_CLASS_00	; No further operands.
   4320 	DEFW	GOTO
   4321 
   4322 mark_0C4F:
   4323 P_IF:
   4324 	DEFB	_CLASS_06	; A numeric expression must follow.
   4325 	DEFB	ZX_THEN		; Separator:	'THEN'
   4326 	DEFB	_CLASS_05	; Variable syntax checked entirely
   4327 				; by routine.
   4328 	DEFW	IF
   4329 
   4330 mark_0C54:
   4331 P_GOSUB:
   4332 	DEFB	_CLASS_06	; A numeric expression must follow.
   4333 	DEFB	_CLASS_00	; No further operands.
   4334 	DEFW	GOSUB
   4335 
   4336 mark_0C58:
   4337 P_STOP:
   4338 	DEFB	_CLASS_00	; No further operands.
   4339 	DEFW	STOP
   4340 
   4341 mark_0C5B:
   4342 P_RETURN:
   4343 	DEFB	_CLASS_00	; No further operands.
   4344 	DEFW	RETURN
   4345 
   4346 mark_0C5E:
   4347 P_FOR:
   4348 	DEFB	_CLASS_04	; A single character variable must
   4349 				; follow.
   4350 	DEFB	ZX_EQUAL	; Separator:	'='
   4351 	DEFB	_CLASS_06	; A numeric expression must follow.
   4352 	DEFB	ZX_TO		; Separator:	'TO'
   4353 	DEFB	_CLASS_06	; A numeric expression must follow.
   4354 	DEFB	_CLASS_05	; Variable syntax checked entirely
   4355 				; by routine.
   4356 	DEFW	FOR
   4357 
   4358 mark_0C66:
   4359 P_NEXT:
   4360 	DEFB	_CLASS_04	; A single character variable must
   4361 				; follow.
   4362 	DEFB	_CLASS_00	; No further operands.
   4363 	DEFW	NEXT
   4364 
   4365 mark_0C6A:
   4366 P_PRINT:
   4367 	DEFB	_CLASS_05	; Variable syntax checked entirely
   4368 				; by routine.
   4369 	DEFW	PRINT		; not LPRINT ???
   4370 
   4371 mark_0C6D:
   4372 P_INPUT:
   4373 	DEFB	_CLASS_01	; A variable is required.
   4374 	DEFB	_CLASS_00	; No further operands.
   4375 	DEFW	INPUT
   4376 
   4377 mark_0C71:
   4378 P_DIM:
   4379 	DEFB	_CLASS_05	; Variable syntax checked entirely
   4380 				; by routine.
   4381 	DEFW	DIM
   4382 
   4383 mark_0C74:
   4384 P_REM:
   4385 	DEFB	_CLASS_05	; Variable syntax checked entirely
   4386 				; by routine.
   4387 	DEFW	REM
   4388 
   4389 mark_0C77:
   4390 P_NEW:
   4391 	DEFB	_CLASS_00	; No further operands.
   4392 	DEFW	NEW
   4393 
   4394 mark_0C7A:
   4395 P_RUN:
   4396 	DEFB	_CLASS_03	; A numeric expression may follow
   4397 				; else default to zero.
   4398 	DEFW	RUN
   4399 
   4400 mark_0C7D:
   4401 P_LIST:
   4402 	DEFB	_CLASS_03	; A numeric expression may follow
   4403 				; else default to zero.
   4404 	DEFW	LIST
   4405 
   4406 mark_0C80:
   4407 P_POKE:
   4408 	DEFB	_CLASS_06	; A numeric expression must follow.
   4409 	DEFB	ZX_COMMA	; Separator:	','
   4410 	DEFB	_CLASS_06	; A numeric expression must follow.
   4411 	DEFB	_CLASS_00	; No further operands.
   4412 	DEFW	POKE
   4413 
   4414 mark_0C86:
   4415 P_RAND:
   4416 	DEFB	_CLASS_03	; A numeric expression may follow
   4417 				; else default to zero.
   4418 	DEFW	RAND
   4419 
   4420 mark_0C89:
   4421 P_LOAD:
   4422 	DEFB	_CLASS_05	; Variable syntax checked entirely
   4423 				; by routine.
   4424 	DEFW	LOAD
   4425 
   4426 mark_0C8C:
   4427 P_SAVE:
   4428 	DEFB	_CLASS_05	; Variable syntax checked entirely
   4429 				; by routine.
   4430 	DEFW	SAVE
   4431 
   4432 mark_0C8F:
   4433 P_CONT:
   4434 	DEFB	_CLASS_00	; No further operands.
   4435 	DEFW	CONT
   4436 
   4437 mark_0C92:
   4438 P_CLEAR:
   4439 	DEFB	_CLASS_00	; No further operands.
   4440 	DEFW	CLEAR
   4441 
   4442 mark_0C95:
   4443 P_CLS:
   4444 	DEFB	_CLASS_00	; No further operands.
   4445 	DEFW	CLS
   4446 
   4447 mark_0C98:
   4448 P_PLOT:
   4449 	DEFB	_CLASS_06	; A numeric expression must follow.
   4450 	DEFB	ZX_COMMA	; Separator:	','
   4451 	DEFB	_CLASS_06	; A numeric expression must follow.
   4452 	DEFB	_CLASS_00	; No further operands.
   4453 	DEFW	PLOT_UNPLOT
   4454 
   4455 mark_0C9E:
   4456 P_UNPLOT:
   4457 	DEFB	_CLASS_06	; A numeric expression must follow.
   4458 	DEFB	ZX_COMMA	; Separator:	','
   4459 	DEFB	_CLASS_06	; A numeric expression must follow.
   4460 	DEFB	_CLASS_00	; No further operands.
   4461 	DEFW	PLOT_UNPLOT
   4462 
   4463 mark_0CA4:
   4464 P_SCROLL:
   4465 	DEFB	_CLASS_00	; No further operands.
   4466 	DEFW	SCROLL
   4467 
   4468 mark_0CA7:
   4469 P_PAUSE:
   4470 	DEFB	_CLASS_06	; A numeric expression must follow.
   4471 	DEFB	_CLASS_00	; No further operands.
   4472 	DEFW	PAUSE
   4473 
   4474 mark_0CAB:
   4475 P_SLOW:
   4476 	DEFB	_CLASS_00	; No further operands.
   4477 	DEFW	SLOW
   4478 
   4479 mark_0CAE:
   4480 P_FAST:
   4481 	DEFB	_CLASS_00	; No further operands.
   4482 	DEFW	FAST
   4483 
   4484 mark_0CB1:
   4485 P_COPY:
   4486 	DEFB	_CLASS_00	; No further operands.
   4487 	DEFW	COPY
   4488 
   4489 mark_0CB4:
   4490 P_LPRINT:
   4491 	DEFB	_CLASS_05	; Variable syntax checked entirely
   4492 				; by routine.
   4493 	DEFW	LPRINT
   4494 
   4495 mark_0CB7:
   4496 P_LLIST:
   4497 	DEFB	_CLASS_03	; A numeric expression may follow
   4498 				; else default to zero.
   4499 	DEFW	LLIST
   4500 
   4501 
   4502 
   4503 ; THE 'LINE SCANNING' ROUTINE
   4504 
   4505 
   4506 mark_0CBA:
   4507 LINE_SCAN:
   4508 	LD	(IY+FLAGS-RAMBASE),1
   4509 	CALL	E_LINE_NUM
   4510 
   4511 mark_0CC1:
   4512 LINE_RUN:
   4513 	CALL	SET_MIN
   4514 	LD	HL,ERR_NR	;
   4515 	LD	(HL),$FF	;
   4516 	LD	HL,FLAGX	;
   4517 	BIT	5,(HL)		;
   4518 	JR	Z,LINE_NULL
   4519 
   4520 	CP	$E3		; 'STOP' ?
   4521 	LD	A,(HL)		;
   4522 	JP	NZ,INPUT_REP
   4523 
   4524 	CALL	SYNTAX_Z
   4525 	RET	Z		;
   4526 
   4527 
   4528 	RST	_ERROR_1
   4529 	DEFB	$0C		; Error Report: BREAK - CONT repeats
   4530 
   4531 
   4532 
   4533 ; THE 'STOP' COMMAND ROUTINE
   4534 
   4535 ;
   4536 ;
   4537 
   4538 mark_0CDC:
   4539 STOP:
   4540 	RST	_ERROR_1
   4541 	DEFB	$08		; Error Report: STOP statement
   4542 ; ___
   4543 
   4544 ; the interpretation of a line continues with a check for just spaces
   4545 ; followed by a carriage return.
   4546 ; The IF command also branches here with a true value to execute the
   4547 ; statement after the THEN but the statement can be null so
   4548 ; 10 IF 1 = 1 THEN
   4549 ; passes syntax (on all ZX computers).
   4550 
   4551 mark_0CDE:
   4552 LINE_NULL:
   4553 	RST	_GET_CHAR
   4554 	LD	B,$00		; prepare to index - early.
   4555 	CP	ZX_NEWLINE		; compare to NEWLINE.
   4556 	RET	Z		; return if so.
   4557 
   4558 
   4559 
   4560 
   4561 
   4562 	LD	C,A		; transfer character to C.
   4563 
   4564 	RST	_NEXT_CHAR	; advances.
   4565 	LD	A,C		; character to A
   4566 	SUB	$E1		; subtract 'LPRINT' - lowest command.
   4567 	JR	C,REPORT_C2	; forward if less
   4568 
   4569 	LD	C,A		; reduced token to C
   4570 	LD	HL,offset_t	; set HL to address of offset table.
   4571 	ADD	HL,BC		; index into offset table.
   4572 	LD	C,(HL)		; fetch offset
   4573 	ADD	HL,BC		; index into parameter table.
   4574 	JR	GET_PARAM
   4575 ; ___
   4576 
   4577 mark_0CF4:
   4578 SCAN_LOOP:
   4579 	LD	HL,(T_ADDR)	;
   4580 
   4581 ; -> Entry Point to Scanning Loop
   4582 
   4583 mark_0CF7:
   4584 GET_PARAM:
   4585 	LD	A,(HL)		;
   4586 	INC	HL		;
   4587 	LD	(T_ADDR),HL	;
   4588 
   4589 	LD	BC,SCAN_LOOP
   4590 	PUSH	BC		; is pushed on machine stack.
   4591 
   4592 	LD	C,A		;
   4593 	CP	ZX_QUOTE	; $0B
   4594 	JR	NC,SEPARATOR
   4595 
   4596 	LD	HL,class_tbl	; class_tbl - the address of the class table.
   4597 	LD	B,$00		;
   4598 	ADD	HL,BC		;
   4599 	LD	C,(HL)		;
   4600 	ADD	HL,BC		;
   4601 	PUSH	HL		;
   4602 
   4603 	RST	_GET_CHAR
   4604 	RET			; indirect jump to class routine and
   4605 				; by subsequent RET to SCAN_LOOP.
   4606 
   4607 
   4608 ; THE 'SEPARATOR' ROUTINE
   4609 
   4610 
   4611 mark_0D10:
   4612 SEPARATOR:
   4613 	RST	_GET_CHAR
   4614 	CP	C		;
   4615 	JR	NZ,REPORT_C2
   4616 				; 'Nonsense in BASIC'
   4617 
   4618 	RST	_NEXT_CHAR
   4619 	RET			; return
   4620 
   4621 
   4622 
   4623 ; THE 'COMMAND CLASS' TABLE
   4624 
   4625 ;
   4626 mark_0D16:
   4627 class_tbl:
   4628 	DEFB	CLASS_0 - $	; 17 offset to; Address: CLASS_0
   4629 	DEFB	CLASS_1 - $	; 25 offset to; Address: CLASS_1
   4630 	DEFB	CLASS_2 - $	; 53 offset to; Address: CLASS_2
   4631 	DEFB	CLASS_3 - $	; 0F offset to; Address: CLASS_3
   4632 	DEFB	CLASS_4 - $	; 6B offset to; Address: CLASS_4
   4633 	DEFB	CLASS_5 - $	; 13 offset to; Address: CLASS_5
   4634 	DEFB	CLASS_6 - $	; 76 offset to; Address: CLASS_6
   4635 
   4636 
   4637 ; THE 'CHECK END' SUBROUTINE
   4638 
   4639 ; Check for end of statement and that no spurious characters occur after
   4640 ; a correctly parsed statement. Since only one statement is allowed on each
   4641 ; line, the only character that may follow a statement is a NEWLINE.
   4642 ;
   4643 mark_0D1D:
   4644 CHECK_END:
   4645 	CALL	SYNTAX_Z
   4646 	RET	NZ		; return in runtime.
   4647 
   4648 	POP	BC		; else drop return address.
   4649 
   4650 mark_0D22:
   4651 CHECK_2:
   4652 	LD	A,(HL)		; fetch character.
   4653 	CP	ZX_NEWLINE	; compare to NEWLINE.
   4654 	RET	Z		; return if so.
   4655 
   4656 mark_0D26:
   4657 REPORT_C2:
   4658 	JR	REPORT_C
   4659 				; 'Nonsense in BASIC'
   4660 
   4661 
   4662 ; COMMAND CLASSES 03, 00, 05
   4663 
   4664 
   4665 mark_0D28:
   4666 CLASS_3:
   4667 	CP	ZX_NEWLINE		;
   4668 	CALL	NUMBER_TO_STK
   4669 
   4670 mark_0D2D:
   4671 CLASS_0:
   4672 	CP	A		;
   4673 
   4674 mark_0D2E:
   4675 CLASS_5:
   4676 	POP	BC		;
   4677 	CALL	Z,CHECK_END
   4678 	EX	DE,HL		;
   4679 	LD	HL,(T_ADDR)	;
   4680 	LD	C,(HL)		;
   4681 	INC	HL		;
   4682 	LD	B,(HL)		;
   4683 	EX	DE,HL		;
   4684 
   4685 mark_0D3A:
   4686 CLASS_END:
   4687 	PUSH	BC		;
   4688 	RET			;
   4689 
   4690 
   4691 ; COMMAND CLASSES 01, 02, 04, 06
   4692 
   4693 
   4694 mark_0D3C:
   4695 CLASS_1:
   4696 	CALL	LOOK_VARS
   4697 
   4698 mark_0D3F:
   4699 CLASS_4_2:
   4700 	LD	(IY+FLAGX-RAMBASE),$00
   4701 	JR	NC,SET_STK
   4702 
   4703 	SET	1,(IY+FLAGX-RAMBASE)
   4704 	JR	NZ,SET_STRLN
   4705 
   4706 
   4707 mark_0D4B:
   4708 REPORT_2:
   4709 	RST	_ERROR_1
   4710 	DEFB	$01		; Error Report: Variable not found
   4711 ; ___
   4712 
   4713 mark_0D4D:
   4714 SET_STK:
   4715 	CALL	Z,STK_VAR
   4716 	BIT	6,(IY+FLAGS-RAMBASE)	; Numeric or string result?
   4717 	JR	NZ,SET_STRLN
   4718 
   4719 	XOR	A		;
   4720 	CALL	SYNTAX_Z
   4721 	CALL	NZ,STK_FETCH
   4722 	LD	HL,FLAGX	; 
   4723 	OR	(HL)		;
   4724 	LD	(HL),A		;
   4725 	EX	DE,HL		;
   4726 
   4727 mark_0D63:
   4728 SET_STRLN:
   4729 	LD	(STRLEN),BC	;
   4730 	LD	(DEST),HL	; 
   4731 
   4732 ; THE 'REM' COMMAND ROUTINE
   4733 
   4734 mark_0D6A:
   4735 REM:
   4736 	RET			;
   4737 
   4738 ; ___
   4739 
   4740 mark_0D6B:
   4741 CLASS_2:
   4742 	POP	BC		;
   4743 	LD	A,(FLAGS)	; sv
   4744 
   4745 mark_0D6F:
   4746 INPUT_REP:
   4747 	PUSH	AF		;
   4748 	CALL	SCANNING
   4749 	POP	AF		;
   4750 	LD	BC,LET	; Address: LET
   4751 	LD	D,(IY+FLAGS-RAMBASE)
   4752 	XOR	D		;
   4753 	AND	$40		;
   4754 	JR	NZ,REPORT_C	; to REPORT_C
   4755 
   4756 	BIT	7,D		;
   4757 	JR	NZ,CLASS_END	; to CLASS_END
   4758 
   4759 	JR	CHECK_2		; to CHECK_2
   4760 ; ___
   4761 
   4762 mark_0D85:
   4763 CLASS_4:
   4764 	CALL	LOOK_VARS
   4765 	PUSH	AF		;
   4766 	LD	A,C		;
   4767 	OR	$9F		;
   4768 	INC	A		;
   4769 	JR	NZ,REPORT_C	; to REPORT_C
   4770 
   4771 	POP	AF		;
   4772 	JR	CLASS_4_2		; to CLASS_4_2
   4773 
   4774 ; ___
   4775 
   4776 mark_0D92:
   4777 CLASS_6:
   4778 	CALL	SCANNING
   4779 	BIT	6,(IY+FLAGS-RAMBASE)	; Numeric or string result?
   4780 	RET	NZ		;
   4781 
   4782 
   4783 mark_0D9A:
   4784 REPORT_C:
   4785 	RST	_ERROR_1
   4786 	DEFB	$0B		; Error Report: Nonsense in BASIC
   4787 
   4788 
   4789 ; THE 'NUMBER TO STACK' SUBROUTINE
   4790 
   4791 ;
   4792 ;
   4793 
   4794 mark_0D9C:
   4795 NUMBER_TO_STK:
   4796 	JR	NZ,CLASS_6	; back to CLASS_6 with a non-zero number.
   4797 
   4798 	CALL	SYNTAX_Z
   4799 	RET	Z		; return if checking syntax.
   4800 
   4801 ; in runtime a zero default is placed on the calculator stack.
   4802 
   4803 	RST	_FP_CALC	;;
   4804 	DEFB	__stk_zero	;;
   4805 	DEFB	__end_calc	;;
   4806 
   4807 	RET			; return.
   4808 
   4809 
   4810 ; THE 'SYNTAX_Z' SUBROUTINE
   4811 
   4812 ; This routine returns with zero flag set if checking syntax.
   4813 ; Calling this routine uses three instruction bytes compared to four if the
   4814 ; bit test is implemented inline.
   4815 
   4816 mark_0DA6:
   4817 SYNTAX_Z:
   4818 	BIT	7,(IY+FLAGS-RAMBASE)	; checking syntax only?
   4819 	RET			; return.
   4820 
   4821 
   4822 ; THE 'IF' COMMAND ROUTINE
   4823 
   4824 ; In runtime, the class routines have evaluated the test expression and
   4825 ; the result, true or false, is on the stack.
   4826 
   4827 mark_0DAB:
   4828 IF:
   4829 	CALL	SYNTAX_Z
   4830 	JR	Z,IF_END	; forward if checking syntax
   4831 
   4832 ; else delete the Boolean value on the calculator stack.
   4833 
   4834 	RST	_FP_CALC	;;
   4835 	DEFB	__delete	;;
   4836 	DEFB	__end_calc	;;
   4837 
   4838 ; register DE points to exponent of floating point value.
   4839 
   4840 	LD	A,(DE)		; fetch exponent.
   4841 	AND	A		; test for zero - FALSE.
   4842 	RET	Z		; return if so.
   4843 
   4844 mark_0DB6:
   4845 IF_END:
   4846 	JP	LINE_NULL		; jump back
   4847 
   4848 
   4849 ; THE 'FOR' COMMAND ROUTINE
   4850 
   4851 ;
   4852 ;
   4853 
   4854 mark_0DB9:
   4855 FOR:
   4856 	CP	ZX_STEP		; is current character 'STEP' ?
   4857 	JR	NZ,F_USE_ONE	; forward if not
   4858 
   4859 
   4860 	RST	_NEXT_CHAR
   4861 	CALL	CLASS_6		; stacks the number
   4862 	CALL	CHECK_END
   4863 	JR	F_REORDER	; forward to F_REORDER
   4864 ; ___
   4865 
   4866 mark_0DC6:
   4867 F_USE_ONE:
   4868 	CALL	CHECK_END
   4869 
   4870 	RST	_FP_CALC	;;
   4871 	DEFB	__stk_one	;;
   4872 	DEFB	__end_calc	;;
   4873 
   4874 
   4875 
   4876 mark_0DCC:
   4877 F_REORDER:
   4878 	RST	_FP_CALC	;;	v, l, s.
   4879 	DEFB	__st_mem_0	;;	v, l, s.
   4880 	DEFB	__delete	;;	v, l.
   4881 	DEFB	__exchange	;;	l, v.
   4882 	DEFB	__get_mem_0	;;	l, v, s.
   4883 	DEFB	__exchange	;;	l, s, v.
   4884 	DEFB	__end_calc	;;	l, s, v.
   4885 
   4886 	CALL	LET
   4887 
   4888 	LD	(MEM),HL	; set MEM to address variable.
   4889 	DEC	HL		; point to letter.
   4890 	LD	A,(HL)		;
   4891 	SET	7,(HL)		;
   4892 	LD	BC,$0006	;
   4893 	ADD	HL,BC		;
   4894 	RLCA			;
   4895 	JR	C,F_LMT_STP
   4896 
   4897 	SLA	C		;
   4898 	CALL	MAKE_ROOM
   4899 	INC	HL		;
   4900 
   4901 mark_0DEA:
   4902 F_LMT_STP:
   4903 	PUSH	HL		;
   4904 
   4905 	RST	_FP_CALC	;; 
   4906 	DEFB	__delete	;;
   4907 	DEFB	__delete	;;
   4908 	DEFB	__end_calc	;;
   4909 
   4910 	POP	HL		;
   4911 	EX	DE,HL		;
   4912 
   4913 	LD	C,$0A		; ten bytes to be moved.
   4914 	LDIR			; copy bytes
   4915 
   4916 	LD	HL,(PPC)	; set HL to system variable PPC current line.
   4917 	EX	DE,HL		; transfer to DE, variable pointer to HL.
   4918 	INC	DE		; loop start will be this line + 1 at least.
   4919 	LD	(HL),E		;
   4920 	INC	HL		;
   4921 	LD	(HL),D		;
   4922 	CALL	NEXT_LOOP	; considers an initial pass.
   4923 	RET	NC		; return if possible.
   4924 
   4925 ; else program continues from point following matching NEXT.
   4926 
   4927 	BIT	7,(IY+PPC_hi-RAMBASE)
   4928 	RET	NZ		; return if over 32767 ???
   4929 
   4930 	LD	B,(IY+STRLEN_lo-RAMBASE)	; fetch variable name from STRLEN_lo
   4931 	RES	6,B		; make a true letter.
   4932 	LD	HL,(NXTLIN)	; set HL from NXTLIN
   4933 
   4934 ; now enter a loop to look for matching next.
   4935 
   4936 mark_0E0E:
   4937 NXTLIN_NO:
   4938 	LD	A,(HL)		; fetch high byte of line number.
   4939 	AND	$C0		; mask off low bits $3F
   4940 	JR	NZ,FOR_END	; forward at end of program
   4941 
   4942 	PUSH	BC		; save letter
   4943 	CALL	NEXT_ONE	; finds next line.
   4944 	POP	BC		; restore letter
   4945 
   4946 	INC	HL		; step past low byte
   4947 	INC	HL		; past the
   4948 	INC	HL		; line length.
   4949 	CALL	TEMP_PTR1	; sets CH_ADD
   4950 
   4951 	RST	_GET_CHAR
   4952 	CP	ZX_NEXT		;
   4953 	EX	DE,HL		; next line to HL.
   4954 	JR	NZ,NXTLIN_NO	; back with no match
   4955 
   4956 ;
   4957 
   4958 	EX	DE,HL		; restore pointer.
   4959 
   4960 	RST	_NEXT_CHAR	; advances and gets letter in A.
   4961 	EX	DE,HL		; save pointer
   4962 	CP	B		; compare to variable name.
   4963 	JR	NZ,NXTLIN_NO	; back with mismatch
   4964 
   4965 mark_0E2A:
   4966 FOR_END:
   4967 	LD	(NXTLIN),HL	; update system variable NXTLIN
   4968 	RET			; return.
   4969 
   4970 
   4971 ; THE 'NEXT' COMMAND ROUTINE
   4972 
   4973 ;
   4974 ;
   4975 
   4976 mark_0E2E:
   4977 NEXT:
   4978 	BIT	1,(IY+FLAGX-RAMBASE)
   4979 	JP	NZ,REPORT_2
   4980 
   4981 	LD	HL,(DEST)
   4982 	BIT	7,(HL)
   4983 	JR	Z,REPORT_1
   4984 
   4985 	INC	HL		;
   4986 	LD	(MEM),HL	;
   4987 
   4988 	RST	_FP_CALC	;;
   4989 	DEFB	__get_mem_0	;;
   4990 	DEFB	__get_mem_2	;;
   4991 	DEFB	__addition	;;
   4992 	DEFB	__st_mem_0	;;
   4993 	DEFB	__delete	;;
   4994 	DEFB	__end_calc	;;
   4995 
   4996 	CALL	NEXT_LOOP
   4997 	RET	C		;
   4998 
   4999 	LD	HL,(MEM)	; 
   5000 	LD	DE,$000F	;
   5001 	ADD	HL,DE		;
   5002 	LD	E,(HL)		;
   5003 	INC	HL		;
   5004 	LD	D,(HL)		;
   5005 	EX	DE,HL		;
   5006 	JR	GOTO_2
   5007 ; ___
   5008 
   5009 mark_0E58:
   5010 REPORT_1:
   5011 	RST	_ERROR_1
   5012 	DEFB	$00		; Error Report: NEXT without FOR
   5013 
   5014 
   5015 
   5016 ; THE 'NEXT_LOOP' SUBROUTINE
   5017 
   5018 ;
   5019 ;
   5020 
   5021 mark_0E5A:
   5022 NEXT_LOOP:
   5023 	RST	_FP_CALC	;;
   5024 	DEFB	__get_mem_1	;;
   5025 	DEFB	__get_mem_0	;;
   5026 	DEFB	__get_mem_2	;;
   5027 	DEFB	__less_0	;;
   5028 	DEFB	__jump_true	;;
   5029 	DEFB	LMT_V_VAL - $	;;
   5030 
   5031 	DEFB	__exchange	;;
   5032 
   5033 mark_0E62:
   5034 LMT_V_VAL:
   5035 	DEFB	__subtract	;;
   5036 	DEFB	__greater_0	;;
   5037 	DEFB	__jump_true	;;
   5038 	DEFB	IMPOSS - $	;;
   5039 
   5040 	DEFB	__end_calc	;;
   5041 
   5042 	AND	A		; clear carry flag
   5043 	RET			; return.
   5044 ; ___
   5045 
   5046 mark_0E69:
   5047 IMPOSS:
   5048 	DEFB	__end_calc	;;
   5049 
   5050 	SCF			; set carry flag
   5051 	RET			; return.
   5052 
   5053 
   5054 ; THE 'RAND' COMMAND ROUTINE
   5055 
   5056 ; The keyword was 'RANDOMISE' on the ZX80, is 'RAND' here on the ZX81 and
   5057 ; becomes 'RANDOMIZE' on the ZX Spectrum.
   5058 ; In all invocations the procedure is the same - to set the SEED system variable
   5059 ; with a supplied integer value or to use a time-based value if no number, or
   5060 ; zero, is supplied.
   5061 
   5062 mark_0E6C:
   5063 RAND:
   5064 	CALL	FIND_INT
   5065 	LD	A,B		; test value
   5066 	OR	C		; for zero
   5067 	JR	NZ,SET_SEED	; forward if not zero
   5068 
   5069 	LD	BC,(FRAMES)	; fetch value of FRAMES system variable.
   5070 
   5071 mark_0E77:
   5072 SET_SEED:
   5073 	LD	(SEED),BC	; update the SEED system variable.
   5074 	RET			; return.
   5075 
   5076 
   5077 ; THE 'CONT' COMMAND ROUTINE
   5078 
   5079 ; Another abbreviated command. ROM space was really tight.
   5080 ; CONTINUE at the line number that was set when break was pressed.
   5081 ; Sometimes the current line, sometimes the next line.
   5082 
   5083 mark_0E7C:
   5084 CONT:
   5085 	LD	HL,(OLDPPC)	; set HL from system variable OLDPPC
   5086 	JR	GOTO_2		; forward
   5087 
   5088 
   5089 ; THE 'GOTO' COMMAND ROUTINE
   5090 
   5091 ; This token also suffered from the shortage of room and there is no space
   5092 ; getween GO and TO as there is on the ZX80 and ZX Spectrum. The same also 
   5093 ; applies to the GOSUB keyword.
   5094 
   5095 mark_0E81:
   5096 GOTO:
   5097 	CALL	FIND_INT
   5098 	LD	H,B		;
   5099 	LD	L,C		;
   5100 
   5101 mark_0E86:
   5102 GOTO_2:
   5103 	LD	A,H		;
   5104 	CP	$F0		; ZX_LIST ???
   5105 	JR	NC,REPORT_B
   5106 
   5107 	CALL	LINE_ADDR
   5108 	LD	(NXTLIN),HL	; sv
   5109 	RET			;
   5110 
   5111 
   5112 ; THE 'POKE' COMMAND ROUTINE
   5113 
   5114 
   5115 mark_0E92:
   5116 POKE:
   5117 	CALL	FP_TO_A
   5118 	JR	C,REPORT_B	; forward, with overflow
   5119 
   5120 	JR	Z,POKE_SAVE	; forward, if positive
   5121 
   5122 	NEG			; negate
   5123 
   5124 mark_0E9B:
   5125 POKE_SAVE:
   5126 	PUSH	AF		; preserve value.
   5127 	CALL	FIND_INT		; gets address in BC
   5128 				; invoking the error routine with overflow
   5129 				; or a negative number.
   5130 	POP	AF		; restore value.
   5131 
   5132 ; Note. the next two instructions are legacy code from the ZX80 and
   5133 ; inappropriate here.
   5134 
   5135 	BIT	7,(IY+ERR_NR-RAMBASE)	; test ERR_NR - is it still $FF ?
   5136 	RET	Z		; return with error.
   5137 
   5138 	LD	(BC),A		; update the address contents.
   5139 	RET			; return.
   5140 
   5141 
   5142 ; THE 'FIND INTEGER' SUBROUTINE
   5143 
   5144 
   5145 mark_0EA7:
   5146 FIND_INT:
   5147 	CALL	FP_TO_BC
   5148 	JR	C,REPORT_B	; forward with overflow
   5149 
   5150 	RET	Z		; return if positive (0-65535).
   5151 
   5152 
   5153 mark_0EAD:
   5154 REPORT_B:
   5155 	RST	_ERROR_1
   5156 	DEFB	$0A		; Error Report: Integer out of range
   5157 ;
   5158 ; Seems stupid, $0A is 10 but the ERROR_CODE_INTEGER_OUT_OF_RANGE is 11
   5159 ; maybe gets incremented ???
   5160 
   5161 
   5162 ; THE 'RUN' COMMAND ROUTINE
   5163 
   5164 
   5165 mark_0EAF:
   5166 RUN:
   5167 	CALL	GOTO
   5168 	JP	CLEAR
   5169 
   5170 
   5171 ; THE 'GOSUB' COMMAND ROUTINE
   5172 
   5173 
   5174 mark_0EB5:
   5175 GOSUB:
   5176 	LD	HL,(PPC)	;
   5177 	INC	HL		;
   5178 	EX	(SP),HL		;
   5179 	PUSH	HL		;
   5180 	LD	(ERR_SP),SP	; set the error stack pointer - ERR_SP
   5181 	CALL	GOTO
   5182 	LD	BC,6		;
   5183 
   5184 
   5185 ; THE 'TEST ROOM' SUBROUTINE
   5186 
   5187 ;
   5188 ; checks ther is room for 36 bytes on the stack
   5189 ;
   5190 mark_0EC5:
   5191 TEST_ROOM:
   5192 	LD	HL,(STKEND)	;
   5193 	ADD	HL,BC		; HL = STKEND + BC
   5194 	JR	C,REPORT_4
   5195 
   5196 	EX	DE,HL		; DE = STKEND + BC
   5197 	LD	HL,$0024	; 36 decimal
   5198 	ADD	HL,DE		; HL = 36 + STKEND + BC
   5199 	SBC	HL,SP		; HL = 36 + STKEND + BC - SP
   5200 	RET	C		;
   5201 
   5202 mark_0ED3:
   5203 REPORT_4:
   5204 	LD	L,3		;
   5205 	JP	ERROR_3
   5206 
   5207 
   5208 ; THE 'RETURN' COMMAND ROUTINE
   5209 
   5210 
   5211 mark_0ED8:
   5212 RETURN:
   5213 	POP	HL		;
   5214 	EX	(SP),HL	;
   5215 	LD	A,H		;
   5216 	CP	$3E		;
   5217 	JR	Z,REPORT_7
   5218 
   5219 	LD	(ERR_SP),SP	;
   5220 	JR	GOTO_2		; back
   5221 ; ___
   5222 
   5223 mark_0EE5:
   5224 REPORT_7:
   5225 	EX	(SP),HL	;
   5226 	PUSH	HL		;
   5227 
   5228 	RST	_ERROR_1
   5229 	DEFB	6		; Error Report: RETURN without GOSUB
   5230 
   5231 ;
   5232 ; Contradicts BASIC manual:
   5233 ; 7 is ERROR_CODE_RETURN_WITHOUT_GOSUB
   5234 ; 6 is ERROR_CODE_ARITHMETIC_OVERFLOW
   5235 ;
   5236 
   5237 
   5238 ; THE 'INPUT' COMMAND ROUTINE
   5239 
   5240 
   5241 mark_0EE9:
   5242 INPUT:
   5243 	BIT	7,(IY+PPC_hi-RAMBASE)
   5244 	JR	NZ,REPORT_8	; to REPORT_8
   5245 
   5246 	CALL	X_TEMP
   5247 	LD	HL,FLAGX	; 
   5248 	SET	5,(HL)		;
   5249 	RES	6,(HL)		;
   5250 	LD	A,(FLAGS)	;
   5251 	AND	$40		; 64
   5252 	LD	BC,2		;
   5253 	JR	NZ,PROMPT	; to PROMPT
   5254 
   5255 	LD	C,$04		;
   5256 
   5257 mark_0F05:
   5258 PROMPT:
   5259 	OR	(HL)		;
   5260 	LD	(HL),A		;
   5261 
   5262 	RST	_BC_SPACES
   5263 	LD	(HL),ZX_NEWLINE
   5264 	LD	A,C		;
   5265 	RRCA			;
   5266 	RRCA			;
   5267 	JR	C,ENTER_CUR
   5268 
   5269 	LD	A,$0B		; ZX_QUOTE ???
   5270 	LD	(DE),A		;
   5271 	DEC	HL		;
   5272 	LD	(HL),A		;
   5273 
   5274 mark_0F14:
   5275 ENTER_CUR:
   5276 	DEC	HL		;
   5277 	LD	(HL),ZX_CURSOR	;
   5278 	LD	HL,(S_POSN)	;
   5279 	LD	(T_ADDR),HL	;
   5280 	POP	HL		;
   5281 	JP	LOWER
   5282 
   5283 ; ___
   5284 
   5285 mark_0F21:
   5286 REPORT_8:
   5287 	RST	_ERROR_1
   5288 	DEFB	7		; Error Report: End of file
   5289 
   5290 
   5291 ; THE 'PAUSE' COMMAND ROUTINE
   5292 
   5293 
   5294 mark_0F23:
   5295 FAST:
   5296 	CALL	SET_FAST
   5297 	RES	6,(IY+CDFLAG-RAMBASE)
   5298 	RET			; return.
   5299 
   5300 
   5301 ; THE 'SLOW' COMMAND ROUTINE
   5302 
   5303 
   5304 mark_0F2B:
   5305 SLOW:
   5306 	SET	6,(IY+CDFLAG-RAMBASE)
   5307 	JP	SLOW_FAST
   5308 
   5309 
   5310 ; THE 'PAUSE' COMMAND ROUTINE
   5311 
   5312 
   5313 mark_0F32:
   5314 PAUSE:
   5315 	CALL	FIND_INT
   5316 	CALL	SET_FAST
   5317 	LD	H,B		;
   5318 	LD	L,C		;
   5319 	CALL	DISPLAY_P
   5320 
   5321 	LD	(IY+FRAMES_hi-RAMBASE),$FF
   5322 
   5323 	CALL	SLOW_FAST
   5324 	JR	DEBOUNCE
   5325 
   5326 
   5327 ; THE 'BREAK' SUBROUTINE
   5328 
   5329 
   5330 mark_0F46:
   5331 BREAK_1:
   5332 	LD	A,$7F			; read port $7FFE - keys B,N,M,.,SPACE.
   5333 	IN	A,(IO_PORT_KEYBOARD_RD)	;
   5334 	RRA				; carry will be set if space not pressed.
   5335 
   5336 
   5337 ; THE 'DEBOUNCE' SUBROUTINE
   5338 
   5339 
   5340 mark_0F4B:
   5341 DEBOUNCE:
   5342 	RES	0,(IY+CDFLAG-RAMBASE)	; update
   5343 	LD	A,$FF		;
   5344 	LD	(DEBOUNCE_VAR),A	; update
   5345 	RET			; return.
   5346 
   5347 
   5348 
   5349 ; THE 'SCANNING' SUBROUTINE
   5350 
   5351 ; This recursive routine is where the ZX81 gets its power.
   5352 ; Provided there is enough memory it can evaluate 
   5353 ; an expression of unlimited complexity.
   5354 ; Note. there is no unary plus so, as on the ZX80, PRINT +1 gives a syntax error.
   5355 ; PRINT +1 works on the Spectrum but so too does PRINT + "STRING".
   5356 
   5357 mark_0F55:
   5358 SCANNING:
   5359 	RST	_GET_CHAR
   5360 	LD	B,0		; set B register to zero.
   5361 	PUSH	BC		; stack zero as a priority end-marker.
   5362 
   5363 mark_0F59:
   5364 S_LOOP_1:
   5365 	CP	ZX_RND
   5366 	JR	NZ,S_TEST_PI	; forward, if not, to S_TEST_PI
   5367 
   5368 
   5369 ; THE 'RND' FUNCTION
   5370 
   5371 RND:
   5372 
   5373 	CALL	SYNTAX_Z
   5374 	JR	Z,S_JPI_END	; forward if checking syntax to S_JPI_END
   5375 
   5376 	LD	BC,(SEED)	; sv
   5377 	CALL	STACK_BC
   5378 
   5379 	RST	_FP_CALC	;;
   5380 	DEFB	__stk_one	;;
   5381 	DEFB	__addition	;;
   5382 	DEFB	__stk_data	;;
   5383 	DEFB	$37		;;Exponent: $87, Bytes: 1
   5384 	DEFB	$16		;;(+00,+00,+00)
   5385 	DEFB	__multiply	;;
   5386 	DEFB	__stk_data	;;
   5387 	DEFB	$80		;;Bytes: 3
   5388 	DEFB	$41		;;Exponent $91
   5389 	DEFB	$00,$00,$80	;;(+00)
   5390 	DEFB	__n_mod_m	;;
   5391 	DEFB	__delete	;;
   5392 	DEFB	__stk_one	;;
   5393 	DEFB	__subtract	;;
   5394 	DEFB	__duplicate	;;
   5395 	DEFB	__end_calc	;;
   5396 
   5397 	CALL	FP_TO_BC
   5398 	LD	(SEED),BC	; update the SEED system variable.
   5399 	LD	A,(HL)		; HL addresses the exponent of the last value.
   5400 	AND	A		; test for zero
   5401 	JR	Z,S_JPI_END	; forward, if so
   5402 
   5403 	SUB	$10		; else reduce exponent by sixteen
   5404 	LD	(HL),A		; thus dividing by 65536 for last value.
   5405 
   5406 mark_0F8A:
   5407 S_JPI_END:
   5408 	JR	S_PI_END	; forward
   5409 
   5410 ; ___
   5411 
   5412 mark_0F8C:
   5413 S_TEST_PI:
   5414 	CP	ZX_PI		; the 'PI' character
   5415 	JR	NZ,S_TST_INK	; forward, if not
   5416 
   5417 
   5418 ; THE 'PI' EVALUATION
   5419 
   5420 
   5421 	CALL	SYNTAX_Z
   5422 	JR	Z,S_PI_END	; forward if checking syntax
   5423 
   5424 
   5425 	RST	_FP_CALC	;;
   5426 	DEFB	__stk_half_pi	;;
   5427 	DEFB	__end_calc	;;
   5428 
   5429 	INC	(HL)		; double the exponent giving PI on the stack.
   5430 
   5431 mark_0F99:
   5432 S_PI_END:
   5433 	RST	_NEXT_CHAR	; advances character pointer.
   5434 
   5435 	JP	S_NUMERIC	; jump forward to set the flag
   5436 				; to signal numeric result before advancing.
   5437 
   5438 ; ___
   5439 
   5440 mark_0F9D:
   5441 S_TST_INK:
   5442 	CP	ZX_INKEY_STR	;
   5443 	JR	NZ,S_ALPHANUM	; forward, if not
   5444 
   5445 
   5446 ; THE 'INKEY$' EVALUATION
   5447 
   5448 
   5449 	CALL	KEYBOARD
   5450 	LD	B,H		;
   5451 	LD	C,L		;
   5452 	LD	D,C		;
   5453 	INC	D		;
   5454 	CALL	NZ,DECODE
   5455 	LD	A,D		;
   5456 	ADC	A,D		;
   5457 	LD	B,D		;
   5458 	LD	C,A		;
   5459 	EX	DE,HL		;
   5460 	JR	S_STRING		; forward
   5461 
   5462 ; ___
   5463 
   5464 mark_0FB2:
   5465 S_ALPHANUM:
   5466 	CALL	ALPHANUM
   5467 	JR	C,S_LTR_DGT	; forward, if alphanumeric
   5468 
   5469 	CP	ZX_PERIOD	; is character a '.' ?
   5470 	JP	Z,S_DECIMAL	; jump forward if so
   5471 
   5472 	LD	BC,$09D8	; prepare priority 09, operation 'subtract'
   5473 	CP	ZX_MINUS	; is character unary minus '-' ?
   5474 	JR	Z,S_PUSH_PO	; forward, if so
   5475 
   5476 	CP	ZX_BRACKET_LEFT	; is character a '(' ?
   5477 	JR	NZ,S_QUOTE	; forward if not
   5478 
   5479 	CALL	CH_ADD_PLUS_1	; advances character pointer.
   5480 
   5481 	CALL	SCANNING	; recursively call to evaluate the sub_expression.
   5482 
   5483 	CP	ZX_BRACKET_RIGHT; is subsequent character a ')' ?
   5484 	JR	NZ,S_RPT_C	; forward if not
   5485 
   5486 
   5487 	CALL	CH_ADD_PLUS_1	; advances.
   5488 	JR	S_J_CONT_3	; relative jump to S_JP_CONT3 and then S_CONT3
   5489 
   5490 ; ___
   5491 
   5492 ; consider a quoted string e.g. PRINT "Hooray!"
   5493 ; Note. quotes are not allowed within a string.
   5494 
   5495 mark_0FD6:
   5496 S_QUOTE:
   5497 	CP	ZX_QUOTE	; is character a quote (") ?
   5498 	JR	NZ,S_FUNCTION	; forward, if not
   5499 
   5500 	CALL	CH_ADD_PLUS_1	; advances
   5501 	PUSH	HL		; * save start of string.
   5502 	JR	S_QUOTE_S	; forward
   5503 
   5504 ; ___
   5505 
   5506 
   5507 mark_0FE0:
   5508 S_Q_AGAIN:
   5509 	CALL	CH_ADD_PLUS_1
   5510 
   5511 mark_0FE3:
   5512 S_QUOTE_S:
   5513 	CP	ZX_QUOTE	; is character a '"' ?
   5514 	JR	NZ,S_Q_NL	; forward if not to S_Q_NL
   5515 
   5516 	POP	DE		; * retrieve start of string
   5517 	AND	A		; prepare to subtract.
   5518 	SBC	HL,DE		; subtract start from current position.
   5519 	LD	B,H		; transfer this length
   5520 	LD	C,L		; to the BC register pair.
   5521 
   5522 mark_0FED:
   5523 S_STRING:
   5524 	LD	HL,FLAGS	; address system variable FLAGS
   5525 	RES	6,(HL)		; signal string result
   5526 	BIT	7,(HL)		; test if checking syntax.
   5527 
   5528 	CALL	NZ,STK_STO_STR	; in run-time stacks the
   5529 				; string descriptor - start DE, length BC.
   5530 
   5531 	RST	_NEXT_CHAR	; advances pointer.
   5532 
   5533 mark_0FF8:
   5534 S_J_CONT_3:
   5535 	JP	S_CONT_3
   5536 
   5537 ; ___
   5538 
   5539 ; A string with no terminating quote has to be considered.
   5540 
   5541 mark_0FFB:
   5542 S_Q_NL:
   5543 	CP	ZX_NEWLINE
   5544 	JR	NZ,S_Q_AGAIN	; loop back if not
   5545 
   5546 mark_0FFF:
   5547 S_RPT_C:
   5548 	JP	REPORT_C
   5549 ; ___
   5550 
   5551 mark_1002:
   5552 S_FUNCTION:
   5553 	SUB	$C4		; subtract 'CODE' reducing codes
   5554 				; CODE thru '<>' to range $00 - $XX
   5555 	JR	C,S_RPT_C	; back, if less
   5556 
   5557 ; test for NOT the last function in character set.
   5558 
   5559 	LD	BC,$04EC	; prepare priority $04, operation 'not'
   5560 	CP	$13		; compare to 'NOT'	( - CODE)
   5561 	JR	Z,S_PUSH_PO	; forward, if so
   5562 
   5563 	JR	NC,S_RPT_C	; back with anything higher
   5564 
   5565 ; else is a function 'CODE' thru 'CHR$'
   5566 
   5567 	LD	B,$10		; priority sixteen binds all functions to
   5568 				; arguments removing the need for brackets.
   5569 
   5570 	ADD	A,$D9		; add $D9 to give range $D9 thru $EB
   5571 				; bit 6 is set to show numeric argument.
   5572 				; bit 7 is set to show numeric result.
   5573 
   5574 ; now adjust these default argument/result indicators.
   5575 
   5576 	LD	C,A		; save code in C
   5577 
   5578 	CP	$DC		; separate 'CODE', 'VAL', 'LEN'
   5579 	JR	NC,S_NUMBER_TO_STRING	; skip forward if string operand
   5580 
   5581 	RES	6,C		; signal string operand.
   5582 
   5583 mark_101A:
   5584 S_NUMBER_TO_STRING:
   5585 	CP	$EA		; isolate top of range 'STR$' and 'CHR$'
   5586 	JR	C,S_PUSH_PO	; skip forward with others
   5587 
   5588 	RES	7,C		; signal string result.
   5589 
   5590 mark_1020:
   5591 S_PUSH_PO:
   5592 	PUSH	BC		; push the priority/operation
   5593 
   5594 	RST	_NEXT_CHAR
   5595 	JP	S_LOOP_1		; jump back
   5596 ; ___
   5597 
   5598 mark_1025:
   5599 S_LTR_DGT:
   5600 	CP	ZX_A		; compare to 'A'.
   5601 	JR	C,S_DECIMAL	; forward if less to S_DECIMAL
   5602 
   5603 	CALL	LOOK_VARS
   5604 	JP	C,REPORT_2	; back if not found
   5605 				; a variable is always 'found' when checking
   5606 				; syntax.
   5607 
   5608 	CALL	Z,STK_VAR	; stacks string parameters or
   5609 				; returns cell location if numeric.
   5610 
   5611 	LD	A,(FLAGS)	; fetch FLAGS
   5612 	CP	$C0		; compare to numeric result/numeric operand
   5613 	JR	C,S_CONT_2	; forward if not numeric
   5614 
   5615 	INC	HL		; address numeric contents of variable.
   5616 	LD	DE,(STKEND)	; set destination to STKEND
   5617 	CALL	MOVE_FP		; stacks the five bytes
   5618 	EX	DE,HL		; transfer new free location from DE to HL.
   5619 	LD	(STKEND),HL	; update STKEND system variable.
   5620 	JR	S_CONT_2		; forward
   5621 ; ___
   5622 
   5623 ; The Scanning Decimal routine is invoked when a decimal point or digit is
   5624 ; found in the expression.
   5625 ; When checking syntax, then the 'hidden floating point' form is placed
   5626 ; after the number in the BASIC line.
   5627 ; In run-time, the digits are skipped and the floating point number is picked
   5628 ; up.
   5629 
   5630 mark_1047:
   5631 S_DECIMAL:
   5632 	CALL	SYNTAX_Z
   5633 	JR	NZ,S_STK_DEC	; forward in run-time
   5634 
   5635 	CALL	DEC_TO_FP
   5636 
   5637 	RST	_GET_CHAR	; advances HL past digits
   5638 	LD	BC,$0006	; six locations are required.
   5639 	CALL	MAKE_ROOM
   5640 	INC	HL		; point to first new location
   5641 	LD	(HL),$7E	; insert the number marker 126 decimal.
   5642 	INC	HL		; increment
   5643 	EX	DE,HL		; transfer destination to DE.
   5644 	LD	HL,(STKEND)	; set HL from STKEND which points to the
   5645 				; first location after the 'last value'
   5646 	LD	C,$05		; five bytes to move.
   5647 	AND	A		; clear carry.
   5648 	SBC	HL,BC		; subtract five pointing to 'last value'.
   5649 	LD	(STKEND),HL	; update STKEND thereby 'deleting the value.
   5650 
   5651 	LDIR			; copy the five value bytes.
   5652 
   5653 	EX	DE,HL		; basic pointer to HL which may be white-space
   5654 				; following the number.
   5655 	DEC	HL		; now points to last of five bytes.
   5656 	CALL	TEMP_PTR1		; advances the character
   5657 				; address skipping any white-space.
   5658 	JR	S_NUMERIC		; forward
   5659 				; to signal a numeric result.
   5660 ; ___
   5661 ; In run-time the branch is here when a digit or point is encountered.
   5662 
   5663 mark_106F:
   5664 S_STK_DEC:
   5665 	RST	_NEXT_CHAR
   5666 	CP	$7E		; compare to 'number marker'
   5667 	JR	NZ,S_STK_DEC	; loop back until found
   5668 				; skipping all the digits.
   5669 
   5670 	INC	HL		; point to first of five hidden bytes.
   5671 	LD	DE,(STKEND)	; set destination from STKEND system variable
   5672 	CALL	MOVE_FP		; stacks the number.
   5673 	LD	(STKEND),DE	; update system variable STKEND.
   5674 	LD	(CH_ADD),HL	; update system variable CH_ADD.
   5675 
   5676 mark_1083:
   5677 S_NUMERIC:
   5678 	SET	6,(IY+FLAGS-RAMBASE)	; Signal numeric result
   5679 
   5680 mark_1087:
   5681 S_CONT_2:
   5682 	RST	_GET_CHAR
   5683 
   5684 mark_1088:
   5685 S_CONT_3:
   5686 	CP	ZX_BRACKET_LEFT		; compare to opening bracket '('
   5687 	JR	NZ,S_OPERTR	; forward if not
   5688 
   5689 	BIT	6,(IY+FLAGS-RAMBASE)	; Numeric or string result?
   5690 	JR	NZ,S_LOOP	; forward if numeric
   5691 
   5692 ; else is a string
   5693 
   5694 	CALL	SLICING
   5695 
   5696 	RST	_NEXT_CHAR
   5697 	JR	S_CONT_3	; back
   5698 ; ___
   5699 ; the character is now manipulated to form an equivalent in the table of
   5700 ; calculator literals. This is quite cumbersome and in the ZX Spectrum a
   5701 ; simple look-up table was introduced at this point.
   5702 
   5703 mark_1098:
   5704 S_OPERTR:
   5705 	LD	BC,$00C3	; prepare operator 'subtract' as default.
   5706 				; also set B to zero for later indexing.
   5707 
   5708 	CP	ZX_GREATER_THAN	; is character '>' ?
   5709 	JR	C,S_LOOP	; forward if less, as
   5710 				; we have reached end of meaningful expression
   5711 
   5712 	SUB	ZX_MINUS	; is character '-' ?
   5713 	JR	NC,SUBMLTDIV	; forward with - * / and '**' '<>'
   5714 
   5715 	ADD	A,13		; increase others by thirteen
   5716 				; $09 '>' thru $0C '+'
   5717 	JR	GET_PRIO	; forward
   5718 
   5719 ; ___
   5720 
   5721 mark_10A7:
   5722 SUBMLTDIV:
   5723 	CP	$03		; isolate $00 '-', $01 '*', $02 '/'
   5724 	JR	C,GET_PRIO	; forward if so
   5725 
   5726 ; else possibly originally $D8 '**' thru $DD '<>' already reduced by $16
   5727 
   5728 	SUB	$C2		; giving range $00 to $05
   5729 	JR	C,S_LOOP	; forward if less
   5730 
   5731 	CP	$06		; test the upper limit for nonsense also
   5732 	JR	NC,S_LOOP	; forward if so
   5733 
   5734 	ADD	A,$03		; increase by 3 to give combined operators of
   5735 
   5736 				; $00 '-'
   5737 				; $01 '*'
   5738 				; $02 '/'
   5739 
   5740 				; $03 '**'
   5741 				; $04 'OR'
   5742 				; $05 'AND'
   5743 				; $06 '<='
   5744 				; $07 '>='
   5745 				; $08 '<>'
   5746 
   5747 				; $09 '>'
   5748 				; $0A '<'
   5749 				; $0B '='
   5750 				; $0C '+'
   5751 
   5752 mark_10B5:
   5753 GET_PRIO:
   5754 	ADD	A,C		; add to default operation 'sub' ($C3)
   5755 	LD	C,A		; and place in operator byte - C.
   5756 
   5757 	LD	HL,tbl_pri - $C3	; theoretical base of the priorities table.
   5758 	ADD	HL,BC		; add C ( B is zero)
   5759 	LD	B,(HL)		; pick up the priority in B
   5760 
   5761 mark_10BC:
   5762 S_LOOP:
   5763 	POP	DE		; restore previous
   5764 	LD	A,D		; load A with priority.
   5765 	CP	B		; is present priority higher
   5766 	JR	C,S_TIGHTER	; forward if so to S_TIGHTER
   5767 
   5768 	AND	A		; are both priorities zero
   5769 	JP	Z,GET_CHAR	; exit if zero via GET_CHAR
   5770 
   5771 	PUSH	BC		; stack present values
   5772 	PUSH	DE		; stack last values
   5773 	CALL	SYNTAX_Z
   5774 	JR	Z,S_SYNTEST	; forward is checking syntax
   5775 
   5776 	LD	A,E		; fetch last operation
   5777 	AND	$3F		; mask off the indicator bits to give true
   5778 				; calculator literal.
   5779 	LD	B,A		; place in the B register for BERG
   5780 
   5781 ; perform the single operation
   5782 
   5783 	RST	_FP_CALC	;;
   5784 	DEFB	__fp_calc_2	;;
   5785 	DEFB	__end_calc	;;
   5786 
   5787 	JR	S_RUNTEST	; forward
   5788 
   5789 ; ___
   5790 
   5791 mark_10D5:
   5792 S_SYNTEST:
   5793 	LD	A,E			; transfer masked operator to A
   5794 	XOR	(IY+FLAGS-RAMBASE)	; XOR with FLAGS like results will reset bit 6
   5795 	AND	$40			; test bit 6
   5796 
   5797 mark_10DB:
   5798 S_RPORT_C:
   5799 	JP	NZ,REPORT_C	; back if results do not agree.
   5800 
   5801 ; ___
   5802 
   5803 ; in run-time impose bit 7 of the operator onto bit 6 of the FLAGS
   5804 
   5805 mark_10DE:
   5806 S_RUNTEST:
   5807 	POP	DE		; restore last operation.
   5808 	LD	HL,FLAGS	; address system variable FLAGS
   5809 	SET	6,(HL)		; presume a numeric result
   5810 	BIT	7,E		; test expected result in operation
   5811 	JR	NZ,S_LOOPEND	; forward if numeric
   5812 
   5813 	RES	6,(HL)		; reset to signal string result
   5814 
   5815 mark_10EA:
   5816 S_LOOPEND:
   5817 	POP	BC		; restore present values
   5818 	JR	S_LOOP		; back
   5819 
   5820 ; ___
   5821 
   5822 mark_10ED:
   5823 S_TIGHTER:
   5824 	PUSH	DE		; push last values and consider these
   5825 
   5826 	LD	A,C		; get the present operator.
   5827 	BIT	6,(IY+FLAGS-RAMBASE)	; Numeric or string result?
   5828 	JR	NZ,S_NEXT	; forward if numeric to S_NEXT
   5829 
   5830 	AND	$3F		; strip indicator bits to give clear literal.
   5831 	ADD	A,$08		; add eight - augmenting numeric to equivalent
   5832 				; string literals.
   5833 	LD	C,A		; place plain literal back in C.
   5834 	CP	$10		; compare to 'AND'
   5835 	JR	NZ,S_NOT_AND	; forward if not
   5836 
   5837 	SET	6,C		; set the numeric operand required for 'AND'
   5838 	JR	S_NEXT		; forward to S_NEXT
   5839 
   5840 ; ___
   5841 
   5842 mark_1102:
   5843 S_NOT_AND:
   5844 	JR	C,S_RPORT_C	; back if less than 'AND'
   5845 				; Nonsense if '-', '*' etc.
   5846 
   5847 	CP	__strs_add	; compare to 'strs_add' literal
   5848 	JR	Z,S_NEXT	; forward if so signaling string result
   5849 
   5850 	SET	7,C		; set bit to numeric (Boolean) for others.
   5851 
   5852 mark_110A:
   5853 S_NEXT:
   5854 	PUSH	BC		; stack 'present' values
   5855 
   5856 	RST	_NEXT_CHAR
   5857 	JP	S_LOOP_1	; jump back
   5858 
   5859 
   5860 
   5861 
   5862 ; THE 'TABLE OF PRIORITIES'
   5863 
   5864 
   5865 mark_110F:
   5866 tbl_pri:
   5867 	DEFB	6		;	'-'
   5868 	DEFB	8		;	'*'
   5869 	DEFB	8		;	'/'
   5870 	DEFB	10		;	'**'
   5871 	DEFB	2		;	'OR'
   5872 	DEFB	3		;	'AND'
   5873 	DEFB	5		;	'<='
   5874 	DEFB	5		;	'>='
   5875 	DEFB	5		;	'<>'
   5876 	DEFB	5		;	'>'
   5877 	DEFB	5		;	'<'
   5878 	DEFB	5		;	'='
   5879 	DEFB	6		;	'+'
   5880 
   5881 
   5882 ; THE 'LOOK_VARS' SUBROUTINE
   5883 
   5884 
   5885 mark_111C:
   5886 LOOK_VARS:
   5887 	SET	6,(IY+FLAGS-RAMBASE)	; Signal numeric result
   5888 
   5889 	RST	_GET_CHAR
   5890 	CALL	ALPHA
   5891 	JP	NC,REPORT_C	; to REPORT_C
   5892 
   5893 	PUSH	HL		;
   5894 	LD	C,A		;
   5895 
   5896 	RST	_NEXT_CHAR
   5897 	PUSH	HL		;
   5898 	RES	5,C		;
   5899 	CP	$10		; $10
   5900 	JR	Z,V_RUN_SYN
   5901 
   5902 	SET	6,C		;
   5903 	CP	ZX_DOLLAR	; $0D
   5904 	JR	Z,V_STR_VAR	; forward
   5905 
   5906 	SET	5,C		;
   5907 
   5908 mark_1139:
   5909 V_CHAR:
   5910 	CALL	ALPHANUM
   5911 	JR	NC,V_RUN_SYN	; forward when not
   5912 
   5913 	RES	6,C		;
   5914 
   5915 	RST	_NEXT_CHAR
   5916 	JR	V_CHAR		; loop back
   5917 
   5918 ; ___
   5919 
   5920 mark_1143:
   5921 V_STR_VAR:
   5922 	RST	_NEXT_CHAR
   5923 	RES	6,(IY+FLAGS-RAMBASE)	; Signal string result
   5924 
   5925 mark_1148:
   5926 V_RUN_SYN:
   5927 	LD	B,C		;
   5928 	CALL	SYNTAX_Z
   5929 	JR	NZ,V_RUN	; forward
   5930 
   5931 	LD	A,C		;
   5932 	AND	$E0		;
   5933 	SET	7,A		;
   5934 	LD	C,A		;
   5935 	JR	V_SYNTAX	; forward
   5936 
   5937 ; ___
   5938 
   5939 mark_1156:
   5940 V_RUN:
   5941 	LD	HL,(VARS)	; sv
   5942 
   5943 mark_1159:
   5944 V_EACH:
   5945 	LD	A,(HL)		;
   5946 	AND	$7F		;
   5947 	JR	Z,V_80_BYTE	;
   5948 
   5949 	CP	C		;
   5950 	JR	NZ,V_NEXT	;
   5951 
   5952 	RLA			;
   5953 	ADD	A,A		;
   5954 	JP	P,V_FOUND_2
   5955 
   5956 	JR	C,V_FOUND_2
   5957 
   5958 	POP	DE		;
   5959 	PUSH	DE		;
   5960 	PUSH	HL		;
   5961 
   5962 mark_116B:
   5963 V_MATCHES:
   5964 	INC	HL		;
   5965 
   5966 mark_116C:
   5967 V_SPACES:
   5968 	LD	A,(DE)		;
   5969 	INC	DE		;
   5970 	AND	A		;
   5971 	JR	Z,V_SPACES	; back
   5972 
   5973 	CP	(HL)		;
   5974 	JR	Z,V_MATCHES	; back
   5975 
   5976 	OR	$80		;
   5977 	CP	(HL)		;
   5978 	JR	NZ,V_GET_PTR	; forward
   5979 
   5980 	LD	A,(DE)		;
   5981 	CALL	ALPHANUM
   5982 	JR	NC,V_FOUND_1	; forward
   5983 
   5984 mark_117F:
   5985 V_GET_PTR:
   5986 	POP	HL		;
   5987 
   5988 mark_1180:
   5989 V_NEXT:
   5990 	PUSH	BC		;
   5991 	CALL	NEXT_ONE
   5992 	EX	DE,HL		;
   5993 	POP	BC		;
   5994 	JR	V_EACH		; back
   5995 
   5996 ; ___
   5997 
   5998 mark_1188:
   5999 V_80_BYTE:
   6000 	SET	7,B		;
   6001 
   6002 mark_118A:
   6003 V_SYNTAX:
   6004 	POP	DE		;
   6005 
   6006 	RST	_GET_CHAR
   6007 	CP	$10		;
   6008 	JR	Z,V_PASS	; forward
   6009 
   6010 	SET	5,B		;
   6011 	JR	V_END		; forward
   6012 
   6013 ; ___
   6014 
   6015 mark_1194:
   6016 V_FOUND_1:
   6017 	POP	DE		;
   6018 
   6019 mark_1195:
   6020 V_FOUND_2:
   6021 	POP	DE		;
   6022 	POP	DE		;
   6023 	PUSH	HL		;
   6024 
   6025 	RST	_GET_CHAR
   6026 
   6027 mark_1199:
   6028 V_PASS:
   6029 	CALL	ALPHANUM
   6030 	JR	NC,V_END	; forward if not alphanumeric
   6031 
   6032 
   6033 	RST	_NEXT_CHAR
   6034 	JR	V_PASS		; back
   6035 
   6036 ; ___
   6037 
   6038 mark_11A1:
   6039 V_END:
   6040 	POP	HL		;
   6041 	RL	B		;
   6042 	BIT	6,B		;
   6043 	RET			;
   6044 
   6045 
   6046 ; THE 'STK_VAR' SUBROUTINE
   6047 
   6048 
   6049 mark_11A7:
   6050 STK_VAR:
   6051 	XOR	A		;
   6052 	LD	B,A		;
   6053 	BIT	7,C		;
   6054 	JR	NZ,SV_COUNT	; forward
   6055 
   6056 	BIT	7,(HL)		;
   6057 	JR	NZ,SV_ARRAYS	; forward
   6058 
   6059 	INC	A		;
   6060 
   6061 mark_11B2:
   6062 SV_SIMPLE_STR:
   6063 	INC	HL		;
   6064 	LD	C,(HL)		;
   6065 	INC	HL		;
   6066 	LD	B,(HL)		;
   6067 	INC	HL		;
   6068 	EX	DE,HL		;
   6069 	CALL	STK_STO_STR
   6070 
   6071 	RST	_GET_CHAR
   6072 	JP	SV_SLICE_QUERY	; jump forward
   6073 
   6074 ; ___
   6075 
   6076 mark_11BF:
   6077 SV_ARRAYS:
   6078 	INC	HL		;
   6079 	INC	HL		;
   6080 	INC	HL		;
   6081 	LD	B,(HL)		;
   6082 	BIT	6,C		;
   6083 	JR	Z,SV_PTR	; forward
   6084 
   6085 	DEC	B		;
   6086 	JR	Z,SV_SIMPLE_STR	; forward
   6087 
   6088 	EX	DE,HL		;
   6089 
   6090 	RST	_GET_CHAR
   6091 	CP	$10		;
   6092 	JR	NZ,REPORT_3	; forward
   6093 
   6094 	EX	DE,HL		;
   6095 
   6096 mark_11D1:
   6097 SV_PTR:
   6098 	EX	DE,HL		;
   6099 	JR	SV_COUNT	; forward
   6100 ; ___
   6101 mark_11D4:
   6102 SV_COMMA:
   6103 	PUSH	HL		;
   6104 
   6105 	RST	_GET_CHAR
   6106 	POP	HL		;
   6107 	CP	ZX_COMMA	; $1A == 26
   6108 	JR	Z,SV_LOOP	; forward
   6109 
   6110 	BIT	7,C		;
   6111 	JR	Z,REPORT_3	; forward
   6112 
   6113 	BIT	6,C		;
   6114 	JR	NZ,SV_CLOSE	; forward
   6115 
   6116 	CP	ZX_BRACKET_RIGHT		; $11
   6117 	JR	NZ,SV_RPT_C	; forward
   6118 
   6119 
   6120 	RST	_NEXT_CHAR
   6121 	RET			;
   6122 ; ___
   6123 mark_11E9:
   6124 SV_CLOSE:
   6125 	CP	ZX_BRACKET_RIGHT		; $11
   6126 	JR	Z,SV_DIM	; forward
   6127 
   6128 	CP	$DF		;
   6129 	JR	NZ,SV_RPT_C	; forward
   6130 
   6131 mark_11F1:
   6132 SV_CH_ADD:
   6133 	RST	_GET_CHAR
   6134 	DEC	HL		;
   6135 	LD	(CH_ADD),HL	; sv
   6136 	JR	SV_SLICE	; forward
   6137 
   6138 ; ___
   6139 
   6140 mark_11F8:
   6141 SV_COUNT:
   6142 	LD	HL,$0000	;
   6143 
   6144 mark_11FB:
   6145 SV_LOOP:
   6146 	PUSH	HL		;
   6147 
   6148 	RST	_NEXT_CHAR
   6149 	POP	HL		;
   6150 	LD	A,C		;
   6151 	CP	ZX_DOUBLE_QUOTE	;
   6152 	JR	NZ,SV_MULT	; forward
   6153 
   6154 
   6155 	RST	_GET_CHAR
   6156 	CP	ZX_BRACKET_RIGHT
   6157 	JR	Z,SV_DIM	; forward
   6158 
   6159 	CP	ZX_TO		;
   6160 	JR	Z,SV_CH_ADD	; back
   6161 
   6162 mark_120C:
   6163 SV_MULT:
   6164 	PUSH	BC		;
   6165 	PUSH	HL		;
   6166 	CALL	DE_DE_PLUS_ONE
   6167 	EX	(SP),HL	;
   6168 	EX	DE,HL		;
   6169 	CALL	INT_EXP1
   6170 	JR	C,REPORT_3
   6171 
   6172 	DEC	BC		;
   6173 	CALL	GET_HL_TIMES_DE
   6174 	ADD	HL,BC		;
   6175 	POP	DE		;
   6176 	POP	BC		;
   6177 	DJNZ	SV_COMMA		; loop back
   6178 
   6179 	BIT	7,C		;
   6180 
   6181 mark_1223:
   6182 SV_RPT_C:
   6183 	JR	NZ,SL_RPT_C
   6184 
   6185 	PUSH	HL		;
   6186 	BIT	6,C		;
   6187 	JR	NZ,SV_ELEM_STR
   6188 
   6189 	LD	B,D		;
   6190 	LD	C,E		;
   6191 
   6192 	RST	_GET_CHAR
   6193 	CP	ZX_BRACKET_RIGHT; is character a ')' ?
   6194 	JR	Z,SV_NUMBER	; skip forward
   6195 
   6196 
   6197 mark_1231:
   6198 REPORT_3:
   6199 	RST	_ERROR_1
   6200 	DEFB	$02		; Error Report: Subscript wrong
   6201 
   6202 
   6203 mark_1233:
   6204 SV_NUMBER:
   6205 	RST	_NEXT_CHAR
   6206 	POP	HL		;
   6207 	LD	DE,$0005	;
   6208 	CALL	GET_HL_TIMES_DE
   6209 	ADD	HL,BC		;
   6210 	RET			; return				>>
   6211 
   6212 ; ___
   6213 
   6214 mark_123D:
   6215 SV_ELEM_STR:
   6216 	CALL	DE_DE_PLUS_ONE
   6217 	EX	(SP),HL	;
   6218 	CALL	GET_HL_TIMES_DE
   6219 	POP	BC		;
   6220 	ADD	HL,BC		;
   6221 	INC	HL		;
   6222 	LD	B,D		;
   6223 	LD	C,E		;
   6224 	EX	DE,HL		;
   6225 	CALL	STK_ST_0
   6226 
   6227 	RST	_GET_CHAR
   6228 	CP	ZX_BRACKET_RIGHT ; is it ')' ?
   6229 	JR	Z,SV_DIM	; forward if so
   6230 
   6231 	CP	ZX_COMMA	; $1A == 26		; is it ',' ?
   6232 	JR	NZ,REPORT_3	; back if not
   6233 
   6234 mark_1256:
   6235 SV_SLICE:
   6236 	CALL	SLICING
   6237 
   6238 mark_1259:
   6239 SV_DIM:
   6240 	RST	_NEXT_CHAR
   6241 
   6242 mark_125A:
   6243 SV_SLICE_QUERY:
   6244 	CP	$10		;
   6245 	JR	Z,SV_SLICE	; back
   6246 
   6247 	RES	6,(IY+FLAGS-RAMBASE)	; Signal string result
   6248 	RET			; return.
   6249 
   6250 
   6251 ; THE 'SLICING' SUBROUTINE
   6252 
   6253 ;
   6254 ;
   6255 
   6256 mark_1263:
   6257 SLICING:
   6258 	CALL	SYNTAX_Z
   6259 	CALL	NZ,STK_FETCH
   6260 
   6261 	RST	_NEXT_CHAR
   6262 	CP	ZX_BRACKET_RIGHT; is it ')' ?
   6263 	JR	Z,SL_STORE	; forward if so
   6264 
   6265 	PUSH	DE		;
   6266 	XOR	A		;
   6267 	PUSH	AF		;
   6268 	PUSH	BC		;
   6269 	LD	DE,$0001	;
   6270 
   6271 	RST	_GET_CHAR
   6272 	POP	HL		;
   6273 	CP	ZX_TO		; is it 'TO' ?
   6274 	JR	Z,SL_SECOND	; forward if so
   6275 
   6276 	POP	AF		;
   6277 	CALL	INT_EXP2
   6278 	PUSH	AF		;
   6279 	LD	D,B		;
   6280 	LD	E,C		;
   6281 	PUSH	HL		;
   6282 
   6283 	RST	_GET_CHAR
   6284 	POP	HL		;
   6285 	CP	ZX_TO		; is it 'TO' ?
   6286 	JR	Z,SL_SECOND	; forward if so
   6287 
   6288 	CP	ZX_BRACKET_RIGHT; $11
   6289 
   6290 mark_128B:
   6291 SL_RPT_C:
   6292 	JP	NZ,REPORT_C
   6293 
   6294 	LD	H,D		;
   6295 	LD	L,E		;
   6296 	JR	SL_DEFINE		; forward
   6297 
   6298 ; ___
   6299 
   6300 mark_1292:
   6301 SL_SECOND:
   6302 	PUSH	HL		;
   6303 
   6304 	RST	_NEXT_CHAR
   6305 	POP	HL		;
   6306 	CP	ZX_BRACKET_RIGHT; is it ')' ?
   6307 	JR	Z,SL_DEFINE	; forward if so
   6308 
   6309 	POP	AF		;
   6310 	CALL	INT_EXP2
   6311 	PUSH	AF		;
   6312 
   6313 	RST	_GET_CHAR
   6314 	LD	H,B		;
   6315 	LD	L,C		;
   6316 	CP	ZX_BRACKET_RIGHT; is it ')' ?
   6317 	JR	NZ,SL_RPT_C	; back if not
   6318 
   6319 mark_12A5:
   6320 SL_DEFINE:
   6321 	POP	AF		;
   6322 	EX	(SP),HL	;
   6323 	ADD	HL,DE		;
   6324 	DEC	HL		;
   6325 	EX	(SP),HL	;
   6326 	AND	A		;
   6327 	SBC	HL,DE		;
   6328 	LD	BC,$0000	;
   6329 	JR	C,SL_OVER	; forward
   6330 
   6331 	INC	HL		;
   6332 	AND	A		;
   6333 	JP	M,REPORT_3	; jump back
   6334 
   6335 	LD	B,H		;
   6336 	LD	C,L		;
   6337 
   6338 mark_12B9:
   6339 SL_OVER:
   6340 	POP	DE		;
   6341 	RES	6,(IY+FLAGS-RAMBASE)	; Signal string result
   6342 
   6343 mark_12BE:
   6344 SL_STORE:
   6345 	CALL	SYNTAX_Z
   6346 	RET	Z		; return if checking syntax.
   6347 
   6348 
   6349 ; THE 'STK_STORE' SUBROUTINE
   6350 
   6351 ;
   6352 ;
   6353 
   6354 mark_12C2:
   6355 STK_ST_0:
   6356 	XOR	A		;
   6357 
   6358 mark_12C3:
   6359 STK_STO_STR:
   6360 	PUSH	BC		;
   6361 	CALL	TEST_5_SP
   6362 	POP	BC		;
   6363 	LD	HL,(STKEND)	; sv
   6364 	LD	(HL),A		;
   6365 	INC	HL		;
   6366 	LD	(HL),E		;
   6367 	INC	HL		;
   6368 	LD	(HL),D		;
   6369 	INC	HL		;
   6370 	LD	(HL),C		;
   6371 	INC	HL		;
   6372 	LD	(HL),B		;
   6373 	INC	HL		;
   6374 	LD	(STKEND),HL	; sv
   6375 	RES	6,(IY+FLAGS-RAMBASE)	; Signal string result
   6376 	RET			; return.
   6377 
   6378 
   6379 ; THE 'INT EXP' SUBROUTINES
   6380 
   6381 ;
   6382 ;
   6383 
   6384 mark_12DD:
   6385 INT_EXP1:
   6386 	XOR	A		;
   6387 
   6388 mark_12DE:
   6389 INT_EXP2:
   6390 	PUSH	DE		;
   6391 	PUSH	HL		;
   6392 	PUSH	AF		;
   6393 	CALL	CLASS_6
   6394 	POP	AF		;
   6395 	CALL	SYNTAX_Z
   6396 	JR	Z,I_RESTORE	; forward if checking syntax
   6397 
   6398 	PUSH	AF		;
   6399 	CALL	FIND_INT
   6400 	POP	DE		;
   6401 	LD	A,B		;
   6402 	OR	C		;
   6403 	SCF			; Set Carry Flag
   6404 	JR	Z,I_CARRY	; forward
   6405 
   6406 	POP	HL		;
   6407 	PUSH	HL		;
   6408 	AND	A		;
   6409 	SBC	HL,BC		;
   6410 
   6411 mark_12F9:
   6412 I_CARRY:
   6413 	LD	A,D		;
   6414 	SBC	A,$00		;
   6415 
   6416 mark_12FC:
   6417 I_RESTORE:
   6418 	POP	HL		;
   6419 	POP	DE		;
   6420 	RET			;
   6421 
   6422 
   6423 ; THE 'DE,(DE+1)' SUBROUTINE
   6424 
   6425 ; INDEX and LOAD Z80 subroutine. 
   6426 ; This emulates the 6800 processor instruction LDX 1,X which loads a two_byte
   6427 ; value from memory into the register indexing it. Often these are hardly worth
   6428 ; the bother of writing as subroutines and this one doesn't save any time or 
   6429 ; memory. The timing and space overheads have to be offset against the ease of
   6430 ; writing and the greater program readability from using such toolkit routines.
   6431 
   6432 mark_12FF:
   6433 DE_DE_PLUS_ONE:
   6434 	EX	DE,HL		; move index address into HL.
   6435 	INC	HL		; increment to address word.
   6436 	LD	E,(HL)		; pick up word low_order byte.
   6437 	INC	HL		; index high_order byte and 
   6438 	LD	D,(HL)		; pick it up.
   6439 	RET			; return with DE = word.
   6440 
   6441 
   6442 ; THE 'GET_HL_TIMES_DE' SUBROUTINE
   6443 
   6444 ;
   6445 
   6446 mark_1305:
   6447 GET_HL_TIMES_DE:
   6448 	CALL	SYNTAX_Z
   6449 	RET	Z		;
   6450 
   6451 	PUSH	BC		;
   6452 	LD	B,$10		;
   6453 	LD	A,H		;
   6454 	LD	C,L		;
   6455 	LD	HL,$0000	;
   6456 
   6457 mark_1311:
   6458 HL_LOOP:
   6459 	ADD	HL,HL		;
   6460 	JR	C,HL_END	; forward with carry
   6461 
   6462 	RL	C		;
   6463 	RLA			;
   6464 	JR	NC,HL_AGAIN	; forward with no carry
   6465 
   6466 	ADD	HL,DE		;
   6467 
   6468 mark_131A:
   6469 HL_END:
   6470 	JP	C,REPORT_4
   6471 
   6472 mark_131D:
   6473 HL_AGAIN:
   6474 	DJNZ	HL_LOOP		; loop back
   6475 
   6476 	POP	BC		;
   6477 	RET			; return.
   6478 
   6479 
   6480 ; THE 'LET' SUBROUTINE
   6481 
   6482 ;
   6483 ;
   6484 
   6485 mark_1321:
   6486 LET:
   6487 	LD	HL,(DEST)
   6488 	BIT	1,(IY+FLAGX-RAMBASE)
   6489 	JR	Z,L_EXISTS	; forward
   6490 
   6491 	LD	BC,$0005	;
   6492 
   6493 mark_132D:
   6494 L_EACH_CH:
   6495 	INC	BC		;
   6496 
   6497 ; check
   6498 
   6499 mark_132E:
   6500 L_NO_SP:
   6501 	INC	HL		;
   6502 	LD	A,(HL)		;
   6503 	AND	A		;
   6504 	JR	Z,L_NO_SP	; back
   6505 
   6506 	CALL	ALPHANUM
   6507 	JR	C,L_EACH_CH	; back
   6508 
   6509 	CP	ZX_DOLLAR	; is it '$' ?
   6510 	JP	Z,L_NEW_STR	; forward if so
   6511 
   6512 
   6513 	RST	_BC_SPACES		; BC_SPACES
   6514 	PUSH	DE		;
   6515 	LD	HL,(DEST)	; 
   6516 	DEC	DE		;
   6517 	LD	A,C		;
   6518 	SUB	$06		;
   6519 	LD	B,A		;
   6520 	LD	A,$40		;
   6521 	JR	Z,L_SINGLE
   6522 
   6523 mark_134B:
   6524 L_CHAR:
   6525 	INC	HL		;
   6526 	LD	A,(HL)		;
   6527 	AND	A		; is it a space ?
   6528 	JR	Z,L_CHAR	; back
   6529 
   6530 	INC	DE		;
   6531 	LD	(DE),A		;
   6532 	DJNZ	L_CHAR		; loop back
   6533 
   6534 	OR	$80		;
   6535 	LD	(DE),A		;
   6536 	LD	A,$80		;
   6537 
   6538 mark_1359:
   6539 L_SINGLE:
   6540 	LD	HL,(DEST)	; 
   6541 	XOR	(HL)		;
   6542 	POP	HL		;
   6543 	CALL	L_FIRST
   6544 
   6545 mark_1361:
   6546 L_NUMERIC:
   6547 	PUSH	HL		;
   6548 
   6549 	RST	_FP_CALC	;;
   6550 	DEFB	__delete	;;
   6551 	DEFB	__end_calc	;;
   6552 
   6553 	POP	HL		;
   6554 	LD	BC,$0005	;
   6555 	AND	A		;
   6556 	SBC	HL,BC		;
   6557 	JR	L_ENTER		; forward
   6558 
   6559 ; ___
   6560 
   6561 mark_136E:
   6562 L_EXISTS:
   6563 	BIT	6,(IY+FLAGS-RAMBASE)	; Numeric or string result?
   6564 	JR	Z,L_DELETE_STR	; forward
   6565 
   6566 	LD	DE,$0006	;
   6567 	ADD	HL,DE		;
   6568 	JR	L_NUMERIC		; back
   6569 
   6570 ; ___
   6571 
   6572 mark_137A:
   6573 L_DELETE_STR:
   6574 	LD	HL,(DEST)	; 
   6575 	LD	BC,(STRLEN)	;
   6576 	BIT	0,(IY+FLAGX-RAMBASE)
   6577 	JR	NZ,L_ADD_STR	; forward
   6578 
   6579 	LD	A,B		;
   6580 	OR	C		;
   6581 	RET	Z		;
   6582 
   6583 	PUSH	HL		;
   6584 
   6585 	RST	_BC_SPACES
   6586 	PUSH	DE		;
   6587 	PUSH	BC		;
   6588 	LD	D,H		;
   6589 	LD	E,L		;
   6590 	INC	HL		;
   6591 	LD	(HL),$00	;
   6592 	LDDR			; Copy Bytes
   6593 	PUSH	HL		;
   6594 	CALL	STK_FETCH
   6595 	POP	HL		;
   6596 	EX	(SP),HL	;
   6597 	AND	A		;
   6598 	SBC	HL,BC		;
   6599 	ADD	HL,BC		;
   6600 	JR	NC,L_LENGTH	; forward
   6601 
   6602 	LD	B,H		;
   6603 	LD	C,L		;
   6604 
   6605 mark_13A3:
   6606 L_LENGTH:
   6607 	EX	(SP),HL	;
   6608 	EX	DE,HL		;
   6609 	LD	A,B		;
   6610 	OR	C		;
   6611 	JR	Z,L_IN_W_S	; forward if zero
   6612 
   6613 	LDIR			; Copy Bytes
   6614 
   6615 mark_13AB:
   6616 L_IN_W_S:
   6617 	POP	BC		;
   6618 	POP	DE		;
   6619 	POP	HL		;
   6620 
   6621 
   6622 ; THE 'L_ENTER' SUBROUTINE
   6623 ;
   6624 ;   Part of the LET command contains a natural subroutine which is a 
   6625 ;   conditional LDIR. The copy only occurs of BC is non-zero.
   6626 
   6627 mark_13AE:
   6628 L_ENTER:
   6629 	EX	DE,HL		;
   6630 if ORIGINAL
   6631 else
   6632 COND_MV:
   6633 endif
   6634 	LD	A,B		;
   6635 	OR	C		;
   6636 	RET	Z		;
   6637 
   6638 	PUSH	DE		;
   6639 	LDIR			; Copy Bytes
   6640 	POP	HL		;
   6641 	RET			; return.
   6642 
   6643 mark_13B7:
   6644 L_ADD_STR:
   6645 	DEC	HL		;
   6646 	DEC	HL		;
   6647 	DEC	HL		;
   6648 	LD	A,(HL)		;
   6649 	PUSH	HL		;
   6650 	PUSH	BC		;
   6651 
   6652 	CALL	L_STRING
   6653 
   6654 	POP	BC		;
   6655 	POP	HL		;
   6656 	INC	BC		;
   6657 	INC	BC		;
   6658 	INC	BC		;
   6659 	JP	RECLAIM_2		; jump back to exit via RECLAIM_2
   6660 
   6661 ; ___
   6662 
   6663 mark_13C8:
   6664 L_NEW_STR:
   6665 	LD	A,$60		; prepare mask %01100000
   6666 	LD	HL,(DEST)	; 
   6667 	XOR	(HL)		;
   6668 
   6669 
   6670 ; THE 'L_STRING' SUBROUTINE
   6671 
   6672 ;
   6673 
   6674 mark_13CE:
   6675 L_STRING:
   6676 	PUSH	AF		;
   6677 	CALL	STK_FETCH
   6678 	EX	DE,HL		;
   6679 	ADD	HL,BC		;
   6680 	PUSH	HL		;
   6681 	INC	BC		;
   6682 	INC	BC		;
   6683 	INC	BC		;
   6684 
   6685 	RST	_BC_SPACES
   6686 	EX	DE,HL		;
   6687 	POP	HL		;
   6688 	DEC	BC		;
   6689 	DEC	BC		;
   6690 	PUSH	BC		;
   6691 	LDDR			; Copy Bytes
   6692 	EX	DE,HL		;
   6693 	POP	BC		;
   6694 	DEC	BC		;
   6695 	LD	(HL),B		;
   6696 	DEC	HL		;
   6697 	LD	(HL),C		;
   6698 	POP	AF		;
   6699 
   6700 mark_13E7:
   6701 L_FIRST:
   6702 	PUSH	AF		;
   6703 	CALL	REC_V80
   6704 	POP	AF		;
   6705 	DEC	HL		;
   6706 	LD	(HL),A		;
   6707 	LD	HL,(STKBOT)	; sv
   6708 	LD	(E_LINE),HL	; sv
   6709 	DEC	HL		;
   6710 	LD	(HL),$80	;
   6711 	RET			;
   6712 
   6713 
   6714 ; THE 'STK_FETCH' SUBROUTINE
   6715 
   6716 ; This routine fetches a five-byte value from the calculator stack
   6717 ; reducing the pointer to the end of the stack by five.
   6718 ; For a floating-point number the exponent is in A and the mantissa
   6719 ; is the thirty-two bits EDCB.
   6720 ; For strings, the start of the string is in DE and the length in BC.
   6721 ; A is unused.
   6722 
   6723 mark_13F8:
   6724 STK_FETCH:
   6725 	LD	HL,(STKEND)	; load HL from system variable STKEND
   6726 
   6727 	DEC	HL		;
   6728 	LD	B,(HL)		;
   6729 	DEC	HL		;
   6730 	LD	C,(HL)		;
   6731 	DEC	HL		;
   6732 	LD	D,(HL)		;
   6733 	DEC	HL		;
   6734 	LD	E,(HL)		;
   6735 	DEC	HL		;
   6736 	LD	A,(HL)		;
   6737 
   6738 	LD	(STKEND),HL	; set system variable STKEND to lower value.
   6739 	RET			; return.
   6740 
   6741 
   6742 ; THE 'DIM' COMMAND ROUTINE
   6743 
   6744 ; An array is created and initialized to zeros which is also the space
   6745 ; character on the ZX81.
   6746 
   6747 mark_1409:
   6748 DIM:
   6749 	CALL	LOOK_VARS
   6750 
   6751 mark_140C:
   6752 D_RPORT_C:
   6753 	JP	NZ,REPORT_C
   6754 
   6755 	CALL	SYNTAX_Z
   6756 	JR	NZ,D_RUN	; forward
   6757 
   6758 	RES	6,C		;
   6759 	CALL	STK_VAR
   6760 	CALL	CHECK_END
   6761 
   6762 mark_141C:
   6763 D_RUN:
   6764 	JR	C,D_LETTER	; forward
   6765 
   6766 	PUSH	BC		;
   6767 	CALL	NEXT_ONE
   6768 	CALL	RECLAIM_2
   6769 	POP	BC		;
   6770 
   6771 mark_1426:
   6772 D_LETTER:
   6773 	SET	7,C		;
   6774 	LD	B,$00		;
   6775 	PUSH	BC		;
   6776 	LD	HL,$0001	;
   6777 	BIT	6,C		;
   6778 	JR	NZ,D_SIZE	; forward
   6779 
   6780 	LD	L,$05		;
   6781 
   6782 mark_1434:
   6783 D_SIZE:
   6784 	EX	DE,HL		;
   6785 
   6786 mark_1435:
   6787 D_NO_LOOP:
   6788 	RST	_NEXT_CHAR
   6789 	LD	H,$40		;
   6790 	CALL	INT_EXP1
   6791 	JP	C,REPORT_3
   6792 
   6793 	POP	HL		;
   6794 	PUSH	BC		;
   6795 	INC	H		;
   6796 	PUSH	HL		;
   6797 	LD	H,B		;
   6798 	LD	L,C		;
   6799 	CALL	GET_HL_TIMES_DE
   6800 	EX	DE,HL		;
   6801 
   6802 	RST	_GET_CHAR
   6803 	CP	ZX_COMMA	; $1A == 26
   6804 	JR	Z,D_NO_LOOP	; back
   6805 
   6806 	CP	ZX_BRACKET_RIGHT; is it ')' ?
   6807 	JR	NZ,D_RPORT_C	; back if not
   6808 
   6809 
   6810 	RST	_NEXT_CHAR
   6811 	POP	BC		;
   6812 	LD	A,C		;
   6813 	LD	L,B		;
   6814 	LD	H,$00		;
   6815 	INC	HL		;
   6816 	INC	HL		;
   6817 	ADD	HL,HL		;
   6818 	ADD	HL,DE		;
   6819 	JP	C,REPORT_4
   6820 
   6821 	PUSH	DE		;
   6822 	PUSH	BC		;
   6823 	PUSH	HL		;
   6824 	LD	B,H		;
   6825 	LD	C,L		;
   6826 	LD	HL,(E_LINE)	; sv
   6827 	DEC	HL		;
   6828 	CALL	MAKE_ROOM
   6829 	INC	HL		;
   6830 	LD	(HL),A	;
   6831 	POP	BC		;
   6832 	DEC	BC		;
   6833 	DEC	BC		;
   6834 	DEC	BC		;
   6835 	INC	HL		;
   6836 	LD	(HL),C		;
   6837 	INC	HL		;
   6838 	LD	(HL),B		;
   6839 	POP	AF		;
   6840 	INC	HL		;
   6841 	LD	(HL),A		;
   6842 	LD	H,D		;
   6843 	LD	L,E		;
   6844 	DEC	DE		;
   6845 	LD	(HL),0		;
   6846 	POP	BC		;
   6847 	LDDR			; Copy Bytes
   6848 
   6849 mark_147F:
   6850 DIM_SIZES:
   6851 	POP	BC		;
   6852 	LD	(HL),B		;
   6853 	DEC	HL		;
   6854 	LD	(HL),C		;
   6855 	DEC	HL		;
   6856 	DEC	A		;
   6857 	JR	NZ,DIM_SIZES	; back
   6858 
   6859 	RET			; return.
   6860 
   6861 
   6862 ; THE 'RESERVE' ROUTINE
   6863 
   6864 ;
   6865 ;
   6866 
   6867 mark_1488:
   6868 RESERVE:
   6869 	LD	HL,(STKBOT)	; address STKBOT
   6870 	DEC	HL		; now last byte of workspace
   6871 	CALL	MAKE_ROOM
   6872 	INC	HL		;
   6873 	INC	HL		;
   6874 	POP	BC		;
   6875 	LD	(E_LINE),BC	; sv
   6876 	POP	BC		;
   6877 	EX	DE,HL		;
   6878 	INC	HL		;
   6879 	RET			;
   6880 
   6881 
   6882 ; THE 'CLEAR' COMMAND ROUTINE
   6883 
   6884 ;
   6885 ;
   6886 
   6887 mark_149A:
   6888 CLEAR:
   6889 	LD	HL,(VARS)	; sv
   6890 	LD	(HL),$80	;
   6891 	INC	HL		;
   6892 	LD	(E_LINE),HL	; sv
   6893 
   6894 
   6895 ; THE 'X_TEMP' SUBROUTINE
   6896 
   6897 ;
   6898 ;
   6899 
   6900 mark_14A3:
   6901 X_TEMP:
   6902 	LD	HL,(E_LINE)	; sv
   6903 
   6904 
   6905 ; THE 'SET_STK' ROUTINES
   6906 
   6907 ;
   6908 ;
   6909 
   6910 mark_14A6:
   6911 SET_STK_B:
   6912 	LD	(STKBOT),HL	; sv
   6913 
   6914 ;
   6915 
   6916 mark_14A9:
   6917 SET_STK_E:
   6918 	LD	(STKEND),HL	; sv
   6919 	RET			;
   6920 
   6921 
   6922 ; THE 'CURSOR_IN' ROUTINE
   6923 
   6924 ; This routine is called to set the edit line to the minimum cursor/newline
   6925 ; and to set STKEND, the start of free space, at the next position.
   6926 
   6927 mark_14AD:
   6928 CURSOR_IN:
   6929 	LD	HL,(E_LINE)		; fetch start of edit line
   6930 	LD	(HL),ZX_CURSOR		; insert cursor character
   6931 
   6932 	INC	HL			; point to next location.
   6933 	LD	(HL),ZX_NEWLINE		; insert NEWLINE character
   6934 	INC	HL			; point to next free location.
   6935 
   6936 	LD	(IY+DF_SZ-RAMBASE),2	; set lower screen display file size
   6937 
   6938 	JR	SET_STK_B		; exit via SET_STK_B above
   6939 
   6940 
   6941 ; THE 'SET_MIN' SUBROUTINE
   6942 
   6943 ;
   6944 ;
   6945 
   6946 mark_14BC:
   6947 SET_MIN:
   6948 	LD	HL,$405D	; normal location of calculator's memory area
   6949 	LD	(MEM),HL	; update system variable MEM
   6950 	LD	HL,(STKBOT)	;
   6951 	JR	SET_STK_E		; back
   6952 
   6953 
   6954 
   6955 ; THE 'RECLAIM THE END_MARKER' ROUTINE
   6956 
   6957 
   6958 mark_14C7:
   6959 REC_V80:
   6960 	LD	DE,(E_LINE)	; sv
   6961 	JP	RECLAIM_1
   6962 
   6963 
   6964 ; THE 'ALPHA' SUBROUTINE
   6965 
   6966 
   6967 mark_14CE:
   6968 ALPHA:
   6969 	CP	ZX_A		; $26
   6970 	JR	ALPHA_2		; skip forward
   6971 
   6972 
   6973 
   6974 ; THE 'ALPHANUM' SUBROUTINE
   6975 
   6976 
   6977 mark_14D2:
   6978 ALPHANUM:
   6979 	CP	ZX_0		;
   6980 
   6981 
   6982 mark_14D4:
   6983 ALPHA_2:
   6984 	CCF			; Complement Carry Flag
   6985 	RET	NC		;
   6986 
   6987 	CP	$40		;
   6988 	RET			;
   6989 
   6990 
   6991 
   6992 ; THE 'DECIMAL TO FLOATING POINT' SUBROUTINE
   6993 
   6994 ;
   6995 
   6996 mark_14D9:
   6997 DEC_TO_FP:
   6998 	CALL	INT_TO_FP		; gets first part
   6999 	CP	ZX_PERIOD		; is character a '.' ?
   7000 	JR	NZ,E_FORMAT	; forward if not
   7001 
   7002 
   7003 	RST	_FP_CALC	;;
   7004 	DEFB	__stk_one	;;
   7005 	DEFB	__st_mem_0	;;
   7006 	DEFB	__delete	;;
   7007 	DEFB	__end_calc	;;
   7008 
   7009 
   7010 mark_14E5:
   7011 
   7012 NXT_DGT_1:
   7013 	RST	_NEXT_CHAR
   7014 	CALL	STK_DIGIT
   7015 	JR	C,E_FORMAT	; forward
   7016 
   7017 
   7018 	RST	_FP_CALC	;;
   7019 	DEFB	__get_mem_0	;;
   7020 	DEFB	__stk_ten	;;
   7021 if ORIGINAL
   7022 	DEFB	__division	;
   7023 	DEFB	$C0		;;st-mem-0
   7024 	DEFB	__multiply	;;
   7025 else
   7026 	DEFB	$04		;;+multiply
   7027 	DEFB	$C0		;;st-mem-0
   7028 	DEFB	$05		;;+division
   7029 endif
   7030 	DEFB	__addition	;;
   7031 	DEFB	__end_calc	;;
   7032 
   7033 	JR	NXT_DGT_1		; loop back till exhausted
   7034 
   7035 ; ___
   7036 
   7037 mark_14F5:
   7038 E_FORMAT:
   7039 	CP	ZX_E		; is character 'E' ?
   7040 	RET	NZ		; return if not
   7041 
   7042 	LD	(IY+MEM_0_1st-RAMBASE),$FF	; initialize sv MEM_0_1st to $FF TRUE
   7043 
   7044 	RST	_NEXT_CHAR
   7045 	CP	ZX_PLUS		; is character a '+' ?
   7046 	JR	Z,SIGN_DONE	; forward if so
   7047 
   7048 	CP	ZX_MINUS		; is it a '-' ?
   7049 	JR	NZ,ST_E_PART	; forward if not
   7050 
   7051 	INC	(IY+MEM_0_1st-RAMBASE)	; sv MEM_0_1st change to FALSE
   7052 
   7053 mark_1508:
   7054 SIGN_DONE:
   7055 	RST	_NEXT_CHAR
   7056 
   7057 mark_1509:
   7058 ST_E_PART:
   7059 	CALL	INT_TO_FP
   7060 
   7061 	RST	_FP_CALC	;;		m, e.
   7062 	DEFB	__get_mem_0	;;		m, e, (1/0) TRUE/FALSE
   7063 	DEFB	__jump_true	;;
   7064 	DEFB	E_POSTVE - $	;;
   7065 	DEFB	__negate	;;		m, _e
   7066 
   7067 mark_1511:
   7068 E_POSTVE:
   7069 	DEFB	__e_to_fp	;;		x.
   7070 	DEFB	__end_calc	;;		x.
   7071 
   7072 	RET			; return.
   7073 
   7074 
   7075 
   7076 ; THE 'STK_DIGIT' SUBROUTINE
   7077 
   7078 ;
   7079 
   7080 mark_1514:
   7081 STK_DIGIT:
   7082 	CP	ZX_0		;
   7083 	RET	C		;
   7084 
   7085 	CP	ZX_A		; $26
   7086 	CCF			; Complement Carry Flag
   7087 	RET	C		;
   7088 
   7089 	SUB	ZX_0		;
   7090 
   7091 
   7092 ; THE 'STACK_A' SUBROUTINE
   7093 
   7094 ;
   7095 
   7096 
   7097 mark_151D:
   7098 STACK_A:
   7099 	LD	C,A		;
   7100 	LD	B,0		;
   7101 
   7102 
   7103 ; THE 'STACK_BC' SUBROUTINE
   7104 
   7105 ; The ZX81 does not have an integer number format so the BC register contents
   7106 ; must be converted to their full floating-point form.
   7107 
   7108 mark_1520:
   7109 STACK_BC:
   7110 	LD	IY,ERR_NR	; re-initialize the system variables pointer.
   7111 	PUSH	BC		; save the integer value.
   7112 
   7113 ; now stack zero, five zero bytes as a starting point.
   7114 
   7115 	RST	_FP_CALC	;;
   7116 	DEFB	__stk_zero	;;			0.
   7117 	DEFB	__end_calc	;;
   7118 
   7119 	POP	BC		; restore integer value.
   7120 
   7121 	LD	(HL),$91	; place $91 in exponent	65536.
   7122 				; this is the maximum possible value
   7123 
   7124 	LD	A,B		; fetch hi-byte.
   7125 	AND	A		; test for zero.
   7126 	JR	NZ,STK_BC_2	; forward if not zero
   7127 
   7128 	LD	(HL),A		; else make exponent zero again
   7129 	OR	C		; test lo-byte
   7130 	RET	Z		; return if BC was zero - done.
   7131 
   7132 ; else	there has to be a set bit if only the value one.
   7133 
   7134 	LD	B,C		; save C in B.
   7135 	LD	C,(HL)		; fetch zero to C
   7136 	LD	(HL),$89	; make exponent $89		256.
   7137 
   7138 mark_1536:
   7139 STK_BC_2:
   7140 	DEC	(HL)		; decrement exponent - halving number
   7141 	SLA	C		;	C<-76543210<-0
   7142 	RL	B		;	C<-76543210<-C
   7143 	JR	NC,STK_BC_2	; loop back if no carry
   7144 
   7145 	SRL	B		;	0->76543210->C
   7146 	RR	C		;	C->76543210->C
   7147 
   7148 	INC	HL		; address first byte of mantissa
   7149 	LD	(HL),B		; insert B
   7150 	INC	HL		; address second byte of mantissa
   7151 	LD	(HL),C		; insert C
   7152 
   7153 	DEC	HL		; point to the
   7154 	DEC	HL		; exponent again
   7155 	RET			; return.
   7156 
   7157 
   7158 ; THE 'INTEGER TO FLOATING POINT' SUBROUTINE
   7159 
   7160 ;
   7161 ;
   7162 
   7163 mark_1548:
   7164 INT_TO_FP:
   7165 	PUSH	AF		;
   7166 
   7167 	RST	_FP_CALC	;;
   7168 	DEFB	__stk_zero	;;
   7169 	DEFB	__end_calc	;;
   7170 
   7171 	POP	AF		;
   7172 
   7173 mark_154D:
   7174 NXT_DGT_2:
   7175 	CALL	STK_DIGIT
   7176 	RET	C		;
   7177 
   7178 	RST	_FP_CALC	;;
   7179 	DEFB	__exchange	;;
   7180 	DEFB	__stk_ten	;;
   7181 	DEFB	__multiply	;;
   7182 	DEFB	__addition	;;
   7183 	DEFB	__end_calc	;;
   7184 
   7185 	RST	_NEXT_CHAR
   7186 	JR	NXT_DGT_2
   7187 
   7188 
   7189 
   7190 ; THE 'E_FORMAT TO FLOATING POINT' SUBROUTINE
   7191 
   7192 ; (Offset $38: 'e_to_fp')
   7193 ; invoked from DEC_TO_FP and PRINT_FP.
   7194 ; e.g. 2.3E4 is 23000.
   7195 ; This subroutine evaluates xEm where m is a positive or negative integer.
   7196 ; At a simple level x is multiplied by ten for every unit of m.
   7197 ; If the decimal exponent m is negative then x is divided by ten for each unit.
   7198 ; A short-cut is taken if the exponent is greater than seven and in this
   7199 ; case the exponent is reduced by seven and the value is multiplied or divided
   7200 ; by ten million.
   7201 ; Note. for the ZX Spectrum an even cleverer method was adopted which involved
   7202 ; shifting the bits out of the exponent so the result was achieved with six
   7203 ; shifts at most. The routine below had to be completely re-written mostly
   7204 ; in Z80 machine code.
   7205 ; Although no longer operable, the calculator literal was retained for old
   7206 ; times sake, the routine being invoked directly from a machine code CALL.
   7207 ;
   7208 ; On entry in the ZX81, m, the exponent, is the 'last value', and the
   7209 ; floating-point decimal mantissa is beneath it.
   7210 
   7211 
   7212 mark_155A:
   7213 e_to_fp:
   7214 	RST	_FP_CALC	;;		x, m.
   7215 	DEFB	__duplicate	;;		x, m, m.
   7216 	DEFB	__less_0	;;		x, m, (1/0).
   7217 	DEFB	__st_mem_0	;;		x, m, (1/0).
   7218 	DEFB	__delete	;;		x, m.
   7219 	DEFB	__abs		;;		x, +m.
   7220 
   7221 mark_1560:
   7222 E_LOOP:
   7223 	DEFB	__stk_one	;;		x, m,1.
   7224 	DEFB	__subtract	;;		x, m-1.
   7225 	DEFB	__duplicate	;;		x, m-1,m-1.
   7226 	DEFB	__less_0	;;		x, m-1, (1/0).
   7227 	DEFB	__jump_true	;;		x, m-1.
   7228 	DEFB	E_END - $	;;		x, m-1.
   7229 
   7230 	DEFB	__duplicate	;;		x, m-1, m-1.
   7231 	DEFB	__stk_data	;;
   7232 	DEFB	$33		;;Exponent: $83, Bytes: 1
   7233 
   7234 	DEFB	$40		;;(+00,+00,+00)	x, m-1, m-1, 6.
   7235 	DEFB	__subtract	;;		x, m-1, m-7.
   7236 	DEFB	__duplicate	;;		x, m-1, m-7, m-7.
   7237 	DEFB	__less_0	;;		x, m-1, m-7, (1/0).
   7238 	DEFB	__jump_true	;;		x, m-1, m-7.
   7239 	DEFB	E_LOW - $	;;
   7240 
   7241 ; but if exponent m is higher than 7 do a bigger chunk.
   7242 ; multiplying (or dividing if negative) by 10 million - 1e7.
   7243 
   7244 	DEFB	__exchange	;;		x, m-7, m-1.
   7245 	DEFB	__delete	;;		x, m-7.
   7246 	DEFB	__exchange	;;		m-7, x.
   7247 	DEFB	__stk_data	;;
   7248 	DEFB	$80		;;Bytes: 3
   7249 	DEFB	$48		;;Exponent $98
   7250 	DEFB	$18,$96,$80	;;(+00)		m-7, x, 10,000,000 (=f)
   7251 	DEFB	__jump		;;
   7252 	DEFB	E_CHUNK - $	;;
   7253 
   7254 ; ___
   7255 
   7256 mark_157A:
   7257 E_LOW:
   7258 	DEFB	__delete	;;		x, m-1.
   7259 	DEFB	__exchange	;;		m-1, x.
   7260 	DEFB	__stk_ten	;;		m-1, x, 10 (=f).
   7261 
   7262 mark_157D:
   7263 E_CHUNK:
   7264 	DEFB	__get_mem_0	;;		m-1, x, f, (1/0)
   7265 	DEFB	__jump_true	;;		m-1, x, f
   7266 	DEFB	E_DIVSN - $	;;
   7267 
   7268 	DEFB	__multiply	;;		m-1, x*f.
   7269 	DEFB	__jump		;;
   7270 	DEFB	E_SWAP - $	;;
   7271 
   7272 ; ___
   7273 
   7274 mark_1583:
   7275 E_DIVSN:
   7276 	DEFB	__division	;;		m-1, x/f (= new x).
   7277 
   7278 mark_1584:
   7279 E_SWAP:
   7280 	DEFB	__exchange	;;		x, m-1 (= new m).
   7281 	DEFB	__jump		;;		x, m.
   7282 	DEFB	E_LOOP - $	;;
   7283 
   7284 ; ___
   7285 
   7286 mark_1587:
   7287 E_END:
   7288 	DEFB	__delete	;;		x. (-1)
   7289 	DEFB	__end_calc	;;		x.
   7290 
   7291 	RET			; return.
   7292 
   7293 
   7294 ; THE 'FLOATING-POINT TO BC' SUBROUTINE
   7295 
   7296 ; The floating-point form on the calculator stack is compressed directly into
   7297 ; the BC register rounding up if necessary.
   7298 ; Valid range is 0 to 65535.4999
   7299 
   7300 mark_158A:
   7301 FP_TO_BC:
   7302 	CALL	STK_FETCH		; exponent to A
   7303 				; mantissa to EDCB.
   7304 	AND	A		; test for value zero.
   7305 	JR	NZ,FPBC_NZRO	; forward if not
   7306 
   7307 ; else value is zero
   7308 
   7309 	LD	B,A		; zero to B
   7310 	LD	C,A		; also to C
   7311 	PUSH	AF		; save the flags on machine stack
   7312 	JR	FPBC_END		; forward
   7313 
   7314 ; ___
   7315 
   7316 ; EDCB	=>	BCE
   7317 
   7318 mark_1595:
   7319 FPBC_NZRO:
   7320 	LD	B,E		; transfer the mantissa from EDCB
   7321 	LD	E,C		; to BCE. Bit 7 of E is the 17th bit which
   7322 	LD	C,D		; will be significant for rounding if the
   7323 				; number is already normalized.
   7324 
   7325 	SUB	$91		; subtract 65536
   7326 	CCF			; complement carry flag
   7327 	BIT	7,B		; test sign bit
   7328 	PUSH	AF		; push the result
   7329 
   7330 	SET	7,B		; set the implied bit
   7331 	JR	C,FPBC_END	; forward with carry from SUB/CCF
   7332 				; number is too big.
   7333 
   7334 	INC	A		; increment the exponent and
   7335 	NEG			; negate to make range $00 - $0F
   7336 
   7337 	CP	$08		; test if one or two bytes
   7338 	JR	C,BIG_INT	; forward with two
   7339 
   7340 	LD	E,C		; shift mantissa
   7341 	LD	C,B		; 8 places right
   7342 	LD	B,$00		; insert a zero in B
   7343 	SUB	$08		; reduce exponent by eight
   7344 
   7345 mark_15AF:
   7346 BIG_INT:
   7347 	AND	A		; test the exponent
   7348 	LD	D,A		; save exponent in D.
   7349 
   7350 	LD	A,E		; fractional bits to A
   7351 	RLCA			; rotate most significant bit to carry for
   7352 				; rounding of an already normal number.
   7353 
   7354 	JR	Z,EXP_ZERO	; forward if exponent zero
   7355 				; the number is normalized
   7356 
   7357 mark_15B5:
   7358 FPBC_NORM:
   7359 	SRL	B		;	0->76543210->C
   7360 	RR	C		;	C->76543210->C
   7361 
   7362 	DEC	D		; decrement exponent
   7363 
   7364 	JR	NZ,FPBC_NORM	; loop back till zero
   7365 
   7366 mark_15BC:
   7367 EXP_ZERO:
   7368 	JR	NC,FPBC_END	; forward without carry to NO_ROUND	???
   7369 
   7370 	INC	BC		; round up.
   7371 	LD	A,B		; test result
   7372 	OR	C		; for zero
   7373 	JR	NZ,FPBC_END	; forward if not to GRE_ZERO	???
   7374 
   7375 	POP	AF		; restore sign flag
   7376 	SCF			; set carry flag to indicate overflow
   7377 	PUSH	AF		; save combined flags again
   7378 
   7379 mark_15C6:
   7380 FPBC_END:
   7381 	PUSH	BC		; save BC value
   7382 
   7383 ; set HL and DE to calculator stack pointers.
   7384 
   7385 	RST	_FP_CALC	;;
   7386 	DEFB	__end_calc	;;
   7387 
   7388 
   7389 	POP	BC		; restore BC value
   7390 	POP	AF		; restore flags
   7391 	LD	A,C		; copy low byte to A also.
   7392 	RET			; return
   7393 
   7394 
   7395 ; THE 'FLOATING-POINT TO A' SUBROUTINE
   7396 
   7397 ;
   7398 ;
   7399 
   7400 mark_15CD:
   7401 FP_TO_A:
   7402 	CALL	FP_TO_BC
   7403 	RET	C		;
   7404 
   7405 	PUSH	AF		;
   7406 	DEC	B		;
   7407 	INC	B		;
   7408 	JR	Z,FP_A_END	; forward if in range
   7409 
   7410 	POP	AF		; fetch result
   7411 	SCF			; set carry flag signaling overflow
   7412 	RET			; return
   7413 
   7414 mark_15D9:
   7415 FP_A_END:
   7416 	POP	AF		;
   7417 	RET			;
   7418 
   7419 
   7420 
   7421 ; THE 'PRINT A FLOATING-POINT NUMBER' SUBROUTINE
   7422 
   7423 ; prints 'last value' x on calculator stack.
   7424 ; There are a wide variety of formats see Chapter 4.
   7425 ; e.g. 
   7426 ; PI		prints as	3.1415927
   7427 ; .123		prints as	0.123
   7428 ; .0123	prints as	.0123
   7429 ; 999999999999	prints as	1000000000000
   7430 ; 9876543210123 prints as	9876543200000
   7431 
   7432 ; Begin by isolating zero and just printing the '0' character
   7433 ; for that case. For negative numbers print a leading '-' and
   7434 ; then form the absolute value of x.
   7435 
   7436 mark_15DB:
   7437 PRINT_FP:
   7438 	RST	_FP_CALC	;;		x.
   7439 	DEFB	__duplicate	;;		x, x.
   7440 	DEFB	__less_0	;;		x, (1/0).
   7441 	DEFB	__jump_true	;;
   7442 	DEFB	PF_NEGTVE - $	;;	 	x.
   7443 
   7444 	DEFB	__duplicate	;;		x, x
   7445 	DEFB	__greater_0	;;		x, (1/0).
   7446 	DEFB	__jump_true	;;
   7447 	DEFB	PF_POSTVE - $	;;		x.
   7448 
   7449 	DEFB	__delete	;;		.
   7450 	DEFB	__end_calc	;;		.
   7451 
   7452 	LD	A,ZX_0		; load accumulator with character '0'
   7453 
   7454 	RST	_PRINT_A
   7455 	RET			; return.				>>
   7456 
   7457 ; ___
   7458 
   7459 mark_15EA:
   7460 PF_NEGTVE:
   7461 	DEFB	__abs		;;		+x.
   7462 	DEFB	__end_calc	;;		x.
   7463 
   7464 	LD	A,ZX_MINUS	; load accumulator with '-'
   7465 
   7466 	RST	_PRINT_A
   7467 
   7468 	RST	_FP_CALC	;;		x.
   7469 
   7470 mark_15F0:
   7471 PF_POSTVE:
   7472 	DEFB	__end_calc	;;		x.
   7473 
   7474 ; register HL addresses the exponent of the floating-point value.
   7475 ; if positive, and point floats to left, then bit 7 is set.
   7476 
   7477 	LD	A,(HL)		; pick up the exponent byte
   7478 	CALL	STACK_A		; places on calculator stack.
   7479 
   7480 ; now calculate roughly the number of digits, n, before the decimal point by
   7481 ; subtracting a half from true exponent and multiplying by log to 
   7482 ; the base 10 of 2. 
   7483 ; The true number could be one higher than n, the integer result.
   7484 
   7485 	RST	_FP_CALC	;;			x, e.
   7486 	DEFB	__stk_data	;;
   7487 	DEFB	$78		;;Exponent: $88, Bytes: 2
   7488 	DEFB	$00,$80		;;(+00,+00)		x, e, 128.5.
   7489 	DEFB	__subtract	;;			x, e -.5.
   7490 	DEFB	__stk_data	;;
   7491 	DEFB	$EF		;;Exponent: $7F, Bytes: 4
   7492 	DEFB	$1A,$20,$9A,$85 ;;			.30103 (log10 2)
   7493 	DEFB	__multiply	;;			x,
   7494 	DEFB	__int		;;
   7495 	DEFB	__st_mem_1	;;			x, n.
   7496 
   7497 
   7498 	DEFB	__stk_data	;;
   7499 	DEFB	$34		;;Exponent: $84, Bytes: 1
   7500 	DEFB	$00		;;(+00,+00,+00)		x, n, 8.
   7501 
   7502 	DEFB	__subtract	;;			x, n-8.
   7503 	DEFB	__negate	;;			x, 8-n.
   7504 	DEFB	__e_to_fp	;;			x * (10^n)
   7505 
   7506 ; finally the 8 or 9 digit decimal is rounded.
   7507 ; a ten-digit integer can arise in the case of, say, 999999999.5
   7508 ; which gives 1000000000.
   7509 
   7510 	DEFB	__stk_half	;;
   7511 	DEFB	__addition	;;
   7512 	DEFB	__int		;;			i.
   7513 	DEFB	__end_calc	;;
   7514 
   7515 ; If there were 8 digits then final rounding will take place on the calculator 
   7516 ; stack above and the next two instructions insert a masked zero so that
   7517 ; no further rounding occurs. If the result is a 9 digit integer then
   7518 ; rounding takes place within the buffer.
   7519 
   7520 	LD	HL,$406B	; address system variable MEM_2_5th
   7521 				; which could be the 'ninth' digit.
   7522 	LD	(HL),$90	; insert the value $90	10010000
   7523 
   7524 ; now starting from lowest digit lay down the 8, 9 or 10 digit integer
   7525 ; which represents the significant portion of the number
   7526 ; e.g. PI will be the nine-digit integer 314159265
   7527 
   7528 	LD	B,10		; count is ten digits.
   7529 
   7530 mark_1615:
   7531 PF_LOOP:
   7532 	INC	HL		; increase pointer
   7533 
   7534 	PUSH	HL		; preserve buffer address.
   7535 	PUSH	BC		; preserve counter.
   7536 
   7537 	RST	_FP_CALC	;;		i.
   7538 	DEFB	__stk_ten	;;		i, 10.
   7539 	DEFB	__n_mod_m	;;		i mod 10, i/10
   7540 	DEFB	__exchange	;;		i/10, remainder.
   7541 	DEFB	__end_calc	;;
   7542 
   7543 	CALL	FP_TO_A		; $00-$09
   7544 
   7545 	OR	$90		; make left hand nibble 9 
   7546 
   7547 	POP	BC		; restore counter
   7548 	POP	HL		; restore buffer address.
   7549 
   7550 	LD	(HL),A		; insert masked digit in buffer.
   7551 	DJNZ	PF_LOOP		; loop back for all ten 
   7552 
   7553 ; the most significant digit will be last but if the number is exhausted then
   7554 ; the last one or two positions will contain zero ($90).
   7555 
   7556 ; e.g. for 'one' we have zero as estimate of leading digits.
   7557 ; 1*10^8 100000000 as integer value
   7558 ; 90 90 90 90 90	90 90 90 91 90 as buffer mem3/mem4 contents.
   7559 
   7560 
   7561 	INC	HL		; advance pointer to one past buffer 
   7562 	LD	BC,$0008	; set C to 8 ( B is already zero )
   7563 	PUSH	HL		; save pointer.
   7564 
   7565 mark_162C:
   7566 PF_NULL:
   7567 	DEC	HL		; decrease pointer
   7568 	LD	A,(HL)		; fetch masked digit
   7569 	CP	$90		; is it a leading zero ?
   7570 	JR	Z,PF_NULL	; loop back if so
   7571 
   7572 ; at this point a significant digit has been found. carry is reset.
   7573 
   7574 	SBC	HL,BC		; subtract eight from the address.
   7575 	PUSH	HL		; ** save this pointer too
   7576 	LD	A,(HL)		; fetch addressed byte
   7577 	ADD	A,$6B		; add $6B - forcing a round up ripple
   7578 				; if	$95 or over.
   7579 	PUSH	AF		; save the carry result.
   7580 
   7581 ; now enter a loop to round the number. After rounding has been considered
   7582 ; a zero that has arisen from rounding or that was present at that position
   7583 ; originally is changed from $90 to $80.
   7584 
   7585 mark_1639:
   7586 PF_RND_LP:
   7587 	POP	AF		; retrieve carry from machine stack.
   7588 	INC	HL		; increment address
   7589 	LD	A,(HL)		; fetch new byte
   7590 	ADC	A,0		; add in any carry
   7591 
   7592 	DAA			; decimal adjust accumulator
   7593 				; carry will ripple through the '9'
   7594 
   7595 	PUSH	AF		; save carry on machine stack.
   7596 	AND	$0F		; isolate character 0 - 9 AND set zero flag
   7597 				; if zero.
   7598 	LD	(HL),A		; place back in location.
   7599 	SET	7,(HL)		; set bit 7 to show printable.
   7600 				; but not if trailing zero after decimal point.
   7601 	JR	Z,PF_RND_LP	; back if a zero
   7602 				; to consider further rounding and/or trailing
   7603 				; zero identification.
   7604 
   7605 	POP	AF		; balance stack
   7606 	POP	HL		; ** retrieve lower pointer
   7607 
   7608 ; now insert 6 trailing zeros which are printed if before the decimal point
   7609 ; but mark the end of printing if after decimal point.
   7610 ; e.g. 9876543210123 is printed as 9876543200000
   7611 ; 123.456001 is printed as 123.456
   7612 
   7613 	LD	B,6		; the count is six.
   7614 
   7615 mark_164B:
   7616 PF_ZERO_6:
   7617 	LD	(HL),$80	; insert a masked zero
   7618 	DEC	HL		; decrease pointer.
   7619 	DJNZ	PF_ZERO_6	; loop back for all six
   7620 
   7621 ; n-mod-m reduced the number to zero and this is now deleted from the calculator
   7622 ; stack before fetching the original estimate of leading digits.
   7623 
   7624 
   7625 	RST	_FP_CALC	;;		0.
   7626 	DEFB	__delete	;;		.
   7627 	DEFB	__get_mem_1	;;		n.
   7628 	DEFB	__end_calc	;;		n.
   7629 
   7630 	CALL	FP_TO_A
   7631 	JR	Z,PF_POS	; skip forward if positive
   7632 
   7633 	NEG			; negate makes positive
   7634 
   7635 mark_165B:
   7636 PF_POS:
   7637 	LD	E,A		; transfer count of digits to E
   7638 	INC	E		; increment twice 
   7639 	INC	E		; 
   7640 	POP	HL		; * retrieve pointer to one past buffer.
   7641 
   7642 mark_165F:
   7643 GET_FIRST:
   7644 	DEC	HL		; decrement address.
   7645 	DEC	E		; decrement digit counter.
   7646 	LD	A,(HL)		; fetch masked byte.
   7647 	AND	$0F		; isolate right-hand nibble.
   7648 	JR	Z,GET_FIRST	; back with leading zero
   7649 
   7650 ; now determine if E-format printing is needed
   7651 
   7652 	LD	A,E		; transfer now accurate number count to A.
   7653 	SUB	5		; subtract five
   7654 	CP	8		; compare with 8 as maximum digits is 13.
   7655 	JP	P,PF_E_FMT	; forward if positive to PF_E_FMT
   7656 
   7657 	CP	$F6		; test for more than four zeros after point.
   7658 	JP	M,PF_E_FMT	; forward if so to PF_E_FMT
   7659 
   7660 	ADD	A,6		; test for zero leading digits, e.g. 0.5
   7661 	JR	Z,PF_ZERO_1	; forward if so to PF_ZERO_1 
   7662 
   7663 	JP	M,PF_ZEROS	; forward if more than one zero to PF_ZEROS
   7664 
   7665 ; else digits before the decimal point are to be printed
   7666 
   7667 	LD	B,A		; count of leading characters to B.
   7668 
   7669 mark_167B:
   7670 PF_NIB_LP:
   7671 	CALL	PF_NIBBLE
   7672 	DJNZ	PF_NIB_LP		; loop back for counted numbers
   7673 
   7674 	JR	PF_DC_OUT		; forward to consider decimal part to PF_DC_OUT
   7675 
   7676 ; ___
   7677 
   7678 mark_1682:
   7679 PF_E_FMT:
   7680 	LD	B,E		; count to B
   7681 	CALL	PF_NIBBLE		; prints one digit.
   7682 	CALL	PF_DC_OUT		; considers fractional part.
   7683 
   7684 	LD	A,ZX_E		; 
   7685 	RST	_PRINT_A
   7686 
   7687 	LD	A,B		; transfer exponent to A
   7688 	AND	A		; test the sign.
   7689 	JP	P,PF_E_POS	; forward if positive to PF_E_POS
   7690 
   7691 	NEG			; negate the negative exponent.
   7692 	LD	B,A		; save positive exponent in B.
   7693 
   7694 	LD	A,ZX_MINUS	; 
   7695 	JR	PF_E_SIGN		; skip forward to PF_E_SIGN
   7696 
   7697 ; ___
   7698 
   7699 mark_1698:
   7700 PF_E_POS:
   7701 	LD	A,ZX_PLUS	; 
   7702 
   7703 mark_169A:
   7704 PF_E_SIGN:
   7705 	RST	_PRINT_A
   7706 
   7707 ; now convert the integer exponent in B to two characters.
   7708 ; it will be less than 99.
   7709 
   7710 	LD	A,B		; fetch positive exponent.
   7711 	LD	B,$FF		; initialize left hand digit to minus one.
   7712 
   7713 mark_169E:
   7714 PF_E_TENS:
   7715 	INC	B		; increment ten count
   7716 	SUB	10		; subtract ten from exponent
   7717 	JR	NC,PF_E_TENS	; loop back if greater than ten
   7718 
   7719 	ADD	A,10		; reverse last subtraction
   7720 	LD	C,A		; transfer remainder to C
   7721 
   7722 	LD	A,B		; transfer ten value to A.
   7723 	AND	A		; test for zero.
   7724 	JR	Z,PF_E_LOW	; skip forward if so to PF_E_LOW
   7725 
   7726 	CALL	OUT_CODE		; prints as digit '1' - '9'
   7727 
   7728 mark_16AD:
   7729 PF_E_LOW:
   7730 	LD	A,C		; low byte to A
   7731 	CALL	OUT_CODE		; prints final digit of the
   7732 				; exponent.
   7733 	RET			; return.				>>
   7734 
   7735 
   7736 ; THE 'FLOATING POINT PRINT ZEROS' LOOP
   7737 ; -------------------------------------
   7738 ; This branch deals with zeros after decimal point.
   7739 ; e.g.      .01 or .0000999
   7740 ; Note. that printing to the ZX Printer destroys A and that A should be 
   7741 ; initialized to '0' at each stage of the loop.
   7742 ; Originally LPRINT .00001 printed as .0XYZ1
   7743 
   7744 mark_16B2:
   7745 PF_ZEROS:
   7746 	NEG			; negate makes number positive 1 to 4.
   7747 	LD	B,A		; zero count to B.
   7748 
   7749 	LD	A,ZX_PERIOD	; prepare character '.'
   7750 	RST	_PRINT_A
   7751 
   7752 
   7753 if ORIGINAL
   7754 	LD	A,ZX_0		; prepare a '0'
   7755 PFZROLP:
   7756 	RST	_PRINT_A
   7757 	DJNZ	PFZROLP		; obsolete loop back to PFZROLP
   7758 else
   7759 PF_ZRO_LP:
   7760 	LD	A,ZX_0		; prepare a '0' in the accumulator each time.
   7761 	RST	_PRINT_A
   7762 	DJNZ	PF_ZRO_LP	;+ New loop back to PF-ZRO-LP
   7763 endif
   7764 
   7765 	JR	PF_FRAC_LP		; forward
   7766 
   7767 ; there is	a need to print a leading zero e.g. 0.1 but not with .01
   7768 
   7769 mark_16BF:
   7770 PF_ZERO_1:
   7771 	LD	A,ZX_0		; prepare character '0'.
   7772 	RST	_PRINT_A
   7773 
   7774 ; this subroutine considers the decimal point and any trailing digits.
   7775 ; if the next character is a marked zero, $80, then nothing more to print.
   7776 
   7777 mark_16C2:
   7778 PF_DC_OUT:
   7779 	DEC	(HL)		; decrement addressed character
   7780 	INC	(HL)		; increment it again
   7781 	RET	PE		; return with overflow	(was 128) >>
   7782 				; as no fractional part
   7783 
   7784 ; else there is a fractional part so print the decimal point.
   7785 
   7786 	LD	A,ZX_PERIOD		; prepare character '.'
   7787 	RST	_PRINT_A
   7788 
   7789 ; now enter a loop to print trailing digits
   7790 
   7791 mark_16C8:
   7792 PF_FRAC_LP:
   7793 	DEC	(HL)		; test for a marked zero.
   7794 	INC	(HL)		;
   7795 	RET	PE		; return when digits exhausted		>>
   7796 
   7797 	CALL	PF_NIBBLE
   7798 	JR	PF_FRAC_LP		; back for all fractional digits
   7799 
   7800 ; ___
   7801 
   7802 ; subroutine to print right-hand nibble
   7803 
   7804 mark_16D0:
   7805 PF_NIBBLE:
   7806 	LD	A,(HL)		; fetch addressed byte
   7807 	AND	$0F		; mask off lower 4 bits
   7808 	CALL	OUT_CODE
   7809 	DEC	HL		; decrement pointer.
   7810 	RET			; return.
   7811 
   7812 
   7813 
   7814 ; THE 'PREPARE TO ADD' SUBROUTINE
   7815 
   7816 ; This routine is called twice to prepare each floating point number for
   7817 ; addition, in situ, on the calculator stack.
   7818 ; The exponent is picked up from the first byte which is then cleared to act
   7819 ; as a sign byte and accept any overflow.
   7820 ; If the exponent is zero then the number is zero and an early return is made.
   7821 ; The now redundant sign bit of the mantissa is set and if the number is 
   7822 ; negative then all five bytes of the number are twos-complemented to prepare 
   7823 ; the number for addition.
   7824 ; On the second invocation the exponent of the first number is in B.
   7825 
   7826 
   7827 mark_16D8:
   7828 PREP_ADD:
   7829 	LD	A,(HL)		; fetch exponent.
   7830 	LD	(HL),0		; make this byte zero to take any overflow and
   7831 				; default to positive.
   7832 	AND	A		; test stored exponent for zero.
   7833 	RET	Z		; return with zero flag set if number is zero.
   7834 
   7835 	INC	HL		; point to first byte of mantissa.
   7836 	BIT	7,(HL)		; test the sign bit.
   7837 	SET	7,(HL)		; set it to its implied state.
   7838 	DEC	HL		; set pointer to first byte again.
   7839 	RET	Z		; return if bit indicated number is positive.>>
   7840 
   7841 ; if negative then all five bytes are twos complemented starting at LSB.
   7842 
   7843 	PUSH	BC		; save B register contents.
   7844 	LD	BC,$0005	; set BC to five.
   7845 	ADD	HL,BC		; point to location after 5th byte.
   7846 	LD	B,C		; set the B counter to five.
   7847 	LD	C,A		; store original exponent in C.
   7848 	SCF			; set carry flag so that one is added.
   7849 
   7850 ; now enter a loop to twos_complement the number.
   7851 ; The first of the five bytes becomes $FF to denote a negative number.
   7852 
   7853 mark_16EC:
   7854 NEG_BYTE:
   7855 	DEC	HL		; point to first or more significant byte.
   7856 	LD	A,(HL)		; fetch to accumulator.
   7857 	CPL			; complement.
   7858 	ADC	A,0		; add in initial carry or any subsequent carry.
   7859 	LD	(HL),A		; place number back.
   7860 	DJNZ	NEG_BYTE		; loop back five times
   7861 
   7862 	LD	A,C		; restore the exponent to accumulator.
   7863 	POP	BC		; restore B register contents.
   7864 
   7865 	RET			; return.
   7866 
   7867 
   7868 ; THE 'FETCH TWO NUMBERS' SUBROUTINE
   7869 
   7870 ; This routine is used by addition, multiplication and division to fetch
   7871 ; the two five_byte numbers addressed by HL and DE from the calculator stack
   7872 ; into the Z80 registers.
   7873 ; The HL register may no longer point to the first of the two numbers.
   7874 ; Since the 32-bit addition operation is accomplished using two Z80 16-bit
   7875 ; instructions, it is important that the lower two bytes of each mantissa are
   7876 ; in one set of registers and the other bytes all in the alternate set.
   7877 ;
   7878 ; In: HL = highest number, DE= lowest number
   7879 ;
   7880 ;	: alt':
   7881 ;	:
   7882 ; Out:
   7883 ;	:H,B-C:C,B: num1
   7884 ;	:L,D-E:D-E: num2
   7885 
   7886 mark_16F7:
   7887 FETCH_TWO:
   7888 	PUSH	HL		; save HL 
   7889 	PUSH	AF		; save A - result sign when used from division.
   7890 
   7891 	LD	C,(HL)		;
   7892 	INC	HL		;
   7893 	LD	B,(HL)		;
   7894 	LD	(HL),A		; insert sign when used from multiplication.
   7895 	INC	HL		;
   7896 	LD	A,C		; m1
   7897 	LD	C,(HL)		;
   7898 	PUSH	BC		; PUSH m2 m3
   7899 
   7900 	INC	HL		;
   7901 	LD	C,(HL)		; m4
   7902 	INC	HL		;
   7903 	LD	B,(HL)		; m5	BC holds m5 m4
   7904 
   7905 	EX	DE,HL		; make HL point to start of second number.
   7906 
   7907 	LD	D,A		; m1
   7908 	LD	E,(HL)		;
   7909 	PUSH	DE		; PUSH m1 n1
   7910 
   7911 	INC	HL		;
   7912 	LD	D,(HL)		;
   7913 	INC	HL		;
   7914 	LD	E,(HL)		;
   7915 	PUSH	DE		; PUSH n2 n3
   7916 
   7917 	EXX			; - - - - - - -
   7918 
   7919 	POP	DE		; POP n2 n3
   7920 	POP	HL		; POP m1 n1
   7921 	POP	BC		; POP m2 m3
   7922 
   7923 	EXX			; - - - - - - -
   7924 
   7925 	INC	HL		;
   7926 	LD	D,(HL)		;
   7927 	INC	HL		;
   7928 	LD	E,(HL)		; DE holds n4 n5
   7929 
   7930 	POP	AF		; restore saved
   7931 	POP	HL		; registers.
   7932 	RET			; return.
   7933 
   7934 
   7935 ; THE 'SHIFT ADDEND' SUBROUTINE
   7936 
   7937 ; The accumulator A contains the difference between the two exponents.
   7938 ; This is the lowest of the two numbers to be added 
   7939 
   7940 mark_171A:
   7941 SHIFT_FP:
   7942 	AND	A		; test difference between exponents.
   7943 	RET	Z		; return if zero. both normal.
   7944 
   7945 	CP	33		; compare with 33 bits.
   7946 	JR	NC,ADDEND_0	; forward if greater than 32
   7947 
   7948 	PUSH	BC		; preserve BC - part 
   7949 	LD	B,A		; shift counter to B.
   7950 
   7951 ; Now perform B right shifts on the addend	L'D'E'D E
   7952 ; to bring it into line with the augend	H'B'C'C B
   7953 
   7954 mark_1722:
   7955 ONE_SHIFT:
   7956 	EXX			; - - -
   7957 	SRA	L		;	76543210->C	bit 7 unchanged.
   7958 	RR	D		; C->76543210->C
   7959 	RR	E		; C->76543210->C
   7960 	EXX			; - - - 
   7961 	RR	D		; C->76543210->C
   7962 	RR	E		; C->76543210->C
   7963 	DJNZ	ONE_SHIFT		; loop back B times
   7964 
   7965 	POP	BC		; restore BC
   7966 	RET	NC		; return if last shift produced no carry.	>>
   7967 
   7968 ; if carry flag was set then accuracy is being lost so round up the addend.
   7969 
   7970 	CALL	ADD_BACK
   7971 	RET	NZ		; return if not FF 00 00 00 00
   7972 
   7973 ; this branch makes all five bytes of the addend zero and is made during
   7974 ; addition when the exponents are too far apart for the addend bits to 
   7975 ; affect the result.
   7976 
   7977 mark_1736:
   7978 ADDEND_0:
   7979 	EXX			; select alternate set for more significant 
   7980 				; bytes.
   7981 	XOR	A		; clear accumulator.
   7982 
   7983 
   7984 ; this entry point (from multiplication) sets four of the bytes to zero or if 
   7985 ; continuing from above, during addition, then all five bytes are set to zero.
   7986 
   7987 mark_1738:
   7988 ZEROS_4_OR_5:
   7989 	LD	L,0		; set byte 1 to zero.
   7990 	LD	D,A		; set byte 2 to A.
   7991 	LD	E,L		; set byte 3 to zero.
   7992 	EXX			; select main set 
   7993 	LD	DE,$0000	; set lower bytes 4 and 5 to zero.
   7994 	RET			; return.
   7995 
   7996 
   7997 ; THE 'ADD_BACK' SUBROUTINE
   7998 
   7999 ; Called from SHIFT_FP above during addition and after normalization from
   8000 ; multiplication.
   8001 ; This is really a 32_bit increment routine which sets the zero flag according
   8002 ; to the 32-bit result.
   8003 ; During addition, only negative numbers like FF FF FF FF FF,
   8004 ; the twos-complement version of xx 80 00 00 01 say 
   8005 ; will result in a full ripple FF 00 00 00 00.
   8006 ; FF FF FF FF FF when shifted right is unchanged by SHIFT_FP but sets the 
   8007 ; carry invoking this routine.
   8008 
   8009 mark_1741:
   8010 ADD_BACK:
   8011 	INC	E		;
   8012 	RET	NZ		;
   8013 
   8014 	INC	D		;
   8015 	RET	NZ		;
   8016 
   8017 	EXX			;
   8018 	INC	E		;
   8019 	JR	NZ,ALL_ADDED	; forward if no overflow
   8020 
   8021 	INC	D		;
   8022 
   8023 mark_174A:
   8024 ALL_ADDED:
   8025 	EXX			;
   8026 	RET			; return with zero flag set for zero mantissa.
   8027 
   8028 
   8029 
   8030 ; THE 'SUBTRACTION' OPERATION
   8031 
   8032 ; just switch the sign of subtrahend and do an add.
   8033 
   8034 mark_174C:
   8035 SUBTRACT:
   8036 	LD	A,(DE)		; fetch exponent byte of second number the
   8037 				; subtrahend. 
   8038 	AND	A		; test for zero
   8039 	RET	Z		; return if zero - first number is result.
   8040 
   8041 	INC	DE		; address the first mantissa byte.
   8042 	LD	A,(DE)		; fetch to accumulator.
   8043 	XOR	$80		; toggle the sign bit.
   8044 	LD	(DE),A		; place back on calculator stack.
   8045 	DEC	DE		; point to exponent byte.
   8046 				; continue into addition routine.
   8047 
   8048 
   8049 ; THE 'ADDITION' OPERATION
   8050 
   8051 ; The addition operation pulls out all the stops and uses most of the Z80's
   8052 ; registers to add two floating-point numbers.
   8053 ; This is a binary operation and on entry, HL points to the first number
   8054 ; and DE to the second.
   8055 
   8056 mark_1755:
   8057 ADDITION:
   8058 	EXX			; - - -
   8059 	PUSH	HL		; save the pointer to the next literal.
   8060 	EXX			; - - -
   8061 
   8062 	PUSH	DE		; save pointer to second number
   8063 	PUSH	HL		; save pointer to first number - will be the
   8064 				; result pointer on calculator stack.
   8065 
   8066 	CALL	PREP_ADD
   8067 	LD	B,A		; save first exponent byte in B.
   8068 	EX	DE,HL		; switch number pointers.
   8069 	CALL	PREP_ADD
   8070 	LD	C,A		; save second exponent byte in C.
   8071 	CP	B		; compare the exponent bytes.
   8072 	JR	NC,SHIFT_LEN	; forward if second higher
   8073 
   8074 	LD	A,B		; else higher exponent to A
   8075 	LD	B,C		; lower exponent to B
   8076 	EX	DE,HL		; switch the number pointers.
   8077 
   8078 mark_1769:
   8079 SHIFT_LEN:
   8080 	PUSH	AF		; save higher exponent
   8081 	SUB	B		; subtract lower exponent
   8082 
   8083 	CALL	FETCH_TWO
   8084 	CALL	SHIFT_FP
   8085 
   8086 	POP	AF		; restore higher exponent.
   8087 	POP	HL		; restore result pointer.
   8088 	LD	(HL),A		; insert exponent byte.
   8089 	PUSH	HL		; save result pointer again.
   8090 
   8091 ; now perform the 32-bit addition using two 16-bit Z80 add instructions.
   8092 
   8093 	LD	L,B		; transfer low bytes of mantissa individually
   8094 	LD	H,C		; to HL register
   8095 
   8096 	ADD	HL,DE		; the actual binary addition of lower bytes
   8097 
   8098 ; now the two higher byte pairs that are in the alternate register sets.
   8099 
   8100 	EXX			; switch in set 
   8101 	EX	DE,HL		; transfer high mantissa bytes to HL register.
   8102 
   8103 	ADC	HL,BC		; the actual addition of higher bytes with
   8104 				; any carry from first stage.
   8105 
   8106 	EX	DE,HL		; result in DE, sign bytes ($FF or $00) to HL
   8107 
   8108 ; now consider the two sign bytes
   8109 
   8110 	LD	A,H		; fetch sign byte of num1
   8111 
   8112 	ADC	A,L		; add including any carry from mantissa 
   8113 				; addition. 00 or 01 or FE or FF
   8114 
   8115 	LD	L,A		; result in L.
   8116 
   8117 ; possible outcomes of signs and overflow from mantissa are
   8118 ;
   8119 ;	H +	L + carry =	L	RRA	XOR L	RRA
   8120 
   8121 ; 00 + 00		= 00	00	00
   8122 ; 00 + 00 + carry	= 01	00	01	carry
   8123 ; FF + FF		= FE C	FF	01	carry
   8124 ; FF + FF + carry	= FF C	FF	00
   8125 ; FF + 00		= FF	FF	00
   8126 ; FF + 00 + carry	= 00 C	80	80
   8127 
   8128 	RRA			; C->76543210->C
   8129 	XOR	L		; set bit 0 if shifting required.
   8130 
   8131 	EXX			; switch back to main set
   8132 	EX	DE,HL		; full mantissa result now in D'E'D E registers.
   8133 	POP	HL		; restore pointer to result exponent on 
   8134 				; the calculator stack.
   8135 
   8136 	RRA			; has overflow occurred ?
   8137 	JR	NC,TEST_NEG	; skip forward if not
   8138 
   8139 ; if the addition of two positive mantissas produced overflow or if the
   8140 ; addition of two negative mantissas did not then the result exponent has to
   8141 ; be incremented and the mantissa shifted one place to the right.
   8142 
   8143 	LD	A,1		; one shift required.
   8144 	CALL	SHIFT_FP		; performs a single shift 
   8145 				; rounding any lost bit
   8146 	INC	(HL)		; increment the exponent.
   8147 	JR	Z,ADD_REP_6	; forward to ADD_REP_6 if the exponent
   8148 				; wraps round from FF to zero as number is too
   8149 				; big for the system.
   8150 
   8151 ; at this stage the exponent on the calculator stack is correct.
   8152 
   8153 mark_1790:
   8154 TEST_NEG:
   8155 	EXX			; switch in the alternate set.
   8156 	LD	A,L		; load result sign to accumulator.
   8157 	AND	$80		; isolate bit 7 from sign byte setting zero
   8158 				; flag if positive.
   8159 	EXX			; back to main set.
   8160 
   8161 	INC	HL		; point to first byte of mantissa
   8162 	LD	(HL),A		; insert $00 positive or $80 negative at 
   8163 				; position on calculator stack.
   8164 
   8165 	DEC	HL		; point to exponent again.
   8166 	JR	Z,GO_NC_MLT	; forward if positive to GO_NC_MLT
   8167 
   8168 ; a negative number has to be twos-complemented before being placed on stack.
   8169 
   8170 	LD	A,E		; fetch lowest (rightmost) mantissa byte.
   8171 	NEG			; Negate
   8172 	CCF			; Complement Carry Flag
   8173 	LD	E,A		; place back in register
   8174 
   8175 	LD	A,D		; ditto
   8176 	CPL			;
   8177 	ADC	A,0		;
   8178 	LD	D,A		;
   8179 
   8180 	EXX			; switch to higher (leftmost) 16 bits.
   8181 
   8182 	LD	A,E		; ditto
   8183 	CPL			;
   8184 	ADC	A,0		;
   8185 	LD	E,A		;
   8186 
   8187 	LD	A,D		; ditto
   8188 	CPL			;
   8189 	ADC	A,0		;
   8190 	JR	NC,END_COMPL	; forward without overflow to END_COMPL
   8191 
   8192 ; else entire mantissa is now zero.	00 00 00 00
   8193 
   8194 	RRA			; set mantissa to 80 00 00 00
   8195 	EXX			; switch.
   8196 	INC	(HL)		; increment the exponent.
   8197 
   8198 mark_17B3:
   8199 ADD_REP_6:
   8200 	JP	Z,REPORT_6	; jump forward if exponent now zero to REPORT_6
   8201 				; 'Number too big'
   8202 
   8203 	EXX			; switch back to alternate set.
   8204 
   8205 mark_17B7:
   8206 END_COMPL:
   8207 	LD	D,A		; put first byte of mantissa back in DE.
   8208 	EXX			; switch to main set.
   8209 
   8210 mark_17B9:
   8211 GO_NC_MLT:
   8212 	XOR	A		; clear carry flag and
   8213 				; clear accumulator so no extra bits carried
   8214 				; forward as occurs in multiplication.
   8215 
   8216 	JR	TEST_NORM		; forward to common code at TEST_NORM 
   8217 				; but should go straight to NORMALIZE.
   8218 
   8219 
   8220 
   8221 ; THE 'PREPARE TO MULTIPLY OR DIVIDE' SUBROUTINE
   8222 
   8223 ; this routine is called twice from multiplication and twice from division
   8224 ; to prepare each of the two numbers for the operation.
   8225 ; Initially the accumulator holds zero and after the second invocation bit 7
   8226 ; of the accumulator will be the sign bit of the result.
   8227 
   8228 mark_17BC:
   8229 PREP_MULTIPLY_OR_DIVIDE:
   8230 	SCF			; set carry flag to signal number is zero.
   8231 	DEC	(HL)		; test exponent
   8232 	INC	(HL)		; for zero.
   8233 	RET	Z		; return if zero with carry flag set.
   8234 
   8235 	INC	HL		; address first mantissa byte.
   8236 	XOR	(HL)		; exclusive or the running sign bit.
   8237 	SET	7,(HL)		; set the implied bit.
   8238 	DEC	HL		; point to exponent byte.
   8239 	RET			; return.
   8240 
   8241 
   8242 ; THE 'MULTIPLICATION' OPERATION
   8243 
   8244 ;
   8245 ;
   8246 
   8247 mark_17C6:
   8248 MULTIPLY:
   8249 	XOR	A		; reset bit 7 of running sign flag.
   8250 	CALL	PREP_MULTIPLY_OR_DIVIDE
   8251 	RET	C		; return if number is zero.
   8252 				; zero * anything = zero.
   8253 
   8254 	EXX			; - - -
   8255 	PUSH	HL		; save pointer to 'next literal'
   8256 	EXX			; - - -
   8257 
   8258 	PUSH	DE		; save pointer to second number 
   8259 
   8260 	EX	DE,HL		; make HL address second number.
   8261 
   8262 	CALL	PREP_MULTIPLY_OR_DIVIDE
   8263 
   8264 	EX	DE,HL		; HL first number, DE - second number
   8265 	JR	C,ZERO_RESULT	; forward with carry to ZERO_RESULT
   8266 				; anything * zero = zero.
   8267 
   8268 	PUSH	HL		; save pointer to first number.
   8269 
   8270 	CALL	FETCH_TWO		; fetches two mantissas from
   8271 				; calc stack to B'C'C,B	D'E'D E
   8272 				; (HL will be overwritten but the result sign
   8273 				; in A is inserted on the calculator stack)
   8274 
   8275 	LD	A,B		; transfer low mantissa byte of first number
   8276 	AND	A		; clear carry.
   8277 	SBC	HL,HL		; a short form of LD HL,$0000 to take lower
   8278 				; two bytes of result. (2 program bytes)
   8279 	EXX			; switch in alternate set
   8280 	PUSH	HL		; preserve HL
   8281 	SBC	HL,HL		; set HL to zero also to take higher two bytes
   8282 				; of the result and clear carry.
   8283 	EXX			; switch back.
   8284 
   8285 	LD	B,33		; register B can now be used to count 33 shifts.
   8286 	JR	STRT_MLT		; forward to loop entry point STRT_MLT
   8287 
   8288 ; ___
   8289 
   8290 ; The multiplication loop is entered at	STRT_LOOP.
   8291 
   8292 mark_17E7:
   8293 MLT_LOOP:
   8294 	JR	NC,NO_ADD	; forward if no carry
   8295 
   8296 				; else add in the multiplicand.
   8297 
   8298 	ADD	HL,DE		; add the two low bytes to result
   8299 	EXX			; switch to more significant bytes.
   8300 	ADC	HL,DE		; add high bytes of multiplicand and any carry.
   8301 	EXX			; switch to main set.
   8302 
   8303 ; in either case shift result right into B'C'C A
   8304 
   8305 mark_17EE:
   8306 NO_ADD:
   8307 	EXX			; switch to alternate set
   8308 	RR	H		; C > 76543210 > C
   8309 	RR	L		; C > 76543210 > C
   8310 	EXX			;
   8311 	RR	H		; C > 76543210 > C
   8312 	RR	L		; C > 76543210 > C
   8313 
   8314 mark_17F8:
   8315 STRT_MLT:
   8316 	EXX			; switch in alternate set.
   8317 	RR	B		; C > 76543210 > C
   8318 	RR	C		; C > 76543210 > C
   8319 	EXX			; now main set
   8320 	RR	C		; C > 76543210 > C
   8321 	RRA			; C > 76543210 > C
   8322 	DJNZ	MLT_LOOP		; loop back 33 timeS
   8323 
   8324 ;
   8325 
   8326 	EX	DE,HL		;
   8327 	EXX			;
   8328 	EX	DE,HL		;
   8329 	EXX			;
   8330 	POP	BC		;
   8331 	POP	HL		;
   8332 	LD	A,B		;
   8333 	ADD	A,C		;
   8334 	JR	NZ,MAKE_EXPT	; forward
   8335 
   8336 	AND	A		;
   8337 
   8338 mark_180E:
   8339 MAKE_EXPT:
   8340 	DEC	A		;
   8341 	CCF			; Complement Carry Flag
   8342 
   8343 mark_1810:
   8344 DIVN_EXPT:
   8345 	RLA			;
   8346 	CCF			; Complement Carry Flag
   8347 	RRA			;
   8348 	JP	P,OFLW1_CLR
   8349 
   8350 	JR	NC,REPORT_6
   8351 
   8352 	AND	A		;
   8353 
   8354 mark_1819:
   8355 OFLW1_CLR:
   8356 	INC	A		;
   8357 	JR	NZ,OFLW2_CLR
   8358 
   8359 	JR	C,OFLW2_CLR
   8360 
   8361 	EXX			;
   8362 	BIT	7,D		;
   8363 	EXX			;
   8364 	JR	NZ,REPORT_6
   8365 
   8366 mark_1824:
   8367 OFLW2_CLR:
   8368 	LD	(HL),A		;
   8369 	EXX			;
   8370 	LD	A,B		;
   8371 	EXX			;
   8372 
   8373 ; addition joins here with carry flag clear.
   8374 
   8375 mark_1828:
   8376 TEST_NORM:
   8377 	JR	NC,NORMALIZE	; forward
   8378 
   8379 	LD	A,(HL)		;
   8380 	AND	A		;
   8381 
   8382 mark_182C:
   8383 NEAR_ZERO:
   8384 	LD	A,$80		; prepare to rescue the most significant bit 
   8385 				; of the mantissa if it is set.
   8386 	JR	Z,SKIP_ZERO	; skip forward
   8387 
   8388 mark_1830:
   8389 ZERO_RESULT:
   8390 	XOR	A		; make mask byte zero signaling set five
   8391 				; bytes to zero.
   8392 
   8393 mark_1831:
   8394 SKIP_ZERO:
   8395 	EXX			; switch in alternate set
   8396 	AND	D		; isolate most significant bit (if A is $80).
   8397 
   8398 	CALL	ZEROS_4_OR_5		; sets mantissa without 
   8399 				; affecting any flags.
   8400 
   8401 	RLCA			; test if MSB set. bit 7 goes to bit 0.
   8402 				; either $00 -> $00 or $80 -> $01
   8403 	LD	(HL),A		; make exponent $01 (lowest) or $00 zero
   8404 	JR	C,OFLOW_CLR	; forward if first case
   8405 
   8406 	INC	HL		; address first mantissa byte on the
   8407 				; calculator stack.
   8408 	LD	(HL),A		; insert a zero for the sign bit.
   8409 	DEC	HL		; point to zero exponent
   8410 	JR	OFLOW_CLR		; forward
   8411 
   8412 ; ___
   8413 
   8414 ; this branch is common to addition and multiplication with the mantissa
   8415 ; result still in registers D'E'D E .
   8416 
   8417 mark_183F:
   8418 NORMALIZE:
   8419 	LD	B,32		; a maximum of thirty-two left shifts will be 
   8420 				; needed.
   8421 
   8422 mark_1841:
   8423 SHIFT_ONE:
   8424 	EXX			; address higher 16 bits.
   8425 	BIT	7,D		; test the leftmost bit
   8426 	EXX			; address lower 16 bits.
   8427 
   8428 	JR	NZ,NORML_NOW	; forward if leftmost bit was set
   8429 
   8430 	RLCA			; this holds zero from addition, 33rd bit 
   8431 				; from multiplication.
   8432 
   8433 	RL	E		; C < 76543210 < C
   8434 	RL	D		; C < 76543210 < C
   8435 
   8436 	EXX			; address higher 16 bits.
   8437 
   8438 	RL	E		; C < 76543210 < C
   8439 	RL	D		; C < 76543210 < C
   8440 
   8441 	EXX			; switch to main set.
   8442 
   8443 	DEC	(HL)		; decrement the exponent byte on the calculator
   8444 				; stack.
   8445 
   8446 	JR	Z,NEAR_ZERO	; back if exponent becomes zero
   8447 				; it's just possible that the last rotation
   8448 				; set bit 7 of D. We shall see.
   8449 
   8450 	DJNZ	SHIFT_ONE	; loop back
   8451 
   8452 ; if thirty-two left shifts were performed without setting the most significant 
   8453 ; bit then the result is zero.
   8454 
   8455 	JR	ZERO_RESULT	; back
   8456 
   8457 ; ___
   8458 
   8459 mark_1859:
   8460 NORML_NOW:
   8461 	RLA			; for the addition path, A is always zero.
   8462 				; for the mult path, ...
   8463 
   8464 	JR	NC,OFLOW_CLR	; forward
   8465 
   8466 ; this branch is taken only with multiplication.
   8467 
   8468 	CALL	ADD_BACK
   8469 
   8470 	JR	NZ,OFLOW_CLR	; forward
   8471 
   8472 	EXX			;
   8473 	LD	D,$80		;
   8474 	EXX			;
   8475 	INC	(HL)		;
   8476 	JR	Z,REPORT_6	; forward
   8477 
   8478 ; now transfer the mantissa from the register sets to the calculator stack
   8479 ; incorporating the sign bit already there.
   8480 
   8481 mark_1868:
   8482 OFLOW_CLR:
   8483 	PUSH	HL		; save pointer to exponent on stack.
   8484 	INC	HL		; address first byte of mantissa which was 
   8485 				; previously loaded with sign bit $00 or $80.
   8486 
   8487 	EXX			; - - -
   8488 	PUSH	DE		; push the most significant two bytes.
   8489 	EXX			; - - -
   8490 
   8491 	POP	BC		; pop - true mantissa is now BCDE.
   8492 
   8493 ; now pick up the sign bit.
   8494 
   8495 	LD	A,B		; first mantissa byte to A 
   8496 	RLA			; rotate out bit 7 which is set
   8497 	RL	(HL)		; rotate sign bit on stack into carry.
   8498 	RRA			; rotate sign bit into bit 7 of mantissa.
   8499 
   8500 ; and transfer mantissa from main registers to calculator stack.
   8501 
   8502 	LD	(HL),A		;
   8503 	INC	HL		;
   8504 	LD	(HL),C		;
   8505 	INC	HL		;
   8506 	LD	(HL),D		;
   8507 	INC	HL		;
   8508 	LD	(HL),E		;
   8509 
   8510 	POP	HL		; restore pointer to num1 now result.
   8511 	POP	DE		; restore pointer to num2 now STKEND.
   8512 
   8513 	EXX			; - - -
   8514 	POP	HL		; restore pointer to next calculator literal.
   8515 	EXX			; - - -
   8516 
   8517 	RET			; return.
   8518 
   8519 ; ___
   8520 
   8521 mark_1880:
   8522 REPORT_6:
   8523 	RST	_ERROR_1
   8524 	DEFB	5		; Error Report: Arithmetic overflow.
   8525 
   8526 
   8527 ; THE 'DIVISION' OPERATION
   8528 
   8529 ;	"Of all the arithmetic subroutines, division is the most complicated and
   8530 ;	the least understood.	It is particularly interesting to note that the 
   8531 ;	Sinclair programmer himself has made a mistake in his programming ( or has
   8532 ;	copied over someone else's mistake!) for
   8533 ;	PRINT PEEK 6352 [ $18D0 ] ('unimproved' ROM, 6351 [ $18CF ] )
   8534 ;	should give 218 not 225."
   8535 ;	- Dr. Ian Logan, Syntax magazine Jul/Aug 1982.
   8536 ;	[ i.e. the jump should be made to div-34th ]
   8537 
   8538 ;	First check for division by zero.
   8539 
   8540 mark_1882:
   8541 DIVISION:
   8542 	EX	DE,HL		; consider the second number first. 
   8543 	XOR	A		; set the running sign flag.
   8544 	CALL	PREP_MULTIPLY_OR_DIVIDE
   8545 	JR	C,REPORT_6	; back if zero
   8546 				; 'Arithmetic overflow'
   8547 
   8548 	EX	DE,HL		; now prepare first number and check for zero.
   8549 	CALL	PREP_MULTIPLY_OR_DIVIDE
   8550 	RET	C		; return if zero, 0/anything is zero.
   8551 
   8552 	EXX			; - - -
   8553 	PUSH	HL		; save pointer to the next calculator literal.
   8554 	EXX			; - - -
   8555 
   8556 	PUSH	DE		; save pointer to divisor - will be STKEND.
   8557 	PUSH	HL		; save pointer to dividend - will be result.
   8558 
   8559 	CALL	FETCH_TWO		; fetches the two numbers
   8560 				; into the registers H'B'C'C B
   8561 				;			L'D'E'D E
   8562 	EXX			; - - -
   8563 	PUSH	HL		; save the two exponents.
   8564 
   8565 	LD	H,B		; transfer the dividend to H'L'H L
   8566 	LD	L,C		; 
   8567 	EXX			;
   8568 	LD	H,C		;
   8569 	LD	L,B		; 
   8570 
   8571 	XOR	A		; clear carry bit and accumulator.
   8572 	LD	B,$DF		; count upwards from -33 decimal
   8573 	JR	DIVISION_START		; forward to mid-loop entry point
   8574 
   8575 ; ___
   8576 
   8577 mark_18A2:
   8578 DIV_LOOP:
   8579 	RLA			; multiply partial quotient by two
   8580 	RL	C		; setting result bit from carry.
   8581 	EXX			;
   8582 	RL	C		;
   8583 	RL	B		;
   8584 	EXX			;
   8585 
   8586 mark_18AB:
   8587 DIV_34TH:
   8588 	ADD	HL,HL		;
   8589 	EXX			;
   8590 	ADC	HL,HL		;
   8591 	EXX			;
   8592 	JR	C,SUBN_ONLY	; forward
   8593 
   8594 mark_18B2:
   8595 DIVISION_START:
   8596 	SBC	HL,DE		; subtract divisor part.
   8597 	EXX			;
   8598 	SBC	HL,DE		;
   8599 	EXX			;
   8600 	JR	NC,NUM_RESTORE	; forward if subtraction goes
   8601 
   8602 	ADD	HL,DE		; else restore
   8603 	EXX			;
   8604 	ADC	HL,DE		;
   8605 	EXX			;
   8606 	AND	A		; clear carry
   8607 	JR	COUNT_ONE		; forward
   8608 
   8609 ; ___
   8610 
   8611 mark_18C2:
   8612 SUBN_ONLY:
   8613 	AND	A		;
   8614 	SBC	HL,DE		;
   8615 	EXX			;
   8616 	SBC	HL,DE		;
   8617 	EXX			;
   8618 
   8619 mark_18C9:
   8620 NUM_RESTORE:
   8621 	SCF			; set carry flag
   8622 
   8623 mark_18CA:
   8624 COUNT_ONE:
   8625 	INC	B		; increment the counter
   8626 	JP	M,DIV_LOOP	; back while still minus to DIV_LOOP
   8627 
   8628 	PUSH	AF		;
   8629 	JR	Z,DIVISION_START	; back to DIV_START
   8630 
   8631 ; "This jump is made to the wrong place. No 34th bit will ever be obtained
   8632 ; without first shifting the dividend. Hence important results like 1/10 and
   8633 ; 1/1000 are not rounded up as they should be. Rounding up never occurs when
   8634 ; it depends on the 34th bit. The jump should be made to div_34th above."
   8635 ; - Dr. Frank O'Hara, "The Complete Spectrum ROM Disassembly", 1983,
   8636 ; published by Melbourne House.
   8637 ; (Note. on the ZX81 this would be JR Z,DIV_34TH)
   8638 ;
   8639 ; However if you make this change, then while (1/2=.5) will now evaluate as
   8640 ; true, (.25=1/4), which did evaluate as true, no longer does.
   8641 
   8642 	LD	E,A		;
   8643 	LD	D,C		;
   8644 	EXX			;
   8645 	LD	E,C		;
   8646 	LD	D,B		;
   8647 
   8648 	POP	AF		;
   8649 	RR	B		;
   8650 	POP	AF		;
   8651 	RR	B		;
   8652 
   8653 	EXX			;
   8654 	POP	BC		;
   8655 	POP	HL		;
   8656 	LD	A,B		;
   8657 	SUB	C		;
   8658 	JP	DIVN_EXPT		; jump back
   8659 
   8660 
   8661 ; THE 'INTEGER TRUNCATION TOWARDS ZERO' SUBROUTINE
   8662 
   8663 ;
   8664 
   8665 mark_18E4:
   8666 TRUNCATE:
   8667 	LD	A,(HL)		; fetch exponent
   8668 	CP	$81		; compare to +1
   8669 	JR	NC,T_GR_ZERO	; forward, if 1 or more
   8670 
   8671 ; else the number is smaller than plus or minus 1 and can be made zero.
   8672 
   8673 	LD	(HL),$00	; make exponent zero.
   8674 	LD	A,$20		; prepare to set 32 bits of mantissa to zero.
   8675 	JR	NIL_BYTES	; forward
   8676 
   8677 ; ___
   8678 
   8679 mark_18EF:
   8680 T_GR_ZERO:
   8681 	SUB	$A0		; subtract +32 from exponent
   8682 	RET	P		; return if result is positive as all 32 bits 
   8683 				; of the mantissa relate to the integer part.
   8684 				; The floating point is somewhere to the right 
   8685 				; of the mantissa
   8686 
   8687 	NEG			; else negate to form number of rightmost bits 
   8688 				; to be blanked.
   8689 
   8690 ; for instance, disregarding the sign bit, the number 3.5 is held as 
   8691 ; exponent $82 mantissa .11100000 00000000 00000000 00000000
   8692 ; we need to set $82 - $A0 = $E2 NEG = $1E (thirty) bits to zero to form the 
   8693 ; integer.
   8694 ; The sign of the number is never considered as the first bit of the mantissa
   8695 ; must be part of the integer.
   8696 
   8697 mark_18F4:
   8698 NIL_BYTES:
   8699 	PUSH	DE		; save pointer to STKEND
   8700 	EX	DE,HL		; HL points at STKEND
   8701 	DEC	HL		; now at last byte of mantissa.
   8702 	LD	B,A		; Transfer bit count to B register.
   8703 	SRL	B		; divide by 
   8704 	SRL	B		; eight
   8705 	SRL	B		;
   8706 	JR	Z,BITS_ZERO	; forward if zero
   8707 
   8708 ; else the original count was eight or more and whole bytes can be blanked.
   8709 
   8710 mark_1900:
   8711 BYTE_ZERO:
   8712 	LD	(HL),0		; set eight bits to zero.
   8713 	DEC	HL		; point to more significant byte of mantissa.
   8714 	DJNZ	BYTE_ZERO		; loop back
   8715 
   8716 ; now consider any residual bits.
   8717 
   8718 mark_1905:
   8719 BITS_ZERO:
   8720 	AND	$07		; isolate the remaining bits
   8721 	JR	Z,IX_END	; forward if none
   8722 
   8723 	LD	B,A		; transfer bit count to B counter.
   8724 	LD	A,$FF		; form a mask 11111111
   8725 
   8726 mark_190C:
   8727 LESS_MASK:
   8728 	SLA	A		; 1 <- 76543210 <- o	slide mask leftwards.
   8729 	DJNZ	LESS_MASK		; loop back for bit count
   8730 
   8731 	AND	(HL)		; lose the unwanted rightmost bits
   8732 	LD	(HL),A		; and place in mantissa byte.
   8733 
   8734 mark_1912:
   8735 IX_END:
   8736 	EX	DE,HL		; restore result pointer from DE. 
   8737 	POP	DE		; restore STKEND from stack.
   8738 	RET			; return.
   8739 
   8740 
   8741 ;   Up to this point all routine addresses have been maintained so that the
   8742 ;   modified ROM is compatible with any machine-code software that uses ROM
   8743 ;   routines.
   8744 ;   The final section does not maintain address entry points as the routines
   8745 ;   within are not generally called directly.
   8746 
   8747 ;**	FLOATING-POINT CALCULATOR **
   8748 ;********************************
   8749 ; As a general rule the calculator avoids using the IY register.
   8750 ; Exceptions are val and str$.
   8751 ; So an assembly language programmer who has disabled interrupts to use IY
   8752 ; for other purposes can still use the calculator for mathematical
   8753 ; purposes.
   8754 
   8755 ; THE 'TABLE OF CONSTANTS'
   8756 
   8757 ; The ZX81 has only floating-point number representation.
   8758 ; Both the ZX80 and the ZX Spectrum have integer numbers in some form.
   8759 
   8760 
   8761 TAB_CNST:
   8762 
   8763 if ORIGINAL
   8764 mark_1915:
   8765 				;	00 00 00 00 00
   8766 stk_zero:
   8767 	DEFB	$00		;;Bytes: 1
   8768 	DEFB	$B0		;;Exponent $00
   8769 	DEFB	$00		;;(+00,+00,+00)
   8770 
   8771 mark_1918:
   8772 				;	81 00 00 00 00
   8773 stk_one:
   8774 	DEFB	$31		;;Exponent $81, Bytes: 1
   8775 	DEFB	$00		;;(+00,+00,+00)
   8776 
   8777 
   8778 mark_191A:
   8779 				;	80 00 00 00 00
   8780 stk_half:
   8781 	DEFB	$30		;;Exponent: $80, Bytes: 1
   8782 	DEFB	$00		;;(+00,+00,+00)
   8783 
   8784 
   8785 mark_191C:
   8786 				;	81 49 0F DA A2
   8787 stk_half_pi:
   8788 	DEFB	$F1		;;Exponent: $81, Bytes: 4
   8789 	DEFB	$49,$0F,$DA,$A2 ;;
   8790 
   8791 mark_1921:
   8792 				;	84 20 00 00 00
   8793 stk_ten:
   8794 	DEFB	$34		;;Exponent: $84, Bytes: 1
   8795 	DEFB	$20		;;(+00,+00,+00)
   8796 else
   8797 ;	This table has been modified so that the constants are held in their
   8798 ;	uncompressed, ready-to-use, 5-byte form.
   8799 
   8800 	DEFB	$00	; the value zero.
   8801 	DEFB	$00	;
   8802 	DEFB	$00	;
   8803 	DEFB	$00	;
   8804 	DEFB	$00	;
   8805 
   8806 	DEFB	$81	; the floating point value 1.
   8807 	DEFB	$00	;
   8808 	DEFB	$00	;
   8809 	DEFB	$00	;
   8810 	DEFB	$00	;
   8811 
   8812 	DEFB	$80	; the floating point value 1/2.
   8813 	DEFB	$00	;
   8814 	DEFB	$00	;
   8815 	DEFB	$00	;
   8816 	DEFB	$00	;
   8817 
   8818 	DEFB	$81	; the floating point value pi/2.
   8819 	DEFB	$49	;
   8820 	DEFB	$0F	;
   8821 	DEFB	$DA	;
   8822 	DEFB	$A2	;
   8823 
   8824 	DEFB	$84	; the floating point value ten.
   8825 	DEFB	$20	;
   8826 	DEFB	$00	;
   8827 	DEFB	$00	;
   8828 	DEFB	$00	;
   8829 endif
   8830 
   8831 
   8832 ; THE 'TABLE OF ADDRESSES'
   8833 
   8834 ;
   8835 ; starts with binary operations which have two operands and one result.
   8836 ; three pseudo binary operations first.
   8837 
   8838 if ORIGINAL
   8839 mark_1923:
   8840 else
   8841 endif
   8842 
   8843 tbl_addrs:
   8844 
   8845 	DEFW	jump_true		; $00 Address: $1C2F - jump_true
   8846 	DEFW	exchange		; $01 Address: $1A72 - exchange
   8847 	DEFW	delete			; $02 Address: $19E3 - delete
   8848 
   8849 ; true binary operations.
   8850 
   8851 	DEFW	SUBTRACT		; $03 Address: $174C - subtract
   8852 	DEFW	MULTIPLY		; $04 Address: $176C - multiply
   8853 	DEFW	DIVISION		; $05 Address: $1882 - division
   8854 	DEFW	to_power		; $06 Address: $1DE2 - to_power
   8855 	DEFW	or			; $07 Address: $1AED - or
   8856 
   8857 	DEFW	boolean_num_and_num		; $08 Address: $1AF3 - boolean_num_and_num
   8858 	DEFW	num_l_eql		; $09 Address: $1B03 - num_l_eql
   8859 	DEFW	num_gr_eql		; $0A Address: $1B03 - num_gr_eql
   8860 	DEFW	nums_neql		; $0B Address: $1B03 - nums_neql
   8861 	DEFW	num_grtr		; $0C Address: $1B03 - num_grtr
   8862 	DEFW	num_less		; $0D Address: $1B03 - num_less
   8863 	DEFW	nums_eql		; $0E Address: $1B03 - nums_eql
   8864 	DEFW	ADDITION		; $0F Address: $1755 - addition
   8865 
   8866 	DEFW	strs_and_num		; $10 Address: $1AF8 - str_and_num
   8867 	DEFW	str_l_eql		; $11 Address: $1B03 - str_l_eql
   8868 	DEFW	str_gr_eql		; $12 Address: $1B03 - str_gr_eql
   8869 	DEFW	strs_neql		; $13 Address: $1B03 - strs_neql
   8870 	DEFW	str_grtr		; $14 Address: $1B03 - str_grtr
   8871 	DEFW	str_less		; $15 Address: $1B03 - str_less
   8872 	DEFW	strs_eql		; $16 Address: $1B03 - strs_eql
   8873 	DEFW	strs_add		; $17 Address: $1B62 - strs_add
   8874 
   8875 ; unary follow
   8876 
   8877 	DEFW	neg		; $18
   8878 	DEFW	code		; $19
   8879 	DEFW	val		; $1A 
   8880 	DEFW	len		; $1B 
   8881 	DEFW	sin		; $1C
   8882 	DEFW	cos		; $1D
   8883 	DEFW	tan		; $1E
   8884 	DEFW	asn		; $1F
   8885 	DEFW	acs		; $20
   8886 	DEFW	atn		; $21
   8887 	DEFW	ln		; $22
   8888 	DEFW	exp		; $23
   8889 	DEFW	int		; $24
   8890 	DEFW	sqr		; $25
   8891 	DEFW	sgn		; $26
   8892 	DEFW	abs		; $27
   8893 	DEFW	PEEK		; $28 Address: $1A1B - peek		!!!!
   8894 	DEFW	usr_num		; $29
   8895 	DEFW	str_dollar	; $2A
   8896 	DEFW	chr_dollar	; $2B
   8897 	DEFW	not		; $2C
   8898 
   8899 ; end of true unary
   8900 
   8901 	DEFW	duplicate	; $2D
   8902 	DEFW	n_mod_m		; $2E
   8903 
   8904 	DEFW	jump		; $2F
   8905 	DEFW	stk_data	; $30
   8906 
   8907 	DEFW	dec_jr_nz	; $31
   8908 	DEFW	less_0		; $32
   8909 	DEFW	greater_0	; $33
   8910 	DEFW	end_calc	; $34
   8911 	DEFW	get_argt	; $35
   8912 	DEFW	TRUNCATE	; $36
   8913 	DEFW	FP_CALC_2	; $37
   8914 	DEFW	e_to_fp		; $38
   8915 
   8916 ; the following are just the next available slots for the 128 compound literals
   8917 ; which are in range $80 - $FF.
   8918 
   8919 	DEFW	series_xx		; $39 : $80 - $9F.
   8920 	DEFW	stk_const_xx		; $3A : $A0 - $BF.
   8921 	DEFW	st_mem_xx		; $3B : $C0 - $DF.
   8922 	DEFW	get_mem_xx		; $3C : $E0 - $FF.
   8923 
   8924 ; Aside: 3D - 7F are therefore unused calculator literals.
   8925 ;	39 - 7B would be available for expansion.
   8926 
   8927 
   8928 ; THE 'FLOATING POINT CALCULATOR'
   8929 
   8930 ;
   8931 ;
   8932 
   8933 mark_199D:
   8934 CALCULATE:
   8935 	CALL	STACK_POINTERS	; is called to set up the
   8936 				; calculator stack pointers for a default
   8937 				; unary operation. HL = last value on stack.
   8938 				; DE = STKEND first location after stack.
   8939 
   8940 ; the calculate routine is called at this point by the series generator...
   8941 
   8942 mark_19A0:
   8943 GEN_ENT_1:
   8944 	LD	A,B		; fetch the Z80 B register to A
   8945 	LD	(BERG),A	; and store value in system variable BERG.
   8946 				; this will be the counter for dec_jr_nz
   8947 				; or if used from FP_CALC2 the calculator
   8948 				; instruction.
   8949 
   8950 ; ... and again later at this point
   8951 
   8952 mark_19A4:
   8953 GEN_ENT_2:
   8954 	EXX			; switch sets
   8955 	EX	(SP),HL		; and store the address of next instruction,
   8956 				; the return address, in H'L'.
   8957 				; If this is a recursive call then the H'L'
   8958 				; of the previous invocation goes on stack.
   8959 				; c.f. end_calc.
   8960 	EXX			; switch back to main set.
   8961 
   8962 ; this is the re-entry looping point when handling a string of literals.
   8963 
   8964 mark_19A7:
   8965 RE_ENTRY:
   8966 	LD	(STKEND),DE	; save end of stack
   8967 	EXX			; switch to alt
   8968 	LD	A,(HL)		; get next literal
   8969 	INC	HL		; increase pointer'
   8970 
   8971 ; single operation jumps back to here
   8972 
   8973 mark_19AE:
   8974 SCAN_ENT:
   8975 	PUSH	HL		; save pointer on stack	*
   8976 	AND	A		; now test the literal
   8977 	JP	P,FIRST_3D	; forward if in range $00 - $3D
   8978 				; anything with bit 7 set will be one of
   8979 				; 128 compound literals.
   8980 
   8981 ; compound literals have the following format.
   8982 ; bit 7 set indicates compound.
   8983 ; bits 6-5 the subgroup 0-3.
   8984 ; bits 4-0 the embedded parameter $00 - $1F.
   8985 ; The subgroup 0-3 needs to be manipulated to form the next available four
   8986 ; address places after the simple literals in the address table.
   8987 
   8988 	LD	D,A		; save literal in D
   8989 	AND	$60		; and with 01100000 to isolate subgroup
   8990 	RRCA			; rotate bits
   8991 	RRCA			; 4 places to right
   8992 	RRCA			; not five as we need offset * 2
   8993 	RRCA			; 00000xx0
   8994 	ADD	A,$72		; add ($39 * 2) to give correct offset.
   8995 				; alter above if you add more literals.
   8996 	LD	L,A		; store in L for later indexing.
   8997 	LD	A,D		; bring back compound literal
   8998 	AND	$1F		; use mask to isolate parameter bits
   8999 	JR	ENT_TABLE	; forward
   9000 
   9001 ; ___
   9002 
   9003 ; the branch was here with simple literals.
   9004 
   9005 mark_19C2:
   9006 FIRST_3D:
   9007 	CP	$18		; compare with first unary operations.
   9008 	JR	NC,DOUBLE_A	; with unary operations
   9009 
   9010 ; it is binary so adjust pointers.
   9011 
   9012 	EXX			;
   9013 	LD	BC,-5
   9014 	LD	D,H		; transfer HL, the last value, to DE.
   9015 	LD	E,L		;
   9016 	ADD	HL,BC		; subtract 5 making HL point to second
   9017 				; value.
   9018 	EXX			;
   9019 
   9020 mark_19CE:
   9021 DOUBLE_A:
   9022 	RLCA			; double the literal
   9023 	LD	L,A		; and store in L for indexing
   9024 
   9025 mark_19D0:
   9026 ENT_TABLE:
   9027 	LD	DE,tbl_addrs	; Address: tbl_addrs
   9028 	LD	H,$00		; prepare to index
   9029 	ADD	HL,DE		; add to get address of routine
   9030 	LD	E,(HL)		; low byte to E
   9031 	INC	HL		;
   9032 	LD	D,(HL)		; high byte to D
   9033 
   9034 	LD	HL,RE_ENTRY
   9035 	EX	(SP),HL	; goes on machine stack
   9036 				; address of next literal goes to HL. *
   9037 
   9038 
   9039 	PUSH	DE		; now the address of routine is stacked.
   9040 	EXX			; back to main set
   9041 				; avoid using IY register.
   9042 	LD	BC,(STKEND+1)	; STKEND_hi
   9043 				; nothing much goes to C but BERG to B
   9044 				; and continue into next ret instruction
   9045 				; which has a dual identity
   9046 
   9047 
   9048 
   9049 ; THE 'DELETE' SUBROUTINE
   9050 
   9051 ; offset $02: 'delete'
   9052 ; A simple return but when used as a calculator literal this
   9053 ; deletes the last value from the calculator stack.
   9054 ; On entry, as always with binary operations,
   9055 ; HL=first number, DE=second number
   9056 ; On exit, HL=result, DE=stkend.
   9057 ; So nothing to do
   9058 
   9059 mark_19E3:
   9060 delete:
   9061 	RET			; return - indirect jump if from above.
   9062 
   9063 
   9064 ; THE 'SINGLE OPERATION' SUBROUTINE
   9065 
   9066 ; offset $37: 'FP_CALC_2'
   9067 ; this single operation is used, in the first instance, to evaluate most
   9068 ; of the mathematical and string functions found in BASIC expressions.
   9069 
   9070 mark_19E4:
   9071 FP_CALC_2:
   9072 	POP	AF		; drop return address.
   9073 	LD	A,(BERG)	; load accumulator from system variable BERG
   9074 				; value will be literal eg. 'tan'
   9075 	EXX			; switch to alt
   9076 	JR	SCAN_ENT	; back
   9077 				; next literal will be end_calc in scanning
   9078 
   9079 
   9080 ; THE 'TEST 5 SPACES' SUBROUTINE
   9081 
   9082 ; This routine is called from MOVE_FP, STK_CONST and STK_STORE to
   9083 ; test that there is enough space between the calculator stack and the
   9084 ; machine stack for another five_byte value. It returns with BC holding
   9085 ; the value 5 ready for any subsequent LDIR.
   9086 
   9087 mark_19EB:
   9088 TEST_5_SP:
   9089 	PUSH	DE		; save
   9090 	PUSH	HL		; registers
   9091 	LD	BC,5		; an overhead of five bytes
   9092 	CALL	TEST_ROOM	; tests free RAM raising
   9093 				; an error if not.
   9094 	POP	HL		; else restore
   9095 	POP	DE		; registers.
   9096 	RET			; return with BC set at 5.
   9097 
   9098 
   9099 
   9100 ; THE 'MOVE A FLOATING POINT NUMBER' SUBROUTINE
   9101 
   9102 ; offset $2D: 'duplicate'
   9103 ; This simple routine is a 5-byte LDIR instruction
   9104 ; that incorporates a memory check.
   9105 ; When used as a calculator literal it duplicates the last value on the
   9106 ; calculator stack.
   9107 ; Unary so on entry HL points to last value, DE to stkend
   9108 
   9109 mark_19F6:
   9110 duplicate:
   9111 MOVE_FP:
   9112 	CALL	TEST_5_SP	; test free memory
   9113 				; and sets BC to 5.
   9114 	LDIR			; copy the five bytes.
   9115 	RET			; return with DE addressing new STKEND
   9116 				; and HL addressing new last value.
   9117 
   9118 
   9119 ; THE 'STACK LITERALS' SUBROUTINE
   9120 
   9121 ; offset $30: 'stk_data'
   9122 ; When a calculator subroutine needs to put a value on the calculator
   9123 ; stack that is not a regular constant this routine is called with a
   9124 ; variable number of following data bytes that convey to the routine
   9125 ; the floating point form as succinctly as is possible.
   9126 
   9127 mark_19FC:
   9128 stk_data:
   9129 	LD	H,D		; transfer STKEND
   9130 	LD	L,E		; to HL for result.
   9131 
   9132 mark_19FE:
   9133 STK_CONST:
   9134 	CALL	TEST_5_SP	; tests that room exists
   9135 				; and sets BC to $05.
   9136 
   9137 	EXX			; switch to alternate set
   9138 	PUSH	HL		; save the pointer to next literal on stack
   9139 	EXX			; switch back to main set
   9140 
   9141 	EX	(SP),HL	; pointer to HL, destination to stack.
   9142 
   9143 if ORIGINAL
   9144 	PUSH	BC		; save BC - value 5 from test room ??.
   9145 else
   9146 ;;	PUSH	BC		; save BC - value 5 from test room. No need.
   9147 endif
   9148 	LD	A,(HL)		; fetch the byte following 'stk_data'
   9149 	AND	$C0		; isolate bits 7 and 6
   9150 	RLCA			; rotate
   9151 	RLCA			; to bits 1 and 0	range $00 - $03.
   9152 	LD	C,A		; transfer to C
   9153 	INC	C		; and increment to give number of bytes
   9154 				; to read. $01 - $04
   9155 	LD	A,(HL)		; reload the first byte
   9156 	AND	$3F		; mask off to give possible exponent.
   9157 	JR	NZ,FORM_EXP	; forward to FORM_EXP if it was possible to
   9158 				; include the exponent.
   9159 
   9160 ; else byte is just a byte count and exponent comes next.
   9161 
   9162 	INC	HL		; address next byte and
   9163 	LD	A,(HL)		; pick up the exponent ( - $50).
   9164 
   9165 mark_1A14:
   9166 FORM_EXP:
   9167 	ADD	A,$50		; now add $50 to form actual exponent
   9168 	LD	(DE),A		; and load into first destination byte.
   9169 	LD	A,$05		; load accumulator with $05 and
   9170 	SUB	C		; subtract C to give count of trailing
   9171 				; zeros plus one.
   9172 	INC	HL		; increment source
   9173 	INC	DE		; increment destination
   9174 
   9175 
   9176 if ORIGINAL
   9177 	LD	B,$00		; prepare to copy. Note. B is zero.
   9178 	LDIR			; copy C bytes
   9179 	POP	BC		; restore 5 counter to BC.
   9180 else
   9181 	LDIR			; copy C bytes
   9182 endif
   9183 
   9184 	EX	(SP),HL		; put HL on stack as next literal pointer
   9185 				; and the stack value - result pointer -
   9186 				; to HL.
   9187 
   9188 	EXX			; switch to alternate set.
   9189 	POP	HL		; restore next literal pointer from stack
   9190 				; to H'L'.
   9191 	EXX			; switch back to main set.
   9192 
   9193 	LD	B,A		; zero count to B
   9194 	XOR	A		; clear accumulator
   9195 
   9196 mark_1A27:
   9197 STK_ZEROS:
   9198 	DEC	B		; decrement B counter
   9199 	RET	Z		; return if zero.		>>
   9200 				; DE points to new STKEND
   9201 				; HL to new number.
   9202 
   9203 	LD	(DE),A		; else load zero to destination
   9204 	INC	DE		; increase destination
   9205 	JR	STK_ZEROS	; loop back until done.
   9206 
   9207 
   9208 ; THE 'SKIP CONSTANTS' SUBROUTINE
   9209 
   9210 ; This routine traverses variable-length entries in the table of constants,
   9211 ; stacking intermediate, unwanted constants onto a dummy calculator stack,
   9212 ; in the first five bytes of the ZX81 ROM.
   9213 
   9214 if ORIGINAL
   9215 mark_1A2D:
   9216 SKIP_CONS:
   9217 	AND	A		; test if initially zero.
   9218 
   9219 mark_1A2E:
   9220 SKIP_NEXT:
   9221 	RET	Z		; return if zero.		>>
   9222 
   9223 	PUSH	AF		; save count.
   9224 	PUSH	DE		; and normal STKEND
   9225 
   9226 	LD	DE,$0000	; dummy value for STKEND at start of ROM
   9227 				; Note. not a fault but this has to be
   9228 				; moved elsewhere when running in RAM.
   9229 				;
   9230 	CALL	STK_CONST		; works through variable
   9231 				; length records.
   9232 
   9233 	POP	DE		; restore real STKEND
   9234 	POP	AF		; restore count
   9235 	DEC	A		; decrease
   9236 	JR	SKIP_NEXT	; loop back
   9237 else
   9238 ; Since the table now uses uncompressed values, some extra ROM space is 
   9239 ; required for the table but much more is released by getting rid of routines
   9240 ; like this.
   9241 endif
   9242 
   9243 
   9244 ; THE 'MEMORY LOCATION' SUBROUTINE
   9245 
   9246 ; This routine, when supplied with a base address in HL and an index in A,
   9247 ; will calculate the address of the A'th entry, where each entry occupies
   9248 ; five bytes. It is used for addressing floating-point numbers in the
   9249 ; calculator's memory area.
   9250 
   9251 mark_1A3C:
   9252 LOC_MEM:
   9253 	LD	C,A		; store the original number $00-$1F.
   9254 	RLCA			; double.
   9255 	RLCA			; quadruple.
   9256 	ADD	A,C		; now add original value to multiply by five.
   9257 
   9258 	LD	C,A		; place the result in C.
   9259 	LD	B,$00		; set B to 0.
   9260 	ADD	HL,BC		; add to form address of start of number in HL.
   9261 
   9262 	RET			; return.
   9263 
   9264 
   9265 ; THE 'GET FROM MEMORY AREA' SUBROUTINE
   9266 
   9267 ; offsets $E0 to $FF: 'get_mem_0', 'get_mem_1' etc.
   9268 ; A holds $00-$1F offset.
   9269 ; The calculator stack increases by 5 bytes.
   9270 
   9271 mark_1A45:
   9272 get_mem_xx:
   9273 
   9274 if ORIGINAL
   9275 	PUSH	DE		; save STKEND
   9276 	LD	HL,(MEM)	; MEM is base address of the memory cells.
   9277 else
   9278 				; Note. first two instructions have been swapped to create a subroutine.
   9279 	LD	HL,(MEM)	; MEM is base address of the memory cells.
   9280 INDEX_5:			; new label
   9281 	PUSH	DE		; save STKEND
   9282 endif
   9283 	CALL	LOC_MEM		; so that HL = first byte
   9284 	CALL	MOVE_FP		; moves 5 bytes with memory
   9285 				; check.
   9286 				; DE now points to new STKEND.
   9287 	POP	HL		; the original STKEND is now RESULT pointer.
   9288 	RET			; return.
   9289 
   9290 
   9291 ; THE 'STACK A CONSTANT' SUBROUTINE
   9292 
   9293 
   9294 stk_const_xx:
   9295 if ORIGINAL
   9296 
   9297 ; offset $A0: 'stk_zero'
   9298 ; offset $A1: 'stk_one'
   9299 ; offset $A2: 'stk_half'
   9300 ; offset $A3: 'stk_half_pi'
   9301 ; offset $A4: 'stk_ten'
   9302 ;
   9303 ; This routine allows a one-byte instruction to stack up to 32 constants
   9304 ; held in short form in a table of constants. In fact only 5 constants are
   9305 ; required. On entry the A register holds the literal ANDed with $1F.
   9306 ; It isn't very efficient and it would have been better to hold the
   9307 ; numbers in full, five byte form and stack them in a similar manner
   9308 ; to that which would be used later for semi-tone table values.
   9309 
   9310 mark_1A51:
   9311 
   9312 	LD	H,D		; save STKEND - required for result
   9313 	LD	L,E		;
   9314 	EXX			; swap
   9315 	PUSH	HL		; save pointer to next literal
   9316 	LD	HL,stk_zero	; Address: stk_zero - start of table of
   9317 				; constants
   9318 	EXX			;
   9319 	CALL	SKIP_CONS
   9320 	CALL	STK_CONST
   9321 	EXX			;
   9322 	POP	HL		; restore pointer to next literal.
   9323 	EXX			;
   9324 	RET			; return.
   9325 else
   9326 stk_con_x:
   9327 	LD	HL,TAB_CNST	; Address: Table of constants.
   9328 
   9329 	JR	INDEX_5		; and join subroutine above.
   9330 endif
   9331 
   9332 
   9333 
   9334 
   9335 ; THE 'STORE IN A MEMORY AREA' SUBROUTINE
   9336 
   9337 ; Offsets $C0 to $DF: 'st_mem_0', 'st_mem_1' etc.
   9338 ; Although 32 memory storage locations can be addressed, only six
   9339 ; $C0 to $C5 are required by the ROM and only the thirty bytes (6*5)
   9340 ; required for these are allocated. ZX81 programmers who wish to
   9341 ; use the floating point routines from assembly language may wish to
   9342 ; alter the system variable MEM to point to 160 bytes of RAM to have
   9343 ; use the full range available.
   9344 ; A holds derived offset $00-$1F.
   9345 ; Unary so on entry HL points to last value, DE to STKEND.
   9346 
   9347 mark_1A63:
   9348 st_mem_xx:
   9349 	PUSH	HL		; save the result pointer.
   9350 	EX	DE,HL		; transfer to DE.
   9351 	LD	HL,(MEM)	; fetch MEM the base of memory area.
   9352 	CALL	LOC_MEM		; sets HL to the destination.
   9353 	EX	DE,HL		; swap - HL is start, DE is destination.
   9354 
   9355 if ORIGINAL
   9356 	CALL	MOVE_FP
   9357 				; note. a short ld bc,5; ldir
   9358 				; the embedded memory check is not required
   9359 				; so these instructions would be faster!
   9360 else
   9361 	LD	C,5		;+ one extra byte but 
   9362 	LDIR			;+ faster and no memory check.
   9363 endif
   9364 
   9365 
   9366 	EX	DE,HL		; DE = STKEND
   9367 	POP	HL		; restore original result pointer
   9368 	RET			; return.
   9369 
   9370 
   9371 ; THE 'EXCHANGE' SUBROUTINE
   9372 
   9373 ; offset $01: 'exchange'
   9374 ; This routine exchanges the last two values on the calculator stack
   9375 ; On entry, as always with binary operations,
   9376 ; HL=first number, DE=second number
   9377 ; On exit, HL=result, DE=stkend.
   9378 
   9379 mark_1A72:
   9380 exchange:
   9381 	LD	B,$05		; there are five bytes to be swapped
   9382 
   9383 ; start of loop.
   9384 
   9385 mark_1A74:
   9386 SWAP_BYTE:
   9387 	LD	A,(DE)		; each byte of second
   9388 if ORIGINAL
   9389 	LD	C,(HL)		; each byte of first
   9390 	EX	DE,HL		; swap pointers
   9391 else
   9392 	LD	C,A		;+
   9393 	LD	A,(HL)
   9394 endif
   9395 	LD	(DE),A		; store each byte of first
   9396 	LD	(HL),C		; store each byte of second
   9397 	INC	HL		; advance both
   9398 	INC	DE		; pointers.
   9399 	DJNZ	SWAP_BYTE	; loop back until all 5 done.
   9400 
   9401 if ORIGINAL
   9402 	EX	DE,HL		; even up the exchanges so that DE addresses STKEND.
   9403 else
   9404 ;	omit
   9405 endif
   9406 	RET			; return.
   9407 
   9408 
   9409 ; THE 'SERIES GENERATOR' SUBROUTINE
   9410 
   9411 
   9412 ; The ZX81 uses Chebyshev polynomials to generate approximations for
   9413 ; SIN, ATN, LN and EXP. These are named after the Russian mathematician
   9414 ; Pafnuty Chebyshev, born in 1821, who did much pioneering work on numerical
   9415 ; series. As far as calculators are concerned, Chebyshev polynomials have an
   9416 ; advantage over other series, for example the Taylor series, as they can
   9417 ; reach an approximation in just six iterations for SIN, eight for EXP and
   9418 ; twelve for LN and ATN. The mechanics of the routine are interesting but
   9419 ; for full treatment of how these are generated with demonstrations in
   9420 ; Sinclair BASIC see "The Complete Spectrum ROM Disassembly" by Dr Ian Logan
   9421 ; and Dr Frank O'Hara, published 1983 by Melbourne House.
   9422 
   9423 mark_1A7F:
   9424 series_xx:
   9425 	LD	B,A		; parameter $00 - $1F to B counter
   9426 	CALL	GEN_ENT_1
   9427 				; A recursive call to a special entry point
   9428 				; in the calculator that puts the B register
   9429 				; in the system variable BERG. The return
   9430 				; address is the next location and where
   9431 				; the calculator will expect its first
   9432 				; instruction - now pointed to by HL'.
   9433 				; The previous pointer to the series of
   9434 				; five-byte numbers goes on the machine stack.
   9435 
   9436 ; The initialization phase.
   9437 
   9438 	DEFB	__duplicate	;;	x,x
   9439 	DEFB	__addition	;;	x+x
   9440 	DEFB	__st_mem_0	;;	x+x
   9441 	DEFB	__delete	;;	.
   9442 	DEFB	__stk_zero	;;	0
   9443 	DEFB	__st_mem_2	;;	0
   9444 
   9445 ; a loop is now entered to perform the algebraic calculation for each of
   9446 ; the numbers in the series
   9447 
   9448 mark_1A89:
   9449 G_LOOP:
   9450 	DEFB	__duplicate	;;	v,v.
   9451 	DEFB	__get_mem_0	;;	v,v,x+2
   9452 	DEFB	__multiply	;;	v,v*x+2
   9453 	DEFB	__get_mem_2	;;	v,v*x+2,v
   9454 	DEFB	__st_mem_1	;;
   9455 	DEFB	__subtract	;;
   9456 	DEFB	__end_calc	;;
   9457 
   9458 ; the previous pointer is fetched from the machine stack to H'L' where it
   9459 ; addresses one of the numbers of the series following the series literal.
   9460 
   9461 	CALL	stk_data		; is called directly to
   9462 				; push a value and advance H'L'.
   9463 	CALL	GEN_ENT_2		; recursively re-enters
   9464 				; the calculator without disturbing
   9465 				; system variable BERG
   9466 				; H'L' value goes on the machine stack and is
   9467 				; then loaded as usual with the next address.
   9468 
   9469 	DEFB	__addition	;;
   9470 	DEFB	__exchange	;;
   9471 	DEFB	__st_mem_2	;;
   9472 	DEFB	__delete	;;
   9473 
   9474 	DEFB	__dec_jr_nz	;;
   9475 	DEFB	$EE		;;back to G_LOOP, G_LOOP
   9476 
   9477 ; when the counted loop is complete the final subtraction yields the result
   9478 ; for example SIN X.
   9479 
   9480 	DEFB	__get_mem_1	;;
   9481 	DEFB	__subtract	;;
   9482 	DEFB	__end_calc	;;
   9483 
   9484 	RET			; return with H'L' pointing to location
   9485 				; after last number in series.
   9486 
   9487 
   9488 ; Handle unary minus (18)
   9489 
   9490 ; Unary so on entry HL points to last value, DE to STKEND.
   9491 
   9492 mark_1AA0:
   9493 neg:
   9494 	LD A,	(HL)		; fetch exponent of last value on the
   9495 				; calculator stack.
   9496 	AND	A		; test it.
   9497 	RET	Z		; return if zero.
   9498 
   9499 	INC	HL		; address the byte with the sign bit.
   9500 	LD	A,(HL)		; fetch to accumulator.
   9501 	XOR	$80		; toggle the sign bit.
   9502 	LD	(HL),A		; put it back.
   9503 	DEC	HL		; point to last value again.
   9504 	RET			; return.
   9505 
   9506 
   9507 ; Absolute magnitude (27)
   9508 
   9509 ; This calculator literal finds the absolute value of the last value,
   9510 ; floating point, on calculator stack.
   9511 
   9512 mark_1AAA:
   9513 abs:
   9514 	INC	HL		; point to byte with sign bit.
   9515 	RES	7,(HL)		; make the sign positive.
   9516 	DEC	HL		; point to last value again.
   9517 	RET			; return.
   9518 
   9519 
   9520 ; Signum (26)
   9521 
   9522 ; This routine replaces the last value on the calculator stack,
   9523 ; which is in floating point form, with one if positive and with -minus one
   9524 ; if negative. If it is zero then it is left as such.
   9525 
   9526 mark_1AAF:
   9527 sgn:
   9528 	INC	HL		; point to first byte of 4-byte mantissa.
   9529 	LD	A,(HL)		; pick up the byte with the sign bit.
   9530 	DEC	HL		; point to exponent.
   9531 	DEC	(HL)		; test the exponent for
   9532 	INC	(HL)		; the value zero.
   9533 
   9534 	SCF			; set the carry flag.
   9535 	CALL	NZ,FP_0_OR_1	; replaces last value with one
   9536 				; if exponent indicates the value is non-zero.
   9537 				; in either case mantissa is now four zeros.
   9538 
   9539 	INC HL			; point to first byte of 4-byte mantissa.
   9540 	RLCA			; rotate original sign bit to carry.
   9541 	RR	(HL)		; rotate the carry into sign.
   9542 	DEC HL			; point to last value.
   9543 	RET			; return.
   9544 
   9545 
   9546 
   9547 ; Handle PEEK function (28)
   9548 
   9549 ; This function returns the contents of a memory address.
   9550 ; The entire address space can be peeked including the ROM.
   9551 
   9552 mark_1ABE:
   9553 PEEK:
   9554 	CALL	FIND_INT	; puts address in BC.
   9555 	LD	A,(BC)		; load contents into A register.
   9556 
   9557 mark_1AC2:
   9558 IN_PK_STK:
   9559 	JP	STACK_A		; exit via STACK_A to put value on the
   9560 				; calculator stack.
   9561 
   9562 
   9563 ; USR number (29)
   9564 
   9565 ; The USR function followed by a number 0-65535 is the method by which
   9566 ; the ZX81 invokes machine code programs. This function returns the
   9567 ; contents of the BC register pair.
   9568 ; Note. that STACK_BC re-initializes the IY register to ERR_NR if a user-written
   9569 ; program has altered it.
   9570 
   9571 mark_1AC5:
   9572 usr_num:
   9573 	CALL	FIND_INT	; to fetch the
   9574 				; supplied address into BC.
   9575 
   9576 	LD	HL,STACK_BC	; address: STACK_BC is
   9577 	PUSH	HL		; pushed onto the machine stack.
   9578 	PUSH	BC		; then the address of the machine code
   9579 				; routine.
   9580 
   9581 	RET			; make an indirect jump to the routine
   9582 				; and, hopefully, to STACK_BC also.
   9583 
   9584 
   9585 
   9586 ; Greater than zero ($33)
   9587 
   9588 ; Test if the last value on the calculator stack is greater than zero.
   9589 ; This routine is also called directly from the end-tests of the comparison
   9590 ; routine.
   9591 
   9592 mark_1ACE:
   9593 greater_0:
   9594 	LD	A,(HL)		; fetch exponent.
   9595 	AND	A		; test it for zero.
   9596 	RET	Z		; return if so.
   9597 
   9598 
   9599 	LD	A,$FF		; prepare XOR mask for sign bit
   9600 	JR	SIGN_TO_C	; forward to SIGN_TO_C
   9601 				; to put sign in carry
   9602 				; (carry will become set if sign is positive)
   9603 				; and then overwrite location with 1 or 0
   9604 				; as appropriate.
   9605 
   9606 
   9607 ; Handle NOT operator ($2C)
   9608 
   9609 ; This overwrites the last value with 1 if it was zero else with zero
   9610 ; if it was any other value.
   9611 ;
   9612 ; e.g. NOT 0 returns 1, NOT 1 returns 0, NOT -3 returns 0.
   9613 ;
   9614 ; The subroutine is also called directly from the end-tests of the comparison
   9615 ; operator.
   9616 
   9617 mark_1AD5:
   9618 not:
   9619 	LD	A,(HL)		; get exponent byte.
   9620 	NEG			; negate - sets carry if non-zero.
   9621 	CCF			; complement so carry set if zero, else reset.
   9622 	JR	FP_0_OR_1	; forward to FP_0_OR_1.
   9623 
   9624 
   9625 ; Less than zero (32)
   9626 
   9627 ; Destructively test if last value on calculator stack is less than zero.
   9628 ; Bit 7 of second byte will be set if so.
   9629 
   9630 mark_1ADB:
   9631 less_0:
   9632 	XOR	A		; set xor mask to zero
   9633 				; (carry will become set if sign is negative).
   9634 
   9635 ; transfer sign of mantissa to Carry Flag.
   9636 
   9637 mark_1ADC:
   9638 SIGN_TO_C:
   9639 	INC	HL		; address 2nd byte.
   9640 	XOR	(HL)		; bit 7 of HL will be set if number is negative.
   9641 	DEC	HL		; address 1st byte again.
   9642 	RLCA			; rotate bit 7 of A to carry.
   9643 
   9644 
   9645 ; Zero or one
   9646 
   9647 ; This routine places an integer value zero or one at the addressed location
   9648 ; of calculator stack or MEM area. The value one is written if carry is set on
   9649 ; entry else zero.
   9650 
   9651 mark_1AE0:
   9652 FP_0_OR_1:
   9653 	PUSH	HL		; save pointer to the first byte
   9654 	LD	B,$05		; five bytes to do.
   9655 
   9656 mark_1AE3:
   9657 FP_loop:
   9658 	LD	(HL),$00	; insert a zero.
   9659 	INC	HL		;
   9660 	DJNZ	FP_loop		; repeat.
   9661 
   9662 	POP	HL		;
   9663 	RET	NC		;
   9664 
   9665 	LD	(HL),$81	; make value 1
   9666 	RET			; return.
   9667 
   9668 
   9669 
   9670 ; Handle OR operator (07)
   9671 
   9672 ; The Boolean OR operator. eg. X OR Y
   9673 ; The result is zero if both values are zero else a non-zero value.
   9674 ;
   9675 ; e.g.	0 OR 0	returns 0.
   9676 ;	-3 OR 0	returns -3.
   9677 ;	0 OR -3 returns 1.
   9678 ;	-3 OR 2	returns 1.
   9679 ;
   9680 ; A binary operation.
   9681 ; On entry HL points to first operand (X) and DE to second operand (Y).
   9682 
   9683 mark_1AED:
   9684 or:
   9685 	LD	A,(DE)		; fetch exponent of second number
   9686 	AND	A		; test it.
   9687 	RET	Z		; return if zero.
   9688 
   9689 	SCF			; set carry flag
   9690 	JR	FP_0_OR_1	; back to FP_0_OR_1 to overwrite the first operand
   9691 				; with the value 1.
   9692 
   9693 
   9694 
   9695 ; Handle number AND number (08)
   9696 
   9697 ; The Boolean AND operator.
   9698 ;
   9699 ; e.g.	-3 AND 2	returns -3.
   9700 ;	-3 AND 0	returns 0.
   9701 ;		0 and -2 returns 0.
   9702 ;		0 and 0	returns 0.
   9703 ;
   9704 ; Compare with OR routine above.
   9705 
   9706 boolean_num_and_num:
   9707 	LD	A,(DE)		; fetch exponent of second number.
   9708 	AND	A		; test it.
   9709 	RET	NZ		; return if not zero.
   9710 
   9711 	JR	FP_0_OR_1	; back to FP_0_OR_1 to overwrite the first operand
   9712 				; with zero for return value.
   9713 
   9714 
   9715 ; Handle string AND number (10)
   9716 
   9717 ; e.g. "YOU WIN" AND SCORE>99 will return the string if condition is true
   9718 ; or the null string if false.
   9719 
   9720 strs_and_num:
   9721 	LD	A,(DE)		; fetch exponent of second number.
   9722 	AND	A		; test it.
   9723 	RET	NZ		; return if number was not zero - the string
   9724 				; is the result.
   9725 
   9726 ; if the number was zero (false) then the null string must be returned by
   9727 ; altering the length of the string on the calculator stack to zero.
   9728 
   9729 	PUSH	DE		; save pointer to the now obsolete number
   9730 				; (which will become the new STKEND)
   9731 
   9732 	DEC	DE		; point to the 5th byte of string descriptor.
   9733 	XOR	A		; clear the accumulator.
   9734 	LD	(DE),A		; place zero in high byte of length.
   9735 	DEC	DE		; address low byte of length.
   9736 	LD	(DE),A		; place zero there - now the null string.
   9737 
   9738 	POP	DE		; restore pointer - new STKEND.
   9739 	RET			; return.
   9740 
   9741 
   9742 ; Perform comparison ($09-$0E, $11-$16)
   9743 
   9744 ; True binary operations.
   9745 ;
   9746 ; A single entry point is used to evaluate six numeric and six string
   9747 ; comparisons. On entry, the calculator literal is in the B register and
   9748 ; the two numeric values, or the two string parameters, are on the
   9749 ; calculator stack.
   9750 ; The individual bits of the literal are manipulated to group similar
   9751 ; operations although the SUB 8 instruction does nothing useful and merely
   9752 ; alters the string test bit.
   9753 ; Numbers are compared by subtracting one from the other, strings are
   9754 ; compared by comparing every character until a mismatch, or the end of one
   9755 ; or both, is reached.
   9756 ;
   9757 ; Numeric Comparisons.
   9758 
   9759 ; The 'x>y' example is the easiest as it employs straight-thru logic.
   9760 ; Number y is subtracted from x and the result tested for greater_0 yielding
   9761 ; a final value 1 (true) or 0 (false).
   9762 ; For 'x<y' the same logic is used but the two values are first swapped on the
   9763 ; calculator stack.
   9764 ; For 'x=y' NOT is applied to the subtraction result yielding true if the
   9765 ; difference was zero and false with anything else.
   9766 ; The first three numeric comparisons are just the opposite of the last three
   9767 ; so the same processing steps are used and then a final NOT is applied.
   9768 ;
   9769 ; literal	Test	No sub 8        ExOrNot  1st RRCA	exch sub	?	End-Tests
   9770 ; =========	====	== ======== === ======== ========	==== ===	=	=== === ===
   9771 ; num_l_eql	x<=y	09 00000001 dec 00000000 00000000	---- x-y	?	--- >0? NOT
   9772 ; num_gr_eql	x>=y	0A 00000010 dec 00000001 10000000c	swap y-x	?	--- >0? NOT
   9773 ; nums_neql	x<>y	0B 00000011 dec 00000010 00000001	---- x-y	?	NOT --- NOT
   9774 ; num_grtr	x>y	0C 00000100 -	00000100 00000010	---- x-y	?	--- >0? ---
   9775 ; num_less	x<y	0D 00000101 -	00000101 10000010c	swap y-x	?	--- >0? ---
   9776 ; nums_eql	x=y	0E 00000110 -	00000110 00000011	---- x-y	?	NOT --- ---
   9777 ;
   9778 ;								comp -> C/F
   9779 ;								====	===
   9780 ; str_l_eql	x$<=y$	11 00001001 dec 00001000 00000100	---- x$y$ 0	!or >0? NOT
   9781 ; str_gr_eql	x$>=y$	12 00001010 dec 00001001 10000100c	swap y$x$ 0	!or >0? NOT
   9782 ; strs_neql	x$<>y$	13 00001011 dec 00001010 00000101	---- x$y$ 0	!or >0? NOT
   9783 ; str_grtr	x$>y$	14 00001100 -	00001100 00000110	---- x$y$ 0	!or >0? ---
   9784 ; str_less	x$<y$	15 00001101 -	00001101 10000110c	swap y$x$ 0	!or >0? ---
   9785 ; strs_eql	x$=y$	16 00001110 -	00001110 00000111	---- x$y$ 0	!or >0? ---
   9786 ;
   9787 ; String comparisons are a little different in that the eql/neql carry flag
   9788 ; from the 2nd RRCA is, as before, fed into the first of the end tests but
   9789 ; along the way it gets modified by the comparison process. The result on the
   9790 ; stack always starts off as zero and the carry fed in determines if NOT is
   9791 ; applied to it. So the only time the greater-0 test is applied is if the
   9792 ; stack holds zero which is not very efficient as the test will always yield
   9793 ; zero. The most likely explanation is that there were once separate end tests
   9794 ; for numbers and strings.
   9795 
   9796 ; $1B03 SAME ADDRESS FOR MULTIPLE ROUTINES ???
   9797 
   9798 num_l_eql:
   9799 num_gr_eql:
   9800 nums_neql:
   9801 num_grtr:
   9802 num_less:
   9803 nums_eql:
   9804 str_l_eql:
   9805 str_gr_eql:
   9806 strs_neql:
   9807 str_grtr:
   9808 str_less:
   9809 strs_eql:
   9810 num_lt_eql:
   9811 if ORIGINAL
   9812 mark_1B03:
   9813 	LD	A,B		; transfer literal to accumulator.
   9814 	SUB	$08		; subtract eight - which is not useful.
   9815 else
   9816 	LD	A,B		; transfer literal to accumulator.
   9817 ;;	SUB	$08		; subtract eight - which is not useful.
   9818 endif
   9819 	BIT	2,A		; isolate '>', '<', '='.
   9820 
   9821 	JR	NZ,EX_OR_NOT	; skip to EX_OR_NOT with these.
   9822 
   9823 	DEC	A		; else make $00-$02, $08-$0A to match bits 0-2.
   9824 
   9825 EX_OR_NOT:
   9826 if ORIGINAL
   9827 mark_1B0B:
   9828 endif
   9829 	RRCA			; the first RRCA sets carry for a swap.
   9830 	JR	NC,NUM_OR_STR	; forward to NUM_OR_STR with other 8 cases
   9831 
   9832 ; for the other 4 cases the two values on the calculator stack are exchanged.
   9833 
   9834 	PUSH	AF		; save A and carry.
   9835 	PUSH	HL		; save HL - pointer to first operand.
   9836 				; (DE points to second operand).
   9837 
   9838 	CALL	exchange		; routine exchange swaps the two values.
   9839 				; (HL = second operand, DE = STKEND)
   9840 
   9841 	POP	DE		; DE = first operand
   9842 	EX	DE,HL		; as we were.
   9843 	POP	AF		; restore A and carry.
   9844 
   9845 ; Note. it would be better if the 2nd RRCA preceded the string test.
   9846 ; It would save two duplicate bytes and if we also got rid of that sub 8
   9847 ; at the beginning we wouldn't have to alter which bit we test.
   9848 
   9849 NUM_OR_STR:
   9850 if ORIGINAL
   9851 mark_1B16:
   9852 
   9853 	BIT	2,A		; test if a string comparison.
   9854 	JR	NZ,STRINGS	; forward to STRINGS if so.
   9855 
   9856 ; continue with numeric comparisons.
   9857 
   9858 	RRCA			; 2nd RRCA causes eql/neql to set carry.
   9859 	PUSH	AF		; save A and carry
   9860 else
   9861 	RRCA			;+ causes 'eql/neql' to set carry.
   9862 	PUSH	AF		;+ save the carry flag.
   9863 
   9864 	BIT	2,A		; test if a string comparison.
   9865 	JR	NZ,STRINGS	; forward to STRINGS if so.
   9866 
   9867 endif
   9868 
   9869 	CALL	SUBTRACT	; leaves result on stack.
   9870 	JR	END_TESTS	; forward to END_TESTS
   9871 
   9872 ; ___
   9873 
   9874 
   9875 STRINGS:
   9876 if ORIGINAL
   9877 mark_1B21:
   9878 	RRCA			; 2nd RRCA causes eql/neql to set carry.
   9879 	PUSH	AF		; save A and carry.
   9880 else
   9881 ;;	RRCA			; 2nd RRCA causes eql/neql to set carry.
   9882 ;;	PUSH	AF		; save A and carry.
   9883 endif
   9884 	CALL	STK_FETCH	; gets 2nd string params
   9885 	PUSH	DE		; save start2 *.
   9886 	PUSH	BC		; and the length.
   9887 
   9888 	CALL	STK_FETCH	; gets 1st string
   9889 				; parameters - start in DE, length in BC.
   9890 	POP	HL		; restore length of second to HL.
   9891 
   9892 ; A loop is now entered to compare, by subtraction, each corresponding character
   9893 ; of the strings. For each successful match, the pointers are incremented and
   9894 ; the lengths decreased and the branch taken back to here. If both string
   9895 ; remainders become null at the same time, then an exact match exists.
   9896 
   9897 if ORIGINAL
   9898 mark_1B2C:
   9899 endif
   9900 BYTE_COMP:
   9901 	LD	A,H		; test if the second string
   9902 	OR	L		; is the null string and hold flags.
   9903 
   9904 	EX	(SP),HL	; put length2 on stack, bring start2 to HL *.
   9905 	LD	A,B		; hi byte of length1 to A
   9906 
   9907 	JR	NZ,SEC_PLUS	; forward to SEC_PLUS if second not null.
   9908 
   9909 	OR	C		; test length of first string.
   9910 
   9911 if ORIGINAL
   9912 mark_1B33:
   9913 endif
   9914 
   9915 SECOND_LOW:
   9916 	POP	BC		; pop the second length off stack.
   9917 	JR	Z,BOTH_NULL	; forward if first string is also
   9918 				; of zero length.
   9919 
   9920 ; the true condition - first is longer than second (SECOND_LESS)
   9921 
   9922 	POP	AF		; restore carry (set if eql/neql)
   9923 	CCF			; complement carry flag.
   9924 				; Note. equality becomes false.
   9925 				; Inequality is true. By swapping or applying
   9926 				; a terminal 'not', all comparisons have been
   9927 				; manipulated so that this is success path.
   9928 	JR	STR_TEST		; forward to leave via STR_TEST
   9929 
   9930 ; ___
   9931 ; the branch was here with a match
   9932 
   9933 if ORIGINAL
   9934 mark_1B3A:
   9935 endif
   9936 
   9937 BOTH_NULL:
   9938 	POP	AF		; restore carry - set for eql/neql
   9939 	JR	STR_TEST		; forward to STR_TEST
   9940 
   9941 ; ___
   9942 ; the branch was here when 2nd string not null and low byte of first is yet
   9943 ; to be tested.
   9944 
   9945 
   9946 mark_1B3D:
   9947 SEC_PLUS:
   9948 	OR	C		; test the length of first string.
   9949 	JR	Z,FRST_LESS	; forward to FRST_LESS if length is zero.
   9950 
   9951 ; both strings have at least one character left.
   9952 
   9953 	LD	A,(DE)		; fetch character of first string.
   9954 	SUB	(HL)		; subtract with that of 2nd string.
   9955 	JR	C,FRST_LESS	; forward to FRST_LESS if carry set
   9956 
   9957 	JR	NZ,SECOND_LOW	; back to SECOND_LOW and then STR_TEST
   9958 				; if not exact match.
   9959 
   9960 	DEC	BC		; decrease length of 1st string.
   9961 	INC	DE		; increment 1st string pointer.
   9962 
   9963 	INC	HL		; increment 2nd string pointer.
   9964 	EX	(SP),HL	; swap with length on stack
   9965 	DEC	HL		; decrement 2nd string length
   9966 	JR	BYTE_COMP		; back to BYTE_COMP
   9967 
   9968 ; ___
   9969 ;	the false condition.
   9970 
   9971 mark_1B4D:
   9972 FRST_LESS:
   9973 	POP	BC		; discard length
   9974 	POP	AF		; pop A
   9975 	AND	A		; clear the carry for false result.
   9976 
   9977 ; ___
   9978 ;	exact match and x$>y$ rejoin here
   9979 
   9980 mark_1B50:
   9981 STR_TEST:
   9982 	PUSH	AF		; save A and carry
   9983 
   9984 	RST	_FP_CALC	;;
   9985 	DEFB	__stk_zero	;;	an initial false value.
   9986 	DEFB	__end_calc	;;
   9987 
   9988 ;	both numeric and string paths converge here.
   9989 
   9990 mark_1B54:
   9991 END_TESTS:
   9992 	POP	AF		; pop carry	- will be set if eql/neql
   9993 	PUSH	AF		; save it again.
   9994 
   9995 	CALL	C,not	; sets true(1) if equal(0)
   9996 				; or, for strings, applies true result.
   9997 	CALL	greater_0		; ??????????
   9998 
   9999 
  10000 	POP	AF		; pop A
  10001 	RRCA			; the third RRCA - test for '<=', '>=' or '<>'.
  10002 	CALL	NC,not	; apply a terminal NOT if so.
  10003 	RET			; return.
  10004 
  10005 ; String concatenation ($17)
  10006 
  10007 ;	This literal combines two strings into one e.g. LET A$ = B$ + C$
  10008 ;	The two parameters of the two strings to be combined are on the stack.
  10009 
  10010 mark_1B62:
  10011 strs_add:
  10012 	CALL	STK_FETCH	; fetches string parameters
  10013 				; and deletes calculator stack entry.
  10014 	PUSH	DE		; save start address.
  10015 	PUSH	BC		; and length.
  10016 
  10017 	CALL	STK_FETCH	; for first string
  10018 	POP	HL		; re-fetch first length
  10019 	PUSH	HL		; and save again
  10020 	PUSH	DE		; save start of second string
  10021 	PUSH	BC		; and its length.
  10022 
  10023 	ADD	HL,BC		; add the two lengths.
  10024 	LD	B,H		; transfer to BC
  10025 	LD	C,L		; and create
  10026 	RST	_BC_SPACES	; BC_SPACES in workspace.
  10027 				; DE points to start of space.
  10028 
  10029 	CALL	STK_STO_STR	; stores parameters
  10030 				; of new string updating STKEND.
  10031 	POP	BC		; length of first
  10032 	POP	HL		; address of start
  10033 
  10034 if ORIGINAL
  10035 	LD	A,B		; test for
  10036 	OR	C		; zero length.
  10037 	JR	Z,OTHER_STR	; to OTHER_STR if null string
  10038 	LDIR			; copy string to workspace.
  10039 else
  10040 	CALL	COND_MV		;+ a conditional (NZ) ldir routine. 
  10041 endif
  10042 
  10043 mark_1B7D:
  10044 OTHER_STR:
  10045 	POP	BC		; now second length
  10046 	POP	HL		; and start of string
  10047 if ORIGINAL
  10048 	LD	A,B		; test this one
  10049 	OR	C		; for zero length
  10050 	JR	Z,STACK_POINTERS	; skip forward to STACK_POINTERS if so as complete.
  10051 
  10052 	LDIR			; else copy the bytes.
  10053 				; and continue into next routine which
  10054 				; sets the calculator stack pointers.
  10055 else
  10056 	CALL	COND_MV		;+ a conditional (NZ) ldir routine. 
  10057 endif
  10058 
  10059 
  10060 ; Check stack pointers
  10061 
  10062 ;	Register DE is set to STKEND and HL, the result pointer, is set to five
  10063 ;	locations below this.
  10064 ;	This routine is used when it is inconvenient to save these values at the
  10065 ;	time the calculator stack is manipulated due to other activity on the
  10066 ;	machine stack.
  10067 ;	This routine is also used to terminate the VAL routine for
  10068 ;	the same reason and to initialize the calculator stack at the start of
  10069 ;	the CALCULATE routine.
  10070 
  10071 mark_1B85:
  10072 STACK_POINTERS:
  10073 	LD	HL,(STKEND)	; fetch STKEND value from system variable.
  10074 	LD	DE,-5
  10075 	PUSH	HL		; push STKEND value.
  10076 
  10077 	ADD	HL,DE		; subtract 5 from HL.
  10078 
  10079 	POP	DE		; pop STKEND to DE.
  10080 	RET			; return.
  10081 
  10082 
  10083 ; Handle CHR$ (2B)
  10084 
  10085 ;	This function returns a single character string that is a result of
  10086 ;	converting a number in the range 0-255 to a string e.g. CHR$ 38 = "A".
  10087 ;	Note. the ZX81 does not have an ASCII character set.
  10088 
  10089 mark_1B8F:
  10090 chr_dollar:
  10091 	CALL	FP_TO_A		; puts the number in A.
  10092 
  10093 	JR	C,REPORT_Bd	; forward if overflow
  10094 	JR	NZ,REPORT_Bd	; forward if negative
  10095 if ORIGINAL
  10096 	PUSH	AF		; save the argument.
  10097 endif
  10098 	LD	BC,1		; one space required.
  10099 	RST	_BC_SPACES	; BC_SPACES makes DE point to start
  10100 if ORIGINAL
  10101 	POP	AF		; restore the number.
  10102 endif
  10103 	LD	(DE),A		; and store in workspace
  10104 
  10105 if ORIGINAL
  10106 	CALL	STK_STO_STR	; stacks descriptor.
  10107 
  10108 	EX	DE,HL		; make HL point to result and DE to STKEND.
  10109 	RET			; return.
  10110 else
  10111 	JR	str_STK	;+ relative jump to similar sequence in str$.
  10112 endif
  10113 ; ___
  10114 
  10115 mark_1BA2:
  10116 REPORT_Bd:
  10117 	RST	_ERROR_1
  10118 	DEFB	$0A		; Error Report: Integer out of range
  10119 
  10120 
  10121 ; Handle VAL ($1A)
  10122 
  10123 ;	VAL treats the characters in a string as a numeric expression.
  10124 ;	e.g. VAL "2.3" = 2.3, VAL "2+4" = 6, VAL ("2" + "4") = 24.
  10125 
  10126 val:
  10127 if ORIGINAL
  10128 mark_1BA4:
  10129 	LD	HL,(CH_ADD)	; fetch value of system variable CH_ADD
  10130 else
  10131 	RST	_GET_CHAR	;+ shorter way to fetch CH_ADD.
  10132 endif
  10133 	PUSH	HL		; and save on the machine stack.
  10134 
  10135 	CALL	STK_FETCH	; fetches the string operand
  10136 				; from calculator stack.
  10137 
  10138 	PUSH	DE		; save the address of the start of the string.
  10139 	INC	BC		; increment the length for a carriage return.
  10140 
  10141 	RST	_BC_SPACES	; BC_SPACES creates the space in workspace.
  10142 	POP	HL		; restore start of string to HL.
  10143 	LD	(CH_ADD),DE	; load CH_ADD with start DE in workspace.
  10144 
  10145 	PUSH	DE		; save the start in workspace
  10146 	LDIR			; copy string from program or variables or
  10147 				; workspace to the workspace area.
  10148 	EX	DE,HL		; end of string + 1 to HL
  10149 	DEC	HL		; decrement HL to point to end of new area.
  10150 	LD	(HL),ZX_NEWLINE	; insert a carriage return at end.
  10151 				; ZX81 has a non-ASCII character set
  10152 	RES	7,(IY+FLAGS-RAMBASE)	; signal checking syntax.
  10153 	CALL	CLASS_6		; evaluates string
  10154 				; expression and checks for integer result.
  10155 
  10156 	CALL	CHECK_2		; checks for carriage return.
  10157 
  10158 
  10159 	POP	HL		; restore start of string in workspace.
  10160 
  10161 	LD	(CH_ADD),HL	; set CH_ADD to the start of the string again.
  10162 	SET	7,(IY+FLAGS-RAMBASE)	; signal running program.
  10163 	CALL	SCANNING	; evaluates the string
  10164 				; in full leaving result on calculator stack.
  10165 
  10166 	POP	HL		; restore saved character address in program.
  10167 	LD	(CH_ADD),HL	; and reset the system variable CH_ADD.
  10168 
  10169 	JR	STACK_POINTERS	; back to exit via STACK_POINTERS.
  10170 				; resetting the calculator stack pointers
  10171 				; HL and DE from STKEND as it wasn't possible
  10172 				; to preserve them during this routine.
  10173 
  10174 
  10175 ; Handle STR$ (2A)
  10176 
  10177 ;	This function returns a string representation of a numeric argument.
  10178 ;	The method used is to trick the PRINT_FP routine into thinking it
  10179 ;	is writing to a collapsed display file when in fact it is writing to
  10180 ;	string workspace.
  10181 ;	If there is already a newline at the intended print position and the
  10182 ;	column count has not been reduced to zero then the print routine
  10183 ;	assumes that there is only 1K of RAM and the screen memory, like the rest
  10184 ;	of dynamic memory, expands as necessary using calls to the ONE_SPACE
  10185 ;	routine. The screen is character-mapped not bit-mapped.
  10186 
  10187 mark_1BD5:
  10188 str_dollar:
  10189 	LD	BC,1		; create an initial byte in workspace
  10190 	RST	_BC_SPACES	; using BC_SPACES restart.
  10191 
  10192 	LD	(HL),ZX_NEWLINE	; place a carriage return there.
  10193 
  10194 	LD	HL,(S_POSN)	; fetch value of S_POSN column/line
  10195 	PUSH	HL		; and preserve on stack.
  10196 
  10197 	LD	L,$FF		; make column value high to create a
  10198 				; contrived buffer of length 254.
  10199 	LD	(S_POSN),HL	; and store in system variable S_POSN.
  10200 
  10201 	LD	HL,(DF_CC)	; fetch value of DF_CC
  10202 	PUSH	HL		; and preserve on stack also.
  10203 
  10204 	LD	(DF_CC),DE	; now set DF_CC which normally addresses
  10205 				; somewhere in the display file to the start
  10206 				; of workspace.
  10207 	PUSH	DE		; save the start of new string.
  10208 
  10209 	CALL	PRINT_FP
  10210 
  10211 	POP	DE		; retrieve start of string.
  10212 
  10213 	LD	HL,(DF_CC)	; fetch end of string from DF_CC.
  10214 	AND	A		; prepare for true subtraction.
  10215 	SBC	HL,DE		; subtract to give length.
  10216 
  10217 	LD	B,H		; and transfer to the BC
  10218 	LD	C,L		; register.
  10219 
  10220 	POP	HL		; restore original
  10221 	LD	(DF_CC),HL	; DF_CC value
  10222 
  10223 	POP	HL		; restore original
  10224 	LD	(S_POSN),HL	; S_POSN values.
  10225 
  10226 if ORIGINAL
  10227 else
  10228 str_STK:			; New entry-point to exploit similarities and save 3 bytes of code.
  10229 endif
  10230 
  10231 	CALL	STK_STO_STR	; stores the string
  10232 				; descriptor on the calculator stack.
  10233 
  10234 	EX	DE,HL		; HL = last value, DE = STKEND.
  10235 	RET			; return.
  10236 
  10237 
  10238 
  10239 ; THE 'CODE' FUNCTION
  10240 
  10241 ; (offset $19: 'code')
  10242 ;	Returns the code of a character or first character of a string
  10243 ;	e.g. CODE "AARDVARK" = 38	(not 65 as the ZX81 does not have an ASCII
  10244 ;	character set).
  10245 
  10246 
  10247 mark_1C06:
  10248 code:
  10249 	CALL	STK_FETCH	; fetch and delete the string parameters.
  10250 				; DE points to the start, BC holds the length.
  10251 	LD	A,B		; test length
  10252 	OR	C		; of the string.
  10253 	JR	Z,STK_CODE	; skip with zero if the null string.
  10254 
  10255 	LD	A,(DE)		; else fetch the first character.
  10256 
  10257 mark_1C0E:
  10258 STK_CODE:
  10259 	JP	STACK_A		; jump back (with memory check)
  10260 
  10261 
  10262 ; THE 'LEN' SUBROUTINE
  10263 
  10264 ; (offset $1b: 'len')
  10265 ;	Returns the length of a string.
  10266 ;	In Sinclair BASIC strings can be more than twenty thousand characters long
  10267 ;	so a sixteen-bit register is required to store the length
  10268 
  10269 mark_1C11:
  10270 len:
  10271 	CALL	STK_FETCH	; fetch and delete the
  10272 				; string parameters from the calculator stack.
  10273 				; register BC now holds the length of string.
  10274 
  10275 	JP	STACK_BC	; jump back to save result on the
  10276 				; calculator stack (with memory check).
  10277 
  10278 
  10279 ; THE 'DECREASE THE COUNTER' SUBROUTINE
  10280 
  10281 ; (offset $31: 'dec_jr_nz')
  10282 ;	The calculator has an instruction that decrements a single-byte
  10283 ;	pseudo-register and makes consequential relative jumps just like
  10284 ;	the Z80's DJNZ instruction.
  10285 
  10286 mark_1C17:
  10287 dec_jr_nz:
  10288 	EXX			; switch in set that addresses code
  10289 
  10290 	PUSH	HL		; save pointer to offset byte
  10291 	LD	HL,BERG		; address BERG in system variables
  10292 	DEC	(HL)		; decrement it
  10293 	POP	HL		; restore pointer
  10294 
  10295 	JR	NZ,JUMP_2	; to JUMP_2 if not zero
  10296 
  10297 	INC	HL		; step past the jump length.
  10298 	EXX			; switch in the main set.
  10299 	RET			; return.
  10300 
  10301 ;	Note. as a general rule the calculator avoids using the IY register
  10302 ;	otherwise the cumbersome 4 instructions in the middle could be replaced by
  10303 ;	dec (iy+$xx) - using three instruction bytes instead of six.
  10304 
  10305 
  10306 
  10307 ; THE 'JUMP' SUBROUTINE
  10308 
  10309 ; (Offset $2F; 'jump')
  10310 ;	This enables the calculator to perform relative jumps just like
  10311 ;	the Z80 chip's JR instruction.
  10312 ;	This is one of the few routines to be polished for the ZX Spectrum.
  10313 ;	See, without looking at the ZX Spectrum ROM, if you can get rid of the
  10314 ;	relative jump.
  10315 
  10316 mark_1C23:
  10317 jump:
  10318 	EXX			;switch in pointer set
  10319 JUMP_2:
  10320 	LD	E,(HL)		; the jump byte 0-127 forward, 128-255 back.
  10321 
  10322 if ORIGINAL
  10323 mark_1C24:
  10324 	XOR	A		; clear accumulator.
  10325 	BIT	7,E		; test if negative jump
  10326 	JR	Z,JUMP_3	; skip, if positive
  10327 	CPL			; else change to $FF.
  10328 else
  10329 				; Note. Elegance from the ZX Spectrum.
  10330 	LD	A,E		;+
  10331 	RLA			;+
  10332 	SBC	A,A		;+
  10333 endif
  10334 
  10335 mark_1C2B:
  10336 JUMP_3:
  10337 	LD	D,A		; transfer to high byte.
  10338 	ADD	HL,DE		; advance calculator pointer forward or back.
  10339 
  10340 	EXX			; switch out pointer set.
  10341 	RET			; return.
  10342 
  10343 
  10344 ; THE 'JUMP ON TRUE' SUBROUTINE
  10345 
  10346 ; (Offset $00; 'jump_true')
  10347 ;	This enables the calculator to perform conditional relative jumps
  10348 ;	dependent on whether the last test gave a true result
  10349 ;	On the ZX81, the exponent will be zero for zero or else $81 for one.
  10350 
  10351 mark_1C2F:
  10352 jump_true:
  10353 	LD	A,(DE)		; collect exponent byte
  10354 
  10355 	AND	A		; is result 0 or 1 ?
  10356 	JR	NZ,jump		; back to JUMP if true (1).
  10357 
  10358 	EXX			; else switch in the pointer set.
  10359 	INC	HL		; step past the jump length.
  10360 	EXX			; switch in the main set.
  10361 	RET			; return.
  10362 
  10363 
  10364 
  10365 ; THE 'MODULUS' SUBROUTINE
  10366 
  10367 ; ( Offset $2E: 'n_mod_m' )
  10368 ; ( i1, i2 -- i3, i4 )
  10369 ;	The subroutine calculate N mod M where M is the positive integer, the
  10370 ;	'last value' on the calculator stack and N is the integer beneath.
  10371 ;	The subroutine returns the integer quotient as the last value and the
  10372 ;	remainder as the value beneath.
  10373 ;	e.g.	17 MOD 3 = 5 remainder 2
  10374 ;	It is invoked during the calculation of a random number and also by
  10375 ;	the PRINT_FP routine.
  10376 
  10377 mark_1C37:
  10378 n_mod_m:
  10379 	RST	_FP_CALC	;;	17, 3.
  10380 	DEFB	__st_mem_0	;;	17, 3.
  10381 	DEFB	__delete	;;	17.
  10382 	DEFB	__duplicate	;;	17, 17.
  10383 	DEFB	__get_mem_0	;;	17, 17, 3.
  10384 	DEFB	__division	;;	17, 17/3.
  10385 	DEFB	__int		;;	17, 5.
  10386 	DEFB	__get_mem_0	;;	17, 5, 3.
  10387 	DEFB	__exchange	;;	17, 3, 5.
  10388 	DEFB	__st_mem_0	;;	17, 3, 5.
  10389 	DEFB	__multiply	;;	17, 15.
  10390 	DEFB	__subtract	;;	2.
  10391 	DEFB	__get_mem_0	;;	2, 5.
  10392 	DEFB	__end_calc	;;	2, 5.
  10393 
  10394 	RET			; return.
  10395 
  10396 
  10397 
  10398 ; THE 'INTEGER' FUNCTION
  10399 
  10400 ; (offset $24: 'int')
  10401 ;	This function returns the integer of x, which is just the same as truncate
  10402 ;	for positive numbers. The truncate literal truncates negative numbers
  10403 ;	upwards so that -3.4 gives -3 whereas the BASIC INT function has to
  10404 ;	truncate negative numbers down so that INT -3.4 is 4.
  10405 ;	It is best to work through using, say, plus or minus 3.4 as examples.
  10406 
  10407 mark_1C46:
  10408 int:
  10409 	RST	_FP_CALC	;;		x.	(= 3.4 or -3.4).
  10410 	DEFB	__duplicate	;;		x, x.
  10411 	DEFB	__less_0	;;		x, (1/0)
  10412 	DEFB	__jump_true	;;		x, (1/0)
  10413 	DEFB	X_NEG - $	;; X_NEG
  10414 
  10415 	DEFB	__truncate	;;		trunc 3.4 = 3.
  10416 	DEFB	__end_calc	;;		3.
  10417 
  10418 	RET			; return with + int x on stack.
  10419 
  10420 
  10421 mark_1C4E:
  10422 X_NEG:
  10423 	DEFB	__duplicate	;;		-3.4, -3.4.
  10424 	DEFB	__truncate	;;		-3.4, -3.
  10425 	DEFB	__st_mem_0	;;		-3.4, -3.
  10426 	DEFB	__subtract	;;		-.4
  10427 	DEFB	__get_mem_0	;;		-.4, -3.
  10428 	DEFB	__exchange	;;		-3, -.4.
  10429 	DEFB	__not		;;			-3, (0).
  10430 	DEFB	__jump_true	;;		-3.
  10431 	DEFB	EXIT - $	;;		-3.
  10432 
  10433 	DEFB	__stk_one	;;		-3, 1.
  10434 	DEFB	__subtract	;;		-4.
  10435 
  10436 mark_1C59:
  10437 EXIT:
  10438 	DEFB	__end_calc	;;		-4.
  10439 
  10440 	RET			; return.
  10441 
  10442 
  10443 
  10444 ; Exponential (23)
  10445 
  10446 ;
  10447 ;
  10448 
  10449 mark_1C5B:
  10450 exp:
  10451 	RST	_FP_CALC	;;
  10452 	DEFB	__stk_data	;;
  10453 	DEFB	$F1		;;Exponent: $81, Bytes: 4
  10454 	DEFB	$38,$AA,$3B,$29 ;;
  10455 	DEFB	__multiply	;;
  10456 	DEFB	__duplicate	;;
  10457 	DEFB	__int		;;
  10458 	DEFB	$C3		;;st_mem_3
  10459 	DEFB	__subtract	;;
  10460 	DEFB	__duplicate	;;
  10461 	DEFB	__addition	;;
  10462 	DEFB	__stk_one	;;
  10463 	DEFB	__subtract	;;
  10464 	DEFB	__series_08	;;
  10465 	DEFB	$13		;;Exponent: $63, Bytes: 1
  10466 	DEFB	$36		;;(+00,+00,+00)
  10467 	DEFB	$58		;;Exponent: $68, Bytes: 2
  10468 	DEFB	$65,$66	;;(+00,+00)
  10469 	DEFB	$9D		;;Exponent: $6D, Bytes: 3
  10470 	DEFB	$78,$65,$40	;;(+00)
  10471 	DEFB	$A2		;;Exponent: $72, Bytes: 3
  10472 	DEFB	$60,$32,$C9	;;(+00)
  10473 	DEFB	$E7		;;Exponent: $77, Bytes: 4
  10474 	DEFB	$21,$F7,$AF,$24 ;;
  10475 	DEFB	$EB		;;Exponent: $7B, Bytes: 4
  10476 	DEFB	$2F,$B0,$B0,$14 ;;
  10477 	DEFB	$EE		;;Exponent: $7E, Bytes: 4
  10478 	DEFB	$7E,$BB,$94,$58 ;;
  10479 	DEFB	$F1		;;Exponent: $81, Bytes: 4
  10480 	DEFB	$3A,$7E,$F8,$CF ;;
  10481 	DEFB	$E3		;;get_mem_3
  10482 	DEFB	__end_calc	;;
  10483 
  10484 	CALL	FP_TO_A
  10485 	JR	NZ,N_NEGTV
  10486 
  10487 	JR	C,REPORT_6b
  10488 
  10489 	ADD	A,(HL)		;
  10490 	JR	NC,RESULT_OK
  10491 
  10492 
  10493 mark_1C99:
  10494 REPORT_6b:
  10495 	RST	_ERROR_1
  10496 	DEFB	$05		; Error Report: Number too big
  10497 
  10498 mark_1C9B:
  10499 N_NEGTV:
  10500 	JR	C,RESULT_ZERO
  10501 
  10502 	SUB	(HL)		;
  10503 	JR	NC,RESULT_ZERO
  10504 
  10505 	NEG			; Negate
  10506 
  10507 mark_1CA2:
  10508 RESULT_OK:
  10509 	LD	(HL),A		;
  10510 	RET			; return.
  10511 
  10512 
  10513 mark_1CA4:
  10514 RESULT_ZERO:
  10515 	RST	_FP_CALC	;;
  10516 	DEFB	__delete	;;
  10517 	DEFB	__stk_zero	;;
  10518 	DEFB	__end_calc	;;
  10519 
  10520 	RET			; return.
  10521 
  10522 
  10523 
  10524 ; THE 'NATURAL LOGARITHM' FUNCTION
  10525 
  10526 ; (offset $22: 'ln')
  10527 ;	Like the ZX81 itself, 'natural' logarithms came from Scotland.
  10528 ;	They were devised in 1614 by well-traveled Scotsman John Napier who noted
  10529 ;	"Nothing doth more molest and hinder calculators than the multiplications,
  10530 ;	divisions, square and cubical extractions of great numbers".
  10531 ;
  10532 ;	Napier's logarithms enabled the above operations to be accomplished by 
  10533 ;	simple addition and subtraction simplifying the navigational and 
  10534 ;	astronomical calculations which beset his age.
  10535 ;	Napier's logarithms were quickly overtaken by logarithms to the base 10
  10536 ;	devised, in conjunction with Napier, by Henry Briggs a Cambridge-educated 
  10537 ;	professor of Geometry at Oxford University. These simplified the layout
  10538 ;	of the tables enabling humans to easily scale calculations.
  10539 ;
  10540 ;	It is only recently with the introduction of pocket calculators and
  10541 ;	computers like the ZX81 that natural logarithms are once more at the fore,
  10542 ;	although some computers retain logarithms to the base ten.
  10543 ;	'Natural' logarithms are powers to the base 'e', which like 'pi' is a 
  10544 ;	naturally occurring number in branches of mathematics.
  10545 ;	Like 'pi' also, 'e' is an irrational number and starts 2.718281828...
  10546 ;
  10547 ;	The tabular use of logarithms was that to multiply two numbers one looked
  10548 ;	up their two logarithms in the tables, added them together and then looked 
  10549 ;	for the result in a table of antilogarithms to give the desired product.
  10550 ;
  10551 ;	The EXP function is the BASIC equivalent of a calculator's 'antiln' function 
  10552 ;	and by picking any two numbers, 1.72 and 6.89 say,
  10553 ;	10 PRINT EXP ( LN 1.72 + LN 6.89 ) 
  10554 ;	will give just the same result as
  10555 ;	20 PRINT 1.72 * 6.89.
  10556 ;	Division is accomplished by subtracting the two logs.
  10557 ;
  10558 ;	Napier also mentioned "square and cubicle extractions". 
  10559 ;	To raise a number to the power 3, find its 'ln', multiply by 3 and find the 
  10560 ;	'antiln'.	e.g. PRINT EXP( LN 4 * 3 )	gives 64.
  10561 ;	Similarly to find the n'th root divide the logarithm by 'n'.
  10562 ;	The ZX81 ROM used PRINT EXP ( LN 9 / 2 ) to find the square root of the 
  10563 ;	number 9. The Napieran square root function is just a special case of 
  10564 ;	the 'to_power' function. A cube root or indeed any root/power would be just
  10565 ;	as simple.
  10566 
  10567 ;	First test that the argument to LN is a positive, non-zero number.
  10568 
  10569 mark_1CA9:
  10570 ln:
  10571 	RST	_FP_CALC	;;
  10572 	DEFB	__duplicate	;;
  10573 	DEFB	__greater_0	;;
  10574 	DEFB	__jump_true	;;
  10575 	DEFB	VALID - $		;;to VALID
  10576 
  10577 	DEFB	__end_calc	;;
  10578 
  10579 
  10580 mark_1CAF:
  10581 REPORT_Ab:
  10582 	RST	_ERROR_1
  10583 	DEFB	$09		; Error Report: Invalid argument
  10584 
  10585 VALID:
  10586 if ORIGINAL
  10587 mark_1CB1:
  10588 	DEFB	__stk_zero	;;		Note. not necessary.
  10589 	DEFB	__delete	;;
  10590 endif
  10591 	DEFB	__end_calc	;;
  10592 	LD	A,(HL)		;
  10593 
  10594 	LD	(HL),$80	;
  10595 	CALL	STACK_A
  10596 
  10597 	RST	_FP_CALC	;;
  10598 	DEFB	__stk_data	;;
  10599 	DEFB	$38		;;Exponent: $88, Bytes: 1
  10600 	DEFB	$00		;;(+00,+00,+00)
  10601 	DEFB	__subtract	;;
  10602 	DEFB	__exchange	;;
  10603 	DEFB	__duplicate	;;
  10604 	DEFB	__stk_data	;;
  10605 	DEFB	$F0		;;Exponent: $80, Bytes: 4
  10606 	DEFB	$4C,$CC,$CC,$CD ;;
  10607 	DEFB	__subtract	;;
  10608 	DEFB	__greater_0	;;
  10609 	DEFB	__jump_true	;;
  10610 	DEFB	GRE_8 - $		;;
  10611 
  10612 	DEFB	__exchange	;;
  10613 	DEFB	__stk_one	;;
  10614 	DEFB	__subtract	;;
  10615 	DEFB	__exchange	;;
  10616 	DEFB	__end_calc	;;
  10617 
  10618 	INC	(HL)		;
  10619 
  10620 	RST	_FP_CALC	;;
  10621 
  10622 mark_1CD2:
  10623 GRE_8:
  10624 	DEFB	__exchange	;;
  10625 	DEFB	__stk_data	;;
  10626 	DEFB	$F0		;;Exponent: $80, Bytes: 4
  10627 	DEFB	$31,$72,$17,$F8 ;;
  10628 	DEFB	__multiply	;;
  10629 	DEFB	__exchange	;;
  10630 	DEFB	__stk_half		;;
  10631 	DEFB	__subtract	;;
  10632 	DEFB	__stk_half		;;
  10633 	DEFB	__subtract	;;
  10634 	DEFB	__duplicate	;;
  10635 	DEFB	__stk_data	;;
  10636 	DEFB	$32		;;Exponent: $82, Bytes: 1
  10637 	DEFB	$20		;;(+00,+00,+00)
  10638 	DEFB	__multiply	;;
  10639 	DEFB	__stk_half		;;
  10640 	DEFB	__subtract	;;
  10641 	DEFB	__series_0C	;;
  10642 	DEFB	$11		;;Exponent: $61, Bytes: 1
  10643 	DEFB	$AC		;;(+00,+00,+00)
  10644 	DEFB	$14		;;Exponent: $64, Bytes: 1
  10645 	DEFB	$09		;;(+00,+00,+00)
  10646 	DEFB	$56		;;Exponent: $66, Bytes: 2
  10647 	DEFB	$DA,$A5		;;(+00,+00)
  10648 	DEFB	$59		;;Exponent: $69, Bytes: 2
  10649 	DEFB	$30,$C5		;;(+00,+00)
  10650 	DEFB	$5C		;;Exponent: $6C, Bytes: 2
  10651 	DEFB	$90,$AA		;;(+00,+00)
  10652 	DEFB	$9E		;;Exponent: $6E, Bytes: 3
  10653 	DEFB	$70,$6F,$61	;;(+00)
  10654 	DEFB	$A1		;;Exponent: $71, Bytes: 3
  10655 	DEFB	$CB,$DA,$96	;;(+00)
  10656 	DEFB	$A4		;;Exponent: $74, Bytes: 3
  10657 	DEFB	$31,$9F,$B4	;;(+00)
  10658 	DEFB	$E7		;;Exponent: $77, Bytes: 4
  10659 	DEFB	$A0,$FE,$5C,$FC ;;
  10660 	DEFB	$EA		;;Exponent: $7A, Bytes: 4
  10661 	DEFB	$1B,$43,$CA,$36 ;;
  10662 	DEFB	$ED		;;Exponent: $7D, Bytes: 4
  10663 	DEFB	$A7,$9C,$7E,$5E ;;
  10664 	DEFB	$F0		;;Exponent: $80, Bytes: 4
  10665 	DEFB	$6E,$23,$80,$93 ;;
  10666 	DEFB	__multiply	;;
  10667 	DEFB	__addition	;;
  10668 	DEFB	__end_calc	;;
  10669 
  10670 	RET			; return.
  10671 
  10672 if ORIGINAL
  10673 else
  10674 ; ------------------------------
  10675 ; THE NEW 'SQUARE ROOT' FUNCTION
  10676 ; ------------------------------
  10677 ; (Offset $25: 'sqr')
  10678 ;	"If I have seen further, it is by standing on the shoulders of giants" -
  10679 ;	Sir Isaac Newton, Cambridge 1676.
  10680 ;	The sqr function has been re-written to use the Newton-Raphson method.
  10681 ;	Joseph Raphson was a student of Sir Isaac Newton at Cambridge University
  10682 ;	and helped publicize his work.
  10683 ;	Although Newton's method is centuries old, this routine, appropriately, is 
  10684 ;	based on a FORTH word written by Steven Vickers in the Jupiter Ace manual.
  10685 ;	Whereas that method uses an initial guess of one, this one manipulates 
  10686 ;	the exponent byte to obtain a better starting guess. 
  10687 ;	First test for zero and return zero, if so, as the result.
  10688 ;	If the argument is negative, then produce an error.
  10689 ;
  10690 sqr:	RST	_FP_CALC	;; 		x
  10691 	DEFB	__st_mem_3	;;		x.	(seed for guess)
  10692 	DEFB	__end_calc	;;		x.
  10693 
  10694 ;	HL now points to exponent of argument on calculator stack.
  10695 
  10696 	LD	A,(HL)		; Test for zero argument
  10697 	AND	A		; 
  10698 
  10699 	RET	Z		; Return with zero on the calculator stack.
  10700 
  10701 ;	Test for a positive argument
  10702 
  10703 	INC	HL		; Address byte with sign bit.
  10704 	BIT	7,(HL)		; Test the bit.
  10705 
  10706 	JR	NZ,REPORT_Ab	; back to REPORT_A 
  10707 				; 'Invalid argument'
  10708  
  10709 ;	This guess is based on a Usenet discussion.
  10710 ;	Halve the exponent to achieve a good guess.(accurate with .25 16 64 etc.)
  10711 
  10712 	LD	HL,$4071	; Address first byte of mem-3
  10713 
  10714 	LD	A,(HL)		; fetch exponent of mem-3
  10715 	XOR	$80		; toggle sign of exponent of mem-3
  10716 	SRA	A		; shift right, bit 7 unchanged.
  10717 	INC	A		;
  10718 	JR	Z,ASIS		; forward with say .25 -> .5
  10719 	JP	P,ASIS		; leave increment if value > .5
  10720 	DEC	A		; restore to shift only.
  10721 ASIS:	XOR	$80		; restore sign.
  10722 	LD	(HL),A	; and put back 'halved' exponent.
  10723 
  10724 ;	Now re-enter the calculator.
  10725 
  10726 	RST	28H		;; FP-CALC		x
  10727 
  10728 SLOOP:	DEFB	__duplicate	;;		x,x.
  10729 	DEFB	__get_mem_3	;;		x,x,guess
  10730 	DEFB	__st_mem_4	;;		x,x,guess
  10731 	DEFB	__division	;;		x,x/guess.
  10732 	DEFB	__get_mem_3	;;		x,x/guess,guess
  10733 	DEFB	__addition	;;		x,x/guess+guess
  10734 	DEFB	__stk_half	;;		x,x/guess+guess,.5
  10735 	DEFB	__multiply	;;		x,(x/guess+guess)*.5
  10736 	DEFB	__st_mem_3	;;		x,newguess
  10737 	DEFB	__get_mem_4	;;		x,newguess,oldguess
  10738 	DEFB	__subtract	;;		x,newguess-oldguess
  10739 	DEFB	__abs		;;		x,difference.
  10740 	DEFB	__greater_0	;;		x,(0/1).
  10741 	DEFB	__jump_true	;;		x.
  10742 
  10743 	DEFB	SLOOP - $	;;		x.
  10744 
  10745 	DEFB	__delete	;;		.
  10746 	DEFB	__get_mem_3	;;		retrieve final guess.
  10747 	DEFB	__end_calc	;;		sqr x.
  10748 
  10749 	RET			; return with square root on stack
  10750 
  10751 ;	or in ZX81 BASIC
  10752 ;
  10753 ;	5 PRINT "NEWTON RAPHSON SQUARE ROOTS"
  10754 ;	10 INPUT "NUMBER ";N
  10755 ;	20 INPUT "GUESS ";G
  10756 ;	30 PRINT " NUMBER "; N ;" GUESS "; G
  10757 ;	40 FOR I = 1 TO 10
  10758 ;	50	LET B = N/G
  10759 ;	60	LET C = B+G
  10760 ;	70	LET G = C/2
  10761 ;	80	PRINT I; " VALUE "; G
  10762 ;	90 NEXT I
  10763 ;	100 PRINT "NAPIER METHOD"; SQR N
  10764 endif
  10765 
  10766 
  10767 ; THE 'TRIGONOMETRIC' FUNCTIONS
  10768 
  10769 ;	Trigonometry is rocket science. It is also used by carpenters and pyramid
  10770 ;	builders. 
  10771 ;	Some uses can be quite abstract but the principles can be seen in simple
  10772 ;	right-angled triangles. Triangles have some special properties -
  10773 ;
  10774 ;	1) The sum of the three angles is always PI radians (180 degrees).
  10775 ;	Very helpful if you know two angles and wish to find the third.
  10776 ;	2) In any right-angled triangle the sum of the squares of the two shorter
  10777 ;	sides is equal to the square of the longest side opposite the right-angle.
  10778 ;	Very useful if you know the length of two sides and wish to know the
  10779 ;	length of the third side.
  10780 ;	3) Functions sine, cosine and tangent enable one to calculate the length 
  10781 ;	of an unknown side when the length of one other side and an angle is 
  10782 ;	known.
  10783 ;	4) Functions arcsin, arccosine and arctan enable one to calculate an unknown
  10784 ;	angle when the length of two of the sides is known.
  10785 
  10786 
  10787 ; THE 'REDUCE ARGUMENT' SUBROUTINE
  10788 
  10789 ; (offset $35: 'get_argt')
  10790 ;
  10791 ;	This routine performs two functions on the angle, in radians, that forms
  10792 ;	the argument to the sine and cosine functions.
  10793 ;	First it ensures that the angle 'wraps round'. That if a ship turns through 
  10794 ;	an angle of, say, 3*PI radians (540 degrees) then the net effect is to turn 
  10795 ;	through an angle of PI radians (180 degrees).
  10796 ;	Secondly it converts the angle in radians to a fraction of a right angle,
  10797 ;	depending within which quadrant the angle lies, with the periodicity 
  10798 ;	resembling that of the desired sine value.
  10799 ;	The result lies in the range -1 to +1.
  10800 ;
  10801 ;			90 deg.
  10802 ; 
  10803 ;			(pi/2)
  10804 ;			II  +1    I
  10805 ;			|
  10806 ;		sin+	|\   |   /|	sin+
  10807 ;		cos-	| \  |	/ |	cos+
  10808 ;		tan-	|  \ | /  |	tan+
  10809 ;			|   \|/)  |
  10810 ;	180 deg. (pi) 0 |----+----|-- 0	(0)	0 degrees
  10811 ;			|   /|\   |
  10812 ;		sin-	|  / | \  |	sin-
  10813 ;		cos-	| /  |  \ |	cos+
  10814 ;		tan+	|/   |   \|	tan-
  10815 ;			|
  10816 ;			III -1	 IV
  10817 ;			(3pi/2)
  10818 ;
  10819 ;			270 deg.
  10820 
  10821 mark_1D18:
  10822 get_argt:
  10823 	RST	_FP_CALC	;;		X.
  10824 	DEFB	__stk_data	;;
  10825 	DEFB	$EE		;;Exponent: $7E, 
  10826 				;;Bytes: 4
  10827 	DEFB	$22,$F9,$83,$6E ;;		X, 1/(2*PI)
  10828 	DEFB	__multiply	;;		X/(2*PI) = fraction
  10829 
  10830 	DEFB	__duplicate	;;
  10831 	DEFB	__stk_half	;;
  10832 	DEFB	__addition	;;
  10833 	DEFB	__int		;;
  10834 
  10835 	DEFB	__subtract	;;	now range -.5 to .5
  10836 
  10837 	DEFB	__duplicate	;;
  10838 	DEFB	__addition	;;	now range -1 to 1.
  10839 	DEFB	__duplicate	;;
  10840 	DEFB	__addition	;;	now range -2 to 2.
  10841 
  10842 ;	quadrant I (0 to +1) and quadrant IV (-1 to 0) are now correct.
  10843 ;	quadrant II ranges +1 to +2.
  10844 ;	quadrant III ranges -2 to -1.
  10845 
  10846 	DEFB	__duplicate	;;	Y, Y.
  10847 	DEFB	__abs		;;	Y, abs(Y).	range 1 to 2
  10848 	DEFB	__stk_one	;;	Y, abs(Y), 1.
  10849 	DEFB	__subtract	;;	Y, abs(Y)-1.	range 0 to 1
  10850 	DEFB	__duplicate	;;	Y, Z, Z.
  10851 	DEFB	__greater_0	;;	Y, Z, (1/0).
  10852 
  10853 	DEFB	__st_mem_0	;;	store as possible sign 
  10854 				;;	for cosine function.
  10855 
  10856 	DEFB	__jump_true	;;
  10857 	DEFB	Z_PLUS - $	;;	with quadrants II and III
  10858 
  10859 ;	else the angle lies in quadrant I or IV and value Y is already correct.
  10860 
  10861 	DEFB	__delete	;;	Y	delete test value.
  10862 	DEFB	__end_calc	;;	Y.
  10863 
  10864 	RET			; return.	with Q1 and Q4 >>>
  10865 
  10866 ;	The branch was here with quadrants II (0 to 1) and III (1 to 0).
  10867 ;	Y will hold -2 to -1 if this is quadrant III.
  10868 
  10869 mark_1D35:
  10870 Z_PLUS:
  10871 	DEFB	__stk_one	;;	Y, Z, 1
  10872 	DEFB	__subtract	;;	Y, Z-1.	Q3 = 0 to -1
  10873 	DEFB	__exchange	;;	Z-1, Y.
  10874 	DEFB	__less_0	;;	Z-1, (1/0).
  10875 	DEFB	__jump_true	;;	Z-1.
  10876 	DEFB	YNEG - $	;; 
  10877 				;;if angle in quadrant III
  10878 
  10879 ;	else angle is within quadrant II (-1 to 0)
  10880 
  10881 	DEFB	__negate	;	range +1 to 0
  10882 
  10883 
  10884 mark_1D3C:
  10885 YNEG:
  10886 	DEFB	__end_calc	;;	quadrants II and III correct.
  10887 
  10888 	RET			; return.
  10889 
  10890 
  10891 
  10892 ; THE 'COSINE' FUNCTION
  10893 
  10894 ; (offset $1D: 'cos')
  10895 ;	Cosines are calculated as the sine of the opposite angle rectifying the 
  10896 ;	sign depending on the quadrant rules. 
  10897 ;
  10898 ;
  10899 ;	    /|
  10900 ;	 h /y|
  10901 ;	  /  |o
  10902 ;	 / x |
  10903 ;	/----|
  10904 ;	  a
  10905 ;
  10906 ;	The cosine of angle x is the adjacent side (a) divided by the hypotenuse 1.
  10907 ;	However if we examine angle y then a/h is the sine of that angle.
  10908 ;	Since angle x plus angle y equals a right-angle, we can find angle y by 
  10909 ;	subtracting angle x from pi/2.
  10910 ;	However it's just as easy to reduce the argument first and subtract the
  10911 ;	reduced argument from the value 1 (a reduced right-angle).
  10912 ;	It's even easier to subtract 1 from the angle and rectify the sign.
  10913 ;	In fact, after reducing the argument, the absolute value of the argument
  10914 ;	is used and rectified using the test result stored in mem-0 by 'get-argt'
  10915 ;	for that purpose.
  10916 
  10917 mark_1D3E:
  10918 cos:
  10919 	RST	_FP_CALC	;;	angle in radians.
  10920 	DEFB	__get_argt	;;	X	reduce -1 to +1
  10921 
  10922 	DEFB	__abs		;;	ABS X	0 to 1
  10923 	DEFB	__stk_one	;;	ABS X, 1.
  10924 	DEFB	__subtract	;;		now opposite angle 
  10925 				;;		though negative sign.
  10926 	DEFB	__get_mem_0	;;		fetch sign indicator.
  10927 	DEFB	__jump_true	;;
  10928 	DEFB	C_ENT - $	;;fwd to C_ENT
  10929 				;;forward to common code if in QII or QIII 
  10930 
  10931 
  10932 	DEFB	__negate	;;		else make positive.
  10933 	DEFB	__jump		;;
  10934 	DEFB	C_ENT - $	;;fwd to C_ENT
  10935 				;;with quadrants QI and QIV 
  10936 
  10937 
  10938 ; THE 'SINE' FUNCTION
  10939 
  10940 ; (offset $1C: 'sin')
  10941 ;	This is a fundamental transcendental function from which others such as cos
  10942 ;	and tan are directly, or indirectly, derived.
  10943 ;	It uses the series generator to produce Chebyshev polynomials.
  10944 ;
  10945 ;
  10946 ;	    /|
  10947 ;	 1 / |
  10948 ;	  /  |x
  10949 ;	 /a  |
  10950 ;	/----|
  10951 ;	  y
  10952 ;
  10953 ;	The 'get-argt' function is designed to modify the angle and its sign 
  10954 ;	in line with the desired sine value and afterwards it can launch straight
  10955 ;	into common code.
  10956 
  10957 mark_1D49:
  10958 sin:
  10959 	RST	_FP_CALC	;;	angle in radians
  10960 	DEFB	__get_argt	;;	reduce - sign now correct.
  10961 
  10962 mark_1D4B:
  10963 C_ENT:
  10964 	DEFB	__duplicate	;;
  10965 	DEFB	__duplicate	;;
  10966 	DEFB	__multiply	;;
  10967 	DEFB	__duplicate	;;
  10968 	DEFB	__addition	;;
  10969 	DEFB	__stk_one	;;
  10970 	DEFB	__subtract	;;
  10971 
  10972 	DEFB	__series_06	;;
  10973 	DEFB	$14		;;Exponent: $64, Bytes: 1
  10974 	DEFB	$E6		;;(+00,+00,+00)
  10975 	DEFB	$5C		;;Exponent: $6C, Bytes: 2
  10976 	DEFB	$1F,$0B		;;(+00,+00)
  10977 	DEFB	$A3		;;Exponent: $73, Bytes: 3
  10978 	DEFB	$8F,$38,$EE	;;(+00)
  10979 	DEFB	$E9		;;Exponent: $79, Bytes: 4
  10980 	DEFB	$15,$63,$BB,$23 ;;
  10981 	DEFB	$EE		;;Exponent: $7E, Bytes: 4
  10982 	DEFB	$92,$0D,$CD,$ED ;;
  10983 	DEFB	$F1		;;Exponent: $81, Bytes: 4
  10984 	DEFB	$23,$5D,$1B,$EA ;;
  10985 
  10986 	DEFB	__multiply	;;
  10987 	DEFB	__end_calc	;;
  10988 
  10989 	RET			; return.
  10990 
  10991 
  10992 
  10993 ; THE 'TANGENT' FUNCTION
  10994 
  10995 ; (offset $1E: 'tan')
  10996 ;
  10997 ;	Evaluates tangent x as	sin(x) / cos(x).
  10998 ;
  10999 ;
  11000 ;	    /|
  11001 ;	 h / |
  11002 ;	  /  |o
  11003 ;	 /x  |
  11004 ;	/----|
  11005 ;	   a
  11006 ;
  11007 ;	The tangent of angle x is the ratio of the length of the opposite side 
  11008 ;	divided by the length of the adjacent side. As the opposite length can 
  11009 ;	be calculates using sin(x) and the adjacent length using cos(x) then 
  11010 ;	the tangent can be defined in terms of the previous two functions.
  11011 
  11012 ;	Error 6 if the argument, in radians, is too close to one like pi/2
  11013 ;	which has an infinite tangent. e.g. PRINT TAN (PI/2)	evaluates as 1/0.
  11014 ;	Similarly PRINT TAN (3*PI/2), TAN (5*PI/2) etc.
  11015 
  11016 mark_1D6E:
  11017 tan:
  11018 	RST	_FP_CALC	;;	x.
  11019 	DEFB	__duplicate	;;	x, x.
  11020 	DEFB	__sin		;;	x, sin x.
  11021 	DEFB	__exchange	;;	sin x, x.
  11022 	DEFB	__cos		;;	sin x, cos x.
  11023 	DEFB	__division	;;	sin x/cos x (= tan x).
  11024 	DEFB	__end_calc	;;	tan x.
  11025 
  11026 	RET			; return.
  11027 
  11028 
  11029 ; THE 'ARCTAN' FUNCTION
  11030 
  11031 ; (Offset $21: 'atn')
  11032 ;	The inverse tangent function with the result in radians.
  11033 ;	This is a fundamental transcendental function from which others such as
  11034 ;	asn and acs are directly, or indirectly, derived.
  11035 ;	It uses the series generator to produce Chebyshev polynomials.
  11036 
  11037 mark_1D76:
  11038 atn:
  11039 	LD	A,(HL)		; fetch exponent
  11040 	CP	$81		; compare to that for 'one'
  11041 	JR	C,SMALL	; forward, if less
  11042 
  11043 	RST	_FP_CALC	;;		X.
  11044 	DEFB	__stk_one	;;
  11045 	DEFB	__negate	;;
  11046 	DEFB	__exchange	;;
  11047 	DEFB	__division	;;
  11048 	DEFB	__duplicate	;;
  11049 	DEFB	__less_0	;;
  11050 	DEFB	__stk_half_pi	;;
  11051 	DEFB	__exchange	;;
  11052 	DEFB	__jump_true	;;
  11053 	DEFB	CASES - $	;;
  11054 
  11055 	DEFB	__negate	;;
  11056 	DEFB	__jump		;;
  11057 	DEFB	CASES - $	;;
  11058 
  11059 ; ___
  11060 
  11061 mark_1D89:
  11062 SMALL:
  11063 	RST	_FP_CALC	;;
  11064 	DEFB	__stk_zero	;;
  11065 
  11066 mark_1D8B:
  11067 CASES:
  11068 	DEFB	__exchange	;;
  11069 	DEFB	__duplicate	;;
  11070 	DEFB	__duplicate	;;
  11071 	DEFB	__multiply	;;
  11072 	DEFB	__duplicate	;;
  11073 	DEFB	__addition	;;
  11074 	DEFB	__stk_one	;;
  11075 	DEFB	__subtract	;;
  11076 
  11077 	DEFB	__series_0C	;;
  11078 	DEFB	$10		;;Exponent: $60, Bytes: 1
  11079 	DEFB	$B2		;;(+00,+00,+00)
  11080 	DEFB	$13		;;Exponent: $63, Bytes: 1
  11081 	DEFB	$0E		;;(+00,+00,+00)
  11082 	DEFB	$55		;;Exponent: $65, Bytes: 2
  11083 	DEFB	$E4,$8D		;;(+00,+00)
  11084 	DEFB	$58		;;Exponent: $68, Bytes: 2
  11085 	DEFB	$39,$BC		;;(+00,+00)
  11086 	DEFB	$5B		;;Exponent: $6B, Bytes: 2
  11087 	DEFB	$98,$FD		;;(+00,+00)
  11088 	DEFB	$9E		;;Exponent: $6E, Bytes: 3
  11089 	DEFB	$00,$36,$75	;;(+00)
  11090 	DEFB	$A0		;;Exponent: $70, Bytes: 3
  11091 	DEFB	$DB,$E8,$B4	;;(+00)
  11092 	DEFB	$63		;;Exponent: $73, Bytes: 2
  11093 	DEFB	$42,$C4		;;(+00,+00)
  11094 	DEFB	$E6		;;Exponent: $76, Bytes: 4
  11095 	DEFB	$B5,$09,$36,$BE ;;
  11096 	DEFB	$E9		;;Exponent: $79, Bytes: 4
  11097 	DEFB	$36,$73,$1B,$5D ;;
  11098 	DEFB	$EC		;;Exponent: $7C, Bytes: 4
  11099 	DEFB	$D8,$DE,$63,$BE ;;
  11100 	DEFB	$F0		;;Exponent: $80, Bytes: 4
  11101 	DEFB	$61,$A1,$B3,$0C ;;
  11102 
  11103 	DEFB	__multiply	;;
  11104 	DEFB	__addition	;;
  11105 	DEFB	__end_calc	;;
  11106 
  11107 	RET			; return.
  11108 
  11109 
  11110 
  11111 ; THE 'ARCSIN' FUNCTION
  11112 
  11113 ; (Offset $1F: 'asn')
  11114 ;	The inverse sine function with result in radians.
  11115 ;	Derived from arctan function above.
  11116 ;	Error A unless the argument is between -1 and +1 inclusive.
  11117 ;	Uses an adaptation of the formula asn(x) = atn(x/sqr(1-x*x))
  11118 ;
  11119 ;
  11120 ;		    /|
  11121 ;		   / |
  11122 ;		 1/  |x
  11123 ;		 /a  |
  11124 ;		/----|
  11125 ;		  y
  11126 ;
  11127 ;	e.g. We know the opposite side (x) and hypotenuse (1) 
  11128 ;	and we wish to find angle a in radians.
  11129 ;	We can derive length y by Pythagoras and then use ATN instead. 
  11130 ;	Since y*y + x*x = 1*1 (Pythagoras Theorem) then
  11131 ;	y=sqr(1-x*x)			- no need to multiply 1 by itself.
  11132 ;	So, asn(a) = atn(x/y)
  11133 ;	or more fully,
  11134 ;	asn(a) = atn(x/sqr(1-x*x))
  11135 
  11136 ;	Close but no cigar.
  11137 
  11138 ;	While PRINT ATN (x/SQR (1-x*x)) gives the same results as PRINT ASN x,
  11139 ;	it leads to division by zero when x is 1 or -1.
  11140 ;	To overcome this, 1 is added to y giving half the required angle and the 
  11141 ;	result is then doubled. 
  11142 ;	That is, PRINT ATN (x/(SQR (1-x*x) +1)) *2
  11143 ;
  11144 ;
  11145 ;	.            /|
  11146 ;	.          c/ |
  11147 ;	.          /1 |x
  11148 ;	. c	b /a  |
  11149 ;	---------/----|
  11150 ;	1	y
  11151 ;
  11152 ;	By creating an isosceles triangle with two equal sides of 1, angles c and 
  11153 ;	c are also equal. If b+c+d = 180 degrees and b+a = 180 degrees then c=a/2.
  11154 ;
  11155 ;	A value higher than 1 gives the required error as attempting to find	the
  11156 ;	square root of a negative number generates an error in Sinclair BASIC.
  11157 
  11158 mark_1DC4:
  11159 asn:
  11160 	RST	_FP_CALC	;;	x.
  11161 	DEFB	__duplicate	;;	x, x.
  11162 	DEFB	__duplicate	;;	x, x, x.
  11163 	DEFB	__multiply	;;	x, x*x.
  11164 	DEFB	__stk_one	;;	x, x*x, 1.
  11165 	DEFB	__subtract	;;	x, x*x-1.
  11166 	DEFB	__negate	;;	x, 1-x*x.
  11167 	DEFB	__sqr		;;	x, sqr(1-x*x) = y.
  11168 	DEFB	__stk_one	;;	x, y, 1.
  11169 	DEFB	__addition	;;	x, y+1.
  11170 	DEFB	__division	;;	x/y+1.
  11171 	DEFB	__atn		;;	a/2	(half the angle)
  11172 	DEFB	__duplicate	;;	a/2, a/2.
  11173 	DEFB	__addition	;;	a.
  11174 	DEFB	__end_calc	;;	a.
  11175 
  11176 	RET			; return.
  11177 
  11178 
  11179 
  11180 ; THE 'ARCCOS' FUNCTION
  11181 
  11182 ; (Offset $20: 'acs')
  11183 ;	The inverse cosine function with the result in radians.
  11184 ;	Error A unless the argument is between -1 and +1.
  11185 ;	Result in range 0 to pi.
  11186 ;	Derived from asn above which is in turn derived from the preceding atn. It 
  11187 ;	could have been derived directly from atn using acs(x) = atn(sqr(1-x*x)/x).
  11188 ;	However, as sine and cosine are horizontal translations of each other,
  11189 ;	uses acs(x) = pi/2 - asn(x)
  11190 
  11191 ;	e.g. the arccosine of a known x value will give the required angle b in 
  11192 ;	radians.
  11193 ;	We know, from above, how to calculate the angle a using asn(x). 
  11194 ;	Since the three angles of any triangle add up to 180 degrees, or pi radians,
  11195 ;	and the largest angle in this case is a right-angle (pi/2 radians), then
  11196 ;	we can calculate angle b as pi/2 (both angles) minus asn(x) (angle a).
  11197 ; 
  11198 ;;
  11199 ;	    /|
  11200 ;	 1 /b|
  11201 ;	  /  |x
  11202 ;	 /a  |
  11203 ;	/----|
  11204 ;	  y
  11205 
  11206 mark_1DD4:
  11207 acs:
  11208 	RST	_FP_CALC	;;	x.
  11209 	DEFB	__asn		;;	asn(x).
  11210 	DEFB	__stk_half_pi	;;	asn(x), pi/2.
  11211 	DEFB	__subtract	;;	asn(x) - pi/2.
  11212 	DEFB	__negate	;;	pi/2 - asn(x) = acs(x).
  11213 	DEFB	__end_calc	;;	acs(x)
  11214 
  11215 	RET			; return.
  11216 
  11217 if ORIGINAL
  11218 
  11219 ; THE 'SQUARE ROOT' FUNCTION
  11220 
  11221 ; (Offset $25: 'sqr')
  11222 ;	Error A if argument is negative.
  11223 ;	This routine is remarkable for its brevity - 7 bytes.
  11224 ;
  11225 ;	The ZX81 code was originally 9K and various techniques had to be
  11226 ;	used to shoe-horn it into an 8K Rom chip.
  11227 
  11228 ; This routine uses Napier's method for calculating square roots which was 
  11229 ; devised in 1614 and calculates the value as EXP (LN 'x' * 0.5).
  11230 ;
  11231 ; This is a little on the slow side as it involves two polynomial series.
  11232 ; A series of 12 for LN and a series of 8 for EXP.
  11233 ; This was of no concern to John Napier since his tables were 'compiled forever'.
  11234 
  11235 mark_1DDB:
  11236 sqr:
  11237 	RST	_FP_CALC	;;	x.
  11238 	DEFB	__duplicate	;;	x, x.
  11239 	DEFB	__not		;;	x, 1/0
  11240 	DEFB	__jump_true	;;	x, (1/0).
  11241 	DEFB	LAST - $	;; exit if argument zero
  11242 				;;		with zero result.
  11243 
  11244 ;	else continue to calculate as x ** .5
  11245 
  11246 	DEFB	__stk_half	;;	x, .5.
  11247 	DEFB	__end_calc	;;	x, .5.
  11248 
  11249 endif
  11250 
  11251 
  11252 ; THE 'EXPONENTIATION' OPERATION
  11253 
  11254 ; (Offset $06: 'to_power')
  11255 ;	This raises the first number X to the power of the second number Y.
  11256 ;	As with the ZX80,
  11257 ;	0 ** 0 = 1
  11258 ;	0 ** +n = 0
  11259 ;	0 ** -n = arithmetic overflow.
  11260 
  11261 mark_1DE2:
  11262 to_power:
  11263 	RST	_FP_CALC	;;	X,Y.
  11264 	DEFB	__exchange	;;	Y,X.
  11265 	DEFB	__duplicate	;;	Y,X,X.
  11266 	DEFB	__not		;;	Y,X,(1/0).
  11267 	DEFB	__jump_true	;;
  11268 	DEFB	XISO - $	;;forward to XISO if X is zero.
  11269 
  11270 ;	else X is non-zero. function 'ln' will catch a negative value of X.
  11271 
  11272 	DEFB	__ln		;;	Y, LN X.
  11273 	DEFB	__multiply	;;	Y * LN X
  11274 	DEFB	__end_calc	;;
  11275 
  11276 	JP	exp		; jump back to EXP routine.	->
  11277 
  11278 ; ___
  11279 
  11280 ;	These routines form the three simple results when the number is zero.
  11281 ;	begin by deleting the known zero to leave Y the power factor.
  11282 
  11283 mark_1DEE:
  11284 XISO:
  11285 	DEFB	__delete	;;	Y.
  11286 	DEFB	__duplicate	;;	Y, Y.
  11287 	DEFB	__not		;;	Y, (1/0).
  11288 	DEFB	__jump_true	;;
  11289 	DEFB	ONE - $		;; if Y is zero.
  11290 
  11291 ;	the power factor is not zero. If negative then an error exists.
  11292 
  11293 	DEFB	__stk_zero	;;	Y, 0.
  11294 	DEFB	__exchange	;;	0, Y.
  11295 	DEFB	__greater_0	;;	0, (1/0).
  11296 	DEFB	__jump_true	;;	0
  11297 	DEFB	LAST - $	;; if Y was any positive 
  11298 				;; number.
  11299 
  11300 ;	else force division by zero thereby raising an Arithmetic overflow error.
  11301 ;	There are some one and two-byte alternatives but perhaps the most formal
  11302 ;	might have been to use end_calc; rst 08; defb 05.
  11303 
  11304 ;	if ORIGINAL
  11305 
  11306 ; the SG ROM seems to want it the old way!
  11307 if 1
  11308 	DEFB	__stk_one	;;	0, 1.
  11309 	DEFB	__exchange	;;	1, 0.
  11310 	DEFB	__division	;;	1/0	>> error 
  11311 else
  11312 	DEFB	$34		;+ end-calc
  11313 REPORT_6c
  11314 	RST	08H		;+ ERROR-1
  11315 	DEFB	$05		;+ Error Report: Number too big
  11316 endif
  11317 
  11318 
  11319 ; ___
  11320 
  11321 mark_1DFB:
  11322 ONE:
  11323 	DEFB	__delete	;;	.
  11324 	DEFB	__stk_one	;;	1.
  11325 
  11326 mark_1DFD:
  11327 LAST:
  11328 	DEFB	__end_calc	;;		last value 1 or 0.
  11329 
  11330 	RET			; return.
  11331 
  11332 
  11333 ; THE 'SPARE LOCATIONS'
  11334 
  11335 SPARE:
  11336 
  11337 if ORIGINAL
  11338 mark_1DFF:
  11339 	DEFB	$FF		; That's all folks.
  11340 else
  11341 mark_1DFE:
  11342 L1DFE:
  11343 
  11344 ;;	DEFB	$FF, $FF	; Two spare bytes.
  11345 	DEFB	$00, $00	; Two spare bytes (as per the Shoulders of Giants ROM)
  11346 endif
  11347 
  11348 
  11349 
  11350 ; THE 'ZX81 CHARACTER SET'
  11351 
  11352 
  11353 mark_1E00:
  11354 char_set:	; - begins with space character.
  11355 
  11356 ; $00 - Character: ' '		CHR$(0)
  11357 
  11358 	DEFB	%00000000
  11359 	DEFB	%00000000
  11360 	DEFB	%00000000
  11361 	DEFB	%00000000
  11362 	DEFB	%00000000
  11363 	DEFB	%00000000
  11364 	DEFB	%00000000
  11365 	DEFB	%00000000
  11366 
  11367 ; $01 - Character: mosaic	CHR$(1)
  11368 
  11369 	DEFB	%11110000
  11370 	DEFB	%11110000
  11371 	DEFB	%11110000
  11372 	DEFB	%11110000
  11373 	DEFB	%00000000
  11374 	DEFB	%00000000
  11375 	DEFB	%00000000
  11376 	DEFB	%00000000
  11377 
  11378 
  11379 ; $02 - Character: mosaic	CHR$(2)
  11380 
  11381 	DEFB	%00001111
  11382 	DEFB	%00001111
  11383 	DEFB	%00001111
  11384 	DEFB	%00001111
  11385 	DEFB	%00000000
  11386 	DEFB	%00000000
  11387 	DEFB	%00000000
  11388 	DEFB	%00000000
  11389 
  11390 
  11391 ; $03 - Character: mosaic	CHR$(3)
  11392 
  11393 	DEFB	%11111111
  11394 	DEFB	%11111111
  11395 	DEFB	%11111111
  11396 	DEFB	%11111111
  11397 	DEFB	%00000000
  11398 	DEFB	%00000000
  11399 	DEFB	%00000000
  11400 	DEFB	%00000000
  11401 
  11402 ; $04 - Character: mosaic	CHR$(4)
  11403 
  11404 	DEFB	%00000000
  11405 	DEFB	%00000000
  11406 	DEFB	%00000000
  11407 	DEFB	%00000000
  11408 	DEFB	%11110000
  11409 	DEFB	%11110000
  11410 	DEFB	%11110000
  11411 	DEFB	%11110000
  11412 
  11413 ; $05 - Character: mosaic	CHR$(5)
  11414 
  11415 	DEFB	%11110000
  11416 	DEFB	%11110000
  11417 	DEFB	%11110000
  11418 	DEFB	%11110000
  11419 	DEFB	%11110000
  11420 	DEFB	%11110000
  11421 	DEFB	%11110000
  11422 	DEFB	%11110000
  11423 
  11424 ; $06 - Character: mosaic	CHR$(6)
  11425 
  11426 	DEFB	%00001111
  11427 	DEFB	%00001111
  11428 	DEFB	%00001111
  11429 	DEFB	%00001111
  11430 	DEFB	%11110000
  11431 	DEFB	%11110000
  11432 	DEFB	%11110000
  11433 	DEFB	%11110000
  11434 
  11435 ; $07 - Character: mosaic	CHR$(7)
  11436 
  11437 	DEFB	%11111111
  11438 	DEFB	%11111111
  11439 	DEFB	%11111111
  11440 	DEFB	%11111111
  11441 	DEFB	%11110000
  11442 	DEFB	%11110000
  11443 	DEFB	%11110000
  11444 	DEFB	%11110000
  11445 
  11446 ; $08 - Character: mosaic	CHR$(8)
  11447 
  11448 	DEFB	%10101010
  11449 	DEFB	%01010101
  11450 	DEFB	%10101010
  11451 	DEFB	%01010101
  11452 	DEFB	%10101010
  11453 	DEFB	%01010101
  11454 	DEFB	%10101010
  11455 	DEFB	%01010101
  11456 ; $09 - Character: mosaic	CHR$(9)
  11457 
  11458 	DEFB	%00000000
  11459 	DEFB	%00000000
  11460 	DEFB	%00000000
  11461 	DEFB	%00000000
  11462 	DEFB	%10101010
  11463 	DEFB	%01010101
  11464 	DEFB	%10101010
  11465 	DEFB	%01010101
  11466 ; $0A - Character: mosaic	CHR$(10)
  11467 
  11468 	DEFB	%10101010
  11469 	DEFB	%01010101
  11470 	DEFB	%10101010
  11471 	DEFB	%01010101
  11472 	DEFB	%00000000
  11473 	DEFB	%00000000
  11474 	DEFB	%00000000
  11475 	DEFB	%00000000
  11476 
  11477 ; $0B - Character: '"'		CHR$(11)
  11478 
  11479 	DEFB	%00000000
  11480 	DEFB	%00100100
  11481 	DEFB	%00100100
  11482 	DEFB	%00000000
  11483 	DEFB	%00000000
  11484 	DEFB	%00000000
  11485 	DEFB	%00000000
  11486 	DEFB	%00000000
  11487 
  11488 ; $0C - Character:	�		CHR$(12)
  11489 
  11490 	DEFB	%00000000
  11491 	DEFB	%00011100
  11492 	DEFB	%00100010
  11493 	DEFB	%01111000
  11494 	DEFB	%00100000
  11495 	DEFB	%00100000
  11496 	DEFB	%01111110
  11497 	DEFB	%00000000
  11498 
  11499 ; $0D - Character: '$'		CHR$(13)
  11500 
  11501 	DEFB	%00000000
  11502 	DEFB	%00001000
  11503 	DEFB	%00111110
  11504 	DEFB	%00101000
  11505 	DEFB	%00111110
  11506 	DEFB	%00001010
  11507 	DEFB	%00111110
  11508 	DEFB	%00001000
  11509 
  11510 ; $0E - Character: ':'		CHR$(14)
  11511 
  11512 	DEFB	%00000000
  11513 	DEFB	%00000000
  11514 	DEFB	%00000000
  11515 	DEFB	%00010000
  11516 	DEFB	%00000000
  11517 	DEFB	%00000000
  11518 	DEFB	%00010000
  11519 	DEFB	%00000000
  11520 
  11521 ; $0F - Character: '?'		CHR$(15)
  11522 
  11523 	DEFB	%00000000
  11524 	DEFB	%00111100
  11525 	DEFB	%01000010
  11526 	DEFB	%00000100
  11527 	DEFB	%00001000
  11528 	DEFB	%00000000
  11529 	DEFB	%00001000
  11530 	DEFB	%00000000
  11531 
  11532 ; $10 - Character: '('		CHR$(16)
  11533 
  11534 	DEFB	%00000000
  11535 	DEFB	%00000100
  11536 	DEFB	%00001000
  11537 	DEFB	%00001000
  11538 	DEFB	%00001000
  11539 	DEFB	%00001000
  11540 	DEFB	%00000100
  11541 	DEFB	%00000000
  11542 
  11543 ; $11 - Character: ')'		CHR$(17)
  11544 
  11545 	DEFB	%00000000
  11546 	DEFB	%00100000
  11547 	DEFB	%00010000
  11548 	DEFB	%00010000
  11549 	DEFB	%00010000
  11550 	DEFB	%00010000
  11551 	DEFB	%00100000
  11552 	DEFB	%00000000
  11553 
  11554 ; $12 - Character: '>'		CHR$(18)
  11555 
  11556 	DEFB	%00000000
  11557 	DEFB	%00000000
  11558 	DEFB	%00010000
  11559 	DEFB	%00001000
  11560 	DEFB	%00000100
  11561 	DEFB	%00001000
  11562 	DEFB	%00010000
  11563 	DEFB	%00000000
  11564 
  11565 ; $13 - Character: '<'		CHR$(19)
  11566 
  11567 	DEFB	%00000000
  11568 	DEFB	%00000000
  11569 	DEFB	%00000100
  11570 	DEFB	%00001000
  11571 	DEFB	%00010000
  11572 	DEFB	%00001000
  11573 	DEFB	%00000100
  11574 	DEFB	%00000000
  11575 
  11576 ; $14 - Character: '='		CHR$(20)
  11577 
  11578 	DEFB	%00000000
  11579 	DEFB	%00000000
  11580 	DEFB	%00000000
  11581 	DEFB	%00111110
  11582 	DEFB	%00000000
  11583 	DEFB	%00111110
  11584 	DEFB	%00000000
  11585 	DEFB	%00000000
  11586 
  11587 ; $15 - Character: '+'		CHR$(21)
  11588 
  11589 	DEFB	%00000000
  11590 	DEFB	%00000000
  11591 	DEFB	%00001000
  11592 	DEFB	%00001000
  11593 	DEFB	%00111110
  11594 	DEFB	%00001000
  11595 	DEFB	%00001000
  11596 	DEFB	%00000000
  11597 
  11598 ; $16 - Character: '-'		CHR$(22)
  11599 
  11600 	DEFB	%00000000
  11601 	DEFB	%00000000
  11602 	DEFB	%00000000
  11603 	DEFB	%00000000
  11604 	DEFB	%00111110
  11605 	DEFB	%00000000
  11606 	DEFB	%00000000
  11607 	DEFB	%00000000
  11608 
  11609 ; $17 - Character: '*'		CHR$(23)
  11610 
  11611 	DEFB	%00000000
  11612 	DEFB	%00000000
  11613 	DEFB	%00010100
  11614 	DEFB	%00001000
  11615 	DEFB	%00111110
  11616 	DEFB	%00001000
  11617 	DEFB	%00010100
  11618 	DEFB	%00000000
  11619 
  11620 ; $18 - Character: '/'		CHR$(24)
  11621 
  11622 	DEFB	%00000000
  11623 	DEFB	%00000000
  11624 	DEFB	%00000010
  11625 	DEFB	%00000100
  11626 	DEFB	%00001000
  11627 	DEFB	%00010000
  11628 	DEFB	%00100000
  11629 	DEFB	%00000000
  11630 
  11631 ; $19 - Character: ';'		CHR$(25)
  11632 
  11633 	DEFB	%00000000
  11634 	DEFB	%00000000
  11635 	DEFB	%00010000
  11636 	DEFB	%00000000
  11637 	DEFB	%00000000
  11638 	DEFB	%00010000
  11639 	DEFB	%00010000
  11640 	DEFB	%00100000
  11641 
  11642 ; $1A - Character: ','		CHR$(26)
  11643 
  11644 	DEFB	%00000000
  11645 	DEFB	%00000000
  11646 	DEFB	%00000000
  11647 	DEFB	%00000000
  11648 	DEFB	%00000000
  11649 	DEFB	%00001000
  11650 	DEFB	%00001000
  11651 	DEFB	%00010000
  11652 
  11653 ; $1B - Character: '"'		CHR$(27)
  11654 
  11655 	DEFB	%00000000
  11656 	DEFB	%00000000
  11657 	DEFB	%00000000
  11658 	DEFB	%00000000
  11659 	DEFB	%00000000
  11660 	DEFB	%00011000
  11661 	DEFB	%00011000
  11662 	DEFB	%00000000
  11663 
  11664 ; $1C - Character: '0'		CHR$(28)
  11665 
  11666 	DEFB	%00000000
  11667 	DEFB	%00111100
  11668 	DEFB	%01000110
  11669 	DEFB	%01001010
  11670 	DEFB	%01010010
  11671 	DEFB	%01100010
  11672 	DEFB	%00111100
  11673 	DEFB	%00000000
  11674 
  11675 ; $1D - Character: '1'		CHR$(29)
  11676 
  11677 	DEFB	%00000000
  11678 	DEFB	%00011000
  11679 	DEFB	%00101000
  11680 	DEFB	%00001000
  11681 	DEFB	%00001000
  11682 	DEFB	%00001000
  11683 	DEFB	%00111110
  11684 	DEFB	%00000000
  11685 
  11686 ; $1E - Character: '2'		CHR$(30)
  11687 
  11688 	DEFB	%00000000
  11689 	DEFB	%00111100
  11690 	DEFB	%01000010
  11691 	DEFB	%00000010
  11692 	DEFB	%00111100
  11693 	DEFB	%01000000
  11694 	DEFB	%01111110
  11695 	DEFB	%00000000
  11696 
  11697 ; $1F - Character: '3'		CHR$(31)
  11698 
  11699 	DEFB	%00000000
  11700 	DEFB	%00111100
  11701 	DEFB	%01000010
  11702 	DEFB	%00001100
  11703 	DEFB	%00000010
  11704 	DEFB	%01000010
  11705 	DEFB	%00111100
  11706 	DEFB	%00000000
  11707 
  11708 ; $20 - Character: '4'		CHR$(32)
  11709 
  11710 	DEFB	%00000000
  11711 	DEFB	%00001000
  11712 	DEFB	%00011000
  11713 	DEFB	%00101000
  11714 	DEFB	%01001000
  11715 	DEFB	%01111110
  11716 	DEFB	%00001000
  11717 	DEFB	%00000000
  11718 
  11719 ; $21 - Character: '5'		CHR$(33)
  11720 
  11721 	DEFB	%00000000
  11722 	DEFB	%01111110
  11723 	DEFB	%01000000
  11724 	DEFB	%01111100
  11725 	DEFB	%00000010
  11726 	DEFB	%01000010
  11727 	DEFB	%00111100
  11728 	DEFB	%00000000
  11729 
  11730 ; $22 - Character: '6'		CHR$(34)
  11731 
  11732 	DEFB	%00000000
  11733 	DEFB	%00111100
  11734 	DEFB	%01000000
  11735 	DEFB	%01111100
  11736 	DEFB	%01000010
  11737 	DEFB	%01000010
  11738 	DEFB	%00111100
  11739 	DEFB	%00000000
  11740 
  11741 ; $23 - Character: '7'		CHR$(35)
  11742 
  11743 	DEFB	%00000000
  11744 	DEFB	%01111110
  11745 	DEFB	%00000010
  11746 	DEFB	%00000100
  11747 	DEFB	%00001000
  11748 	DEFB	%00010000
  11749 	DEFB	%00010000
  11750 	DEFB	%00000000
  11751 
  11752 ; $24 - Character: '8'		CHR$(36)
  11753 
  11754 	DEFB	%00000000
  11755 	DEFB	%00111100
  11756 	DEFB	%01000010
  11757 	DEFB	%00111100
  11758 	DEFB	%01000010
  11759 	DEFB	%01000010
  11760 	DEFB	%00111100
  11761 	DEFB	%00000000
  11762 
  11763 ; $25 - Character: '9'		CHR$(37)
  11764 
  11765 	DEFB	%00000000
  11766 	DEFB	%00111100
  11767 	DEFB	%01000010
  11768 	DEFB	%01000010
  11769 	DEFB	%00111110
  11770 	DEFB	%00000010
  11771 	DEFB	%00111100
  11772 	DEFB	%00000000
  11773 
  11774 ; $26 - Character: 'A'		CHR$(38)
  11775 
  11776 	DEFB	%00000000
  11777 	DEFB	%00111100
  11778 	DEFB	%01000010
  11779 	DEFB	%01000010
  11780 	DEFB	%01111110
  11781 	DEFB	%01000010
  11782 	DEFB	%01000010
  11783 	DEFB	%00000000
  11784 
  11785 ; $27 - Character: 'B'		CHR$(39)
  11786 
  11787 	DEFB	%00000000
  11788 	DEFB	%01111100
  11789 	DEFB	%01000010
  11790 	DEFB	%01111100
  11791 	DEFB	%01000010
  11792 	DEFB	%01000010
  11793 	DEFB	%01111100
  11794 	DEFB	%00000000
  11795 
  11796 ; $28 - Character: 'C'		CHR$(40)
  11797 
  11798 	DEFB	%00000000
  11799 	DEFB	%00111100
  11800 	DEFB	%01000010
  11801 	DEFB	%01000000
  11802 	DEFB	%01000000
  11803 	DEFB	%01000010
  11804 	DEFB	%00111100
  11805 	DEFB	%00000000
  11806 
  11807 ; $29 - Character: 'D'		CHR$(41)
  11808 
  11809 	DEFB	%00000000
  11810 	DEFB	%01111000
  11811 	DEFB	%01000100
  11812 	DEFB	%01000010
  11813 	DEFB	%01000010
  11814 	DEFB	%01000100
  11815 	DEFB	%01111000
  11816 	DEFB	%00000000
  11817 
  11818 ; $2A - Character: 'E'		CHR$(42)
  11819 
  11820 	DEFB	%00000000
  11821 	DEFB	%01111110
  11822 	DEFB	%01000000
  11823 	DEFB	%01111100
  11824 	DEFB	%01000000
  11825 	DEFB	%01000000
  11826 	DEFB	%01111110
  11827 	DEFB	%00000000
  11828 
  11829 ; $2B - Character: 'F'		CHR$(43)
  11830 
  11831 	DEFB	%00000000
  11832 	DEFB	%01111110
  11833 	DEFB	%01000000
  11834 	DEFB	%01111100
  11835 	DEFB	%01000000
  11836 	DEFB	%01000000
  11837 	DEFB	%01000000
  11838 	DEFB	%00000000
  11839 
  11840 ; $2C - Character: 'G'		CHR$(44)
  11841 
  11842 	DEFB	%00000000
  11843 	DEFB	%00111100
  11844 	DEFB	%01000010
  11845 	DEFB	%01000000
  11846 	DEFB	%01001110
  11847 	DEFB	%01000010
  11848 	DEFB	%00111100
  11849 	DEFB	%00000000
  11850 
  11851 ; $2D - Character: 'H'		CHR$(45)
  11852 
  11853 	DEFB	%00000000
  11854 	DEFB	%01000010
  11855 	DEFB	%01000010
  11856 	DEFB	%01111110
  11857 	DEFB	%01000010
  11858 	DEFB	%01000010
  11859 	DEFB	%01000010
  11860 	DEFB	%00000000
  11861 
  11862 ; $2E - Character: 'I'		CHR$(46)
  11863 
  11864 	DEFB	%00000000
  11865 	DEFB	%00111110
  11866 	DEFB	%00001000
  11867 	DEFB	%00001000
  11868 	DEFB	%00001000
  11869 	DEFB	%00001000
  11870 	DEFB	%00111110
  11871 	DEFB	%00000000
  11872 
  11873 ; $2F - Character: 'J'		CHR$(47)
  11874 
  11875 	DEFB	%00000000
  11876 	DEFB	%00000010
  11877 	DEFB	%00000010
  11878 	DEFB	%00000010
  11879 	DEFB	%01000010
  11880 	DEFB	%01000010
  11881 	DEFB	%00111100
  11882 	DEFB	%00000000
  11883 
  11884 ; $30 - Character: 'K'		CHR$(48)
  11885 
  11886 	DEFB	%00000000
  11887 	DEFB	%01000100
  11888 	DEFB	%01001000
  11889 	DEFB	%01110000
  11890 	DEFB	%01001000
  11891 	DEFB	%01000100
  11892 	DEFB	%01000010
  11893 	DEFB	%00000000
  11894 
  11895 ; $31 - Character: 'L'		CHR$(49)
  11896 
  11897 	DEFB	%00000000
  11898 	DEFB	%01000000
  11899 	DEFB	%01000000
  11900 	DEFB	%01000000
  11901 	DEFB	%01000000
  11902 	DEFB	%01000000
  11903 	DEFB	%01111110
  11904 	DEFB	%00000000
  11905 
  11906 ; $32 - Character: 'M'		CHR$(50)
  11907 
  11908 	DEFB	%00000000
  11909 	DEFB	%01000010
  11910 	DEFB	%01100110
  11911 	DEFB	%01011010
  11912 	DEFB	%01000010
  11913 	DEFB	%01000010
  11914 	DEFB	%01000010
  11915 	DEFB	%00000000
  11916 
  11917 ; $33 - Character: 'N'		CHR$(51)
  11918 
  11919 	DEFB	%00000000
  11920 	DEFB	%01000010
  11921 	DEFB	%01100010
  11922 	DEFB	%01010010
  11923 	DEFB	%01001010
  11924 	DEFB	%01000110
  11925 	DEFB	%01000010
  11926 	DEFB	%00000000
  11927 
  11928 ; $34 - Character: 'O'		CHR$(52)
  11929 
  11930 	DEFB	%00000000
  11931 	DEFB	%00111100
  11932 	DEFB	%01000010
  11933 	DEFB	%01000010
  11934 	DEFB	%01000010
  11935 	DEFB	%01000010
  11936 	DEFB	%00111100
  11937 	DEFB	%00000000
  11938 
  11939 ; $35 - Character: 'P'		CHR$(53)
  11940 
  11941 	DEFB	%00000000
  11942 	DEFB	%01111100
  11943 	DEFB	%01000010
  11944 	DEFB	%01000010
  11945 	DEFB	%01111100
  11946 	DEFB	%01000000
  11947 	DEFB	%01000000
  11948 	DEFB	%00000000
  11949 
  11950 ; $36 - Character: 'Q'		CHR$(54)
  11951 
  11952 	DEFB	%00000000
  11953 	DEFB	%00111100
  11954 	DEFB	%01000010
  11955 	DEFB	%01000010
  11956 	DEFB	%01010010
  11957 	DEFB	%01001010
  11958 	DEFB	%00111100
  11959 	DEFB	%00000000
  11960 
  11961 ; $37 - Character: 'R'		CHR$(55)
  11962 
  11963 	DEFB	%00000000
  11964 	DEFB	%01111100
  11965 	DEFB	%01000010
  11966 	DEFB	%01000010
  11967 	DEFB	%01111100
  11968 	DEFB	%01000100
  11969 	DEFB	%01000010
  11970 	DEFB	%00000000
  11971 
  11972 ; $38 - Character: 'S'		CHR$(56)
  11973 
  11974 	DEFB	%00000000
  11975 	DEFB	%00111100
  11976 	DEFB	%01000000
  11977 	DEFB	%00111100
  11978 	DEFB	%00000010
  11979 	DEFB	%01000010
  11980 	DEFB	%00111100
  11981 	DEFB	%00000000
  11982 
  11983 ; $39 - Character: 'T'		CHR$(57)
  11984 
  11985 	DEFB	%00000000
  11986 	DEFB	%11111110
  11987 	DEFB	%00010000
  11988 	DEFB	%00010000
  11989 	DEFB	%00010000
  11990 	DEFB	%00010000
  11991 	DEFB	%00010000
  11992 	DEFB	%00000000
  11993 
  11994 ; $3A - Character: 'U'		CHR$(58)
  11995 
  11996 	DEFB	%00000000
  11997 	DEFB	%01000010
  11998 	DEFB	%01000010
  11999 	DEFB	%01000010
  12000 	DEFB	%01000010
  12001 	DEFB	%01000010
  12002 	DEFB	%00111100
  12003 	DEFB	%00000000
  12004 
  12005 ; $3B - Character: 'V'		CHR$(59)
  12006 
  12007 	DEFB	%00000000
  12008 	DEFB	%01000010
  12009 	DEFB	%01000010
  12010 	DEFB	%01000010
  12011 	DEFB	%01000010
  12012 	DEFB	%00100100
  12013 	DEFB	%00011000
  12014 	DEFB	%00000000
  12015 
  12016 ; $3C - Character: 'W'		CHR$(60)
  12017 
  12018 	DEFB	%00000000
  12019 	DEFB	%01000010
  12020 	DEFB	%01000010
  12021 	DEFB	%01000010
  12022 	DEFB	%01000010
  12023 	DEFB	%01011010
  12024 	DEFB	%00100100
  12025 	DEFB	%00000000
  12026 
  12027 ; $3D - Character: 'X'		CHR$(61)
  12028 
  12029 	DEFB	%00000000
  12030 	DEFB	%01000010
  12031 	DEFB	%00100100
  12032 	DEFB	%00011000
  12033 	DEFB	%00011000
  12034 	DEFB	%00100100
  12035 	DEFB	%01000010
  12036 	DEFB	%00000000
  12037 
  12038 ; $3E - Character: 'Y'		CHR$(62)
  12039 
  12040 	DEFB	%00000000
  12041 	DEFB	%10000010
  12042 	DEFB	%01000100
  12043 	DEFB	%00101000
  12044 	DEFB	%00010000
  12045 	DEFB	%00010000
  12046 	DEFB	%00010000
  12047 	DEFB	%00000000
  12048 
  12049 ; $3F - Character: 'Z'		CHR$(63)
  12050 
  12051 	DEFB	%00000000
  12052 	DEFB	%01111110
  12053 	DEFB	%00000100
  12054 	DEFB	%00001000
  12055 	DEFB	%00010000
  12056 	DEFB	%00100000
  12057 	DEFB	%01111110
  12058 	DEFB	%00000000
  12059 
  12060