ZX81 Assembly Listing for circles.asm


ZX81 assembly listing for **CIRCLES**SLR/2022**

**CIRCLES**SLR/2022** (circles.asm)

A fun little screen saver that prints a bunch circles.


ASSEMBLY PROGRAM LISTING

;
; Circles
; v1.04 Steven Reid (c) 2022
; Converting a simple BASIC circle routine to assembler and
; then making it do something interesting.
;

; +++
;
; Header and startup
;

        ; start up stuff
        org 16514               ; stored in REM at top (ZX81)
        jr start                ; needed for z80asm

; title and copyright (will show on listing)
copy:
        db _as,_as,_c_,_i_,_r_,_c_,_l_,_e_,_s_,_as
        db _as,_s_,_l_,_r_,_sl,_2_,_0_,_2_,_2_,_as
        db _as,$76  ; **CIRCLES**SLR/2022**

start:
        call slow               ; SLOW is required.
        call cls                ; clear screen / exapnd screen
        call ichroma            ; is chroma installed?

; end header and startup
;
; ---

; +++
;
; Main Loop
;

mainloop:
        ld b,10                 ; loop variable
circle_loop:
        push bc

        ; get circle color
        ld d,15                 ; color range (skipping white)
        call rnd                ; returns from 1-15
        dec a                   ; make it 0-14
        add a,240               ; white background
        ld (color),a            ; save color


        ; get random location and radius
        ld d,64                 ; x can be from 0 to 63
        call rnd                ; returns a from 1 to 64
        dec a                   ; make from 0 to 63
        ld b,a                  ; save x in b

        ld d,45                 ; y can be from 0 to 45
        call rnd                ; returns a from 1 to 46
        dec a                   ; make from 0 to 45
        ld c,a                  ; save y in c

        ld d,21                 ; range size (max = 22)
        call rnd                ; returns a from 1 to 21
        inc a                   ; make range from 2 to 22
        ; a is set to range
        call Draw_Circle

        ld hl,150               ; short pause
        call newpause

        pop bc
        djnz circle_loop        ; not done yet!

        ld hl,300               ; longer pause
        call newpause
        call fastcls            ; clear sreen

        jp mainloop             ; start again!

; End of loop!
;

; +++
;
; Routines
;

; get absolute value of A

absA:
        or a
        ret p
        neg
        ret

; ---
; Draw_Circle
;       moving the circle into a routine
;       paramters:
;               bc = x,y coords (center)
;               a = radius
;       variables:
;               x, y
;               x1, y1
;               p
;               py
;               pxy

;variables

x_var:  db 0
y_var:  db 0

p_var:          db 0
y1_var:         db 0
x1_var:         db 0

Draw_Circle:
        ; save x, y
        ld hl,x_var
        ld (hl),b
        inc hl
        ld (hl),c

        ; set p and y1 to zero
        ld (x1_var),a   ; set x1 to r
        xor a
        ld (p_var),a    ; set p to 0
        ld (y1_var),a   ; set y1 to 0

plot_loop:
        ; Plot the coordinates in each sector
        ; X+X1,Y+Y1
        ld hl,(y1_var)   ; x1 in h, y1 in l

        ld a,(x_var)
        add a,h         ; x+x1
        ld b,a

        ld a,(y_var)
        add a,l         ; y+y1
        ld c,a

        call zxplot
        call setcolor

        ; X-X1,Y+Y1
        ld hl,(y1_var)   ; x1 in h, y1 in l

        ld a,(x_var)
        sub h         ; x+x1
        ld b,a

        ld a,(y_var)
        add a,l         ; y+y1
        ld c,a

        call zxplot
        call setcolor

        ; X+X1,Y-Y1
        ld hl,(y1_var)   ; x1 in h, y1 in l

        ld a,(x_var)
        add a,h         ; x+x1
        ld b,a

        ld a,(y_var)
        sub l         ; y-y1
        ld c,a

        call zxplot
        call setcolor

        ; X-X1,Y-Y1
        ld hl,(y1_var)   ; x1 in h, y1 in l

        ld a,(x_var)
        sub h         ; x-x1
        ld b,a

        ld a,(y_var)
        sub l         ; y-y1
        ld c,a

        call zxplot
        call setcolor

        ; X+Y1,Y+X1
        ld hl,(y1_var)   ; x1 in h, y1 in l

        ld a,(x_var)
        add a,l         ; x+y1
        ld b,a

        ld a,(y_var)
        add a,h         ; y+x1
        ld c,a

        call zxplot
        call setcolor

        ; X-Y1,Y+X1
        ld hl,(y1_var)   ; x1 in h, y1 in l

        ld a,(x_var)
        sub l         ; x-y1
        ld b,a

        ld a,(y_var)
        add a,h         ; y+x1
        ld c,a

        call zxplot
        call setcolor

        ; X+Y1,Y-X1
        ld hl,(y1_var)   ; x1 in h, y1 in l

        ld a,(x_var)
        add a,l         ; x+y1
        ld b,a

        ld a,(y_var)
        sub h         ; y-x1
        ld c,a

        call zxplot
        call setcolor

        ; X-Y1,Y-X1
        ld hl,(y1_var)   ; x1 in h, y1 in l

        ld a,(x_var)
        sub l         ; x-y1
        ld b,a

        ld a,(y_var)
        sub h         ; y-x1
        ld c,a

        call zxplot
        call setcolor

        ; calculate changes
        ld hl,(y1_var)   ; x1 in h, y1 in l
        ; PY=P+Y1+Y1+1
        ld a,(p_var)
        inc a
        add a,l
        add a,l
        ld b,a          ; save py into b
        ld (p_var),a    ; save py for later
        ; PXY=PY-X1-X1+1
        inc a
        sub h
        sub h
        ld c,a          ; save pxy into c

        ld hl,y1_var    ; y1=y1+1
        inc (hl)

        ; okay, test if we need to change position
        ld a,b          ; set a to py
        call absA
        ld b,a          ; b now holds abs py
        ld a,c          ; set a to pxy
        call absA       ; a is now abs pxy
        cp b            ; check if abs pxy >= abs py
        jp nc,skipahead ; no carry if true


        ld a,c          ; set a to pxy
        ld (p_var),a    ; and store in p!

        ld hl,x1_var    ; x1=x1-1
        dec (hl)

skipahead:
        ld hl,(y1_var)  ; x1 in h, y1 in l
        ld a,h          ; a is now x1
        cp l            ; is x1>=y1?
        ret c           ; if no we are all done, return!
        jp plot_loop    ; it is, then we keep going!

; end Draw_Circle
; ---

; +++
; ZXPlot
        ;alter pixel nominated by plotx and ploty
        ;plotmodes are flag2 bit 1. 0 = plot, 1 = unplot
        ;x can be 0 to 63
        ;y can be 0 to 45
;       my rewrite to see if I can optimize, improve speed
flag2:  db 0

zxplot:
        ; bc = x,y coords
        ; d = plotsector
        ; hl = plot_origin

        ; work out what square on the screen the pixel appears at
        ld a,b          ; ld a with x
        bit 7,a
        ret nz          ; out of bounds
        sub 64
        ret p           ; out of bounds

        ld a,c          ; ld a with y
        bit 7,a
        ret nz          ; out of bounds
        sub 46
        ret p           ; out of bounds

        ld d,0          ; set plotsector to 0

        ld a,b          ; ld a with x
        srl a
        ld b,a          ; save new x
        jr nc,pixelleft
        ld d,1          ; pixel is in right half

pixelleft:
        ld a,c          ; ld a with y
        srl a
        ld c,a          ; save new y
        jr nc,pixelup
        ld a,d          ; load a with plot sector
        set 1,a
        ld d,a          ; pixel is in lower half

pixelup:
        ;now find the correct screen position

        push de         ; save plotsector

        ld hl,(d_file)
        inc hl
        ld a,c          ; load a wity y
        or a            ; cp 0
        jr z,findx      ; already at y,skip
        ld de,33
findy:
        add hl,de
        dec a
        jr nz, findy

findx:
        ld de,$00
        ld e,b          ; load e with x
        add hl,de

        pop de          ; restore plotsector

        ; hl holds plot_orgin!

; are we plotting or unplotting?
        ld a,(flag2)    ; grab flag (plot or unplot)
        bit 1,a
        jp nz,unplot_pixel

plot_pixel:
; plot the pixel in the co-ord from plot_origin (square on screen) and
; plotsector (actual pixel)
;   0= top left, 1 = top right, 2 = bottom left, 3 = bottom right

        ld a,d          ; ld a with plotsector
        or a            ; cp 0
        jr z,plottl
        dec a           ; cp 1
        jr z,plottr
        dec a           ; cp 2
        jr z,plotbl

        ;bottom right quadrant
        ld a,(hl)
        bit 7,a   ;collision detect
        ret nz
        set 7,a
        xor $07 ;invert all other bits
        ld (hl),a
        ret  ; plot pixel

plottl: ;top left quadrant
        ld a,(hl)
        bit 7,a
        jr nz,tlinvert
        set 0,a
        ld (hl),a
        ret

tlinvert:
        res 0,a
        ld (hl),a
        ret

plottr: ;top right quadrant
        ld a,(hl)
        bit 7,a
        jr nz,trinvert
        set 1,a
        ld (hl),a
        ret

trinvert:
        res 1,a
        ld (hl),a
        ret

plotbl: ;bottom left quadrant
        ld a,(hl)
        bit 7,a
        jr nz,blinvert
        set 2,a
        ld (hl),a
        ret

blinvert:
        res 2,a
        ld (hl),a
        ret

unplot_pixel:
        ; unplot the pixel in the co-ord from plot_origin (square on screen) and
        ; plotsector (actual pixel)
        ;  0= top left, 1 = top right, 2 = bottom left, 3 = bottom right

        ld a,d          ; ld a with plotsector
        or a            ; cp 0
        jr z,uplottl
        dec a           ; cp 1
        jr z,uplottr
        dec a           ; cp 2
        jr z,uplotbl

        ;bottom right quadrant
        ld a,(hl)
        bit 7,a
        ret z
        res 7,a
        xor $07 ;invert all other bits
        ld (hl),a
        ret ;unplot pixel

uplottl: ;top left quadrant
        ld a,(hl)
        bit 7,a
        jr nz,utlinvert
        res 0,a
        ld (hl),a
        ret

utlinvert:
        set 0,a
        ld (hl),a
        ret

uplottr: ;top right quadrant
        ld a,(hl)
        bit 7,a
        jr nz,utrinvert
        res 1,a
        ld (hl),a
        ret

utrinvert:
        set 1,a
        ld (hl),a
        ret


uplotbl: ;bottom left quadrant
        ld a,(hl)
        bit 7,a
        jr nz,ublinvert
        res 2,a
        ld (hl),a
        ret

ublinvert:
        set 2,a
        ld (hl),a
        ret

; end zxplot
; ---

; Print string at HL
; stops when reaches $FF
;
print:
        ld a,(hl)               ; load character
        inc hl                  ; increment memory
        cp $ff                  ; last character?
        ret z                   ; yep, return
        rst $10                 ; nope, print it!
        jr print                ; loop

;
; Delay
;
; set bc to speed
; press space to 

pframe: dw $0000
newpause:
        ld (pframe),hl

        call kscan              ; get key press
        inc l
        jr z,lppause            ; not yet loop
        dec l
        ld b,h
        ld c,l
        call findchar           ; yep, grab character pressed
        ld a,(hl)
        and a                   ; pressed space (break or 0)?
        jr nz,lppause           ; not yet loop

        call wait               ; make sure user has let go of key
        call resetchroma        ; clear chroma settings!
        jp stop                 ; stop!

        ; loop!
lppause:
        ld hl,(pframe)
        dec hl
        ld a,h
        or l
        jr nz,newpause          ; not zero, keep going!

        ret                     ; pause is done!

wait:   call kscan              ; Wait for human to take finger off of key.
        inc l
        jr nz,wait
        ret

; +++
;
; Random
;
;       Returns a random number between 1 and range value (a)
;
; in:           d       = range value (high)
; out:          a       = a number between 1 and range value
; preserves:    de, bc (d is range)
; destroys:     af, hl
;
rnd:    ; default routine
        ; shorter, faster random!
        ld a,r                  ; Load the A register with the refresh register
        ld l,a                  ; Copy register A into register L
        and $0f                 ; This masking prevents the address we are forming from accessing RAM
        ld h,a                  ; Copy register A into register H

	ld a,(hl)		; get value in ROM
rrange:	sub d			; we need 0-rval only
	jr nc,rrange            ; repeat unitl within range of value
	adc a,d		        ; undo last subtraction, range 1-rval
	ret			; back to mainprogram

; end random
;
; ---

; +++
;
; Fast CLS
;       
; in:           none
; out:          none
; preserves:    none
; destroys:     bc
;
fastcls:
        ld hl,(d_file)
        inc hl
        xor a
        ld c,24         ; rows
fastcls_y_loop:
        ld b,32         ; columns
fastcls_x_loop:
        ld (hl),a       ; clear character
        inc hl
        djnz fastcls_x_loop

        inc hl          ; move past return

        dec c
        jr nz,fastcls_y_loop

        ret

; end fast cls
;
; ---

; +++
;
; In Chroma
;
; in:           nothing
; out:          colors enabled
; preserves:    hl,e
; destroys:     af, bc
;

; pheripherals
achroma:        db $ff
;+---+---+---+---+---+---+---+---+
;| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
;+---+---+---+---+---+---+---+---+
;  |   |   |   |   |   |   |   |
;  |   |   |   |   |   +---+---+-------- Ink colour (format: GRB).
;  |   |   |   |   +-------------------- Ink colour bright bit.
;  |   +---+---+------------------------ Paper colour (format: GRB).
;  +------------------------------------ Paper colour bright bit.
; blue     = 1001-9, red   = 1010-a, green    = 1100-c
; yellow   = 1110-e, cyan  = 1101-d, purple   = 1011-b
; white    = 1111-f, black = 1000-8
; dkblue   = 0001-1, dkred = 0010-2, dkgreen  = 0100-4
; dkyellow = 0110-6, teal  = 0101-5, dkpurple = 0011-3
; gray     = 0111-7, black = 0000-0


; add in chroma colors!
ichroma:
        ld bc,$7fef             ; Chroma port.
        in a,(c)
        ld (achroma),a          ; Save port contents.
        and $20
        ret nz                  ; Check if Chroma is available.

        ld a,$3f                ; Use attributes file and black border.
        out (c),a

        ld hl,(d_file)          ; Initialize the attributes file.
        ld b,24                 ; note 24 rows, includes input lines
cloop:  inc hl
        ld a,(hl)
        cp $76                  ; check if end of line
        set 7,h                 ; change page file
        ld (hl),$ff             ; white on white
        res 7,h                 ; reset page file
        jr nz,cloop             ; not end of line, skip
        djnz cloop

        ret

; end ichroma
;
; ---

; +++
;
; Reset Chroma
;
; in:           nothing
; out:          screen colors reset
; preserves:    hl,de
; destroys:     af, bc
;

resetchroma:
        ld bc,07fefh            ;Go back to B/W.
        in a,(c)
        and 20h
        ret nz
        xor a
        out (c),a
        ld a,$ff
        ld (achroma),a
        ret

; end chroma routines
;
; ---

; +++
;
; Set Chroma
;
color: db 9
setcolor:
        ld a,(achroma)          ; do we add color?
        and 20h
        ret nz                  ; no chroma, return
        ld a,(color)

        set 7,h
        ld (hl),a               ; set drop color

        ret

; end set chroma
;
; ---

; +++
;
; Data and Defines
;

; ZX81 system vars
d_file:         equ $400c
d_fcc:          equ 16398
frames:         equ 16436

; ZX81 ROM functions
kscan:          equ $02bb
findchar:       equ $07bd
stop:           equ $0cdc
slow:           equ $0f2b
fast:           equ $02e7
save:           equ $02f9
printat:        equ $08f5
pause:          equ $0f35
cls:            equ $0a2a

; ZX81 Characters (not ASCII)
_sp:            equ $00
_qu:            equ $0b
_lb:            equ $0c
_dl:            equ $0d
_cl:            equ $0e
_lp:            equ $10
_rp:            equ $11
_gt:            equ $12
_lt:            equ $13
_eq:            equ $14
_pl:            equ $15
_mi:            equ $16
_as:            equ $17
_sl:            equ $18
_sc:            equ $19
_cm:            equ $1a
_pr:            equ $1b
_0_:            equ $1c
_1_:            equ $1d
_2_:            equ $1e
_3_:            equ $1f
_4_:            equ $20
_5_:            equ $21
_6_:            equ $22
_7_:            equ $23
_8_:            equ $24
_9_:            equ $25
_a_:            equ $26
_b_:            equ $27
_c_:            equ $28
_d_:            equ $29
_e_:            equ $2a
_f_:            equ $2b
_g_:            equ $2c
_h_:            equ $2d
_i_:            equ $2e
_j_:            equ $2f
_k_:            equ $30
_l_:            equ $31
_m_:            equ $32
_n_:            equ $33
_o_:            equ $34
_p_:            equ $35
_q_:            equ $36
_r_:            equ $37
_s_:            equ $38
_t_:            equ $39
_u_:            equ $3a
_v_:            equ $3b
_w_:            equ $3c
_x_:            equ $3d
_y_:            equ $3e
_z_:            equ $3f

; end defines
; ---