CPU-Z80-Disassembler
view release on metacpan or search on metacpan
t/data/zx81.asm view on Meta::CPAN
;
; --------------------
; 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
; when line count has incremented to zero.
;
; Note. the synchronizing NMI when A increments from zero to one takes this
; 7 clock cycle route making 39 clock cycles in all.
;; NMI-RET
NMI_RET:
ex af, af' ; (4) switch out the incremented line counter
; or test result $80
ret ; (10) return to User application for a while.
;
; ---
; This branch is taken when the 55 (or 31) lines have been drawn.
;; NMI-CONT
NMI_CONT:
ex af, af' ; (4) restore the main accumulator.
;
push af ; (11) * Save Main Registers
push bc ; (11) **
push de ; (11) ***
push hl ; (11) ****
;
; the next set-up procedure is only really applicable when the top set of
; blank lines have been generated.
ld hl, (D_FILE) ; (16) fetch start of Display File from D_FILE
; points to the HALT at beginning.
set 7, h ; (8) point to upper 32K 'echo display file'
;
halt ; (1) HALT synchronizes with NMI.
; Used with special hardware connected to the
; Z80 HALT and WAIT lines to take 1 clock cycle.
;
; ----------------------------------------------------------------------------
; the NMI has been generated - start counting. The cathode ray is at the RH
; side of the TV.
; First the NMI servicing, similar to CALL = 17 clock cycles.
; Then the time taken by the NMI for zero-to-one path = 39 cycles
; The HALT above = 01 cycles.
; The two instructions below = 19 cycles.
; The code at L0281 up to and including the CALL = 43 cycles.
; The Called routine at L02B5 = 24 cycles.
; -------------------------------------- ---
; Total Z80 instructions = 143 cycles.
;
; Meanwhile in TV world,
; Horizontal retrace = 15 cycles.
; Left blanking border 8 character positions = 32 cycles
; Generation of 75% scanline from the first NEWLINE = 96 cycles
; --------------------------------------- ---
; 143 cycles
;
; Since at the time the first JP (HL) is encountered to execute the echo
; display another 8 character positions have to be put out, then the
; Refresh register need to hold $F8. Working back and counteracting
; the fact that every instruction increments the Refresh register then
; the value that is loaded into R needs to be $F5. :-)
;
;
out ($FD), a ; (11) Stop the NMI generator.
;
jp (ix) ; (8) forward to L0281 (after top) or L028F
;
; ****************
; ** KEY TABLES **
; ****************
; -------------------------------
; THE 'UNSHIFTED' CHARACTER CODES
; -------------------------------
;; K-UNSHIFT
K_UNSHIFT:
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
t/data/zx81.asm view on Meta::CPAN
; ---
;; NO-SLOW
NO_SLOW:
res 6, (hl) ; reset bit 6 of CDFLAG.
ret ; return.
;
; -----------------------
; THE 'MAIN DISPLAY' LOOP
; -----------------------
; This routine is executed once for every frame displayed.
;; DISPLAY-1
DISPLAY_1:
ld hl, (FRAMES) ; fetch two-byte system variable FRAMES.
dec hl ; decrement frames counter.
;
;; DISPLAY-P
DISPLAY_P:
ld a, $7F ; prepare a mask
and h ; pick up bits 6-0 of H.
or l ; and any bits of L.
ld a, h ; reload A with all bits of H for PAUSE test.
;
; Note both branches must take the same time.
jr nz, ANOTHER ; (12/7) forward if bits 14-0 are not zero
; to ANOTHER
;
rla ; (4) test bit 15 of FRAMES.
jr OVER_NC ; (12) forward with result to OVER-NC
;
; ---
;; ANOTHER
ANOTHER:
ld b, (hl) ; (7) Note. Harmless Nonsensical Timing weight.
scf ; (4) Set Carry Flag.
;
; Note. the branch to here takes either (12)(7)(4) cyles or (7)(4)(12) cycles.
;; OVER-NC
OVER_NC:
ld h, a ; (4) set H to zero
ld (FRAMES), hl ; (16) update system variable FRAMES
ret nc ; (11/5) return if FRAMES is in use by PAUSE
; command.
;
;; DISPLAY-2
DISPLAY_2:
call KEYBOARD ; routine KEYBOARD gets the key row in H and
; the column in L. Reading the ports also starts
; the TV frame synchronization pulse. (VSYNC)
;
ld bc, (LAST_K) ; fetch the last key values read from LAST_K
ld (LAST_K), hl ; update LAST_K with new values.
;
ld a, b ; load A with previous column - will be $FF if
; there was no key.
add a, $02 ; adding two will set carry if no previous key.
;
sbc hl, bc ; subtract with the carry the two key values.
;
; If the same key value has been returned twice then HL will be zero.
ld a, (DB_ST) ; fetch system variable DEBOUNCE
or h ; and OR with both bytes of the difference
or l ; setting the zero flag for the upcoming branch.
;
ld e, b ; transfer the column value to E
ld b, $0B ; and load B with eleven
;
ld hl, CDFLAG ; address system variable CDFLAG
res 0, (hl) ; reset the rightmost bit of CDFLAG
jr nz, NO_KEY ; skip forward if debounce/diff >0 to NO-KEY
;
bit 7, (hl) ; test compute and display bit of CDFLAG
set 0, (hl) ; set the rightmost bit of CDFLAG.
ret z ; return if bit 7 indicated fast mode.
;
dec b ; (4) decrement the counter.
nop ; (4) Timing - 4 clock cycles. ??
scf ; (4) Set Carry Flag
;
;; NO-KEY
NO_KEY:
ld hl, DB_ST ; sv DEBOUNCE
ccf ; Complement Carry Flag
rl b ; rotate left B picking up carry
; C<-76543210<-C
;
;; LOOP-B
LOOP_B:
djnz LOOP_B ; self-loop while B>0 to LOOP-B
;
ld b, (hl) ; fetch value of DEBOUNCE to B
ld a, e ; transfer column value
cp $FE ;
sbc a, a ;
ld b, $1F ;
or (hl) ;
and b ;
rra ;
ld (hl), a ;
out ($FF), a ; end the TV frame synchronization pulse.
;
ld hl, (D_FILE) ; (12) set HL to the Display File from D_FILE
set 7, h ; (8) set bit 15 to address the echo display.
;
call DISPLAY_3 ; (17) routine DISPLAY-3 displays the top set
; of blank lines.
;
; ---------------------
; THE 'VIDEO-1' ROUTINE
; ---------------------
;; R-IX-1
R_IX_1:
ld a, r ; (9) Harmless Nonsensical Timing or something
; very clever?
ld bc, $1901 ; (10) 25 lines, 1 scanline in first.
ld a, $F5 ; (7) This value will be loaded into R and
; ensures that the cycle starts at the right
; part of the display - after 32nd character
; position.
;
call DISPLAY_5 ; (17) routine DISPLAY-5 completes the current
; blank line and then generates the display of
; the live picture using INT interrupts
; The final interrupt returns to the next
; address.
;
dec hl ; point HL to the last NEWLINE/HALT.
;
call DISPLAY_3 ; routine DISPLAY-3 displays the bottom set of
; blank lines.
;
; ---
;; R-IX-2
R_IX_2:
jp DISPLAY_1 ; JUMP back to DISPLAY-1
;
; ---------------------------------
; THE 'DISPLAY BLANK LINES' ROUTINE
; ---------------------------------
; This subroutine is called twice (see above) to generate first the blank
; lines at the top of the television display and then the blank lines at the
; bottom of the display.
;; DISPLAY-3
DISPLAY_3:
pop ix ; pop the return address to IX register.
; will be either L0281 or L028F - see above.
;
ld c, (iy+MARGIN-IY0) ; load C with value of system constant MARGIN.
bit 7, (iy+CDFLAG-IY0) ; test CDFLAG for compute and display.
jr z, DISPLAY_4 ; forward, with FAST mode, to DISPLAY-4
;
ld a, c ; move MARGIN to A - 31d or 55d.
neg ; Negate
( run in 1.703 second using v1.01-cache-2.11-cpan-39bf76dae61 )