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