misc/rapidcleartest.s
;========================================================================================
;  rapidcleartest.s
;  Copyright (C) 2003-2025 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/
;========================================================================================

;----------------------------------------------------------------
;	rapidcleartest.x
;
;	グラフィック画面の高速クリアをテストします。
;	エリアテストとポートテストを同時に行います。
;	エリアテストはVRAMのクリアされた範囲が正しいか調べます。
;	ポートテストはCRTCの動作ポートbit1の変化が正しいか調べます。
;
;	LCD向けの同期周波数が選択されているとき一時的にCRT向けに変更します。
;
;----------------------------------------------------------------

	.include	bioswork.equ
	.include	control2.mac
	.include	crtc.equ
	.include	doscall.mac
	.include	iocscall.mac
	.include	mfp.equ
	.include	misc.mac
	.include	push2.mac
	.include	vicon.equ


NAME	reg	'rapidcleartest.x'
VERSION	reg	'(2025-09-26)'


;定数
MASK	equ	%0110		;実画面サイズ512x512のときクリアする4bitページのマスク
PAINTED	equ	$5432		;塗り潰すパレット
T0	equ	(((.not.MASK)&%0001)*$000F)&PAINTED
T1	equ	(((.not.MASK)&%0010)*$0078)&PAINTED
T2	equ	(((.not.MASK)&%0100)*$03C0)&PAINTED
T3	equ	(((.not.MASK)&%1000)*$1E00)&PAINTED
CLEARED	equ	T3|T2|T1|T0	;クリアされたパレット


;レジスタ
dPAGE	reg	d4			;ページ
dSCROLL	reg	d5			;スクロール位置の番号
dSCRLX	reg	d6			;X方向のスクロール位置
dSCRLY	reg	d7			;Y方向のスクロール位置
aINFO	reg	a5			;画面モードの情報
aBASE	reg	a6			;相対アクセスベースアドレス


;相対アクセスベースアドレス
base:
	lea.l	base(pc),aBASE
r	reg	-base(aBASE)

;スタックエリアを設定する
	move.l	#stack_tail-base,d0
	lea.l	(aBASE,d0.l),sp

;引数を確認する
	addq.l	#1,a2
;画面モード
	moveq.l	#-2,d1			;-3=エラー,-2=指定なし,-1=all,0~18=画面モード
	lea.l	(str_buffer)r,a0
	movea.l	a2,a1
	jbsr	argcpy
	movea.l	a1,a2
	if	ne
		lea.l	(str_buffer)r,a0
		movestr	<'all'>,a1
		jbsr	stricmp
		if	eq
			moveq.l	#-1,d1			;-1=all
		else
			jbsr	stou
			ifand	<>,cc,<cmp.l #18,d0>,ls
				move.w	d0,d1			;0~18=画面モード
			else
				moveq.l	#-3,d1			;-3=エラー
			endif
		endif
	endif
;スクロール位置の番号
	moveq.l	#-2,d2			;-3=エラー,-2=指定なし,-1=all,0~3=スクロール位置の番号
	lea.l	(str_buffer)r,a0
	movea.l	a2,a1
	jbsr	argcpy
	movea.l	a1,a2
	if	ne
		lea.l	(str_buffer)r,a0
		movestr	<'all'>,a1
		jbsr	stricmp
		if	eq
			moveq.l	#-1,d2			;-1=all
		else
			jbsr	stou
			ifand	<>,cc,<cmp.l #3,d0>,ls
				move.w	d0,d2			;0~3=スクロール位置の番号
			else
				moveq.l	#-3,d2			;-3=エラー
			endif
		endif
	endif
;
	ifor	<cmp.w #-2,d1>,le,<cmp.w #-3,d2>,le
		movestr	<NAME,' ',VERSION,13,10,'  ',NAME,' mode(0-18,all) scroll(0-3,[all])',13,10>,a0
		jbsr	print
		move.w	#1,-(sp)
		DOS	_EXIT2
	endif
	move.w	d1,(specified_mode)r
	move.w	d2,(specified_scroll)r

;テストの通過数と総数を初期化する
	clr.l	(area_passed)r
	clr.l	(area_tested)r
	clr.l	(port_passed)r
	clr.l	(port_tested)r

;画面モードを保存する
	move.l	#$000E_FFFF,-(sp)
	DOS	_CONCTRL
	move.w	d0,2(sp)
	move.l	#$0010_FFFF,-(sp)
	DOS	_CONCTRL
	move.w	d0,2(sp)

;LCD向けを保存してCRT向けに変更する
	moveq.l	#0,d0
	move.w	#$16FF,d1
	IOCS	_CRTMOD
	rol.l	#8,d0
	moveq.l	#0,d1
	if	<cmp.b #$96,d0>,eq	;LCD向け
		move.w	#$43FF,d1		;CRT向け
		IOCS	_CRTMOD
		moveq.l	#1,d1
	endif
	move.w	d1,-(sp)

;アボート処理を保存する
	move.w	#_ERRJVC,-(sp)
	DOS	_INTVCG
	addq.l	#2,sp
	move.l	d0,-(sp)
	move.w	#_CTRLVC,-(sp)
	DOS	_INTVCG
	addq.l	#2,sp
	move.l	d0,-(sp)

;アボート処理を変更する
	pea.l	(abort_process)r
	move.w	#_CTRLVC,-(sp)
	DOS	_INTVCS
	addq.l	#6,sp
	move.l	sp,(abort_sp)r

;スーパーバイザモードへ移行する
	supervisormode

;画面モードのループ
	lea.l	(info_array)r,aINFO	;画面モードの情報
	do
		move.w	(specified_mode)r,d0	;指定された画面モード
		ifor	<>,mi,<cmp.w i_crtmod(aINFO),d0>,eq	;allまたは一致
			bsr	test_mode		;画面モード毎のテスト
		endif
		lea.l	i_sizeof(aINFO),aINFO	;次の画面モードの情報
	while	<tst.w i_crtmod(aINFO)>,pl

;ユーザモードへ復帰する
	usermode

;アボート処理を復元する
abort_process:
	lea.l	base(pc),aBASE
	movea.l	(abort_sp)r,sp
	move.w	#_CTRLVC,-(sp)
	DOS	_INTVCS
	addq.l	#6,sp
	move.w	#_ERRJVC,-(sp)
	DOS	_INTVCS
	addq.l	#6,sp

;LCD向けを復元する
	tst.w	(sp)+
	if	ne			;LCD向け
		move.w	#$4CFF,d1		;LCD向け
		IOCS	_CRTMOD
	endif

;画面モードを復元する
	DOS	_CONCTRL
	addq.l	#4,sp
	DOS	_CONCTRL
	addq.l	#4,sp

;テストの結果を表示する
	lea.l	(str_buffer)r,a0
;エリアテスト
	movestr	<'area test passed '>,a1
	jbsr	strcpy
	move.l	(area_passed)r,d0
	move.l	(area_tested)r,d1
	bsr	ratio
	jbsr	crlf
;ポートテスト
	movestr	<'port test passed '>,a1
	jbsr	strcpy
	move.l	(port_passed)r,d0
	move.l	(port_tested)r,d1
	bsr	ratio
	jbsr	crlf
;
	lea.l	(str_buffer)r,a0
	jbsr	print

;終了する
exit:
	DOS	_EXIT


;画面モード毎のテスト
;<aINFO.l:画面モードの情報
test_mode:

;画面モードを変更する
	move.w	i_crtmod(aINFO),d1
	IOCS	_CRTMOD
	IOCS	_G_CLR_ON

;画面モードを表示する
	lea.l	(str_buffer)r,a0
	movestr	<'testing in mode '>,a1
	jbsr	strcpy
	moveq.l	#0,d0
	move.w	i_crtmod(aINFO),d0
	jbsr	utos
	move.b	#':',(a0)+
	move.b	#' ',(a0)+
	moveq.l	#0,d0
	move.w	i_width(aINFO),d0
	jbsr	utos
	move.b	#'x',(a0)+
	moveq.l	#0,d0
	move.w	i_height(aINFO),d0
	jbsr	utos
	if	<tst.w i_memory(aINFO)>,eq
		movestr	<'/512x512 16-color'>,a1
	elif	<cmpi.w #3,i_memory(aINFO)>,lo
		movestr	<'/512x512 256-color'>,a1
	elif	eq
		movestr	<'/512x512 65536-color'>,a1
	else
		movestr	<'/1024x1024 16-color'>,a1
	endif
	jbsr	strcpy
	if	<tst.w i_interlaced(aINFO)>,eq
		movestr	<' progressive'>,a1
	else
		movestr	<' interlaced'>,a1
	endif
	jbsr	strcpy
	jbsr	crlf
	lea.l	(str_buffer)r,a0
	jbsr	print

;0.5秒待つ
	moveq.l	#30-1,d0
	for	d0
		bsr	wait_vdisp_0
		bsr	wait_vdisp_1
	next

;グラフィックページの優先順位を変更する
;	ページ0と2を入れ替えて2>1>0>3にする
;	高速クリアに影響しない
;		     SP TX GR G4 G3 G2 G1
	move.w	#%00_00_01_10_11_00_01_10,VICON_PRIORITY

;スクロール位置のループ
	moveq.l	#0,dSCROLL		;スクロール位置の番号。0=(0,0),1=(-1,0),2=(0,-1),3=(-1,-1)
	do
		move.w	(specified_scroll)r,d0	;指定されたスクロール位置の番号
		ifor	<>,mi,<cmp.w dSCROLL,d0>,eq	;allまたは一致
			bsr	test_scroll		;スクロール位置毎のテスト
		endif
		addq.w	#1,dSCROLL		;次のスクロール位置の番号
	while	<cmp.w #4,dSCROLL>,lo

	rts


;スクロール位置毎のテスト
;<dSCROLL.w:スクロール位置の番号。0~3
;<aINFO.l:画面モードの情報
test_scroll:

;スクロール位置を決める
	move.w	dSCROLL,dSCRLY		;dSCRLY 0  1  2  3
	lsr.w	#1,dSCRLY		;dSCRLY 0  0  1  1
					;     x 0  1  0  1
	subx.w	dSCRLX,dSCRLX		;dSCRLX 0 -1  0 -1
	neg.w	dSCRLY			;dSCRLY 0  0 -1 -1
	and.w	#1023,dSCRLX
	and.w	#1023,dSCRLY
;<dSCRLX.w:X方向のスクロール位置
;<dSCRLY.w:Y方向のスクロール位置

;スクロール位置を表示する
	lea.l	(str_buffer)r,a0
	movestr	<'scroll to '>,a1
	jbsr	strcpy
	moveq.l	#0,d0
	move.w	dSCRLX,d0
	jbsr	utos
	move.b	#',',(a0)+
	moveq.l	#0,d0
	move.w	dSCRLY,d0
	jbsr	utos
	jbsr	crlf
	lea.l	(str_buffer)r,a0
	jbsr	print

;スクロール位置を設定する
;	ページ0以外は高速クリアに影響しない
	move.w	dSCRLX,d0
	move.w	dSCRLY,d1
	move.w	d0,CRTC_GRAPHIC_X_0	;ページ0
	move.w	d1,CRTC_GRAPHIC_Y_0
	not.b	d0
	not.b	d1
	move.w	d0,CRTC_GRAPHIC_X_1	;ページ1
	move.w	d1,CRTC_GRAPHIC_Y_1
	not.w	d0
	not.w	d1
	move.w	d0,CRTC_GRAPHIC_X_2	;ページ2
	move.w	d1,CRTC_GRAPHIC_Y_2
	not.b	d0
	not.b	d1
	move.w	d0,CRTC_GRAPHIC_X_3	;ページ3
	move.w	d1,CRTC_GRAPHIC_Y_3

;メモリモード毎のテスト
	move.w	i_memory(aINFO),d0	;メモリモード
	if	eq			;メモリモード0
		bsr	test_body_0
	elif	<subq.w #3,d0>,lo	;メモリモード1
		bsr	test_body_1
	elif	eq			;メモリモード3
		bsr	test_body_3
	else				;メモリモード4
		bsr	test_body_4
	endif

	rts


;メモリモード0のテスト
;	実画面サイズ512x512、16色、4ページ
;<dSCRLX.w:X方向のスクロール位置
;<dSCRLY.w:Y方向のスクロール位置
;<aINFO.l:画面モードの情報
test_body_0:

;実画面を塗り潰す
	move.l	#PAINTED<<16|PAINTED,d3
	lea.l	$00C00000,a0
	moveq.l	#4-1,d2
	for	d2
		move.l	#$F<<16|$F,d0
		and.l	d3,d0
		moveq.l	#-1,d1			;512*512/4-1=65535
		for	d1
			move.l	d0,(a0)+
			move.l	d0,(a0)+
		next
		lsr.l	#4,d3
	next

;高速クリアを実行する
	bsr	rapid_clear

;ページのループ
	moveq.l	#0,dPAGE		;ページ。0,1,2,3
	do
	;<dPAGE.w:ページ

	;パレットを用意する
		move.w	#PAINTED,d0
		move.w	#CLEARED,d1
		move.w	dPAGE,d2
		lsl.w	#2,d2
		lsr.w	d2,d0
		lsr.w	d2,d1
		and.w	#$F,d0
		and.w	#$F,d1
		movea.w	d0,a2
		movea.w	d1,a3
	;<a2.w:塗り潰されたパレット
	;<a3.w:クリアされたパレット

	;比較のためのラインを作る
		bsr	make_line

	;512x512の画面を比較する
		bsr	compare_screen_512

		addq.w	#1,dPAGE
	while	<cmp.w	#4,dPAGE>,lo

	rts


;メモリモード1のテスト
;	実画面サイズ512x512、256色、2ページ
;<dSCRLX.w:X方向のスクロール位置
;<dSCRLY.w:Y方向のスクロール位置
;<aINFO.l:画面モードの情報
test_body_1:

;実画面を塗り潰す
	move.l	#PAINTED<<16|PAINTED,d3
	lea.l	$00C00000,a0
	moveq.l	#2-1,d2
	for	d2
		move.l	#$FF<<16|$FF,d0
		and.l	d3,d0
		moveq.l	#-1,d1			;512*512/4-1=65535
		for	d1
			move.l	d0,(a0)+
			move.l	d0,(a0)+
		next
		lsr.l	#8,d3
	next

;高速クリアを実行する
	bsr	rapid_clear

;ページのループ
	moveq.l	#0,dPAGE		;ページ。0,1
	do
	;<dPAGE.w:ページ

	;パレットを用意する
		move.w	#PAINTED,d0
		move.w	#CLEARED,d1
		move.w	dPAGE,d2
		lsl.w	#3,d2
		lsr.w	d2,d0
		lsr.w	d2,d1
		and.w	#$FF,d0
		and.w	#$FF,d1
		movea.w	d0,a2
		movea.w	d1,a3
	;<a2.w:塗り潰されたパレット
	;<a3.w:クリアされたパレット

	;比較のためのラインを作る
		bsr	make_line

	;512x512の画面を比較する
		bsr	compare_screen_512

		addq.w	#1,dPAGE
	while	<cmp.w	#2,dPAGE>,lo

	rts


;メモリモード3のテスト
;	実画面サイズ512x512、65536色、1ページ
;<dSCRLX.w:X方向のスクロール位置
;<dSCRLY.w:Y方向のスクロール位置
;<aINFO.l:画面モードの情報
test_body_3:

;実画面を塗り潰す
	move.l	#PAINTED<<16|PAINTED,d0
	lea.l	$00C00000,a0
	moveq.l	#-1,d1			;512*512/4-1=65535
	for	d1
		move.l	d0,(a0)+
		move.l	d0,(a0)+
	next

;高速クリアを実行する
	bsr	rapid_clear

;ページ
	moveq.l	#0,dPAGE		;ページ。0
;<dPAGE.w:ページ

;パレットを用意する
	movea.w	#PAINTED,a2
	movea.w	#CLEARED,a3
;<a2.w:塗り潰されたパレット
;<a3.w:クリアされたパレット

;比較のためのラインを作る
	bsr	make_line

;512x512の画面を比較する
	bsr	compare_screen_512

	rts


;メモリモード4のテスト
;	実画面サイズ1024x1024、16色、1ページ
;<dSCRLX.w:X方向のスクロール位置
;<dSCRLY.w:Y方向のスクロール位置
;<aINFO.l:画面モードの情報
test_body_4:

;実画面を塗り潰す
	move.l	#(PAINTED&$F)<<16|(PAINTED&$F),d0
	lea.l	$00C00000,a0
	move.l	#1024*1024/4-1,d1
	forlong	d1
		move.l	d0,(a0)+
		move.l	d0,(a0)+
	next

;高速クリアを実行する
	bsr	rapid_clear

;パレットを用意する
	movea.w	#PAINTED&$F,a2
	suba.l	a3,a3
;<a2.w:塗り潰されたパレット
;<a3.w:クリアされたパレット

;比較のためのラインを作る
	bsr	make_line

;1024x1024の画面を比較する
	bsr	compare_screen_1024

	rts


;高速クリアを実行する
;<aINFO.l:画面モードの情報
rapid_clear:
	move.w	CRTC_ACCESS,-(sp)
	move.w	#MASK,CRTC_ACCESS	;実画面サイズ512x512のときクリアする4bitページのマスク
	if	<tst.w i_interlaced(aINFO)>,eq	;プログレッシブ
		bsr	wait_vdisp_0
		bsr	wait_vdisp_1
		bsr	check_port_0
		move.w	#$0002,CRTC_ACTION	;予約
		bsr	check_port_0
		bsr	wait_vdisp_0
		bsr	check_port_0
		bsr	wait_vdisp_1		;開始
		bsr	check_port_1
		bsr	wait_vdisp_0
		bsr	check_port_1
		bsr	wait_vdisp_1		;終了
		bsr	check_port_0
	else				;インターレース
		bsr	wait_vdisp_0
		bsr	wait_vdisp_1
		bsr	check_port_0
		move.w	#$0002,CRTC_ACTION	;予約
		bsr	check_port_0
		bsr	wait_vdisp_0
		bsr	check_port_0
		bsr	wait_vdisp_1		;開始(偶数フレーム)
		moveq.l	#$0002,d0
		and.w	CRTC_ACTION,d0
		if	eq			;開始していない。奇数フレームだった
			bsr	wait_vdisp_0
			bsr	check_port_0
			bsr	wait_vdisp_1		;開始(偶数フレーム)
		else
			bsr	check_port_1		;数合わせ
		endif
		bsr	check_port_1
		bsr	wait_vdisp_0
		bsr	check_port_1
		bsr	wait_vdisp_1		;開始(奇数フレーム)
		bsr	check_port_1
		bsr	wait_vdisp_0
		bsr	check_port_1
		bsr	wait_vdisp_1		;終了
		bsr	check_port_0
	endif
	move.w	(sp)+,CRTC_ACCESS
	rts


;比較のためのラインを作る
;<dSCRLX.w:X方向のスクロール位置
;<a2.w:塗り潰されたパレット
;<a3.w:クリアされたパレット
;<aINFO.l:画面モードの情報
;?d1-d3/a0-a1
make_line:
	move.w	dSCRLX,d2		;X方向のスクロール位置
	and.w	#512-2,d2		;X座標開始位置。偶数
	move.w	i_width(aINFO),d3	;表示画面の幅
	if	<cmp.w #512,d3>,hs
		clr.w	d2
		move.w	#512,d3
	endif
	add.w	d2,d3			;X座標終了位置
;<d2.w:X座標開始位置。0~510
;<d3.w:X座標終了位置。0~1022
	lea.l	(line_painted)r,a0		;塗り潰された状態のラインバッファ
	lea.l	(line_cleared)r,a1		;クリアされた状態のラインバッファ
	moveq.l	#0,d1			;X座標
	if	<cmp.w #512,d3>,ls	;512を跨がないとき
	;0	d2	d3	512
	;.......********........
		docontinue
			move.w	a2,(a0)+
			move.w	a2,(a1)+
			addq.w	#1,d1
		while	<cmp.w d2,d1>,lo
		docontinue
			move.w	a2,(a0)+
			move.w	a3,(a1)+
			addq.w	#1,d1
		while	<cmp.w d3,d1>,lo
		docontinue
			move.w	a2,(a0)+
			move.w	a2,(a1)+
			addq.w	#1,d1
		while	<cmp.w #512,d1>,lo
	else				;512を跨ぐとき
		sub.w	#512,d3
	;0	d3	d2	512
	;*******........********
		docontinue
			move.w	a2,(a0)+
			move.w	a3,(a1)+
			addq.w	#1,d1
		while	<cmp.w d3,d1>,lo
		docontinue
			move.w	a2,(a0)+
			move.w	a2,(a1)+
			addq.w	#1,d1
		while	<cmp.w d2,d1>,lo
		docontinue
			move.w	a2,(a0)+
			move.w	a3,(a1)+
			addq.w	#1,d1
		while	<cmp.w #512,d1>,lo
	endif
	rts


;512x512の画面を比較する
;<dPAGE.w:ページ
;<dSCRLY.w:Y方向のスクロール位置
;<aINFO.l:画面モードの情報
;?d0-d3/a0-a1
compare_screen_512:
	move.w	dSCRLY,d2		;Y方向のスクロール位置
	and.w	#511,d2			;Y座標開始位置
	move.w	i_height(aINFO),d3	;表示画面の高さ
	if	<cmp.w #512,d3>,hs
		clr.w	d2
		move.w	#512,d3
	endif
	add.w	d2,d3			;Y座標終了位置
;<d2.w:Y座標開始位置。0~511
;<d3.w:Y座標終了位置。0~1023
	moveq.l	#$00C00000>>19,d0
	add.w	dPAGE,d0		;ページ
	lsl.w	#3,d0
	swap.w	d0			;$00C00000+2*512*512*ページ番号
	movea.l	d0,a0			;ページの先頭
	moveq.l	#0,d1			;Y座標
	if	<cmp.w #512,d3>,ls	;512を跨がないとき
	;0	d2	d3	512
	;.......********........
		docontinue
			lea.l	(line_painted)r,a1
			bsr	compare_line		;ラインを比較する
			addq.w	#1,d1
		while	<cmp.w d2,d1>,lo
		docontinue
			lea.l	(line_cleared)r,a1
			bsr	compare_line		;ラインを比較する
			addq.w	#1,d1
		while	<cmp.w d3,d1>,lo
		docontinue
			lea.l	(line_painted)r,a1
			bsr	compare_line		;ラインを比較する
			addq.w	#1,d1
		while	<cmp.w #512,d1>,lo
	else				;512を跨ぐとき
		sub.w	#512,d3
	;0	d3	d2	512
	;*******........********
		docontinue
			lea.l	(line_cleared)r,a1
			bsr	compare_line		;ラインを比較する
			addq.w	#1,d1
		while	<cmp.w d3,d1>,lo
		docontinue
			lea.l	(line_painted)r,a1
			bsr	compare_line		;ラインを比較する
			addq.w	#1,d1
		while	<cmp.w d2,d1>,lo
		docontinue
			lea.l	(line_cleared)r,a1
			bsr	compare_line		;ラインを比較する
			addq.w	#1,d1
		while	<cmp.w #512,d1>,lo
	endif
	rts


;1024x1024の画面を比較する
;<dSCRLY.w:Y方向のスクロール位置
;<aINFO.l:画面モードの情報
;?d0-d3/a0-a1
compare_screen_1024:
	move.w	dSCRLY,d2		;Y方向のスクロール位置
	and.w	#1023,d2		;Y座標開始位置
	move.w	i_height(aINFO),d3	;表示画面の高さ
	add.w	d2,d3			;Y座標終了位置
;<d2.w:Y座標開始位置。0~1023
;<d3.w:Y座標終了位置。0~2047
	lea.l	$00C00000,a0
	moveq.l	#0,d1			;Y座標
	if	<cmp.w #1024,d3>,ls	;1024を跨がないとき
	;0	d2	d3	1024
	;.......********........
		docontinue
			lea.l	(line_painted)r,a1
			bsr	compare_line		;ラインを比較する
			lea.l	(line_painted)r,a1
			bsr	compare_line		;ラインを比較する
			addq.w	#1,d1
		while	<cmp.w d2,d1>,lo
		docontinue
			lea.l	(line_cleared)r,a1
			bsr	compare_line		;ラインを比較する
			lea.l	(line_cleared)r,a1
			bsr	compare_line		;ラインを比較する
			addq.w	#1,d1
		while	<cmp.w d3,d1>,lo
		docontinue
			lea.l	(line_painted)r,a1
			bsr	compare_line		;ラインを比較する
			lea.l	(line_painted)r,a1
			bsr	compare_line		;ラインを比較する
			addq.w	#1,d1
		while	<cmp.w #1024,d1>,lo
	else				;1024を跨ぐとき
		sub.w	#1024,d3
	;0	d3	d2	1024
	;*******........********
		docontinue
			lea.l	(line_cleared)r,a1
			bsr	compare_line		;ラインを比較する
			lea.l	(line_cleared)r,a1
			bsr	compare_line		;ラインを比較する
			addq.w	#1,d1
		while	<cmp.w d3,d1>,lo
		docontinue
			lea.l	(line_painted)r,a1
			bsr	compare_line		;ラインを比較する
			lea.l	(line_painted)r,a1
			bsr	compare_line		;ラインを比較する
			addq.w	#1,d1
		while	<cmp.w d2,d1>,lo
		docontinue
			lea.l	(line_cleared)r,a1
			bsr	compare_line		;ラインを比較する
			lea.l	(line_cleared)r,a1
			bsr	compare_line		;ラインを比較する
			addq.w	#1,d1
		while	<cmp.w #1024,d1>,lo
	endif
	rts


;ラインを比較する
;<a0.l:VRAMのラインの先頭
;<a1.l:ラインバッファの先頭
;>a0.l:VRAMのラインの末尾
;>a1.l:ラインバッファの末尾
;?d0
compare_line:
	move.w	#512-1,d0
	for	d0
		cmpm.w	(a0)+,(a1)+
		if	eq
			addq.l	#1,(area_passed)r
		endif
		addq.l	#1,(area_tested)r
	next
	rts


;比率の文字列を作る
;	sprintf(str,"%d%% (%d/%d)",100*num/den,num,den)
;<d0.l:num。num<=den
;<d1.l:den。0<den
;<a0.l:str
;>a0.l:str
;?d0-d1
ratio:
	move.l	d1,-(sp)
	move.l	d0,-(sp)
	docontinue
		lsr.l	#1,d0
		lsr.l	#1,d1
	while	<cmp.l #$0000FFFF,d1>,hi
	mulu.w	#100,d0
	divu.w	d1,d0
	and.l	#$0000FFFF,d0
	jbsr	utos
	move.b	#'%',(a0)+
	move.b	#' ',(a0)+
	move.b	#'(',(a0)+
	move.l	(sp)+,d0
	jbsr	utos
	move.b	#'/',(a0)+
	move.l	(sp)+,d0
	jbsr	utos
	move.b	#')',(a0)+
	clr.b	(a0)
	rts


;VDISP=0を待つ
wait_vdisp_0:
	do
	while	<btst.b #MFP_G_VDISP_BIT,MFP_GPDR>,ne
	rts


;VDISP=1を待つ
wait_vdisp_1:
	do
	while	<btst.b #MFP_G_VDISP_BIT,MFP_GPDR>,eq
	rts


;動作ポートbit1が0であることを確認する
;?d0
check_port_0:
	moveq.l	#$0002,d0
	and.w	CRTC_ACTION,d0
	if	eq
		addq.l	#1,(port_passed)r
	endif
	addq.l	#1,(port_tested)r
	rts


;動作ポートbit1が1であることを確認する
;?d0
check_port_1:
	moveq.l	#$0002,d0
	and.w	CRTC_ACTION,d0
	if	ne
		addq.l	#1,(port_passed)r
	endif
	addq.l	#1,(port_tested)r
	rts


;画面モードの情報の配列
	.offset	0
i_crtmod:	.ds.w	1		;画面モード
i_width:	.ds.w	1		;表示画面の幅
i_height:	.ds.w	1		;表示画面の高さ
i_memory:	.ds.w	1		;メモリモード。0,1,3,4
i_interlaced:	.ds.w	1		;0=プログレッシブ,1=インターレース
i_sizeof:
	.text
info_array:
	.dc.w	0,512,512,4,0
	.dc.w	1,512,480,4,1
	.dc.w	2,256,256,4,0
	.dc.w	3,256,240,4,0
	.dc.w	4,512,512,0,0
	.dc.w	5,512,480,0,1
	.dc.w	6,256,256,0,0
	.dc.w	7,256,240,0,0
	.dc.w	8,512,512,1,0
	.dc.w	9,512,480,1,1
	.dc.w	10,256,256,1,0
	.dc.w	11,256,240,1,0
	.dc.w	12,512,512,3,0
	.dc.w	13,512,480,3,1
	.dc.w	14,256,256,3,0
	.dc.w	15,256,240,3,0
	.dc.w	16,768,512,4,0
	.dc.w	17,1024,424,4,0
	.dc.w	18,1024,848,4,1
;	.dc.w	19,640,480,4,0		;Compact以降
	.dc.w	-1


	.bss
	.even
specified_mode:
	.ds.w	1			;指定された画面モード。-1=all,0~18=画面モード
specified_scroll:
	.ds.w	1			;指定されたスクロール位置の番号。-2=指定なし,-1=all,0~3=スクロール位置の番号
area_passed:
	.ds.l	1			;エリアテストの通過数
area_tested:
	.ds.l	1			;エリアテストの総数
port_passed:
	.ds.l	1			;ポートテストの通過数
port_tested:
	.ds.l	1			;ポートテストの総数
abort_sp:
	.ds.l	1			;アボート処理を復元するときのsp
line_painted:
	.ds.w	512			;塗り潰された状態のラインバッファ
line_cleared:
	.ds.w	512			;クリアされた状態のラインバッファ
str_buffer:
	.ds.b	256			;文字列バッファ
	.ds.b	65536			;スタックエリア
stack_tail:



	.text

;----------------------------------------------------------------
;引数をコピーする
;	空白を読み飛ばしてから次の空白の手前までコピーする
;	"~"または'~'で囲むと引数に空白を含めることができる
;	""または''と書くと長さが0の引数を与えることができる
;<a0.l:コピー先のバッファの先頭
;<a1.l:コピー元の文字列の先頭
;>d0.l:0=引数がない,1=引数がある
;>a0.l:コピー先の文字列の末尾の0の位置
;>a1.l:コピー元の引数の直後。なければコピー元の文字列の末尾の0の位置
;>eq=引数がない,ne=引数がある
argcpy::
	exg.l	a0,a1
	jbsr	nextword		;空白を読み飛ばす
	exg.l	a0,a1
	if	eq			;引数がない
		clr.b	(a0)
		moveq.l	#0,d0
		rts
	endif
	dostart
		if	<cmp.b #'"',d0>,eq	;"~"
			dostart
				move.b	d0,(a0)+		;書き込む
			start
				move.b	(a1)+,d0		;次の文字
				break2	eq			;引数が終わった
			while	<cmp.b #'"',d0>,ne
		elif	<cmp.b #39,d0>,eq	;'~'
			dostart
				move.b	d0,(a0)+		;書き込む
			start
				move.b	(a1)+,d0		;次の文字
				break2	eq			;引数が終わった
			while	<cmp.b #$39,d0>,ne
		else
			move.b	d0,(a0)+		;書き込む
		endif
	start
		move.b	(a1)+,d0		;次の文字
		break	eq			;引数が終わった
		breakand	<cmp.b #9,d0>,hs,<cmp.b #13,d0>,ls	;\t\n\v\f\rならば終了
	while	<cmp.b #' ',d0>,ne	;空白でなければ繰り返す
	subq.l	#1,a1			;進み過ぎた分戻る
	clr.b	(a0)
	moveq.l	#1,d0
	rts

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

;----------------------------------------------------------------
;空白文字か \s
;<d0.b:文字
;>z:eq=空白文字,ne=空白文字ではない(0を含む)
isspace::
	if	<cmp.b #' ',d0>,ne
		ifand	<cmp.b #9,d0>,hs,<cmp.b #13,d0>,ls	;\t\n\v\f\r
			cmp.b	d0,d0
		endif
	endif
	rts

;----------------------------------------------------------------
;空白を読み飛ばす
;<a0.l:文字列
;>d0.l:最初の空白以外の文字または0
;>a0.l:最初の空白以外の文字または0の位置
;>z:ne=空白以外の文字がある,eq=空白以外の文字がない
nextword::
	moveq.l	#0,d0
	do
		move.b	(a0)+,d0		;次の文字
		break	eq			;0ならば終了
		jbsr	isspace			;空白か
	while	eq			;空白ならば繰り返す
	subq.l	#1,a0			;進み過ぎた分戻る
	tst.l	d0
	rts

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

;----------------------------------------------------------------
;10進数の文字列を符号なし整数に変換する
;<a0.l:10進数の文字列。先頭の空白は認めない
;>d0.l:(ccのとき)符号なし整数。(csのとき)0=10進数の文字がない,-1=オーバーフロー
;>a0.l:(ccのとき)10進数の文字列の次の位置。(csのとき)変化しない
;>z:(ccのとき)eq=符号なし整数が0
;>v:(csのとき)vc=10進数の文字がない,vs=オーバーフロー
;>c:cs=10進数の文字がないまたはオーバーフロー
stou::
	push	d1-d2/a1
	moveq.l	#0,d0			;符号なし整数
	moveq.l	#0,d1			;文字
	movea.l	a0,a1			;開始位置
	dostart
		goto	<cmp.l #$1999999A,d0>,hs,20f	;10倍したらオーバーフローする
		move.l	d0,d2			;1倍
		lsl.l	#2,d0			;4倍
		add.l	d2,d0			;5倍
		add.l	d0,d0			;10倍して
		add.l	d1,d0			;1桁加える
		goto	cs,20f			;オーバーフローした
	start
		move.b	(a0)+,d1		;次の文字
		sub.b	#'0',d1			;整数にする
	whileand	<>,hs,<cmp.b #10,d1>,lo	;10進数の文字ならば繰り返す
	subq.l	#1,a0			;進み過ぎた分戻る
	goto	<cmpa.l a1,a0>,eq,30f	;進んでいない。10進数の文字がない
	tst.l	d0			;ne/eq,vc,cc
10:	pop
	rts

;オーバーフロー
20:
  .if 0
	do
		move.b	(a0)+,d1		;次の文字
		sub.b	#'0',d1			;整数にする
	whileand	<>,hs,<cmp.b #10,d1>,lo	;10進数の文字を読み飛ばす
	subq.l	#1,a0			;進み過ぎた分戻る
  .else
	movea.l	a1,a0			;開始位置に戻る
  .endif
	moveq.l	#-1,d0			;オーバーフロー
	move.w	#%00011,ccr		;ne,vs,cs
	goto	10b

;10進数の文字がない
30:
;	moveq.l	#0,d0			;10進数の文字がない
	move.w	#%00101,ccr		;eq,vc,cs
	goto	10b

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

;----------------------------------------------------------------
;小文字化しながら文字列比較
;	'['<'A'となることに注意。SJISは正しく比較できないことに注意
;<a0.l:文字列0。引かれる
;<a1.l:文字列1。引く
;>ccr:eq=文字列0==文字列1,lo=文字列0<文字列1,hi=文字列1<文字列0
stricmp::
	push	d0-d1/a0-a1
	do
		move.b	(a0)+,d0
		if	eq
			cmp.b	(a1)+,d0
			break
		endif
		move.b	(a1)+,d1
		ifand	<cmp.b #'A',d0>,hs,<cmp.b #'Z',d0>,ls
			or.b	#$20,d0
		endif
		ifand	<cmp.b #'A',d1>,hs,<cmp.b #'Z',d1>,ls
			or.b	#$20,d1
		endif
		cmp.b	d1,d0
	while	eq
	pop
	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