CPU-Z80-Disassembler
view release on metacpan or search on metacpan
t/data/zx81.asm view on Meta::CPAN
; ===========================================================
; An Assembly Listing of the Operating System of the ZX81 ROM
; ===========================================================
; -------------------------
; Last updated: 13-DEC-2004
; -------------------------
;
; Work in progress.
; This file will cross-assemble an original version of the "Improved"
; ZX81 ROM. The file can be modified to change the behaviour of the ROM
; when used in emulators although there is no spare space available.
;
; The documentation is incomplete and if you can find a copy
; of "The Complete Spectrum ROM Disassembly" then many routines
; such as POINTERS and most of the mathematical routines are
; similar and often identical.
;
; I've used the labels from the above book in this file and also
; some from the more elusive Complete ZX81 ROM Disassembly
; by the same publishers, Melbourne House.
; ================
; ZX-81 MEMORY MAP
; ================
; +------------------+-- Top of memory
; | Reserved area |
; +------------------+-- (RAMTOP)
; | GOSUB stack |
; +------------------+-- (ERR_SP)
; | Machine stack |
; +------------------+-- SP
; | Spare memory |
; +------------------+-- (STKEND)
; | Calculator stack |
; +------------------+-- (STKBOT)
; | Edit line |
; +------------------+-- (E_LINE)
; | User variables |
; +------------------+-- (VARS)
; | Screen |
; +------------------+-- (D_FILE)
; | User program |
; +------------------+-- 407Dh (16509d)
; | System variables |
; +------------------+-- 4000h (16384d)
; ======================
; ZX-81 SYSTEM VARIABLES
; ======================
ERR_NR equ $4000 ; N1 Current report code minus one
FLAGS equ $4001 ; N1 Various flags
ERR_SP equ $4002 ; N2 Address of top of GOSUB stack
RAMTOP equ $4004 ; N2 Address of reserved area (not wiped out by NEW)
MODE equ $4006 ; N1 Current cursor mode
PPC equ $4007 ; N2 Line number of line being executed
VERSN equ $4009 ; N1 First system variable to be SAVEd
E_PPC equ $400A ; N2 Line number of line with cursor
D_FILE equ $400C ; N2 Address of start of display file
DF_CC equ $400E ; N2 Address of print position within display file
VARS equ $4010 ; N2 Address of start of variables area
DEST equ $4012 ; N2 Address of variable being assigned
E_LINE equ $4014 ; N2 Address of start of edit line
CH_ADD equ $4016 ; N2 Address of the next character to interpret
X_PTR equ $4018 ; N2 Address of char. preceding syntax error marker
STKBOT equ $401A ; N2 Address of calculator stack
STKEND equ $401C ; N2 Address of end of calculator stack
BERG equ $401E ; N1 Used by floating point calculator
MEM equ $401F ; N2 Address of start of calculator's memory area
SPARE1 equ $4021 ; N1 One spare byte
DF_SZ equ $4022 ; N2 Number of lines in lower part of screen
S_TOP equ $4023 ; N2 Line number of line at top of screen
LAST_K equ $4025 ; N2 Keyboard scan taken after the last TV frame
DB_ST equ $4027 ; N1 Debounce status of keyboard
MARGIN equ $4028 ; N1 Number of blank lines above or below picture
NXTLIN equ $4029 ; N2 Address of next program line to be executed
OLDPPC equ $402B ; N2 Line number to which CONT/CONTINUE jumps
FLAGX equ $402D ; N1 Various flags
STRLEN equ $402E ; N2 Information concerning assigning of strings
T_ADDR equ $4030 ; N2 Address of next item in syntax table
SEED equ $4032 ; N2 Seed for random number generator
FRAMES equ $4034 ; N2 Updated once for every TV frame displayed
COORDS equ $4036 ; N2 Coordinates of last point PLOTed
PR_CC equ $4038 ; N1 Address of LPRINT position (high part assumed $40)
S_POSN equ $4039 ; N2 Coordinates of print position
CDFLAG equ $403B ; N1 Flags relating to FAST/SLOW mode
PRBUFF equ $403C ; N21h Buffer to store LPRINT output
MEMBOT equ $405D ; N1E Area which may be used for calculator memory
SPARE2 equ $407B ; N2 Two spare bytes
PROG equ $407D ; Start of BASIC program
IY0 equ ERR_NR
org $0000
;*****************************************
;** Part 1. RESTART ROUTINES AND TABLES **
;*****************************************
; -----------
; THE 'START'
; -----------
; All Z80 chips start at location zero.
; At start-up the Interrupt Mode is 0, ZX computers use Interrupt Mode 1.
; Interrupts are disabled .
;; START
START:
out ($FD), a ; Turn off the NMI generator if this ROM is
; running in ZX81 hardware. This does nothing
; if this ROM is running within an upgraded
; ZX80.
ld bc, $7FFF ; Set BC to the top of possible RAM.
; The higher unpopulated addresses are used for
; video generation.
jp RAM_CHECK ; Jump forward to RAM-CHECK.
;
; -------------------
; THE 'ERROR' RESTART
; -------------------
; The error restart deals immediately with an error. ZX computers execute the
; same code in runtime as when checking syntax. If the error occurred while
; running a program then a brief report is produced. If the error occurred
; while entering a BASIC line or in input etc., then the error marker indicates
; the exact point at which the error lies.
;; ERROR-1
ERROR_1:
ld hl, (CH_ADD) ; fetch character address from CH_ADD.
ld (X_PTR), hl ; and set the error pointer X_PTR.
jr ERROR_2 ; forward to continue at ERROR-2.
;
; -------------------------------
; THE 'PRINT A CHARACTER' RESTART
; -------------------------------
; This restart prints the character in the accumulator using the alternate
; register set so there is no requirement to save the main registers.
; There is sufficient room available to separate a space (zero) from other
; characters as leading spaces need not be considered with a space.
;; PRINT-A
PRINT_A:
and a ; test for zero - space.
jp nz, PRINT_CH ; jump forward if not to PRINT-CH.
;
jp PRINT_SP ; jump forward to PRINT-SP.
;
; ---
;
defb $FF ; unused location.
;
; ---------------------------------
; THE 'COLLECT A CHARACTER' RESTART
; ---------------------------------
; The character addressed by the system variable CH_ADD is fetched and if it
; is a non-space, non-cursor character it is returned else CH_ADD is
; incremented and the new addressed character tested until it is not a space.
;; GET-CHAR
GET_CHAR:
ld hl, (CH_ADD) ; set HL to character address CH_ADD.
ld a, (hl) ; fetch addressed character to A.
;
;; TEST-SP
TEST_SP:
and a ; test for space.
ret nz ; return if not a space
;
nop ; else trickle through
nop ; to the next routine.
;
; ------------------------------------
; THE 'COLLECT NEXT CHARACTER' RESTART
; ------------------------------------
; The character address in incremented and the new addressed character is
; returned if not a space, or cursor, else the process is repeated.
;; NEXT-CHAR
NEXT_CHAR:
call CH_ADD_1 ; routine CH-ADD+1 gets next immediate
; character.
jr TEST_SP ; back to TEST-SP.
;
; ---
defb $FF, $FF, $FF ; unused locations.
;
; ---------------------------------------
; THE 'FLOATING POINT CALCULATOR' RESTART
; ---------------------------------------
; this restart jumps to the recursive floating-point calculator.
; the ZX81's internal, FORTH-like, stack-based language.
;
; In the five remaining bytes there is, appropriately, enough room for the
; end-calc literal - the instruction which exits the calculator.
;; FP-CALC
FP_CALC:
jp CALCULATE ; jump immediately to the CALCULATE routine.
;
; ---
;; end-calc
end_calc:
pop af ; drop the calculator return address RE-ENTRY
exx ; switch to the other set.
;
ex (sp), hl ; transfer H'L' to machine stack for the
; return address.
; when exiting recursion then the previous
; pointer is transferred to H'L'.
;
exx ; back to main set.
ret ; return.
;
;
; -----------------------------
; THE 'MAKE BC SPACES' RESTART
; -----------------------------
; This restart is used eight times to create, in workspace, the number of
; spaces passed in the BC register.
;; BC-SPACES
BC_SPACES:
push bc ; push number of spaces on stack.
ld hl, (E_LINE) ; fetch edit line location from E_LINE.
push hl ; save this value on stack.
jp RESERVE ; jump forward to continue at RESERVE.
;
t/data/zx81.asm view on Meta::CPAN
; with interrupts disabled.
;
set 3, c ; (8) Load the scan line counter with eight.
; Note. LD C,$08 is 7 clock cycles which
; is way too fast.
;
; ->
;; WAIT-INT
WAIT_INT:
ld r, a ; (9) Load R with initial rising value $DD.
;
ei ; (4) Enable Interrupts. [ R is now $DE ].
;
jp (hl) ; (4) jump to the echo display file in upper
; memory and execute characters $00 - $3F
; as NOP instructions. The video hardware
; is able to read these characters and,
; with the I register is able to convert
; the character bitmaps in this ROM into a
; line of bytes. Eventually the NEWLINE/HALT
; will be encountered before R reaches $FF.
; It is however the transition from $FF to
; $80 that triggers the next interrupt.
; [ The Refresh register is now $DF ]
;
; ---
;; SCAN-LINE
SCAN_LINE:
pop de ; (10) discard the address after NEWLINE as the
; same text line has to be done again
; eight times.
;
ret z ; (5) Harmless Nonsensical Timing.
; (condition never met)
;
jr WAIT_INT ; (12) back to WAIT-INT
;
; Note. that a computer with less than 4K or RAM will have a collapsed
; display file and the above mechanism deals with both types of display.
;
; With a full display, the 32 characters in the line are treated as NOPS
; and the Refresh register rises from $E0 to $FF and, at the next instruction
; - HALT, the interrupt occurs.
; With a collapsed display and an initial NEWLINE/HALT, it is the NOPs
; generated by the HALT that cause the Refresh value to rise from $E0 to $FF,
; triggering an Interrupt on the next transition.
; This works happily for all display lines between these extremes and the
; generation of the 32 character, 1 pixel high, line will always take 128
; clock cycles.
; ---------------------------------
; THE 'INCREMENT CH-ADD' SUBROUTINE
; ---------------------------------
; This is the subroutine that increments the character address system variable
; and returns if it is not the cursor character. The ZX81 has an actual
; character at the cursor position rather than a pointer system variable
; as is the case with prior and subsequent ZX computers.
;; CH-ADD+1
CH_ADD_1:
ld hl, (CH_ADD) ; fetch character address to CH_ADD.
;
;; TEMP-PTR1
TEMP_PTR1:
inc hl ; address next immediate location.
;
;; TEMP-PTR2
TEMP_PTR2:
ld (CH_ADD), hl ; update system variable CH_ADD.
;
ld a, (hl) ; fetch the character.
cp $7F ; compare to cursor character.
ret nz ; return if not the cursor.
;
jr TEMP_PTR1 ; back for next character to TEMP-PTR1.
;
; --------------------
; THE 'ERROR-2' BRANCH
; --------------------
; This is a continuation of the error restart.
; If the error occurred in runtime then the error stack pointer will probably
; lead to an error report being printed unless it occurred during input.
; If the error occurred when checking syntax then the error stack pointer
; will be an editing routine and the position of the error will be shown
; when the lower screen is reprinted.
;; ERROR-2
ERROR_2:
pop hl ; pop the return address which points to the
; DEFB, error code, after the RST 08.
ld l, (hl) ; load L with the error code. HL is not needed
; anymore.
;
;; ERROR-3
ERROR_3:
ld (iy+ERR_NR-IY0), l ; place error code in system variable ERR_NR
ld sp, (ERR_SP) ; set the stack pointer from ERR_SP
call SLOW_FAST ; routine SLOW/FAST selects slow mode.
jp SET_MIN ; exit to address on stack via routine SET-MIN.
;
; ---
defb $FF ; unused.
;
; ------------------------------------
; THE 'NON MASKABLE INTERRUPT' ROUTINE
; ------------------------------------
; Jim Westwood's technical dodge using Non-Maskable Interrupts solved the
; flicker problem of the ZX80 and gave the ZX81 a multi-tasking SLOW mode
; with a steady display. Note that the AF' register is reserved for this
; function and its interaction with the display routines. When counting
; TV lines, the NMI makes no use of the main registers.
; The circuitry for the NMI generator is contained within the SCL (Sinclair
; Computer Logic) chip.
; ( It takes 32 clock cycles while incrementing towards zero ).
;; NMI
NMI:
ex af, af' ; (4) switch in the NMI's copy of the
; accumulator.
inc a ; (4) increment.
jp m, NMI_RET ; (10/10) jump, if minus, to NMI-RET as this is
; part of a test to see if the NMI
; generation is working or an intermediate
; value for the ascending negated blank
; line counter.
;
jr z, NMI_CONT ; (12) forward to NMI-CONT
t/data/zx81.asm view on Meta::CPAN
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
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 'SHIFTED' CHARACTER CODES
; -----------------------------
;; K-SHIFT
K_SHIFT:
defb $0E ; :
defb $19 ;
defb $0F ; ?
defb $18 ; /
defb $E3 ; STOP
defb $E1 ; LPRINT
defb $E4 ; SLOW
defb $E5 ; FAST
defb $E2 ; LLIST
defb $C0 ; ""
defb $D9 ; OR
defb $E0 ; STEP
defb $DB ; <=
defb $DD ; <>
defb $75 ; EDIT
defb $DA ; AND
defb $DE ; THEN
defb $DF ; TO
defb $72 ; cursor-left
defb $77 ; RUBOUT
defb $74 ; GRAPHICS
defb $73 ; cursor-right
defb $70 ; cursor-up
defb $71 ; cursor-down
defb $0B ; "
defb $11 ; )
defb $10 ; (
defb $0D ; $
defb $DC ; >=
defb $79 ; FUNCTION
defb $14 ; =
defb $15 ; +
defb $16 ; -
defb $D8 ; **
defb $0C ; ukp
defb $1A ; ,
defb $12 ; >
defb $13 ; <
defb $17 ; *
;
; ------------------------------
; THE 'FUNCTION' CHARACTER CODES
; ------------------------------
;; K-FUNCT
K_FUNCT:
defb $CD ; LN
defb $CE ; EXP
defb $C1 ; AT
defb $78 ; KL
defb $CA ; ASN
defb $CB ; ACS
defb $CC ; ATN
defb $D1 ; SGN
defb $D2 ; ABS
defb $C7 ; SIN
defb $C8 ; COS
defb $C9 ; TAN
defb $CF ; INT
defb $40 ; RND
defb $78 ; KL
defb $78 ; KL
defb $78 ; KL
defb $78 ; KL
defb $78 ; KL
defb $78 ; KL
defb $78 ; KL
defb $78 ; KL
defb $78 ; KL
defb $78 ; KL
defb $C2 ; TAB
defb $D3 ; PEEK
defb $C4 ; CODE
defb $D6 ; CHR$
defb $D5 ; STR$
defb $78 ; KL
defb $D4 ; USR
defb $C6 ; LEN
defb $C5 ; VAL
defb $D0 ; SQR
defb $78 ; KL
defb $78 ; KL
t/data/zx81.asm view on Meta::CPAN
;
; ----------------------------
; THE 'INITIALIZATION' ROUTINE
; ----------------------------
;
;
;; INITIAL
INITIAL:
ld hl, (RAMTOP) ; fetch system variable RAMTOP.
dec hl ; point to last system byte.
ld (hl), $3E ; make GO SUB end-marker $3E - too high for
; high order byte of line number.
; (was $3F on ZX80)
dec hl ; point to unimportant low-order byte.
ld sp, hl ; and initialize the stack-pointer to this
; location.
dec hl ; point to first location on the machine stack
dec hl ; which will be filled by next CALL/PUSH.
ld (ERR_SP), hl ; set the error stack pointer ERR_SP to
; the base of the now empty machine stack.
;
; Now set the I register so that the video hardware knows where to find the
; character set. This ROM only uses the character set when printing to
; the ZX Printer. The TV picture is formed by the external video hardware.
; Consider also, that this 8K ROM can be retro-fitted to the ZX80 instead of
; its original 4K ROM so the video hardware could be on the ZX80.
ld a, $1E ; address for this ROM is $1E00.
ld i, a ; set I register from A.
im 1 ; select Z80 Interrupt Mode 1.
;
ld iy, ERR_NR ; set IY to the start of RAM so that the
; system variables can be indexed.
ld (iy+CDFLAG-IY0), $40 ; set CDFLAG 0100 0000. Bit 6 indicates
; Compute nad Display required.
;
ld hl, PROG ; The first location after System Variables -
; 16509 decimal.
ld (D_FILE), hl ; set system variable D_FILE to this value.
ld b, $19 ; prepare minimal screen of 24 NEWLINEs
; following an initial NEWLINE.
;
;; LINE
LINE:
ld (hl), $76 ; insert NEWLINE (HALT instruction)
inc hl ; point to next location.
djnz LINE ; loop back for all twenty five to LINE
;
ld (VARS), hl ; set system variable VARS to next location
;
call CLEAR ; routine CLEAR sets $80 end-marker and the
; dynamic memory pointers E_LINE, STKBOT and
; STKEND.
;
;; N/L-ONLY
N_L_ONLY:
call CURSOR_IN ; routine CURSOR-IN inserts the cursor and
; end-marker in the Edit Line also setting
; size of lower display to two lines.
;
call SLOW_FAST ; routine SLOW/FAST selects COMPUTE and DISPLAY
;
; ---------------------------
; THE 'BASIC LISTING' SECTION
; ---------------------------
;
;
;; UPPER
UPPER:
call CLS ; routine CLS
ld hl, (E_PPC) ; sv E_PPC_lo
ld de, (S_TOP) ; sv S_TOP_lo
and a ;
sbc hl, de ;
ex de, hl ;
jr nc, ADDR_TOP ; to ADDR-TOP
;
add hl, de ;
ld (S_TOP), hl ; sv S_TOP_lo
;
;; ADDR-TOP
ADDR_TOP:
call LINE_ADDR ; routine LINE-ADDR
jr z, LIST_TOP ; to LIST-TOP
;
ex de, hl ;
;; LIST-TOP
LIST_TOP:
call LIST_PROG ; routine LIST-PROG
dec (iy+BERG-IY0) ; sv BERG
jr nz, LOWER ; to LOWER
;
ld hl, (E_PPC) ; sv E_PPC_lo
call LINE_ADDR ; routine LINE-ADDR
ld hl, (CH_ADD) ; sv CH_ADD_lo
scf ; Set Carry Flag
sbc hl, de ;
ld hl, S_TOP ; sv S_TOP_lo
jr nc, INC_LINE ; to INC-LINE
;
ex de, hl ;
ld a, (hl) ;
inc hl ;
ldi ;
ld (de), a ;
jr UPPER ; to UPPER
;
; ---
;; DOWN-KEY
DOWN_KEY:
ld hl, E_PPC ; sv E_PPC_lo
;
;; INC-LINE
INC_LINE:
ld e, (hl) ;
inc hl ;
ld d, (hl) ;
push hl ;
ex de, hl ;
inc hl ;
call LINE_ADDR ; routine LINE-ADDR
call LINE_NO ; routine LINE-NO
pop hl ;
;; KEY-INPUT
KEY_INPUT:
bit 5, (iy+FLAGX-IY0) ; sv FLAGX
jr nz, LOWER ; forward to LOWER
;
ld (hl), d ;
dec hl ;
ld (hl), e ;
jr UPPER ; to UPPER
;
; ----------------------------
; THE 'EDIT LINE COPY' SECTION
; ----------------------------
; This routine sets the edit line to just the cursor when
; 1) There is not enough memory to edit a BASIC line.
; 2) The edit key is used during input.
; The entry point LOWER
;; EDIT-INP
EDIT_INP:
call CURSOR_IN ; routine CURSOR-IN sets cursor only edit line.
;
; ->
;; LOWER
LOWER:
ld hl, (E_LINE) ; fetch edit line start from E_LINE.
;
;; EACH-CHAR
EACH_CHAR:
ld a, (hl) ; fetch a character from edit line.
cp $7E ; compare to the number marker.
jr nz, END_LINE ; forward if not to END-LINE
;
ld bc, $0006 ; else six invisible bytes to be removed.
call RECLAIM_2 ; routine RECLAIM-2
jr EACH_CHAR ; back to EACH-CHAR
;
; ---
;; END-LINE
END_LINE:
cp $76 ;
inc hl ;
jr nz, EACH_CHAR ; to EACH-CHAR
;
;; EDIT-LINE
EDIT_LINE:
call CURSOR ; routine CURSOR sets cursor K or L.
;
;; EDIT-ROOM
EDIT_ROOM:
call LINE_ENDS ; routine LINE-ENDS
ld hl, (E_LINE) ; sv E_LINE_lo
ld (iy+ERR_NR-IY0), $FF ; sv ERR_NR
call COPY_LINE ; routine COPY-LINE
bit 7, (iy+ERR_NR-IY0) ; sv ERR_NR
jr nz, DISPLAY_6 ; to DISPLAY-6
;
ld a, (DF_SZ) ; sv DF_SZ
cp $18 ;
jr nc, DISPLAY_6 ; to DISPLAY-6
;
inc a ;
ld (DF_SZ), a ; sv DF_SZ
ld b, a ;
ld c, $01 ;
call LOC_ADDR ; routine LOC-ADDR
ld d, h ;
ld e, l ;
ld a, (hl) ;
;; FREE-LINE
FREE_LINE:
dec hl ;
cp (hl) ;
jr nz, FREE_LINE ; to FREE-LINE
;
inc hl ;
ex de, hl ;
ld a, ($4005) ; sv RAMTOP_hi
cp $4D ;
call c, RECLAIM_1 ; routine RECLAIM-1
jr EDIT_ROOM ; to EDIT-ROOM
;
; --------------------------
; THE 'WAIT FOR KEY' SECTION
; --------------------------
;
;
;; DISPLAY-6
DISPLAY_6:
ld hl, START ;
ld (X_PTR), hl ; sv X_PTR_lo
;
ld hl, CDFLAG ; system variable CDFLAG
bit 7, (hl) ;
call z, DISPLAY_1 ; routine DISPLAY-1
;
;; SLOW-DISP
SLOW_DISP:
bit 0, (hl) ;
jr z, SLOW_DISP ; to SLOW-DISP
;
t/data/zx81.asm view on Meta::CPAN
; --------------------------
;
;
;; FUNCTION
FUNCTION:
ld a, e ;
and $07 ;
ld (MODE), a ; sv MODE
jr ENDED_2 ; back to ENDED-2
;
; ------------------------------------
; THE 'COLLECT LINE NUMBER' SUBROUTINE
; ------------------------------------
;
;
;; ZERO-DE
ZERO_DE:
ex de, hl ;
ld de, $04C2 ; $04C2 - a location addressing two zeros.
;
; ->
;; LINE-NO
LINE_NO:
ld a, (hl) ;
and $C0 ;
jr nz, ZERO_DE ; to ZERO-DE
;
ld d, (hl) ;
inc hl ;
ld e, (hl) ;
ret ;
; ----------------------
; THE 'EDIT KEY' ROUTINE
; ----------------------
;
;
;; EDIT-KEY
EDIT_KEY:
call LINE_ENDS ; routine LINE-ENDS clears lower display.
;
ld hl, EDIT_INP ; Address: EDIT-INP
push hl ; ** is pushed as an error looping address.
;
bit 5, (iy+FLAGX-IY0) ; test FLAGX
ret nz ; indirect jump if in input mode
; to L046F, EDIT-INP (begin again).
;
;
ld hl, (E_LINE) ; fetch E_LINE
ld (DF_CC), hl ; and use to update the screen cursor DF_CC
;
; so now RST $10 will print the line numbers to the edit line instead of screen.
; first make sure that no newline/out of screen can occur while sprinting the
; line numbers to the edit line.
ld hl, $1821 ; prepare line 0, column 0.
ld (S_POSN), hl ; update S_POSN with these dummy values.
;
ld hl, (E_PPC) ; fetch current line from E_PPC may be a
; non-existent line e.g. last line deleted.
call LINE_ADDR ; routine LINE-ADDR gets address or that of
; the following line.
call LINE_NO ; routine LINE-NO gets line number if any in DE
; leaving HL pointing at second low byte.
;
ld a, d ; test the line number for zero.
or e ;
ret z ; return if no line number - no program to edit.
;
dec hl ; point to high byte.
call OUT_NO ; routine OUT-NO writes number to edit line.
;
inc hl ; point to length bytes.
ld c, (hl) ; low byte to C.
inc hl ;
ld b, (hl) ; high byte to B.
;
inc hl ; point to first character in line.
ld de, (DF_CC) ; fetch display file cursor DF_CC
;
ld a, $7F ; prepare the cursor character.
ld (de), a ; and insert in edit line.
inc de ; increment intended destination.
;
push hl ; * save start of BASIC.
;
ld hl, $001D ; set an overhead of 29 bytes.
add hl, de ; add in the address of cursor.
add hl, bc ; add the length of the line.
sbc hl, sp ; subtract the stack pointer.
;
pop hl ; * restore pointer to start of BASIC.
;
ret nc ; return if not enough room to L046F EDIT-INP.
; the edit key appears not to work.
;
ldir ; else copy bytes from program to edit line.
; Note. hidden floating point forms are also
; copied to edit line.
;
ex de, hl ; transfer free location pointer to HL
;
pop de ; ** remove address EDIT-INP from stack.
;
call SET_STK_B ; routine SET-STK-B sets STKEND from HL.
;
jr ENDED_2 ; back to ENDED-2 and after 3 more jumps
; to L0472, LOWER.
; Note. The LOWER routine removes the hidden
; floating-point numbers from the edit line.
;
; -------------------------
; THE 'NEWLINE KEY' ROUTINE
; -------------------------
;
;
;; N/L-KEY
N_L_KEY:
call LINE_ENDS ; routine LINE-ENDS
;
ld hl, LOWER ; prepare address: LOWER
;
bit 5, (iy+FLAGX-IY0) ; sv FLAGX
jr nz, NOW_SCAN ; to NOW-SCAN
;
ld hl, (E_LINE) ; sv E_LINE_lo
ld a, (hl) ;
cp $FF ;
jr z, STK_UPPER ; to STK-UPPER
;
call CLEAR_PRB ; routine CLEAR-PRB
call CLS ; routine CLS
;
;; STK-UPPER
STK_UPPER:
ld hl, UPPER ; Address: UPPER
;
;; NOW-SCAN
NOW_SCAN:
push hl ; push routine address (LOWER or UPPER).
call LINE_SCAN ; routine LINE-SCAN
pop hl ;
call CURSOR ; routine CURSOR
t/data/zx81.asm view on Meta::CPAN
rst $10 ; PRINT-A
inc hl ;
inc hl ;
;; COPY-LINE
COPY_LINE:
ld (CH_ADD), hl ; sv CH_ADD_lo
set 0, (iy+FLAGS-IY0) ; sv FLAGS - Suppress leading space
;
;; MORE-LINE
MORE_LINE:
ld bc, (X_PTR) ; sv X_PTR_lo
ld hl, (CH_ADD) ; sv CH_ADD_lo
and a ;
sbc hl, bc ;
jr nz, TEST_NUM ; to TEST-NUM
;
ld a, $B8 ;
rst $10 ; PRINT-A
;
;; TEST-NUM
TEST_NUM:
ld hl, (CH_ADD) ; sv CH_ADD_lo
ld a, (hl) ;
inc hl ;
call NUMBER ; routine NUMBER
ld (CH_ADD), hl ; sv CH_ADD_lo
jr z, MORE_LINE ; to MORE-LINE
;
cp $7F ;
jr z, OUT_CURS ; to OUT-CURS
;
cp $76 ;
jr z, OUT_CH ; to OUT-CH
;
bit 6, a ;
jr z, NOT_TOKEN ; to NOT-TOKEN
;
call TOKENS ; routine TOKENS
jr MORE_LINE ; to MORE-LINE
;
; ---
;; NOT-TOKEN
NOT_TOKEN:
rst $10 ; PRINT-A
jr MORE_LINE ; to MORE-LINE
;
; ---
;; OUT-CURS
OUT_CURS:
ld a, (MODE) ; Fetch value of system variable MODE
ld b, $AB ; Prepare an inverse [F] for function cursor.
;
and a ; Test for zero -
jr nz, FLAGS_2 ; forward if not to FLAGS-2
;
ld a, (FLAGS) ; Fetch system variable FLAGS.
ld b, $B0 ; Prepare an inverse [K] for keyword cursor.
;
;; FLAGS-2
FLAGS_2:
rra ; 00000?00 -> 000000?0
rra ; 000000?0 -> 0000000?
and $01 ; 0000000? 0000000x
;
add a, b ; Possibly [F] -> [G] or [K] -> [L]
;
call PRINT_SP ; routine PRINT-SP prints character
jr MORE_LINE ; back to MORE-LINE
;
; -----------------------
; THE 'NUMBER' SUBROUTINE
; -----------------------
;
;
;; NUMBER
NUMBER:
cp $7E ;
ret nz ;
inc hl ;
inc hl ;
inc hl ;
inc hl ;
inc hl ;
ret ;
; --------------------------------
; THE 'KEYBOARD DECODE' SUBROUTINE
; --------------------------------
;
;
;; DECODE
DECODE:
ld d, $00 ;
sra b ;
sbc a, a ;
or $26 ;
ld l, $05 ;
sub l ;
;; KEY-LINE
KEY_LINE:
add a, l ;
scf ; Set Carry Flag
rr c ;
jr c, KEY_LINE ; to KEY-LINE
;
inc c ;
ret nz ;
ld c, b ;
dec l ;
ld l, $01 ;
t/data/zx81.asm view on Meta::CPAN
RESERVE:
ld hl, (STKBOT) ; address STKBOT
dec hl ; now last byte of workspace
call MAKE_ROOM ; routine MAKE-ROOM
inc hl ;
inc hl ;
pop bc ;
ld (E_LINE), bc ; sv E_LINE_lo
pop bc ;
ex de, hl ;
inc hl ;
ret ;
; ---------------------------
; THE 'CLEAR' COMMAND ROUTINE
; ---------------------------
;
;
;; CLEAR
CLEAR:
ld hl, (VARS) ; sv VARS_lo
ld (hl), $80 ;
inc hl ;
ld (E_LINE), hl ; sv E_LINE_lo
;
; -----------------------
; THE 'X-TEMP' SUBROUTINE
; -----------------------
;
;
;; X-TEMP
X_TEMP:
ld hl, (E_LINE) ; sv E_LINE_lo
;
; ----------------------
; THE 'SET-STK' ROUTINES
; ----------------------
;
;
;; SET-STK-B
SET_STK_B:
ld (STKBOT), hl ; sv STKBOT
;
;
;; SET-STK-E
SET_STK_E:
ld (STKEND), hl ; sv STKEND
ret ;
; -----------------------
; THE 'CURSOR-IN' ROUTINE
; -----------------------
; This routine is called to set the edit line to the minimum cursor/newline
; and to set STKEND, the start of free space, at the next position.
;; CURSOR-IN
CURSOR_IN:
ld hl, (E_LINE) ; fetch start of edit line from E_LINE
ld (hl), $7F ; insert cursor character
;
inc hl ; point to next location.
ld (hl), $76 ; insert NEWLINE character
inc hl ; point to next free location.
;
ld (iy+DF_SZ-IY0), $02 ; set lower screen display file size DF_SZ
;
jr SET_STK_B ; exit via SET-STK-B above
;
; ------------------------
; THE 'SET-MIN' SUBROUTINE
; ------------------------
;
;
;; SET-MIN
SET_MIN:
ld hl, MEMBOT ; normal location of calculator's memory area
ld (MEM), hl ; update system variable MEM
ld hl, (STKBOT) ; fetch STKBOT
jr SET_STK_E ; back to SET-STK-E
;
;
; ------------------------------------
; THE 'RECLAIM THE END-MARKER' ROUTINE
; ------------------------------------
;; REC-V80
REC_V80:
ld de, (E_LINE) ; sv E_LINE_lo
jp RECLAIM_1 ; to RECLAIM-1
;
; ----------------------
; THE 'ALPHA' SUBROUTINE
; ----------------------
;; ALPHA
ALPHA:
cp $26 ;
jr ALPHA_2 ; skip forward to ALPHA-2
;
;
; -------------------------
; THE 'ALPHANUM' SUBROUTINE
; -------------------------
;; ALPHANUM
ALPHANUM:
cp $1C ;
;; ALPHA-2
ALPHA_2:
( run in 2.550 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )