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 ; ---