COLLECTED BY
Organization:
Archive Team

Formed in 2009, the Archive Team (not to be confused with the archive.org Archive-It Team) is a rogue archivist collective dedicated to saving copies of rapidly dying or deleted websites for the sake of history and digital heritage. The group is 100% composed of volunteers and interested parties, and has expanded into a large amount of related projects for saving online and digital history.
History is littered with hundreds of conflicts over the future of a community, group, location or business that were "resolved" when one of the parties stepped ahead and destroyed what was there. With the original point of contention destroyed, the debates would fall to the wayside. Archive Team believes that by duplicated condemned data, the conversation and debate can continue, as well as the richness and insight gained by keeping the materials. Our projects have ranged in size from a single volunteer downloading the data to a small-but-critical site, to over 100 volunteers stepping forward to acquire terabytes of user-created data to save for future generations.
The main site for Archive Team is at archiveteam.org and contains up to the date information on various projects, manifestos, plans and walkthroughs.
This collection contains the output of many Archive Team projects, both ongoing and completed. Thanks to the generous providing of disk space by the Internet Archive, multi-terabyte datasets can be made available, as well as in use by the Wayback Machine, providing a path back to lost websites and work.
Our collection has grown to the point of having sub-collections for the type of data we acquire. If you are seeking to browse the contents of these collections, the Wayback Machine is the best first stop. Otherwise, you are free to dig into the stacks to see what you may find.
The Archive Team Panic Downloads are full pulldowns of currently extant websites, meant to serve as emergency backups for needed sites that are in danger of closing, or which will be missed dearly if suddenly lost due to hard drive crashes or server failures.
ArchiveBot is an IRC bot designed to automate the archival of smaller websites (e.g. up to a few hundred thousand URLs). You give it a URL to start at, and it grabs all content under that URL, records it in a WARC, and then uploads that WARC to ArchiveTeam servers for eventual injection into the Internet Archive (or other archive sites).
To use ArchiveBot, drop by #archivebot on EFNet. To interact with ArchiveBot, you issue commands by typing it into the channel. Note you will need channel operator permissions in order to issue archiving jobs. The dashboard shows the sites being downloaded currently.
There is a dashboard running for the archivebot process at http://www.archivebot.com.
ArchiveBot's source code can be found at https://github.com/ArchiveTeam/ArchiveBot.
The Wayback Machine - https://web.archive.org/web/20150815035611/http://www.wearmouth.demon.co.uk/zx80.htm
; ===================================================
;
; An Assembly Listing of the ROM of the Sinclair ZX80
; ---------------------------------------------------
;
; -------------------------
; Last updated: 12-SEP-2002
; -------------------------
;
; Note. This is not the original text file, which was
; written by John Grant in 1979, but a file that
; performs a similar function in that it assembles
; a 4K ROM file that may be used in ZX80 emulators.
;
; The resultant ROM file is identical to the original
; and a comparison between the object code and the original
; is made as part of the process of uploading this file.
;
; It would be desirable that the original file be published but, until such
; time, this file may serve as a poor substitute.
;
; Actually I learn that the complete Assembly Listing was published, with
; "Designer's Annotations", in 1980. Also in that year, appeared "The ZX80
; Monitor Listing" by Ian Logan, published by LINSAC.
;
; ===================================================
#define DEFB .BYTE ; TASM cross-assembler definitions
#define DEFW .WORD
#define EQU .EQU
; ===================================================
;
; To do justice to the original program it is desirable
; that, while the instructions should not be over
; commented, what is appended should be of high quality.
;
; Send details of any improvements/corrections to
; geoff@wearmouth.demon.co.uk.spamnothanks
; All contributions will be credited.
;
; File incorporates contributions from
; Peter Liebert-Adelt
;
; and borrows from the writings of
; Wilf Rigter,
; Dr Ian Logan,
; Dr Frank O'Hara.
;
; ===================================================
.ORG $0000
; -----------
; THE 'START'
; -----------
;; START
L0000: LD HL,$7FFF ; top of possible RAM.
; (highest integer is 32767).
LD A,$3F ; page before RAM.
JP L0261 ; forward to RAM-FILL.
; -------------------
; THE 'ERROR' RESTART
; -------------------
;; ERROR-1
L0008: POP HL ; drop the return address.
LD L,(HL) ; fetch the error code after RST 8.
BIT 7,(IY+$00) ; test ERR_NR for value $FF (OK)
JR L0013 ; forward to continue at ERROR-2.
; -------------------------------
; THE 'PRINT A CHARACTER' RESTART
; -------------------------------
;; PRINT-A
L0010: JP L0560 ; jump forward immediately to PRINT-A-2
; ---
; A continuation of the previous Error restart.
;; ERROR-2
L0013: RET Z ; return if $FF - OK.
LD (IY+$00),L ; else set system variable ERR_NR
RET ; return.
; ---------------------------------------------
; THE 'COLLECT NEXT CHARACTER OR SPACE' RESTART
; ---------------------------------------------
; This will collect any next character including space (zero).
;; NXT-CH-SP
L0018: JR L0052 ; forward to CH_ADD+1
; ---
; This subroutine will collect the character at the current character address
; searching for the next non-space character should the fetched character be
; a space.
;; get-char
L001A: LD HL,($4026) ; get pointer from CH_ADD
LD A,(HL) ; fetch addressed character.
; This subroutine tests the current character in the accumulator retrieving
; the next non-space character should the accumulator contain a space
;; TEST-CHAR
L001E: AND A ; test for space (zero).
RET NZ ; return if not a space.
;-------------------------------------------
; THE 'COLLECT NEXT VALID CHARACTER' RESTART
;-------------------------------------------
;; NEXT-CHAR
L0020: CALL L0052 ; routine CH_ADD+1
JR L001E ; loop back to TEST-CHAR until valid
; ---
; This subroutine advances the character pointer and evaluates the following
; expression.
; It is called twice with CH_ADD addressing the '(' character
;; EVAL-EXPR
L0025: CALL L0055 ; routine CH_ADD_LP
; ---------------------------------
; THE 'SCANNING-CALCULATOR' RESTART
; ---------------------------------
;; SCAN-CALC
L0028: CALL L001A ; routine get-char.
LD B,$00 ; set B to zero as a starting
; priority marker.
JP L09E1 ; jump forward to SCANNING
; ----------------------------
; THE 'MAKE BC SPACES' RESTART
; ----------------------------
;; BC-SPACES
L0030: CALL L094F ; routine TEST-ROOM
RET NC ; return if not enough room.
PUSH BC ; save number of bytes required.
JP L0CF3 ; jump forward to RESERVE
; --------------------------------
; THE 'MASKABLE INTERRUPT' ROUTINE
; --------------------------------
; Note. the maskable interrupt is concerned with generating the TV picture,
; one of the main tasks in the ZX80. This requires some understanding of
; how the video hardware interacts with the system and part of the process
; is to present to the Z80 chip a phantom display file in the upper
; unpopulated 32K of memory. This topsy-turvy display file
; executes characters like "HELLO WORLD" as NOP instructions but recognizes
; a newline ($76) as a true HALT instruction.
; The video hardware sniffs the databus and grabs the data as it flies by
; sending it on to the shifting circuits. The I register permanently holds
; $0E. The video circuitry uses this register and the lower six bits of the
; character to index into the character set bitmaps at the end of this ROM,
; at $0E00, and so cobble together a scan-line.
; If bit 7 of the character latch is set, then the serial video data is
; inverted so that any character in the range 127-191 appears as the inverse
; of normal characters 0 - 63.
; For a proper explanation of this system, I recommend Wilf Rigter's
; online documentation, available from several indexed sites.
; I have borrowed a few comments from that file to remind myself of what
; is happening. I have indicated where the Z80 instructions should be
; read in conjunction with Wilf's file by using a double semi-colon.
; On entry, B holds the line number and C the number of the scanline.
;; MASK-INT
L0038: DEC C ;; decrement the scan line counter in register C.
JP NZ,L0045 ;; JUMP to SCAN-LINE : repeats 8 times for each
;; row of characters in DFILE.
POP HL ;; point to the start of next DFILE row
DEC B ;; decrement ROW counter
RET Z ;; return if zero to
SET 3,C ;; load scan line counter with 08 was 00.
;; WAIT-INT
L0041: LD R,A ;; load refresh register with value $DD.
EI ;; enable interrupts.
JP (HL) ;; jump to execute the NOPs in DFILE
;; terminated by a NEWLINE/HALT instruction.
; ---
;; SCAN-LINE
L0045: POP DE ;; discard return address.
RET Z ;; delay (Zero never set)
JR L0041 ;; back to WAIT-INT above
; ----------------------------------------------
; THE 'EVALUATE BRACKETED EXPRESSION' SUBROUTINE
; ----------------------------------------------
; This subroutine is used when an opening bracket is encountered to evaluate
; the expression within. It is called from LOOK-VARS when an integral function
; or array is encountered and recursively from within SCANNING when any
; bracketed argument or sub-expression is encountered.
;; BRACKET
L0049: CALL L0025 ; routine EVAL-EXPR
LD A,(HL) ; fetch subsequent character
CP $D9 ; is character a ')' ?
JP NZ,L08AE ; jump to INS-ERR with other characters.
; else continue and get the character after the ')' ...
; ---------------------------------
; THE 'INCREMENT CH_ADD' SUBROUTINE
; ---------------------------------
;; CH_ADD+1
L0052: LD HL,($4026) ; fetch character address from CH_ADD
;; CH_ADD_LP
L0055: INC HL ; increment the pointer.
LD ($4026),HL ; set system variable CH_ADD
LD A,(HL) ; fetch the addressed value.
CP $B0 ; is character inverse 'K'
RET NZ ; return if not. >>
LD ($4004),HL ; set P_PTR system variable
BIT 7,(IY+$19) ; test FLAGX - will be set if K-mode
JR Z,L0055 ; back to CH_ADD_LP if not K-mode
L0066: SET 2,(IY+$01) ; update FLAGS set K mode.
JR L0055 ; back to CH_ADD_LP
; Note there is no NMI routine at L0066.
; ---------------
; THE 'KEY' TABLE
; ---------------
; The Key Table is indexed with a key value 1-78.
; -----------------------
; THE 39 'UNSHIFTED' KEYS
; -----------------------
;; MAIN-KEYS
L006C: DEFB $3F ; Z
DEFB $3D ; X
DEFB $28 ; C
DEFB $3B ; V
DEFB $26 ; A
DEFB $38 ; S
DEFB $29 ; D
DEFB $2B ; F
DEFB $2C ; G
DEFB $36 ; Q
DEFB $3C ; W
DEFB $2A ; E
DEFB $37 ; R
DEFB $39 ; T
DEFB $1D ; 1
DEFB $1E ; 2
DEFB $1F ; 3
DEFB $20 ; 4
DEFB $21 ; 5
DEFB $1C ; 0
DEFB $25 ; 9
DEFB $24 ; 8
DEFB $23 ; 7
DEFB $22 ; 6
DEFB $35 ; P
DEFB $34 ; O
DEFB $2E ; I
DEFB $3A ; U
DEFB $3E ; Y
DEFB $76 ; NEWLINE ED-ENTER
DEFB $31 ; L
DEFB $30 ; K
DEFB $2F ; J
DEFB $2D ; H
DEFB $00 ; SPACE
DEFB $1B ; .
DEFB $32 ; M
DEFB $33 ; N
DEFB $27 ; B
; ----------------------
; THE 39 'SHIFTED' CODES
; ----------------------
DEFB $0E ; ':'
DEFB $D7 ; ';'
DEFB $0F ; '?'
DEFB $DF ; '/'
DEFB $09 ; mosaic $09
DEFB $08 ; mosaic $08
DEFB $06 ; mosaic $06
DEFB $07 ; mosaic $07
DEFB $0B ; mosaic $0B
DEFB $02 ; mosaic $02
DEFB $03 ; mosaic $03
DEFB $04 ; mosaic $0A
DEFB $05 ; mosaic $04
DEFB $0A ; mosaic $05
DEFB $DB ; 'NOT'
DEFB $E0 ; 'AND'
DEFB $D5 ; 'THEN'
DEFB $D6 ; 'TO'
DEFB $72 ; cursor left
DEFB $77 ; [ RUBOUT ]
DEFB $74 ; [ HOME ]
DEFB $73 ; cursor right
DEFB $70 ; cursor up
DEFB $71 ; cursor down
DEFB $DE ; '*'
DEFB $D9 ; ')'
DEFB $DA ; '('
DEFB $0D ; '$'
DEFB $01 ; '"'
DEFB $75 ; [ EDIT ]
DEFB $E3 ; '='
DEFB $DD ; '+'
DEFB $DC ; '-'
DEFB $E2 ; '**'
DEFB $0C ; uk currency symbol
DEFB $D8 ; ','
DEFB $E4 ; '>'
DEFB $E5 ; '<'
DEFB $E1 ; 'OR'
; -----------------
; THE 'TOKEN' TABLE
; -----------------
;; TKN-TABLE
L00BA: DEFB $D4 ; chr$ 212 - the threshold character
; tokens below this are printed using
; the next character
DEFB $8F ; '?' + $80
DEFB $81 ; '"' + $80
DEFB $39,$2D,$2A,$B3 ; THEN
DEFB $39,$B4 ; TO
DEFB $99 ; ;
DEFB $9A ; ,
DEFB $91 ; (
DEFB $90 ; )
DEFB $33,$34,$B9 ; NOT
DEFB $92 ; -
DEFB $93 ; +
DEFB $94 ; *
DEFB $95 ; /
DEFB $26,$33,$A9 ; AND
DEFB $34,$B7 ; OR
DEFB $14,$14+$80 ; **
DEFB $96 ; =
DEFB $97 ; <
DEFB $98 ; >
DEFB $31,$2E,$38,$B9 ; LIST
DEFB $37,$2A,$39,$3A,$37,$B3 ; RETURN
DEFB $28,$31,$B8 ; CLS
DEFB $29,$2E,$B2 ; DIM
DEFB $38,$26,$3B,$AA ; SAVE
DEFB $2B,$34,$B7 ; FOR
DEFB $2C,$34,$00,$39,$B4 ; GO TO
DEFB $35,$34,$30,$AA ; POKE
DEFB $2E,$33,$35,$3A,$B9 ; INPUT
DEFB $37,$26,$33,$29 ; ...
DEFB $34,$32,$2E,$38,$AA ; RANDOMISE
DEFB $31,$2A,$B9 ; LET
DEFB $8F ; '?' + $80
DEFB $8F ; '?' + $80
DEFB $33,$2A,$3D,$B9 ; NEXT
DEFB $35,$37,$2E,$33,$B9 ; PRINT
DEFB $8F ; '?' + $80
DEFB $33,$2A,$BC ; NEW
DEFB $37,$3A,$B3 ; RUN
DEFB $38,$39,$34,$B5 ; STOP
DEFB $28,$34,$33,$39,$2E ; ...
DEFB $33,$3A,$AA ; CONTINUE
DEFB $2E,$AB ; IF
DEFB $2C,$34,$00,$38,$3A,$A7 ; GO SUB
DEFB $31,$34,$26,$A9 ; LOAD
DEFB $28,$31,$2A,$26,$B7 ; CLEAR
DEFB $37,$2A,$B2 ; REM
DEFB $8F ; '?' + $80
; ----------------------
; THE 'DISPLAY' ROUTINES
; ----------------------
; ->
;; DISP-1
L013C: CALL L01AD ;; routine DISP-2
; The initial entry point
;; KEYBOARD
L013F: LD B,$08 ; (7) set counter to 8
;; KB-1
L0141: DJNZ L0141 ; (13,8) and loop back 7 times. (7*13+8)
; "WASTE 99 T-STATES"
;; KB-2
L0143: LD HL,($401E) ; (16) fetch two-byte FRAMES value.
INC HL ; ( 6) increment
LD ($401E),HL ; (16) and store in FRAMES again.
; now read the keyboard
LD HL,$FFFF ; (10) prepare a buffer
LD B,$FE ; ( 7) set B to $FE
LD C,B ; ( 4) now BC is $FEFE - slightly slower than
; the equally time-critical LD BC,$FEFE (10)
; that is used in the ZX81 ROM.
IN A,(C) ; (12) now read port $FEFE the half-row with
; the shift key.
; "START FRAME SYNC"
; START COUNTING
OR $01 ; (7) set the rightmost bit so as to ignore
; shift.
;; EACH-LINE
L0154: OR $E0 ; [7] OR 11100000.
LD D,A ; [4] transfer to D.
CPL ; [4] complement - only bits 4-0 meaningful now.
CP $01 ; [7] sets carry if A is zero.
SBC A,A ; [4] $FF if $00 else zero.
OR B ; [4] $FF or port FE,FD,FB....
AND L ; [4] unless more than one key, L will still
; be $FF if more than one key pressed A
; is now invalid
LD L,A ; [4] transfer to L.
; now consider the column identifier.
LD A,H ; [4] will be $FF if no previous keys.
AND D ; [4] 111xxxxx
LD H,A ; [4] transfer A to H
; since only one key may be pressed, H will, if valid, be one of
; 11111110, 11111101, 11111011, 11110111, 11101111
; reading from the outer column, say Q, to the inner column, say T.
RLC B ; [8] rotate the 8-counter/port address.
; sets carry if more to do.
IN A,(C) ; [12] read another half-row.
; all five bits this time.
JR C,L0154 ; [12],(7) loop back, until done, to EACH-LINE
; (658 T-states).
; the last row read is SHIFT,Z,X,C,V for the second time.
RRA ; (4) test the shift key - carry reset if
; pressed.
;; KB-3
L0168: RL H ; (8) rotate H to the left picking up the carry.
; giving column values -
; $FD, $FB, $F7, $EF, $DF.
; or $FC, $FA, $F6, $EE, $DE if shifted.
; we now have H identifying the columns and L identifying the row of the
; keyboard matrix.
; This is a good time to test if this is an American or British machine.
; The US machine has an extra diode that causes bit 6 of a byte read from a
; port to be reset.
RLA ; (4) compensate for the shift test.
RLA ; (4) rotate bit 7 out.
RLA ; (4) test bit 6.
SBC A,A ; (4) $FF or $00 (USA)
AND $18 ; (7) and 24
ADD A,$20 ; (7) add 32
; gives either 32 (USA) or 56 (UK) blank lines above the TV picture.
; This value will be decremented for the lower border.
LD ($4023),A ; (13) place margin in RESULT_hi.
; The next snippet tests that the same raw key is read twice in succession.
; The first time through, the routine uses a character address value,
; which is inappropriate to match against a key value, but the next time
; through it matches the key value it placed there on the first pass.
; Seems to be 713 T-states.
;
; "717 T-STATES SINCE START OF FRAME SYNC, 545 BEFORE END"
LD BC,($4026) ; (20) fetch possible previous key value from
; CH_ADD
LD ($4026),HL ; (16) put the fresh key value in CH_ADD.
LD A,B ; ( 4) fetch high byte.
ADD A,$02 ; ( 7) test for $FF, no-key which will set
; carry.
SBC HL,BC ; (15) subtract the two raw keys.
EX DE,HL ; ( 4) result, possibly zero, to DE.
LD HL,$4022 ; (10) now address system variable RESULT.
LD A,(HL) ; ( 7) load A from RESULT_lo.
OR D ; ( 4) check the
OR E ; ( 4) subtraction result.
RET Z ; ( 5,11) return if all three zero. >>>
; T-states = 96 so far
; proceed to debounce. The 'no-key' value $FF must be returned five times
; before a new key is accepted above.
; Holding down a key causes the shift counter to be maintained at five.
; The initial state of RESULT is unimportant.
LD A,B ; ( 4) fetch hi byte of PREVIOUS key code.
CP $FE ; ( 7) sets carry if valid -
; $FD, $FB, $F7, $EF, $DF
SBC A,A ; ( 4) gives $FF if pressed or $00 if no-key.
LD B,$1F ; ( 7) prepare the shift counter
; (and also the timed delay)
OR (HL) ; ( 7) OR with RESULT_lo
AND B ; ( 4) limit the count to five set bits.
RRA ; ( 4) 'shift' to right
LD (HL),A ; ( 7) place result in RESULT_lo
DEC B ; ( 4) adjust the delay counter B to thirty.
; t states = 48 ( Total 96+48=144)
;; KB-4
L0194: DJNZ L0194 ;; (13,8) wait a while looping to KB-4
;; equals 13*29+8 = 385
; "FRAME SYNC ENDS AT NEXT M1"
OUT ($FF),A ;; (11) stops the VSYNC pulse
LD A,$EC ;; ( 7) the value for R register
LD B,$19 ;; there are 25 HALTs including the initial
;; one.
LD HL,($400C) ;; point HL to D-FILE the first HALT
;; instruction.
SET 7,H ;; now point to the DFILE echo in the
;; top 32K of address space.
CALL L01AD ;; routine DISP-2
LD A,$F3 ;; prepare to set the R refresh register to $F3.
INC B ;; increment the line count
DEC HL ;; decrement screen address.
DEC (IY+$23) ;; decrement RESULT_hi the blank line counter.
JR L013C ;; back to display and read
; ---
;; DISP-2
L01AD: LD C,(IY+$23) ;; load C the col count from RESULT_hi.
LD R,A ;; R increments with each opcode until A6
;; goes low which generates the INT signal.
LD A,$DD ;; set the left margin of all other lines.
;; loaded later to R - the incremental refresh
;; register.
EI ;; with R set up, enable interrupts.
JP (HL) ;; jump to execute the echo DFILE starting with
;; HALT and waits for the first INT to
;; come to the rescue.
; --------------------------
; THE 'SAVE' COMMAND ROUTINE
; --------------------------
; There isn't a program name involved.
; The routine saves the System Variables, Program Area and BASIC Variables.
; One of the five System commands that cannot be used from within a program.
;; SAVE
L01B6: POP DE ; discard return address.
LD DE,$12CB ; timing value of 5 seconds for leader.
;; SAVE-1
L01BA: LD A,$7F ; read port $7FFE.
IN A,($FE) ; all 16 bits are placed on address bus.
RRA ; test for the space key.
JR NC,L0203 ; forward, if pressed, indirectly to MAIN-EXEC.
;; SAVE-2
L01C1: DJNZ L01C1 ; delay self-looping to SAVE-2
DEC DE ; decrement
LD A,D ; and test
OR E ; for zero.
JR NZ,L01BA ; back if not zero to outer delay loop SAVE-1.
LD HL,$4000 ; commence saving at start of RAM.
;; SAVE-3
L01CB: LD DE,$F808 ; register E counts the 8 bits.
; $F8 is first delay.
;; EACH-BIT
L01CE: RLC (HL) ; spin the actual program byte.
SBC A,A ; $FF or $00.
AND $05 ; $05 or $00.
ADD A,$04 ; $09 or $04.
LD C,A ; timer to C.
; a set bit has a pulse longer than
; an unset bit.
;; SAVE-4
L01D6: OUT ($FF),A ; pulses
LD B,$24 ; delay counter.
;; SAVE-5
L01DA: DJNZ L01DA ; self loop for delay to SAVE-5
LD A,$7F ; read the space row and hold for later.
IN A,($FE) ; also ...
LD B,$23 ; another delay counter.
;; SAVE-6
L01E2: DJNZ L01E2 ; self loop for delay2 to SAVE-6
DEC C ; decrement pulse counter
JR NZ,L01D6 ; back while more to SAVE-4.
LD B,D ; a terminating delay - D is zero (256).
;; SAVE-7
L01E8: NOP ; 4 T-states.
DJNZ L01E8 ; execute the NOP 256 times.
LD D,$FE ; subsequent timing value
DEC E ; decrement the 8 counter.
JR NZ,L01CE ; back if more to EACH-BIT.
RRA ; test for space key pressed at last test.
JR NC,L0203 ; forward, if so, indirectly to MAIN-EXEC.
CALL L01F8 ; routine TEST-END does not return if at
; the end. >>
JR L01CB ; else back to do another byte.
; ---
; This subroutine is used by both the SAVE and LOAD command routines
; to check when the required area has been completed and to then make an exit
; from the called loop.
; Note. that for the LOAD command the value of E_LINE is not that at the outset
; of the LOAD command but at the start of the command that saved the section.
; The first bytes to be loaded are the System Variables and E_LINE will be the
; eleventh and twelfth bytes to be loaded. The low byte is read in before the
; high byte so after the low byte is read in, E_LINE is in an indeterminate
; state. Hence E_LINE_hi is incremented at the outset to avoid a premature
; end to loading.
;; TEST-END
L01F8: INC HL ; increase pointer.
EX DE,HL ;
LD HL,($400A) ; load HL with E_LINE - the location following
; the variables end-marker.
SCF ; force a carry when equal.
SBC HL,DE ; trial subtraction.
EX DE,HL ; restore pointer.
RET NC ; return if more bytes to do.
POP HL ; else drop the return address.
;; JUMP-EXEC
L0203: JP L0283 ; JUMP forward to MAIN-EXEC.
; Note. the above jump could be replaced by a relative jump saving one
; instruction byte. A few other direct jumps to this destination could be
; replaced with a series of relative jumps as has been done elsewhere.
; --------------------------
; THE 'LOAD' COMMAND ROUTINE
; --------------------------
; A System Command to load a program from tape.
;; LOAD
L0206: POP DE ; discard the return address.
;; LOAD-1
L0207: LD DE,$5712 ; set a timing constant.
;; LOAD-2
L020A: LD A,$7F ; read from port $7FFE.
IN A,($FE) ; the keyboard row with space.
RRA ; test the outer key.
JR NC,L0203 ; back, if pressed, indirectly to MAIN-EXEC
RLA ; cancel the above RRA.
RLA ; now do an RLA to read tape signal - bit 7.
JR C,L0207 ; back without signal to outer loop LOAD-1.
DEC DE ; decrement timer
LD A,D ; and test
OR E ; for zero.
JR NZ,L020A ; back if not to inner loop LOAD-2.
INC (IY+$0B) ; increment E_LINE_hi to prevent premature
; end after loading E_LINE-lo.
; see TEST-END.
LD HL,$4000 ; start of RAM - system variables to be
; overwritten.
;; LOAD-3
L0220: LD E,$08 ; the bit counter for each byte.
;; LOAD-4
L0222: LD A,$7F ; test the keyboard
IN A,($FE) ; reading the
RRA ; space key.
JR NC,L024D ; forward, if space pressed, to LD-ABORT.
RLA ; restore to original state.
RLA ; now test the tape bit.
JR NC,L0222 ; back if ???? to LOAD-4
; start building up a byte.
LD C,$94 ; set timing value. The exit value of this
; register determines if a bit was set or unset.
;; LOAD-5
L022F: LD B,$1A ; inner timer
;; LOAD-6
L0231: DEC C ; decrement counter.
IN A,($FE) ; read the tape port.
RLA ; test the tape bit.
BIT 7,C ; test if counter above 127. A set bit.
LD A,C ; save in A.
JR C,L022F ; back while bit set to LOAD-5
DJNZ L0231 ; decrement B counter and loop while not
; zero to LOAD-6.
; Note. this instruction has no effect on any
; flags.
JR NZ,L0242 ; forward if C was > $7F (with NC) to LOAD-7
CP $56 ; compare copy of counter to $56
JR NC,L0222 ; back if $56-$7F to LOAD-4
;; LOAD-7
L0242: CCF ; else clear if from above but set carry if
; branching to here.
RL (HL) ; rotate the bit into position.
DEC E ; decrement the eight counter
JR NZ,L0222 ; loop back for entire byte.
CALL L01F8 ; routine TEST-END quits early at end.
JR L0220 ; and back to load another byte.
; ---------------------------
; THE 'LOAD ABORT' EXIT ROUTE
; ---------------------------
; If the LOAD command has started to load data then a reset is performed.
; If it's still waiting for the leader then rejoin the main execution loop
; after restoring the location of the Edit Line to its correct value.
;; LD-ABORT
L024D: DEC D ; ??
JP P,L0000 ; a reset
DEC (IY+$0B) ; restore E_LINE_hi to a valid state.
JR L0203 ; indirect jump to MAIN-EXEC.
; --------------------------
; THE 'LIST' COMMAND ROUTINE
; --------------------------
; Another System command that can't be used from within a program.
;; LIST
L0256: RES 7,B ; start by making the high byte,
; of an invalid, user-supplied,
RES 6,B ; line number within range $00-$3F.
; this invisible mending is inappropriate and it is preferable to tell the
; user of any typos. e.g. LIST 40000 is silently changed to LIST 7232
; when the user probably meant to type LIST 4000. However space is tight.
LD ($4006),BC ; set E-PPC from line number.
POP BC ; discard return address.
JR L0283 ; forward to MAIN-EXEC which produces an
; 'automatic listing'.
; ----------------------------
; THE 'INITIALIZATION' ROUTINE
; ----------------------------
; A holds $3F, HL holds $7FFF.
;; RAM-FILL
L0261: LD (HL),$01 ; fill location with 1 (null).
DEC HL ; decrement address.
CP H ; compare address high byte to $3F.
JR NZ,L0261 ; back, while higher, to RAM-FILL.
;; RAM-READ
L0267: INC HL ; address the next higher location.
DEC (HL) ; decrement to zero.
JR Z,L0267 ; back, if successful to RAM-READ.
; else we have encountered first unpopulated RAM location.
LD SP,HL ; initialize stack pointer at end.
PUSH AF ; place gosub end-marker $3F??
LD A,$0E ; set the I register to $0E to tell
LD I,A ; the video hardware where to find
; the character set ($0E00).
IM 1 ; select Interrupt Mode 1.
LD IY,$4000 ; set IY to the start of the forty system
; variables.
; -----------------------------------------------------------------------------
;
; ---------------------
; THE 'ZX80 MEMORY MAP'
; ---------------------
;
; There are forty ($28) system variables followed by Program area
; These are located at the start of RAM.
;
; +---------+---------+-----------+---+-----------+-----------+-------+-------+
; | | | | | | | | |
; | SYSVARS | Program | Variables |80h| WKG Space | Disp File | Spare | Stack |
; | | | | | | | | |
; +---------+---------+-----------+---+-----------+-----------+-------+-------+
; ^ ^ ^ ^ ^ ^ ^
; $4024 VARS E_LINE D_FILE DF_END SP
; DF_EA
;
; -----------------------------------------------------------------------------
LD HL,$4028 ; set to location after sysvars.
LD ($4008),HL ; set the system variable VARS.
LD (HL),$80 ; and insert variables end-marker.
INC HL ; address the next location.
LD ($400A),HL ; set the system variable E_LINE.
; and continue...
; -------------------------
; THE 'MAIN EXECUTION' LOOP
; -------------------------
; This is the MAIN EXECUTION LOOP that handles the creation and interpretation
; of user input. The various 'subroutines' from this main loop including those
; launched from the Editing Keys Table are really just branches which all
; ultimately jump back to here. Although service routines make use of the
; machine stack, the stack is generally empty and only has one return address
; on it during command execution.
;; MAIN-EXEC
L0283: LD HL,($400A) ; fetch E-LINE
LD (HL),$B0 ; insert the character inverse 'K'.
INC HL ; address the next location.
LD (HL),$76 ; insert a newline.
INC HL ; address the next location.
LD ($400C),HL ; set D-FILE to start of dynamic display file.
LD (IY+$12),$02 ; set DF-SZ to 2 lines.
; ->
;; AUTO-LIST
L0293: CALL L0747 ; routine CLS sets a minimal display and
; initializes screen values in registers.
EX DE,HL ;
LD A,B ; load line value, 23, to A.
SUB (IY+$12) ; subtract DF-SZ of lower screen.
JR C,L02F7 ; forward if the lower screen is 24 lines
; to ED-COPY.
INC A ; allow for a blank line.
LD B,A ; place in B line
EXX ; switch to preserve line/column values.
LD HL,($4006) ; fetch E_PPC the current line number.
LD DE,($4013) ; fetch the top line on screen from S_TOP.
SBC HL,DE ; subtract the two BASIC line numbers
EX DE,HL ; and bring S_TOP to HL.
JR NC,L02B0 ; forward if current line >= top line to LIST-1.
ADD HL,DE ; else reform the E_PPC value
LD ($4013),HL ; and make S_TOP the same.
;; LIST-1
L02B0: CALL L060A ; routine LINE-ADDR gets the address of the
; BASIC line in HL.
LD E,$00 ; signal current line yet to be printed
;; LIST-ALL
L02B5: CALL L04F7 ; routine OUT-LINE
JR C,L02B5 ; loop until upper screen is full to LIST-ALL.
DEC E ; test if current line has appeared.
JR NZ,L02F0 ; forward to LIST-DONE if current line
; has appeared.
; else the current line has yet to appear.
PUSH HL ; else save HL ( )
LD HL,($4006) ; fetch E_PPC - the current line.
CALL L060A ; routine LINE-ADDR in DE
POP HL ; restore HL
AND A ; prepare to subtract.
SBC HL,DE ; subtract setting carry.
LD HL,$4013 ; address system variable S_TOP
JR NC,L02D8 ; forward if E_PPC precedes to LN-FETCH
EX DE,HL ; else swap pointers.
LD A,(HL) ; pick up high byte.
INC HL ; address low byte.
LDI ; copy low byte to S_TOP_lo.
LD (DE),A ; insert the high byte.
;; AUTO-L-J
L02D3: JR L0293 ; back to AUTO-LIST.
; ------------------------------------
; THE 'CURSOR DOWN EDITING' SUBROUTINE
; ------------------------------------
;; ED-DOWN
L02D5: LD HL,$4006 ; address system variable E_PPC
; and continue...
; ----------------------
; THE 'LN-FETCH' SECTION
; ----------------------
;; LN-FETCH
L02D8: LD E,(HL) ;
INC HL ;
LD D,(HL) ;
PUSH HL ;
EX DE,HL ;
INC HL ; increment as starting point
CALL L060A ; routine LINE-ADDR
CALL L03C2 ; LINE-NO
POP HL ; restore hi pointer.
; ----------------------
; THE 'LN-STORE' SECTION
; ----------------------
; On entry, HL holds E_PPC_hi.
;; LN-STORE
L02E5: BIT 5,(IY+$19) ; test FLAGX.
JR NZ,L02F7 ; forward if INPUT to ED-COPY.
LD (HL),D ; insert high byte
DEC HL ; DECrement
LD (HL),E ; insert low byte
;
JR L0293 ; back to AUTO-LIST
; --------------------------
; THE 'LIST-DONE' SUBROUTINE
; --------------------------
; When the listing is complete then the rest of the upper display is blanked,
; to erase what may have been printed during the interim, the display file
; cursor is updated and the current line is printed in the lower screen.
;; LIST-DONE
L02F0: CALL L05C2 ; CL-EOD clear to end of upper display.
LD ($400E),DE ; set lower screen position DF_EA
; to end
; and continue...
; -------------------------------------
; THE 'LOWER SCREEN COPYING' SUBROUTINE
; -------------------------------------
; This is called.
; When the line in the editing area is to be printed in the lower screen.
; It is by repeatedly printing the line when any key is pressed that the
; cursor for instance appears to move.
; It is called in a similar fashion to animate the input line.
;; ED-COPY
L02F7: LD (IY+$01),$01 ; set FLAGS leading space allowed
LD HL,($400A) ; E_LINE
CALL L07BE ; routine MAIN-G checks syntax of line.
LD DE,($400E) ; fetch start of lower screen from DF_EA
LD B,(IY+$12) ; fetch lines in lower screen from DF_SZ
LD C,$01 ; set column to 1
; to print an initial newline for gap?
EXX ;
LD HL,($400A) ; fetch start of edit line from E_LINE
CALL L0512 ; routine OUT-LINE-2 prints characters starting
; with the individual digits of line number.
JR C,L031D ; forward with success to LINE-DONE
; else there wasn't enough room in lower screen for line.
LD HL,$4012 ; address DF_SZ the Display Size for
; the lower screen.
INC (HL) ; increment it.
LD A,$18 ; load A with 24 decimal.
CP (HL) ; compare to DF-SZ
JR NC,L02D3 ; indirect jump back to AUTO-LIST
; if no greater than 24 lines.
LD (HL),A ; else limit to 24 lines.
;; LINE-DONE
L031D: CALL L05C2 ; routine CL-EOD clears to the end of lower
; screen
CALL L013F ; routine KEYBOARD gets key values in BC.
; now decode the value
SRA B ; sets carry if unshifted (bit 7 remains set)
SBC A,A ; $FF unshifted, else $00
OR $26 ; $FF unshifted, else $26
LD L,$05 ; there are five keys in each row.
SUB L ; set the starting point
;; KEY-LINE
L032B: ADD A,L ; add value 5 (or 1)
SCF ; carry will go to bit 7
RR C ; test C (which has 1 unset bit identifying row)
JR C,L032B ; back if carry to KEY-LINE
; if only one key pressed C should now be $FF.
INC C ; test for $FF
JR NZ,L02F7 ; back if multiple keys to ED-COPY
; the high byte of the key value identifies the column - again only one bit is
; now reset.
LD C,B ; transfer to B
DEC L ; test if this is first time through
LD L,$01 ; reduce increment from five to one.
JR NZ,L032B ; back if L was five to KEY-LINE
; The accumulator now holds a key value 1-78 decimal.
LD HL,L006C - 1 ; location before the MAIN-KEYS table ($006B)
; the index value is 1 - 78.
LD E,A ; code to E (D is zero from keyboard)
ADD HL,DE ; index into the table.
LD A,(HL) ; pick up the letter/number/.
BIT 2,(IY+$01) ; test FLAGS K-MODE ?
JR Z,L034D ; skip forward if not
ADD A,$C0 ; add 192 decimal
; e.g. 'A' 38d + 192 = 230 (LIST)
CP $E6 ; compare to 'LIST'
JR NC,L034D ; skip forward if command tokens to EDC-2.
LD A,(HL) ; else load A from HL again
; (numbers and symbols)
;; EDC-2
L034D: CP $C0 ; set the overflow flag for editing key $70-$77
JP PE,L035E ; forward with range $40 - $7F to ED-KEYS
LD HL,($4004) ; else fetch keyboard cursor from P_PTR
LD BC,$0001 ; one space required.
CALL L05D5 ; routine MAKE-ROOM makes room at cursor.
; note HL - first, DE - LAST
LD (DE),A ; and insert the keyboard character.
;; EDC-JR
L035C: JR L02F7 ; loop back to ED-COPY
; -----------------------------
; THE 'EDITING KEYS' SUBROUTINE
; -----------------------------
;; ED-KEYS
L035E: LD E,A ; transfer code to E.
; (D holds zero from 'keyboard')
LD HL,L0372-$70-$70; theoretical base of ED-K-TAB $0292
ADD HL,DE ; index twice
ADD HL,DE ; as a two-byte address is required.
LD C,(HL) ; low byte of routine.
INC HL
LD B,(HL) ; high byte of routine.
PUSH BC ; push routine address to stack.
LD HL,($4004) ; set HL to cursor from P_PTR
RET ; jump to routine.
; Note the stack is empty.
; ---------------------------------------------
; THE EDITING 'DELETE ONE CHARACTER' SUBROUTINE
; ---------------------------------------------
;; ED-DEL-1
L036C: LD BC,$0001 ; one character
JP L0666 ; routine RECLAIM-2
; ------------------------
; THE 'EDITING KEYS' TABLE
; ------------------------
;; ED-K-TAB
L0372: DEFW L03A9 ; ED-UP $70
DEFW L02D5 ; ED-DOWN $71
DEFW L0382 ; ED-LEFT $72
DEFW L0387 ; ED-RIGHT $73
DEFW L03B9 ; ED-HOME $74
DEFW L03CB ; ED-EDIT $75
DEFW L0408 ; ED-ENTER $76
DEFW L0395 ; ED-DELETE $77
; ------------------------------------
; THE 'CURSOR LEFT EDITING' SUBROUTINE
; ------------------------------------
;; ED-LEFT
L0382: CALL L039E ; routine ED-EDGE checks that cursor
; not at start without disturbing HL.
; quits early if not possible. >>
DEC HL ; move left.
DEC HL ; and again for luck.
; ...
; -------------------------------------
; THE 'CURSOR RIGHT EDITING' SUBROUTINE
; -------------------------------------
;; ED-RIGHT
L0387: INC HL ; move right
LD A,(HL) ; pick up the character.
CP $76 ; is it newline ?
JR Z,L03A7 ; triple jump back to ED-COPY if so.
LD (HL),$B0 ; else place inverse cursor there.
LD HL,($4004) ; fetch P_PTR
LD (HL),A ; and put character there
JR L035C ; double jump back to ED-COPY
; -------------------------------
; THE 'DELETE EDITING' SUBROUTINE
; -------------------------------
;; ED-DELETE
L0395: CALL L039E ; routine ED-EDGE will loop back to
; ED-COPY if no deletion possible >>
DEC HL ; decrement position
CALL L036C ; routine ED-DEL-1
JR L035C ; back to ED-COPY
; ------------------------
; THE 'ED-EDGE' SUBROUTINE
; ------------------------
;; ED-EDGE
L039E: LD DE,($400A) ; fetch E_LINE - start of edit line.
LD A,(DE) ; pick up first character.
CP $B0 ; test for inverse 'K'
RET NZ ; return if cursor not at start.
POP DE ; else drop the return address.
;; EDC-JR2
L03A7: JR L035C ; and back to ED-COPY
; ----------------------------------
; THE 'CURSOR UP EDITING' SUBROUTINE
; ----------------------------------
;; ED-UP
L03A9: LD HL,($4006) ; E_PPC
CALL L060A ; routine LINE-ADDR
EX DE,HL
CALL L03C2 ; LINE-NO
;; ED-LINE
L03B3: LD HL,$4007 ; E_PPC_hi
JP L02E5 ; to LN-STORE to store new line
; and produce an automatic listing.
; ------------------------
; THE 'ED-HOME' SUBROUTINE
; ------------------------
; ED-HOME (SHIFT 9) starts the listing at the first line.
; dropped in later ZX computers.
;; ED-HOME
L03B9: LD DE,$0000 ; start at 'line zero'
JR L03B3 ; back to ED-LINE above.
; --------------------------------------
; THE 'COLLECT A LINE NUMBER' SUBROUTINE
; --------------------------------------
;; LINE-NO-A
L03BE: EX DE,HL ; bring previous line to HL
; and set DE in case we loop back a second time.
LD DE,L03B9 + 1 ; address of $00 $00 within the subroutine
; above.
; -> The Entry Point.
;; LINE-NO
L03C2: LD A,(HL) ; fetch hi byte of line number
AND $C0 ; test against $3F
JR NZ,L03BE ; back to LINE-NO-A if at end.
LD D,(HL) ; else high byte to D
INC HL ; increase pointer
LD E,(HL) ; low byte in E.
RET ; return.
; with next line number in DE
; -------------------------
; THE 'EDIT KEY' SUBROUTINE
; -------------------------
; Pressing the EDIT key causes the current line to be copied to the
; edit line. The two-byte line number is converted into 4 characters
; using leading spaces if the line is less than 1000. Next the 'K'
; cursor is inserted and the rest of the characters are copied verbatim
; into the edit buffer, keywords remaining as single character tokens.
;; ED-EDIT
L03CB: LD C,$00 ; set column to zero to inhibit a line feed
; while 'sprinting' to the edit line.
; see PRINT-A-2.
LD DE,($400A) ; set DE (print destination) to E_LINE
EXX ; switch.
LD HL,($4006) ; E_PPC current line.
CALL L060A ; routine LINE-ADDR
CALL L03C2 ; routine LINE-NO
LD A,D
OR E
JP Z,L0283 ; back if zero to MAIN-EXEC
; no program.
DEC HL ; point to location before
CALL L06BF ; routine OUT-NUM-2 prints line number
; to the edit line (unseen).
DEC HL ; point to line number again
CALL L0624 ; routine NEXT-ONE gets length in
; BC register.
INC HL ; point to the
INC HL ; first token.
DEC BC ; decrease the length
DEC BC ; by the same.
EXX
PUSH DE ; pick up the print position in the
EXX ; edit line.
POP DE ; and pop it to this set of registers
LD A,$B0 ; the inverse 'K' cursor
LD (DE),A ; is inserted after line number.
INC DE ; address next 'print' location.
PUSH HL ; push position within program.
LD HL,$0022 ; an overhead of 34d bytes.
ADD HL,DE ; add to edit line position
ADD HL,BC ; add in length of line.
SBC HL,SP ; subtract the stack pointer.
JR NC,L03A7 ; back to ED-COPY if not enough
; room to fill edit line.
POP HL ; restore program position.
LDIR ; and copy it to edit line.
LD ($400C),DE ; update D_FILE
JP L0293 ; jump back to AUTO-LIST
; ------------------------------
; THE 'ENTER EDITING' SUBROUTINE
; ------------------------------
; This causes the line to be parsed.
; The subroutine then loops back to MAIN-EXEC.
;; ED-ENTER
L0408: LD HL,($4015) ; fetch X_PTR the error pointer.
LD A,H ; check that it is
OR L ; zero - no error.
JR NZ,L03A7 ; double jump back to ED-COPY
; if an error has occurred during
; syntax checking.
LD HL,($4004) ; P_PTR
CALL L036C ; ED-DEL-1 gets rid of cursor.
LD HL,($400A) ; E_LINE
LD ($4026),HL ; CH_ADD
CALL L001A ; get-char
BIT 5,(IY+$19) ; FLAGX input 1/edit 0
JR NZ,L043C ; forward to MAIN-1 if in input mode.
; else the edit line is to be run.
CALL L0679 ; INT-TO-HL line number to HL'
EXX ; switch in set with the line number.
LD A,H ; and test
OR L ; for zero.
JP NZ,L04BA ; jump forward with a number to MAIN-ADD
; to add a new BASIC line or replacement.
; else must be a direct command.
DEC HL ; make the line number
DEC HL ; the value minus two.
LD ($4002),HL ; and set PPC
CALL L0747 ; routine CLS
EXX ;
LD A,(HL) ; fetch first character.
CP $76 ; is it just a newline ?
JP Z,L0283 ; jump back with newline to MAIN-EXEC
; to produce an automatic listing.
; else check syntax and enter
;; MAIN-1
L043C: LD (IY+$00),$FF ; set ERR_NR to no error
LD (IY+$01),$88 ; update FLAGS
; set bit 7 - syntax checking off
; set bit 3 - 'K' mode
;; M-2
L0444: CALL L07BE ; routine MAIN-G parses and executes the line.
; Note. this causes the value L0447 to be placed
; on the machine stack as a return address.
;; M-3
L0447: CALL L0D0A ; REC-EDIT reclaims the edit line
LD DE,($4002) ; fetch current line number from PPC
LD HL,$4019 ; address FLAGX
BIT 5,(HL) ; test FLAGX - input???
JR Z,L0458 ; skip if editing to ->
RES 5,(HL) ; update FLAGX - signal editing.
INC DE ; increase line number so cursor doesn't show.
;; M-4
L0458: BIT 7,(IY+$00) ; check ERR_NR.
JR Z,L0488 ; forward if an error has occurred.
LD HL,$4001 ; address FLAGS system variable
BIT 3,(HL) ; test FLAGS - K mode ?
RES 3,(HL) ; update FLAGS - set L mode for future anyway.
LD HL,($4026) ; fetch character address CH_ADD
INC HL ;
JR Z,L0474 ; forward if not K mode.
EX DE,HL ; current line to HL, next char to DE.
LD A,H ; fetch high byte of line number.
AND $C0 ; test for -2, -1 - direct command.
JR NZ,L0488 ; forward to MAIN-ERR if so
CALL L060A ; routine LINE-ADDR gets address of this line.
;; M-5
L0474: LD A,(HL) ; fetch
AND $C0 ;
JR NZ,L0488 ; at program end
; else pick up the next line number
LD D,(HL) ;
INC HL ;
LD E,(HL) ;
LD ($4002),DE ; place in PPC system variable
INC HL ; point to first character
; (space or command)
LD A,$7F ; test for
IN A,($FE) ; space key pressed.
RRA ; the space bit.
JR C,L0444 ; back if BREAK
; else continue...
;; MAIN-ERR
L0488: CALL L06E0 ; UNSTACK-Z quits if checking syntax >>>
CALL L05C2 ; routine CL-EOD clears to the end of upper
; display area.
LD BC,$0120 ; set line 1, column 32 for lower screen.
EXX ;
LD A,($4000) ; fetch the error number from ERR_NR
LD BC,($4002) ; fetch the current line from PPC
INC A ; test if error still $FF
JR Z,L04A8 ; forward if so to MAIN-5.
CP $09 ; is the error the STOP statement ?
JR NZ,L04A1 ; forward if not STOP to SET-CONT to make the
; continuing line the same as current.
INC BC ; else increment line number for STOP.
;; SET-CONT
L04A1: LD ($4017),BC ; store line number in OLDPPC
JR NZ,L04A8 ; forward if not STOP as line number is current
DEC BC ; else decrement line number again.
; Now print the report line e.g. 100/0 (terminated OK at line 100)
;; MAIN-5
L04A8: CALL L0556 ; routine OUT-CODE prints line number
LD A,$15 ; prepare character '/'
RST 10H ; print the separator
CALL L06A1 ; OUT-NUM-1 to print error-code in A.
CALL L05C2 ; routine CL-EOD
CALL L013F ; routine KEYBOARD
JP L0283 ; jump back to MAIN-EXEC
; ---------------------
; THE 'MAIN-ADD' BRANCH
; ---------------------
; This section allows a new BASIC line to be added to the Program.
;; MAIN-ADD
L04BA: LD ($4006),HL ; make E_PPC the new line number.
EXX ;
EX DE,HL ;
CALL L0747 ; routine CLS
SBC HL,DE ;
EXX ;
CALL L060A ; routine LINE-ADDR
PUSH HL ;
JR NZ,L04D1 ; forward if line doesn't exist to MAIN-ADD1.
CALL L0624 ; routine NEXT-ONE gets length of old line
CALL L0666 ; routine RECLAIM-2
;; MAIN-ADD1
L04D1: EXX ;
INC HL ;
LD B,H ;
LD C,L ;
LD A,L ;
SUB $03 ;
OR H ;
CALL NZ,L094F ; routine TEST-ROOM
POP HL ;
JR NC,L04F4 ; double jump back to MAIN-EXEC
; not possible.
PUSH BC ;
DEC HL ;
CALL L05D5 ; routine MAKE-ROOM
INC DE ;
LD HL,($400C) ; set HL from D_FILE
DEC HL ; now points to end of edit line.
POP BC ; restore length
DEC BC ;
LDDR ; copy line from edit line to prog.
LD HL,($4006) ; E_PPC - line number
EX DE,HL ; swap
LD (HL),D ; insert high byte
INC HL ;
LD (HL),E ; insert low byte
;; MAIN-JR
L04F4: JP L0283 ; jump back to MAIN-EXEC
; -----------------------------------------
; THE 'PRINT A WHOLE BASIC LINE' SUBROUTINE
; -----------------------------------------
;; OUT-LINE
L04F7: LD BC,($4006) ; fetch E_PPC
CALL L061C ; routine CP-LINES
LD D,$97 ; prepare character '>'
JR Z,L0507 ; forward with line cursor if line is the
; current edit line to OUT-LINE-1
LD DE,$0000 ; else replace line cursor with a
; space in D, and zero to E.
RL E ; pick up any carry from CP-LINES
; should the line precede the
; current edit line.
;; OUT-LINE-1
L0507: LD A,(HL) ; fetch the high byte of line number.
CP $40 ; compare with end marker
CALL C,L06BF ; routine OUT-NUM-2 if a valid line number.
RET NC ; return if out of screen >>>
INC HL ; address the first command character.
LD A,D ; fetch the space/cursor
RST 10H ; print it.
RET NC ; return if out of screen.
;; OUT-LINE-2
L0512: SET 0,(IY+$01) ; update FLAGS - suppress a leading space
;; OUT-LINE-3
L0516: LD BC,($4015) ; fetch error pointer - X_PTR
AND A ; prepare to subtract.
SBC HL,BC ; subtract the current address.
JR NZ,L0523 ; forward to OUT-LINE-4 if not an
; exact match.
LD A,$B8 ; prepare inverse 'S' to show syntax error.
RST 10H ; print it.
RET Z ; return if at end
;; OUT-LINE-4
L0523: ADD HL,BC ; restore pointer.
LD A,(HL) ; fetch character.
INC HL ; address next character.
CP $B0 ; is character inverse 'K' ?
JR Z,L053C ; forward if so to OUT-CURS.
; then cleverly split the characters into 4 streams.
CP $C0 ; compare character to 192 ?
JP PE,L0559 ; jump forward with 64-127 to OUT-SP-CH
; thereby exiting the routine
; as it must be the 118, NEWLINE character.
JR C,L0536 ; forward with 0-63, 128-191 to OUT-LINE-5
; to print simple characters and their inverse
; forms.
; that leaves tokens $C0 - $FF
CALL L0584 ; routine PO-TOKEN
JR L0539 ; forward to OUT-LINE-6
; ---
;; OUT-LINE-5
L0536: CALL L0559 ; routine OUT-SP-CH
;; OUT-LINE-6
L0539: RET NC ; return if out of screen. >>
JR L0516 ; else back to OUT-LINE-3 for more.
; ---------------------------------------------------------------------------
; Z80 PARITY/OVERFLOW FLAG:
; ------------------------
; The use of this flag is two-fold depending on the type of operation.
; It indicates the parity of the result of a LOGICAL operation such as an AND,
; OR, XOR by being set PE if there are an even number of set bits and reset
; PO if there are an odd number of set bits.
; so 10101010 is parity even, 00000001 is parity odd.
; JP PE, LABEL
; JP PO, LABEL are obvious.
; For MATHEMATICAL operations, (ADD, SUB, CP etc.) the P/V bit indicates a
; carry out of bit position 6 of the accumulator if signed values are being
; used.
; This indicates an overflow of a result greater than 127, which carries
; into bit 7, the sign bit.
; So as CP is just a SUB with the result thrown away.
; $C0 SUB $CO gives result $00 (PO - no overflow from 6 to 7)
; $8O SUB $C0 gives result $C0 (PO - no overflow from 6 to 7)
; $00 SUB $C0 gives result $40 (PO - no overflow from 6 to 7)
; $40 SUB $CO gives result $80 (PE - overflow from 6 to 7)
; The overflow flag is similarly set following 16-bit addition and subtraction
; routines.
; ---------------------------------------------------------------------------
; -----------------------------
; THE 'PRINT THE CURSOR' BRANCH
; -----------------------------
;; OUT-CURS
L053C: BIT 2,(IY+$01) ; test FLAGS - K-mode ?
JR NZ,L0543 ; skip to OUT-K if 'K' mode.
INC A ; change from 'K' to 'L' cursor.
;; OUT-K
L0543: RST 10H ; print the cursor.
JR L0539 ; back to OUT-LINE-6 above.
; -----------------------------------------------------
; THE 'PRINTING CHARACTERS IN A BASIC LINE' SUBROUTINES
; -----------------------------------------------------
;; OUT-SP-2
L0546: LD A,E ; transfer E to A
; register E will be
; $FF - no leading space.
; $01 - the leading space itself.
; $1C - '0' from a previous non-space print.
RLCA ; test for the
RRCA ; value $FF.
RET C ; return if no leading space
JR L055C ; forward to OUT-LD-SP
; ---
; --> The Entry Point.
;; OUT-SP-NO
L054C: XOR A ; set accumulator to zero.
;; OUT-SP-1
L054D: ADD HL,BC ; addition of negative number.
INC A ; increment the digit.
JR C,L054D ; back while overflow exists to OUT-SP-1
SBC HL,BC ; else reverse the last addition.
DEC A ; and decrement the digit.
JR Z,L0546 ; back to OUT-SP-2 if digit is zero again.
; else continue to print the final digit using OUT-CODE.
;; OUT-CODE
L0556: LD E,$1C ; load E with '0'
; Note. that E will remain as such for all
; further calls. The leading space is no more.
ADD A,E ; add the digit 1-9 to give '1' to '9'
;; OUT-SP-CH
L0559: AND A ; test value for space.
JR Z,L0560 ; skip if zero to PRINT-A-2
;; OUT-LD-SP
L055C: RES 0,(IY+$01) ; signal allow leading space to FLAGS
; and continue...
; ------------------------------
; THE 'MAIN PRINTING' SUBROUTINE
; ------------------------------
; This is a continuation of the PRINT restart.
; It is used primarily to print to the dynamic screen checking free memory
; before every character is printed.
; However it can also be used as an invisible process to 'sprint' the line
; number of a BASIC line to the Edit Line by ED-EDIT setting DE from E_LINE.
;
; As lines are unexpanded, then when the column count is reduced from 32 to 0 a
; newline is inserted before the character and the column count is reset.
;; PRINT-A-2
L0560: EXX ; switch sets.
LD H,A ; preserve character in H.
; Note. this is restored by TEST-RM-2
RLA ; rotate character twice to
RLA ; test bit 6 - sets carry for NEWLINE.
DEC C ; decrease column count - affects zero / sign.
JR NC,L0569 ; forward if 0-63 or inverse to NO-NL
; else the incoming character is a NEWLINE $76
LD C,$00 ; set column to zero without disturbing flags.
; if this is a received NEWLINE.
; this will be set to 32 if a subsequent
; character is printed
;; NO-NL
L0569: JP M,L0574 ; jump to PR-SPR if column was originally 0
JR C,L057C ; forward to PRI-CHAR with a received NEWLINE.
JR NZ,L057C ; forward if column not yet reduced to zero
; to PRI-CHAR
; else an automatic newline is required before the received character as
; we are at end of line.
LD A,$76 ; prepare the newline
LD (DE),A ; insert at screen position
INC DE ; increase the address pointer.
;; PR-SPR
L0574: JR C,L0578 ; skip if a received newline to PRI-SKIP
LD C,$20 ; reset column to 32 decimal.
;; PRI-SKIP
L0578: AND A ; clear carry now to signal failure should the
; next test fail.
DEC B ; decrease line.
JR Z,L0582 ; forward with out of screen to PR-END.
;; PRI-CH
L057C: LD L,B ; transfer line number, B to L for next routine.
CALL L0958 ; routine TEST-RM-2 tests room.
; (character is in H returned in A)
; carry set if there is room.
LD (DE),A ; insert chr at screen (or edit line).
INC DE ; increase destination address.
;; PR-END
L0582: EXX ; switch to protect registers.
RET ; return
; -------------------------------
; THE 'TOKEN PRINTING' SUBROUTINE
; -------------------------------
;; PO-TOKEN
L0584: CALL L05A8 ; routine PO-SEARCH locates token
JR NC,L0592 ; forward to PO-LOOP if first character is
; not alphanumeric. e.g. '**'
; else consider a leading space.
BIT 0,(IY+$01) ; test FLAGS - leading space allowed ?
JR NZ,L0592 ; forward to PO-LOOP if not.
; else print a leading space.
XOR A ; prepare a space
RST 10H ; print it
RET NC ; return if out of screen.
; now enter a loop to print each character and then consider a trailing space.
;; PO-LOOP
L0592: LD A,(BC) ; fetch character from token table.
AND $3F ; mask to give range ' ' to 'Z'
CALL L0559 ; routine OUT-SP-CH
RET NC ; return if out of screen.
LD A,(BC) ; reload the character
INC BC ; point to next.
ADD A,A ; test for the inverted bit.
JR NC,L0592 ; loop back if not inverted to PO-LOOP
;
CP $38 ; compare with what was '0' before doubling.
RET C ; return if less. i.e. not a command. >>
XOR A ; else prepare a space
SET 0,(IY+$01) ; update FLAGS - use no leading space
JR L0560 ; back to PRINT-A-2 for trailing space. >>
; -----------------------------
; THE 'TABLE SEARCH' SUBROUTINE
; -----------------------------
;; PO-SEARCH
L05A8: PUSH HL ; * preserve character pointer
LD HL,$00BA ; point to start of the table
SUB (HL) ; test against the threshold character 212
INC HL ; address next in table. ('?' + $80 )
JR C,L05B9 ; forward to PO-FOUND if less than 212
; to print a question mark.
INC A ; make range start at 1 for chr 212.
; note - should the required token be 212
; the printable quote character then the
; pointer currently addresses '"' + $80.
LD B,A ; save reduced token in B as a counter.
;; PO-STEP
L05B2: BIT 7,(HL) ; test for inverted bit
INC HL ; increase address
JR Z,L05B2 ; back to PO-STEP for inverted bit
DJNZ L05B2 ; decrement counter and loop back to PO-STEP
; until at required token.
;; PO-FOUND
L05B9: LD B,H ; transfer the address
LD C,L ; to BC.
POP HL ; * restore string address
LD A,(BC) ; fetch first character from token.
AND $3F ; mask off range 0-63d, SPACE to Z
ADD A,$E4 ; add value 228
RET ; return with carry set if alphanumeric and a
; leading space is required.
; -------------------------------------
; THE 'CLEAR TO END OF DISPLAY' ROUTINE
; -------------------------------------
;; CL-EOD
L05C2: EXX ; switch in the set with screen values.
XOR A ; clear accumulator.
CP B ; compare with line counter - 0 to 23.
JR Z,L05D0 ; forward if clear to SET-EOD.
CP C ; compare to column count - 0 to 32.
LD A,$76 ; prepare a NEWLINE.
JR Z,L05CE ; forward, if zero, to CL-EOL.
;; INS-CR
L05CC: LD (DE),A ; insert a newline/carriage return.
INC DE ; address next position.
;; CL-EOL
L05CE: DJNZ L05CC ; reduce line counter and loop back to INS-CR.
;; SET-EOD
L05D0: LD ($4010),DE ; update DF_END - display file end.
RET ; return.
; --------------------------
; THE 'MAKE-ROOM' SUBROUTINE
; --------------------------
;; MAKE-ROOM
L05D5: CALL L05DF ; routine POINTERS also sets BC
LD HL,($4010) ; fetch new display file end DF_END
EX DE,HL ; switch source/destination.
LDDR ; now make the room.
RET ; return.
; with HL pointing at first new location.
; -------------------------
; THE 'POINTERS' SUBROUTINE
; -------------------------
;; POINTERS
L05DF: PUSH AF ;
PUSH HL ;
LD HL,$4008 ; VARS
LD A,$05 ;
;; PTR-NEXT
L05E6: LD E,(HL) ;
INC HL ;
LD D,(HL) ;
EX (SP),HL ;
AND A ;
SBC HL,DE ;
ADD HL,DE ;
EX (SP),HL ;
JR NC,L05FA ; forward to PTR-DONE
PUSH DE ;
EX DE,HL ;
ADD HL,BC ;
EX DE,HL ;
LD (HL),D ;
DEC HL ;
LD (HL),E ;
INC HL ;
POP DE ;
;; PTR-DONE
L05FA: INC HL ;
DEC A ;
JR NZ,L05E6 ; back to PTR-NEXT for all five
; dynamic variables.
; now find the size of the block to be moved.
EX DE,HL ;
POP DE ;
POP AF ;
AND A ;
SBC HL,DE ;
LD B,H ;
LD C,L ;
INC BC ;
ADD HL,DE ;
EX DE,HL ;
RET ; return ->
; --------------------------
; THE 'LINE-ADDR' SUBROUTINE
; --------------------------
;; LINE-ADDR
L060A: PUSH HL ; save the given line number.
LD HL,$4028 ; start of PROG
LD D,H ; transfer the address
LD E,L ; to the DE register pair.
;; LINE-AD-1
L0610: POP BC ; the given line number.
EX DE,HL ;
CALL L061C ; routine CP-LINES
RET NC ; return if carry set >>
PUSH BC ; otherwise save given line number
CALL L0624 ; routine NEXT-ONE
JR L0610 ; back to LINE-AD-1 to consider the next
; line of the program.
; -------------------------------------
; THE 'COMPARE LINE NUMBERS' SUBROUTINE
; -------------------------------------
;; CP-LINES
L061C: LD A,(HL) ; fetch the high byte of the addressed line
CP B ; number and compare it.
RET NZ ; return if they do not match.
INC HL ; next compare the low bytes.
LD A,(HL) ;
DEC HL ;
CP C ;
RET ; return with carry flag set if the addressed
; line number has yet to reach the
; given line number.
;------------------------------------------------------------------------
; Storage of variables. For full details - see Page 107
; ZX80 BASIC Programming by Hugo Davenport 1980.
; It is bits 7-5 of the first character of a variable that allow
; the five types to be distinguished. Bits 4-0 are the reduced letter.
; So any variable name is higher that $3F and can be distinguished
; also from the variables area end-marker $80.
;
; 76543210 meaning brief outline of format after letter.
; -------- ------------------------ -----------------------
; 011 simple integer variable. 2 bytes. (after letter)
; 010 long-named integer variable 2 bytes. (after inverted name)
; 100 string letter + contents + $01.
; 101 array of integers letter + max subs byte + subs * 2.
; 111 for-next loop variable. 7 bytes - letter, value, limit, line.
; 10000000 the variables end-marker.
;
; Note. any of the above six will serve as a program end-marker.
;
; -----------------------------------------------------------------------
; -------------------------
; THE 'NEXT-ONE' SUBROUTINE
; -------------------------
;; NEXT-ONE
L0624: PUSH HL ; save address of current line or variable.
LD A,(HL) ; fetch the first byte.
ADD A,A ; test bits 7 and 6
JP M,L0635 ; jump forward if simple, long-named or for-next
; control variable to NO-SLNFM
JR C,L0643 ; forward if string or arrays to NO-STR-AR
; that leaves program line numbers.
INC HL ; step past high byte
LD A,$76 ; the search is for newline
;; NO-SEARCH
L062F: INC HL ; skip to next address past low byte.
LD B,A ; save search byte in B to create
; a large value in BC so that search is
; not curtailed.
CPIR ; and locate the known character.
JR L0652 ; forward to ??? with HL addressing
; the following character.
; ---
; the branch was here with simple, long-named and for-next variables
;; NO-SLNFN
L0635: LD BC,$0002 ; presume a for-next variable (1+2 cells)
JR C,L063B ; skip forward if for-next variable.
LD C,B ; set C to zero - just one cell for simple
; and long-named.
;; NO-FNXT
L063B: RLA ; original bit 5 is now bit 7.
;; NO-LNLP
L063C: RLA ; test original bit 5 of letter.
INC HL ; advance address.
LD A,(HL) ; pick up next byte - possibly a letter
JR NC,L063C ; back if originally long-named or if
; on subsequent loops character is not inverted
; whatever the route we are now pointing at the first cell with the number
; of cells less one in register C.
JR L064F ; forward to NO-CELLS to calculate space to the
; end of variable.
; ---
; the branch was here with either single strings or numeric array variables
;; NO-STR_AR
L0643: AND $40 ; test shifted bit 6 - will be set for arrays
LD A,$01 ; set search for null terminator
JR Z,L062F ; back if not an array to NO-SEARCH to
; search for the end of string.
; the object is a NUMERIC ARRAY
INC HL ; point to maximum subscription
LD A,(HL) ; and fetch
INC HL ; point to first cell.
LD B,$00 ; prepare to index
LD C,A ; max subscription to C
; and continue to find following byte.
;; NXT-O-6
L064F: INC BC ; bump the range
ADD HL,BC ; add to start
ADD HL,BC ; add again as each cell is two bytes.
;; NXT-O-7
L0652: POP DE ; restore previous address to DE and
; continue into the difference routine...
; ---------------------------
; THE 'DIFFERENCE' SUBROUTINE
; ---------------------------
;; DIFFER
L0653: AND A ; prepare to subtract.
SBC HL,DE ; calculate the length of the line/var
LD B,H ; transfer the length
LD C,L ; to the BC register pair.
ADD HL,DE ; reform the address of next one in HL.
EX DE,HL ; swap pointers
RET ; return.
; ------------------------------
; THE 'CLEAR' COMMAND SUBROUTINE
; ------------------------------
; The CLEAR command removes all BASIC variables.
;; CLEAR
L065B: LD HL,($400A) ; set HL to E_LINE.
DEC HL ; decrement to point to the $80 end-marker.
LD DE,($4008) ; set start from VARS system variable.
; ----------------------------
; THE 'RECLAIMING' SUBROUTINES
; ----------------------------
;; RECLAIM-1
L0663: CALL L0653 ; routine DIFFER
;; RECLAIM-2
L0666: PUSH BC ;
LD A,B ;
CPL ;
LD B,A ;
LD A,C ;
CPL ;
LD C,A ;
INC BC ;
CALL L05DF ; routine POINTERS
EX DE,HL ;
POP HL ;
ADD HL,DE ;
PUSH DE ;
LDIR ;
POP HL ;
RET ; return.
; ----------------------------------------
; THE 'INTEGER TO ALTERNATE HL' SUBROUTINE
; ----------------------------------------
;; INT-TO-HL
L0679: LD A,(HL) ; fetch first digit
EXX ; switch
LD HL,$0000 ; initialize result register to zero.
LD B,H ; make B zero also.
;; DEC-LP
L067F: SUB $1C ; subtract chr '0'
JR C,L069A ; forward to STOR-RSLT if less. >>
CP $0A ; compare with 'ten'
JR NC,L069A ; forward to STOR-RSLT if higher than '9'. >>
LD C,A ; save unit in C.
; now test that the result is not about to enter the 32768 - 65535 region.
LD A,$0D ; value 13 to A
CP H ; compare to result_hi
JR NC,L068E ; forward if less to NO-OVERFLW
LD H,A ; else maintain the overflow condition.
;; NO-OVRFLW
L068E: LD D,H ; copy HL.
LD E,L ; to DE.
ADD HL,HL ; double result
ADD HL,HL ; and again.
ADD HL,DE ; now * 5
ADD HL,HL ; now *10
ADD HL,BC ; add in new digit.
EXX ; switch
RST 18H ; NXT-CH-SP
EXX ; switch
JR L067F ; loop back to DEC-LP for more digits.
; -------------------------------------
; THE 'STORE INTEGER RESULT' SUBROUTINE
; -------------------------------------
;; STOR-RSLT
L069A: LD A,H ; transfer high byte to A.
LD ($4022),HL ; set value of expression RESULT
EXX ; switch
RLA ; sets carry if higher than 32767
RET ; return.
; ------------------------------------------------
; THE 'REPORT AND LINE NUMBER PRINTING' SUBROUTINE
; ------------------------------------------------
; Actually the first entry point prints any number in the
; range -32768 to 32767.
; --> This entry point prints a number in BC.
;; OUT-NUM-1
L06A1: PUSH DE ; preserve registers
PUSH HL ; throughout
LD H,B ; transfer number
LD L,C ; to be printed to HL.
BIT 7,B ; test the sign bit
JR Z,L06B5 ; forward if positive to OUT-NUM-P
LD A,$12 ; prepare character '-'
CALL L0559 ; routine OUT-SP-CH
JR NC,L06DD ; forward if out of screen to OUT-NUM-4
LD HL,$0001 ; else make the negative number
SBC HL,BC ; positive.
; at this stage the number is positive
;; OUT-NUM-P
L06B5: LD E,$FF ; signal no leading space.
LD BC,$D8F0 ; prepare the value -10000
CALL L054C ; routine OUT-SP-NO will print the first digit
; of a 5-digit number but nothing if smaller.
JR L06C8 ; forward to OUT-NUM-3
; to consider other four digits in turn.
; (with carry set from a successful print)
; ---
; --> This entry point prints a BASIC line number addressed by HL.
;; OUT-NUM-2
L06BF: PUSH DE ; save DE throughout
LD D,(HL) ; fetch high byte of number to D
INC HL
LD E,(HL) ; fetch low byte of number to E
PUSH HL ; save HL now till the end.
EX DE,HL ; number to HL.
LD E,$00 ; prepare a leading space
SCF ; set carry flag for subtractions.
; both paths converge here.
;; OUT-NUM-3
L06C8: LD BC,$FC18 ; the value -1000
CALL C,L054C ; routine OUT-SP-NO
LD BC,$FF9C ; the value -100
CALL C,L054C ; routine OUT-SP-NO
LD C,$F6 ; the value -10
CALL C,L054C ; routine OUT-SP-NO
LD A,L ; the remainder.
CALL C,L0556 ; routine OUT-CODE
;; OUT-NUM-4
L06DD: POP HL ; restore original
POP DE ; registers.
RET ; return.
; --------------------------
; THE 'UNSTACK-Z' SUBROUTINE
; --------------------------
;; UNSTACK-Z
L06E0: BIT 7,(IY+$01) ; test FLAGS - Checking Syntax ?
POP HL ; drop the return address
RET Z ; return if so.
; else fetch screen coordinates alternate registers for the run-time situation.
EXX
LD DE,($400E) ; fetch display print position DF_EA
LD BC,($4024) ; fetch line and column from SPOSN
EXX ; exchange and continue...
; and jump back to the calling routine...
; ------------------
; THE 'USR' FUNCTION
; ------------------
;; USR
L06F0: JP (HL) ; that appears to be it.
; ---------------------------
; THE 'PRINT ITEM' SUBROUTINE
; ---------------------------
;; PR-ITEM
L06F1: BIT 7,(IY+$00) ; ERR_NR
RET Z ; return if an error has already been
; encountered.
CALL L06E0 ; UNSTACK-Z quits if checking syntax
LD HL,($4022) ; fetch result of SCANNING from RESULT
BIT 6,(IY+$01) ; test FLAGS for result type.
JR Z,L070C ; forward to PR-STRING if type string.
LD B,H ; transfer result
LD C,L ; to BC register pair.
CALL L06A1 ; routine OUT-NUM-1
JR L0723 ; forward to PO-CHECK to check for
; success and store position
; -----------------------------
; THE 'PRINT STRING' SUBROUTINE
; -----------------------------
;; PO-CHAR
L0709: RST 10H ; PRINT-A
;; PO-LOOP
L070A: JR NC,L0725 ; forward to ERROR-05 with carry
; Out of screen.
; --> Entry Point.
;; PR-STRING
L070C: LD A,(HL) ; fetch a character.
INC HL ; increment pointer.
CP $01 ; is it null-terminator.
JR Z,L073A ; forward to PO-STORE if so.
BIT 6,A ; test if simple character or inverse
JR Z,L0709 ; back to PO-CHAR if so
CALL L0584 ; routine PO-TOKEN to print
; ranges $40 - $7f, $0C - $FF
JR L070A ; loop back to PO-LOOP
; --------------------------------
; THE 'CARRIAGE RETURN' SUBROUTINE
; --------------------------------
;; PRINT-CR
L071B: CALL L06E0 ; UNSTACK-Z quits if checking syntax
LD A,$76 ; prepare a NEWLINE character
CALL L0559 ; routine OUT-SP-CH prints it
; returning with carry reset if there
; was no room on the screen.
;; PO-CHECK
L0723: JR C,L073A ; forward to PO-STORE if OK
;; ERROR-05
L0725: RST 08H ; ERROR restart
DEFB $04 ; No more room on screen.
; ------------------------
; THE 'PO-FILL' SUBROUTINE
; ------------------------
;; PO-FILL
L0727: CALL L06E0 ; UNSTACK-Z return if checking syntax.
SET 0,(IY+$01) ; signal no leading space.
;; PO-SPACE
L072E: XOR A ; prepare a space
RST 10H ; PRINT-A outputs the character.
JR NC,L0725 ; back to ERROR-05 if out of screen
EXX ;
LD A,C ; get updated column
EXX ;
DEC A ; decrement it.
AND $07 ; isolate values 0 - 7
JR NZ,L072E ; back to PO-SPACE for more.
; -------------------------------
; THE 'POSITION STORE' SUBROUTINE
; -------------------------------
;; PO-STORE
L073A: EXX ; switch in the set that maintains the print
; positions in the registers.
EX DE,HL ; switch print position to HL for easier coding.
;; PO-STOR-2
L073C: LD ($4024),BC ; set SPOSN to line/column
LD ($400E),HL ; set DF_EA to output address
LD ($4010),HL ; set DF_END output address
RET ; return.
; ----------------------------
; THE 'CLS' COMMAND SUBROUTINE
; ----------------------------
;; CLS
L0747: LD HL,($400C) ; fetch start of display from D_FILE
LD (HL),$76 ; insert a single newline.
INC HL ; advance address.
LD BC,$1721 ; set line to 23 and column to 33.
JR L073C ; back to PO-STOR-2 above
; -------------------
; THE 'SYNTAX TABLES'
; -------------------
;; i. The offset table
L0752: DEFB L07A1 - $ ; $4F offset to $07A1 P-LIST
DEFB L077F - $ ; $2C offset to $077F P-RETURN
DEFB L07B8 - $ ; $64 offset to $07B8 P-CLS
DEFB L0794 - $ ; $3F offset to $0794 P-DIM
DEFB L07AF - $ ; $59 offset to $07AF P-SAVE
DEFB L0782 - $ ; $2B offset to $0782 P-FOR
DEFB L076F - $ ; $17 offset to $076F P-GO-TO
DEFB L07A4 - $ ; $4B offset to $07A4 P-POKE
DEFB L0790 - $ ; $36 offset to $0790 P-INPUT
DEFB L07A9 - $ ; $4E offset to $07A9 P-RANDOMISE
DEFB L076C - $ ; $10 offset to $076C P-LET
DEFB L07BB - $ ; $5E offset to $07BB P-CH-END
DEFB L07BB - $ ; $5D offset to $07BB P-CH-END
DEFB L0789 - $ ; $2A offset to $0789 P-NEXT
DEFB L078D - $ ; $2D offset to $078D P-PRINT
DEFB L07BB - $ ; $5A offset to $07BB P-CH-END
DEFB L07C2 + 1 - $ ; $61 offset to $07C3 P-NEW
DEFB L079E - $ ; $3B offset to $079E P-RUN
DEFB L077C - $ ; $18 offset to $077C P-STOP
DEFB L07B2 - $ ; $4D offset to $07B2 P-CONTINUE
DEFB L0773 - $ ; $0D offset to $0773 P-IF
DEFB L0778 - $ ; $11 offset to $0778 P-GOSUB
DEFB L07AC - $ ; $44 offset to $07AC P-LOAD
DEFB L07B5 - $ ; $4C offset to $07B5 P-CLEAR
DEFB L079B - $ ; $31 offset to $079B P-REM
DEFB L07BB - $ ; $50 offset to $07BB P-CH-END
;; ii. The parameter table.
;; P-LET
L076C: DEFB $01 ; Class-01 - a variable is required.
DEFB $E3 ; separator '='
DEFB $02 ; Class-02 - an expression, of type integer or
; string must follow.
;; P-GO-TO
L076F: DEFB $06 ; Class-06 - a numeric expression must follow.
DEFB $00 ; Class-00 - no further operands.
DEFW L0934 ; address: $0934
;; P-IF
L0773: DEFB $06 ; Class-06 - a numeric expression must follow.
DEFB $D5 ; separator 'THEN'
DEFB $05 ; Class-05 - variable syntax checked entirely
; by routine.
DEFW L08B9 ; address: $08B9
;; P-GOSUB
L0778: DEFB $06 ; Class-06 - a numeric expression must follow.
DEFB $00 ; Class-00 - no further operands.
DEFW L0943 ; address: $0943
;; P-STOP
L077C: DEFB $00 ; Class-00 - no further operands.
DEFW L092E ; address: $092E
;; P-RETURN
L077F: DEFB $00 ; Class-00 - no further operands.
DEFW L0965 ; address: $0965
;; P-FOR
L0782: DEFB $04 ; Class-04 - a single-character variable must
; follow.
DEFB $E3 ; separator '='
DEFB $06 ; Class-06 - a numeric expression must follow.
DEFB $D6 ; separator 'TO'
DEFB $05 ; Class-05 - variable syntax checked entirely
; by routine.
DEFW L08C4 ; address: $08C4
;; P-NEXT
L0789: DEFB $04 ; Class-04 - a single-character variable must
; follow.
DEFB $00 ; Class-00 - no further operands.
DEFW L08F9 ; address: $08F9
;; P-PRINT
L078D: DEFB $05 ; Class-05 - variable syntax checked entirely
; by routine.
DEFW L0972 ; address: $0972
;; P-INPUT
L0790: DEFB $01 ; Class-01 - a variable is required.
DEFB $00 ; Class-00 - no further operands.
DEFW L099A ; address: $099A
;; P-DIM
L0794: DEFB $04 ; Class-04 - a single-character variable must
; follow.
DEFB $DA ; separator '('
DEFB $06 ; Class-06 - a numeric expression must follow.
DEFB $D9 ; separator ')'
DEFB $00 ; Class-00 - no further operands.
DEFW L0CD3 ; address: $0CD3
;; P-REM
L079B: DEFB $05 ; Class-05 - variable syntax checked entirely
; by routine.
DEFW L084A ; address: $084A
;; P-RUN
L079E: DEFB $03 ; Class-03 - a numeric expression may follow
; otherwise zero will be used.
DEFW L093D ; address: $093D
;; P-LIST
L07A1: DEFB $03 ; Class-03 - a numeric expression may follow
; else default to zero.
DEFW L0256 ; Address: $0256
;; P-POKE
L07A4: DEFB $06 ; Class-06 - a numeric expression must follow.
DEFB $D8 ; separator ','
DEFB $05 ; Class-05 - variable syntax checked entirely
; by routine.
DEFW L09D1 ; address: $09D1
;; P-RANDOMISE
L07A9: DEFB $03 ; Class-03 - a numeric expression may follow
; otherwise zero will be used.
DEFW L0923 ; address: $0923
;; P-LOAD
L07AC: DEFB $00 ; Class-00 - no further operands.
DEFW L0206 ; address: $0206
;; P-SAVE
L07AF: DEFB $00 ; Class-00 - no further operands.
DEFW L01B6 ; address: $01B6
;; P-CONTINUE
L07B2: DEFB $00 ; Class-00 - no further operands.
DEFW L0930 ; address: $0930
;; P-CLEAR
L07B5: DEFB $00 ; Class-00 - no further operands.
DEFW L065B ; address: $065B
;; P-CLS
L07B8: DEFB $00 ; Class-00 - no further operands.
DEFW L0747 ; Address: $0747
;; P-CH-END
L07BB: DEFB $05 ; Class-05 - variable syntax checked entirely
; by routine.
DEFW L0844 ; address: $0844
; Note. one would expect the entry for the P-NEW parameters to be here.
; It should consist of a class 0, followed by the address word zero as,
; without any protected RAM, the NEW command is no more sophisticated than
; a reset.
; However, there just isn't room. All 4096 bytes of the ROM have been
; put to good use so the required entry, three zero bytes, is embedded
; in the next routine, adding a harmless NOP to make up the three zero bytes.
; Aye, and you try telling young people of today that. And they won't
; believe you.
; ------------------------------
;; MAIN-G
L07BE: DEC HL
LD ($4026),HL ; CH_ADD
;; P-NEW-1
L07C2: LD HL,$0000 ; prepare to clear error pointer.
NOP ; Note. See comment above.
LD ($4015),HL ; clear X_PTR
LD HL,$4019 ; address FLAGX
BIT 5,(HL) ; is INPUT mode set ?
JR Z,L07D7 ; forward if not to E-LINE-NO
; else runtime input.
RES 7,(HL) ; signal L mode.
LD B,(HL) ; FLAGX to B for class routine.
RST 18H ; NXT-CH-SP advances.
JP L0889 ; jump forward to VAL-FETCH.
; -----------------------
; THE 'E-LINE-NO' SECTION
; -----------------------
;; E-LINE-NO
L07D7: SET 7,(HL) ; update FLAGX - signal K mode
RST 20H ; NEXT-CHAR
CALL L0679 ; routine INT-TO-HL puts the BASIC Line Number
; into HL'
JR C,L07E5 ; forward if a negative to insert error.
; else test against upper limit.
EXX ;
LD DE,$D8F0 ; value -9999
ADD HL,DE ;
EXX ;
;; E-L-ERR
L07E5: CALL C,L08AE ; routine INS-ERR if greater than 9999
; -----------------------
; THE 'LINE-SCAN' SECTION
; -----------------------
;; LINE-SCAN
L07E8: CALL L001A ; get the COMMAND CHARACTER.
RES 7,(IY+$19) ; update FLAGX signal not K mode anymore.
LD BC,$0000 ; this also sets B to zero for later.
LD ($4022),BC ; default RESULT to ZERO
; for, say, RUN without an operand.
CP $76 ; compare to just newline
RET Z ; return if so.
; for example with a space for formatting.
LD C,A ; transfer the character to C
RST 20H ; NEXT_CHAR advances pointer
LD A,C ; fetch back character to A.
SUB $E6 ; subtract lowest command 'LIST'
JR C,L07E5 ; back if not a command to E-L-ERR
; the loop will eventually find the newline
; and the original error point will not be
; altered.
LD C,A ; place reduced character in C.
LD HL,L0752 ; set HL to offset table
ADD HL,BC ; add the one-byte offset
LD C,(HL) ; fetch the offset from table
ADD HL,BC ; add to form address of parameters.
JR L080C ; forward to GET-PARAM
; ------------------------
; THE 'MAIN SCANNING LOOP'
; ------------------------
; entered at GET-PARAM after first instruction.
;; SCAN-LOOP
L0809: LD HL,($401A) ; T_ADDR
; --> Entry Point.
;; GET-PARAM
L080C: LD A,(HL) ; get parameter from syntax table.
INC HL ; point to next one.
LD ($401A),HL ; initialize or update T_ADDR
LD BC,$0809 ; pre-load the machine stack with the
PUSH BC ; return address SCAN-LOOP above.
LD C,A ; copy parameter entry to C for later.
RLA ; test bit 7
JR C,L0826 ; forward to SEPARATOR if inverted.
LD HL,L0836 ; base address of command class table.
LD B,$00 ; prepare to index.
ADD HL,BC ; add the command class 0 - 6
LD C,(HL) ; fetch the addressed byte to C
ADD HL,BC ; compute starting address of routine.
PUSH HL ; push the address on the machine stack.
CALL L001A ; routine GET-CHAR advances character position
; and resets the zero flag - see later.
RET ; >> an indirect jump to the COMMAND CLASS
; routine.
; Note. HL addresses the next non-space
; character e.g. the variable in LET I = 1
; the non-space character is in A
; ----------------------
; THE 'SEPARATOR' BRANCH
; ----------------------
; branch to here if the parameter has bit seven set.
;; SEPARATOR
L0826: CALL L001A ; get character in A
CP $D5 ; compare to the token 'THEN'
JR NZ,L0831 ; forward if another character to SEP-1.
SET 7,(IY+$19) ; else update FLAGX back to K mode
;; SEP-1
L0831: CP C ; compare with expected token/character
JR NZ,L08AE ; forward if no match to set X-PTR
; using INS-ERR
RST 20H ; else step past a correct character.
RET ; return >>
; (to SCAN-LOOP)
; -------------------------
; THE 'COMMAND CLASS' TABLE
; -------------------------
;; TAB-CLASS
L0836: DEFB L0855 - $ ; $1F offset to class-0 $0855
DEFB L086A - $ ; $33 offset to class-1 $086A
DEFB L0885 - $ ; $4D offset to class-2 $0885
DEFB L0850 - $ ; $17 offset to class-3 $0850
DEFB L089E - $ ; $64 offset to class-4 $089E
DEFB L0856 - $ ; $1B offset to class-5 $0856
DEFB L08A8 - $ ; $6C offset to class-6 $08A8
; --------------------------
; THE 'CHECK END' SUBROUTINE
; --------------------------
;; CHECK-END
L083D: BIT 7,(IY+$01) ; check FLAGS - checking syntax ?
RET NZ ; return if running program.
POP BC ; else drop the return address.
;; CH-END-2
L0843: LD A,(HL) ; fetch character from CH_ADD address
;; CH-END-3
L0844: CP $76 ; compare to carriage return.
CALL NZ,L08AE ; routine INS-ERR if not disturbing the
; accumulator.
;; SEE-BELOW
L0849: LD A,(HL) ; reload character again.
; and continue...
; -------------------------
; THE 'REM' COMMAND ROUTINE
; -------------------------
; The REM command compares each character until a newline is encountered.
; However this is a class 5 routine so the initial accumulator value will
; be zero (from the BC test) and not the character following REM.
; A line consisting of a single REM will have the newline skipped and if no
; $76 is encountered in the binary line number then the following line will
; be skipped also as in
; 10 REM
; 20 PRINT "THIS IS NOT HERE"
; The command address should be that of the previous instruction L0849 as the
; accumulator has been disturbed.
;; REM
L084A: CP $76 ; compare with newline.
RET Z ; return with newline.
RST 20H ; NEXT-CHAR
JR L084A ; loop back to REM until newline found.
; -----------------------------------
; THE 'COMMAND CLASSES - 00, 03 & 05'
; -----------------------------------
; these three commands always terminate a sequence of parameters and
; are followed by the address of a routine.
;; CLASS-03
L0850: CP $76 ; check for carriage return
CALL NZ,L08A8 ; else look for optional number using CLASS-06
; e.g. RUN & RUN 100
; return and continue through other two classes.
;; CLASS-00
L0855: CP A ; set the zero flag to invoke CHECK-END later.
; this class has no operands e.g. CONTINUE.
;; CLASS-05
L0856: POP BC ; drop the looping address - last in sequence.
CALL Z,L083D ; routine CHECK-END if zero flag set.
; (classes 03 and 00)
EX DE,HL ; save HL in DE (original CH_ADD)
LD HL,($401A) ; fetch table address from T_ADDR
LD C,(HL) ; low byte to C
INC HL ;
LD B,(HL) ; high byte to B
EX DE,HL ; bring back the original character address
;; JUMP-BC
L0862: PUSH BC ; push routine address on machine stack
LD BC,($4022) ; load value of last expression from RESULT
LD A,B ; test the value
OR C ; for zero.
RET ; jump to the command routine.
; with HL pointing at original CH_ADD
; DE pointing to T_ADDR
; BC holding parameter
; ---------------------------------------
; THE 'COMMAND CLASSES - 01, 02, 04 & 06'
; ---------------------------------------
; the first routine is for LET or INPUT.
;; CLASS-01
L086A: CALL L0D14 ; routine ALPHA tests the character.
JR NC,L08AE ; forward to INS-ERR if character not A-Z.
BIT 7,(IY+$01) ; test FLAGS - the syntax bit.
JP Z,L0AAD ; jump forward to LOOK-VARS if checking syntax.
; continue in runtime
LD ($4020),HL ; save address of destination variable
; in BASIC line in DEST system variable.
RES 7,(IY+$01) ; signal to FLAGS that syntax is being checked.
CALL L0AAD ; routine LOOK-VARS.
SET 7,(IY+$01) ; set FLAGS back to 'running program' status.
RET ; return (to SCAN-LOOP).
; ------------------------------
; used only for LET - an expression of the correct type must be present.
;; CLASS-02
L0885: POP BC ; drop the looping address as CLASS-02 is the
; last in a sequence of parameters. It is
; relevant only to the LET command.
LD B,(IY+$01) ; load B with value of FLAGS.
; (runtime input joins here with FLAGX in B instead of FLAGS)
; ---------------------------
; THE 'FETCH A VALUE' SECTION
; ---------------------------
;; VAL-FETCH
L0889: PUSH BC ; preserve value of FLAGS (or FLAGX if input)
RST 28H ; SCAN-CALC evaluates the expression
; to be assigned setting the result type flag.
POP DE ; restore the pre-evaluation copy of the
; flag register to D.
LD BC,L0C3D ; the address of the LET routine is pushed on
; the machine stack.
LD A,($4001) ; fetch the post-evaluation FLAGS to A
BIT 7,A ; test the syntax bit.
JR NZ,L0862 ; back in runtime to JUMP-BC and then LET
; if checking syntax.
XOR D ; exclusive or the two flags
AND $40 ; AND 01000000 to isolate the type bit.
CALL NZ,L08AE ; routine INS-ERR inserts the error position
; when they are not the same type.
JR L0843 ; back to CH-END-2 to consider lesser errors
; and advance to end of line.
; ------------------------------
; FOR, NEXT, DIM - HL points to variable in BASIC line, A holds the character
;; CLASS-04
L089E: LD ($4020),HL ; set system variable DEST from HL.
CALL L0D14 ; routine ALPHA checks the character.
JR NC,L08AE ; forward to INS-ERR if not A-Z.
RST 18H ; NXT-CH-SP advances character address.
RET ; return to SCAN-LOOP >>
; ------------------------------
; a mandatory INTEGER expression must follow. e.g. GO TO 100
;; CLASS-06
L08A8: RST 28H ; SCAN-CALC evaluates expression.
BIT 6,(IY+$01) ; test FLAGS - numeric result ?
RET NZ ; return if numeric.
; -----------------------------
; THE 'INSERT ERROR' SUBROUTINE
; -----------------------------
;; INS-ERR
L08AE: LD A,($4015) ; check that error pointer X_PTR
OR (IY+$16) ; contains zero.
RET NZ ; return if there is already an error
LD ($4015),HL ; else place error address at X-PTR
RET ; return.
; ------------------------
; THE 'IF' COMMAND ROUTINE
; ------------------------
;; IF
L08B9: JR NZ,L08C1 ; if expression is TRUE forward to IF-1
BIT 7,(IY+$01) ; test FLAGS - checking syntax ?
JR NZ,L084A ; back to REM to ignore rest of the line
; in runtime.
; - else continue and check the syntax of the rest of the line.
;; IF-1
L08C1: JP L07E8 ; jump back to LINE-SCAN to execute what
; follows the 'THEN'
; -------------------------
; THE 'FOR' COMMAND ROUTINE
; -------------------------
; for example, FOR X = 1 TO 10
; There is no step or direction.
; The body of the loop is always entered at least once - even if the initial
; value exceeds the limit.
; The ZX81 and ZX Spectrum adhered more closely to the ANS X3.60 1978 BASIC
; standard.
;; FOR
L08C4: PUSH BC ; save the start value.
CALL L08A8 ; routine CLASS-06 evaluates LIMIT
; expression.
POP BC ; start value back to BC
CALL L083D ; routine CHECK-END quits if checking
; syntax >>
LD HL,($4022) ; fetch limit from RESULT
PUSH HL ; save limit
CALL L0C3D ; routine LET
POP BC ; restore limit to BC
BIT 7,(IY+$00) ; examine ERR_NR
RET Z ; return if not $FF >>
PUSH BC ; push the limit value.
DEC HL ; point to letter.
BIT 7,(HL) ; test bit 7 - is it a FOR-NEXT variable.
SET 7,(HL) ; set bit 7 as it is going to be.
INC HL ; point to end of value
INC HL
JR NZ,L08EA ; skip forward if it is a proper
; for/next variable to FOR-2
LD BC,$0004 ; else an extra 4 bytes are needed.
INC HL ; point to start of new space.
CALL L05D5 ; routine MAKE-ROOM creates it.
; HL - first, DE- last
;; FOR-2
L08EA: INC HL ; address limit location
POP DE ; retrieve limit value to DE.
LD (HL),E ; insert low byte of limit.
INC HL
LD (HL),D ; and then the high byte
INC HL ; point to the looping line cell.
LD DE,($4002) ; load DE with the current line from PPC
INC DE ; increment as iteration will start from the
; next line at least.
LD (HL),E ; insert low byte of line number.
INC HL
LD (HL),D ; insert high byte of line number.
RET ; return.
; --------------------------
; THE 'NEXT' COMMAND ROUTINE
; --------------------------
;; NEXT
L08F9: LD HL,($4020) ; fetch address of variable in BASIC from DEST.
CALL L0B3B ; routine LV-FIND finds the equivalent in the
; variables area and returns the value in HL.
BIT 7,(IY+$00) ; test ERR_NR
RET Z ; return with error.
; will be 02 - variable not found.
; continue if LV-FIND found the variable - HL contains the value, DE points
; to the high byte of value location.
EX DE,HL ; value to DE, address to HL
DEC HL ; point to low byte
DEC HL ; point to the variable letter.
BIT 7,(HL) ; - should have letter mask 111xxxxx
JR Z,L0921 ; forward to ERROR-01 if not initialized by FOR.
; - NEXT without FOR.
INC DE ; increment the integer value
; no step or direction possible.
INC HL ; address first location
LD (HL),E ; store low byte of value.
INC HL ; next
LD (HL),D ; store high byte of value.
INC HL ;
LD C,(HL) ; pick up limit low
INC HL ;
LD B,(HL) ; and limit high.
PUSH BC ; save limit.
EX (SP),HL ; limit to HL, pointer to stack.
CALL L0DCD ; routine no-less compares HL DE
; setting carry if HL is less.
POP HL ; retrieve the pointer from the stack.
RET C ; return if no more iterations possible >>
INC HL ; else address next location.
LD C,(HL) ; pick up low byte of line number
INC HL ; address next
LD B,(HL) ; pick up high byte of looping line.
JR L0934 ; jump to GOTO to perform another
; iteration
; ---
;; ERROR-01
L0921: RST 08H ; ERROR restart
DEFB $00 ; NEXT without FOR
; -------------------------------
; THE 'RANDOMISE' COMMAND ROUTINE
; -------------------------------
; This command sets the seed to the supplied integer -32767 to 32767.
; In the absence of a parameter the FRAMES counter, related to the time
; the computer has been switched on, is used.
;; RANDOMISE
L0923: JR NZ,L0929 ; forward to RAND-1 if parameter is
; not zero.
LD BC,($401E) ; else use value of system variable FRAMES.
;; RAND-1
L0929: LD ($401C),BC ; insert value in system variable SEED.
RET ; return.
; --------------------------
; THE 'STOP' COMMAND ROUTINE
; --------------------------
;; STOP
;; ERROR-9
L092E: RST 08H ; ERROR restart
DEFB $08 ; - STOP statement executed.
; ------------------------------
; THE 'CONTINUE' COMMAND ROUTINE
; ------------------------------
;; CONTINUE
L0930: LD BC,($4017) ; fetch continuing line number from OLDPPC
; and continue into GOTO routine.
; ---------------------------
; THE 'GO TO' COMMAND ROUTINE
; ---------------------------
;; GOTO
L0934: LD ($4002),BC ; set PPC to supplied line number.
SET 3,(IY+$01) ; update FLAGS - use K cursor.
RET ; return.
; -------------------------
; THE 'RUN' COMMAND ROUTINE
; -------------------------
; The RUN command may have an optional line number that will be passed to
; the GOTO routine before erasing any variables and executing the line
; (or first line after zero).
;; RUN
L093D: CALL L0934 ; routine GOTO sets up any supplied line number.
JP L065B ; exit via CLEAR to erase variables.
; ----------------------------
; THE 'GO SUB' COMMAND ROUTINE
; ----------------------------
;; GOSUB
L0943: LD HL,($4002) ; fetch current line from PPC
INC HL ; increment the line number
EX (SP),HL ; place on machine stack
;
PUSH HL ; push what was on the stack back up there.
CALL L0934 ; routine GOTO sets up a branch to the line
; number.
LD BC,$0006 ; and exit by a six-byte memory check.
; --------------------------
; THE 'TEST ROOM' SUBROUTINE
; --------------------------
; The ZX80 dates from the days when RAM chips cost a fortune and it came with
; only 1K of RAM, 1024 bytes.
; The screen could show 768 characters and to economize it is dynamic and
; initialized to a single newline ($76) by CLS. The TEST-ROOM routine has to
; allow for enough newlines to expand down to the bottom line and a few extra
; for the report codes "0/9999".
; The second entry point is from PRINT-A and the character is similarly
; in H and the line number in L.
;; TEST-ROOM
L094F: LD HL,($4010) ; fetch DF_END last location before
; spare memory.
ADD HL,BC ; add the supplied overhead.
EX DE,HL ; save the result in DE.
LD HL,($4025) ; SPOSN-Y to L gives 24 - number
; of screen lines used so far.
LD H,A ; preserve the accumulator in H
;; TEST-RM-2
L0958: LD A,$13 ; load A with 19
ADD A,L ; add to L to give the number of bytes
; required to fill rest of screen with
; newlines - plus a bit extra.
LD L,A ; put result in L.
LD A,H ; restore the accumulator.
LD H,$00 ; set H to zero.
ADD HL,DE ; add this extra screen allowance
; to the previous result.
SBC HL,SP ; subtract the stack pointer.
RET C ; return if the stack pointer is
; above the estimate. All is well.
;
;; ERROR-4
L0963: RST 08H ; ERROR restart
DEFB $03 ; No room
; ----------------------------
; THE 'RETURN' COMMAND ROUTINE
; ----------------------------
; As with all commands, there is only one value on the machine stack during
; command execution. This is the return address.
; Above the machine stack is the gosub stack that contains a line number
; (only one statement per line).
;; RETURN
L0965: POP HL ; drop the return address clearing the stack.
POP BC ; drop a line number off the gosub stack.
PUSH HL ; restore the machine stack.
LD A,B ; test high byte of line number.
CP $3F ; against the gosub stack end-marker.
JR NZ,L0934 ; back to GOTO if a valid line number.
POP HL ; else collapse the machine stack.
PUSH BC ; push the end-marker.
PUSH HL ; restore the machine stack.
;; ERROR-07
RST 08H ; ERROR restart
DEFB $06 ; RETURN with no corresponding GO SUB.
; ---------------------------
; THE 'PRINT' COMMAND ROUTINE
; ---------------------------
;; PRINT
L0972: LD A,(HL) ; fetch the character
CP $76 ; compare to NEWLINE
JP Z,L071B ; back to PRINT-CR if so.
;; PR-POSN-1
L0978: SUB $D8 ; subtract ','
; (';' gives -1 and carry set)
ADC A,$00 ; convert the two separators to zero.
JR Z,L0991 ; forward to PR-POSN-2 with ';' and ','
RST 28H ; else SCAN-CALC evaluates expression.
CALL L06F1 ; routine PRINT-ITEM prints it.
CALL L001A ; routine GET-CHAR gets following character.
SUB $D8 ; compare with ',' and test for
ADC A,$00 ; terminating separators.
JR Z,L0991 ; forward to PR-POSN-2 with ';' and ','
CALL L083D ; routine CHECK-END errors with anything else.
JP L071B ; jump to PRINT-CR for carriage return.
; ---
;; PR-POSN-2
L0991: CALL NC,L0727 ; routine PO-FILL if comma control.
RST 20H ; NEXT-CHAR
CP $76 ; compare to NEWLINE
RET Z ; return if so leaving print position
; unchanged.
JR L0978 ; else loop back to PR-POSN-1 to consider
; more sequences of positional
; controls and print items.
; ---------------------------
; THE 'INPUT' COMMAND ROUTINE
; ---------------------------
; INPUT must be used from a running program. It is not available as a
; direct command.
;; INPUT
L099A: BIT 7,(IY+$03) ; test PPC_hi - will be -2 if a direct command
JR NZ,L09CF ; forward if so, to ERROR-08
POP HL ; discard return address - L0447
LD HL,$4019 ; point to FLAGX
SET 5,(HL) ; signal input
RES 6,(HL) ; reset so as not to affect combine
LD A,($4001) ; fetch FLAGS to A
AND $40 ; isolate bit 6 - the result type
LD BC,$0002 ; allow two locations for numeric.
JR NZ,L09B4 ; skip forward to IN-PR-1 if numeric.
LD C,$04 ; allow two extra spaces for quotes.
;; IN-PR-1
L09B4: OR (HL) ; combine FLAG bit with FLAGX.
LD (HL),A ; and place result in FLAGS.
RST 30H ; BC-SPACES creates 2/4 locations.
RET NC ; return with problems.
LD (HL),$76 ; insert a newline at end.
LD A,C ; now test C - 2 (num) 4 (str).
RRCA ; 1 2
RRCA ; carry 1
JR C,L09C2 ; skip forward with numeric to IN-PR-3
LD (DE),A ; insert initial quote (chr$ 1) at DE
DEC HL ; decrease HL pointer
LD (HL),A ; insert closing quote.
;; IN-PR-3
L09C2: DEC HL ; decrease pointer
LD (HL),$B0 ; insert cursor inverse 'K'
LD A,($4025) ; SPOSN-Y
INC A ; allow a blank line
LD ($4012),A ; set DF-SZ
JP L02F7 ; jump back to ED-COPY
; ---
;; ERROR-08
L09CF: RST 08H ; ERROR restart
DEFB $07 ; INPUT can only be used in a program.
; --------------------------
; THE 'POKE' COMMAND ROUTINE
; --------------------------
;; POKE
L09D1: PUSH BC ; save result of first expression.
RST 28H ; use SCAN-CALC to evaluate expression
; after the comma.
POP DE ; restore destination address.
CALL L083D ; routine CHECK-END
LD A,($4022) ; RESULT
BIT 7,(IY+$00) ; ERR_NR
RET Z ; return if error
LD (DE),A ; load memory location with A
RET ; return
; ----------------------
; THE 'SCANNING' ROUTINE
; ----------------------
; The scanning routine is a continuation of RST 28.
; The B register has been set to zero as a starting priority.
; The HL register contains the character address CH_ADD.
; The addressed character is in A.
;; SCANNING
L09E1: LD C,B ; make BC zero - the starting priority
; marker.
PUSH BC ; save on machine stack.
;; S-LOOP-1
L09E3: CALL L0D18 ; routine ALPHANUM
JR C,L0A24 ; forward if a variable or digit. to S-VAR-NUM
; now consider negate (-) and perform '$0000 - value' if so.
LD BC,$0900 ; prepare priority $09, operation 'subtract'
LD D,C ; set DE to $0000 for value to be stacked.
LD E,C ;
SUB $DC ; subtract the character '-'
JR Z,L0A17 ; forward with unary minus to S-PUSH-PO
; now consider 'not' and perform $FFFF - value if so.
DEC DE ; set DE to $FFFF for value to be stacked.
LD B,$04 ; prepare priority 4, operation still 'subtract'
INC A ; test for 'NOT' ?
JR Z,L0A17 ; forward with NOT to S-PUSH-PO
; now consider an opening bracket.
INC A ; test the character.
JR Z,L0A1C ; forward with '(' to S-BRACKET
; to evaluate the sub-expression recursively
; using SCANNING.
CP $27 ; commencing quote ?
JR NZ,L0A0E ; forward to S-ABORT if not, as all valid
; possibilities have been exhausted.
; continue to evaluate a string.
RES 6,(IY+$01) ; signal string result to FLAGS.
INC HL ; step past the opening quote.
LD ($4022),HL ; store the string pointer in
; system variable RESULT.
;; S-Q-CHAR
L0A06: RST 18H ; NXT-CH-SP
DEC A ; test for the string terminator.
JR Z,L0A21 ; forward to S-CONT if found. >>
CP $75 ; [ EDIT ] SHIFT-ENTER
JR NZ,L0A06 ; loop back to S-Q-CHAR till terminator found.
; ---
; the branch was here when something unexpected appeared in the expression
; or, if from above, in the string.
;; S-ABORT
L0A0E: CALL L08AE ; routine INS-ERR marks the spot.
EXX ;
LD BC,$0000 ; this forces the zero priority marker down
; from the stack.
; Note. just setting B to zero should do.
JR L0A4C ; forward to S-LOOP to balance and exit
; ---
; the ZX80 juggles with expression components using just the machine stack
; pushing first the value and then the priority/operator beneath.
; As with all ZX computers, provided there is enough memory, an expression of
; unlimited complexity can be evaluated.
;; S-PUSH-PO
L0A17: PUSH DE ; push the value ($0000 if '-', $FFFF if 'NOT')
PUSH BC ; then push the priority and operator.
;; SCAN-LOOP
L0A19: RST 20H ; NEXT-CHAR advances the character address.
JR L09E3 ; back to S-LOOP-1
; ---
;; S-BRACKET
L0A1C: CALL L0049 ; routine BRACKET evaluates expression
; inside the brackets checking for
; terminator using SCANNING
; recursively.
JR L0A37 ; forward to S-OPERTR
; ---
; the branch was here when the end of a string had been found.
;; S-CONT
L0A21: RST 18H ; NXT-CH-SP
JR L0A37 ; forward to S-OPERTR to consider comparisons
; ---
;; S-VAR-NUM
L0A24: CP $26 ; compare to 'A'
JR C,L0A2D ; forward if numeric to S-DIGIT
; present character is alpha
CALL L0AAD ; routine LOOK-VARS
JR L0A37 ; forward to S-OPERTR
; ---
;; S-DIGIT
L0A2D: CALL L0679 ; routine INT-TO-HL
CALL C,L08AE ; routine INS-ERR with overflow.
SET 6,(IY+$01) ; signal numeric result in FLAGS
;; S-OPERTR
L0A37: CALL L001A ; routine get-char
EXX
LD BC,$0000 ; prepare zero priority in case not an operator
; in which case at end of expression
SUB $DC ; reduce by '-'
JR C,L0A4C ; forward if less than an operator to S-LOOP
CP $0A ; compare to ten.
JR NC,L0A4C ; forward if higher than nine to S-LOOP
; leaves ten operators -, +, *, /, AND, OR, **, =, >, <.
LD C,A ; transfer operation to C, register B is zero.
LD HL,L0AA3 ; address table of priorities.
ADD HL,BC ; index into table.
LD B,(HL) ; pick up the priority.
;; S-LOOP
L0A4C: POP DE ; pop the previous priority/operation
LD A,D ; priority to A
CP B ; compare with current priority B
JR C,L0A88 ; forward to S-TIGHTER if current priority is
; higher
; else this is the correct place in the expression to perform this operation.
AND A ; first test for zero priority marker
EXX ;
RET Z ; return if so, HL is result. >>>>>
EXX ;
BIT 7,(IY+$01) ; FLAGS
JR Z,L0A6F ; forward if checking syntax to S-SYNTEST
; but in runtime the operation is performed.
LD D,$00 ; prepare to index.
LD HL,L0D1F ; address the table of operators and addresses.
ADD HL,DE ; index twice using the operation code.
ADD HL,DE ; as there are two bytes per entry.
LD E,(HL) ; pick up low byte of address.
INC HL ; next location.
LD D,(HL) ; get high byte of address.
LD HL,L0A7F ; the return address S-INS-VAL
EX (SP),HL ; goes to the stack and argument to HL
PUSH DE ; now push the address of the routine.
LD DE,($4022) ; pick up last value from RESULT
RET ; and make an indirect jump to
; the routine. >>>>>>>>
; ------------------------------
;; S-SYNTEST
L0A6F: LD A,E ; get the last operation code
CP $0A ; compare to ten - sets carry if numeric
RRA ; carry to bit 7
RRA ; carry to bit 6
XOR (IY+$01) ; exclusive or with FLAGS
AND $40 ; isolate bit 6 - the result type.
EXX ;
CALL NZ,L08AE ; routine INS-ERR if not of same type.
EXX ;
POP HL ; fetch the last value from machine stack
; >>>>>>>>
; Note. this is also the return address from mathematical and string
; comparisons, see above, in which case HL will contain the result and BC
; the priority/operation.
;; S-INS-VAL
L0A7F: LD ($4022),HL ; place value in system variable RESULT
SET 6,(IY+$01) ; signal numeric result to FLAGS
JR L0A4C ; back to S-LOOP
; ---
;; S-TIGHTER
L0A88: PUSH DE ; push lower priority
LD A,C ; fetch operator
BIT 6,(IY+$01) ; test FLAGS
JR NZ,L0A9A ; forward if numeric to S-NEXT.
ADD A,$03 ; augment nos-eql to strs-eql etc.
LD C,A ; and put back in C
CP $0A ; compare to ten - start of string comparisons
EXX ;
CALL C,L08AE ; routine INS-ERR if lower
; a$ * b$ is invalid but so too
; is a$ + b$ (no string concatenation)
EXX ;
;; S-NEXT
L0A9A: LD HL,($4022) ; fetch RESULT to HL
PUSH HL ; push intermediate result
PUSH BC ; and then priority/operator
EXX ;
JP L0A19 ; jump back to SCAN-LOOP
; -------------------------
; THE 'TABLE OF PRIORITIES'
; -------------------------
; Table of mathematical priorities that dictate, in the absence of brackets,
; the order in which operations are performed.
; unary minus (priority $09) and NOT (priority $04) are handled directly.
;; TAB-PRIO
L0AA3: DEFB $06 ; $00 subtract
DEFB $06 ; $01 addition
DEFB $08 ; $02 multiply
DEFB $07 ; $03 division
DEFB $03 ; $04 and
DEFB $02 ; $05 or
DEFB $0A ; $06 to-power
DEFB $05 ; $07 nos-eql
DEFB $05 ; $08 no-grtr
DEFB $05 ; $09 no-less
; --------------------------
; THE 'LOOK-VARS' SUBROUTINE
; --------------------------
;; LOOK-VARS
L0AAD: PUSH HL ; * push pointer to first letter
LD HL,$4001 ; address FLAGS
RES 5,(HL) ; update FLAGS - signal not a function yet.
; but no use is made of this flag bit.
SET 6,(HL) ; update FLAGS - presume a numeric result.
RST 18H ; NXT-CH-SP
CP $0D ; compare to '$' ?
JP Z,L0B30 ;; JUMP forward with match to STRING
CP $DA ; compare to '(' ?
JP Z,L0B2B ;; JUMP forward with match to ARRAY
; that leaves three types of integer plus functions.
;; V-CHAR
L0AC0: CALL L0D18 ; routine ALPHANUM
JR NC,L0AC8 ; forward when not alphanumeric to FUNC-LOOP.
RST 18H ; fetch NXT-CH-SP.
JR L0AC0 ; loop back to V-CHAR for more.
; ---
;; FUNC-LOOP
L0AC8: CP $DA ; compare to '(' ?
JR Z,L0AD6 ; forward with a match to FUNC-SRCH
CP $0D ; compare to '$' ?
JP NZ,L0B35 ;; JUMP forward if not to V-SYN
; but if this is a string function such as CHR$ then the bracket must follow.
RST 18H ; NXT-CH-SP
CP $DA ; compare to '(' ?
JR NZ,L0B27 ; forward if not to FUNC-ERR.
; This has the correct format for a function and an exact match must now be
; made to one of the entries in the functions table.
;; FUNC-SRCH
L0AD6: LD DE,L0BC0 - 1 ; point to location before TAB-FUNC
;; FUNC-LOOP
L0AD9: POP HL ; pop pointer to first character in command
PUSH HL ; and push again.
;; FUNC-CHAR
L0ADB: LD C,(HL) ; fetch command character to C.
CALL L0055 ; routine CH-ADD-LP advances CH-ADD
; to next non-space position.
INC DE ; increment position in table
LD A,(DE) ; fetch table character to A.
CP C ; compare with one in command.
JR Z,L0ADB ; loop back with match to FUNC-CHAR
; e.g. PEEK
AND $3F ; cancel any inversion.
CP C ; and compare again
JR NZ,L0AEE ; skip if no match to FUNC-NEXT.
LD A,$DA ; load with '('
CP (HL) ; compare to next valid character
JR Z,L0AF9 ; forward with success to FUNC-MTCH.
;; FUNC-NEXT
L0AEE: LD A,(DE) ; fetch next character from table.
AND A ; test for zero end-marker.
JR Z,L0B27 ; forward if at end of table to FUNC-ERR.
INC DE ; else increment pointer.
RLA ; test for inverted bit.
JR NC,L0AEE ; loop back to FUNC-NEXT
; until new token found.
INC DE ; increment pointer.
; to skip address in table.
JR L0AD9 ; loop back to FUNC-LOOP
; which begins by skipping the
; remaining address byte.
; ---
; A function such as PEEK has been found with the necessary opening bracket.
;; FUNC-MTCH
L0AF9: PUSH DE ; save pointer to address within
; table.
CALL L0049 ; routine BRACKET evaluates an
; expression within brackets in command.
; result in HL
POP DE ; retrieve table address pointer.
EX (SP),HL ; result to stack, discarding command
; character pointer.
LD HL,$4001 ; load with address FLAGS
LD A,(DE) ; fetch the last inverted character.
XOR (HL) ; XOR with FLAGS
AND $40 ; isolate bit 6 - result type.
JR NZ,L0B27 ; to FUNC-ERR to insert an error with
; an argument type mismatch.
SET 5,(HL) ; update FLAGS signal a function has been found
; but no use is made of this ?????
SET 6,(HL) ; default the result type to be numeric.
LD A,(DE) ; fetch last character
AND $3F ; lose the indicator bits.
CP $0D ; is character '$' ?
; i.e. CHR$, STR$ or TL$.
JR NZ,L0B15 ; forward with numeric function results
; to FUNC-SYN.
RES 6,(HL) ; else set FLAGS to indicate a string
; result is expected.
;; FUNC-SYN
L0B15: BIT 7,(HL) ; test FLAGS checking syntax?
POP HL ; restore RESULT of expression in brackets.
RET Z ; return if checking syntax. >>
LD HL,L0BBA ; else the routine INS-RSLT
PUSH HL ; is pushed on the machine stack
EX DE,HL ; HL now points to table entry.
INC HL ; point to address low byte.
LD E,(HL) ; pick up the low byte.
INC HL
LD D,(HL) ; pick up the high byte.
PUSH DE ; push routine address on stack.
LD HL,($4022) ; load HL with argument from RESULT
; either integer or string pointer.
RET ; indirect jump to routine and then
; to INS-RSLT .
; ---
;; FUNC-ERR
L0B27: POP HL ; balance stack.
JP L08AE ; jump back to INS-ERR
; ------------------------------
;; ARRAY
L0B2B: CALL L0049 ; routine BRACKET evaluates expression
JR L0B35 ; skip to V-SYN
; ---
;; STRING
L0B30: RES 6,(IY+$01) ; FLAGS signal string result.
RST 18H ; NXT-CH-SP
;; V-SYN
L0B35: POP HL ; * restore pointer to first letter
BIT 7,(IY+$01) ; check FLAGS
RET Z ; return if checking syntax
; but continue in run-time
; also called from NEXT and LET
; HL points to first letter of variable in the command.
;; LV-FIND
L0B3B: LD C,(HL) ; C first character
INC HL
LD A,(HL) ; A second character
PUSH HL ; save pointer to character 2
CP $DA ; is second character '(' ?
JR NZ,L0B5C ; forward if not to LV-ENCODE with strings and
; simple numeric variables.
; an array
PUSH BC ; save BC on stack
LD BC,($4026) ; fetch character address CH_ADD
PUSH BC ; and save that on stack as well.
CALL L0025 ; routine EVAL-EXPR evaluates the
; expression after the current '('
; disturbing CH_ADD
POP HL ; restore original value of CH_ADD
LD ($4026),HL ; and backdate CH_ADD system variable.
POP BC ; restore the letter in BC.
LD HL,$4000 ; address system variable ERR_NR
BIT 7,(HL) ; test if $FF has been disturbed by eval_expr.
JR NZ,L0B6B ; forward if not to V-RUN.
LD (HL),$02 ; else insert the code for subscript error
POP HL ; balance the stack
RET ; return with error set. >>
; ---
; encode the variable type into bits 5-7 of the letter.
;; LV-ENCODE
L0B5C: RES 5,C ; presume type string
CP $0D ; is second character '$' ?
JR Z,L0B6B ; forward if so to V-RUN
SET 6,C ; presume long-named numeric.
CALL L0D18 ; routine ALPHANUM test second character.
JR C,L0B6B ; forward if so to V-RUN
SET 5,C ; else mark as simple numeric or for/next
;; V-RUN
L0B6B: LD HL,($4008) ; point HL to the first variable from VARS.
;; V-EACH
L0B6E: LD A,(HL) ; fetch letter/marker
AND $7F ; reset bit 7 to allow simple numeric variables
; to match against FOR-NEXT variables.
JP Z,L0CD0 ; if character was $80 then forward to ERROR-02
; Variable not found.
CP C ; else compare to first letter in command
JR NZ,L0B93 ; forward if no match to V-NEXT
RLA ; rotate A to left and then
ADD A,A ; double to test bits 5 and 6.
JP M,L0BA4 ; forward to STK-VAR with
; all single letter numeric variables
; including for/next and arrays.
JR NC,L0BB8 ; forward to STR-RSLT with string.
; that leaves long-named variables (mask 010xxxxx)
; that have to be matched in full.
POP DE ; take a copy of pointer.
PUSH DE ; to 2nd character in BASIC area.
PUSH HL ; save 1st letter pointer in vars area.
;; V-MATCHES
L0B81: INC HL ; point to next vars character.
LD A,(DE) ; fetch each BASIC char in turn.
INC DE ; advance BASIC pointer
CP (HL) ; compare to character in variable
JR Z,L0B81 ; back if the same to V-MATCHES
OR $80 ; try a match on inverted character.
CP (HL) ; compare to variable
JR NZ,L0B92 ; forward to V-GET-PTR without full
; match.
LD A,(DE) ; check that the end of name in BASIC
; has been reached.
CALL L0D18 ; routine ALPHANUM checks that no
; more letters follow.
JR NC,L0B9B ; forward to V-FOUND-1 with a full
; match on an inverted long name.
; else continue the search
;; V-GET-PTR
L0B92: POP HL ; fetch the pointer.
;; V-NEXT
L0B93: PUSH BC ; save B and C
CALL L0624 ; routine NEXT-ONE points DE at next
; variable
EX DE,HL ; switch pointers.
POP BC ; retrieve B and C.
JR L0B6E ; back for another search to V-EACH.
; ---
;; V-FOUND-1
L0B9B: POP DE ; drop saved var pointer
;; V-FOUND-2
L0B9C: POP DE ; drop pointer to second character
;; V-FOUND-3
L0B9D: INC HL ; advance to value.
LD E,(HL) ; fetch low byte to E
INC HL ;
LD D,(HL) ; fetch high byte to D.
EX DE,HL ; value to HL
JR L0BBA ; forward to INS-RSLT
; ---
; simple 011xxxxx, array 101xxxxx, for/next 111xxxxx
;; STK-VAR
L0BA4: JR C,L0B9C ; back to V-FOUND-2 above with simple
; and FOR/NEXT variables.
;; SV-ARRAYS
EX (SP),HL ; save pointer to letter on stack discarding
; the second letter pointer
LD HL,($4022) ; fetch argument within brackets from RESULT
RLC H ; test the high byte.
POP DE ; retrieve pointer to letter
JR NZ,L0BBE ; forward to ERROR-03 subscript error
; if subscript > 255
INC DE ; point to dimensions value - 1 byte
LD A,(DE) ; fetch the max subscription
CP L ; compare to low byte of argument.
JR C,L0BBE ; forward if higher than max subscription
; to ERROR-03.
ADD HL,HL ; double the subscript 0 - 510
ADD HL,DE ; add to variable pointer
; now point to location before required cell.
; if the first element is 0 then still pointing
; at the max subscription byte.
JR L0B9D ; back to V-FOUND-3 above.
; ---
; string type mask 100xxxxx
;; STR-RSLT
L0BB8: POP DE ; drop pointer to var.
INC HL ; advance to first character of string.
;; INS-RSLT
L0BBA: LD ($4022),HL ; insert value/pointer into RESULT
RET ; return.
; ---
;; ERROR-03
L0BBE: RST 08H ; ERROR restart
DEFB $02 ; subscript error
; ------------------------------
; THE 'INTEGRAL FUNCTIONS TABLE'
; ------------------------------
; Table of functions to be parsed and addresses.
; Parsed by LOOK-VARS.
; Inversion is with $80 (string argument)
; and with $CO (numeric argument).
; The TL$, "Truncate Left string", of "CABBAGE" is "ABBAGE".
;; TAB-FUNC
L0BC0: DEFB $35,$2A,$2A,$F0 ; PEEK (+$C0)
DEFW L0C24 ; $0C24
DEFB $28,$2D,$37,$CD ; CHR$ (+$C0)
DEFW L0C28 ; $0C28
DEFB $28,$34,$29,$AA ; CODE (+$80)
DEFW L0C24 ; $0C24
DEFB $37,$33,$E9 ; RND (+$C0)
DEFW L0BED ; $OBED
DEFB $39,$31,$8D ; TL$ (+$80)
DEFW L0C38 ; $0C38
DEFB $3A,$38,$F7 ; USR (+$C0)
DEFW L06F0 ; $06F0
DEFB $38,$39,$37,$CD ; STR$ (+$C0)
DEFW L0C10 ; $0C10
DEFB $26,$27,$F8 ; ABS (+$C0)
DEFW L0DF2 ; $0DF2
DEFB $00 ; zero end-marker
; ------------------
; THE 'RND' FUNCTION
; ------------------
; e.g. LET LOTTERYNUMBER = RND (49) produces a random number in the range
; 1 to 49.
; the routine has two stages -
; First the seed is fetched and manipulated in such a way that it cycles through
; every value between 0 and 65535 in a pseudo-random way before repeating the
; sequence. If the seed fetched is zero it is set to 65536-77.
; The multiplicand used is 77 and any overflow is subtracted from the
; register result.
;; RND
L0BED: PUSH HL ; * save the integer parameter e.g. 49.
LD HL,($401C) ; fetch the 'seed' from SEED.
LD DE,$004D ; place 77 in DE
LD A,H ; test the seed
OR L ; for value zero
JR Z,L0C03 ; forward if zero.
CALL L0D55 ; routine MULT16 multiplies seed by 77
; BC contains zero or overflow
AND A ; clear carry flag.
SBC HL,BC ; subtract any overflow from lower 16 bits
JR NC,L0C05 ; forward if no carry to RND-3
INC HL ; increase seed value.
JR L0C05 ; forward to RND-3
; ---
;; RND-2
L0C03: SBC HL,DE ; form number $FFB3 if seed is zero.
;; RND-3
L0C05: LD ($401C),HL ; store new value of SEED
; now multiply the new seed by the argument to give result-1 in BC.
POP DE ; * restore argument
CALL L0D55 ; routine MULT16 multiplies HL by DE
; returning in BC, for the example, 0-48
LD H,B ; transfer BC
LD L,C ; to HL - the result register.
INC HL ; increment - make range start with 1.
RET ; return
; -------------------
; THE 'STR$' FUNCTION
; -------------------
; the function produces a string comprising the characters that would appear
; if the numeric argument were printed.
; So seven characters e.g. "-10000" terminated by the null character ($01)
; is the maximum amount of characters required.
; Note. that for this reason the ZX80, unlike the ZX81 and ZX Spectrum, is able
; to have four tabstops across the 32 character screen.
;; str$
L0C10: EXX
LD BC,$0007 ; 7 characters required at most.
RST 30H ; routine BC-SPACES
JR NC,L0C34 ; forward to NULL-STR if not enough
; memory.
PUSH DE ; * save start of new space
EXX ; switch in other set
LD B,H ; transfer argument to BC
LD C,L ; register.
CALL L06A1 ; OUT-NUM-1 prints at this DE in WKG Space.
EXX ; switch back
LD A,$01 ; prepare the terminating '"'
LD (DE),A ; and place at end of string.
;; POP-RET
L0C22: POP HL ; * restore result pointer.
RET ; return.
; -------------------------------
; THE 'CODE' AND 'PEEK' FUNCTIONS
; -------------------------------
; Two functions in one subroutine.
; CODE with HL pointing to start of string.
; and also,
; PEEK with HL pointing to a memory address.
; The return value is in HL.
;; CODE
;; PEEK
L0C24: LD L,(HL) ; parameter is in HL.
LD H,$00 ;
RET ; return with result in HL.
; -------------------
; THE 'CHR$' FUNCTION
; -------------------
; this function returns the null-terminated single-character string that
; corresponds to the integer argument e.g. CHR$(38) returns "A".
;; chr$
L0C28: LD BC,$0002 ; two locations required.
LD A,L ; character to A.
RST 30H ; BC-SPACES creates two locations
; in WORKSPACE
JR NC,L0C34 ; forward to NULL-STR if no room.
;; NULL-PTR
L0C2F: LD (HL),$01 ; insert the '"' terminator at last new location
DEC HL ; decrease the pointer.
LD (HL),A ; insert the character.
RET ; return with HL pointing to string.
; ---
;; NULL-STR
L0C34: LD HL,L0C2F + 1 ; point to the null string at NULL-PTR + 1
; in the above code.
RET ; return.
; ------------------
; THE 'TL$' FUNCTION
; ------------------
; This limited string slicing function returns the tail of a string starting
; at the second character and the null string otherwise.
; It requires no string workspace.
;; tl$
L0C38: LD A,(HL) ; fetch first character of string
DEC A ; decrement it.
RET Z ; return if was CHR$ 1 - the null string.
INC HL ; else increase the string pointer
RET ; return with HL pointing at result.
; -----------------
; THE 'LET' ROUTINE
; -----------------
; This subroutine is called from the FOR command and the CLASS-02 routine
; to create the variable.
;; LET
L0C3D: BIT 7,(IY+$00) ; test ERR_NR
RET Z ; return if not $FF
; proceed if no errors so far.
PUSH BC ; save start val
LD HL,($4020) ; fetch location of letter in BASIC from DEST
CALL L0B3B ; routine LV-FIND will set error
LD HL,$4000 ; ERR_NR
LD A,(HL)
CP $02 ; compare to 2 - subscript out of range
JR Z,L0C22 ; back to POP-RET if so >>>
; continue with variable not found or OK.
RLA ; test for $FF??
BIT 6,(IY+$01) ; test bit 6 FLAGS - affects zero flag only.
; zero if string NZ if numeric
JR C,L0C93 ; forward if error was $FF to L-EXISTS
; continue if variable does not exist.
LD (HL),$FF ; cancel the error as variable will be created.
JR Z,L0CA3 ; forward to L-STRING with string var.
; continue with numeric INTEGER variable
LD HL,($4020) ; pick up destination from DEST
LD BC,$0002 ; set default space for integer contents
; will be 3 including letter
;; L-EACH-CH
L0C62: INC BC ; pre-increment character count.
INC HL ; increment character pointer in BASIC or
; workspace.
LD A,(HL) ; fetch the character.
CALL L0D18 ; routine ALPHANUM check if "[0-Z]"
JR C,L0C62 ; loop back if so to L-EACH-CH
CP $DA ; is character '(' ?
JR Z,L0CD0 ; forward if so to ERROR-02 - var not found.
; e.g. perhaps a function has been misspelled.
RST 30H ; BC-SPACES creates room for new INTEGER
; variable at D-FILE - 1, the variables
; end-marker.
JR NC,L0C22 ; back to POP-RET if not enough room
PUSH DE ; save first new location ***
LD HL,($4020) ; fetch DEST the pointer to letter in command
DEC BC ; reduce count by
DEC BC ; the three bytes
DEC BC ; for simple integer.
DEC DE ; point to destination
LD A,B ; check if this is a one-character
OR C ; variable name from reduced count.
LD A,$40 ; prepare mask 010xxxxx
JR Z,L0C87 ; forward to L-SINGLE if is simple numeric.
LDIR ; else copy all but one characters of name.
LD A,(HL) ; fetch last character
OR $80 ; invert it
LD (DE),A ; place at last destination
LD A,$60 ; prepare mask 011xxxxx
;; L-SINGLE
L0C87: POP HL ; restore first new location ***
CALL L0CB9 ; routine L-MASK inserts masked letter.
EX DE,HL ;
DEC DE ;
; and continue to initialize variable contents.
; this branch is taken from below to overwrite contents.
;; L-NUMERIC
L0C8D: POP HL ; restore variable value
EX DE,HL ; HL points last location
LD (HL),D ; insert high byte.
DEC HL ; decrement the pointer.
LD (HL),E ; and insert low-byte value
RET ; return. with HL addressing the value. >>>>
; ---
;; L-EXISTS
L0C93: JR NZ,L0C8D ; back to L-NUMERIC to overwrite variable
; if numeric type.
POP HL ; restore string
CALL L0CA4 ; routine L-LENGTH evaluates length of OLD
; string
LD HL,($4022) ; fetch string pointer from RESULT
DEC HL ; decrement to point to letter.
CALL L0624 ; routine NEXT-ONE calculate space to delete
JP L0666 ; routine RECLAIM-2
; now continue into L-STRING to evaluate length of new string.
; ---
;; L-STRING
L0CA3: POP HL ; restore pointer to contents.
;; L-LENGTH
L0CA4: LD A,$01 ; the search will be for the quote character.
LD BC,$0001 ; initialize length to one.
;; L-COUNT
L0CA9: CP (HL) ; is addressed character null ?
INC HL ; increase pointer.
INC BC ; increase length.
JR NZ,L0CA9 ; loop back to L-COUNT till terminating
; quote found.
PUSH HL ; save pointer to end - null terminator.
RST 30H ; routine BC-SPACES creates room at end.
EX DE,HL ; transfer end to DE.
POP HL ; retrieve pointer to null terminator in E-LINE.
RET NC ; return if no room was available.
LDDR ; else copy string to the variables area.
EX DE,HL ; HL now points to letter -1
INC HL ; adjust
LD A,$A0 ; prepare mask %10100000
;; L-MASK
L0CB9: EX DE,HL ; save variable pointer in DE.
LD HL,($4020) ; fetch destination in prog/e-line area
; from system variable DEST
XOR (HL) ; XOR mask with the letter.
; Note. All letters have bit 5 set. The
; preparation of masks must accommodate this.
EX DE,HL ; variable pointer to HL,
PUSH AF ; save masked letter
CALL L0D0D ; routine REC-V80 reclaims
; the previous $80 variables end-marker.
POP AF ; pop the letter.
DEC HL ; point to the letter in the variables area.
; which is now one location lower than it was
; a moment ago.
LD (HL),A ; insert masked letter.
LD HL,($400C) ; use D_FILE value
LD ($400A),HL ; to update new E_LINE
DEC HL ; step back.
LD (HL),$80 ; and insert the new variable $80 end-marker.
RET ; return.
; ---
;; ERROR-02
L0CD0: POP HL ;
RST 08H ; ERROR restart
DEFB $01 ; variable name not found.
; -------------------------
; THE 'DIM' COMMAND ROUTINE
; -------------------------
; This routine creates a one-dimensional numeric array with up to
; 256 subscripts. Each is initialized to the integer zero.
; Note. array subscripts begin at zero. On later ZX computers subscripts began
; at 1 and there were no limits to the dimensions and subscripts other than
; memory.
;; DIM
L0CD3: AND B ; check high byte of parameter.
; a maximum of 255 subscripts possible.
JP NZ,L0BBE ; back to ERROR-03 - subscript error.
PUSH BC ; save max subscript
LD H,B ; transfer
LD L,C ; to HL.
INC HL ; increment to make range 1-256 from 0-255
INC HL ; increment for letter and subscript byte
ADD HL,HL ; double - allocates two bytes per integer
; and two for the letter and subscript.
LD B,H ; transfer count
LD C,L ; to BC
RST 30H ; BC-SPACES
JP NC,L0C22 ; back to POP-RET if out of memory
DEC HL ; point to last new location
LD D,H ; transfer to DE
LD E,L ; - the destination.
DEC DE ; make DE one less than source.
DEC BC ; reduce count
DEC BC ; by two.
LD (HL),$00 ; insert a zero at source.
LDDR ; block fill locations with zero.
POP BC ; restore number of subscripts
LD (HL),C ; and place in location before data.
LD A,$80 ; prepare mask %100
JR L0CB9 ; back to L-MASK
; ---------------------
; THE 'RESERVE' ROUTINE
; ---------------------
; A continuation of the BC-SPACES RESTART.
; the number of bytes required is on the machine stack.
;; RESERVE
L0CF3: LD HL,($400A) ; fetch start of WKG Space from E_LINE
PUSH HL ; preserve location.
LD HL,($400C) ; fetch location after WKG Space from D_FILE
DEC HL ; point to last byte of WKG space.
CALL L05D5 ; routine MAKE-ROOM creates the space after
; last byte sliding D-FILE up and updating
; D_FILE, DF_EA and DF_END
INC HL ; increase address
INC HL ; by two bytes
POP BC ; retrieve E_LINE which may have been updated
; by pointers
LD ($400A),BC ; restore E_LINE
POP BC ; restore the number of bytes required.
EX DE,HL ; switch - DE points to first
INC HL ; make HL point to last new byte
SCF ; signal success
RET ; return
; --------------------------------------
; THE 'RECLAIM THE EDIT LINE' SUBROUTINE
; --------------------------------------
; Interestingly, Hugo Davenport refers to this subroutine in the manual
; by its Nine Tiles source code label X_TEMP.
; The second entry point deletes the old variables end-marker when creating
; a new variable immediately after this position.
;; REC-EDIT
L0D0A: LD HL,($400C) ; D_FILE
;; REC-V80
L0D0D: LD DE,($400A) ; E_LINE
JP L0663 ; RECLAIM-1
; ----------------------
; THE 'ALPHA' SUBROUTINE
; ----------------------
;; ALPHA
L0D14: CP $26 ; compare to 'A'
JR L0D1A ; forward to ALPHA-2 to compare
; against 'Z'
; -------------------------
; THE 'ALPHANUM' SUBROUTINE
; -------------------------
; The zx80 character set makes this routine as straightforward as the one above
; as there is no gap between numerals and alphabetic characters.
;; ALPHANUM
L0D18: CP $1C ; compare to '0' - carry set if less
;; ALPHA-2
L0D1A: CCF ; change to carry reset if less.
RET NC ; return if less than '0'
CP $40 ; compare to character after 'Z'
RET ; return with carry set if in the
; range '0' - 'Z'
; ------------------------------------------------
; THE 'ARITHMETIC OPERATORS AND COMPARISONS' TABLE
; ------------------------------------------------
; This table is indexed with the operator * 2 to access the address of the
; associated routine.
;; TAB-OPS
L0D1F: DEFW L0D39 ; $00 subtract
DEFW L0D3E ; $01 addition
DEFW L0D44 ; $02 multiply
DEFW L0D90 ; $03 division
DEFW L0DB5 ; $04 and
DEFW L0DBC ; $05 or
DEFW L0D70 ; $06 to-power
DEFW L0DC3 ; $07 nos-eql
DEFW L0DCC ; $08 no-grtr
DEFW L0DCD ; $09 no-less
DEFW L0DD9 ; $0A strs-eql
DEFW L0DDF ; $0B str-grtr
DEFW L0DDE ; $0C str-less
; ---------------------------
; THE 'SUBTRACTION' OPERATION
; ---------------------------
; offset $00 : subtract
; This operation simply uses the Z80's 16-bit register subtract instruction
; which sets the overflow flag if the lower 15 bits overflow.
;; subtract
L0D39: AND A ; clear carry flag.
SBC HL,DE ; 16 bit subtraction.
JR L0D41 ; forward to RSLT-TEST
; ------------------------
; THE 'ADDITION' OPERATION
; ------------------------
; offset $01 : add
; This operation simply uses the Z80's 16-bit register add instruction
; which sets the overflow flag in the manner above.
;; addition
L0D3E: AND A ; clear carry flag.
ADC HL,DE ; 16 bit addition.
;; RSLT-TEST
L0D41: RET PO ; return if no twos-complement arithmetic
; overflow.
;; ERROR-06
L0D42: RST 08H ; ERROR restart
DEFB $05 ; arithmetic overflow.
; ------------------------------
; THE 'MULTIPLICATION' OPERATION
; ------------------------------
; offset $02 : multiply
; the multiplication operation converts the two numbers HL and DE to positive
; integers, saving the result sign in the accumulator. If the positive result
; is above 32767 then an error code is produced else result is converted
; to the required sign, if necessary, as dictated by the accumulator.
;; multiply
L0D44: CALL L0DED ; routine PREP-MD
PUSH BC ; save priority/operation
EX AF,AF' ; save result sign
CALL L0D55 ; routine MULT16
JR NZ,L0D8D ; forward with overflow to POP6
; clear the stack and produce ERROR-06
;; MULT-2
L0D4E: POP BC ; restore priority/operation
EX AF,AF' ; restore result sign.
RRA ; test sign bit.
RET NC ; return if result positive.
JP L0DF6 ; exit via routine TWOS-COMP
; ----------------------------------------
; THE 'SIXTEEN BIT MULTIPLICATION' ROUTINE
; ----------------------------------------
; Binary long multiplication by shifting and addition at the appropriate place
; if the multiplier bit is set.
; This important subroutine is called from the multiply routine, the to-power
; routine and twice from the RND function routine.
; It multiplies the 16 bit multiplier, HL, by the 16-bit multiplicand DE.
; Since the highest number the ZX80 can hold is 32767, the routine detects
; any overflow above this, resetting the zero flag - NZ with overflow.
; However if overflow occurs the routine does not abort, as does say the
; Spectrum, but continues to calculate the 32-bit result in B, C, H, L.
; Use is made of this by the RND routine.
;; MULT16
L0D55: LD B,H ; transfer HL to BC
LD C,L ; register.
LD A,$10 ; count 16 bits.
LD HL,$0000 ; initialize result register.
;; MULT-LP
L0D5C: ADD HL,HL ; shift result left.
RL C ; shift multiplier
RL B ; to the left.
; and capture any overflow.
JR NC,L0D67 ; skip addition if no carry to MULT-SKIP.
ADD HL,DE ; else add in multiplicand for this bit
JR NC,L0D67 ; forward if no overflow.
INC BC ; capture overflow in BC
;; MULT-SKIP
L0D67: DEC A ; decrement bit count.
JR NZ,L0D5C ; loop back for all 16 bits to MULT-LP.
LD A,H ; test for a
AND $80 ; negative result.
OR B ; test for any
OR C ; intermediate overflow
RET ; return with zero flag set
; for success.
; ------------------------
; THE 'TO-POWER' OPERATION
; ------------------------
; offset $06 : to-power
; This routine raises HL to the power DE, by performing a multiplication
; for each unit of the power. For the integer range supported this is quite
; adequate with 2**14 returning the result without any noticeable delay
; and 1**32767 blacking the screen out for no more than a second.
; Note also that
; 0 ** 0 = 1.
; 0 ** +n = 0.
; 0 ** -n = arithmetic overflow.
;; to-power
L0D70: BIT 7,D ; test if second number negative.
JR NZ,L0D42 ; back to ERROR-06 if so.
XOR A ; initialize sign flag
CALL L0DF2 ; routine ABS - makes HL positive.
; A holds 1 if HL was negative else 0.
AND E ;
EX AF,AF' ; save result
PUSH BC ; save priority/operation
LD B,D ; transfer power
LD C,E ; to BC
EX DE,HL ; transfer number to DE
LD HL,$0001 ; initialize result.
;; POWER-LP
L0D81: DEC BC ; decrement power counter.
BIT 7,B ; check when zero passed.
JR NZ,L0D4E ; back when finished to MULT-2
; to test result. >>
PUSH BC ; save counter.
CALL L0D55 ; routine MULT16
POP BC ; restore counter.
JR Z,L0D81 ; loop while no overflow exists from
; the multiplication to POWER-LP.
;; POP6
L0D8D: POP BC ; restore priority/operation
JR L0D42 ; back to ERROR-06 - arithmetic overflow.
; ------------------------
; THE 'DIVISION' OPERATION
; ------------------------
; offset $03 : division
; Binary long division by shifting and subtraction at the appropriate place,
; setting correct quotient bit if the subtraction goes.
; dividend (HL) / divisor (DE) = quotient (HL)
;; division
L0D90: LD A,D ; test divisor for zero
OR E ; avoiding division by zero.
JR Z,L0D42 ; to ERROR-06 - arithmetic overflow
; if so.
CALL L0DED ; routine PREP-MD converts HL and DE to 15-bit
; integers and records the result sign in A.
PUSH BC ; save the priority/operation.
RRA ; sets carry if a negative result.
ADC HL,HL ; pick up the carry in HL, (bit 15 was reset)
LD A,H ; transfer modified dividend to
LD C,L ; registers A and C.
LD HL,L0000 ; initialize 'accumulator' to zero.
LD B,$10 ; sixteen bits including sign bit.
;; DIV-1
L0DA2: ADC HL,HL ;
SBC HL,DE ; subtract divisor.
JR NC,L0DA9 ; skip forward if subtraction goes to DIV-2.
ADD HL,DE ; add back divisor.
;; DIV-2
L0DA9: RL C ; as dividend bits are shifted out, the
RLA ; result bits are shifted in.
DJNZ L0DA2 ; back for all 16 bits.
; note after 16 bits the final RLA retrieves the sign
LD H,A ; transfer result in A and C
LD L,C ; to HL
INC HL ; increment
POP BC ; restore priority/operation.
RET C ; return if .
JR L0DF6 ; else forward to TWOS-COMP.
; ---------------------------
; THE 'BITWISE AND' OPERATION
; ---------------------------
; offset $04 : and
;; and
L0DB5: LD A,H ;
AND D ;
LD H,A ;
LD A,L ;
AND E ;
LD L,A ;
RET ;
; --------------------------
; THE 'BITWISE OR' OPERATION
; --------------------------
; offset $05 : or
;; or
L0DBC: LD A,H ;
OR D ;
LD H,A ;
LD A,L ;
OR E ;
LD L,A ;
RET ;
; -----------------------------------------
; THE 'THREE NUMERIC COMPARISON' OPERATIONS
; -----------------------------------------
; offsets $07 - nos-eql, $08 - no-grtr, $09 - no-less.
;
; for example, PRINT 2=2 gives result -1 (true)
;; nos-eql
L0DC3: AND A ; prepare to subtract.
SBC HL,DE ; subtract the two numbers.
;; SET-RSLT
L0DC6: LD HL,$FFFF ; prepare true result.
RET Z ; return true result, $FFFF, in HL
; if remainder was zero.
INC HL ; else increment to $0000
RET ; return false result, zero in HL.
; ---
;; no-grtr
L0DCC: EX DE,HL ; swap values and continue into ...
;; no-less
L0DCD: AND A ; prepare for true subtraction
SBC HL,DE ; subtract using registers
LD A,H ; fetch MSB
RLA ; test the sign bit without affecting P/V flag
JP PO,L0DD6 ; skip to TEST-HL with no overflow
CCF ; complement the carry flag
;; TEST-HL
L0DD6: SBC HL,HL ; result HL will be $0000 false or $FFFF true
; with carry.
RET ; return
; ----------------------------------------
; THE 'THREE STRING COMPARISON' OPERATIONS
; ----------------------------------------
; offsets $0A - strs-eql, $0B - str-grtr, $0C - str-less.
;; strs-eql
L0DD9: CALL L0DE4 ; routine STR-CMP
JR L0DC6 ; to SET-RSLT
; ---
;; str-grtr
L0DDE: EX DE,HL ; swap the two string pointers
;; str-less
L0DDF: CALL L0DE4 ; routine STR-CMP
JR L0DD6 ; back to TEST-HL
; ----------------------------------
; THE 'STRING COMPARISON' SUBROUTINE
; ----------------------------------
;; STR-CMP
L0DE4: LD A,(DE) ; fetch character of 2nd string.
CP (HL) ; compare to first.
RET NZ ; return with mismatch, carry flag
; shows the comparison.
DEC A ; test for the null string chr$ 1.
RET Z ; return as both strings have
; terminated - an exact match.
INC DE ; else increase
INC HL ; both the string pointers.
JR L0DE4 ; and loop back to STR-CMP till one
; of the two conditions is met.
; ----------------------------------------------
; THE 'PREPARE TO MULTIPLY OR DIVIDE' SUBROUTINE
; ----------------------------------------------
;; PREP-MD
L0DED: XOR A ; initialize a sign flag.
CALL L0DF1 ; call PREP-1 to prepare one number
; and continue into routine to prepare
; the other number.
;; PREP-1
L0DF1: EX DE,HL ; switch numbers at each pass
; ------------------
; THE 'ABS' FUNCTION
; ------------------
; finds the absolute value of an signed integer.
; Negative numbers are twos complemented.
; e.g. minus 1 ($FFFF) is first 'ones complemented' to $0000 then incremented.
;; abs
L0DF2: BIT 7,H ; test sign of HL.
RET Z ; return if positive.
INC A ; sets bit 0 if result is negative.
; two negatives will reset bit 0 when this
; routine is used to prepare for multiplication.
; 'a minus times a minus gives a plus'.
;; TWOS-COMP
L0DF6: EX AF,AF' ; save running flag.
LD A,H ; fetch high byte
CPL ; complement it
LD H,A ; put back
LD A,L ; fetch low byte
CPL ; complement
LD L,A ; put back
INC HL ; twos complement
EX AF,AF' ; restore running flag.
RET ; return.
; -------------------
; THE 'SPARE' SECTION
; -------------------
; Start of Spare bytes
; End of Spare bytes.
;--------------------
; THE 'CHARACTER SET'
;--------------------
;; char-set
; $00 - space character CHR$(0)
L0E00: DEFB %00000000
DEFB %00000000
DEFB %00000000
DEFB %00000000
DEFB %00000000
DEFB %00000000
DEFB %00000000
DEFB %00000000
; $01 - Character: '"' CHR$(1)
DEFB %00000000
DEFB %00010100
DEFB %00010100
DEFB %00000000
DEFB %00000000
DEFB %00000000
DEFB %00000000
DEFB %00000000
; $02 - Character: mosaic CHR$(2)
DEFB %11110000
DEFB %11110000
DEFB %11110000
DEFB %11110000
DEFB %11110000
DEFB %11110000
DEFB %11110000
DEFB %11110000
; $03 - Character: mosaic CHR$(3)
DEFB %00000000
DEFB %00000000
DEFB %00000000
DEFB %00000000
DEFB %11111111
DEFB %11111111
DEFB %11111111
DEFB %11111111
; $04 - Character: mosaic CHR$(4)
DEFB %11110000
DEFB %11110000
DEFB %11110000
DEFB %11110000
DEFB %00000000
DEFB %00000000
DEFB %00000000
DEFB %00000000
; $05 - Character: mosaic CHR$(5)
DEFB %00001111
DEFB %00001111
DEFB %00001111
DEFB %00001111
DEFB %00000000
DEFB %00000000
DEFB %00000000
DEFB %00000000
; $06 - Character: mosaic CHR$(6)
DEFB %00000000
DEFB %00000000
DEFB %00000000
DEFB %00000000
DEFB %11110000
DEFB %11110000
DEFB %11110000
DEFB %11110000
; $07 - Character: mosaic CHR$(7)
DEFB %00000000
DEFB %00000000
DEFB %00000000
DEFB %00000000
DEFB %00001111
DEFB %00001111
DEFB %00001111
DEFB %00001111
; $08 - Character: mosaic CHR$(8)
DEFB %00001111
DEFB %00001111
DEFB %00001111
DEFB %00001111
DEFB %11110000
DEFB %11110000
DEFB %11110000
DEFB %11110000
; $09 - Character: mosaic CHR$(9)
DEFB %10101010
DEFB %01010101
DEFB %10101010
DEFB %01010101
DEFB %10101010
DEFB %01010101
DEFB %10101010
DEFB %01010101
; $0A - Character: mosaic CHR$(10)
DEFB %00000000
DEFB %00000000
DEFB %00000000
DEFB %00000000
DEFB %10101010
DEFB %01010101
DEFB %10101010
DEFB %01010101
; $0B - Character: mosaic CHR$(11)
DEFB %10101010
DEFB %01010101
DEFB %10101010
DEFB %01010101
DEFB %00000000
DEFB %00000000
DEFB %00000000
DEFB %00000000
; $0C - Character: uk pound CHR$(12)
DEFB %00000000
DEFB %00011110
DEFB %00100001
DEFB %01111000
DEFB %00100000
DEFB %00100000
DEFB %01111111
DEFB %00000000
; $0D - Character: '$' CHR$(13)
DEFB %00000000
DEFB %00001000
DEFB %00111110
DEFB %01001000
DEFB %00111110
DEFB %00001001
DEFB %00111110
DEFB %00001000
; $0E - Character: ':' CHR$(14)
DEFB %00000000
DEFB %00000000
DEFB %00000000
DEFB %00001000
DEFB %00000000
DEFB %00000000
DEFB %00001000
DEFB %00000000
; $0F - Character: '?' CHR$(15)
DEFB %00000000
DEFB %00111110
DEFB %01000001
DEFB %00000110
DEFB %00001000
DEFB %00000000
DEFB %00001000
DEFB %00000000
; $10 - Character: '(' CHR$(16)
DEFB %00000000
DEFB %00000100
DEFB %00001000
DEFB %00001000
DEFB %00001000
DEFB %00001000
DEFB %00000100
DEFB %00000000
; $11 - Character: ')' CHR$(17)
DEFB %00000000
DEFB %00010000
DEFB %00001000
DEFB %00001000
DEFB %00001000
DEFB %00001000
DEFB %00010000
DEFB %00000000
; $12 - Character: '-' CHR$(18)
DEFB %00000000
DEFB %00000000
DEFB %00000000
DEFB %00000000
DEFB %00111110
DEFB %00000000
DEFB %00000000
DEFB %00000000
; $13 - Character: '+' CHR$(19)
DEFB %00000000
DEFB %00000000
DEFB %00001000
DEFB %00001000
DEFB %00111110
DEFB %00001000
DEFB %00001000
DEFB %00000000
; $14 - Character: '*' CHR$(20)
DEFB %00000000
DEFB %00000000
DEFB %00101010
DEFB %00011100
DEFB %00001000
DEFB %00011100
DEFB %00101010
DEFB %00000000
; $15 - Character: '/' CHR$(21)
DEFB %00000000
DEFB %00000000
DEFB %00000010
DEFB %00000100
DEFB %00001000
DEFB %00010000
DEFB %00100000
DEFB %00000000
; $16 - Character: '=' CHR$(22)
DEFB %00000000
DEFB %00000000
DEFB %00000000
DEFB %00111110
DEFB %00000000
DEFB %00111110
DEFB %00000000
DEFB %00000000
; $17 - Character: '>' CHR$(23)
DEFB %00000000
DEFB %00000000
DEFB %00010000
DEFB %00001000
DEFB %00000100
DEFB %00001000
DEFB %00010000
DEFB %00000000
; $18 - Character: '<' CHR$(24)
DEFB %00000000
DEFB %00000000
DEFB %00000100
DEFB %00001000
DEFB %00010000
DEFB %00001000
DEFB %00000100
DEFB %00000000
; $19 - Character: ';' CHR$(25)
DEFB %00000000
DEFB %00000000
DEFB %00001000
DEFB %00000000
DEFB %00000000
DEFB %00001000
DEFB %00001000
DEFB %00010000
; $1A - Character: ',' CHR$(26)
DEFB %00000000
DEFB %00000000
DEFB %00000000
DEFB %00000000
DEFB %00000000
DEFB %00001000
DEFB %00001000
DEFB %00010000
; $1B - Character: '.' CHR$(27)
DEFB %00000000
DEFB %00000000
DEFB %00000000
DEFB %00000000
DEFB %00000000
DEFB %00001100
DEFB %00001100
DEFB %00000000
; $1C - Character: '0' CHR$(28)
DEFB %00000000
DEFB %00011100
DEFB %00100010
DEFB %01000001
DEFB %01000001
DEFB %00100010
DEFB %00011100
DEFB %00000000
; $1D - Character: '1' CHR$(29)
DEFB %00000000
DEFB %00001100
DEFB %00010100
DEFB %00000100
DEFB %00000100
DEFB %00000100
DEFB %00011110
DEFB %00000000
; $1E - Character: '2' CHR$(30)
DEFB %00000000
DEFB %00111110
DEFB %01000001
DEFB %00000001
DEFB %00111110
DEFB %01000000
DEFB %01111111
DEFB %00000000
; $1F - Character: '3' CHR$(31)
DEFB %00000000
DEFB %00111110
DEFB %01000001
DEFB %00000110
DEFB %00000001
DEFB %01000001
DEFB %00111110
DEFB %00000000
; $20 - Character: '4' CHR$(32)
DEFB %00000000
DEFB %00001100
DEFB %00010100
DEFB %00100100
DEFB %01000100
DEFB %01111111
DEFB %00000100
DEFB %00000000
; $21 - Character: '5' CHR$(33)
DEFB %00000000
DEFB %01111111
DEFB %01000000
DEFB %01111110
DEFB %00000001
DEFB %01000001
DEFB %00111110
DEFB %00000000
; $22 - Character: '6' CHR$(34)
DEFB %00000000
DEFB %00111110
DEFB %01000000
DEFB %01111110
DEFB %01000001
DEFB %01000001
DEFB %00111110
DEFB %00000000
; $23 - Character: '7' CHR$(35)
DEFB %00000000
DEFB %01111111
DEFB %00000001
DEFB %00000010
DEFB %00000100
DEFB %00001000
DEFB %00001000
DEFB %00000000
; $24 - Character: '8' CHR$(36)
DEFB %00000000
DEFB %00111110
DEFB %01000001
DEFB %00111110
DEFB %01000001
DEFB %01000001
DEFB %00111110
DEFB %00000000
; $25 - Character: '9' CHR$(37)
DEFB %00000000
DEFB %00111110
DEFB %01000001
DEFB %01000001
DEFB %00111111
DEFB %00000001
DEFB %00111110
DEFB %00000000
; $26 - Character: 'A' CHR$(38)
DEFB %00000000
DEFB %00111110
DEFB %01000001
DEFB %01000001
DEFB %01111111
DEFB %01000001
DEFB %01000001
DEFB %00000000
; $27 - Character: 'B' CHR$(39)
DEFB %00000000
DEFB %01111110
DEFB %01000001
DEFB %01111110
DEFB %01000001
DEFB %01000001
DEFB %01111110
DEFB %00000000
; $28 - Character: 'C' CHR$(40)
DEFB %00000000
DEFB %00011110
DEFB %00100001
DEFB %01000000
DEFB %01000000
DEFB %00100001
DEFB %00011110
DEFB %00000000
; $29 - Character: 'D' CHR$(41)
DEFB %00000000
DEFB %01111100
DEFB %01000010
DEFB %01000001
DEFB %01000001
DEFB %01000010
DEFB %01111100
DEFB %00000000
; $2A - Character: 'E' CHR$(42)
DEFB %00000000
DEFB %01111111
DEFB %01000000
DEFB %01111100
DEFB %01000000
DEFB %01000000
DEFB %01111111
DEFB %00000000
; $2B - Character: 'F' CHR$(43)
DEFB %00000000
DEFB %01111111
DEFB %01000000
DEFB %01111100
DEFB %01000000
DEFB %01000000
DEFB %01000000
DEFB %00000000
; $2C - Character: 'G' CHR$(44)
DEFB %00000000
DEFB %00011110
DEFB %00100001
DEFB %01000000
DEFB %01000111
DEFB %00100001
DEFB %00011110
DEFB %00000000
; $2D - Character: 'H' CHR$(45)
DEFB %00000000
DEFB %01000001
DEFB %01000001
DEFB %01111111
DEFB %01000001
DEFB %01000001
DEFB %01000001
DEFB %00000000
; $2E - Character: 'I' CHR$(46)
DEFB %00000000
DEFB %00111110
DEFB %00001000
DEFB %00001000
DEFB %00001000
DEFB %00001000
DEFB %00111110
DEFB %00000000
; $2F - Character: 'J' CHR$(47)
DEFB %00000000
DEFB %00000010
DEFB %00000010
DEFB %00000010
DEFB %01000010
DEFB %00100010
DEFB %00011100
DEFB %00000000
; $30 - Character: 'K' CHR$(48)
DEFB %00000000
DEFB %01000010
DEFB %01000100
DEFB %01111000
DEFB %01000100
DEFB %01000010
DEFB %01000001
DEFB %00000000
; $31 - Character: 'L' CHR$(49)
DEFB %00000000
DEFB %01000000
DEFB %01000000
DEFB %01000000
DEFB %01000000
DEFB %01000000
DEFB %01111111
DEFB %00000000
; $32 - Character: 'M' CHR$(50)
DEFB %00000000
DEFB %01000001
DEFB %01100011
DEFB %01010101
DEFB %01001001
DEFB %01000001
DEFB %01000001
DEFB %00000000
; $33 - Character: 'N' CHR$(51)
DEFB %00000000
DEFB %01100001
DEFB %01010001
DEFB %01001001
DEFB %01000101
DEFB %01000011
DEFB %01000001
DEFB %00000000
; $34 - Character: 'O' CHR$(52)
DEFB %00000000
DEFB %00111110
DEFB %01000001
DEFB %01000001
DEFB %01000001
DEFB %01000001
DEFB %00111110
DEFB %00000000
; $35 - Character: 'P' CHR$(53)
DEFB %00000000
DEFB %01111110
DEFB %01000001
DEFB %01000001
DEFB %01111110
DEFB %01000000
DEFB %01000000
DEFB %00000000
; $36 - Character: 'Q' CHR$(54)
DEFB %00000000
DEFB %00111110
DEFB %01000001
DEFB %01000001
DEFB %01001001
DEFB %01000101
DEFB %00111110
DEFB %00000000
; $37 - Character: 'R' CHR$(55)
DEFB %00000000
DEFB %01111110
DEFB %01000001
DEFB %01000001
DEFB %01111110
DEFB %01000100
DEFB %01000010
DEFB %00000000
; $38 - Character: 'S' CHR$(56)
DEFB %00000000
DEFB %00111110
DEFB %01000000
DEFB %00111110
DEFB %00000001
DEFB %01000001
DEFB %00111110
DEFB %00000000
; $39 - Character: 'T' CHR$(57)
DEFB %00000000
DEFB %01111111
DEFB %00001000
DEFB %00001000
DEFB %00001000
DEFB %00001000
DEFB %00001000
DEFB %00000000
; $3A - Character: 'U' CHR$(58)
DEFB %00000000
DEFB %01000001
DEFB %01000001
DEFB %01000001
DEFB %01000001
DEFB %01000001
DEFB %00111110
DEFB %00000000
; $3B - Character: 'V' CHR$(59)
DEFB %00000000
DEFB %01000001
DEFB %01000001
DEFB %01000001
DEFB %00100010
DEFB %00010100
DEFB %00001000
DEFB %00000000
; $3C - Character: 'W' CHR$(60)
DEFB %00000000
DEFB %01000001
DEFB %01000001
DEFB %01000001
DEFB %01001001
DEFB %01010101
DEFB %00100010
DEFB %00000000
; $3D - Character: 'X' CHR$(61)
DEFB %00000000
DEFB %00100001
DEFB %00010010
DEFB %00001100
DEFB %00001100
DEFB %00010010
DEFB %00100001
DEFB %00000000
; $3E - Character: 'Y' CHR$(62)
DEFB %00000000
DEFB %01000001
DEFB %00100010
DEFB %00011100
DEFB %00001000
DEFB %00001000
DEFB %00001000
DEFB %00000000
; $3F - Character: 'Z' CHR$(63)
DEFB %00000000
DEFB %01111111
DEFB %00000010
DEFB %00000100
DEFB %00001000
DEFB %00010000
DEFB %01111111
L0FFF: DEFB %00000000
.END ;TASM assembler directive.
; -----------------------------------------------------------------------------
;
; -------------------
; The 'Character set'
; -------------------
;
; $00 $01 $02 $03 $04 $05 $06 $07 $08 $09 $0A $0B $0C $0D $0E $0F
; nul gra gra gra gra gra gra gra gra gra gra £ $ : ?
;
; $10 $11 $12 $13 $14 $15 $16 $17 $18 $19 $1A $1B $1C $1D $1E $1F
; ( ) - + * / = > < ; , . 0 1 2 3
;
; $20 $21 $22 $23 $24 $25 $26 $27 $28 $29 $2A $2B $2C $2D $2E $2F
; 4 5 6 7 8 9 A B C D E F G H I J
;
; $30 $31 $32 $33 $34 $35 $36 $37 $38 $39 $3A $3B $3C $3D $3E $3F
; K L M N O P Q R S T U V W X Y Z
;
; -----------------------------------------------------------------------------
;
; -------------------
; THE 'ZX80 KEYBOARD'
; -------------------
; [] mosaic graphic £ currency symbol
;
; NOT AND THEN TO <= V ^ => HOME RUBOUT
;+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
;| | | | | | | | | | | | | | | | | | | |
;| 1 | | 2 | | 3 | | 4 | | 5 | | 6 | | 7 | | 8 | | 9 | | 0 |
;+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
;
; NEW LOAD SAVE RUN CONT REM IF INPUT PRINT
;+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
;| [] | | [] | | [] | | [] | | [] | | " | | $ | | ( | | ) | | * |
;| Q | | W | | E | | R | | T | | Y | | U | | I | | O | | P |
;+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
;
; LIST STOP DIM FOR GOTO POKE RAND LET EDIT
;+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
;| [] | | [] | | [] | | [] | | [] | | ** | | - | | + | | = | | NEW |
;| A | | S | | D | | F | | G | | H | | J | | K | | L | | LINE|
;+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
;
; CLEAR CLS GOSUB RET NEXT BREAK
;+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
;| | | : | | ; | | ? | | / | | OR | | < | | > | | , | | £ |
;|SHIFT| | Z | | X | | C | | V | | B | | N | | M | | . | |SPACE|
;+-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+ +-----+
;
;
;
; -----------------------------------------------------------------------------
;
; ----------------------
; THE 'SYSTEM VARIABLES'
; ----------------------
; Note. the names of the System Variables are taken from the original
; Nine Tiles Assembly Listing.
;
; 1 16384 $4000 IY+$00 ERR_NR One less than report code.
; X1 16385 $4001 IY+$01 FLAGS Various Flags to control BASIC System.
; 7 1-Syntax off 0-Syntax on
; 6 1-Numeric result 0-String result
; 5 1-Evaluating function (not used)
; 3 1-K cursor 0-L cursor
; 2 1-K mode 0-L mode.
; 0 1-No leading space 0-Leading space.
; 2 16386 $4002 IY+$02 PPC Line number of current line.
; N2 16388 $4004 IY+$04 P_PTR. Position in RAM of [K] or [L] cursor.
; 2 16390 $4006 IY+$06 E_PPC Number of current line with [>] cursor.
; X2 16392 $4008 IY+$08 VARS Address of start of variables area.
; X2 16394 $400A IY+$0A E_LINE Address of start of Edit Line.
; X2 16396 $400C IY+$0C D_FILE Start of Display File.
; X2 16398 $400E IY+$0E DF_EA Address of the start of lower screen.
; X2 16400 $4010 IY+$10 DF_END Display File End.
; X1 16402 $4012 IY+$12 DF_SZ Number of lines in lower screen.
; 2 16403 $4013 IY+$13 S_TOP. The number of first line on screen.
; 2 16405 $4015 IY+$15 X_PTR Address of the character preceding
; the [S] marker.
; 2 16407 $4017 IY+$17 OLDPPC Line number to which continue jumps.
; N1 16409 $4019 IY+$19 FLAGX. More flags.
; 7 1-K mode 0-L mode.
; 6 1-Numeric result 0-String result
; 5 1-Inputting 0-Editing
; N2 16410 $401A IY+$1A T_ADDR Address of next item in syntax table.
; U2 16412 $401C IY+$1C SEED The seed for the random number.
; U2 16414 $401E IY+$1E FRAMES Count of frames shown since start-up.
; N2 16416 $4020 IY+$20 DEST Address of variable in statement.
; N2 16418 $4022 IY+$22 RESULT. Value of the last expression.
; X1 16420 $4024 IY+$24 S_POSN_X Column number for print position.
; X1 16421 $4025 IY+$25 S_POSN_Y Line number for print position.
; X2 16422 $4026 IY+$26 CH_ADD. Address of next character to be
; interpreted.
;
; -----------------------------------------------------------------------------