;zen.i
;The Amiga Zen Timer
;Copyright (c) 1990 by Dan Babcock

;ZTimerOn macro starts timing
;ZTimerOff macro ends timing
;ZTimerReport subroutine prints the results

;Note: One color clock = two MC68000 cycles

;This include file is intended to be assembled with Macro68, the best
;assembler ever!

ZTimerOn	macro

;Disable interrupts

	movem.l	d0/d1/a0/a1/a6,-(sp)
	movea.l	(4).w,a6
	SYS	Disable
	movem.l	(sp)+,d0/d1/a0/a1/a6

;Wait for scan line 1

	move.l	d0,-(sp)
.Z1\#	move.l	(vposr+_custom),d0
	and.l	#$0001FF00,d0
	cmp.l	#$0100,d0
	bne.b	.Z1\#
	moveq	#$20,d0
	move.w	d0,(intreq+_custom)	;clear vblank interrupt
	move.l	(sp)+,d0

;Sample the video beam counter

	move.l	(vposr+_custom),(ZTimerSampleOne)
	endm

ZTimerOff	macro

;Sample the video beam counter

	move.l	(vposr+_custom),(ZTimerSampleTwo)
	btst.b	#INTB_VERTB,(intreqr+1+_custom)	;check vblank
	beq.b	.Z2\#
	clr.l	(ZTimerSampleTwo)	;sample is invalid
.Z2\#

;Enable interrupts

	movem.l	d0/d1/a0/a1/a6,-(sp)
	movea.l	(4).w,a6
	SYS	Enable
	movem.l	(sp)+,d0/d1/a0/a1/a6
	endm

	bra	__EndZCode

ZTimerReport:

	movem.l	d0-d7/a0-a6,-(sp)
	movea.l	(4).w,a6
	move.l	(ZTimerSampleOne,pc),d0
	beq	.NoSample
	move.l	(ZTimerSampleTwo,pc),d1
	beq	.TooLong

;Compute elapsed time

	bsr	ZDifference
	move.l	d1,d3

;Find the overhead of the Zen Timer, and subtract it

	ZTimerOn
	ZTimerOff

	lea	(ZTimerSampleOne,pc),a0
	movem.l	(a0)+,d0/d1
	clr.l	(-8,a0)
	bsr.b	ZDifference
	sub.l	d1,d3

;Number of color clocks now in D3

;Print the results

	lea	(ZResults,pc),a0
	lea	(.DataStream,pc),a1
	move.l	d3,(a1)
	lea	(ZPrintChar,pc),a2
	lea	(ZOutputBuffer,pc),a3
	SYS	RawDoFmt
	movea.l	a3,a0
	bsr	ZPrint

.Exit:
	movem.l	(sp)+,d0-d7/a0-a6
	rts

.TooLong:
	lea	(TooLongStr,pc),a0
	bsr	ZPrint
	bra.b	.Exit

.NoSample:
	lea	(NoSampleStr,pc),a0
	bsr	ZPrint
	bra.b	.Exit

.DataStream:
	dc.l	0

ZDifference:
;Test for NTSC/PAL, and branch to the proper routine
;Assumes ExecBase in A6

	cmpi.b	#60,(VBlankFrequency,a6)
	beq.b	ZDifference_NTSC

ZDifference_PAL:

;Compute the difference, in color clocks, of two samples
;Samples are in D0 and D1, result in D1
;D0 < D1

;uses d0,d1,d2

	move.l	d0,d2
	and.l	#$0001FF00,d2	;vertical only
	lsr.l	#8,d2
	mulu.w	#227,d2
	and.l	#$000000FF,d0	;horizontal only
	add.l	d2,d0

	move.l	d1,d2
	and.l	#$0001FF00,d2	;vertical only
	lsr.l	#8,d2
	mulu.w	#227,d2
	and.l	#$000000FF,d1	;horizontal only
	add.l	d2,d1

	sub.l	d0,d1
	rts

ZDifference_NTSC:

;Compute the difference, in color clocks, of two samples
;Samples are in D0 and D1, result in D1
;D0 < D1

;uses d0,d1,d2

	move.l	d0,d2
	and.l	#$0001FF00,d2	;vertical only
	lsr.l	#8,d2
	mulu.w	#455,d2
	lsr.l	#1,d2
	and.l	#$000000FF,d0	;horizontal only
	add.l	d2,d0

	move.l	d1,d2
	and.l	#$0001FF00,d2	;vertical only
	lsr.l	#8,d2
	mulu.w	#455,d2
	lsr.l	#1,d2
	and.l	#$000000FF,d1	;horizontal only
	add.l	d2,d1

	sub.l	d0,d1
	rts

ZPrintChar:
	move.b	d0,(a3)+
	clr.b	(a3)
	rts

ZPrint:
;Output a string to the CLI
;Enter with pointer to a zero-terminated string in a0
;All registers are preserved

	movem.l	d0-d7/a0-a6,-(sp)
	movea.l	a0,a5
	movea.l	(4).w,a6
	lea	(DosLibStr,pc),a1
	SYS	OldOpenLibrary
	tst.l	d0
	beq.b	.ZPrintEnd
	movea.l	d0,a6
	movea.l	a5,a0
	movea.l	a5,a4
.PrintLine:
	tst.b	(a5)+
	bne.b	.PrintLine
	subq.l	#1,a5
	suba.l	a0,a5
	SYS	Output
	move.l	d0,d1  
	move.l	a4,d2
	move.l	a5,d3
	SYS	Write
	movea.l	a6,a1
	movea.l	(4).w,a6
	SYS	CloseLibrary
.ZPrintEnd:
	movem.l	(sp)+,d0-d7/a0-a6
	rts

ZResults:
	dc.b	'%ld color clocks.',$a,0
	even

DosLibStr:
	dc.b	'dos.library',0
	even

TooLongStr:
	dc.b	'Can''t time code longer than about 20 milliseconds!',$a,0
	even

NoSampleStr:
	dc.b	'You''ve got to use ZTimerOn/ZTimerOff'
	dc.b	' before calling ZTimerReport!',$a,0
	even

ZTimerSampleOne:	dc.l	0
ZTimerSampleTwo:	dc.l	0

ZOutputBuffer:	dcb.b	80,0	;adjust upward if neccessary!

__EndZCode:
