A fun little screen saver that prints a bunch circles.
;
; 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
; ---