This made me think how to solve this.
On a ZX Spectrum you could do a HALT and then do the drawing before
a next intrupt would occur.
How can this be done on a ZX81?
At first I needed a small program that would give flickers when altering display.
For this test I simply erased a "A" and placed the "A" after some delay.
This was done with all "A"'s on the screen. The result: Flickering "A"'s
Test program is working.
Code: Select all
; Flicker free
org #4009
eoscr equ vars
; in LOWRES more sysvar are used, but in this way the shortest code
; over sysvar to start machinecode. This saves 11 bytes of BASIC
; DO NOT CHANGE AFTER BASIC+3 (=DFILE)
basic ld h,dfile/256 ; highbyte of dfile
jr init1
db 236 ; BASIC over DFILE data
db 212,28 ; GOTO USR 0
db 126,143,0,18 ; short FP notation for #8009, no NEWLINE for BASIC
eline dw last
chadd dw last-1
db 0,0,0,0,0,0 ; x
berg db 0 ; x
mem db 0,0 ; x OVERWRITTEN ON LOAD
init1 ld l, dfile mod 256 ; low byte of dfile
jr init2
lastk db 255,255,255
margin db 55
nxtlin dw basic ; BASIC-line over sysvar
flagx equ init2+2
init2 ld (basic+3),hl ; repair correct DFILE flagx will be set with 64, the correct value
ld h,eoscr/256
db 0,0 ; x used by ZX81, not effective code after loading
ld l,eoscr mod 256
frames db #37
db #e9 ; set a end of screen marker
jp init ; initroutine in screenmemory
dw 0
cdflag db 64
; DO NOT CHANGE SYSVAR ABOVE UNLESS YOU KNOW WHAT YOU DO
init ld de,dfile+1
wrch xor a ; erase A
ld (de),a
ld b,20 ; some delay
lp djnz lp
ld a,38
ld (de),a ; write A
sklf inc de ; do full screen
ld a,(de)
cp #76
jr z,sklf
cp #e9
jr nz,wrch
jr init
; the display file, Code the lines needed.
dfile db 118
; each needed line has text and a Newline
block 32,38
db #76
block 32,38
db #76
block 32,38
db #76
block 32,38
db #76
block 32,38
db #76
block 32,38
db #76
block 32,38
db #76
block 32,38
db #76
; vars becomes EOSCR with JP (HL)
vars db 128
last equ $
end
Now I needed a way to test when a screenupdate will occur.
This is held in A'. I was suspecting that reading A' could cause
a screen updata not to occur, so I tested it.
Code: Select all
init ld de,dfile+1
wrch ex af,af' ; read screendelay
ld c,a ; save counter
ex af,af' ; back to main
ld a,253
cp c ; test enough time to update a character
jr c,sklf ; if not wait until intrupt is done
xor a
ld (de),a
ld b,20
lp djnz lp
ld a,38
ld (de),a
sklf inc de
ld a,(de)
cp #76
jr z,sklf
cp #e9
jr nz,wrch
jr init
intrupts occur when I was reading A'. The full screen was no longer fixed but moved a bit.
I had to find a way to safely read A' without the change that an intrupt would occur.
This can be done by checking the last value that is pushed on the stack
Code: Select all
init ld de,dfile+1
wrch ld h,0 ; stack 0 for A
push hl
pop hl ; First free value on stack holds 0
ch2 dec sp ; fake a register on the stack
dec sp
pop af ; get last register pushed on the stack
or a ; test if it is 0 from above
jr z,ch2 ; while 0, no intrupt has occurred
ex af,af' ; we are just behind an intrupt so it is
ld c,a ; now safe to read A'
ex af,af'
ld a,253
cp c
jr c,sklf
xor a
ld (de),a
ld b,20
lp djnz lp
ld a,38
ld (de),a
sklf inc de
ld a,(de)
cp #76
jr z,sklf
cp #e9
jr nz,wrch
jr init
This code will produce a flickerfree screen when updating characters.
You can use it for lowres and hires screens. When your updating of
a character is still flickering then you must decrease the 253 in a lower value.
This will give you more time for your update. Just remember that the more time
your routine needs the less changes can be done between screenupdates.
Only 18 bytes to make your game flickerfree.
It can be done in 16 with A and A' only
Code: Select all
wrch xor a ; stack 0 for A
push af
pop af ; First free value on stack holds 0
ch2 dec sp ; fake a register on the stack
dec sp
pop af ; get last register pushed on the stack
or a ; test if it is 0 from above
jr z,ch2 ; while 0, no intrupt has occurred
ex af,af' ; we are just behind an intrupt so it is
cp 253
jr nc,sklf-1
ex af,af'
; erase and set
db 62 ; skip EX AF,AF' from above JR'
ex af,af'
sklf