; ****************************************************************************
; * Assembly File Listing to generate 4K "ROM A" for Galaksija microcomputer *
; ****************************************************************************

; Introduction
; ************

; Disassembled from a binary ROM image and annotated by
; Tomaz Solc (tomaz.solc@tablix.org)
; using z80dasm (http://www.tablix.org/~avian/blog/articles/z80dasm)
; between September 2006 and September 2007

; The original assembly listing, complete with its lack of useful comments 
; is available at:

; http://www.galaksija.org/hr/index.php?title=Disasemblirani_ROM_A

; (Titled "MALI RACUNAR GALAKSIJA" by Voja Antonic 03.01.1984)

; $Id: rom1.asm,v 1.26 2007-09-23 12:06:17 avian Exp $

; "ROM A" contains basic operating system of Galaksija, which can be roughly
; separated into following sections:

;	o Initialization routines,
;	o video driver,
;	o keyboard scanning and simple terminal emulation,
;	o BASIC interpreter,
;	o RPN FP calculator and
;	o audio cassette load/save routines.

; This ROM is a work of art when you consider how tighly optimized for size 
; it is and a nightmare if you wish to completely understand or even modify 
; anything in it.

; This disassembly is a work in progress. Sections of the code remain 
; uncommented, however this file should assemble into a binary that is 
; identical to the original ROM image.

; Any contributions (for example additional comments on the code, patches, 
; etc.) are most welcome at tomaz.solc@tablix.org.


; Code sightseeing
; ****************

; A must-see list of 10 most-interesting parts of code:

; l0098h	Part of video driver code used as ASCII string for 
;		BASIC interpreter.

; l00a0h	Part of video driver code used a 1.0 floating point
;		constant.

; l0038h	Video driver code as a whole, tuned to one T cycle accuracy.

; l038ch	A tutorial on how to use "ld" instructions instead of "jr"
; l0393h	and save a few bytes in the process.
; l0396h 

; l0018h	A function that gets its arguments from bytes in ROM that 
;		follow its call.

; l0d2ah	Increasing randomness of pseudo-random generator by changing 
;		the seed after some keys are pressed.

; l0d70h	One look-up table nested inside unused space of another.

; l06cfh	DOT - a true multi-purpose function: query, set or reset a 
;		pseudo-graphic pixel or turn real time clock on or off
;		all in one block of code.

; l0e58h	Record one additional garbage byte at the end of an audio tape
;		because it saves one "jr" instruction in ROM.

; l0fffh	One spare byte for future expansions.


; About the latch
; ***************

; A 6-bit register (called "latch" in the original documentation) can be 
; accessed on all memory addresses that can be written in binary as

; 0 0 1 0  0 x x x  x x 1 1  1 x x x  
; (for example 207fh as used in VIDEO_INT)

; The content is write-only. A read from these addresses will return an 
; unspecified value.

; Individual bits have the following meaning:
;
;  7	Clamp RAM A7 to one (1 disabled, 0 enabled)
;  ---
;  6    Cassette port output bit 0
;  ---
;  5    Character generator row bit 3
;  ---
;  4	Character generator row bit 2
;  ---
;  3	Character generator row bit 1
;  ---
;  2	Character generator row bit 0
;	Cassette port output bit 1
;  ---
;  1	Unused
;  ---
;  0	Unused

;  Character generator row bits hold the current row of the character being
;  drawn to the screen.

;  Cassette port is high if both output bits are 1, low if both are 0 and
;  zero if one bit is 1 and one is 0.

;  Bit 7 forces RAM address line A7 to one. This is required because the top
;  bit of the R register never changes (only bottom 7 bits are incremented
;  during each opcode).



; ROM A is mapped to memory addresses from 0000h to 0fffh

	org	00000h


; 'START'
; =======
; At power on Z80 starts to execute code here. Interrupt mode is set to 0.

;; START
l0000h:
	di		;0000   Disable interrupts
	sub a		;0001	Clear accumulator
	jp l03dah	;0002	Jump forward to START_2, the remainder of
			;	the initialization code.

; 'EVALUATE NEXT INTEGER ARGUMENT'
; ================================
; Evaluate an integer expression at DE behind a ASCII comma. If comma is not
; found, jump to WHAT_RST.

;; EVAL_INT_EXP_NEXT
l0005h:
	rst 18h		;0005	Call READ_PAR
	db ','		;0006	
	db l0034h-$-1	;0007	Jump to WHAT_RST if there is no next argument
			;	at DE.

; 'EVALUATE INTEGER EXPRESSION'
; =============================
; Evaluate an integer expression at DE and return the result in HL.

;; EVAL_INT_EXP
l0008h:
	call l0ab2h	;0008	Call EVAL_EXPRESSION
	jp l0a6dh	;000b	Jump to FP_TO_INT and return.

; 'FAST MODE'
; ===========
; Disable video interrupt.

;; FAST
l000eh:	
	di		;000e
	ret		;000f	

; 'COMPARE HL WITH DE'
; ====================
; This function compares HL with DE register pair and sets C and Z flags 
; accordingly

; Parameters:
;	DE, HL: values to be compared
; Returns:
;	C, Z flag
; Destroys:
;	A, all other flags

;; CMP_HL_DE
l0010h:
	ld a,h		;0010	Load H into A
	cp d		;0011	Compare with D
	ret nz		;0012	Return if not equal
	ld a,l		;0013	Load L into A
	cp e		;0014	Compare with E
	ret		;0015	Return

; 'SLOW MODE'
; ===========
; Enable video interrupt.

;; SLOW
l0016h:
	ei		;0016
	ret		;0017

; 'READ PARAMETER'
; ================
; This function reads the byte following the calling "rst" instruction and
; returns to a different location (specified with the second following byte) 
; if the byte doesn't match the first non-space character in the string pointed 
; to by DE register.

; Example:
;	rst 18h		; 0005
;	db ','		; 0006
;	db 02ch		; 0007
;       ...		; 0008

; This compares the first non-space character in DE with ASCII comma ',' 
; ignoring any leading space. If it matches, READ PARAMETER returns to the next
; instruction following the two bytes (at 0008h). If not, it adds 02ch to this
; return address (in this case it would return to 0034h). In the first case
; DE is also incremented to account for the matched byte.

; In pseudo-code:
;
; If (**SP) == (EAT_SPACE(DE)) Then
;	*SP=*SP+2
; 	DE=DE+1
; Else
;	*SP=*SP+2+(*(*SP+1))		
; End

; Parameters:
;	DE: Pointer a string.
; Returns:
;	DE: Skips leading space and increments DE, if there is a match.
;	A: First non-space character in DE.
;	Zf: Set if character matches, reset if not.
; Destroys: 
;	flags.

;; READ_PAR
l0018h:
	ex (sp),hl	;0018	Load a pointer from top of stack into HL

	call l0105h	;0019	Call EAT_SPACE	      

	cp (hl)		;001c	Compare memory pointed by HL with A
	jp l0194h	;001d	Jump to the rest of the function at READ_PAR_2

; 'PUT CHARACTER ON SCREEN'
; =========================
; Print a character in A to the screen at the current cursor position 
; (CURSOR_POS)

; Parameters:
;	A: Character to print
; Returns:
;	HL': Position of the printed character + 1
; Destroys:
;	flags

;; PUTCH_RST
l0020h:
	exx		;0020	Save BC, DE and HL registers

	cp 020h		;0021	Set C flag if character is ASCII special.
			;	(ASCII code less than 20h)

	call l09b5h	;0023	Jump to remainder of function.
	exx		;0026	Restore BC, DE and HL registers.
	ret		;0027	Return

; 'CLEAR HL'
; ==========
; Loads 0000h into HL

;; CLEAR_HL
l0028h:
	ld hl,l0000h	;0028	Load 0000h into HL
	ret		;002b	Return


; 'ONE OVER TEN FLOATING POINT CONSTANT'
; ======================================
; Approximately 0.1 in four-byte floating point format.

;; FP_ONE_OVER_TEN
l002ch:
	db	0cch	;002c	Mantissa: cccccch
	db	0cch	;002d
	db 	0cch	;002e	Sign: 00h
	db	07eh	;002f   Exponent: fdh

; 'NEXT BASIC STATEMENT'
; ======================
; Continue execution of the next BASIC statement. BASIC commands call this
; function at the end. It never returns.

;; BASIC_NEXT
l0030h:
	pop af		;0030	Remove return address from stack
	call l0414h	;0031	Call CONTINUE

l0034h:
	jp l078fh	;0034	Jump to WHAT_RST if CONTINUE found no
			;	valid next command.

; 'ROM A VERSION'
; ===============

;; ROM_VERSION
	db	28	;0037

; 'VIDEO INTERRUPT DRIVER'
; ========================
; This routine gets called 50 times per second via the Z80's maskable 
; interrupt. 

; Interrupt gets triggered on the vertical sync impulse. Video synchronization 
; hardware then makes sure (by inserting WAIT states) that the first opcode 
; starts to execute exactly in sync with the next horizontal sync.

; Timing is very important here! This routine must execute in perfect sync
; with the video hardware.

; The routine must make sure that the R and I registers are properly set at
; exactly the right time so that the Z80's memory refresh feature can start
; reading video line data from video RAM. It also must latch the correct video
; line number into the register connected to the character generator ROM and
; adjust the RAM memory map if needed (A7 line).

; The address of a character on screen:
;
;					A7 from latch
;                                       |
;                    <-- I register |   | | R register -->
;              ||                   ||  v |              ||
; Address bits || 11 | 10 |  9 |  8 ||  7 |  6 |  5 |  4 ||  3 |  2 |  1 |  0
;              ||              |    ||              |    ||
;                              |                    |
;     <-- Base address (2800h) |  Row (4 bits)      | Column (5 bits)

;; VIDEO_INT			T states
l0038h:
	push af		;0038	11	Save all used registers on the stack.
	push bc		;0039	11	
	push de		;003a	11
	push hl		;003b	11

	ld hl,02bb0h	;003c	10	Load SCROLL_CNT address to HL
	ld a,0c0h	;003f	7	Load A with 192 
	sub (hl)	;0041	7
	sub (hl)	;0042	7
	sub (hl)	;0043	7	Subtract 3 * SCROLL_CNT from A
	ld e,a		;0044 	4	Load result into E

	ld a,(hl)	;0045	7	Load A with value from SCROLL_CNT
	rrca		;0046	4	Rotate right A three times
	rrca		;0047	4
	rrca		;0048	4	
	ld b,a		;0049	4 	Load result into B

	or a		;004a	4 	set Z flag if A = 0
			;		reset C flag
			;	-----
			;       113 

; The following code is a pause with length (24 + B * 18) T states. 
; This determines the vertical position of the screen.

	jr z,l004dh	;004b	12/7	Wait 5 T states if Z set...
l004dh:
	jr z,l0054h	;004d	12/7	and jump forward
	dec (hl)	;004f	11	... else decrement SCROLL_CNT
	xor a		;0050	4	    clear A (reset C flag)
l0051h:
	ret c		;0051	5	    wait 5 T states 
			;		    (C flag always reset)
	djnz l0051h	;0052	13/8        ... loop B times


l0054h:
	inc hl		;0054	6	Load SCROLL_FLAG address to HL
	ld (hl),a	;0055	13	Set SCROLL_FLAG = 0

	ld b,e		;0056	4	Set B = 192 - 3 * SCROLL_CNT
	ld hl,0207fh	;0057	10	Load latch address to HL
	ld c,l		;005a	4	Load C with 7fh

	ld a,(02ba8h)	;005b	13	Load A with HORIZ_POS
	rra		;005e	4 	Divide A with 2 (C flag always reset)
			;		load bit 0 into C flag.
			;	----
			;	54

; B holds the total number of scanlines to be drawn.

; C holds the current line number

; During one iteration of VIDEO_DISPLAY_LOOP one line of characters is drawn.

; Here is another pause with length (2 + 5 * Cf + 16 * A) T states.
; This determines the horizontal position of the screen.
; Note: HORIZ_POS must be >= 2.

; On later iterations of VIDEO_DISPLAY_LOOP A is always set to 3, this means
; a constant pause of 43 T states

	jr c,l0061h	;005f	12/7	Wait 5 T if HORIZ_POS odd.

;; VIDEO_DISPLAY_LOOP
l0061h:
	dec a		;0061	4	Decrement A
	jr nz,l0061h	;0062	12/7	...loop A times

	jr l006dh	;0064	12	Jump forward

; 'HARD BREAK'
; ============
; On a non-maskable interrupt, Z80 jumps here. This is used as a "hard break"
; button on Galaksija.

;; HARD_BREAK
	di		;0066		Disable interrupts.

; 'RESET BASIC'
; =============
; Resets BASIC interpreter.

;; RESET_BASIC
l0067h:
	ld sp,02ba8h	;0067	Load HORIZ_POS address to SP
	jp l0317h	;006a	Jump to the rest at RESET_BASIC_2

; Continuing VIDEO_DISPLAY_LOOP

l006dh:
	inc c		;006d	4	Increment C

	ld a,c		;006e	4	Load A with C
	and 008h	;006f	7	Set A = A & 08h
	rrca		;0071	4	Rotate A right 3 times
	rrca		;0072	4
	rrca		;0073	4	
	or 028h		;0074	7 	Set A = A | 28h
	ld i,a		;0076	9	Load I with result

			;		I now has the upper 8 bits of the
			;		address for the line that will
			;		be drawn to the sceeen (either 28h
			;		or 29h)

	inc de		;0078	6	NOP
	ld de,0080ch	;0079	10	Load DE with 080ch
	ld a,c		;007c	4	Load A with C
	rrca		;007d	4	Rotate A right 3 times
	rrca		;007e	4
	rrca		;007f	4
	ccf		;0080	4	Complement C flag
	rr d		;0081	8	Rotate D right through C flag
			;		D is now 84h or 04h

			;		The MSB determines whether the RAM
			;		address line A7 will be forced to 1

	or 01fh		;0083	7	Set A = A | 1fh
	rlca		;0085	4	Rotate left
	sub 040h	;0086	7	Subtract 40h
	rrca		;0088	4	Rotate right
	ld r,a		;0089	9	Load R with A

; E holds the number of scan lines to be drawn for this line of characters.

; During one iteration of VIDEO_LINE_LOOP one scanline of video is drawn.

;; VIDEO_LINE_LOOP
l008bh:
	ld (hl),d	;008b	7 	Latch value in D to the character
			;		generator register

; Opcodes are arbitrary, but must all consist of 4 T states (one M state) - 
; 8 pixels are drawn during each opcode.

	inc d		;008c	4
	inc d		;008d	4
	inc d		;008e	4
	inc d		;008f	4	
	xor a		;0090	4
	scf		;0091	4
	rra		;0092	4
	rra		;0093	4	
	xor d		;0094	4	
	ld d,a		;0095	4
	ld h,c		;0096	4
	ld a,b		;0097	4

;; BREAK_STRING
l0098h:

; This part of the line drawing code also serves as a string "BREAK" for the
; basic interepreter.

	ld b,d		;0098	4 	B 
	ld d,d		;0099	4 	R 
	ld b,l		;009a	4 	E 
	ld b,c		;009b	4 	A 
	ld c,e		;009c	4 	K 
	nop		;009d	4 	\0  

	ld b,a		;009e	4
	ld c,h		;009f	4

; This part of the line drawing code also serves as a constant 1.0 in four-byte
; floating point format.

;; FP_ONE
l00a0h:
	nop		;00a0	4	00h	Mantissa: 800000h
	nop		;00a1	4	00h
	add a,b		;00a2	4	80h	Sign bit: 00h
	nop		;00a3	4	00h	Exponent: 01h

	xor a		;00a4	4
	scf		;00a5	4
	rra		;00a6	4
	rra		;00a7	4
	rra		;00a8	4
	ld h,a		;00a9	4
	rla		;00aa	4

; At the end of line drawing:
; 	A = 40h
;	B remains unmodified
;	C remains unmodified
;	D = 40h XOR (D + 4)
;	E remains unmodified
; 	HL remains unmodified (207fh)

	ld (hl),a	;00ab	10	During the last character we clear 
			;		the register so nothing gets
			;		drawn outside the screen (character
			;		generator line 0)

; End of line drawing

	dec b		;00ac	4	Decrement B
	jr z,l00beh	;00ad	12/7	Break from loop if B is zero.

	ld a,r		;00af	9	Load A with R
	sub 027h	;00b1	7	Subtract 27h
	and l		;00b3	4	Clear the top bit (L = 7fh)
			;		This bit is provided by A7 clamp
	ld r,a		;00b4	9	Load R with A

	dec e		;00b6	4	Decrement E
	jp nz,l008bh	;00b7	12/7	If not zero jump to VIDEO_LINE_LOOP

	ld a,003h	;00ba	7	Load A with 03h
	jr l0061h	;00bc	12	Jump to VIDEO_DISPLAY_LOOP

; At this point the screen has been drawn. Timing is no longer critical.
l00beh:
	ld (hl),0bch	;00be	Latch bch into the register
			;	This disables A7 clamp and sets character
			;	generator to an empty line 15 so that nothing
			;	gets drawn outside the screen

; The following code increments the real-time clock in BASIC string $Y.

; The clock only works correctly if Y$ contains one of the following
; ASCII combinations:

; Y$ = "HH:MM:SS:PP\0", Y$ = "HH:MM:SS\0PP", Y$ = "HH:MM\0SS:PP"

; Where HH are hours, MM minutes, SS seconds and PP 1/100th of a second

	ld a,(02a82h)	;00c0	Load memory location 2a82h into A
			;	This is third character in Y$
	cp 03ah		;00c3	Compare A with 3ah (ASCII ':')
	jr nz,l00fbh	;00c5	Jump to VIDEO_END if not equal

	ld a,(02bafh)	;00c7 	Load CLOCK_ON into A
	rlca		;00ca	Move MSB into C flag
	jr nc,l00fbh	;00cb	Jump to VIDEO_END if MSB is zero

; Clock is enabled and seems to contain a valid ASCII string.
; HL contains pointer to the current character
; B contains number of characters left

	ld hl,02a8ah	;00cd	Load 2a8ah into HL 
			;	This is the last (11th) character in string Y$
	ld de,03930h	;00d0	Load 3930h into DE
			;	D = '9' E = '0'
	ld b,008h	;00d3	Load 08h into B
	ld a,d		;00d5	Load 39h into A
			;	A = '9'

	inc (hl)	;00d6	Increment last character (1/100th s) two times
	inc (hl)	;00d7 	(this routine is called 50 times per second)
	cp (hl)		;00d8	Compare last character with '9'

	jr l00dfh	;00d9	Jump forward

; This code propagates change in the 1/100th field to seconds, minutes and 
; hours 

l00dbh:
	inc (hl)	;00db	Increment character
	cp (hl)		;00dc	Compare character with A
	ld a,035h	;00dd	Load '5' into A

l00dfh:
	jr nc,l00ebh	;00df	If character less or equal to A ('9' or '5') 
			;	then jump forward.

	ld (hl),e	;00e1	Replace current character with '0'
	dec hl		;00e2	Move pointer to the next character.
	bit 0,b		;00e3	If B even...
	jr z,l00e9h	;00e5	...jump forward

	dec hl		;00e7	Else move pointer again (to skip ':' or '\0')
	ld a,d		;00e8	Load '9' into A

l00e9h:
	djnz l00dbh	;00e9	Loop until B equals 0
l00ebh:

	dec b		;00eb	Decrement B
	djnz l00fbh	;00ec	Jump to VIDEO_END if B not equal to 0...
			;	...else hours field was updated and must
			;	   be checkd for overflow

	ld a,(hl)	;00ee	Load the character into A
	cp 034h		;00ef	Compare with '4'
	jr c,l00fbh	;00f1	If character less or equal to '4' jump to 
			;	VIDEO_END

	dec hl		;00f3	Move pointer to the next character
	bit 1,(hl)	;00f4	Test bit 1 (character equal to '2' or more)
	jr z,l00fbh	;00f6	If bit 1 not set jump to VIDEO_END...

	ld (hl),e	;00f8	Else load '0' in the last two characters
	inc hl		;00f9
	ld (hl),e	;00fa	

;; VIDEO_END
l00fbh:
	jp (iy)		;00fb	Jump to video hook (jumps to l00fdh by
			;	default)

l00fdh:
	pop hl		;00fd	Restore all registers from stack
	pop de		;00fe	
	pop bc		;00ff	
	pop af		;0100	

	ei		;0101	Enable interrupts
	reti		;0102	Return from interrupt

; 'EAT SPACE'
; ===========
; Increments DE until it points to a non-ASCII space (20h) character

; Parameters:
;	DE: starting position
; Returns:
;	A:  first non-space character
;	DE: address of the character in A
; Destroys:
;	flags

l0104h:
	inc de		;0104	Increment DE

;; EAT_SPACE
l0105h:
	ld a,(de)	;0105	Load memory byte pointed by DE into A
	cp 020h		;0106	Compare A with ASCII ' '
	jr z,l0104h	;0108	Loop if equal...
	ret		;010a	...else Return 

; 'ARR$'
; ======
;; ARR$ BASIC command

;; ARR$
l010bh:
	inc hl			;010b	23 	# 
	xor a			;010c	af 	  
	call l0df3h		;010d	cd f3 0d 	      
	ld (02a99h),hl		;0110	22 99 2a 	"   * 
	rst 30h			;0113	f7 	  
l0114h:
	rst 8			;0114	cf 	  
	inc hl			;0115	23 	# 
	xor a			;0116	af 	  
	call l0df3h		;0117	cd f3 0d 	      
	push de			;011a	d5 	  
	ld de,(02a99h)		;011b	ed 5b 99 2a 	  [   * 
	inc de			;011f	13 	  
	rst 10h			;0120	d7 	  
	jr nc,l0154h		;0121	30 31 	0 1 
	jr l0146h		;0123	18 21 	  ! 

; 'LOCATE BASIC NUMERIC VARIABLE'
; ===============================
; Locates a BASIC variable containing 4-byte floating point number and stores
; its address in HL.

; Recognizes ordinary variables from A - Z and A(I) array.

; Returns:
;	HL: Location of the variable

;; LOCATE_VARIABLE
l0125h:
	call l0105h	;0125	Fetch the next character (call EAT_SPACE)

; Return with Cf set if character not between 'A' and 'Z'

	sub 041h	;0128	Subtract ASCII value 'A'
	ret c		;012a	Return if less

	cp 01ah		;012b 	Compare character with ASCII value 'Z' + 1
	ccf		;012d	
	ret c		;012e	Return if greater or equal

	inc de		;012f	Move to the next character
	and a		;0130	
	jr nz,l015eh	;0131	Jump to LOCATE_VARIABLE_BZ if character 
			;	is not A

	rst 18h		;0133	Call READ_PAR
	db '('		;0134
	db l015dh-$-1	;0135	Jump to LOCATE_VARIABLE_A if character A is
			;	not followed by '('

; A(I) array

	rst 8		;0136 	HL = index (call EVAL_INT_EXP)
	inc hl		;0137	Increment index

	add hl,hl	;0138	HL = index * 4
	add hl,hl	;0139	

	push de		;013a	Save DE on stack
	jr c,l0154h	;013b	Jump to SORRY_RST on carry (index too large)

	ld de,(02a99h)	;013d	HL = index * 4 + ARRAY_LEN
	add hl,de	;0141

	pop de		;0142	Fetch DE from stack
	push de		;0143

	jr c,l0153h	;0144	Jump to SORRY_RST_PUSH_DE on carry 
			;	(index too large)
l0146h:
	pop de		;0146	Restore DE

	rst 18h		;0147	Call READ_PAR
	db ')'		;0148
	db l0153h-$-1	;0149	Jump to SORRY_RST_PUSH_DE if no closing ')' 
			;	found.

	push de		;014a	Save DE

	ex de,hl	;014b	DE = index * 4 + ARRAY_LEN
	call l0183h	;014c	Call FREE_MEM

	rst 10h		;014f	Call CMP_HL_DE

	jr nc,l0188h	;0150	Jump to SUB_RAMTOP_HL if enough memory and 
			;	return

	db 03eh		;0152	Dummy ld a,nn (ignore push de command)

; '"SORRY" ERROR RESTART'
; =======================
; This restart is called when there is not enough memory available to 
; complete a function or command.

;; SORRY_RST_PUSH_DE
l0153h:
	push de		;0153	Push current parser address to stack.
;; SORRY_RST
l0154h:
	call l0799h		;0154	Call BASIC_ERROR
	dm "SORRY", 00dh	;0157

; Ordinary variable

;; LOCATE_VARIABLE_A
l015dh:
	xor a		;015d	Clear A
;; LOCATE_VARIABLE_BZ
l015eh:
	ld h,02ah	;015e	HL = 2a00h + A * 4
	rla		;0160	
	rla		;0161	
	ld l,a		;0162

	xor a		;0163	Clear A and Cf

	ret		;0164	Return

; 'CONVERT ASCII HEX CHAR TO AN INTEGER'
; ======================================
; This function converts a single ASCII character to its hexadecimal numerical 
; value (for example 'B' returns 11) and increments DE.

; Parameters:
;	DE: Pointer to the character to be converted
; Returns:
;	A: Numerical value of character in (DE) or the character in (DE) on 
;	   error (character not between ASCII '0' and '9').
;	DE: Incremented by 1 or unmodified on error.
;	C flag: Set on error, reset otherwise
; Destroys:
;	Flags

;; HEXCHAR_TO_INT
l0165h:
	call l0172h	;0165	First try to convert an ASCII integer
	ret nc		;0168	return if call to CHAR_TO_INT succeeded

	cp 041h		;0169	Return with Cf set if character less than 'A'
	ret c		;016b	

	add a,009h	;016c	Add 09h to ASCII code (lower 4 bits are now
			;	equal to the hex value)

	cp 050h		;016e	Compare with 'F' + 09h + 1

	jr l0178h	;0170	Jump forward (check for error, clear upper
			;	for bits and return)

; 'CONVERT ASCII CHAR TO AN INTEGER'
; ==================================
; This function converts a single ASCII character to its decimal numerical 
; value and increments DE.

; Parameters:
;	DE: Pointer to the character to be converted
; Returns:
;	A: Numerical value of character in (DE) or the character in (DE) on 
;	   error (character not between ASCII '0' and '9').
;	DE: Incremented by 1 or unmodified on error.
;	C flag: Set on error, reset otherwise
; Destroys:
;	Flags

;; CHAR_TO_INT
l0172h:
	ld a,(de)	;0172	Load (DE) into A
	cp 030h		;0173	Compare with 30h (ASCII '0')...
	ret c		;0175	...and return if smaller.

	cp 03ah		;0176	Compare with 3ah (ASCII '9' + 1)...
l0178h:
	ccf		;0178	   (complement carry flag)
	ret c		;0179	...and return if larger or equal.

	inc de		;017a	Increment DE
l017bh:
	and 00fh	;017b	A = A & 0fh (clear upper 4 bits)
			;	also resets carry flag

	ret		;017d	Return

l017eh:
	ld (hl),a			;017e	77 	w 
l017fh:
	inc hl			;017f	23 	# 
	ld a,l			;0180	7d 	} 
	jr l017bh		;0181	18 f8 	    

; 'FREE MEMORY REMAINING'
; =======================
; Calculate bytes available from end of BASIC program to top of RAM

; Returns:
;	HL: Free bytes available.

;; FREE_MEM
l0183h:
	push de		;0183	Save DE to stack

	ld de,(02c38h)	;0184	Load BASIC_END into DE

; 'SUBTRACT HL FROM RAM_TOP'
; ==========================

; Returns:
;	HL: HL = RAM_TOP - HL

;; SUB_RAMTOP_HL
l0188h:
	ld hl,(02a6ah)	;0188	Load RAM_TOP into DE

	ld a,l		;018b	HL = HL & 0fff0h
	and 0f0h	;018c	(resets Cf)
	ld l,a		;018e

	sbc hl,de	;018f	HL = HL - DE - 0

	pop de		;0191	Restore DE
	xor a		;0192	Clear A (resets carry)

	ret		;0193	Return

; 'READ PARAMETER (cont.)'
; ========================

;; READ_PAR_2
l0194h:
	inc hl		;0194	Increment HL
	jr z,l019eh	;0195	Jump forward if character in DE matches

	push bc		;0197	Save BC on stack
	ld c,(hl)	;0198	Load (HL) into BC
	ld b,000h	;0199
	add hl,bc	;019b	Add BC to HL
	pop bc		;019c	Restore BC from stack

	dec de		;019d	Decrement DE

l019eh:
	inc de		;019e	Increment DE
	inc hl		;019f	Increment HL
	ex (sp),hl	;01a0	Store HL back to the top of the stack
	ret		;01a1	Return

; 'CONVERT STRING TO FLOATING POINT NUMBER'
; =========================================
; Converts a string at DE to a floating point number and pushes it to the
; arithmetic stack.

; Returns:
;	Zf: Set if no errors occured

;; STRING_TO_FP
l01a2h:
	call l0248h	;01a2	Clear HL' C' (call CLEAR_CX_HLX_B6)

	ld b,000h	;01a5	Clear B and C
	ld c,b		;01a7

	call l0105h	;01a8	Skip any leading whitespace (call EAT_SPACE)

l01abh:
	call l01b0h	;01ab	Call STRING_TO_FP_FETCH_DECIMAL
	jr l01abh	;01ae	Loop

;		L'	H'	C'	L	H
; ----------------------------------------------------------
;		24 bit mantissa		Exp	Sign

; B register (holds status of the conversion)

; bit	7	6	5	4	3	2	1	0
; ----------------------------------------------------------------------
; 	Mantissa overflow

;		Mantissa started with a number

;			Exponent started with a number

;							Negative exponent

;								Decimal part

; C register holds (negative) number of decimals after the decimal point.


; Stack: Top
;	 -> STRING_TO_FP

;; STRING_TO_FP_FETCH_DECIMAL
l01b0h:
	call l0172h	;01b0	Call CHAR_TO_INT
	jr c,l01d5h	;01b3	Jump on conversion error

	set 6,b		;01b5	Set bit 6 of B

	bit 7,b		;01b7
	jr nz,l01d0h	;01b9	Jump forward on mantissa overflow.

	call l01c3h	;01bb	Call STRING_TO_FP_ADD_DECIMAL

	bit 0,b		;01be
	ret z		;01c0	Decrement C if after decimal point.

	dec c		;01c1	
	ret		;01c2	Return


; Stack: Top
;	 -> STRING_TO_FP
;        -> STRING_TO_FP_FETCH_DECIMAL

;; STRING_TO_FP_ADD_DECIMAL
l01c3h:
	call l024fh	;01c3	Call FP_MUL_10_ADD_A

	ret z		;01c6	Return if no overflow in mantissa

; Restore original mantissa if there was an overflow

	exx		;01c7	
	ld h,d		;01c8	Load DE' into HL'
	ld l,e		;01c9	
	ex af,af'	;01ca	
	ld c,a		;01cb	Load A' into C'
	exx		;01cc	

	set 7,b		;01cd	Set bit 7 of B

	pop af		;01cf	Remove top return address from stack.
			;	(will return to STRING_TO_FP)

l01d0h:
	bit 0,b		;01d0
	ret nz		;01d2	Increment C if before decimal point.

	inc c		;01d3	
	ret		;01d4	Return

; Stack: Top
;	 -> STRING_TO_FP

l01d5h:
	rst 18h		;01d5	Call READ_PAR
	db '.'		;01d6
	db l01ddh-$-1	;01d7

; Decimal point found

	bit 0,b		;01d8
	set 0,b		;01da	
	ret z		;01dc	Return if bit 0 not set,
			;	else set bit 0 of B.

			;	Two decimal points found
l01ddh:
	pop af		;01dd	Remove top return address from stack.

	bit 6,b		;01de	
	ret z		;01e0	Return from STRING_TO_FP if first character
			;	of mantissa was not a number.

	ld hl,l0018h	;01e1	Exponent = 24, sign = positive
	push bc		;01e4	Save BC on stack
	push de		;01e5	Save DE on stack

	exx		;01e6
	call l0914h	;01e7	Call CORRECT_EXP_ADD_IX_10

	pop de		;01ea	Restore DE from stack

	ld bc,l01f3h	;01eb	Push STRING_TO_FP_PARSE_EXP address on stack.
	push bc		;01ee	

	push de		;01ef	Save DE on stack
	jp l0b6dh	;01f0	Jump to STORE_ARITHM_RET and return 
			;	to STRING_TO_FP_PARSE_EXP

; At this point mantissa is on the top of arithmetic stack and DE points
; to the beginning of the exponent.

; Stack: Top
;	 -> STRING_TO_FP

;; STRING_TO_FP_PARSE_EXP
l01f3h:
	pop bc		;01f3	Restore BC from stack
	push de		;01f4	Save DE on stack

	rst 18h		;01f5	Call READ_PAR
	db 'E' 		;01f6	
	db l0213h-$-1	;01f7	No exponent

	rst 18h		;01f8	Call READ_PAR
	db '+'		;01f9	
	db l01fdh-$-1	;01fa	Ignore leading + sign

	jr l0202h	;01fb

l01fdh:
	rst 18h		;01fd	Call READ_PAR
	db '-'		;01fe
	db l0202h-$-1	;01ff

	set 1,b		;0200	Mark negative exponent

;; STRING_TO_FP_GET_EXP
l0202h:
	call l024ah	;0202	Call CLEAR_CX_HLX

l0205h:
	call l0172h	;0205	Call CHAR_TO_INT
	jr c,l0217h	;0208	Break from loop on conversion error

	set 5,b		;020a	Mark exponent started with number

	call l024fh	;020c	Add decimal to the exponent
			;	(call FP_MUL_10_ADD_A)

	jr nz,l0225h	;020f	Jump to HOW_RST_PUSH_DE on exponent overflow

	jr l0205h	;0211	Loop

l0213h:
	pop de		;0213	Restore DE
	xor a		;0214	Clear A
	jr l022eh	;0215	

l0217h:
	bit 5,b		;0217	
	jr z,l0213h	;0219	Jump to FIXME if exponent did not start with
			;	a number

	pop af		;021b	FIXME

	exx		;021c	
	ld a,c		;021d	
	or h		;021e	Test C' and H'

	ld a,l		;021f	A = L'

	exx		;0220

	jr nz,l0225h	;0221	If C' or H' not equal to zero, call HOW_RST
			;	(exponent overflowed)
	bit 7,a		;0223	
l0225h:
	jp nz,l065ah	;0225	If mantissa overflowed, call HOW_RST

	bit 1,b		;0228	If exponent negative, negate A
	jr z,l022eh	;022a	
	neg		;022c
l022eh:

	add a,c		;022e	Add exponent and number of decimal points

; Mantissa is still on the top of the arithmetic stack. Exponent is in A. 

; Multiply mantissa with 10^A.

;; STRING_TO_FP_EXP_LOOP
l022fh:
	and a		;022f	
	jr z,l0245h	;0230	If A zero, jump to STRING_TO_FP_END

	bit 7,a		;0232
	jr z,l023dh	;0234	Multiply by 10 if exponent positive,
			;	else divide by 10

	inc a		;0236	Increment A
	push af		;0237	Save A on stack
	call l0af4h	;0238	Call FP_DIV_10
	jr l0242h	;023b

l023dh:
	dec a		;023d	Decrement A
	push af		;023e	Save A on stack
	call l0ae3h	;023f	Call FP_MUL_10

l0242h:
	pop af		;0242	Restore A from stack
	jr l022fh	;0243	Jump to STRING_TO_FP_EXP_LOOP

;; STRING_TO_FP_END
l0245h:
	bit 6,b		;0245	Test bit 6 of B (valid mantissa)
	ret		;0247	Return


; 'CLEAR C' HL''
; ==============
; Loads 00 0000h into the mantissa in C' HL' and clears bit 6 of B

;; CLEAR_CX_HLX_B6
l0248h:
	res 6,b		;0248	Clear bit 6 of B

;; CLEAR_CX_HLX
l024ah:
	exx		;024a	Exchange BC,DE,HL with BC',DE',HL'
	rst 28h		;024b	Call CLEAR_HL
	ld c,l		;024c	Load 00h into C
	exx		;024d	Exchange BC,DE,HL with BC',DE',HL'
	ret		;024e	Return

; 'ADD A DECIMAL NUMBER TO MANTISSA'
; ==================================
; Multiplies floating point number's mantissa in HL' C' by 10 and adds integer 
; in A to it.

; Parameters:
;	HL' C': Input mantissa (24 bit)
;	A: Integer to add
; Returns:
;	HL' BC': Output mantissa (32 bit)
;	DE' A': Unmodified input mantissa (24 bit)
;	Zf: Set if B' is zero

;; FP_MUL_10_ADD_A
l024fh:
	ex af,af'	;024f	
	exx		;0250

	ld d,h		;0251	DE' A' = HL' C'
	ld e,l		;0252
	ld a,c		;0253

	ld b,000h	;0254	Clear B'

	push af		;0256	Push AF' on stack

;		L'	H'	C'	B'	L	H
; ----------------------------------------------------------
;		32 bit mantissa		(MSB)	Exp	Sign

	add hl,hl	;0257	HL' BC' = HL' BC' * 2
	rl c		;0258	
	rl b		;025a	

	add hl,hl	;025c	HL' C' = HL' C' * 2
	rl c		;025d	
	rl b		;025f	

	add hl,de	;0261	HL' BC' = HL' BC' + DE' A'
	adc a,c		;0262	
	ld c,a		;0263	

	ld a,000h	;0264	
	adc a,b		;0266
	ld b,a		;0267

; We now have HL' BC' = HL' BC' * 5

	pop af		;0268	Pop AF' from stack

	push de		;0269	Push DE' to stack

	ld d,000h	;026a	Clear D'

	add hl,hl	;026c	HL' BC' = HL' BC' * 2
	rl c		;026d	
	rl b		;026f

; We now have HL' BC' = HL' BC' * 10 

	ex af,af'	;0271	Exchange AF with AF'

	ld e,a		;0272	Load A into E'

	add hl,de	;0273	HL' BC' = HL' BC' + E'

	ld a,d		;0274	
	adc a,c		;0275	
	ld c,a		;0276	

	ld a,d		;0277
	adc a,b		;0278	
	ld b,a		;0279	

	pop de		;027a	Pop DE' from stack

	exx		;027b	
	ret		;027c	Return

; 'EDIT'
; ======
; "EDIT" BASIC command.

; Edit a line of BASIC with a simple line editor. Takes one integer argument
; which is the line number to edit.

; Delete key was pressed while in line editor mode. Remove one character
; at '_' cursor position.

;; EDIT_DELETE
l027dh:
	ld e,l		;027d	DE' = HL'
	ld d,h		;027e	

l027fh:
	inc de		;027f	(DE') = (DE' + 1)
	ld a,(de)	;0280	
	dec de		;0281	
	ld (de),a	;0282	

	inc de		;0283	Increment DE'

	cp 00dh		;0284 	Loop until end of line is reached
	jr nz,l027fh	;0286	

	jr l02afh	;0288	Continue with EDIT_LOOP

;; EDIT_LEFT
l028ah:
	ld a,l		;028a	Check if cursor is at the beginning of buffer.
	cp 0b6h		;028b	
	jr z,l02afh	;028d	

	dec hl		;028f	Move cursor one position left
	jr l02afh	;0290	Continue with EDIT_LOOP

;; EDIT_RIGHT
l0292h:
	ld a,(hl)	;0292	Check if cursor is at the end of buffer.
	cp 00dh		;0293	
	jr z,l02afh	;0295	

	jr l02eah	;0297	Move cursor one position right
			;	and continue with EDIT_LOOP

; Entry point to the function

;; EDIT
l0299h:
	call l0cd3h	;0299	HL = line number to edit or 0 on error
			;	(call STRING_TO_INT)

	call l07f2h	;029c	DE = start of the BASIC line
			;	(call FIND_LINE)

	jp c,l065ah	;029f	Jump to HOW_RST_PUSH_DE if exact line number
			;	in argument was not found.

	ld a,00ch	;02a2	Clear screen with PUTCH_RST
	rst 20h		;02a4	(print ASCII FF)

	ld hl,02bb6h	;02a5	Load INPUT_BUFFER address into HL

	ld (02a68h),hl	;02a8	Move cursor at the beggining of the buffer
			;	(update CURSOR_POS)

	call l0931h	;02ab	Print the selected line into buffer
			;	(call PRINT_BASIC_LINE)

			;	HL' = address of the last character
			;             in buffer + 1

	exx		;02ae

;; EDIT_LOOP
l02afh:
	ld de,02800h	;02af	Set CURSOR_POS to the top left corner of the
	ld (02a68h),de	;02b2	screen.

; Print the BASIC line in buffer on the screen with the '_' cursor inserted 
; at HL'.

	ld de,02bb6h	;02b6	DE' = INPUT_BUFFER

	ld c,(hl)	;02b9	Save character at HL' in C'
	ld (hl),000h	;02ba	and overwrite it with ASCII NUL

	call l0937h	;02bc	Call PRINTSTR

			;	DE' = address of the first character after 
			;	      inserted ASCII NUL

	ld a,05fh	;02bf	Load cursor character (ASCII '_') into A

	call l07b6h	;02c1	Decrement DE'
			;	Restore character in C' to HL'
			;	Call PUTCH_PRINTSTR

			;	DE' = address of the last character in the
			;	      buffer.

	call l0cf5h	;02c4	Wait for a keypress (call KEY)

	cp 00dh		;02c7	"RETURN" pressed...
	jr z,l033ch	;02c9	...call BASIC_CMDLINE_ENTRY and proceed as if
			;	   the buffer was entered on the command line.

	or a		;02cb	"DELETE" pressed...
	jr z,l027dh	;02cc	...jump to EDIT_DELETE

	cp 01dh		;02ce	"LEFT" pressed...
	jr z,l028ah	;02d0	...jump to EDIT_LEFT

	cp 01eh		;02d2	"RIGHT" pressed...
	jr z,l0292h	;02d4	...jump to EDIT_RIGHT

	jr c,l02afh	;02d6	Ignore any other special keys (scancode < 1eh)
			;	(loop to EDIT_LOOP)

; Alfanumeric key was pressed...

	ld b,a		;02d8	Load ASCII code into B

	push hl		;02d9	Save '_' cursor address on stack

	ld hl,02c34h	;02da	Check there is space in the buffer for
			;	another character.
	rst 10h		;02dd	(call CMP_HL_DE)

	pop hl		;02de	Restore '_' cursor address.

	jr c,l02afh	;02df	Ignore key press that would overflow the
			;	buffer (loop to EDIT_LOOP)

; Make space for the inserted character by moving all character in front
; one position to the right.

l02e1h:
	dec de		;02e1	(DE') = (DE' - 1) 
	ld a,(de)	;02e2	
	inc de		;02e3	
	ld (de),a	;02e4	

	dec de		;02e5	Decrement DE'
	rst 10h		;02e6	Compare with '_' cursor position in HL'

	jr nz,l02e1h	;02e7	Loop until cursor position is reached

	ld (hl),b	;02e9	Insert ASCII code into string

l02eah:
	inc hl		;02ea	Move '_' cursor to the right.
	jr l02afh	;02eb	Loop to EDIT_LOOP

; 'MOVE CURSOR INTO A NEW LINE'
; =============================
; This routine prints a new line if the cursor is not in the upper left corner
; of the screen.

;; NEWLINE
l02edh:
	ld a,(02a68h)	;02ed	Set Zf if cursor in upper left corner of the
	and 01fh	;02f0	screen.

	ld a,00dh	;02f2	Load ASCII CR into A
	ld (02bb5h),a	;02f4	Load 0dh into FIXME

	ret z		;02f7	Print ASCII CR if Zf not set.	
	rst 20h		;02f8
	ret		;02f9

; 'CHECK IF "BREAK" KEY IS PRESSED'
; =================================
; This function checks if "BREAK" key is pressed. If so it executes the BREAK
; routine.

l02fah:
	ld a,(02033h)	;02fa	Check for "DELETE" key press.
	rrca		;02fd	
	ret c		;02fe	Return if key is not pressed. Else check for
			;	BREAK keypress again.

			;	FIXME: Phantom keypress recognition?

;; CHECK_BREAK
l02ffh:
	ld a,(02031h)	;02ff	Check for "BREAK" key press.
	rrca		;0302	 	  
	jr c,l02fah	;0303	If key is pressed (LSB of A is 0), continue 
			;	to the BREAK function. Else jump.

; 'BREAK BASIC INTERPRETER'
; =========================
; This function gets called whenever the "BREAK" key is pressed during the 
; execution of the BASIC interpreter.

;; BREAK
l0305h:
	call l02edh		;0305	cd ed 02 	      
	ld de,l0098h		;0308	11 98 00 	      
	call l0937h		;030b	cd 37 09 	  7   
	ld de,(02a9fh)		;030e	ed 5b 9f 2a 	  [   * 
	ld a,d			;0312	7a 	z 
	or e			;0313	b3 	  
	call nz,l08edh		;0314	c4 ed 08 	      

; 'RESET BASIC (cont.)'
; =====================

;; RESET_BASIC_2
l0317h:
	ei		;0317	Enable interrupts

	call l02edh	;0318	Call NEWLINE

	ld de,l0f07h	;031b	Print "READY" string
	call l0937h	;031e	(call PRINTSTR)

;; BASIC_CMDLINE_LOOP
l0321h:

; Reset BASIC interpreter variables

	rst 28h		;0321	Call CLEAR_HL
	ld de,03031h	;0322	
	ld sp,02aa7h	;0325	

	push de		;0328	Load 3031h into KEY_DIFF	(2aa5-2aa6)
	push hl		;0329	Clear FIXME			(2aa3-2aa4)
	push hl		;032a	Clear FIXME 			(2aa1-2aa2)
	push hl		;032b	Clear BASIC_LINE                (2a9f-2aa0)

	ld hl,(02c36h)	;032c	Load BASIC_START+2 into HL 
	inc hl		;032f	
	inc hl		;0330	

	push hl		;0331	Load HL into 2a9dh (FIXME)

	ld sp,02ba8h	;0332	Restore CPU and arithmetic stack pointers.
	ld ix,02aach	;0335

	call l07bbh	;0339	Get command line (call GETSTR)

; Process string in input buffer and either store a BASIC line to memory or 
; execute and immediate command.

;; BASIC_CMDLINE_ENTRY
l033ch:
	push de		;033c	Push address of the end of the string to stack,

	ld de,02bb6h	;033d	Load INPUT_BUFFER address into DE

	call l0cd3h	;0340	Call STRING_TO_INT

			;	Stores line number in HL, or set Zf if
			;	no line number was entered.

	pop bc		;0343	Restore end address into BC.

	jp z,l038ch	;0344	No line number, jump to IMMEDIATE

; Store the entered BASIC line in memory

; Example: 20 XXX entered on the command line

	dec de		;0347	Store line number at (DE-2)	
	ld a,h		;0348	(two bytes before the start of the line 
	ld (de),a	;0349   contents)
	dec de		;034a
	ld a,l		;034b
	ld (de),a	;034c

	push bc		;034d	Save line end address and line start address
	push de		;034e	on stack.

	ld a,c		;034f	A = C - E
	sub e		;0350	

	push af		;0351	

	call l07f2h	;0352	(call FIND_LINE)

	push de		;0355	Store start address of the next line on stack
	jr nz,l0368h	;0356

; Entered line number doesn't exist yet

	push de		;0358

	call l0811h	;0359	Move DE to the beginning of the line 
			;	(call FIND_LINE_NEXT)

	pop bc		;035c	BC = start address of the next line

	ld hl,(02c38h)	;035d	2a 38 2c 	* 8 , 

	call l0944h	;0360	Call MOVE_MEM

	ld h,b		;0363	60 	` 
	ld l,c		;0364	69 	i 
	ld (02c38h),hl	;0365	22 38 2c 	" 8 , 
l0368h:
	pop bc		;0368	c1 	  
	ld hl,(02c38h)	;0369	2a 38 2c 	* 8 , 
	pop af		;036c	f1 	  
	push hl		;036d	e5 	  
	cp 003h		;036e	fe 03 	    
	jr z,l0321h	;0370	28 af 	(   
	ld e,a		;0372	5f 	_ 
	ld d,000h	;0373	16 00 	    
	add hl,de	;0375	19 	  
	ld de,(02a6ah)	;0376	ed 5b 6a 2a 	  [ j * 
	rst 10h		;037a	d7 	  
	jp nc,00153h	;037b	d2 53 01 	  S   
	ld (02c38h),hl	;037e	22 38 2c 	" 8 , 
	pop de		;0381	d1 	  
	call l094ch	;0382	cd 4c 09 	  L   
	pop de		;0385	d1 	  
	pop hl		;0386	e1 	  
	call l0944h	;0387	cd 44 09 	  D   
	jr l0321h	;038a	Jump to BASIC_CMDLINE_LOOP

; 'PARSE AN IMMEDIATE COMMAND'
; ============================
; Parses and executes a BASIC command entered on the command line.

; Calls PARSE with BASIC_CMDLINE_TABLE

;; IMMEDIATE
l038ch:
	ld hl,l0317h	;038c	Push RESET_BASIC_2 address on stack
	push hl		;038f

	ld l,(l0f0fh-1)&00ffh
			;0390					HL = 0f0eh
	db 1		;0392  					BC = xx

; 'EVALUATE NUMERIC FUNCTIONS'
; ============================
; Evaluates any functions from the numeric function table that appear at DE.

; Calls PARSE with BASIC_FUNC_TABLE.

;; EVAL_FUNCTIONS
l0393h:
	ld l,(l0f9ch-1)&00ffh
			;0393			HL = 0f9bh
	db 1		;0395   		BC = xx		BC = xx
l0396h:
	ld l,0eeh	;0396	HL = 0feeh	

; 'BASIC FUNCTION PARSER'
; =======================
; Parse BASIC commands at DE. 

; Parameters:
;	DE: String containing BASIC commands.
;	L: Low byte of a pointer to the appropriate command table.

;; PARSE
l0398h:
	ld h,00fh	;0398

;; PARSE_FIRST
l039ah:
	call l0105h	;039a	Skip leading space and get first character 
			;	from string in DE (Call EAT_SPACE)

	push de		;039d	Store address of the first character on stack

	inc de		;039e	Increment DE and HL
	inc hl		;039f

	cp (hl)		;03a0	Compare first character with first character
			;	in table

	jr z,l03a9h	;03a1	Jump to PARSE_COMPARE if equal.

	bit 7,(hl)	;03a3	Test MSB of (HL)
	jr nz,l03b3h	;03a5	Jump to PARSE_END if set

	jr l03bah	;03a7	Jump to PARSE_NEXT if characters do not match

; Compares string in DE (BASIC line) with string in HL (BASIC command table)

;; PARSE_COMPARE
l03a9h:
	ld a,(de)	;03a9	Get next character

	inc de		;03aa	Increment DE and HL
	inc hl		;03ab

	cp (hl)		;03ac	Compare character
	jr z,l03a9h	;03ad	Loop if they match

	bit 7,(hl)	;03af	Test MSB of (HL)
	jr z,l03b6h	;03b1	Jump to PARSE_DOT if not set.

; Complete table has been checked and no matching BASIC command has been found

;; PARSE_END
l03b3h:
	dec de		;03b3	Decrement DE
	jr l03c8h	;03b4	Jump to PARSE_MATCH

; A matching BASIC command has been found

;; PARSE_DOT
l03b6h:
	cp 02eh		;03b6	Compare last character with ASCII '.'
	jr z,l03c3h	;03b8	If equal then jump to PARSE_MATCH_PARTIAL
			;	else continue checking with next command in 
			;	the command table.

; Move (HL) to the next entry in the BASIC command table

;; PARSE_NEXT
l03bah:
	inc hl		;03ba	Increment HL until MSB of (HL) is set
	bit 7,(hl)	;03bb	
	jr z,l03bah	;03bd

	inc hl		;03bf	Increment HL
	pop de		;03c0	Restore DE
	jr l039ah	;03c1	Jump to PARSE_FIRST

;; PARSE_MATCH_PARTIAL
l03c3h:
	inc hl		;03c3	Increment HL until MSB of (HL) is set
	bit 7,(hl)	;03c4	
	jr z,l03c3h	;03c6

;; PARSE_MATCH
l03c8h:
	ld a,(hl)	;03c8	HL = (HL) & 7fffh 
	inc hl		;03c9	number in (HL) is big endian!
	ld l,(hl)	;03ca	
	and 07fh	;03cb	
	ld h,a		;03cd

	pop af		;03ce	Removed saved DE from stack
	bit 6,h		;03cf	Test bit 6 of H
	res 6,h		;03d1	Reset bit 6 of H

	push hl		;03d3	Push HL to stack

	call nz,l0a6ah	;03d4	Call EVAL_PAREN_INT if bit 6 of H set.
			;	(get function's argument)

	jp 02ba9h	;03d7	Jump to BASIC_LINK (Returns to address in HL)

; 'START (cont.)'
; ===============
; This is the rest of the boot code (it is executed only once, at power on)

;; START_2
l03dah:
	im 1		;03da	Set interrupt mode 1
	ld iy,l00fdh	;03dc	Load 00fdh into IY 
			;	(default video interrupt hook)

	ld hl,027ffh	;03e0	Load latch address (27ffh) into HL
	ld (hl),l	;03e3	Load ffh into the latch (disable A7 clamp, 
			;	empty character scanline)

	ld b,l		;03e4	Load ffh into B.

; This routine clears the entire RAM, starting at 2800h, if A holds 00h.

l03e5h:
	inc hl		;03e5	Increment HL
	ld (hl),b	;03e6	Load B (ffh) into (HL)
	inc (hl)	;03e7	Increment (HL)
			;	(HL) should now hold 00h if the address in HL
			;	is mapped to RAM.

	jr nz,l03edh	;03e8	If not zero, break from loop 
			;	(reached the end of RAM)

	or (hl)		;03ea	If (HL) | A ...
	jr z,l03e5h	;03eb	... is zero, loop

l03edh:
	ld (02a6ah),hl	;03ed	Store the last address in RAM + 1 into RAM_TOP

	ld sp,02badh	;03f0	Set SP to 2badh 
	ld hl,0c90bh	;03f3	Load c90bh into HL
	push hl		;03f6	Store c9h (ret) into 2bach (VIDEO_LINK)
			;	Store 0bh into 2babh

	dec sp		;03f7	Decrement SP (2baah)
	push hl		;03f8	Store c9h (ret) into 2ba9h (BASIC_LINK)
			;	Store 0bh into 2ba8h (HORIZ_POS)

	ld a,00ch	;03f9	Load 0ch (ASCII FF) into A
	rst 20h		;03fb	Call PUTCH_RST
			;	This clears the screen and places cursor in
			;	the top left corner

; Execution now continues to the NEW command. DE is (probably) set to 0000h 
; after reset (points to the start of the ROM). Since there is no valid ASCII 
; string there the code below behaves as if NEW command was called without an 
; argument.
	
; 'NEW'
; =====
; "NEW" BASIC command line command.

;; NEW
l03fch:
	call l0cd3h	;03fc	Read command argument (BASIC offset)
			;	into HL (if any)
			;	(call STRING_TO_INT)

	ld de,02c3ah	;03ff	Load 2c3ah (USER_MEM) into DE
	add hl,de	;0402	Add DE to HL

	ld sp,02c3ah	;0403	Load 2c3ah (USER_MEM) into SP
	push hl		;0406	Store HL to 2c38 (BASIC_END)
	push hl		;0407	Store HL to 2c36 (BASIC_START)
l0408h:
	jp l0067h	;0408	Jump to RESET_BASIC

; 'RUN'
; =====
; "RUN" BASIC command line command

;; RUN
l040bh:
	call l0cd3h	;040b	Read command argument
			;	(call STRING_TO_INT)

	ld de,(02c36h)	;040e	Load BASIC_START address into DE
l0412h:
	jr l0422h	;0412	Jump to RUN_DO    

; 'CONTINUE'
; ==========
; Continue execution of a BASIC program.

; A call to this function will try to execute the next command on the line
; or will continue to the next line. If a valid command is found this function
; never returns. On the other hand if neither ':' nor line end is encountered, 
; it returns.

;; CONTINUE
l0414h:
	ld (02bb5h),a	;0414	Load A into FIXME

	rst 18h		;0417	Call READ_PAR
	db ':'		;0418	
	db l041dh-$-1	;0419	Check for ':'. If not found jump to CONTINUE_CR

;; ELSE
l041ah:
	pop af		;041a	Remove return address from stack.
	jr l042dh	;041b	Execute the rest of the line 
			;	(jump to RUN_CONT_LINE)

;; CONTINUE_CR
l041dh:
	rst 18h		;041d	Call READ_PAR
	db 00dh		;041e	
	db l0440h-$-1	;041f	Check for ASCII CR. If not found return.

	pop af		;0420	Remove return address from stack and 
			;	execute next BASIC line.

; 'INTERPRET NEXT LINE OF BASIC'
; =============================
; Jump to this location finds the next BASIC line following DE and starts BASIC 
; interpreter at the BASIC.

;; RUN_NEXT_LINE
l0421h:
	rst 28h		;0421	Call CLEAR_HL

;; RUN_DO
l0422h:
	call l07f6h	;0422	Call FIND_LINE_SCOPE

	jr c,l0408h	;0425	Jump to RESET_BASIC if line was not found.

; 'INTERPRET A LINE OF BASIC'
; =============================
; Jump to this location starts BASIC interpreter at the BASIC line at DE.

;; RUN_THIS_LINE
l0427h:
	ld (02a9fh),de	;0427	Load DE into BASIC_LINE
	inc de		;042b	DE = DE + 2 
	inc de		;042c	(points to the ASCII part of the line)

; 'INTERPRET THE REST OF THE LINE'
; ================================
; Jump to this location interprets the rest of the line at DE.

;; RUN_CONT_LINE
l042dh:
	call l02ffh	;042d	Call CHECK_BREAK

	ld ix,02aach	;0430	Load ARITHM_STACK into IX

	ld l,(l0f30h-1)&00ffh	
			;0434	Load 2fh into L

	jp l0398h	;0436	Jump to PARSE with pointer to the
			;	BASIC_CMD_TABLE.

; 'EVALUATE RELATIONAL OPERATORS (cont.)'
; =======================================
; Fetches the next expression at DE and compares its value with the top of 
; the stack.

; Returns:
;	HL: 0000h
;	Flags: result of comparisson

;; EVAL_RELATIONAL_2
l0439h:
	call l068eh	;0439	Call EVAL_ARITHMETIC
	call l0b10h	;043c	Call FP_COMPARE
	rst 28h		;043f	Call CLEAR_HL
l0440h:
	ret		;0440	Return

;; IF
l0441h:
	rst 8			;0441	cf 	  
	ld a,h			;0442	7c 	| 
	or l			;0443	b5 	  
	jr nz,l042dh		;0444	20 e7 	    
	call l081ch		;0446	cd 1c 08 	      

l0449h:
	jr nc,l0427h	;0449	Jump to RUN_THIS_LINE
	jr l0408h	;044b	...else jump to RESET_BASIC

; 'COMMENT'
; =========
; "!" BASIC command. Does nothing. NOTE: An ELSE with IF also points here.

;; COMMENT
l044dh:
	rst 28h		;044d	Call CLEAR_HL
	call l0813h	;044e	Find next line (call FIND_LINE_NEXT_2)
	jr l0449h	;0451	

; 'GOTO'
; ======
; "GOTO" BASIC command.

;; GOTO
l0453h:
	rst 8		;0453	Get command argument
	push de		;0454	Save DE on stack

	call l07f2h	;0455	Call FIND_LINE.
	jp nz,l065bh	;0458	Jump to HOW_RST, if exact line number in
			;	argument was not found.

l045bh:
	pop af		;045b	Remove saved DE from stack.
	jr l0427h	;045c	Jump to RUN_THIS_LINE.

; 'LIST'
; ======
; "LIST" BASIC command line command.

;; LIST
l045eh:
	call l0cd3h	;045e	Read argument into HL (call STRING_TO_INT)

; Note: if called from KEY, HL contains 0000h.

;; LIST_KEY
l0461h:
	call l02edh	;0461	Move cursor to a new line (call NEWLINE)
	call l07f2h	;0464	Find the required BASIC line (call FIND_LINE)
l0467h:
	jr c,l0408h	;0467	Jump to RESET_BASIC if line not found

; Keep printing BASIC lines as long as RETURN or LIST key is pressed.

;; LIST_LOOP
l0469h:
	call l0931h	;0469	Call PRINT_BASIC_LINE
	call l07f6h	;046c	Find the following line (call FIND_LINE_SCOPE)

	jr c,l0467h	;046f	Jump to RESET_BASIC if line not found

;; LIST_KEY_LOOP
l0471h:
	call l02ffh	;0471	Call CHECK_BREAK

	ld a,(02030h)	;0474	Load "RETURN" key status into A
	ld hl,02034h	;0477	Load "LIST" key address into HL
	and (hl)	;047a	
	rrca		;047b	
	jr nc,l0469h	;047c	If either "RETURN" or "LIST" is pressed, loop
			;	to LIST_LOOP

	jr l0471h	;047e	Else loop to LIST_KEY_LOOP

; 'PRINT'
; =======
; "PRINT" BASIC command.

;; PRINT
l0480h:
	rst 18h		;0480	Call READ_PAR
	db ':'		;0481
	db l0488h-$-1	;0482

			;	If ':' follows the PRINT command, just print
			;	a carriage return and continue execution
			;	at the rest of the line.

	ld a,00dh	;0483	Print ASCII CR
	rst 20h		;0485	(call PUTCH_RST)
	jr l042dh	;0486	Jump to RUN_CONT_LINE

l0488h:
	rst 18h		;0488	Call READ_PAR
	db 00dh		;0489	(ASCII CR)
	db l04d1h-$-1	;048a	
	
			;	Jump to PRINT_DO if there is an argument

			;	Just PRINT without and argument prints a
			;	carriage return.

	rst 20h		;048b	Print ASCII CR
l048ch:
	jr l0421h	;048c	Jump to RUN_NEXT_LINE

;; PRINTSTR_QUOTE
l048eh:
	rst 18h		;048e	Call READ_PAR
	db '"'		;048f
	db l04e5h-$-1	;0490	

			;	If the argument doesn't begin with a quote
			;	evaluate its contents. Jump to FIXME

			;	If the argument begins with a quote, print
			;	the quoted string.

	call l0938h	;0491	Print string following command ending with 
			;	'"'. (call PRINTSTR_A)

	jr nz,l048ch	;0494	No closing '"' found. Ignore this error and
			;	jump to RUN_NEXT_LINE

	jr l04adh	;0496	Jump FIXME
;; X$
l0498h:
	ld l,05ch		;0498	2e 5c 	. \ 
	db 001h		;049a	Dummy ld bc,nn (skip next instruction)
;; Y$
l049bh:
	ld l,060h	;049b
l049dh:
	ld h,02ah		;049d	26 2a 	& * 
	call l060eh		;049f	cd 0e 06 	      
l04a2h:
	ld a,(hl)			;04a2	7e 	~ 
	inc hl			;04a3	23 	# 
	or a			;04a4	b7 	  
	jr z,l04adh		;04a5	28 06 	(   
	rst 20h			;04a7	e7 	  
	ld a,l			;04a8	7d 	} 
	and 00fh		;04a9	e6 0f 	    
	jr nz,l04a2h		;04ab	20 f5 	    

l04adh:
	rst 18h		;04ad	Call READ_PAR
	db ','		;04ae
	db l04cbh-$-1	;04af

l04b0h:
	ld a,(02a68h)		;04b0	3a 68 2a 	: h * 
	and 007h		;04b3	e6 07 	    
	jr z,l04ceh		;04b5	28 17 	(   
	ld a,020h		;04b7	3e 20 	>   
	rst 20h			;04b9	e7 	  
	jr l04b0h		;04ba	18 f4 	    
;; AT
l04bch:
	rst 8			;04bc	cf 	  
	ld a,h			;04bd	7c 	| 
	or 028h		;04be	f6 28 	  ( 
	and 029h		;04c0	e6 29 	  ) 
	ld h,a			;04c2	67 	g 
	ld (02a68h),hl		;04c3	22 68 2a 	" h * 
	rst 18h			;04c6	df 	  
	inc l			;04c7	2c 	, 
	ld (bc),a			;04c8	02 	  
	jr l04ceh		;04c9	18 03 	    
l04cbh:
	rst 18h		;04cb	Call READ_PAR
	db ';'		;04cc
	db l04e1h-$-1	;04cd

l04ceh:
	call l0414h		;04ce	cd 14 04 	      

; 'PRINT (cont.)'
; ===============

;; PRINT_DO
l04d1h:
	ld l,(l0fe1h-1)&00ffh	
			;04d1	Jump to PARSE with pointer to the 
	jp l0398h	;04d3	BASIC_PRINT_TABLE

; 'HOME'
; ======
; "HOME" BASIC command

;; HOME
l04d6h:
	call l0cd3h	;04d6	Get command argument (call STRING_TO_INT)

	ld (02a6ch),hl	;04d9	Store argument into WINDOW_LEN

	jr nz,l04e4h	;04dc	If there was a non-zero argument, that is all.
			;	Call BASIC_NEXT

	ld a,00ch	;04de	Load ASCII FF into A
	db 001h		;04e0	Dummy "ld bc,nn" (skip next two instructions)
l04e1h:
	ld a,00dh	;04e1	Load ASCII CR into A

	rst 20h		;04e3	Call PUTCH_RST
l04e4h:
	rst 30h		;04e4	Call BASIC_NEXT

l04e5h:
	call l0396h		;04e5	cd 96 03 	      
	jr nz,l04f1h		;04e8	20 07 	    
	call l0ab2h		;04ea	cd b2 0a 	      
	call l08f6h		;04ed	cd f6 08 	      

; following two lines from Diss_019.jpg
	db 03eh			;04f0	Dummy LD A,
l04f1h:	
	rst 20h			;04f1	e7 	>   

	jr l04adh		;04f2	18 b9 	    
;; CALL
l04f4h:
	call l0974h		;04f4	cd 74 09 	  t   
	rst 8			;04f7	cf 	  
	push de			;04f8	d5 	  
	call l07f2h		;04f9	cd f2 07 	      
	jp nz,l065bh		;04fc	c2 5b 06 	  [   
	ld hl,(02a9fh)		;04ff	2a 9f 2a 	*   * 
	push hl			;0502	e5 	  
	ld hl,(02aa3h)		;0503	2a a3 2a 	*   * 
	push hl			;0506	e5 	  
	rst 28h			;0507	ef 	  
	ld (02aa1h),hl		;0508	22 a1 2a 	"   * 
	add hl,sp			;050b	39 	9 
	ld (02aa3h),hl		;050c	22 a3 2a 	"   * 
	jp l0427h		;050f	c3 27 04 	  '   
;; RET
l0512h:
	ld hl,(02aa3h)		;0512	2a a3 2a 	*   * 
	ld a,h			;0515	7c 	| 
	or l			;0516	b5 	  
	jp z,l065ah		;0517	ca 5a 06 	  Z   
	ld sp,hl			;051a	f9 	  
	pop hl			;051b	e1 	  
	ld (02aa3h),hl		;051c	22 a3 2a 	"   * 
	pop hl			;051f	e1 	  
	ld (02a9fh),hl		;0520	22 9f 2a 	"   * 
	pop de			;0523	d1 	  
l0524h:
	call l0959h		;0524	cd 59 09 	  Y   
	rst 30h			;0527	f7 	  
;; STEP
l0528h:
	rst 8			;0528	cf 	  
	db 001h		;0529	Dummy ld bc,nn (skip next two instructions)

l052ah:
	rst 28h		;052a
	inc hl		;052b
	ld (02a91h),hl		;052c	22 91 2a 	"   * 
	ld hl,(02a9fh)		;052f	2a 9f 2a 	*   * 
	ld (02a93h),hl		;0532	22 93 2a 	"   * 
	ex de,hl			;0535	eb 	  
	ld (02a95h),hl		;0536	22 95 2a 	"   * 
	ld bc,l0005h+5		;0539	01 0a 00 	      
	ld hl,(02aa1h)		;053c	2a a1 2a 	*   * 
	ex de,hl			;053f	eb 	  
	rst 28h			;0540	ef 	  
	add hl,sp		;0541	39 	9 
; Following two lines from Diss_019.jph
	db 03eh			;0542	Dummy LD A,
l0543h:
	add hl,bc		;0543	09 	>   

	ld a,(hl)		;0544	7e 	~ 
	inc hl			;0545	23 	# 
	or (hl)			;0546	b6 	  
	jr z,l055fh		;0547	28 16 	(   
	ld a,(hl)			;0549	7e 	~ 
	dec hl			;054a	2b 	+ 
	cp d			;054b	ba 	  
	jr nz,l0543h		;054c	20 f5 	    
	ld a,(hl)			;054e	7e 	~ 
	cp e			;054f	bb 	  
	jr nz,l0543h		;0550	20 f1 	    
	ex de,hl			;0552	eb 	  
	rst 28h			;0553	ef 	  
	add hl,sp			;0554	39 	9 
	ld b,h			;0555	44 	D 
	ld c,l			;0556	4d 	M 
	ld hl,l0005h+5		;0557	21 0a 00 	!     
	add hl,de			;055a	19 	  
	call l094ch		;055b	cd 4c 09 	  L   
	ld sp,hl			;055e	f9 	  
l055fh:
	ld hl,(02a95h)		;055f	2a 95 2a 	*   * 
	ex de,hl			;0562	eb 	  
	rst 30h			;0563	f7 	  
; 'NEXT'
; ======
; "NEXT" BASIC command

;; NEXT
l0564h:
	call l078bh	;0564	Call LOCATE_VARIABLE_ERR
	ld (02a9bh),hl	;0567	Load variable location into NEXT_VAR
l056ah:
	push de		;056a	Save parser address on stack

	ex de,hl	;056b	DE = NEXT_VAR

	ld hl,(02aa1h)	;056c	Load FOR_POINTER into HL

	ld a,h		;056f
	or l		;0570	
	jp z,l065bh	;0571	Jump to HOW_RST if FOR_POINTER is 0000h

	rst 10h		;0574	Run CMP_HL_DE

	jr z,l0580h	;0575	Jump to FIXME if FOR_POINTER == NEXT_VAR

	pop de		;0577	Remove DE from stack

	call l0959h	;0578	cd 59 09 	  Y   
	ld hl,(02a9bh)	;057b	2a 9b 2a 	*   * 
	jr l056ah	;057e	18 ea 	   

l0580h:
	call l0a45h	;0580	Call PUSH_FP
	call l0a6dh	;0583	Call FP_TO_INT

	ex de,hl	;0586	HL = NEXT variable address
			;	DE = NEXT variabe value

	ld hl,(02a91h)	;0587	Load FOR_STEP value into HL

	push hl		;058a	Save FOR_STEP to the stack

	add hl,de	;058b	HL = current NEXT variable value + FOR_STEP

	push hl		;058c	Save HL on stack

	call l0abch	;058d	Call INT_TO_FP

	ld hl,(02aa1h)	;0590	Load FOR_POINTER into HL
	call l073bh	;0593	Store new value into variable (call POP_FP)

	pop de		;0596	DE = value of the NEXT variable
	ld hl,(02a6eh)	;0597	HL = FOR_TO value 
	pop af	 	;059a	AF = FOR_STEP

	rlca		;059b	07 	  
	jr nc,l059fh	;059c	30 01 	0   

	ex de,hl		;059e	eb 	  
l059fh:
	ld a,h			;059f	7c 	| 
	xor d			;05a0	aa 	  
	jp p,l05a5h		;05a1	f2 a5 05 	      
	ex de,hl			;05a4	eb 	  
l05a5h:
	rst 10h			;05a5	d7 	  
	pop de			;05a6	d1 	  
	jp c,l0524h		;05a7	da 24 05 	  $   
	ld hl,(02a93h)		;05aa	2a 93 2a 	*   * 
	ld (02a9fh),hl		;05ad	22 9f 2a 	"   * 
	jr l055fh		;05b0	18 ad 	    
l05b2h:
	jp z,l0736h		;05b2	ca 36 07 	  6   
l05b5h:
	push hl			;05b5	e5 	  
	call l05fch		;05b6	cd fc 05 	      
	jr c,l05cah		;05b9	38 0f 	8   
	jr z,l05e2h		;05bb	28 25 	( % 
	ex (sp),hl			;05bd	e3 	  
	pop bc			;05be	c1 	  
l05bfh:
	ld a,(bc)			;05bf	0a 	  
	or a			;05c0	b7 	  
	jr z,l05edh		;05c1	28 2a 	( * 
	inc bc			;05c3	03 	  
	call l017eh		;05c4	cd 7e 01 	  ~   
	jr nz,l05bfh		;05c7	20 f6 	    
	ret			;05c9	c9 	  
l05cah:
	pop hl			;05ca	e1 	  
	rst 18h			;05cb	df 	  
; Following lines from Diss_020.jpg
	db '"'			;05cc
	db 000h			;05cd
l05ceh:
	call l05d9h		;05ce	cd d9 05 	  
	jr z,l05edh		;05d1	28 1a 	(   
	inc de			;05d3	13 	  
	call l017eh		;05d4	cd 7e 01 	  ~   
	jr nz,l05ceh		;05d7	20 f5 	    
l05d9h:
	ld a,(de)		;05d9	1a 	  
	cp 00dh		;05da	fe 0d 	    
	ret z			;05dc	c8 	  
	cp 022h		;05dd	fe 22 	  " 
	ret nz			;05df	c0 	  
	inc de			;05e0	13 	  
	ret			;05e1	c9 	  
l05e2h:
	dec de			;05e2	1b 	  
	call l0396h		;05e3	cd 96 03 	      
	jr z,l05cah		;05e6	28 e2 	(   
	pop hl			;05e8	e1 	  
	call l017eh		;05e9	cd 7e 01 	  ~   
	ret z			;05ec	c8 	  
l05edh:
	rst 18h			;05ed	df 	  
	dec hl			;05ee	2b 	+ 
	ld (bc),a			;05ef	02 	  
	jr l05b5h		;05f0	18 c3 	    
	ld (hl),000h		;05f2	36 00 	6   
l05f4h:
	call l017fh		;05f4	cd 7f 01 	     
	ret z			;05f7	c8 	  
	ld (hl),030h		;05f8	36 30 	6 0 
	jr l05f4h		;05fa	18 f8 	    
l05fch:
	call l0125h		;05fc	cd 25 01 	  %   
	ret c			;05ff	d8 	  
l0600h:
	dec de			;0600	1b 	  
	ld a,(de)			;0601	1a 	  
	inc de			;0602	13 	  
	cp 029h		;0603	fe 29 	  ) 
	ret z			;0605	c8 	  
	ld a,(de)			;0606	1a 	  
	cp 024h		;0607	fe 24 	  $ 
	jr z,l060dh		;0609	28 02 	(   
;; FIXME catch all
l060bh:
	xor a			;060b	af 	  
	ret			;060c	c9 	  
l060dh:
	inc de			;060d	13 	  
l060eh:
	ld a,l			;060e	7d 	} 
	sub 05ch		;060f	d6 5c 	  \ 
	jr nz,l061dh		;0611	20 0a 	    
	ld l,070h		;0613	2e 70 	. p 
	rst 18h			;0615	df 	  
	jr z,l061bh		;0616	28 03 	(   
	call l0114h		;0618	cd 14 01 	      
l061bh:
	or h			;061b	b4 	  
	ret			;061c	c9 	  
l061dh:
	cp 007h		;061d	fe 07 	    
	jp nc,l078fh		;061f	d2 8f 07 	      
	ld l,080h		;0622	2e 80 	.   
	or h			;0624	b4 	  
	ret			;0625	c9 	  
;; TAKE
l0626h:
	call l05fch		;0626	cd fc 05 	      
	jr c,l0663h		;0629	38 38 	8 8 
	push de			;062b	d5 	  
	push af			;062c	f5 	  
	push hl			;062d	e5 	  
	ld de,(02a9dh)		;062e	ed 5b 9d 2a 	  [   * 
	ld hl,(02c38h)		;0632	2a 38 2c 	* 8 , 
l0635h:
	rst 18h			;0635	df 	  
	inc hl			;0636	23 	# 
	ld (bc),a			;0637	02 	  
	jr l063dh		;0638	18 03 	    
	rst 18h			;063a	df 	  
	inc l			;063b	2c 	, 
	rrca			;063c	0f 	  
l063dh:
	pop hl			;063d	e1 	  
	pop af			;063e	f1 	  
	call l05b2h		;063f	cd b2 05 	      
l0642h:
	ld (02a9dh),de		;0642	ed 53 9d 2a 	  S   * 
	pop de			;0646	d1 	  
	rst 18h			;0647	df 	  
	inc l			;0648	2c 	, 
	ld b,e			;0649	43 	C 
	jr l0626h		;064a	18 da 	    
l064ch:
	ld a,(de)			;064c	1a 	  
	inc de			;064d	13 	  
	cp 00dh		;064e	fe 0d 	    
	jr nz,l064ch		;0650	20 fa 	    
	inc de			;0652	13 	  
	inc de			;0653	13 	  
	rst 10h			;0654	d7 	  
	jr nc,l0635h		;0655	30 de 	0   
	pop hl			;0657	e1 	  
l0658h:
	pop af			;0658	f1 	  
; from Diss_020.jph

	db 00eh			;0659	Dummy LD,C

; '"HOW?" ERROR RESTART'
; =======================
; This restart is called when an argument for a function or command is invalid.
; (for example out of range)

;; HOW_RST_PUSH_DE
l065ah:
	push de		;065a	Push current parser address on stack.

;; HOW_RST
l065bh:
	call l0799h	;065b	Call BASIC_ERROR
	dm "HOW?", 00dh ;065e

l0663h:
	rst 8			;0663	cf 	  
	push de			;0664	d5 	  
	call l07f2h		;0665	cd f2 07 	      
	inc de			;0668	13 	  
	inc de			;0669	13 	  
	jr l0642h		;066a	18 d6 	    
;; INPUT
l066ch:
	push de			;066c	d5 	  
	ld a,03fh		;066d	3e 3f 	> ? 
	call l07bdh		;066f	cd bd 07 	      
	ld de,02bb6h		;0672	11 b6 2b 	    + 
	rst 18h			;0675	df 	  
	dec c			;0676	0d 	  
	dec b			;0677	05 	  
	pop de			;0678	d1 	  
	call l05fch		;0679	cd fc 05 	      
	rst 30h			;067c	f7 	  
	pop de			;067d	d1 	  
	push de			;067e	d5 	  
	call l05fch		;067f	cd fc 05 	      
	jr c,l065bh		;0682	38 d7 	8   
	push de			;0684	d5 	  
	ld de,02bb6h		;0685	11 b6 2b 	    + 
	call l05b2h		;0688	cd b2 05 	      
	pop de			;068b	d1 	  
	pop af			;068c	f1 	  
	rst 30h			;068d	f7 	  

; 'EVALUATE ARITHMETIC OPERATORS'
; ===============================
; Evaluates an arithmetic expression at DE and returns its value on arithmetic
; stack.

;; EVAL_ARITHMETIC
l068eh:

; Start by checking for a leading "+" or "-" character.

	rst 18h		;068e	Call READ_PAR
	db '-'		;068f	
	db l0697h-$-1	;0690

; Leading "-" sign - add an implicit 0 to arithmetic stack and jump to 
; subtraction.

	rst 28h		;0691	Call CLEAR_HL
	call l0abch	;0692	Call INT_TO_FP
	jr l06abh	;0695	Jump to subtraction

l0697h:	
	rst 18h		;0697	Call READ_PAR
	db '+'		;0698
	db 000h		;0699

; Ignore a leading plus sign. Load level 2 value to arithmetic stack.

	call l06b3h	;069a	Call EVAL_LVL2

; Level 1 - Evaluation of addition and subtraction

;; EVAL_LVL1
l069dh:
	rst 18h		;069d	Call READ_PAR
	db '+'		;069e
	db l06a8h-$-1	;069f

; Addition. Load a value from level 2 and add them together

	call l06b3h	;06a0	Call EVAL_LVL2
	call l0b32h	;06a3	Call FP_ADD
	jr l069dh	;06a6	Jump back to EVAL_LVL1

l06a8h:
	rst 18h		;06a8	Call READ_PAR
	db '-'		;06a9
	db l078ah-$-1	;06aa	Return if operand is neither "+" nor "-"

; Subtraction. Load a value from level 2 and add them together

l06abh:
	call l06b3h	;06ab	Call EVAL_LVL2
	call l0b1eh	;06ae	Call FP_SUB
	jr l069dh	;06b1	Jump back to EVAL_LVL1

; Level 2 - Evaluation of multiplication and division

;; EVAL_LVL2
l06b3h:
	call l0393h	;06b3	Call EVAL_FUNCTIONS
l06b6h:
	rst 18h		;06b6	Call READ_PAR
	db '*'		;06b7
	db l06c1h-$-1	;06b8

; Multiplication

	call l0393h 	;06b9	Call EVAL_FUNCTIONS
	call l0ae6h	;06bc	Call FP_MUL
	jr l06b6h	;06bf	Return back to level 2 evaluation

l06c1h:
	rst 18h		;06c1	Call READ_PAR
	db '/'		;06c2
	db l078ah-$-1 	;06c3	Return if operand is neither "+" nor "-"

; Division

	call l0393h	;06c4	Call EVAL_FUNCTIONS
	call l0af7h	;06c7	Call FP_DIV
	jr l06b6h	;06ca	Return back to level 2 evaluation	  

; 'UNDOT'
; =======
; "UNDOT" BASIC command.

;; UNDOT
l06cch:
	ld a,001h	;06cc	Load 01h into A (Zf = 0, Sf = 0)

	db 001h		;06ce	Dummy ld bc,nn (skip next instruction)

; 'DOT'
; =====
; "DOT" BASIC command.

;; DOT
l06cfh:
	ld a,080h	;06cf	Load 80h into A (Zf = 0, Sf = 1)

	push af		;06d1	Store AF on stack

	rst 18h		;06d2	Call READ_PAR
	db '*'		;06d3
	db l06dah-$-1	;06d4

; DOT* and UNDOT* versions of command: turn clock on or off

	pop af		;06d5	Restore AF from stack

	ld (02bafh),a	;06d6	Store A into CLOCK_ON
	rst 30h		;06d9	Continue with the next command (call BASIC_NEXT)

l06dah:
	pop af		;06da	Restore AF from stack
	db 006h		;06db	Dummy "ld b,nn" (skip next two commands so that
			;	flags remain unchanged)

; 'DOT FUNCTION'
; ==============
; "DOT" BASIC function.

;; DOT_FUNC
l06dch:
	xor a		;06dc	Clear A, set Zf and clear Sf
	and a		;06dd

; Meaning of flags at this point:
;
; Zf	Sf	function
; -----------------------------------------
; 1	x	Query pixel (DOT function)
; 0	0	Clear pixel (UNDOT command)
; 0	1	Draw pixel  (DOT command)

	push af		;06de	Save A on stack

	rst 8		;06df	Get X coordinate (call EVAL_INT_EXP)
	push hl		;06e0	Save X on stack

	call l0005h	;06e1	Get Y coordinate (call EVAL_INT_EXP_NEXT)
	push de		;06e4	Save DE on stack
	ex de,hl	;06e5	Move Y to DE (actually E, since Y < 48)

	ld bc,32	;06e6	Load 32 into BC

	inc e		;06e9	Increment E
	ld hl,02800h	;06ea	Load VIDEO_MEM into HL

; HL = 2800h + 32 * (E / 3)
; A = 1 << (E % 3)

;; DOT_DIV_3_LOOP
l06edh:
	ld d,3		;06ed	Load 3 into D
	ld a,1		;06ef	Load 1 into A

;; DOT_DIV_1_LOOP
l06f1h:
	dec e		;06f1	Decrement E
	jr z,l06feh	;06f2	Break from loop if E = 0

	rlca		;06f4	Rotate A left 2 times
	rlca		;06f5

	dec d		;06f6	Decrement D, loop to DOT_DIV_1_LOOP if not zero
	jr nz,l06f1h	;06f7

	add hl,bc	;06f9	Add 32 to HL for each 3 decrements of E
	res 1,h		;06fa	HL = HL & 01ff
	jr l06edh	;06fc	Loop to DOT_DIV_3_LOOP

; HL contains address of the character line that holds the required graphics
; coordinates.

l06feh:
	ld b,a		;06fe	Save A to B (?)
	pop de		;06ff	Restore DE from stack

	ex (sp),hl	;0700	Save line address to stack, move X to HL

	res 7,l		;0701	X = X & 001f
	res 6,l		;0703

	srl l		;0705	X = X / 2

	jr nc,l070ah	;0707	Shift A left if X odd
	rlca		;0709
l070ah:

	ld h,000h	;070a	Clear H

	pop bc		;070c	Get line address from stack
	add hl,bc	;070d	Add X / 2.

	ld b,a		;070e	Save A to B

	pop af		;070f	Restore flags from stack
	ld a,b		;0710	

; HL now contains the address of the character, A contains the bitmask.

	jr nz,l071fh	;0711	If Zf not set, jump to DOT_DRAW_OR_CLEAR

; Check if pixel is set and return a floating point value 1 or 0

	bit 7,(hl)	;0713	If (HL) is not graphics character (bit 7 not
	jr z,l0718h	;0715	set), jump over and return 0.

	and (hl)	;0717	Check if bit in A is set in (HL)
l0718h:
	rst 28h		;0718	Call CLEAR_HL

	jr z,l071ch	;0719	If bit was set HL = 1 else HL = 0
	inc hl		;071b
l071ch:
	jp l0abch	;071c	Jump to INT_TO_FP and return

; Draw or clear the pixel

;; DOT_DRAW_OR_CLEAR
l071fh:
	push af		;071f	Save flags on stack

	bit 7,(hl)	;0720	If (HL) is not already a graphics character
	jr nz,l0726h	;0722	write a blank character (80h).
	ld (hl),080h	;0724	
l0726h:

	pop af		;0726	Restore flags from stack
	jp m,l072dh	;0727	If sign negative, draw a pixel, else clear
			;	a pixel.

	cpl		;072a	Clear bit in A in (HL)
	and (hl)	;072b 	
	db 006h		;072c	Dummy ld b,nn (skip next instruction)
l072dh:
	or (hl)		;072d	Set bit in A in (HL)

	ld (hl),a	;072e	Store result back to (HL)
	rst 30h		;072f	Continue with the next command (call BASIC_NEXT)

l0730h:
	call l078bh	;0730	Call LOCATE_VARIABLE_ERR

	rst 18h		;0733	Call READ_PAR
	db '='		;0734
	db l078fh-$-1	;0735	Else jump to WHAT_RST

l0736h:
	push hl			;0736	e5 	  
	call l0ab2h		;0737	cd b2 0a 	      
	pop hl			;073a	e1 	  

; 'POP FLOATING POINT NUMBER FROM STACK'
; ======================================
; Fetches a floating point number from the top of the arithmetic stack and
; stores it in 4-byte format at (HL).

; IX Offset	0	1	2	3	4
; ---------------------------------------------------
;		24 bit mantissa	(MSB)	Exp	Sign

; IX Offset	0        1        2	   3        4
; -------------------------------------------------------------
;		MMMMMMMM MMMMMMMM 1MMMMMMM EEEEEEEE S0000000
;		(LSB)		  (MSB)

; HL Offset	0        1        2	   3
; --------------------------------------------------
;		MMMMMMMM MMMMMMMM EMMMMMMM SEEEEEEE
;		(LSB)		  (MSB)

;; POP_FP
l073bh:
	call l090eh	;073b	Call SUB_IX_5

	ld bc,0004h	;073e	Load 4 into BC
	push de		;0741	Save HL and DE to stack
	push hl		;0742	

	ex de,hl	;0743	Store HL to DE
	push ix		;0744   Store IX to HL
	pop hl		;0746	

	ldir		;0747	Transfer 4 bytes from (IX) to (HL)
			;	DE = DE_orig + 4

	ex de,hl	;0749	Restore HL and DE

	dec hl		;074a	HL = HL_orig + 2
	dec hl		;074b
	rl (hl)		;074c	Rotate left (HL_orig + 2)

	inc hl		;074e	HL = HL_orig + 3
	ld a,(ix+4)	;074f	Sign bit to Cf
	rla		;0752	
	rr (hl)		;0753	Store sign bit to MSB of (HL_orig + 3)
			;	LSB of exponent to Cf.

	dec hl		;0755	HL = HL_orig + 2
	rr (hl)		;0756	Store LSB of exponent in MSB of (HL_orig + 2)

	pop hl		;0758	Restore HL and DE from stack
	pop de		;0759	
	ret		;075a	Return

;; CATCH-ALL-COMMAND
l075bh:
	call l05fch		;075b	cd fc 05 	      
	jr c,l0768h		;075e	38 08 	8   
	push af			;0760	f5 	  
	rst 18h			;0761	df 	  
	dec a			;0762	3d 	= 
	dec hl			;0763	2b 	+ 
	pop af			;0764	f1 	  
	call l05b2h		;0765	cd b2 05 	      
l0768h:
	rst 30h			;0768	f7 	  

;; PTR
l0769h:
	ld h,d			;0769	62 	b 
	ld l,e			;076a	6b 	k 
	call l05fch		;076b	cd fc 05 	      
	jr l071ch		;076e	18 ac 	    
;; VAL
l0770h:
	push de			;0770	d5 	  
	ex de,hl			;0771	eb 	  
	call l0ab2h		;0772	cd b2 0a 	      
	pop de			;0775	d1 	  
	ret			;0776	c9 	  

; 'BASIC NUMERIC EXPRESSION EVALUATION' 
; =====================================
; This function is called if no other BASIC function matches. It evaluates a
; numeric expression at DE.

;; NUMBER
l0777h:
	call l0125h	;0777	Call LOCATE_VARIABLE

	jp nc,l0a45h	;077a	Store variable contents on stack and return
			;	(call PUSH_FP)

; Not a variable

	call l01a2h	;077d	Call STRING_TO_FP
	ret nz		;0780	Return if valid.

; Not a constant

; 'EVALUATE PARENTHESIS'
; ======================
; This function evaluates an expression enclosed in parenthesis at DE 
; and returns its value on the top of arithmetic stack.

;; EVAL_PAREN
l0781h:
	rst 18h		;0781	Call READ_PAR
	db '('		;0782	
	db l078fh-$-1	;0783	If '(' not found, jump to WHAT_RST

	call l0ab2h	;0784	Call EVAL_EXPRESSION

	rst 18h		;0787	Call READ_PAR
	db ')'		;0788
	db l078bh-$-1	;0789

l078ah:
	ret		;078a	Return if closing ')' found

; Closing ')' not found.

; 'LOCATE VARIABLE OR ERROR'
; ==========================
; Like LOCATE_VARIABLE, but jumps to "WHAT?" error if variable is not found.

;; LOCATE_VARIABLE_ERR
l078bh:
	call l0125h	;078b	Call LOCATE_VARIABLE

	ret nc		;078e	Return if variable found, else continue to 
			;	WHAT_RST

; '"WHAT?" ERROR RESTART'
; =======================
; This restart is called when an unknown function or command is called.

;; WHAT_RST
l078fh:
	push de			;078f	Store current parser address on stack.

	call l0799h		;0790	Store address of the "WHAT?" string
				;	on the stack and call BASIC_ERROR.

	dm "WHAT?", 00dh	;0793

; 'BASIC ERROR'
; =============
; Pointer to the error message is the first 16 bit value on the CPU stack. 
; Current parser address is the second 16 bit value on the CPU stack.

;; BASIC_ERROR
l0799h:
	pop de		;0799	Load address of the error message into DE

	call l0937h	;079a	Call PRINTSTR

	ld de,(02a9fh)	;079d	Load BASIC_LINE into DE

	ld a,e		;07a1	
	or d		;07a2	Set Z flag if BASIC_LINE is zero.

	ld hl,l0317h	;07a3	Load RESET_BASIC_2 address into
	ex (sp),hl	;07a6	the address at the top of the stack
			;	and store stack value into HL.

			;	Top of the stack stores the current parser 
			;	address or return address of the calling 
			;	function.

	ret z		;07a7	Return into RESET_BASIC_2 if BASIC_LINE = 0

	rst 10h		;07a8	Call CMP_HL_DE

	ret c		;07a9	Return into RESET_BASIC_2 if 
			;	BASIC_LINE > current parser address

			;	(stack did not contain a valid parser address)

	ld c,(hl)	;07aa	Save character at current parser addr. into C
	push bc		;07ab	Store BC on stack

	ld (hl),000h	;07ac	Store 00h (ASCII NUL) to current parser addr.
	push hl		;07ae	Store HL on stack

	call l0931h	;07af	Call PRINT_BASIC_LINE

	pop hl		;07b2	Restore BC and HL from stack.
	pop bc		;07b3

	ld a,03fh	;07b4	Load ASCII '?' into A



l07b6h:
	dec de		;07b6	DE = BASIC_LINE - 1
	ld (hl),c	;07b7	Restore character at the current parser 
			;	address.

	jp l0936h	;07b8	Jump to	PUTCH_PRINTSTR and return into
			;	RESET_BASIC_2

; 'GET STRING FROM KEYBOARD'
; ==========================
; This function reads a string from the keyboard into the input buffer. String
; is terminated with ASCII CR. Some minimal editing is supported ("LEFT" key
; acts as a backspace, "SHIFT-DELECT" clears the buffer and screen)

; Returns:
;	DE: Address of the last character in the string + 1

;; GETSTR
l07bbh:
	ld a,'>'	;07bb	Load prompt into A

l07bdh:
	ld de,02bb6h	;07bd	Load INPUT_BUFFER address into DE
	rst 20h		;07c0 	Display prompt.

;; GETSTR_LOOP_CURS
l07c1h:
	exx		;07c1
	ld (hl),'_'	;07c2	Print cursor at location (HL')
	exx		;07c4	Note: HL' is set by PUTCH_RST.

;; GETSTR_LOOP
l07c5h:
	call l0cf5h	;07c5	Read a key and print it (call KEY)
	rst 20h		;07c8	(call PUTCH_RST)

	exx		;07c9	
	ld (hl),'_'	;07ca	Print cursor
	exx		;07cc

	cp 00dh		;07cd	
	jr z,l07ddh	;07cf	"ENTER" pressed, jump to GETSTR_ADD

	cp 01dh		;07d1	
	jr z,l07eah	;07d3	"LEFT" pressed, jump to GETSTR_BACKSPACE

	cp 00ch		;07d5
	jr z,l07bbh	;07d7	"SHIFT-DELETE" pressed - begin from the start

	cp 020h		;07d9	 	    
	jr c,l07c5h	;07db	Ignore if key code is less than 20h otherwise

;; GETSTR_ADD
l07ddh:
	ld (de),a	;07dd	Load ASCII code of the pressed key into the
	inc de		;07de	buffer and increment DE

	cp 00dh		;07df	If "ENTER" was pressed, return.
	ret z		;07e1

	ld a,e		;07e2	Compare DE with 2c36h (end of buffer)
	cp 034h		;07e3

	jr nz,l07c5h	;07e5	If end of buffer not reached, 
			;	loop to GETSTR_LOOP...

	ld a,01dh	;07e7	...else delete last pressed character from the
	rst 20h		;07e9	   screen and buffer.

;; GETSTR_BACKSPACE
l07eah:
	ld a,e		;07ea	Compare DE with 2bb6h (start of buffer)
	cp 0b6h		;07eb	
	jr z,l07bbh	;07ed	If not at start of buffer decrement DE
	dec de		;07ef	
	jr l07c1h	;07f0	Jump to GETSTR_LOOP_CURS    

; 'FIND BASIC LINE'
; =================
; Finds BASIC line with line number equal or greater than HL in the entire 
; BASIC code.

;; FIND_LINE
l07f2h:
	ld de,(02c36h)	;07f2	Load BASIC_START into DE and continue with
			;	FIND_LINE_SCOPE

; 'FIND BASIC LINE IN SCOPE'
; ==========================
; Finds BASIC line with line number equal or greater than HL, starting at DE. 
; If line number was not found after DE, Cf is set.

; Parameters:
;	DE: Pointer to the start of a BASIC line where the search starts.
;	HL: Line number to find.
; Returns:
;	DE: Pointer to the start of the BASIC line if a matching line number 
;           is found
;	Cf: Set if line number was not found.
;	Zf: Set if line number found is equal to HL.

;; FIND_LINE_SCOPE
l07f6h:
	push hl		;07f6	Save HL on stack

; Check if DE is within the expected margins of the BASIC program.

	ld hl,(02c36h)	;07f7	Load BASIC_START-1 into HL
	dec hl		;07fa

	rst 10h		;07fb	(call CMP_HL_DE)
	jp nc,l0317h	;07fc	Jump to RESET_BASIC_2 if DE < BASIC_START

	ld hl,(02c38h)	;07ff	Load BASIC_END-1 into HL
	dec hl		;0802

	rst 10h		;0803	(call CMP_HL_DE)

	pop hl		;0804	Restore HL

	ret c		;0805	Return if DE >= BASIC_END

	ld a,(de)	;0806	Subtract HL from 16-bit line number at (DE)
	sub l		;0807	
	ld b,a		;0808
	inc de		;0809	
	ld a,(de)	;080a	
	sbc a,h		;080b	BA = (DE)-HL

l080ch:
	jr c,l0812h	;080c	Jump to FIND_LINE_NEXT if HL > line number

	dec de		;080e	Decrement DE

	or b		;080f	Check if HL is equal to line number at (DE)

	ret		;0810	Return

l0811h:
	inc de		;0811	Increment DE

; Increments DE until start of the next BASIC line.

;; FIND_LINE_NEXT
l0812h:
	inc de		;0812	Increment DE (points to first character after
			;	line number)

; 'FIND NEXT BASIC LINE'
; ========================
; A call to this location moves DE to the start of the next BASIC line if 
; HL contains 0000h.

;; FIND_LINE_NEXT_2
l0813h:
	ld a,(de)	;0813	Load character into A

	cp 00dh		;0814
	jr nz,l0812h	;0816	Loop until equal to CR

l0818h:
	inc de		;0818	Increment DE (points to line number of the next
			;	line)

	jr l07f6h	;0819	Loop

;; FIXME: catch all
l081bh:
	inc de			;081b	13 	  
l081ch:
	ld a,(de)			;081c	1a 	  
	rst 28h			;081d	ef 	  
	cp 00dh		;081e	fe 0d 	    
	jr z,l0818h		;0820	28 f6 	(   
	cp 021h		;0822	fe 21 	  ! 
	jr z,l0812h		;0824	28 ec 	(   
	cp 022h		;0826	fe 22 	  " 
	jr nz,l0834h		;0828	20 0a 	    
l082ah:
	inc de			;082a	13 	  
	ld a,(de)			;082b	1a 	  
	cp 00dh		;082c	fe 0d 	    
	jr z,l0818h		;082e	28 e8 	(   
	cp 022h		;0830	fe 22 	  " 
	jr nz,l082ah		;0832	20 f6 	    
l0834h:
	cp 045h		;0834	fe 45 	  E 
	jr nz,l081bh		;0836	20 e3 	    
	ld l,0f6h		;0838	2e f6 	.   
	jp l0398h		;083a	c3 98 03 	      

; 'PRINT A FLOATING POINT NUMBER (cont.)'
; =======================================
; Prints a floating point number on the top of the arithmetic stack at the 
; current cursor position. Number must not be zero.

; IX Offset	-5	-4	-3	-2	-1
; ---------------------------------------------------
;		24 bit mantissa	(MSB)	Exp	Sign

;; PRINTFP_DO


; First print the sign character and make the floating point number positive.

l083dh:
	ld a,(ix-1)	;083d	Load sign bit into A
	and a		;0840	
	ld a,' '	;0841	If sign is positive, store ASCII ' ' in A
			;	else store ASCII '-'.
	jr z,l0847h	;0843	
	ld a,'-'	;0845
l0847h:

	rst 20h		;0847	Print sign character (call PUTCH_RST)

	xor a		;0848
	ld (ix-1),a	;0849	Clear sign bit.

	dec a		;084c	A = -1

; Convert the number into floating point format with base of exponent 10.

;; PRINTFP_MUL10_LOOP
l084dh:
	push af		;084d	Store AF to stack

	ld hl,l002ch	;084e	Load FP_ONE_OVER_TEN address into HL

	call l0b05h	;0851	Call FP_COMPARE_HL

	jr nc,l0863h	;0854	If number printed is greater or equal to 0.1, 
			;	jump to next step.

	call l0ae3h	;0856	Multiply number by 10 (call FP_MUL_10)

	pop af		;0859	Restore AF from stack

	dec a		;085a	Decrement A

	jr l084dh	;085b	Jump to PRINTFP_MUL10_LOOP

;; PRINTFP_DIV10_LOOP
l085dh:
	call l0af4h	;085d	Divide number by 10 (call FP_DIV_10)
	pop af		;0860	Restore AF from stack
	inc a		;0861	Increment A
	push af		;0862	Save AF to stack

l0863h:
	ld hl,l00a0h	;0863	Load FP_ONE address into HL
	call l0b05h	;0866	Call FP_COMPARE_HL

	jr nc,l085dh	;0869	If number is greater or equal to 1,
			;	jump to PRINTFP_DIV10_LOOP

; M = abs( N * 10^(-1 - A) )

; 1 > M >= 0.1

; where N is the original number, and M is the number in HL' C' HL and at the
; top of the arithmetic stack. A is stored at the top of the arithmetic stack.

	ld a,(ix-2)	;086b	Load negative exponent (base 2) into A
	neg		;086e

; Apply base 2 exponent to the number's mantissa

;; PRINTFP_APPLY_EXP2
l0870h:
	jr z,l087dh	;0870	Break from loop if exponent is zero.
	exx		;0872
	srl c		;0873	Shift mantissa right (divide by 2)
	rr h		;0875
	rr l		;0877
	exx		;0879
	dec a		;087a	Decrement exponent
	jr l0870h	;087b	Loop to PRINTFP_APPLY_EXP2


; M = O * 2^(-24)

; where O is the number in HL' C'

; Build 8 digit binary-coded decimal at the top of the arithmetic stack

l087dh:
	ld b,7		;087d	B = 7
	push ix		;087f	HL = IX (top of arithmetic stack)
	pop hl		;0881	
	ld (hl),000h	;0882	Load 0 into first BCD digit.
	inc hl		;0884	Increment HL

; This loop multiplies O by 10 in each iteration and stores the part of O
; that is before decimal point into (HL)

;; PRINTFP_BCD_LOOP
l0885h:

	xor a		;0885	Clear A
	call l024fh	;0886	Call FP_MUL_10_ADD_A

	exx		;0889	
	ld a,b		;088a
	exx		;088b
	ld (hl),a	;088c	Load B' (mantissa overflow) into HL
	inc hl		;088d	Increment HL

	djnz l0885h	;088e	Loop 7 times to PRINTFP_BCD_LOOP

; HL	-8	-7	-6	-5	-4	-3	-2	-1
; -------------------------------------------------------------------
;	0	X	X	X	X	X	X	Y

;	<-- most significant                least significant --> 

; P = M * 10^7 = abs( N * 10^(6 - A) )

; Round the lowest X digit up, if Y digit >= 5.

	ld bc,l0600h	;0890	B = 6
			;	C = 0 	

	dec hl		;0893	Decrement HL
	ld a,(hl)	;0894	
	cp 5		;0895	Compare last digit with 5

; Propagate carry and also set the bitmap in C

;; PRINTFP_ROUND_LOOP
l0897h:
	ccf		;0897	Cf set if >=5, reset if <5
			;	Cf set if carry from the previous decimal digit.

	ld a,0		;0898	Add 1 to the digit one place higher if Cf set.
	dec hl		;089a	
	adc a,(hl)	;089b
	sla c		;089c	Shift C left
	cp 10		;089e	Compare corrected digit with 10

	jr c,l08a4h	;08a0	
	ld a,000h	;08a2	Load 0 into A if greater or equal to 10
l08a4h:

	ld (hl),a	;08a4	Load corrected digit into (HL)
	push af		;08a5	Save Cf on stack

	and a		;08a6	
	jr z,l08abh	;08a7	If digit not zero, set bit 0 of C.
	set 0,c		;08a9	
l08abh:
	pop af		;08ab	Restore Cf from stack
	djnz l0897h	;08ac	Loop 6 times to PRINTFP_ROUND_LOOP

	ld a,c		;08ae	Load bitmask into A

	pop bc		;08af	Restore exponent from stack into B
	jr c,l08b8h	;08b0	If no carry on the most significant digit, 
			;	break from loop...
	inc b		;08b2   ...else increment base 10 exponent
	push bc		;08b3	   Save exponent back to stack

	ld b,001h	;08b4	  
	jr l0897h	;08b6      loop one more time to PRINTFP_ROUND_LOOP

; P = abs( N * 10^(6 - A) )

l08b8h:
	ld c,a		;08b8	Move bitmask back to C
	ld a,b		;08b9	Move exponent back to A

	inc a		;08ba	Jump to PRINTFP_EXP if A not between 0 and 6
	jp m,l08c8h	;08bb	
	cp 7		;08be	
	jr nc,l08c8h	;08c0	

; No exponential notation necessary. Just print the mantissa and exit.

	ld b,a		;08c2	Exponent to B
	call l091ch	;08c3	Call PRINT_BCD

	jr l090bh	;08c6	Finish (remove stored values from stack, and
			;	return)

; Number either too large or too small. Print in exponential notation.

;; PRINTFP_EXP
l08c8h:
	push bc		;08c8	Save exponent and bitmask to stack

	ld b,001h	;08c9	Print mantissa 	
	call l091ch	;08cb	(call PRINT_BCD)

	ld a,'E'	;08ce	Print exponent character 'E'
	rst 20h		;08d0

; Convert exponent into decimal and print it.

	pop bc		;08d1	Restore BC from stack

	bit 7,b		;08d2	Check sign bit of the exponent

	ld a,'+'	;08d4	
	jr z,l08e0h	;08d6	If exponent positive, jump to PRINTFP_EXP_POS

; Exponent base 10 is negative

	ld a,'-'	;08d8	Print minus sign
	rst 20h		;08da	(call PUTCH_RST)

	ld a,b		;08db	Load negative exponent base 10 into A
	neg		;08dc	
	jr l08e2h	;08de	Jump to PRINTFP_EXP_ABS

;; PRINTFP_EXP_POS
l08e0h:
	rst 20h		;08e0	Print plus sign (call PUTCH_RST)
	ld a,b		;08e1	Load exponent base 10 into A

; Absolute value of exponent base 10 in A. Now split exponent into two decimal
; digits: B contains tens (+ ASCII offset), A contains ones.

;; PRINTFP_EXP_ABS
l08e2h:
	ld b,'0'	;08e2	Initialize B
l08e4h:
	cp 10		;08e4	
	jr c,l0904h	;08e6	Jump to PRINTFP_END if number of ones is less 
			;	than 10.

	add a,-10	;08e8	Subtract 10 from number of ones and add 1 to
	inc b		;08ea 	the number of tens.

	jr l08e4h	;08eb	Loop

; 'PRINT A 16 BIT NUMBER'
; =======================
; Prints a 16 bit number at DE to the screen at current cursor position.

; Parameters:
;	DE: Pointer to the 16 bit number to print.
; Returns:
;	DE: DE + 2

;; PRINT_WORD
l08edh:
	ld a,(de)	;08ed	Load BASIC line number (at DE) into HL and
	ld l,a		;08ee	DE = DE + 2
	inc de		;08ef	
	ld a,(de)	;08f0	
	ld h,a		;08f1	
	inc de		;08f2

	call l0abch	;08f3	Push line number to arithmetic stack
			;	(Call INT_TO_FP)

; 'PRINT A FLOATING POINT NUMBER'
; ===============================
; Prints a floating point number on the top of the arithmetic stack at the 
; current cursor position.

; IX Offset	-5	-4	-3	-2	-1
; ---------------------------------------------------
;		24 bit mantissa	(MSB)	Exp	Sign

;; PRINTFP
l08f6h:
	push de		;08f6	Save BC,DE and HL to stack
	push bc		;08f7	
	push hl		;08f8

	ld a,(ix-2)	;08f9	
	cp 080h		;08fc	
	jp nz,l083dh	;08fe	Jump to PRINTFP_DO if line number is not 0

	xor a		;0901	Clear A
	ld b,020h	;0902	Load ASCII ' ' into B

;; PRINTFP_END
l0904h:
	or 030h		;0904	Convert integer in A to ASCII numeral
	ld c,a		;0906	and store it into C

	ld a,b		;0907	Print character in B
	rst 20h		;0908	(Call PUTCH_RST)
	ld a,c		;0909	Print character in C
	rst 20h		;090a	(Call PUTCH_RST)

l090bh:
	pop hl		;090b	Restore HL and BC from stack
	pop bc		;090c

; 'STORE ARITHMETIC RESULT & RETURN (cont.)'
; ==========================================
; Restores DE register from CPU stack, removes the top value from the 
; arithmetic stack and returns.

;; STORE_ARITHM_RET_2
l090dh:
	pop de		;090d	

; 'SUB IX,5'
; ==========
; Subtracts 5 from the contents of the IX register. Stores -5 in BC.

;; SUB_IX_5
l090eh:
	ld bc,0fffbh	;090e	Load -5 into BC

; ADD_IX_10 jumps here
l0911h:
	add ix,bc	;0911	Add BC to IX
	ret		;0913	Return

; 'CORRECT EXPONENT & ADD IX,10'
; ==============================
; Corrects exponent of FP number in HL C' HL' and adds 10 to IX (

;; CORRECT_EXP_ADD_IX_10
l0914h:
	call l0c4ch	;0914	Call CORRECT_EXP

; 'ADD IX,10'
; ===========
; Adds 10 to the contents of the IX register. Stores 10 in BC.

;; ADD_IX_10
l0917h:
	ld bc,0000ah	;0917	Load 10 into BC
	jr l0911h	;091a	Jump forward

; 'PRINT A BINARY-CODED DECIMAL NUMBER'
; =====================================
; Prints a BCD number at HL. Each byte represents one digit. B holds the number
; of digits before decimal point.

; Parameters:
;	HL: Pointer to the BCD number.
;	B: Location of the decimal point (after B digits)
;	C: Bitmap of the digits (0 means zero digit, 1 means non-zero digit)

; BCD digit	HL+7	HL+6	HL+5	HL+4	HL+3	HL+2	HL+1	HL
; C bit		7	6	5	4	3	2	1	0

;; PRINT_BCD
l091ch:
	inc b		;091c 	

;; PRINT_BCD_LOOP
l091dh:
	djnz l0922h	;091d	Decrement B. 

	ld a,'.'	;091f	Print decimal point if B == 0
	rst 20h		;0921	(call PUTCH_RST)
l0922h:

	ld a,(hl)	;0922	Print BCD digit in (HL)
	or 030h		;0923	
	rst 20h		;0925	(call PUTCH_RST)

	inc hl		;0926	Move HL to the next digit.

	srl c		;0927	Shift C right and...
	jr nz,l091dh	;0929	...loop to PRINT_BCD_LOOP if there are further 
			;	   non-zero digits

; There are only zeroes left. Note: B remains unmodified.

	dec b		;092b	
	dec b		;092c	
	ret m		;092d	Return if B <= 1  
	inc b		;092e	

	jr l091ch	;092f	Restart to PRINT_BCD.

; 'PRINT A BASIC LINE TO SCREEN'
; ==============================
; Print a complete BASIC line to screen. First the line number is printed,
; followed by ASCII space and line contents.

; Parameters:
;	DE: Pointer to the BASIC line.

;; PRINT_BASIC_LINE
l0931h:
	call l08edh	;0931	Print line number (call PRINT_WORD)
	ld a,020h	;0934	Load ASCII ' ' into A

; 'PRINT A CHARACTER FOLLOWED BY A STRING TO SCREEN'
; ==================================================
; Call PUTCH_RST and PRINTSTR

;; PUTCH_PRINTSTR
l0936h:
	rst 20h		;0936	Call PUTCH_RST

; 'PRINT A STRING TO SCREEN'
; ==========================
; Print a string of characters at (DE) to the screen at the current cursor 
; position (CURSOR_POS).

; String must be terminated with 00h (NUL) or 0d (CR). In the second case a
; new line added at the end of the string.

; Parameters:
;	DE: Address of the first character in the string.
; Returns:
;	Zf: Set if string ended with NUL, reset if it ended with CR.
;	HL': Address of the last printed character on screen + 1
;	DE: Address of the last read character + 1
; Destroys:
;	A,B,flags

;; PRINTSTR
l0937h:
	xor a		;0937	A = ASCII NUL

; 'PRINT A STRING TO SCREEN ENDING ON A'
; ======================================
; Like PRINTSTR, except string is terminated with character in A (which is not 
; printed) or CR (which is printed).

; Returns:
;	Zf: Set if string ended with character in A, reset if it ended with CR.

;; PRINTSTR_A
l0938h:
	ld b,a		;0938	Load A into B

l0939h:
	ld a,(de)	;0939	Load character pointed by DE into A
	inc de		;093a	Increment DE

	cp b		;093b	Compare A with B...
	ret z		;093c	...and return if equal

	rst 20h		;093d	Call PUTCH_RST

	cp 00dh		;093e	Compare A with 0dh (CR)...
	jr nz,l0939h	;0940	...and loop if not equal

	inc a		;0942	Increment A
	ret		;0943	Return.

; 'MOVE MEMORY BLOCK'
; ===================
;
; -------------     -------------
; |source     |     |destination|
; -------------     -------------
; ^            ^    ^
; |            |    |
; DE           HL   BC

;; MOVE_MEM
l0944h:
	rst 10h		;0944	Call CMP_HL_DE
	ret z		;0945	Return if HL == DE

	ld a,(de)	;0946	(BC) = (DE)
	ld (bc),a	;0947	

	inc de		;0948	Increment BC and DE
	inc bc		;0949	

	jr l0944h	;094a	Loop

l094ch:
	ld a,b			;094c	78 	x 
	sub d			;094d	92 	  
	jr nz,l0953h		;094e	20 03 	    
	ld a,c			;0950	79 	y 
	sub e			;0951	93 	  
	ret z			;0952	c8 	  
l0953h:
	dec de			;0953	1b 	  
	dec hl			;0954	2b 	+ 
	ld a,(de)			;0955	1a 	  
	ld (hl),a			;0956	77 	w 
	jr l094ch		;0957	18 f3 	    
l0959h:
	pop bc			;0959	c1 	  
	pop hl			;095a	e1 	  
	ld (02aa1h),hl		;095b	22 a1 2a 	"   * 
	ld a,h			;095e	7c 	| 
	or l			;095f	b5 	  
	jr z,l0972h		;0960	28 10 	(   
	pop hl			;0962	e1 	  
	ld (02a91h),hl		;0963	22 91 2a 	"   * 
	pop hl			;0966	e1 	  
	ld (02a6eh),hl		;0967	22 6e 2a 	" n * 
	pop hl			;096a	e1 	  
	ld (02a93h),hl		;096b	22 93 2a 	"   * 
	pop hl			;096e	e1 	  
	ld (02a95h),hl		;096f	22 95 2a 	"   * 
l0972h:
	push bc			;0972	c5 	  
	ret			;0973	c9 	  

l0974h:
	ld hl,-02b38h	;0974	     
	pop bc		;0977	Remove BC from stack
	add hl,sp	;0978	 
	jp nc,l0153h	;0979	Jump to SORRY_RST_PUSH_DE if SP < 2b38h

	ld hl,(02aa1h)	;097c	2a a1 2a 	*   * 
	ld a,h		;097f	7c 	| 
	or l		;0980	b5 	  
	jr z,l0996h	;0981	28 13 	(   

	ld hl,(02a95h)		;0983	2a 95 2a 	*   * 
	push hl			;0986	e5 	  
	ld hl,(02a93h)		;0987	2a 93 2a 	*   * 
	push hl			;098a	e5 	  
	ld hl,(02a6eh)		;098b	2a 6e 2a 	* n * 
	push hl			;098e	e5 	  
	ld hl,(02a91h)		;098f	2a 91 2a 	*   * 
	push hl			;0992	e5 	  
	ld hl,(02aa1h)		;0993	2a a1 2a 	*   * 

l0996h:
	push hl			;0996	e5 	  
	push bc			;0997	c5 	  
	ret			;0998	c9 	  

; 'EVALUATE RELATIONAL OPERATORS'
; ===============================
; Evaluates a relational operator at DE and returns HL = 1 if true or HL = 0
; if false.

; If a relational expression is not found, it returns two functions up.

; Returns:
;	HL: Result of the relational operator.

;; EVAL_RELATIONAL
l0999h:
	rst 18h		;0999	Call READ_PAR
	db '>'		;099a
	db l09a3h-$-1	;099b

	call l0439h	;099c	Call EVAL_RELATIONAL_2

	ret z		;099f	Return HL = 1 if greater
	ret c		;09a0
	inc hl		;09a1
	ret		;09a2

l09a3h:
	rst 18h		;09a3	Call READ_PAR  
	db '='		;09a4
	db l09ach-$-1	;09a5	

	call l0439h	;09a6	Call EVAL_RELATIONAL_2

	ret nz		;09a9	Return HL = 1 if equal
	inc hl		;09aa	
	ret		;09ab	

l09ach:
	rst 18h		;09ac	Call READ_PAR
	db '<'		;09ad
	db l0a02h-$-1	;09ae	Return two functions up.

	call l0439h	;09af	Call EVAL_RELATIONAL_2
	ret nc		;09b2	Return HL = 1 if less
	inc hl		;09b3	
	ret		;09b4

; 'PUT CHARACTER ON SCREEN'
; =========================
; Print a character in A to the screen at the current cursor position 
; (CURSOR_POS).

; This function holds Galaksija's "terminal emulation" routines. Several
; special ASCII characters are recognized if C flag is set. Video output
; can be redirected with the use of VIDEO_LINK.

; Parameters:
;	A: Character to print
;	C flag: Character is considered special if C flag is set
; Returns:
;	HL: Position of the printed character + 1

; Destroys:
;	BC,DE

;; PUTCH
l09b5h:
	push af		;09b5	Push AF to stack
	call 02bach	;09b6	Call VIDEO_LINK
	ld hl,(02a68h)	;09b9	Load CURSOR_POS into HL

	jr c,l0a04h	;09bc	If carry set, jump to SPECIAL_CHAR

	ld (hl),a	;09be	Write character in A to screen
	inc hl		;09bf	Increment HL

; Scroll the screen if necessary

;; PUTCH_SCROLL
l09c0h:
	ld a,02ah	;09c0	Load 2ah into A
	cp h		;09c2	Compare with H
	jr nz,l09ffh	;09c3	If cursor is still within video memory,
			;	jump to PUTCH_END.

; Scroll screen contents content up one line, skipping WINDOW_LEN characters
; on top.

	ld hl,02bb0h	;09c5	Load SCROLL_CNT address into HL
	call l0a3dh	;09c8	Call WAIT_INT (wait for soft scroll to finish)

	push hl		;09cb	Push HL to stack
	inc hl		;09cc	Increment HL (now points to SCROLL_FLAG)

	inc (hl)	;09cd	Set SCROLL_FLAG
	call l0a3dh	;09ce	Call WAIT_INT (sync to video refresh)

	or a		;09d1	?

	ld de,(02a6ch)	;09d2	Load WINDOW_LEN into DE
	res 1,d		;09d6	Reset bit 1 of D

	ld hl,001e0h	;09d8	Load 480 into HL (32 characters * 15 lines)
	sbc hl,de	;09db	Substract DE from HL

	jr z,l09edh	;09dd	Jump forward if result is zero...
	jr c,l09edh	;09df	...or less

	ld b,h		;09e1	Load HL into BC
	ld c,l		;09e2	(number of characters moved)

	set 3,d		;09e3	D = D | 28h
	set 5,d		;09e5

	ld hl,32	;09e7	HL (source) = DE (dest) + 32 
	add hl,de	;09ea	(one line of characters lower)

	ldir		;09eb	Block transfer 

; Soft scroll screen up one line, if WINDOW_LEN is zero

l09edh:
	ld hl,(02a6ch)	;09ed	Load WINDOW_LEN into HL 

	ld a,h		;09f0	Load top byte of WINDOW_LEN into A
	or l		;09f1	A = A | L

	pop hl		;09f2	Pop HL from stack (HL points to SCROLL_CNT)

	jr nz,l09f7h	;09f3	If WINDOW_LEN is not zero, jump forward...
	ld (hl),003h	;09f5	Else load 3 into SCROLL_CNT

; Clear bottom line

l09f7h:
	ld hl,029e0h	;09f7	Load 29e0h into HL (start of the bottom line
			;	on the screen)
	push hl		;09fa	Push HL on stack
	call l0a34h	;09fb	Call CLEAR_LINE
	pop hl		;09fe	Pop HL from stack

; Update cursor position and return.

;; PUTCH_END
l09ffh:
	ld (02a68h),hl	;09ff	Update cursor position

l0a02h:
	pop af		;0a02	Pop AF from stack
	ret		;0a03	Return

; Interpret special characters

;; SPECIAL_CHAR
l0a04h:
	cp 00dh		;0a04	Compare A with 0dh (ASCII CR)	    
	jr nz,l0a16h	;0a06	If not equal jump forward

; Put cursor on the next line

	ld a,h		;0a08	Load A with H
	cp 02bh		;0a09	Compare H with 2bh (is cursor on screen?)

	jr c,l0a11h	;0a0b	If H less than 2bh jump forward...
	ld (hl),00dh	;0a0d	...else put character on screen
	jr l09ffh	;0a0f	   and jump to PUTCH_END

l0a11h:
	call l0a34h	;0a11	Call CLEAR_LINE (puts cursor on the start
			;	of the next line)
	jr l09c0h	;0a14	Jump to PUTCH_SCROLL

l0a16h:
	cp 00ch		;0a16	Compare A with 0ch (ASCII FF)
	jr nz,l0a27h	;0a18	If not equal jump forward

; Clear screen

	ld hl,029ffh	;0a1a	Load 29ffh to HL (last character on screen)
l0a1dh:
	ld (hl),020h	;0a1d	Load 20h (ASCII space) to (HL)
	dec hl		;0a1f	Decrement HL
	bit 1,h		;0a20	Test bit 1 of H
	jr z,l0a1dh	;0a22	If zero, loop

l0a24h:
	inc hl		;0a24	Increment HL 
			;	(points to the first char on screen)
	jr l09ffh	;0a25	Jump to PUTCH_SCROLL

l0a27h:
	cp 01dh		;0a27	Compare A with 1dh (ASCII GS)    
	jr nz,l09ffh	;0a29	If not equal jump to PUTCH_END

; Clear current character and move cursor one position back

	ld (hl),020h	;0a2b	Load 20h (ASCII space) to (HL)
	dec hl		;0a2d	Decrement HL

	bit 1,h		;0a2e	Test bit 1 of H
	jr nz,l0a24h	;0a30	If not zero (cursor went off screen), jump
			;	to increment back HL.
	jr l09ffh	;0a32	Jump to PUTCH_END

; 'CLEAR LINE'
; ============
; This function fills a line with ASCII space (20h) characters from the 
; location pointed by HL to the end of the line.

; Parameters:
;	HL: Pointer to the start of the line to be filled.
; Returns:
;	HL: Pointer to the start of the next line
; Destroys:
;	A, flags

;; CLEAR_LINE
l0a34h:
	ld (hl),020h	;0a34	Store ASCII space at location pointed to by HL
	inc hl		;0a36	Increment HL

	ld a,l		;0a37	Load L into A
	and 01fh	;0a38	A = A & 1fh

	jr nz,l0a34h	;0a3a	If A not zero, loop...
	ret		;0a3c	...else return

; 'WAIT FOR INTERRUPT'
; ====================
; This function waits for an interrupt routine to reset a flag pointed to
; by HL register.

; Function returns immediately if interrupts are disabled.

; Parameters:
;	HL: pointer to the flag (interrupt must set this to 0)
; Destroys:
;	A, flags

;; WAIT_INT
l0a3dh:
	ld a,i		;0a3d	Load FF2 state into P/V flag
	ret po		;0a3f	Return if interrupts are disabled

l0a40h:
	ld a,(hl)	;0a40	Load flag byte into A
	or a		;0a41	Update Z flag
	jr nz,l0a40h	;0a42	If byte is not zero, loop...
	ret		;0a44	...else return

; 'PUSH FLOATING POINT NUMBER ON STACK'
; =====================================
; Stores a 4-byte floating point number at (HL) on the arithmetic stack.

; IX Offset	0	1	2	3	4
; ---------------------------------------------------
;		24 bit mantissa	(MSB)	Exp	Sign

; IX Offset	0        1        2	   3        4
; -------------------------------------------------------------
;		MMMMMMMM MMMMMMMM 1MMMMMMM EEEEEEEE S0000000
;		(LSB)		  (MSB)

; HL Offset	0        1        2	   3
; --------------------------------------------------
;		MMMMMMMM MMMMMMMM EMMMMMMM SEEEEEEE
;		(LSB)		  (MSB)

;; PUSH_FP
l0a45h:
	push de		;0a45	Save DE, HL and AF on stack
	push hl		;0a46	
	push af		;0a47	

	ld bc,00004h	;0a48	Load 4 into BC

	push ix		;0a4b	Load IX into DE
	pop de		;0a4d

	ldir		;0a4e	Transfer 4 bytes starting from (HL) into (IX)

	rl (ix+2)	;0a50	Extract sign bit from IX+2 and IX+3
	rl (ix+3)	;0a54

	ld a,b		;0a58	Store sign bit in IX+4
	rra		;0a59	
	ld (ix+4),a	;0a5a

	scf		;0a5d	Set top bit of mantissa
	rr (ix+2)	;0a5e

	ld c,005h	;0a62	IX = IX + 5
	add ix,bc	;0a64	

	pop af		;0a66	Restore DE, HL and AL from stack
	pop hl		;0a67	
	pop de		;0a68	

	ret		;0a69	Return

; 'EVALULATE INTEGER VALUE IN PARENTHESIS'
; ========================================
; Evaluates expression in parenthesis at DE, converts it to integer and returns
; it in DE.

;; EVAL_PAREN_INT
l0a6ah:
	call l0781h	;0a6a	Call EVAL_PAREN

; 'FLOATING POINT TO INTEGER'
; ===========================
; Convert floating point at the top of the arithmetic stack to integer.

; Returns:
;	HL: Integer value

;; FP_TO_INT
l0a6dh:
	exx		;0a6d	
	call l090eh	;0a6e	Call SUB_IX_5

	ld de,l0000h	;0a71	Clear DE'

; IX Offset	0	1	2	3	4
; ---------------------------------------------------
;		24 bit mantissa	(MSB)	Exp	Sign

	ld a,(ix+3)	;0a74	Load exponent into A
	ld c,(ix+4)	;0a77	Load sign into C'

	cp 080h		;0a7a	Return 0 if exponent equal to -128
	jr z,l0aaah	;0a7c	

	cp 001h		;0a7e	Return 0 if exponent less than 1
	jp m,l0aaeh	;0a80	(why not jump to l0aaah like above?)

	cp 010h		;0a83	Jump to error if exponent greater than 16
	exx		;0a85	
	jp p,l065ah	;0a86	
	exx		;0a89	

; DE = mantissa * 2 ^ exponent

	ld b,a		;0a8a	Load exponent into B'

	ld a,(ix+000h)	;0a8b	Load mantissa into HL' A'
	ld l,(ix+001h)	;0a8e	
	ld h,(ix+002h)	;0a91

l0a94h:
	sla a		;0a94	Shift left HL' A'
	adc hl,hl	;0a96

	rl e		;0a98	Shift left DE'
	rl d		;0a9a

	djnz l0a94h	;0a9c	Loop

l0a9eh:
	sla c		;0a9e	Jump forward if sign is positive 
	jr nc,l0aaah	;0aa0	

	or h		;0aa2	Increment DE' if HL' A' not zero
	or l		;0aa3	
	jr z,l0aa7h	;0aa4
	inc de		;0aa6
l0aa7h:
	call l0ad7h	;0aa7	DE' = -DE' (Call NEG_DE)

l0aaah:
	push de		;0aaa	Load result into HL
	exx		;0aab	
	pop hl		;0aac 	  
	ret		;0aad	Return

l0aaeh:
	ld a,0ffh	;0aae	Set A to -1
	jr l0a9eh	;0ab0	

; 'EVALUATE NUMERIC EXPRESSION'
; =============================
; Evaluate numeric expression at DE and push the result on the arithmetic 
; stack.

;; EVAL_EXPRESSION
l0ab2h:
	call l068eh	;0ab2	Call EVAL_ARITHMETIC
	call l0999h	;0ab5	Call EVAL_RELATIONAL
			;	Returns to the calling function, if no
			;	relational operator found.

	db 001h		;0ab8	Dummy ld bc,nn (skip the following instruction)

; 'PUSH 10 TO ARITHMETIC STACK'
; ============================
; Pushes floating point constant 10 to the arithmetic stack.

;; PUSH_FP_10
l0ab9h:
	ld hl,0000ah	;0ab9

; Push result from EVAL_RELATIONAL to stack.

; 'INTEGER TO FLOATING POINT'
; ===========================
; Converts integer in HL to floating point and stores it into the arithmetic
; stack.

; Parameters:
;	HL: Integer to convert.	

;; INT_TO_FP
l0abch:
	push de		;0abc	Save DE on stack.

;; INT_TO_FP_2
l0abdh:
	ex de,hl	;0abd	DE = integer to convert

	call l0917h	;0abe	Call ADD_IX_10
	call l0ad4h	;0ac1	Call ABS_DE

	push de		;0ac4	Save DE on stack

	ld hl,0010h	;0ac5	Load 16 into L
	rr h		;0ac8	Set MSB of H to sign bit.

	exx		;0aca

	pop de		;0acb	Restore DE' from stack
	rst 28h		;0acc	Clear HL' (Call CLEAR_HL)
	ld h,e		;0acd	Load E' into H'
	ld c,d		;0ace	Load D' into C'

; IX Offset	-5	-4	-3	-2	-1
; ---------------------------------------------------
;		L'	H'	C'	L	H
; ---------------------------------------------------
;		24 bit mantissa	(MSB)	Exp	Sign

	call l0c4ch	;0acf	Call CORRECT_EXP
	jr l0b03h	;0ad2	Jump to STORE_ARITHM_RET_0

; 'ABSOLUTE VALUE DE'
; ===================
; Calculates absolute value of integer in DE.

; Parameters:
;	DE
; Returns:
;	DE: Absolute value.
;       Cf: Set if DE was negative, reset otherwise.
; Destroys:
;	A

;; ABS_DE
l0ad4h:
	xor a		;0ad4	Clear A
	add a,d		;0ad5	Add D to A.
	ret p		;0ad6	Return if D positive, otherwise continue to 
			;	NEG_DE

; 'NEGATE DE'
; ===========
; Negates the value of integer in DE.

; Parameters:
;	DE
; Returns:
;	DE: Absolute value.
;       Cf: Always Set.
; Destroys:
;	A

;; NEG_DE
l0ad7h:
	ld a,e		;0ad7	E = -E
	neg		;0ad8	
	ld e,a		;0ada

	ld a,d		;0adb	D = ~D + ~Cf
	cpl		;0adc	
	ccf		;0add	
	adc a,000h	;0ade	
	ld d,a		;0ae0 	

	scf		;0ae1	Set carry flag
	ret		;0ae2	Return

; 'MULTIPLY BY 10'
; ================
; Multiplies the number on the top of the arithmetic stack by 10

;; FP_MUL_10
l0ae3h:
	call l0ab9h	;0ae3	Push 10 on the arithmetic stack 
			;	(call PUSH_FP_10)

;; FP_MUL
l0ae6h:
	call l0c68h	;0ae6	Call FETCH_TWO_FP
	jr z,l0b29h	;0ae9	If first operand is zero, just remove the 
			;	second operand from stack and return (jumps 
			;	to STORE_ARITHM_RET_2)

	cp e		;0aeb	If the second operand is zero, store a zero
	jp z,l0b6bh	;0aec	floating point value on stack and return
			;	(jump to STORE_ZERO_RET)

	call l0b81h	;0aef	Call FP_MUL_DO
	jr l0b03h	;0af2	Jump to STORE_ARITHM_RET_0

; 'DIVIDE BY 10'
; ================
; Divides the number on the top of the arithmetic stack by 10

;; FP_DIV_10
l0af4h:
	call l0ab9h	;0af4	Push 10 on the arithmetic stack
			;	(call PUSH_FP_10)
;; FP_DIV
l0af7h:
	call l0c68h		;0af7	cd 68 0c 	  h   
	jr z,l0b29h		;0afa	28 2d 	( - 
	cp e			;0afc	bb 	  
	jp z,l065bh		;0afd	ca 5b 06 	  [   
	call l0baeh		;0b00	cd ae 0b 	      

; 'STORE ARITHMETIC RESULT TRAMPOLINE'
; ====================================

;; STORE_ARITHM_RET_0
l0b03h:
	jr l0b6dh		;0b03	Jump to STORE_ARITHM_RET

; 'COMPARE VARIABLE WITH ARITHMETIC STACK'
; ========================================
; Compares the number at the top of the arithmetic stack with the 4-byte
; floating point at (HL)

;; FP_COMPARE_HL
l0b05h:
	call l0a45h	;0b05	Call PUSH_FP
	call l0c68h	;0b08	Call FETCH_TWO_FP

	ld bc,0fffbh	;0b0b	Load -5 into BC	      
	jr l0b16h	;0b0e	Jump into FP_COMPARE (remove the only the value
			;	pushed on the stach by PUSH_FP)


; 'COMPARE TWO FLOATING POINT NUMBERS'
; ====================================
; Pops two floating point numbers from the top of the arithmetic stack, 
; compares them and returns the result in the flags register.

;; FP_COMPARE
l0b10h:
	call l0c68h	;0b10	Call FETCH_TWO_FP
	ld bc,0fff6h	;0b13	
l0b16h:
	add ix,bc	;0b16	Subtract -10 from IX

	cp l		;0b18	Compare A (80h) with L  
	call l0be6h	;0b19	Jump to the rest of the function

	pop de		;0b1c	Restore DE
	ret		;0b1d	Return

;; FP_SUB
l0b1eh:
	call l0c68h		;0b1e	cd 68 0c 	  h   
	jr nz,l0b28h		;0b21	20 05 	    
	call l0b62h		;0b23	cd 62 0b 	  b   
	jr l0b58h		;0b26	18 30 	  0 
l0b28h:
	cp e			;0b28	bb 	  
l0b29h:
	jr z,l0b7eh	;0b29	Jump to STORE_ARITHM_RET_2
	xor d			;0b2b	aa 	  
	ld d,a			;0b2c	57 	W 
	jr l0b3ah		;0b2d	18 0b 	    
	call l0a45h		;0b2f	cd 45 0a 	  E   

; 'ADD TWO FLOATING POINT NUMBERS'
; ================================
; Pops two numbers from the top of the arithmetic stack, adds them and pushes
; the result on the stack.

; IX Offset	-5	-4	-3	-2	-1
; ---------------------------------------------------
;		E'	D'	B'	E	D
; ---------------------------------------------------
;		24 bit mantissa	(MSB)	Exp	Sign

; IX Offset	-10	-9	-8	-7	-6
; ---------------------------------------------------
;		L'	H'	C'	L	H
; ---------------------------------------------------
;		24 bit mantissa	(MSB)	Exp	Sign

;; FP_ADD
l0b32h:
	call l0c68h	;0b32	Call FETCH_TWO_FP
	jr z,l0b63h	;0b35	Second number is zero.

	cp e		;0b37	
	jr z,l0b7eh	;0b38	First number is zero. Just remove the second 
			;	operand from stack.

			;	Jump to STORE_ARITHM_RET_2

l0b3ah:
	call l0c04h	;0b3a	Call FP_COMPARE_ABS
	jr z,l0b4dh	;0b3d	Mantissa and exponent are equal

	jr nc,l0b48h	;0b3f	If DE' B' DE > HL' C' HL, exchange operands

	ex de,hl	;0b41	exchange DE' B' DE and HL' C' HL
	exx		;0b42	
	ex de,hl	;0b43	
	ld a,c		;0b44	
	ld c,b		;0b45
	ld b,a		;0b46
	exx		;0b47

l0b48h:
	call l0c17h	;0b48	Call FP_ADD_DO
	jr l0b6dh	;0b4b	Jump to STORE_ARITHM_RET

; Mantissa and exponent of operands are equal

l0b4dh:
	ld a,h		;0b4d	A = XOR of both sign bits
	xor d		;0b4e
	jr nz,l0b6bh	;0b4f	Signs different: jump to STORE_ZERO_RET

	ld e,001h	;0b51	Signs equal: Multiply by 2
	call l0c3fh	;0b53	Jump to FP_MUL_EXP

	jr l0b6dh	;0b56	Jump to STORE_ARITHM_RET

l0b58h:
	ld a,(ix-1)		;0b58	dd 7e ff 	  ~   
	xor 080h		;0b5b	ee 80 	    
	ld (ix-1),a		;0b5d	dd 77 ff 	  w   
	pop de			;0b60	d1 	  
	ret			;0b61	c9 	  
l0b62h:
	push de			;0b62	d5 	  

; Second operand of addition is zero.

;; FP_ADD_ZERO_2
l0b63h:
	ld h,d		;0b63	HL' C' HL = DE' B' DE
	ld l,e		;0b64	
	exx		;0b65	
	ld l,e		;0b66
	ld h,d		;0b67
	ld c,b		;0b68
	exx		;0b69

	db 001h		;0b6a	Dummy ld bc,nn (skip ld l,080h)

; 'STORE ZERO RESULT & RETURN'
; ============================

;; STORE_ZERO_RET
l0b6bh:
	ld l,080h	;0b6b

; 'STORE ARITHMETIC RESULT & RETURN'
; ==================================
; JP to this location is used by arithmetic functions with two operands to
; store the result on the arithmetic stack at IX. 

; DE pointer is restored from CPU stack before returning.

; Top two values are removed from the stack and the Floating point number in
; HL' C' HL is stored.

; IX Offset	-5	-4	-3	-2	-1
; ---------------------------------------------------
;		L'	H'	C'	L	H
; ---------------------------------------------------
;		24 bit mantissa	(MSB)	Exp	Sign

;; STORE_ARITHM_RET
l0b6dh:
	ld (ix-6),h		;0b6d	Store result in the second-to-last  
	ld (ix-7),l		;0b70	stack location.
	exx			;0b73	
	ld (ix-10),l		;0b74	
	ld (ix-9),h		;0b77	
	ld (ix-8),c		;0b7a
	exx			;0b7d

l0b7eh:
	jp l090dh		;0b7e	Jump to STORE_ARITHM_RET_2

; 'MULTIPLY TWO FLOATING POINT NUMBERS (cont.)'
; =============================================
; Multiplies two floating point numbers (both not equal to zero).

; (first operand, result)

; IX Offset	-5	-4	-3	-2	-1
; ---------------------------------------------------
;		E'	D'	B'	E	D
; ---------------------------------------------------
;		24 bit mantissa	(MSB)	Exp	Sign

; (second operand)

; IX Offset	-10	-9	-8	-7	-6
; ---------------------------------------------------
;		L'	H'	C'	L	H
; ---------------------------------------------------
;		24 bit mantissa	(MSB)	Exp	Sign

;; FP_MUL_DO
l0b81h:
	ld a,h		;0b81	Sign bit of the result = XOR sign bits of
	xor d		;0b82	operands.
	ld h,a		;0b83

	dec e		;0b84	Decrement first exponent.

	push hl		;0b85	Save HL and BC on stack
	push bc		;0b86	

	ld b,018h	;0b87	06 18 	    
	call l0c81h	;0b89	cd 81 0c 	      

	xor a		;0b8c	af 	  

	rst 28h		;0b8d	Call CLEAR_HL

	ld c,a			;0b8e	4f 	O 
l0b8fh:
	exx			;0b8f	d9 	  
	srl c		;0b90	cb 39 	  9 
	rr h		;0b92	cb 1c 	    
	rr l		;0b94	cb 1d 	    
	exx			;0b96	d9 	  
	jr nc,l0b9dh		;0b97	30 04 	0   
	add hl,de			;0b99	19 	  
	ld a,c			;0b9a	79 	y 
	adc a,b			;0b9b	88 	  
	ld c,a			;0b9c	4f 	O 
l0b9dh:
	exx			;0b9d	d9 	  
	djnz l0ba5h		;0b9e	10 05 	    
	pop bc			;0ba0	c1 	  
	pop hl			;0ba1	e1 	  
	exx			;0ba2	d9 	  
	jr l0bd5h		;0ba3	18 30 	  0 
l0ba5h:
	exx			;0ba5	d9 	  
	rr c		;0ba6	cb 19 	    
	rr h		;0ba8	cb 1c 	    
	rr l		;0baa	cb 1d 	    
	jr l0b8fh		;0bac	18 e1 	    
l0baeh:
	ld a,e			;0bae	7b 	{ 
	neg		;0baf	ed 44 	  D 
	ld e,a			;0bb1	5f 	_ 
	ld a,h			;0bb2	7c 	| 
	xor d			;0bb3	aa 	  
	ld h,a			;0bb4	67 	g 
	push hl			;0bb5	e5 	  
	push bc			;0bb6	c5 	  
	ld b,019h		;0bb7	06 19 	    
	exx			;0bb9	d9 	  
l0bbah:
	sbc hl,de		;0bba	ed 52 	  R 
	ld a,c			;0bbc	79 	y 
	sbc a,b			;0bbd	98 	  
	ld c,a			;0bbe	4f 	O 
	jr nc,l0bc4h		;0bbf	30 03 	0   
	add hl,de		;0bc1	19 	  
	adc a,b			;0bc2	88 	  
	ld c,a			;0bc3	4f 	O 
l0bc4h:
	exx			;0bc4	d9 	  
	ccf			;0bc5	3f 	? 
	adc hl,hl		;0bc6	ed 6a 	  j 
	rl c		;0bc8	cb 11 	    
	djnz l0bd7h		;0bca	10 0b 	    
	push hl			;0bcc	e5 	  
	push bc			;0bcd	c5 	  
	exx			;0bce	d9 	  
	pop bc			;0bcf	c1 	  
	pop hl			;0bd0	e1 	  
	exx			;0bd1	d9 	  
	pop bc			;0bd2	c1 	  
	pop hl			;0bd3	e1 	  
	exx			;0bd4	d9 	  
l0bd5h:
	jr l0c35h		;0bd5	18 5e 	  ^ 
l0bd7h:
	exx			;0bd7	d9 	  
	add hl,hl			;0bd8	29 	) 
	rl c		;0bd9	cb 11 	    
	jr nc,l0bbah		;0bdb	30 dd 	0   
	ccf			;0bdd	3f 	? 
	sbc hl,de		;0bde	ed 52 	  R 
	ld a,c			;0be0	79 	y 
	sbc a,b			;0be1	98 	  
	ld c,a			;0be2	4f 	O 
	or a			;0be3	b7 	  
	jr l0bc4h		;0be4	18 de 	    

; 'COMPARE TWO FLOATING POINT NUMBERS (cont.)'
; ============================================

;		E'	D'	B'	E	D
; ---------------------------------------------------
;		24 bit mantissa	(MSB)	Exp	Sign

;		L'	H'	C'	L	H
; ---------------------------------------------------
;		24 bit mantissa	(MSB)	Exp	Sign


; signs	A B	- -	- +	+ -	+ +
; |A| > |B|	A < B	A < B	A > B	A > B
; |A| = |B|	A = B	A < B	A > B	A = B
; |A| < |B|	A > B	A < B	A > B	A < B

;; FP_COMPARE_2
l0be6h:
	jr z,l0bf2h	;0be6	HL' C' HL == 0 

	cp e		;0be8	
	jr z,l0bfah	;0be9	DE' B' DE == 0

	ld a,h		;0beb	A = XOR of both sign bits
	xor d		;0bec	(resets Cf)

	call z,l0c04h	;0bed	Call FP_COMPARE_ABS if signs are equal

			;	Different signs: Cf = 0, Zf = 0

			;	Equal signs:				Cf Zf
			;		|HL' C' HL| > |DE' B' DE| :	0  0
			;		|HL' C' HL| = |DE' B' DE| :	0  1
			;		|HL' C' HL| < |DE' B' DE| :	1  0

	jr l0bf9h	;0bf0	Jump forward

l0bf2h:
	cp e		;0bf2	Return if both numbers are 0
	ret z		;0bf3

			;	HL' C' HL == 0
			;	DE' B' DE != 0

	scf		;0bf4			Cf Zf
	bit 7,d		;0bf5	DE' B' DE > 0 :	1  1
			;	DE' B' DE < 0 :	1  0

	jr l0bfch	;0bf7	

l0bf9h:
	ret z		;0bf9	Return if sign, mantissa and exponent are equal

; also jumps here if DE' B' DE == 0 (Cf = 0)

l0bfah:				
			;			Zf
	bit 7,h		;0bfa	HL' C' HL > 0 : 1
			;	HL' C' HL < 0 :	0

; Cf	Zf	Result	Cf	Zf
; ------------------------------------
; 0	0		1	0
; 0	1		0	1
; 1	0		0	0
; 1	1		1	1

l0bfch:
	ccf		;0bfc	
	ret nz		;0bfd 	Return with complemented Cf if Zf = 0
	ccf		;0bfe	

	rra		;0bff	A = A | 01h
	scf		;0c00	
	rl a		;0c01	Clear Zf
	
	ret		;0c03	Return with original Cf if Zf = 1

; 'COMPARE ABSOLUTE VALUES'
; =========================
; Compares mantissa and exponent of two floating point numbers.

; Parameters:
;	DE' B' DE, HL' C' HL: Floating point numbers to compare

; Returns:
;	Cf, Zf: Result of (HL' C' HL - DE' B' DE) comparisson.

;		E'	D'	B'	E	D
; ---------------------------------------------------
;		24 bit mantissa	(MSB)	Exp	Sign

;		L'	H'	C'	L	H
; ---------------------------------------------------
;		24 bit mantissa	(MSB)	Exp	Sign

;; FP_COMPARE_ABS
l0c04h:
	ld a,l		;0c04	Subtract exponents
	sub e		;0c05	

	jr z,l0c0fh	;0c06	Equal exponents: Compare mantissa

	jp po,l0c0dh	;0c08	Negate top bit of result on overflow
	neg		;0c0b	
l0c0dh:
	rlca		;0c0d	Shift top bit into Cf
	ret		;0c0e	Return

l0c0fh:
	exx		;0c0f	
	ld a,c		;0c10	Compare top bytes of mantissa
	cp b		;0c11	
	jr nz,l0c15h	;0c12	
	rst 10h		;0c14	Compare lower two bytes if top bytes equal
			;	(Call CMP_HL_DE)
l0c15h:
	exx		;0c15	
	ret		;0c16	Return


; 'ADD TWO FLOATING POINT NUMBERS (cont.)'
; ========================================
; Adds number in DE' B' DE to HL' C' HL. HL' C' HL must be larger than 
; DE' B' DE.

; IX Offset	-5	-4	-3	-2	-1
; ---------------------------------------------------
;		E'	D'	B'	E	D
; ---------------------------------------------------
;		24 bit mantissa	(MSB)	Exp	Sign

; IX Offset	-10	-9	-8	-7	-6
; ---------------------------------------------------
;		L'	H'	C'	L	H
; ---------------------------------------------------
;		24 bit mantissa	(MSB)	Exp	Sign

;; FP_ADD_DO
l0c17h:
	ld a,l		;0c17	
	sub e		;0c18	A = L - E
	jr z,l0c29h	;0c19	Jump forward if exponents already equal

	cp 24		;0c1b	
	ret nc		;0c1d	If L - E >= 24, return
			;	(DE' B' DE is too small to affect HL' C' HL)

; Make exponents equal

	exx		;0c1e	
l0c1fh:
	srl b		;0c1f	Shift mantissa (DE' B') right
	rr d		;0c21	
	rr e		;0c23
	dec a		;0c25	Loop A times
	jr nz,l0c1fh	;0c26

	exx		;0c28

l0c29h:
	ld e,000h	;0c29	Clear
	ld a,h		;0c2b	A = XOR both sign bits
	xor d		;0c2c	 	  

	jp m,l0c46h	;0c2d	Signs different

	exx		;0c30	HL' C' = HL' C' + DE' B'
	add hl,de	;0c31
	ld a,c		;0c32
	adc a,b		;0c33
	ld c,a		;0c34
l0c35h:
	jr nc,l0c3eh	;0c35	If carry, rotate mantissa right to
	rr c		;0c37	include the carry bit.
	rr h		;0c39	
	rr l		;0c3b	
	scf		;0c3d	Clear carry flag.
l0c3eh:
	exx		;0c3e

; Multiply with Cf and return

; 'MULTIPLY FLOATING POINT NUMBER WITH 2^(E+Cf)'
; ==============================================
; Multiplies floating point number in HL' C' HL with 2^(E+Cf)

; Parameters:
;	E, Cf: Number to multiply with
;	HL' C' HL: Floating point number
; Return:
;	HL' C' HL: Result

;; FP_MUL_EXP
l0c3fh:
	ld a,l		;0c3f	A = L + E + Cf
	adc a,e		;0c40
l0c41h:
	jp pe,l0c61h	;0c41	Jump to CORRECT_EXP_OVERFLOW if exponent 
			;	overflowed...  
	ld l,a		;0c44	...else load A into L and return
	ret		;0c45	

l0c46h:
	exx			;0c46	d9 	  
	sbc hl,de		;0c47	ed 52 	  R 
	ld a,c			;0c49	79 	y 
	sbc a,b			;0c4a	98 	  
	ld c,a			;0c4b	4f 	O 

; 'CORRECT EXPONENT'
; ==================
; This function removes any leading zeros in the mantissa and corrects
; the exponent.

; It is always called with the C' HL' register set selected.

; Parameters:
;	HL C' HL': Input floating point number
; Returns:
;	HL C' HL': Corrected floating point number.

;; CORRECT_EXP
l0c4ch:
	ld b,018h	;0c4c	Load 24 into B'
	xor a		;0c4e	Clear A

	inc c		;0c4f	Set S flag for C'
	dec c		;0c50	
l0c51h:
	jp m,l0c5dh	;0c51	Break from loop top bit of C' HL' set

	dec a		;0c54	Decrement A

	add hl,hl	;0c55	Shift C' HL' left
	rl c		;0c56	 

	djnz l0c51h	;0c58	Loop

; all 24 bits of C' HL' are zero.

;; CORRECT_EXP_ZERO
l0c5ah:
	ld l,080h	;0c5a	Set exponent to -128
	ret		;0c5c	Return

l0c5dh:
	exx		;0c5d
	add a,l		;0c5e	Add L to A
	jr l0c41h	;0c5f	Check for overflow.

; Negative overflow in the exponent occured.

;; CORRECT_EXP_OVERFLOW
l0c61h:
	ld a,h		;0c61	
	or a		;0c62
	jp p,l0658h	;0c63	Jump to "HOW?" error if number was positive...
	jr l0c5ah	;0c66	...else jump to CORRECT_EXP_ZERO

; 'FETCH TWO FLOATING POINT NUMBERS FROM STACK'
; =============================================
; Fetches two floating point number from the top of the arithmetic stack and
; stores them HL' C' HL and DE' B' DE registers. Does not decrement IX.

; Returns:
;	A: 80h
;	DE' B' DE: First floating point number
;	HL' C' HL: Second floating point number
;	Zf: Set if second number is 0.

; IX Offset	-5	-4	-3	-2	-1
; ---------------------------------------------------
;		E'	D'	B'	E	D
; ---------------------------------------------------
;		24 bit mantissa	(MSB)	Exp	Sign

; IX Offset	-10	-9	-8	-7	-6
; ---------------------------------------------------
;		L'	H'	C'	L	H
; ---------------------------------------------------
;		24 bit mantissa	(MSB)	Exp	Sign

;; FETCH_TWO_FP
l0c68h:
	pop hl			;0c68	
	push de			;0c69	Store DE and HL on stack
	push hl			;0c6a	

	ld d,(ix-1)		;0c6b	
	ld e,(ix-2)		;0c6e
	ld h,(ix-6)		;0c71
	ld l,(ix-7)		;0c74
	exx			;0c77
	ld e,(ix-5)		;0c78
	ld d,(ix-4)		;0c7b
	ld b,(ix-3)		;0c7e
l0c81h:
	ld l,(ix-10)		;0c81
	ld h,(ix-9)		;0c84
	ld c,(ix-8)		;0c87
	exx			;0c8a

	ld a,080h		;0c8b	Is second number equal to zero?
	cp l			;0c8d

	ret			;0c8e 	Return	  

; 'RANDOM'
; ========
; "RND" BASIC command.
;
; This pseudo-random number generator pushes a random floating point number
; on the arithmetic stack.

;; RND
l0c8fh:
	push de		;0c8f	Save DE on stack

	exx		;0c90	

	ld hl,02aa7h	;0c91	Load RND_SEED address into HL'
	push hl		;0c94	Save HL' on stack

	ld e,(hl)	;0c95	Load contents of RND_SEED into DE' B'
	inc hl		;0c96	
	ld d,(hl)	;0c97	
	inc hl		;0c98	 	
	ld b,(hl)	;0c99	

	exx		;0c9a	

			;	Clear HL' C' HL

	call l0248h	;0c9b	Call CLEAR_CX_HLX_B6
	rst 28h		;0c9e	Call CLEAR_HL

	ld c,003h	;0c9f	Load 03h into C
l0ca1h:
	ld b,008h	;0ca1	Load 8 into B
	ld d,(hl)	;0ca3	Load (HL) into D

l0ca4h:
	exx		;0ca4	
	add hl,hl	;0ca5	Rotate HL' C' left
	rl c		;0ca6  
	exx		;0ca8	

	rl d		;0ca9	Rotate D left
	jr nc,l0cb3h	;0cab	Add DE' B' if top bit of D is set...

	exx		;0cad	
	add hl,de	;0cae   HL' C' = HL' C' + DE' B'
	ld a,c		;0caf
	adc a,b		;0cb0	
	ld c,a		;0cb1	
	exx		;0cb2	

l0cb3h:
	djnz l0ca4h	;0cb3	Loop 8 times

	inc hl		;0cb5	Increment HL

	dec c		;0cb6	Decrement C
	jr nz,l0ca1h	;0cb7	Loop 3 times

	rst 28h		;0cb9	Call CLEAR_HL

	exx		;0cba	
	pop de		;0cbb	Restore RND_SEED address from stack into DE'

	ld a,l		;0cbc	L' = L' + 65h
	add a,065h	;0cbd	(RND_SEED) = L'
	ld (de),a	;0cbf
	inc de		;0cc0	Increment DE'
	ld l,a		;0cc1	

	ld a,h		;0cc2	H' = H' + b0h + Cf
	adc a,0b0h	;0cc3	(RND_SEED+1) = H'
	ld (de),a	;0cc5
	inc de		;0cc6	Increment DE'
	ld h,a		;0cc7	

	ld a,c		;0cc8	C' + 05h + Cf
	adc a,005h	;0cc9	(RND_SEED+2) = C'
	ld (de),a	;0ccb	
	ld c,a		;0ccc	

	call l0914h	;0ccd	Call CORRECT_EXP_ADD_IX_10
	jp l0b6dh	;0cd0	Jump to STORE_ARITHM_RET

; 'CONVERT STRING TO AN INTEGER'
; ==============================
; Converts string at DE into an integer. String must start with a numeral.

; Parameters:
;	DE: Pointer to the string to be converted.
; Returns:
;	HL: Converted integer or 0 on error.
;	Zf: Set on error or clears on success.
;	DE: First character after the converted number.

;; STRING_TO_INT
l0cd3h:
	rst 28h		;0cd3	Call CLEAR_HL
	call l0105h	;0cd4	Call EAT_SPACE

	call l0172h	;0cd7	Check if the next character is a number 
			;	(call CHAR_TO_INT)

	jr c,l0ce3h	;0cda	If it's not, jump forward

	dec de		;0cdc	Decrement DE (step back to character used for 
			;	CHAR_TO_INT)

			;	Convert the string at DE to integer in HL.

	call l01a2h	;0cdd	Call STRING_TO_FP
	call l0a6dh	;0ce0	Call FP_TO_INT
l0ce3h:
	ld a,h		;0ce3	Check if HL contains 0 (either the number
	or l		;0ce4	read is 0 or the conversion failed)

	ret		;0ce5	Return

; 'READ A KEY FROM KEYBOARD'
; ==========================
; Waits for a key press on the keyboard and returns the code of the pressed
; key in A (for most keys this means the ASCII code of the character printed
; on the key. Special keys return their own scan code).

; A press to the "list" key causes a jump to the LIST function.

; A press to the "break" key causes a jump to the BREAK function.

; Returns:
;	A: Code of the key pressed
; Destroys:
;	Flags

; A key had been seen as released. Key code in A. Address in DE.

; Clear the key's position in KEY_DIFF (HL), if this key has been recently
; pressed.

;; KEY_RELEASED
l0ce6h:
	cp h		;0ce6	Compare A with H...
	jr nz,l0cebh	;0ce7	...and jump forward if not equal

	ld h,000h	;0ce9	...else reset H
l0cebh:
	cp l		;0ceb	Compare A with L...
	jr nz,l0cf0h	;0cec	...and jump to KEY_READ_NEXT if not equal

	ld l,000h	;0cee	...else reset L

; Scan the next key, or start from the beginning if on the last key.

;; KEY_READ_NEXT
l0cf0h:

	dec e		;0cf0	Decrement E, move to the next key
	jr nz,l0cfeh	;0cf1	Jump to KEY_READ if more keys to read
	jr l0cfbh	;0cf3	Jump to KEY_RESTART if on the last key.

; Entry point into the function

;; KEY
l0cf5h:
	exx		;0cf5	Save BC, DE and HL registers

	ld hl,(02aa5h)	;0cf6	Load KEY_DIFF into HL

	ld c,00eh	;0cf9	Load 0eh into C (speed of the "repeat" key)

; Restart scanning from the beginning.

;; KEY_RESTART
l0cfbh:
	ld de,02034h	;0cfb	Load 2034h into DE
			;	This is the address of the last key on the
			;	keyboard except for "shift".

;; KEY_READ
l0cfeh:
	ld a,(de)	;0cfe	Load (DE) into A
	rrca		;0cff	Rotate A right through carry flag
	ld a,e		;0d00	Load E (code of the current key) into A

	jr c,l0ce6h	;0d01	Jump to KEY_RELEASED if low bit of A is set.

	cp 032h		;0d03	Compare A with 32h...
	jr nz,l0d0fh	;0d05	...and jump to KEY_PRESSED, if not equal

; "rept" key is pressed. This key is special because it causes the last 
; keypress to be repeated.

	dec c		;0d07	Decrement C...
	jr nz,l0ce6h	;0d08	...and jump to KEY_RELEASED if not zero

	ld a,(02bb4h)	;0d0a	Load LAST_KEY into A
	jr l0d54h	;0d0d	Jump to KEY_END

; A key had been seen as pressed. Key code in A. Address in DE.

;; KEY_PRESSED
l0d0fh:
	cp h		;0d0f	Compare A with H...
	jr z,l0cf0h	;0d10	...and jump to KEY_READ_NEXT if equal

	cp l		;0d12	Compare A with L...
	jr z,l0cf0h	;0d13	...and jump to KEY_READ_NEXT if equal

; Wait for 256 cycles for key release (to filter out switch bounces)

	ld b,000h	;0d15	Clear B
l0d17h:
	rst 10h		;0d17	Call CMP_HL_DE (pause)

	ld a,(de)	;0d18	Load (DE) into A
	rrca		;0d19	Rotate A right through carry flag...
	jr c,l0ce6h	;0d1a	...and jump to KEY_RELEASED if carry set.

	djnz l0d17h	;0d1c	Loop 256 times

; Fill in an empty position in KEY_DIFF (HL)

	ld a,h		;0d1e	Load H into A
	or a		;0d1f	Set Z flag...
	jr nz,l0d25h	;0d20	...and jump forward if A not zero

	ld h,e		;0d22	Load E into H
	jr l0d2ah	;0d23	Jump forward

l0d25h:
	ld a,l		;0d25	Load L into A
	or a		;0d26	Set Z flag...
	jr nz,l0cfeh	;0d27	...and jump to KEY_READ if A not zero
	ld l,e		;0d29	Load E into L

; A valid key press has been detected. Check for special keys, add proper 
; ASCII offsets and look keys up in the shift table. DE holds the key's 
; memory address.

;; KEY_COMPUTE
l0d2ah:
	ld (02aa5h),hl	;0d2a	Load HL into KEY_DIFF 
	rst 28h		;0d2d	Call CLEAR_HL
	ld a,e		;0d2e	Load E into A 

; Check for special keys, that directly invoke functions in the BASIC 
; interpreter.

	cp 034h		;0d2f	Compare A with 34h ("list" key) and...
	jp z,l0461h	;0d31	...jump to LIST_KEY if equal

	cp 031h		;0d34	Compare A with 31h ("break" key) and... 
	jp z,l0305h	;0d36	...jump to BREAK if equal

	cp 01bh		;0d39	Compare A with 1bh ("up" key).
	ld hl,02035h	;0d3b	Load 2035h into HL ("shift" key address)
	jr c,l0d59h	;0d3e	Jump to KEY_END_ALPHA if A less than 1bh

	cp 01fh		;0d40	Compare A with 1fh ("space" key address)
	jr c,l0d54h	;0d42	Jump to KEY_END if A is less than 1fh
			;	("up", "down", "left" or "right" keys)

; Code for numerical and symbol keys, that are looked up in KEY_SHIFT_SYM_TABLE

	sub 01fh	;0d44	Subtract 1fh from A
	rr (hl)		;0d46	Rotate (HL) right
			;	Since HL contains the address of the "shift"
			;	key, this moves that status of the "shift" key
			;	into carry flag.

	rla		;0d48	Rotate A left. 
			;	A = A * 2 + 0 (if shift is pressed)
			;	A = A * 2 + 1 (if shirt is released)

	ld c,a		;0d49	Load A into C

	ld hl,l0d70h	;0d4a	Load KEY_SHIFT_SYM_TABLE address into HL
	add hl,bc	;0d4d	Add BC to HL

; This seeds the random generator with the value of the R register after
; some key presses.

	ld a,r		;0d4e	Load R into A
	ld (02aa8h),a	;0d50	Load A into 2nd byte of RND_SEED

	ld a,(hl)	;0d53	Load a character from the symbol table into A

; The code of the pressed key is in A. Store in LAST_KEY and return.

;; KEY_END
l0d54h:
	ld (02bb4h),a	;0d54	Load A into LAST_KEY
	exx		;0d57	Restore BC, DE and HL registers.	
	ret		;0d58	Return

; Pressed key is a letter. Add proper ASCII offset, check shift mapping in 
; table and return.

;; KEY_END_ALPHA
l0d59h:
	add a,040h	;0d59	Add 40h to A (ASCII offset)
	rr (hl)		;0d5b	Rotate (HL) right...
			;	Since HL contains the address of the "shift"
			;	key, this moves that status of the "shift" key
			;	into carry flag.
	jr c,l0d54h	;0d5d	...and jump to KEY_END if shift key not pressed.

	ld hl,l0d94h	;0d5f	Load KEY_SHIFT_YU_TABLE address into HL
	ld bc,l045bh	;0d62	Load 4 into B and 5bh into C

; B holds the length of the KEY_SHIFT_YU_TABLE, C holds the first ASCII code
; of the Yugoslavian character set.

l0d65h:
	cp (hl)		;0d65	Compare (HL) with A...
	jr z,l0d6dh	;0d66	Jump forward if equal
	inc hl		;0d68	Increment HL
	inc c		;0d69	Increment C
	djnz l0d65h	;0d6a	Loop 4 times

; If loops ends here, a dummy load instruction is executed. Else value in C
; (a different character) is stored into A

	db 00eh		;0d6c	These two bytes also form the instruction
l0d6dh:	
	ld a,c		;0d6d	"ld c,079h"

	jr l0d54h	;0d6e	Jump to KEY_END

; 'KEYBOARD TABLES'
; =================

; This table contains characters, that are obtained by pressing keys with
; addresses from 1fh ("space") to 30h ("return").

; The first character in table is obtained by pressing shift-key and the
; second is obtained by pressing the key alone.

;; KEY_SHIFT_SYM_TABLE
l0d70h:
	db	' ',	' '	; 1fh
	db	'_',	'0'	; 20h
	db	'!',	'1'	; 21h
	db	'"',	'2'	; 22h
	db	'#',	'3'	; 23h
	db	'$',	'4'	; 24h
	db	'%',	'5'	; 25h
	db	'&',	'6'	; 26h
	db	0bfh,	'7'	; 27h (bfh is block graphics character)
	db	'(',	'8'	; 28h
	db	')',	'9'	; 29h
	db	'+',	';'	; 2ah
	db	'*',	':'	; 2bh
	db	'<',	','	; 2ch
	db	'-',	'='	; 2dh
	db	'>',	'.'	; 2eh
	db	'?',	'/'	; 2fh
	db	00dh,	00dh	; 30h (CR)

; This table contains characters, that are mapped to Yugoslavian characters
; when the shift-key is pressed.

; It also serves as the KEY_SHIFT_SYM_TABLE entries for "break" and "repeat" 
; keys, which have special functions and are never looked up here.

;; KEY_SHIFT_YU_TABLE
l0d94h:
	db	'X' 		; C with caron		31h
	db 	'C'		; C with acute
	db 	'Z'		; Z with caron		32h
	db	'S'		; S with caron

; KEY_SHIFT_SYM_TABLE entry for the "delete" key

	db	0ch,	00h	; 33h (clear screen - shift delete, delete)

; 'MEM'
; =====
; "MEM" BASIC function

;; MEM
l0d9ah:
	call l0183h	;0d9a	Call FREE_MEM

	ld bc,(02a99h)	;0d9d	Subtract array length from 
	sbc hl,bc	;0da1

	jr l0dbfh	;0da3	Jump to INT_TO_FP and return

; 'WORD'
; ======
; "WORD" BASIC function

;; WORD
l0da5h:
	ld c,(hl)	;0da5	Load word at (HL) into HL
	inc hl		;0da6	
	ld h,(hl)	;0da7	
	ld l,c		;0da8

	jr l0dbfh	;0da9	Jump to INT_TO_FP and return.

; 'KEY'
; =====
; "KEY" BASIC function

;; KEY_CMD
l0dabh:
	ld a,h		;0dab	Check if HL = 0
	or l		;0dac	
	jr nz,l0db4h	;0dad	If HL = 0 (no argument), 
			;	read which key has been pressed and return

	call l0cf5h	;0daf	Call KEY
	jr l0dbah	;0db2	Jump to KEY_CMD_END

l0db4h:
	set 5,h		;0db4	HL = HL | 2000h

	ld a,(hl)	;0db6	Load value from keyboard into A
	cpl		;0db7	Complement A
l0db8h:
	and 001h	;0db8	Filter out LSB.

;; KEY_CMD_END
l0dbah:
	ld l,a		;0dba	Move A into L.
	db 03eh		;0dbb	Dummy "ld a,nn" (skip next instruction - 
			;	clear H and jump to INT_TO_FP)

; 'BYTE'
; ======
; "BYTE" BASIC function

;; BYTE_FUNC
l0dbch:
	ld l,(hl)	;0dbc	Load byte at (HL) into HL
	ld h,000h	;0dbd

l0dbfh:
	jp l0abch	;0dbf	Jump to INT_TO_FP and return.

;; EQ
l0dc2h:
	call l05fch		;0dc2	cd fc 05 	      
	push hl			;0dc5	e5 	  
	rst 18h			;0dc6	df 	  
	inc l			;0dc7	2c 	, 
	nop			;0dc8	00 	  
	call l05fch		;0dc9	cd fc 05 	      
	pop bc			;0dcc	c1 	  
l0dcdh:
	ld a,(bc)			;0dcd	0a 	  
	cp (hl)			;0dce	be 	  
	jr nz,l0ddch		;0dcf	20 0b 	    
	or a			;0dd1	b7 	  
	jr z,l0ddbh		;0dd2	28 07 	(   
	inc hl			;0dd4	23 	# 
	inc bc			;0dd5	03 	  
	ld a,l			;0dd6	7d 	} 
	and 00fh		;0dd7	e6 0f 	    
	jr nz,l0dcdh		;0dd9	20 f2 	    

; following lines from Diss_010.jpg
l0ddbh:
	db 03eh			;0ddb
l0ddch:
	xor a			;0ddc	af 	>   
	jr l0db8h		;0ddd	18 d9 	    
;; HEX
l0ddfh:
	call l0165h	;0ddf	Test the first character 
			;	(Call HEXCHAR_TO_INT_

	jr c,l0df8h	;0de2	Jump to HOW_RST_PUSH_DE if conversion failed

	dec de		;0de4	Move DE back to the beginning

	rst 28h		;0de5	Call CLEAR_HL

;; HEX_LOOP
l0de6h:
	call l0165h	;0de6	Call HEXCHAR_TO_INT

	jr c,l0dbfh	;0de9	Jump to INT_TO_FP and return on end of hex
			; 	number (on first non-hex character)

	rlca		;0deb	A = A << 4
	rlca		;0dec	
	rlca		;0ded	
	rlca		;0dee	

	ld bc,l0de6h	;0def	Load HEX_LOOP address to the top of the
	push bc		;0df2	stack

; Shift four bits in A to HL

l0df3h:
	ld b,004h	;0df3	
l0df5h:
	rlca		;0df5	HL A = HL A << 4
	adc hl,hl	;0df6	
l0df8h:
	jp c,l065ah	;0df8	Jump to HOW_RST_PUSH_DE on overflow

	djnz l0df5h	;0dfb	Loop

	ret		;0dfd	Jump to HEX_LOOP

; 'WORD'
; ======
; "WORD" BASIC command.

l0dfeh:
	db 0f6h		;0dfe	Dummy "or nn" 
			;	(skip next instruction, clear Zf)

; 'BYTE'
; ======
; "BYTE" BASIC command.

;; BYTE
l0dffh:
	xor a		;0dff	Set Zf
	push af		;0e00	Push flags on sack

	rst 8		;0e01	Get address (call EVAL_INT_EXP)
	push hl		;0e02	Save address on stack.

	call l0005h	;0e03	Get content (call EVAL_INT_EXP_NEXT)

	ex (sp),hl	;0e06	HL = address
	pop bc		;0e07	BC = content

	ld (hl),c	;0e08	Load lower byte into (HL)

	pop af		;0e09	Get flags from stack

	jr z,l0e0eh	;0e0a	If Zf not set, store upper byte into (HL+1) 
	inc hl		;0e0c	 
	ld (hl),b	;0e0d	
l0e0eh:
	rst 30h		;0e0e	f7 	  

; 'USR'
; =====
; "USR" BASIC function.

;; USR
l0e0fh:
	push de		;0e0f	Save DE pointer on stack
	ld de,l0abdh	;0e10	Load INT_TO_FP_2 address on stack
	push de		;0e13
	jp (hl)		;0e14	Jump to user function
			;	(returns back to INT_TO_FP_2, which pushes
			;	result to arithmetic stack and restores DE
			;	pointer)

;; CHR$
l0e15h:
	or d			;0e15	b2 	  
	ld a,l			;0e16	7d 	} 
	ret			;0e17	c9 	  
;; FOR
l0e18h:
	call l0974h		;0e18	cd 74 09 	  t   
	call l0730h		;0e1b	cd 30 07 	  0   
	ld (02aa1h),hl		;0e1e	22 a1 2a 	"   * 
	rst 18h			;0e21	df 	  
	ld d,h			;0e22	54 	T 
	or d			;0e23	b2 	  
	rst 18h			;0e24	df 	  
	ld c,a			;0e25	4f 	O 
	xor a			;0e26	af 	  
	rst 8			;0e27	cf 	  
	ld (02a6eh),hl		;0e28	22 6e 2a 	" n * 
	ld l,0d8h		;0e2b	2e d8 	.   
	jp l0398h		;0e2d	c3 98 03 	      

; 'SAVE'
; ======
; "SAVE" BASIC command.

;; SAVE
l0e30h:	
	ld hl,02c36h	;0e32 	Load BASIC_START address into HL...
	push hl		;0e33	...and save it to stack

	ld hl,(02c38h)	;0e34	Load BASIC_END into HL

	rst 18h		;0e37	Call READ_PAR
	db 00dh		;0e38	ASCII CR
	db l0e3ch-$-1	;0e39

	jr l0e42h	;0e3a	There is no parameter on the rest of the line.
			;	Jump forward

; This looks like the SAVE nnnn,nnnn variant of the command.

l0e3ch:
	rst 8		;0e3c	Call EVAL_INT_EXP

	ex (sp),hl	;0e3d	Replace BASIC_START address on the stack with
			;	the number from EVAL_INT_EXP
	call l0005h	;0e3e	Call EVAL_INT_EXP_NEXT

	inc hl		;0e41	Replace BASIC_END address in HL with the number
			;	from EVAL_INT_EXP_NEXT + 1.

l0e42h:
	pop de		;0e42	...restore BASIC_START address into DE
			;	(address of the first byte of the block to 
			;	save)

	ld b,060h	;0e43	Load 60h into B
	di		;0e45	Disable interrupts

; Save 96 sync bytes (00h)

l0e46h:
	xor a		;0e46	Clear A
	call l0e68h	;0e47	Call SAVE_BYTE
	djnz l0e46h	;0e4a	Repeat 96 times

; B = 0 and from now on holds the sum of all saved bytes.

; Save start byte (a5h)

	ld a,0a5h	;0e4c	Load a5h into A
	call l0e68h	;0e4e	Call SAVE_BYTE

	call l0e62h	;0e51	Call SAVE_WORD
			;	Saves DE (start address)
	call l0e62h	;0e54	Call SAVE_WORD
			;	Saves HL (end address)

	dec hl		;0e57	Decrement HL 
			;	(address of the last byte of the block to save)

; Save data (from DE to HL inclusive)

l0e58h:
	ld a,(de)	;0e58	Load byte at (DE) into A
	inc de		;0e59	Increment DE
	call l0e68h	;0e5a	Call SAVE_BYTE
	jr nc,l0e58h	;0e5d	If DE <= HL then loop

	ld a,b		;0e5f	Load sum into A
	cpl		;0e60	Complement A (make checksum)
	ld e,a		;0e61	Load checksum into E

; Save checksum and one garbage byte in D and return.

; 'SAVE WORD'
; ===========
; This function saves one word (16 bits) to the audio cassette.

; Parameters:
;	DE: word to be saved
; Returns:
;	HL: holds previous contents of DE
;	DE: holds previous contents of HL
;	B: B + sum of both saved bytes
; Destroys:
;	A

;; SAVE_WORD
l0e62h:
	ex de,hl	;0e62	Exchange contents of DE and HL registers.
	ld a,l		;0e63	Load L into A
	call l0e68h	;0e64	Call SAVE_BYTE

	ld a,h		;0e67	Load H into A

; Save the second byte and return.

; 'SAVE BYTE'
; ===========
; This function saves one byte to the audio cassette.

; Parameters:
;	A: byte to be saved
; Returns:
;	B: B = B + A
;	flags: output of CMP_HL_DE
; Destroys:
;	A

;; SAVE_BYTE
l0e68h:
	exx		;0e68	Exchange BC,DE,HL with BC',DE',HL'

	ld c,010h	;0e69	Load 16 into C
	ld hl,02038h	;0e6b	Load latch address (2038h) into HL

;; SAVE_BYTE_LOOP
l0e6eh:
	bit 0,c		;0e6e	Test bit 0 of C
	jr z,l0e77h	;0e70	If C even, always make an impulse on output...
	rrca		;0e72	...else rotate A right (stores LSB in C flag)
	ld b,064h	;0e73	   load 100 into B
	jr nc,l0e86h	;0e75	   skip impulse if LSB not set

l0e77h:
	ld (hl),0fch	;0e77	Set output to high
	ld b,032h	;0e79	Load 50 into B
l0e7bh:
	djnz l0e7bh	;0e7b	Wait (approx. 650 T)
	ld (hl),0b8h	;0e7d	Set output to low
	ld b,032h	;0e7f	Load 50 into B
l0e81h:
	djnz l0e81h	;0e81	Wait (approx. 650 T)
	ld (hl),0bch	;0e83	Set output to zero
	inc b		;0e85	Load 01h into B
l0e86h:
	djnz l0e86h	;0e86	Wait (13 or 1300 T, depending whether 
			;	C was even or odd)
l0e88h:
	djnz l0e88h	;0e88	Wait (approx. 3328 T)
	dec c		;0e8a	Decrement C
	jr nz,l0e6eh	;0e8b	Jump to SAVE_BYTE_LOOP

			;	BC = 0
			;	The following loop waits for 512 cycles
l0e8dh:
	inc bc		;0e8d	Increment BC
	bit 1,b		;0e8e	Test bit 1 of B...
	jr z,l0e8dh	;0e90	... and loop if not set.

	exx		;0e92	Exchange BC,DE,HL with BC',DE',HL'

; LOAD_BYTE function jumps here at the end
l0e93h:
	add a,b		;0e93	Add B to A
	ld b,a		;0e94	B = A + B
	rst 10h		;0e95	Call CMP_HL_DE

	ret		;0e96	Return


; 'OLD'
; =====
; "OLD" BASIC command.

; Verifies saved data if there is a '?' character after the command.

;; OLD
l0e97h:
	rst 18h		;0e97	Call READ_PAR
	db '?' 		;0e98
	db l0e9ah-$-1	;0e99	Check for '?' in the argument
l0e9ah:

	push af		;0e9a	Push result of READ_PAR. 

	rst 18h		;0e9b	Call READ_PAR
	db 00dh		;0e9c	ASCII CR
	db l0ea0h-$-1	;0e9d

	rst 28h		;0e9e	Call CLEAR_HL
	db 03eh		;0e9f	Dummy ld a,	(ignores "rst 8" instruction,
			;			if there was no parameter)
l0ea0h:
	rst 8		;0ea0	Read load offset to HL (Call EVAL_INT_EXP)

	push hl		;0ea1	Store load offset on stack

	di		;0ea2	Disable interrupts

; Wait for the start byte (a5h)

l0ea3h:
	call l0eddh	;0ea3	Call LOAD_BYTE
	ld a,c		;0ea6	
	cp 0a5h		;0ea7	Compare loaded byte with a5h and ...
	jr nz,l0ea3h	;0ea9	... loop if not equal.

	ld b,a		;0eab	Load a5h into B 
			;	(value of the first loaded byte, for checksum)
	call l0ed9h	;0eac	Call LOAD_WORD (start address)
	ld h,c		;0eaf

	pop de		;0eb0	Fetch load offset from stack and add it
	push de		;0eb1	to the start address.
	add hl,de	;0eb2

	ex de,hl	;0eb3	DE = start address

	call l0ed9h	;0eb4	Call LOAD_WORD (end address)
	ld h,c		;0eb7

	dec hl		;0eb8	Decrement end address 
			;	HL = address of last byte to load

	ld a,b		;0eb9	Save checksum to A

	pop bc		;0eba	Add load offset
	add hl,bc	;0ebb	

	ld b,a		;0ebc	Restore checksum to B

l0ebdh:
	ex de,hl	;0ebd	HL = address of the current byte
			;	DE = address of the last byte

	call l0eddh	;0ebe	Call LOAD_BYTE
	ex af,af'	;0ec1	F' holds results of CMP_HL_DE

	ld a,c		;0ec2	Compare loaded byte with (HL) and ...
	cp (hl)		;0ec3		
	jr z,l0ecbh	;0ec4	... jump forward if equal

	pop af		;0ec6	Restore flags 
	jr z,l0ed6h	;0ec7	Jump to WHAT_RST if loaded byte not equal 
			;	to memory byte and verify mode is enabled
			;	(Z flag is set by the READ_PAR function).
	push af		;0ec9	Save flags

	ld (hl),c	;0eca	Store loaded byte in memory

l0ecbh:
	inc hl		;0ecb	Increment HL

	ex de,hl	;0ecc	DE = address of the current byte
			;	HL = address of the last byte

	ex af,af'	;0ecd 	  
	jr c,l0ebdh	;0ece	Loop if current address < last address

	call l0eddh	;0ed0	Call LOAD_BYTE (checksum)
	pop af		;0ed3	Remove stored flags from stack

	inc b		;0ed4	Return if B = ffh, else display WHAT? error
	ret z		;0ed5	

l0ed6h:
	jp l078fh	;0ed6	Jump to WHAT_RST
			;	Tape loading error

; 'LOAD WORD'
; ===========
; Loads one word (16 bits) from the audio cassette. It executes CMP_HL_DE
; function and returns its result in the flag register.

; Returns:
;	L: low byte
;	C: high byte
;	B: B = B + sum of both loaded bytes
;	flags: Result of the CMP_HL_DE function.

;; LOAD_WORD
l0ed9h:
	call l0eddh	;0ed9	Call LOAD_BYTE
	ld l,c		;0edc	Save result into L

; Continue with another LOAD_BYTE and return

; 'LOAD BYTE'
; ===========
; This function loads one byte from the audio cassette.

; Returns:
;	C: byte loaded 
;	B: B = B + C

;; LOAD_BYTE
l0eddh:
	exx		;0edd
	ld b,001h	;0ede	Load 1 into B'

l0ee0h:
	ld a,0a7h	;0ee0	Load 167 into A

; This block waits for an impulse on the cassette port. If B' = 1 (on first 
; iteration), it waits indefinitely. If B' = 0 it waits for A loop iterations.

; 49 T * 167 = 8183 T = 2.7ms

;; LOAD_WAIT_PULSE
l0ee2h:
	add a,b		;0ee2	4	Add B' to A
	ld hl,02000h	;0ee3	10	Load cassette port address into HL'
	bit 0,(hl)	;0ee6	12	Test bit 0 
	jr z,l0ef1h	;0ee8	12,7	If impulse was detected, break loop...
	dec a		;0eea	4	...else decrement A and
	jr nz,l0ee2h	;0eeb	12,7	   loop to LOAD_WAIT_PULSE if not zero

	exx		;0eed	4	
	ld a,c		;0eee	4	Load C into A

	jr l0e93h	;0eef		B = A + B, compare HL with DE
			;		and return from function

l0ef1h:

; Pause for 4369 T = 1.42 ms

	ld b,0dah	;0ef1	7	Load 218 into B'
l0ef3h:
	ld a,0a9h	;0ef3	7	Load a9h into A
	djnz l0ef3h	;0ef5	13,8	Loop

	ld b,05ah	;0ef7	7	Load 90 into B'

; This loop checks if the first pulse is followed by another one in specified
; time interval. It has 90 iterations, each 35 T (11.4us) long. If input is 
; low in more than 4 iterations (so that A doesn't overflow), then bit 1 is 
; loaded into C. Else bit 0.

; This gives a minimum pulse width of 140 T (45 us). 

;; LOAD_READ_PULSE
l0ef9h:
	ld c,(hl)	;0ef9	7	Load C' from cassette port
	rr c		;0efa	8	Move bit 0 into carry flag...
	adc a,000h	;0efc	7	...and add it to A
	djnz l0ef9h	;0efe	13,8	Loop to LOAD_READ_PULSE

	rlca		;0f00	Rotate A left (MSB into carry flag)
	exx		;0f01
	rr c		;0f02	Rotate C right (carry flag into MSB)
	exx		;0f04

	jr l0ee0h	;0f05	Loop LOAD_WAIT_PULSE (B' = 0)

; **********************************
; * BASIC INTERPRETER DATA SECTION *
; **********************************

; 'READY STRING'
; ==============
; Command prompt string, printed when in command line mode.
;; READY
l0f07h:
	dm 040h, 027h			;0f07
	dm "READY", 00dh		;0f09

; 'BASIC TABLES'
; ==============
; Following section contains tables for the BASIC interpreter 
; (NOTE: complete table must fit into 0fxxh page)

; Format of the table is:
;	dm 	"function name"
;	db 	"high byte of function's address" + 80h 
;			( + 40h if function takes an integer argument in 
;			parenthesis)
;	db 	"low byte of function's address"

; A catch-all rule lacks the function name.

; 'BASIC COMMAND LINE TABLE'
; ==========================
; These BASIC commands take zero or one integer argument and can only appear 
; on the command line.

;; BASIC_CMDLINE_TABLE
l0f0fh:
	dm "LIST"			;0f0f
	db ((l045eh>>8)&00ffh)+80h	;0f13
	db (l045eh)&00ffh		;0f14

	dm "RUN"			;0f15
	db ((l040bh>>8)&00ffh)+80h	;0f18
	db (l040bh)&00ffh		;0f19

	dm "NEW"			;0f1a
	db ((l03fch>>8)&00ffh)+80h	;0f1d
	db (l03fch)&00ffh		;0f1e

	dm "SAVE"			;0f1f
	db ((l0e30h>>8)&00ffh)+80h	;0f23
	db (l0e30h)&00ffh		;0f24

	dm "OLD"			;0f25
	db ((l0e97h>>8)&00ffh)+80h	;0f28
	db (l0e97h)&00ffh		;0f29

	dm "EDIT"			;0f2a
	db ((l0299h>>8)&00ffh)+80h	;0f2e
	db (l0299h)&00ffh		;0f2f

; 'BASIC COMMAND TABLE'
; =====================
; These BASIC commands take zero or one integer argument and jump to 
; RUN_THIS_LINE routine (or one of interpreter's other entry points) at the
; end.

;; BASIC_CMD_TABLE
l0f30h:
	dm "NEXT"			;0f30
	db ((l0564h>>8)&00ffh)+80h	;0f34
	db (l0564h)&00ffh		;0f35

	dm "INPUT"			;0f36
	db ((l066ch>>8)&00ffh)+80h	;0f3b
	db (l066ch)&00ffh		;0f3c

	dm "IF"				;0f3d
	db ((l0441h>>8)&00ffh)+80h	;0f3f
	db (l0441h)&00ffh		;0f40

	dm "GOTO"			;0f41
	db ((l0453h>>8)&00ffh)+80h	;0f45
	db (l0453h)&00ffh		;0f46

	dm "CALL"			;0f47
	db ((l04f4h>>8)&00ffh)+80h	;0f4b
	db (l04f4h)&00ffh		;0f4c

	dm "UNDOT"			;0f4d
	db ((l06cch>>8)&00ffh)+80h	;0f52
	db (l06cch)&00ffh		;0f53
	
	dm "RET"			;0f54
	db ((l0512h>>8)&00ffh)+80h	;0f57
	db (l0512h)&00ffh		;0f58

	dm "TAKE"			;0f59
	db ((l0626h>>8)&00ffh)+80h	;0f5d
	db (l0626h)&00ffh		;0f5e

	dm "!"				;0f5f
	db ((l044dh>>8)&00ffh)+80h	;0f60
	db (l044dh)&00ffh		;0f61

	dm "#"				;0f62
	db ((l044dh>>8)&00ffh)+80h	;0f63
	db (l044dh)&00ffh		;0f64

	dm "FOR"			;0f65
	db ((l0e18h>>8)&00ffh)+80h	;0f68
	db (l0e18h)&00ffh		;0f69

	dm "PRINT"			;0f69
	db ((l0480h>>8)&00ffh)+80h	;0f6f
	db (l0480h)&00ffh		;0f70

	dm "DOT"			;0f71
	db ((l06cfh>>8)&00ffh)+80h	;0f74
	db (l06cfh)&00ffh		;0f75

	dm "ELSE"			;0f76
	db ((l044dh>>8)&00ffh)+80h	;0f7a
	db (l044dh)&00ffh		;0f7b

	dm "BYTE"			;0f7c
	db ((l0dffh>>8)&00ffh)+80h	;0f80
	db (l0dffh)&00ffh		;0f81

	dm "WORD"			;0f82
	db ((l0dfeh>>8)&00ffh)+80h	;0f86
	db (l0dfeh)&00ffh		;0f87

	dm "ARR$"			;0f88
	db ((l010bh>>8)&00ffh)+80h+40h	;0f8c
	db (l010bh)&00ffh		;0f8d

	dm "STOP"			;0f8e
	db ((l0317h>>8)&00ffh)+80h	;0f92
	db (l0317h)&00ffh		;0f93

	dm "HOME"			;0f94
	db ((l04d6h>>8)&00ffh)+80h	;0f98
	db (l04d6h)&00ffh		;0f99

; Catch-all rule for BASIC commands.

	db ((l075bh>>8)&00ffh)+80h	;0f9a
	db (l075bh)&00ffh		;0f9b

; 'BASIC FUNCTION TABLE'
; ======================
; These BASIC functions take zero or one integer arguments and leave a
; floating point value on the arithmetic stack after they return.

;; BASIC_FUNC_TABLE
l0f9ch:
	dm "RND" 			;0f9c
	db ((l0c8fh>>8)&00ffh)+80h	;0f9f
	db (l0c8fh)&00ffh		;0fa0

	dm "MEM"			;0fa1
	db ((l0d9ah>>8)&00ffh)+80h	;0fa4
	db (l0d9ah)&00ffh		;0fa5

	dm "KEY" 			;0fa6
	db ((l0dabh>>8)&00ffh)+80h+40h	;0fa9
	db (l0dabh)&00ffh		;0faa

	dm "BYTE"			;0fab
	db ((l0dbch>>8)&00ffh)+80h+40h	;0faf
	db (l0dbch)&00ffh		;0fb0

	dm "WORD"			;0fb1
	db ((l0da5h>>8)&00ffh)+80h+40h	;0fb5
	db (l0da5h)&00ffh		;0fb6

	dm "PTR"			;0fb7
	db ((l0769h>>8)&00ffh)+80h	;0fba
	db (l0769h)&00ffh		;0fbb

	dm "VAL"			;0fbc
	db ((l0770h>>8)&00ffh)+80h+40h	;0fbf
	db (l0770h)&00ffh		;0fc0

	dm "EQ"				;0fc1
	db ((l0dc2h>>8)&00ffh)+80h	;0fc3
	db (l0dc2h)&00ffh		;0fc4

	dm "INT"			;0fc5
	db ((l0abch>>8)&00ffh)+80h+40h	;0fc8
	db (l0abch)&00ffh		;0fc9

	dm "&"				;0fca
	db ((l0ddfh>>8)&00ffh)+80h	;0fcb
	db (l0ddfh)&00ffh		;0fcc

	dm "USR"			;0fcd
	db ((l0e0fh>>8)&00ffh)+80h+40h	;0fd0
	db (l0e0fh)&00ffh		;0fd1

	dm "DOT"			;0fd2
	db ((l06dch>>8)&00ffh)+80h	;0fd5
	db (l06dch)&00ffh		;0fd6

; Catch-all rule for BASIC functions.

	db ((l0777h>>8)&00ffh)+80h	;0fd7
	db (l0777h)&00ffh		;0fd8

	dm "STEP"			;0fd9
	db ((l0528h>>8)&00ffh)+80h	;0fdd
	db (l0528h)&00ffh		;0fde

; Catch-all rule

	db ((l052ah>>8)&00ffh)+80h	;0fdf
	db (l052ah)&00ffh		;0fe0

; 'BASIC "PRINT" COMMAND TABLE'
; =============================
; These BASIC commands can only appear after the "PRINT" command. They
; jump to RUN_THIS_LINE routine (or one of interpreter's other entry points)
; at the end.

;; BASIC_PRINT_TABLE
l0fe1h:

	dm "AT"				;0fe1
	db ((l04bch>>8)&00ffh)+80h	;0fe3
	db (l04bch)&00ffh		;0fe4

	dm "X$"				;0fe5
	db ((l0498h>>8)&00ffh)+80h	;0fe7
	db (l0498h)&00ffh		;0fe8

	dm "Y$"				;0fe9
	db ((l049bh>>8)&00ffh)+80h	;0feb
	db (l049bh)&00ffh		;0fec

; Catch-all rule

	db ((l048eh>>8)&00ffh)+80h	;0fed
	db (l048eh)&00ffh		;0fee
	
	dm "CHR$"			;0fef
	db ((l0e15h>>8)&00ffh)+80h+40h	;0ff3
	db (l0e15h)&00ffh		;0ff4

; Catch-all rule

	db ((l060bh>>8)&00ffh)+80h	;0ff5
	db (l060bh)&00ffh		;0ff6

	dm "ELSE"			;0ff7
	db ((l041ah>>8)&00ffh)+80h	;0ffb
	db (l041ah)&00ffh		;0ffc

; Catch-all rule

	db ((l081bh>>8)&00ffh)+80h	;0ffd
	db (l081bh)&00ffh		;0ffe

; One (!) spare byte

	db 00h				;0fff

	end