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

	.include	bioswork.equ
	.include	control2.mac
	.include	crtc.equ
	.include	doscall.mac
	.include	dosconst.equ
	.include	doswork.equ
	.include	iocscall.mac
	.include	mfp.equ
	.include	misc.mac
	.include	push2.mac
	.include	sprc.equ
	.include	vector.equ
	.include	vicon.equ

DEVICE_NAME	reg	'/*FLPT*/'
TITLE_STRING	reg	'フルパターンメモリドライバ'
PROGRAM_NAME	reg	'fullpat.x'
MAGIC_CODE	equ	'FLPT'
VERSION_CODE	equ	'1.00'
VERSION_STRING	reg	'1.00'

EXPAND_LOOP	equ	1		;ループを展開する

;----------------------------------------------------------------
;プログラムの先頭
	.text
program_head:

;デバイスヘッダ
	.dc.l	-1			;次のデバイスヘッダ。-1=デバイスヘッダのリストの末尾
	.dc.w	$8000			;デバイスタイプ。キャラクタデバイス
	.dc.l	strategy_routine	;ストラテジルーチン
	.dc.l	interrupt_routine	;インタラプトルーチン
	.dc.b	DEVICE_NAME		;デバイス名

;ベクタテーブル
vector_table:
	.dc.w	4*($100+_SP_INIT)	;オフセット
	.dc.l	iocs_C0_SP_INIT		;新しいベクタ
	.dc.l	0			;古いベクタ
	.dc.w	4*($100+_SP_ON)
	.dc.l	iocs_C1_SP_ON
	.dc.l	0
	.dc.w	4*($100+_SP_OFF)
	.dc.l	iocs_C2_SP_OFF
	.dc.l	0
	.dc.w	4*($100+_SP_CGCLR)
	.dc.l	iocs_C3_SP_CGCLR
	.dc.l	0
	.dc.w	4*($100+_SP_DEFCG)
	.dc.l	iocs_C4_SP_DEFCG
	.dc.l	0
	.dc.w	4*($100+_SP_GTPCG)
	.dc.l	iocs_C5_SP_GTPCG
	.dc.l	0
	.dc.w	4*($100+_SP_REGST)
	.dc.l	iocs_C6_SP_REGST
	.dc.l	0
	.dc.w	4*($100+_SP_REGGT)
	.dc.l	iocs_C7_SP_REGGT
	.dc.l	0
	.dc.w	4*($100+_BGSCRLST)
	.dc.l	iocs_C8_BGSCRLST
	.dc.l	0
	.dc.w	4*($100+_BGSCRLGT)
	.dc.l	iocs_C9_BGSCRLGT
	.dc.l	0
	.dc.w	4*($100+_BGCTRLST)
	.dc.l	iocs_CA_BGCTRLST
	.dc.l	0
	.dc.w	4*($100+_BGCTRLGT)
	.dc.l	iocs_CB_BGCTRLGT
	.dc.l	0
	.dc.w	4*($100+_BGTEXTCL)
	.dc.l	iocs_CC_BGTEXTCL
	.dc.l	0
	.dc.w	4*($100+_BGTEXTST)
	.dc.l	iocs_CD_BGTEXTST
	.dc.l	0
	.dc.w	4*($100+_BGTEXTGT)
	.dc.l	iocs_CE_BGTEXTGT
	.dc.l	0
	.dc.w	4*($100+_SPALET)
	.dc.l	iocs_CF_SPALET
	.dc.l	0
	.dc.w	0

;リクエストヘッダのアドレス
request_header:
	.dc.l	0

;ストラテジルーチン
strategy_routine:
	move.l	a5,request_header
	rts

;インタラプトルーチン
interrupt_routine:
	push	d0-d7/a0-a6
	movea.l	request_header(pc),a5
	moveq.l	#0,d0
	move.b	2(a5),d0		;コマンド番号
	if	<cmp.w #(jump_table_end-jump_table)/2,d0>,hs	;範囲外
		moveq.l	#(jump_table_end-jump_table)/2,d0
	endif
	add.w	d0,d0
	move.w	jump_table(pc,d0.w),d0
	jsr	jump_table(pc,d0.w)
	move.b	d0,3(a5)		;エラーコード下位
	lsr.w	#8,d0
	move.b	d0,4(a5)		;エラーコード上位
	pop
	rts

;デバイスコマンドのジャンプテーブル
jump_table:
	.dc.w	initialize-jump_table		;デバイスコマンド0 初期化
	.dc.w	command_error-jump_table	;デバイスコマンド1 ディスク交換チェック
	.dc.w	command_error-jump_table	;デバイスコマンド2 BPBテーブルの再構築
	.dc.w	ioctrl_input-jump_table		;デバイスコマンド3 _IOCTRLによる入力
	.dc.w	input-jump_table		;デバイスコマンド4 入力
	.dc.w	control_sense-jump_table	;デバイスコマンド5 コントロール/センス
	.dc.w	input_status-jump_table		;デバイスコマンド6 入力ステータス
	.dc.w	input_flush-jump_table		;デバイスコマンド7 入力バッファフラッシュ
	.dc.w	output-jump_table		;デバイスコマンド8 出力(ベリファイなし)
	.dc.w	output-jump_table		;デバイスコマンド9 出力(ベリファイあり)
	.dc.w	output_status-jump_table	;デバイスコマンド10 出力ステータス
	.dc.w	no_error-jump_table		;デバイスコマンド11 正常終了
	.dc.w	ioctrl_output-jump_table	;デバイスコマンド12 _IOCTRLによる出力
jump_table_end:
	.dc.w	command_error-jump_table	;範囲外 コマンドエラー

;デバイスコマンド1 ディスク交換チェック
;デバイスコマンド2 BPBテーブルの再構築
;コマンドエラー
command_error:
	move.w	#IGNORE|ABORT|UNKNOWN_COMMAND,d0	;無視(I) 中止(A) デバイスドライバに無効なコマンドを指定しました
	rts

;デバイスコマンド3 _IOCTRLによる入力
ioctrl_input:
;	movea.l	14(a5),a1		;アドレス
	goto	command_error

;デバイスコマンド4 入力
input:
	movea.l	14(a5),a1		;アドレス
	move.l	18(a5),d3		;長さ
	docontinue
		clr.b	(a1)+
	while	<subq.l #1,d3>,cc
	moveq.l	#0,d0			;常に成功する(終わるまで復帰しない)
	rts

;デバイスコマンド5 コントロール/センス
control_sense:
	clr.b	13(a5)			;データ
	moveq.l	#0,d0			;常に成功する
	rts

;デバイスコマンド6 入力ステータス
input_status:
	moveq.l	#1,d0			;0=入力バッファが空ではないので入力できる,1=入力バッファが空なので入力できない
	rts

;デバイスコマンド7 入力バッファフラッシュ
input_flush:
	moveq.l	#0,d0			;常に成功する
	rts

;デバイスコマンド8 出力(ベリファイなし)
;デバイスコマンド9 出力(ベリファイあり)
output:
;	movea.l	14(a5),a1		;アドレス
;	move.l	18(a5),d3		;長さ
	moveq.l	#0,d0			;常に成功する(終わるまで復帰しない)
	rts

;デバイスコマンド10 出力ステータス
output_status:
	moveq.l	#1,d0			;0=出力バッファが満杯ではないので出力できる,1=出力バッファが満杯なので出力できない
	rts

;デバイスコマンド11 正常終了
no_error:
	moveq.l	#0,d0			;常に成功する
	rts

;デバイスコマンド12 _IOCTRLによる出力
ioctrl_output:
;	movea.l	14(a5),a1		;アドレス
	goto	command_error



;----------------------------------------------------------------
;ワークエリア
extended_1xx1x:
	.dc.b	1			;%1xx1xのときスプライト画面を使用できるか。-1=使える,0=使えない,1=未確認
	.even

;----------------------------------------------------------------
;スプライト画面を使用できるか確認する
;	IOCSコールの先頭で呼び出す
;	スプライト画面を使用できるとき何もしない
;	スプライト画面を使用できないときd0.l=-1でIOCSコールを終了する
;?d0
check_sprite:
	moveq.l	#.not.%10010,d0
	or.b	CRTC_RESOLUTION_BYTE,d0	;R20L。%1xx1xのときだけ%11111111
	not.b	d0			;%1xx1xのときだけ%00000000
	if	eq			;%1xx1x。使用できない
		moveq.l	#-1,d0			;スプライト画面を使用できない
		addq.l	#4,sp			;IOCSコールを終了する
	endif
	rts

;----------------------------------------------------------------
;VDISPの立ち下がりを待つ
vdisp_falling_edge:
	do
	while	<btst.b #MFP_G_VDISP_BIT,MFP_GPDR>,eq
	do
	while	<btst.b #MFP_G_VDISP_BIT,MFP_GPDR>,ne
	rts



;マジックコード
magic_code:
	.dc.l	MAGIC_CODE

;バージョンコード
version_code:
	.dc.l	VERSION_CODE

;----------------------------------------------------------------
;$C0	SP_INIT
;	スプライト・バックグラウンドを初期化します。
;>d0.l:-1=スプライト画面を使用できない,0=正常終了
;?a0
iocs_C0_SP_INIT:
	bsr	check_sprite		;スプライト画面を使用できるか確認する
	push	d1-d5/a1-a4/a6
	lea.l	SPRC_CONTROL,a5
;d1-d4/a1-a4をゼロにする
	moveq.l	#0,d1
  .irp rn,d2,d3,d4,a1,a2,a3,a4
	move.l	d1,rn
  .endm
;スプライトコントロールレジスタとパターンとテキストエリアをゼロクリアする
	move.w	#$0400,d5		;MPUCS。$0400=後半,$0000=前半
	do
		move.w	d5,(a5)
		lea.l	SPRC_PATTERN-SPRC_CONTROL(a5),a0
	  .if EXPAND_LOOP
		moveq.l	#128*256/32/8-1,d0
		for	d0
			.rept	8
				movem.l	d1-d4/a1-a4,(a0)
				lea.l	32(a0),a0
			.endm
		next
	  .else
		moveq.l	#128*256/32-1,d0
		for	d0
			movem.l	d1-d4/a1-a4,(a0)
			lea.l	32(a0),a0
		next
	  .endif
		eor.w	#$0400,d5
	while	eq
;バックグラウンドスクロールレジスタをゼロクリアする
	movem.l	d1-d2,SPRC_BG_0_X-SPRC_CONTROL(a5)
;スプライトスクロールレジスタをゼロクリアする
	lea.l	SPRC_SCROLL-SPRC_CONTROL(a5),a0
  .if EXPAND_LOOP
	moveq.l	#8*128/32/8-1,d0	;128枚
	for	d0
		.rept	8
			movem.l	d1-d4/a1-a4,(a0)
			lea.l	32(a0),a0
		.endm
	next
  .else
	moveq.l	#8*128/32-1,d0		;128枚
	for	d0
		movem.l	d1-d4/a1-a4,(a0)
		lea.l	32(a0),a0
	next
  .endif
;スプライトパレットを初期化する
	lea.l	VICON_TSPALET+2*16,a0	;パレットブロック1~15
	movem.l	100f(pc),d1-d4/a1-a4	;カラーコードの初期値
	bsr	vdisp_falling_edge	;VDISPの立ち下がりを待つ
	moveq.l	#15-1,d0
	for	d0
		movem.l	d1-d4/a1-a4,(a0)
		lea.l	32(a0),a0
	next
	moveq.l	#0,d0			;正常終了
	pop
	rts

;カラーコードの初期値
100:	dcrgb	0,0,0			;0=黒
	dcrgb	10,10,10		;1=暗い灰色
	dcrgb	0,0,16			;2=暗い青
	dcrgb	0,0,31			;3=青
	dcrgb	16,0,0			;4=暗い赤
	dcrgb	31,0,0			;5=赤
	dcrgb	16,0,16			;6=暗い紫
	dcrgb	31,0,31			;7=紫
	dcrgb	0,16,0			;8=暗い緑
	dcrgb	0,31,0			;9=緑
	dcrgb	0,16,16			;10=暗い水色
	dcrgb	0,31,31			;11=水色
	dcrgb	16,16,0			;12=暗い黄色
	dcrgb	31,31,0			;13=黄色
	dcrgb	21,21,21		;14=明るい灰色
	dcrgb	31,31,31		;15=白

;----------------------------------------------------------------
;$C1	SP_ON
;	スプライト・バックグラウンド画面を表示します。
;>d0.l:-1=スプライト画面を使用できない,0=正常終了
iocs_C1_SP_ON:
	bsr	check_sprite		;スプライト画面を使用できるか確認する
	ori.w	#VICON_SPON_MASK,VICON_VISIBLE
	ori.w	#SPRC_SPRITE_ON,SPRC_CONTROL
	moveq.l	#0,d0			;正常終了
	rts

;----------------------------------------------------------------
;$C2	SP_OFF
;	スプライト・バックグラウンド画面を表示しません。
;>d0.l:0=正常終了
iocs_C2_SP_OFF:
	andi.w	#.notw.VICON_SPON_MASK,VICON_VISIBLE
	andi.w	#.notw.SPRC_SPRITE_ON,SPRC_CONTROL
	moveq.l	#0,d0			;正常終了
	rts

;----------------------------------------------------------------
;$C3	SP_CGCLR
;	パターンをゼロクリアします。
;<d1.w:パターン番号。0~511
;>d0.l:-1=スプライト画面を使用できない,0=正常終了
;?a0
;	MPUCSは入力は不定、出力は0
iocs_C3_SP_CGCLR:
	bsr	check_sprite		;スプライト画面を使用できるか確認する
	push	d1/d5/a5
	lea.l	SPRC_CONTROL,a5
	move.w	(a5),d5
	and.w	#.notw.$0400,d5		;MPUCSをクリアした値
	move.w	d1,d0
	and.w	#$0100,d0
	lsl.w	#2,d0			;bit8→bit10
	or.w	d5,d0
	move.w	d0,(a5)			;MPUCSを変更
	and.w	#$00FF,d1
	lsl.w	#7,d1			;*128
	lea.l	SPRC_PATTERN-SPRC_CONTROL(a5),a0
	adda.w	d1,a0
	moveq.l	#0,d0
  .if EXPAND_LOOP
	.rept	128/4
		move.l	d0,(a0)+
	.endm
  .else
	moveq.l	#128/4-1,d1
	for	d1
		move.l	d0,(a0)+
	next
  .endif
	move.w	d5,(a5)			;MPUCSをクリア
;	moveq.l	#0,d0			;正常終了
	pop
	rts

;----------------------------------------------------------------
;$C4	SP_DEFCG
;	パターンを設定します。
;<d1.w:パターン番号。0~511
;<d2.b:サイズ。0=8x8,1=16x16
;<a1.l:バッファのアドレス。偶数
;>d0.l:-1=スプライト画面を使用できない,0=正常終了
;?a0
;	MPUCSは入力は不定、出力は0
iocs_C4_SP_DEFCG:
	bsr	check_sprite		;スプライト画面を使用できるか確認する
	push	d1/d5/a1/a5
	lea.l	SPRC_CONTROL,a5
	move.w	(a5),d5
	and.w	#.notw.$0400,d5		;MPUCSをクリアした値
	move.w	d1,d0
	if	<tst.b d2>,eq		;8x8
		and.w	#$0400,d0
		or.w	d5,d0
		move.w	d0,(a5)			;MPUCSを変更
		and.w	#$03FF,d1
		lsl.w	#5,d1			;*32
		lea.l	SPRC_PATTERN-SPRC_CONTROL(a5),a0
		adda.w	d1,a0
	  .if EXPAND_LOOP
		.rept	32/4
			move.l	(a1)+,(a0)+
		.endm
	  .else
		moveq.l	#32/4-1,d1
		for	d1
			move.l	(a1)+,(a0)+
		next
	  .endif
	else				;16x16
		and.w	#$0100,d0
		lsl.w	#2,d0			;bit8→bit10
		or.w	d5,d0
		move.w	d0,(a5)			;MPUCSを変更
		and.w	#$00FF,d1
		lsl.w	#7,d1			;*128
		lea.l	SPRC_PATTERN-SPRC_CONTROL(a5),a0
		adda.w	d1,a0
	  .if EXPAND_LOOP
		.rept	128/4
			move.l	(a1)+,(a0)+
		.endm
	  .else
		moveq.l	#128/4-1,d1
		for	d1
			move.l	(a1)+,(a0)+
		next
	  .endif
	endif
	move.w	d5,(a5)			;MPUCSをクリア
	moveq.l	#0,d0			;正常終了
	pop
	rts

;----------------------------------------------------------------
;$C5	SP_GTPCG
;	パターンを取得します。
;<d1.w:パターン番号。0~511
;<d2.b:サイズ。0=8x8,1=16x16
;<a1.l:バッファのアドレス。偶数
;>d0.l:-1=スプライト画面を使用できない,0=正常終了
;?a0
;	MPUCSは入力は不定、出力は0
iocs_C5_SP_GTPCG:
	bsr	check_sprite		;スプライト画面を使用できるか確認する
	push	d1/d5/a1/a5
	lea.l	SPRC_CONTROL,a5
	move.w	(a5),d5
	and.w	#.notw.$0400,d5		;MPUCSをクリアした値
	move.w	d1,d0
	if	<tst.b d2>,eq		;8x8
		and.w	#$0400,d0
		or.w	d5,d0
		move.w	d0,(a5)			;MPUCSを変更
		and.w	#$03FF,d1
		lsl.w	#5,d1			;*32
		lea.l	SPRC_PATTERN-SPRC_CONTROL(a5),a0
		adda.w	d1,a0
	  .if EXPAND_LOOP
		.rept	32/4
			move.l	(a0)+,(a1)+
		.endm
	  .else
		moveq.l	#32/4-1,d1
		for	d1
			move.l	(a0)+,(a1)+
		next
	  .endif
	else				;16x16
		and.w	#$0100,d0
		lsl.w	#2,d0			;bit8→bit10
		or.w	d5,d0
		move.w	d0,(a5)			;MPUCSを変更
		and.w	#$00FF,d1
		lsl.w	#7,d1			;*128
		lea.l	SPRC_PATTERN-SPRC_CONTROL(a5),a0
		adda.w	d1,a0
	  .if EXPAND_LOOP
		.rept	128/4
			move.l	(a0)+,(a1)+
		.endm
	  .else
		moveq.l	#128/4-1,d1
		for	d1
			move.l	(a0)+,(a1)+
		next
	  .endif
	endif
	move.w	d5,(a5)			;MPUCSをクリア
	moveq.l	#0,d0			;正常終了
	pop
	rts

;----------------------------------------------------------------
;$C6	SP_REGST
;	スプライトスクロールレジスタを設定します。
;<d1.l bit31:VDISPの立ち下がり。0=待つ,1=待たない
;<d1.w:スプライト番号。0~127
;<d2.l bit31:X座標の設定。0=する。1=しない
;<d2.w:X座標。0~1023
;<d3.l bit31:Y座標の設定。0=する,1=しない
;<d3.w:Y座標。0~1023
;<d4.l bit31:キャラクタの設定。0=する,1=しない
;<d4.w:キャラクタ。0~65535
;<d5.l bit31:プライオリティの設定。0=する,1=しない
;<d5.w:プライオリティ。0~7
;>d0.l:-1=スプライト画面を使用できない,0=正常終了
;?a0
iocs_C6_SP_REGST:
	bsr	check_sprite		;スプライト画面を使用できるか確認する
	moveq.l	#$7F,d0			;ここで上位ワードをクリアする
	and.w	d1,d0
	lsl.w	#3,d0
	lea.l	SPRC_SCROLL,a0
	adda.l	d0,a0
	if	<tst.l d1>,pl
		bsr	vdisp_falling_edge	;VDISPの立ち下がりを待つ
	endif
	if	<tst.l d2>,pl
		move.w	d2,(a0)			;X座標
	endif
	if	<tst.l d3>,pl
		move.w	d3,2(a0)		;Y座標
	endif
	if	<tst.l d4>,pl
		move.w	d4,4(a0)		;キャラクタ
	endif
	if	<tst.l d5>,pl
		move.w	d5,6(a0)		;プライオリティ
	endif
	moveq.l	#0,d0			;正常終了
	rts

;----------------------------------------------------------------
;$C7	SP_REGGT
;	スプライトスクロールレジスタを取得します。
;<d1.w:スプライト番号。0~127
;>d0.l:-1=スプライト画面を使用できない,0=正常終了
;>d2.l:X座標。0~1023
;>d3.l:Y座標。0~1023
;>d4.l:キャラクタ。0~65535
;>d5.l:プライオリティ。0~7
;?a0
iocs_C7_SP_REGGT:
	bsr	check_sprite		;スプライト画面を使用できるか確認する
	moveq.l	#$7F,d0			;ここで上位ワードをクリアする
	and.w	d1,d0
	lsl.w	#3,d0
	lea.l	SPRC_SCROLL,a0
	adda.l	d0,a0
	moveq.l	#0,d2
	moveq.l	#0,d3
	moveq.l	#0,d4
	moveq.l	#0,d5
	move.w	(a0)+,d2		;X座標
	move.w	(a0)+,d3		;Y座標
	move.w	(a0)+,d4		;キャラクタ
	move.w	(a0)+,d5		;プライオリティ
	moveq.l	#0,d0			;正常終了
	rts

;----------------------------------------------------------------
;$C8	BGSCRLST
;	バックグラウンドスクロールレジスタを設定します。
;<d1.l bit31:VDISPの立ち下がり。0=待つ,1=待たない
;<d1.b:バックグラウンド番号。0~1
;<d2.l bit31:X座標の設定。0=する。1=しない
;<d2.w:X座標。0~1023
;<d3.l bit31:Y座標の設定。0=する,1=しない
;<d3.w:Y座標。0~1023
;>d0.l:-1=スプライト画面を使用できない,0=正常終了
;?a0
iocs_C8_BGSCRLST:
	bsr	check_sprite		;スプライト画面を使用できるか確認する
	if	<tst.l d1>,pl
		bsr	vdisp_falling_edge	;VDISPの立ち下がりを待つ
	endif
	lea.l	SPRC_BG_0_X,a0
	if	<tst.b d1>,ne
		addq.l	#SPRC_BG_1_X-SPRC_BG_0_X,a0
	endif
	if	<tst.l d2>,pl
		move.w	d2,(a0)			;X座標
	endif
	if	<tst.l d3>,pl
		move.w	d3,2(a0)		;Y座標
	endif
	moveq.l	#0,d0			;正常終了
	rts

;----------------------------------------------------------------
;$C9	BGSCRLGT
;	バックグラウンドスクロールレジスタを取得します。
;<d1.b:バックグラウンド番号。0~1
;>d2.l:X座標。0~1023
;>d3.l:Y座標。0~1023
;>d0.l:-1=スプライト画面を使用できない,0=正常終了
;?a0
iocs_C9_BGSCRLGT:
	bsr	check_sprite		;スプライト画面を使用できるか確認する
	lea.l	SPRC_BG_0_X,a0
	if	<tst.b d1>,ne
		addq.l	#SPRC_BG_1_X-SPRC_BG_0_X,a0
	endif
	moveq.l	#0,d2
	moveq.l	#0,d3
	move.w	(a0)+,d2		;X座標
	move.w	(a0)+,d3		;Y座標
	moveq.l	#0,d0			;正常終了
	rts

;----------------------------------------------------------------
;$CA	BGCTRLST
;	バックグラウンド制御レジスタを設定します。
;<d1.b:バックグラウンド番号。0~1
;<d2.l bit31:テキスト番号の設定。0=する,1=しない
;<d2.b:テキスト番号。0~3
;<d3.l bit31:表示の有無の設定。0=する,1=しない
;<d3.b:表示の有無。0~1
;>d0.l:-1=スプライト画面を使用できない,0=正常終了
;?a0
iocs_CA_BGCTRLST:
	bsr	check_sprite		;スプライト画面を使用できるか確認する
	move.w	SPRC_CONTROL,d0
	if	<tst.b d1>,ne		;バックグラウンド1
		ror.w	#3,d0
	endif
	if	<tst.l d2>,pl
		and.b	#.notb.%110,d0
		move.b	d2,-(sp)
		and.b	#3,d2			;テキスト番号
		add.b	d2,d2
		or.b	d2,d0
		move.b	(sp)+,d2
	endif
	if	<tst.l d3>,pl
		and.b	#.notb.%001,d0
		if	<tst.b d3>,ne		;表示する
			addq.b	#%001,d0
		endif
	endif
	if	<tst.b d1>,ne		;バックグラウンド1
		rol.w	#3,d0
	endif
	move.w	d0,SPRC_CONTROL
	moveq.l	#0,d0			;正常終了
	rts

;----------------------------------------------------------------
;$CB	BGCTRLGT
;	バックグラウンド制御レジスタを取得します。
;<d1.b:バックグラウンド番号。0~1
;>d0.l:-1=スプライト画面を使用できない,0~7=テキスト番号<<1|表示の有無
;?a0
iocs_CB_BGCTRLGT:
	bsr	check_sprite		;スプライト画面を使用できるか確認する
	moveq.l	#0,d0
	move.w	SPRC_CONTROL,d0
	if	<tst.b d1>,ne		;バックグラウンド1
		lsr.w	#3,d0
	endif
	and.w	#%111,d0
	rts

;----------------------------------------------------------------
;$CC	BGTEXTCL
;	バックグラウンドテキストをキャラクタで埋め尽くします。
;<d1.b:テキスト番号。0~3
;<d2.w:キャラクタ。0~65535
;>d0.l:-1=スプライト画面を使用できない,0=正常終了
;?a0
;	MPUCSは入力は不定、出力は0
iocs_CC_BGTEXTCL:
	bsr	check_sprite		;スプライト画面を使用できるか確認する
	push	d1-d5/a1-a5
	lea.l	SPRC_CONTROL,a5
	move.w	(a5),d5
	and.w	#.notw.$0400,d5		;MPUCSをクリアした値
	moveq.l	#$02,d0
	and.b	d1,d0
	ror.w	#7,d0			;bit1→bit10
	or.w	d5,d0
	move.w	d0,(a5)			;MPUCSを変更
	moveq.l	#$01,d0			;ここで上位ワードをクリアする
	and.b	d1,d0
	ror.w	#3,d0			;bit0→bit13 2*64*64
	lea.l	SPRC_TEXT_0,a0
	adda.l	d0,a0
	move.w	d2,d0
	swap.w	d2
	move.w	d0,d2
  .irp rn,d1,d3,d4,a1,a2,a3,a4
	move.l	d2,rn
  .endm
	moveq.l	#2*64*64/32/8-1,d0
	for	d0
		.rept	8
			movem.l	d1-d4/a1-a4,(a0)
			lea.l	32(a0),a0
		.endm
	next
	move.w	d5,(a5)			;MPUCSをクリア
	moveq.l	#0,d0			;正常終了
	pop
	rts

;----------------------------------------------------------------
;$CD	BGTEXTST
;	バックグラウンドテキストにキャラクタを書き込みます。
;<d1.b:テキスト番号。0~3
;<d2.w:X座標。0~63
;<d3.w:Y座標。0~63
;<d4.w:キャラクタ。0~65535
;>d0.l:-1=スプライト画面を使用できない,0=正常終了
;?a0
;	MPUCSは入力は不定、出力は0
iocs_CD_BGTEXTST:
	bsr	check_sprite		;スプライト画面を使用できるか確認する
	push	d5/a5
	lea.l	SPRC_CONTROL,a5
	move.w	(a5),d5
	and.w	#.notw.$0400,d5		;MPUCSをクリアした値
	moveq.l	#$02,d0
	and.b	d1,d0
	ror.w	#7,d0			;bit1→bit10
	or.w	d5,d0
	move.w	d0,(a5)			;MPUCSを変更
	moveq.l	#$01,d0			;ここで上位ワードをクリアする
	and.b	d1,d0
	ror.w	#3,d0			;bit0→bit13 2*64*64
	lea.l	SPRC_TEXT_0,a0
	adda.l	d0,a0
	moveq.l	#63,d0			;00111111
	and.b	d3,d0			;00YYYYYY
	move.b	d0,-(sp)		;00YYYYYY
	move.w	(sp)+,d0		;00YYYYYY........
	move.b	d2,d0			;00YYYYYY..XXXXXX
	add.b	d0,d0			;00YYYYYY.XXXXXX0
	add.b	d0,d0			;00YYYYYYXXXXXX00
	lsr.w	#1,d0			;000YYYYYYXXXXXX0
	move.w	d4,(a0,d0.w)		;キャラクタ
	move.w	d5,(a5)			;MPUCSをクリア
	moveq.l	#0,d0			;正常終了
	pop
	rts

;----------------------------------------------------------------
;$CE	BGTEXTGT
;	バックグラウンドテキストからキャラクタを読み出します。
;<d1.b:テキスト番号。0~3
;<d2.w:X座標。0~63
;<d3.w:Y座標。0~63
;>d0.l:-1=スプライト画面を使用できない,0~65535=キャラクタ
;?a0
;	MPUCSは入力は不定、出力は0
iocs_CE_BGTEXTGT:
	bsr	check_sprite		;スプライト画面を使用できるか確認する
	push	d5/a5
	lea.l	SPRC_CONTROL,a5
	move.w	(a5),d5
	and.w	#.notw.$0400,d5		;MPUCSをクリアした値
	moveq.l	#$02,d0
	and.b	d1,d0
	ror.w	#7,d0			;bit1→bit10
	or.w	d5,d0
	move.w	d0,(a5)			;MPUCSを変更
	moveq.l	#$01,d0			;ここで上位ワードをクリアする
	and.b	d1,d0
	ror.w	#3,d0			;bit0→bit13 2*64*64
	lea.l	SPRC_TEXT_0,a0
	adda.l	d0,a0
	moveq.l	#63,d0			;00111111
	and.b	d3,d0			;00YYYYYY
	move.b	d0,-(sp)		;00YYYYYY
	move.w	(sp)+,d0		;00YYYYYY........
	move.b	d2,d0			;00YYYYYY..XXXXXX
	add.b	d0,d0			;00YYYYYY.XXXXXX0
	add.b	d0,d0			;00YYYYYYXXXXXX00
	lsr.w	#1,d0			;000YYYYYYXXXXXX0
;	moveq.l	#0,d0
	move.w	(a0,d0.w),d0		;キャラクタ
	move.w	d5,(a5)			;MPUCSをクリア
	pop
	rts

;----------------------------------------------------------------
;$CF	SPALET
;	スプライトパレットを設定または取得します。
;	パレットブロック0は指定できません。
;<d1.l bit31:VDISPの立ち下がり。0=待つ,1=待たない
;<d1.b:パレットブロック<<4|パレットコード。0~255
;<d2.b:パレットブロック。0~15
;<d3.l bit31:モード。0=設定,1=取得
;<d3.w:カラーコード。0~65535
;>d0.l:-2=パレットブロック0が指定された,0~65535=設定前のカラーコード
;?a0
iocs_CF_SPALET:
	move.b	d2,-(sp)
	moveq.l	#$0F,d0			;ここで上位ワードをクリアする
	and.b	d1,d0			;0<<4|パレットコード
	lsl.b	#4,d2			;d2のパレットブロック<<4|0
	if	ne			;d2にパレットブロックがある
		or.b	d2,d0			;d2のパレットブロック<<4|パレットコード
	else
		goto	<cmp.b d1,d0>,eq,20f	;d2とd1のどちらにもパレットブロックがない
		move.b	d1,d0		;d1のパレットブロック<<4|パレットコード
	endif
	add.w	d0,d0
	lea.l	VICON_TSPALET,a0
	adda.l	d0,a0
	if	<tst.l d1>,pl
		bsr	vdisp_falling_edge	;VDISPの立ち下がりを待つ
	endif
	move.w	(a0),d0			;取得
	if	<tst.l d3>,pl
		move.w	d3,(a0)			;設定
	endif
10:	move.b	(sp)+,d2
	rts

20:	moveq.l	#-2,d0			;パレットブロック0が指定された
	goto	10b



;----------------------------------------------------------------
;デバイスドライバの末尾
device_tail:



dFLAG	reg	d4			;-1=常駐していない,0=常駐部分はデバイスドライバ,1=常駐部分はメモリブロック
aRESI	reg	a2			;常駐部分のプログラムの先頭。0=常駐していない
aPREV	reg	a3			;デバイスドライバとして常駐しているとき直前のデバイスドライバ。さもなくば最後のデバイスドライバ
aSELF	reg	a4			;自分のプログラムの先頭
r	reg	-program_head(aSELF)

;----------------------------------------------------------------
;デバイスコマンド0 初期化
initialize:
	lea.l	program_head(pc),aSELF	;自分のプログラムの先頭

;オプションを確認する
	movea.l	18(a5),a0		;引数の並び。区切りは0、末尾は0,0。先頭はデバイスファイル名
	do
	while	<tst.b (a0)+>,ne	;デバイスファイル名を読み飛ばす
	dostart
		gotoand	<cmp.b #'-',d0>,ne,<cmp.b #'/',d0>,ne,option_error	;1文字目が-,/でない
		move.b	(a0)+,d0		;2文字目
		goto	eq,option_error		;-,/の後に文字がない
		jbsr	tolower
		if	<cmp.b #'q',d0>,eq	;-q メッセージ非表示
			st.b	(quiet_flag)r
		else
			goto	option_error
		endif
		tst.b	(a0)+			;引数の区切り
		goto	ne,option_error		;余分な文字がある
	start
		move.b	(a0)+,d0		;次の引数の1文字目
	while	ne

;ベクタを変更する
	lea.l	vector_table(pc),a0	;ベクタテーブル
	bsr	set_vector		;ベクタを変更する

;改行とタイトルを表示する
	if	<tst.b (quiet_flag)r>,eq
		jbsr	printcrlf
		lea.l	title_message(pc),a0
		jbsr	print
	endif

;デバイスドライバの末尾を設定して正常終了する
	move.l	#device_tail,14(a5)	;デバイスドライバの末尾
	moveq.l	#0,d0			;正常終了する
	rts

;オプションエラー
option_error:
	lea.l	wrong_message(pc),a1	;オプションが違います

;改行とプログラム名とエラーメッセージを表示する。-qは無効
;<a1.l:メッセージ
device_error:
	jbsr	printcrlf
	lea.l	program_colon(pc),a0
	jbsr	print
	movea.l	a1,a0
	jbsr	print

;デバイスドライバを組み込まない
	move.w	#ABORT|MISCELLANEOUS_ERROR,d0	;中止(A) エラーが発生しました
	rts

;----------------------------------------------------------------
;実行開始
execution_start:
	lea.l	program_head(pc),aSELF	;自分のプログラムの先頭

;オプションを確認する
	lea.l	1(a2),a0		;コマンドライン
	dostart
		addq.l	#1,a0
		gotoand	<cmp.b #'-',d0>,ne,<cmp.b #'/',d0>,ne,option_exit	;1文字目が-,/でない
		move.b	(a0)+,d0		;2文字目
		goto	eq,option_exit		;-,/の後に文字がない
		jbsr	tolower
		if	<cmp.b #'c',d0>,eq	;-c 常駐確認
			st.b	(check_flag)r
		elifor	<cmp.b #'h',d0>,eq,<cmp.b #'?',d0>,eq	;-h/-? 使用法表示
			st.b	(help_flag)r
		elif	<cmp.b #'k',d0>,eq	;-k 常駐
			st.b	(keep_flag)r
		elif	<cmp.b #'q',d0>,eq	;-q メッセージ非表示
			st.b	(quiet_flag)r
		elif	<cmp.b #'r',d0>,eq	;-r 常駐解除
			st.b	(release_flag)r
		elif	<cmp.b #'v',d0>,eq	;-v バージョン確認
			st.b	(version_flag)r
		else
			goto	option_exit
		endif
		move.b	(a0),d0			;次の文字
		break	eq
		jbsr	isspace
		goto	ne,option_exit		;余分な文字がある
	start
		jbsr	nextword		;空白を読み飛ばす
	while	ne

;-c -h/-? -k -r -vは同時に指定できない
	move.b	(check_flag)r,d0
	add.b	(help_flag)r,d0
	goto	cs,option_exit
	add.b	(keep_flag)r,d0
	goto	cs,option_exit
	add.b	(release_flag)r,d0
	goto	cs,option_exit
	add.b	(version_flag)r,d0
	goto	cs,option_exit

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

;使用法表示
	goto	<tst.b (help_flag)r>,ne,help_exit	;使用法表示

;バージョン確認
	if	<tst.b (version_flag)r>,ne	;バージョン確認
		moveq.l	#1,d1			;タイトル
		moveq.l	#0,d2			;正常終了
		goto	message_exit
	endif

;常駐部分を探す
	do
	;デバイスドライバを探す
		moveq.l	#0,dFLAG		;常駐部分はデバイスドライバ
		movea.l	DOS_HUMAN_MEMORY.w,a0	;Human68kの先頭。これより手前はスーパーバイザスタックエリア
		move.w	#'NU',d0		;NULデバイスドライバ=デバイスドライバのリストの先頭を探す。必ずある
		lea.l	DH_NAME(a0),a0
		do
			do
			while	<cmp.w (a0)+,d0>,ne
		whileor	<cmpi.l #'L   ',2-2(a0)>,ne,<cmpi.w #'  ',6-2(a0)>,ne,<cmpi.w #$8024,DH_TYPE-(DH_NAME+2)(a0)>,ne
		lea.l	-(DH_NAME+2)(a0),aRESI	;NULデバイスドライバ
		movem.l	DH_NAME(aSELF),d0-d1	;自分のデバイス名
		do
			break2and	<cmp.l DH_NAME(aRESI),d0>,eq,<cmp.l DH_NAME+4(aRESI),d1>,eq	;デバイス名が同じ
			movea.l	aRESI,aPREV		;デバイスドライバ→直前のデバイスドライバ
			movea.l	DH_NEXT(aRESI),aRESI	;次のデバイスドライバ
		while	<cmpa.w #-1,aRESI>,ne
	;メモリブロックを探す
		moveq.l	#1,dFLAG		;常駐部分はメモリブロック
		movea.l	DOS_HUMAN_MEMORY.w,aRESI	;メモリブロックのリストの先頭
		dostart
			if	<cmpi.b #-1,MM_PARENT(aRESI)>,eq	;常駐している。自分はここで取り除く
				lea.l	MM_PROGRAM+iocs_C0_SP_INIT-program_head(aRESI),a0	;常駐部分のSP_INIT
				ifand	<cmpa.l MM_TAIL(aRESI),a0>,ls,<cmp.l program_head+DH_NAME-iocs_C0_SP_INIT(a0),d0>,eq,<cmp.l program_head+DH_NAME+4-iocs_C0_SP_INIT(a0),d1>,eq	;長さが足りていてデバイス名が同じ
					lea.l	MM_PROGRAM(aRESI),aRESI	;常駐部分のプログラムの先頭
					break2
				endif
			endif
		start
			movea.l MM_NEXT(aRESI),aRESI	;次のメモリ管理テーブル
		while	<cmpa.w #0,aRESI>,ne
		moveq.l	#-1,dFLAG		;常駐していない
	while	f
;<dFLAG.l:-1=常駐していない,0=常駐部分はデバイスドライバ,1=常駐部分はメモリブロック
;<aRESI.l:常駐部分のプログラムの先頭。0=常駐していない
;<aPREV.l:デバイスドライバとして常駐しているとき直前のデバイスドライバ。さもなくば最後のデバイスドライバ

;常駐確認
	if	<tst.b (check_flag)r>,ne	;常駐確認
		moveq.l	#2+4,d1			;プログラム名とメッセージ
		moveq.l	#2,d2			;エラー終了。常駐しています
		lea.l	already_message(pc),a1	;常駐しています
		if	<tst.l dFLAG>,mi	;常駐していない
			moveq.l	#3,d2			;エラー終了。常駐していません
			lea.l	not_yet_message(pc),a1	;常駐していません
		endif
		goto	message_exit
	endif

;解除
	if	<tst.b (release_flag)r>,ne	;解除

	;常駐していないのに解除しようとしたらエラー
		if	<tst.l dFLAG>,mi	;常駐していない
			moveq.l	#2+4,d1			;プログラム名とメッセージ
			moveq.l	#3,d2			;エラー終了。常駐していません
			lea.l	not_yet_message(pc),a1	;常駐していません
			goto	message_exit
		endif

	;常駐部分のバージョンが違ったらエラー
	;	ベクタが変更されていないか確認する前に行うこと
	;	常駐部分のメモリブロックの長さは確認済み
		move.l	version_code-program_head(aRESI),d0	;常駐部分のバージョンコード
		if	<cmp.l version_code(pc),d0>,ne	;バージョンコードが違う
			moveq.l	#2+4,d1			;プログラム名とメッセージ
			moveq.l	#5,d2			;エラー終了。常駐部分のバージョンが違います。解除できません
			lea.l	version_message(pc),a1	;常駐部分のバージョンが違います。解除できません
			goto	message_exit
		endif

	;ベクタが変更されていたらエラー
		lea.l	vector_table-program_head(aRESI),a0	;常駐部分のベクタテーブル
		bsr	check_vector		;ベクタを確認する
		if	ne			;ベクタが変更されている
			moveq.l	#2+4,d1			;プログラム名とメッセージ
			moveq.l	#4,d2			;エラー終了。ベクタが変更されています。解除できません
			lea.l	vector_message(pc),a1	;ベクタが変更されています。解除できません
			goto	message_exit
		endif

	;初期化する
		moveq.l	#0,d1
		bsr	iocs_C0_SP_INIT

	;ベクタを復元する
		lea.l	vector_table-program_head(aRESI),a0	;常駐部分のベクタテーブル
		bsr	release_vector		;ベクタを復元する

	;デバイスドライバを切り離す/メモリブロックを開放する
		if	<tst.l dFLAG>,eq	;常駐部分はデバイスドライバ
			move.l	DH_NEXT(aRESI),DH_NEXT(aPREV)	;直前のデバイスドライバの次のデバイスドライバは次のデバイスドライバ(-1を含む)
		else				;常駐部分はメモリブロック
			pea.l	MM_SIZE-MM_PROGRAM(aRESI)	;常駐部分のメモリブロックの先頭
			DOS	_MFREE
			addq.l	#4,sp
		endif

	;正常終了する
		moveq.l	#2+4,d1			;プログラム名とメッセージ
		moveq.l	#0,d2			;正常終了
		lea.l	released_message(pc),a1	;解除しました
		goto	message_exit

	endif

;常駐
	if	<tst.b (keep_flag)r>,ne	;常駐

	;常駐しているのに常駐しようとしたらエラー
		if	<tst.l dFLAG>,pl	;常駐している
			moveq.l	#2+4,d1			;プログラム名とメッセージ
			moveq.l	#2,d2			;エラー終了。常駐しています
			lea.l	already_message(pc),a1	;常駐しています
			goto	message_exit
		endif

	;ベクタを変更する
		lea.l	vector_table(pc),a0	;ベクタテーブル
		bsr	set_vector		;ベクタを変更する

	;デバイスドライバを接続する
	;	move.l	aSELF,(aPREV)		;最後のデバイスドライバの次のデバイスドライバを自分にする

	;初期化する
		moveq.l	#0,d1
		bsr	iocs_C0_SP_INIT

	;常駐終了する
		moveq.l	#2+4,d1			;プログラム名とメッセージ
		moveq.l	#-1,d2			;常駐終了
		lea.l	resident_message(pc),a1	;常駐しました
		goto	message_exit

	endif

;使用法を表示して正常終了する
help_exit:
	moveq.l	#1+4,d1			;タイトルとメッセージ
	moveq.l	#0,d2			;正常終了
	lea.l	help_message(pc),a1	;使用法
	goto	message_exit

;ユーザモードへ復帰して終了する
;<d1.l:1=タイトルを表示する,2=プログラム名を表示する,4=メッセージを表示する
;<d2.w:終了コード。-1=常駐終了,0=正常終了,1~=エラー終了
;<a1.l:メッセージ
message_exit:
;ユーザモードへ復帰する
	usermode
	if	<tst.b (quiet_flag)r>,eq
		if	<btst.l #0,d1>,ne	;タイトルを表示する
			lea.l	title_message(pc),a0
			jbsr	print
		endif
		if	<btst.l #1,d1>,ne	;プログラム名を表示する
			lea.l	program_colon(pc),a0
			jbsr	print
		endif
		if	<btst.l #2,d1>,ne	;メッセージを表示する
			movea.l	a1,a0
			jbsr	print
		endif
	endif
;終了する
	if	<tst.w d2>,mi		;常駐終了
		clr.w	-(sp)
		move.l	#device_tail-program_head,-(sp)
		DOS	_KEEPPR
	endif
	move.w	d2,-(sp)
	DOS	_EXIT2

;オプションが違う
option_exit:
;プログラム名とエラーメッセージとタイトルと使用法を表示する。-qは無効
	lea.l	program_colon(pc),a0
	jbsr	print
	lea.l	wrong_message(pc),a0	;オプションが違います
	jbsr	print
	lea.l	title_message(pc),a0
	jbsr	print
	lea.l	help_message(pc),a0
	jbsr	print
;エラー終了する
	move.w	#1,-(sp)
	DOS	_EXIT2

;----------------------------------------------------------------
;ベクタを変更する
;	スーパーバイザモードで呼び出すこと
;<a0.l:ベクタテーブル
set_vector:
	push	d0/a0-a1
	dostart
		movea.w	d0,a1			;オフセット
		move.l	(a1),d0
		move.l	(a0)+,(a1)		;新しいベクタ
		move.l	d0,(a0)+		;古いベクタ
	start
		move.w	(a0)+,d0
	while	ne
	pop
	rts

;----------------------------------------------------------------
;ベクタを確認する
;	スーパーバイザモードで呼び出すこと
;<a0.l:常駐部分のベクタテーブル
;>ccr:eq=ベクタは変更されていない,ne=ベクタが変更されている
check_vector:
	push	d0/a0-a1
	dostart
		movea.w	d0,a1			;オフセット
		move.l	(a1),d0
		break	<cmp.l (a0)+,d0>,ne	;新しいベクタが現在のベクタと一致しなければ失敗
		addq.l	#4,a0			;古いベクタを読み飛ばす
	start
		move.w	(a0)+,d0
	while	ne
	pop
	rts

;----------------------------------------------------------------
;ベクタを復元する
;	スーパーバイザモードで呼び出すこと
;<a0.l:常駐部分のベクタテーブル
release_vector:
	push	d0/a0-a1
	dostart
		movea.w	d0,a1			;オフセット
		addq.l	#4,a0			;新しいベクタを読み飛ばす
		move.l	(a0)+,(a1)		;古いベクタ
	start
		move.w	(a0)+,d0
	while	ne
	pop
	rts

;----------------------------------------------------------------
;文字列
title_message:
	.dc.b	TITLE_STRING,' ',PROGRAM_NAME,' version ',VERSION_STRING,13,10,0
program_colon:
	.dc.b	PROGRAM_NAME,': ',0
help_message:
	.dc.b	'機能',13,10
	.dc.b	9,'スプライト関連のIOCSコールをフルパターンメモリに対応させます。',13,10
	.dc.b	'使用法',13,10
	.dc.b	9,'CONFIG.SYS',13,10
	.dc.b	9,9,'device=',PROGRAM_NAME,' オプション',13,10
	.dc.b	9,'コマンドライン',13,10
	.dc.b	9,9,'A>',PROGRAM_NAME,' オプション',13,10
	.dc.b	9,'オプション',13,10
	.dc.b	9,9,'-c',9,'常駐確認',13,10
	.dc.b	9,9,'-h/-?',9,'使用法表示',13,10
	.dc.b	9,9,'-k',9,'常駐',13,10
	.dc.b	9,9,'-q',9,'メッセージ非表示',13,10
	.dc.b	9,9,'-r',9,'常駐解除',13,10
	.dc.b	9,9,'-v',9,'バージョン確認',13,10
	.dc.b	0
wrong_message:
	.dc.b	'オプションが違います',13,10,0
already_message:
	.dc.b	'常駐しています',13,10,0
resident_message:
	.dc.b	'常駐しました',13,10,0
not_yet_message:
	.dc.b	'常駐していません',13,10,0
vector_message:
	.dc.b	'ベクタが変更されています。解除できません',13,10,0
version_message:
	.dc.b	'常駐部分のバージョンが違います。解除できません',13,10,0
released_message:
	.dc.b	'解除しました',13,10,0
	.even

	.data

;----------------------------------------------------------------
;フラグ
check_flag:
	.dc.b	0			;-c 常駐確認
help_flag:
	.dc.b	0			;-h/-? 使用法表示
keep_flag:
	.dc.b	0			;-k 常駐
quiet_flag:
	.dc.b	0			;-q メッセージ非表示
release_flag:
	.dc.b	0			;-r 常駐解除
version_flag:
	.dc.b	0			;-v バージョン確認
	.even



	.text
	.even

;----------------------------------------------------------------
;空白文字か \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

;----------------------------------------------------------------
;改行を表示する
printcrlf:
	move.l	a0,-(sp)
	lea.l	100f(pc),a0		;13,10
	jbsr	print
	movea.l	(sp)+,a0
	rts

100:	.dc.b	13,10,0
	.even

;----------------------------------------------------------------
;文字列の長さを数える
;<a0.l:文字列
;>d0.l:長さ
strlen:
	move.l	a0,d0			;d0=先頭
	do
	while	<tst.b (a0)+>,ne		;0の次の位置まで進む
	subq.l	#1,a0			;進み過ぎた分戻る。a0=0の位置
	exg.l	d0,a0			;d0=末尾,a0=先頭
	sub.l	a0,d0			;d0=末尾-先頭=長さ
	rts

;----------------------------------------------------------------
;小文字にする
;<d0.b:文字
;>d0.b:文字
tolower:
	ifand	<cmp.b #'A',d0>,hs,<cmp.b #'Z',d0>,ls	;大文字
		add.b	#'a'-'A',d0		;小文字にする
	endif
	rts



;----------------------------------------------------------------
;プログラムの末尾
	.bss
	.even
program_end:

	.end	execution_start