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 )