misc/vperiod.s
;========================================================================================
;  vperiod.s
;  Copyright (C) 2003-2024 Makoto Kamada
;
;  This file is part of the XEiJ (X68000 Emulator in Java).
;  You can use, modify and redistribute the XEiJ if the conditions are met.
;  Read the XEiJ License for more details.
;  https://stdkmd.net/xeij/
;========================================================================================

;----------------------------------------------------------------------------------------
;	vperiod.x
;	垂直周期(垂直同期信号の周期)を計測します
;----------------------------------------------------------------------------------------

TITLE		reg	'vperiod.x (2024-02-17)'

	.include	control2.mac
	.include	doscall.mac
	.include	mfp.equ
	.include	misc.mac
	.include	push2.mac

;グローバルレジスタ
dZERO	reg	d7
	moveq.l	#0,dZERO
aTCDCR	reg	a6
	lea.l	MFP_TCDCR,aTCDCR

;スーパーバイザモード
	supervisormode

;割り込み禁止
	di

;タイマ保存
	move.b	MFP_IERB-MFP_TCDCR(aTCDCR),-(sp)
	move.b	MFP_IMRB-MFP_TCDCR(aTCDCR),-(sp)
	move.b	MFP_TCDCR-MFP_TCDCR(aTCDCR),-(sp)

;タイマ設定
	andi.b	#.notb.(MFP_B_TIMERC_MASK|MFP_B_TIMERD_MASK),MFP_IMRB-MFP_TCDCR(aTCDCR)	;Timer-C/D割り込み禁止
	andi.b	#.notb.(MFP_B_TIMERC_MASK|MFP_B_TIMERD_MASK),MFP_IERB-MFP_TCDCR(aTCDCR)	;Timer-C/D割り込み停止。IPRBクリア

;カウント停止
	move.b	dZERO,(aTCDCR)		;Timer-C/Dカウント停止
	do
	while	<tst.b (aTCDCR)>,ne	;完全に停止するまで待つ

;V-DISPの1→0を待つ
	do
	while	<btst.b #MFP_G_VDISP_BIT,MFP_GPDR>,eq	;?→1を待つ
	do
	while	<btst.b #MFP_G_VDISP_BIT,MFP_GPDR>,ne	;1→0を待つ

;カウント開始
	moveq.l	#0,d2			;neg(TCDR)のbit7の1→0の回数
	moveq.l	#0,d3			;前回のneg(TCDR)
	move.b	dZERO,MFP_TCDR-MFP_TCDCR(aTCDCR)	;Timer-Cカウンタクリア
	move.b	dZERO,MFP_TDDR-MFP_TCDCR(aTCDCR)	;Timer-Dカウンタクリア
	move.b	#MFP_50US<<4|MFP_1US,(aTCDCR)	;Timer-C/Dカウント開始
					;Timer-Cは1/200プリスケール(50us)
					;Timer-Dは1/4プリスケール(1us)

;V-DISPの1→0を待つ
	do
		moveq.l	#0,d0
		sub.b	MFP_TCDR-MFP_TCDCR(aTCDCR),d0	;neg(TCDR)
		eor.b	d0,d3
		ifand	<>,mi,<tst.b d0>,pl	;neg(TCDR)のbit7が1→0
			addq.w	#1,d2			;数える
		endif
		move.b	d0,d3
	while	<btst.b #MFP_G_VDISP_BIT,MFP_GPDR>,eq	;V-DISPの?→1を待つ
	do
		moveq.l	#0,d0
		sub.b	MFP_TCDR-MFP_TCDCR(aTCDCR),d0	;neg(TCDR)
		eor.b	d0,d3
		ifand	<>,mi,<tst.b d0>,pl	;neg(TCDR)のbit7が1→0
			addq.w	#1,d2			;数える
		endif
		move.b	d0,d3
	while	<btst.b #MFP_G_VDISP_BIT,MFP_GPDR>,ne	;V-DISPの1→0を待つ

;カウント停止
	move.b	dZERO,(aTCDCR)		;Timer-C/Dカウント停止
	do
	while	<tst.b (aTCDCR)>,ne	;完全に停止するまで待つ

;タイマ取得
	moveq.l	#0,d0
	moveq.l	#0,d1
	sub.b	MFP_TCDR-MFP_TCDCR(aTCDCR),d0	;Timer-Cカウント数
	sub.b	MFP_TDDR-MFP_TCDCR(aTCDCR),d1	;Timer-Dカウント数(オーバーフローあり)
	eor.b	d0,d3
	ifand	<>,mi,<tst.b d0>,pl	;neg(TCDR)のbit7が1→0
		addq.w	#1,d2			;数える
	endif

;タイマ復元
	move.b	#200,MFP_TCDR-MFP_TCDCR(aTCDCR)	;Timer-Cカウンタ復元
	move.b	dZERO,MFP_TDDR-MFP_TCDCR(aTCDCR)	;Timer-Dカウンタクリア
	move.b	(sp)+,(aTCDCR)
	move.b	(sp)+,MFP_IMRB-MFP_TCDCR(aTCDCR)
	move.b	(sp)+,MFP_IERB-MFP_TCDCR(aTCDCR)

;割り込み許可
	ei

;カウンタ合成
	mulu.w	#50,d0
	if	<cmp.b d1,d0>,hi
		add.w	#256,d0
	endif
	move.b	d1,d0
	mulu.w	#50*256,d2
	add.l	d2,d0			;垂直周期(us)
	move.l	d0,d1

;ユーザモード
	usermode

;結果を表示する
	lea.l	buffer(pc),a0
	leastrdata	<TITLE,13,10,'obs_VP='>,a1
	bsr	strcpy
	move.l	d1,d0
	bsr	utos
	bsr	crlf
	lea.l	buffer(pc),a0
	bsr	print

;終了
	DOS	_EXIT

	.bss
buffer:
	.ds.b	256
	.text



;----------------------------------------------------------------
;改行をコピーする
;<a0.l:コピー先
;>a0.l:コピー先の0の位置
crlf::
	move.b	#13,(a0)+
	move.b	#10,(a0)+
	clr.b	(a0)
	rts

;----------------------------------------------------------------
;文字列を表示する
;<a0.l:文字列
print::
	push	d0
	bsr	strlen
	move.l	d0,-(sp)
	move.l	a0,-(sp)
	move.w	#1,-(sp)
	DOS	_WRITE
	lea.l	(10,sp),sp
	pop
	rts

;----------------------------------------------------------------
;文字列をコピーする
;<a0.l:コピー先
;<a1.l:コピー元
;>a0.l:コピー先の0の位置
;>a1.l:コピー元の0の次の位置
strcpy::
	do
		move.b	(a1)+,(a0)+
	while	ne			;0でなければ繰り返す
	subq.l	#1,a0			;進み過ぎた分戻る
	rts

;----------------------------------------------------------------
;文字列の長さを数える
;<a0.l:文字列
;>d0.l:長さ
strlen::
	move.l	a0,d0			;d0=先頭
	do
		tst.b (a0)+
	while	ne			;0でなければ繰り返す
	subq.l	#1,a0			;進み過ぎた分戻る。a0=末尾
	exg.l	d0,a0			;d0=末尾,a0=先頭
	sub.l	a0,d0			;d0=末尾-先頭=長さ
	rts

;----------------------------------------------------------------
;32ビット符号なし整数を10進数の文字列に変換する
;<d0.l:符号なし整数
;<a0.l:バッファ。10進数の文字列の先頭
;>a0.l:10進数の文字列の末尾の0の位置
utos::
	if	<tst.l d0>,eq		;0
		move.b	#'0',(a0)+
	else				;0以外
		push	d0-d2/a1
		lea.l	utos_table(pc),a1
		do
			move.l	(a1)+,d1
		while	<cmp.l d1,d0>,lo	;引けるところまで進む。ゼロサプレス
		do
			moveq.l	#'0'-1,d2
			do
				addq.b	#1,d2
				sub.l	d1,d0
			while	hs			;引ける回数を数える
			move.b	d2,(a0)+
			add.l	d1,d0			;引き過ぎた分を加え戻す
			move.l	(a1)+,d1
		while	ne
		pop
	endif
	clr.b	(a0)
	rts

utos_table::
	.dc.l	1000000000
	.dc.l	100000000
	.dc.l	10000000
	.dc.l	1000000
	.dc.l	100000
	.dc.l	10000
	.dc.l	1000
	.dc.l	100
	.dc.l	10
	.dc.l	1
	.dc.l	0