Page 1 of 1

Stable frame timing for Albert

Posted: Mon Nov 04, 2019 3:24 pm
by sirmorris
I was irritated, very much like an oyster with a bit of sand in its shell, by the fact that I didn't have a stable vsync to lock my game to. In practice it didn't really matter as the game feels fine for the most part, but I can tell - it does feel like there's a little bit of grit in the gears from time to time.

So just as an oyster makes a pearl by depositing a layer of mother-of-pearl around the aforementioned grain of sand, so I .. err, wrote some code.

It's real simple but effective. Set up a timer interrupt to fire at just under the frame rate, which is almost 20 milliseconds, or 50 times per second. Inside the timer interrupt busy-wait for the VDP's vsync bit to get set. Reset the timer. Repeat ad nauseum.

It might be possible to find a timer combination to exactly match the vsync, in which case we wouldn't need to reset the timer, but in practice I suspect there'd be a slight drift which could have consequences. So resetting the timer it is!

Anyway - here it is. Have fun! :ugeek:

Code: Select all

; tight vsync demo
;
; assemble with BRASS - http://www.benryves.com/bin/brass/
;
; tabs = 4

VDP_DATA		.equ $08	; read/write data
VDP_REG			.equ $09	; write/address
VDP_STAT		.equ $09	; read

CTC_TMR2		.equ $2a
CTC_TMR3		.equ $2b

COL_BLACK		.equ $01
COL_DBLUE		.equ $04

; time constants to give us a 19.9 millisecond timer period
TC2				.equ 92
TC3				.equ 54


	.org	$100


	ld		sp,$7fff

	di

	ld		hl,_irqhandler		; install own handler over the system's timer3 vector
	ld		($fb06),hl

	ld		a,$1f				; disable interrupt + timer mode + prescaler 16 + rising edge + clk starts + time constant follows + reset + control
	out		(CTC_TMR2),a		; ctc channel 2 write timer config
	ld		a,TC2
	out		(CTC_TMR2),a		; write time constant

	ld		a,$df				; enable interrupt + counter mode + (n/a) + rising edge + clk starts + time constant follows + reset + control
	out		(CTC_TMR3),a		; ctc channel 3 write timer config
	ld		a,TC3
	out		(CTC_TMR3),a		; write time constant

	ei

	; awaaay we go.

	; result should be thin blue line. the line starts at the time the
	; timer irq fires, and ends when vsync bit is set in VDP.

	; the aim is to tighten the timer such that absolute minimum of time
	; is wasted waiting for the vblank.

	jr		$


_irqhandler:
	di
	exx							; doesn't save AF. ask me how i know.
	push	af

	ld		a,COL_DBLUE			; set border blue
	out		(VDP_REG),a
	ld		a,$87
	out		(VDP_REG),a

-:	in		a,(VDP_STAT)		; wait for VDP VSYNC bit
	rla
	jr		nc,{-}

	ld		a,COL_BLACK			; set order black
	out		(VDP_REG),a
	ld		a,$87
	out		(VDP_REG),a

	; if we had a stable timer config that didn't drift then
	; we wouldn't need to reset the timer. but life's too short
	; to wast finding one :D so...
	;
	; reset timer to fire in 19.9 milliseconds time
	; (92*16)*54 = 79488 / 4000000 = 0.0199 sec

	ld		a,$1f
	out		(CTC_TMR2),a
	ld		a,TC2
	out		(CTC_TMR2),a

	ld		a,$df
	out		(CTC_TMR3),a
	ld		a,TC3
	out		(CTC_TMR3),a

	pop		af
	exx
	ei
	reti

Re: Stable frame timing for Albert

Posted: Thu Apr 29, 2021 10:00 pm
by gunrock
Nice solution.

Did they fix the "VDP INT pin unconnected" in the design of the 256?

I've looked at the schematic and it seems to be connected to the gate array IC numbered I006, on pin 77, but what that is comnected to as an output, I have no clue (schematics aren't my forte). I see that KYBDINT feeds the same gate array and is connected to the CTC, but can't be sure how/where this I006 gate array routes it out (if at all).